Add podcasts and map view

This commit is contained in:
2023-06-18 15:53:49 +10:00
parent 85dd61510e
commit 0cf6d0d540
17 changed files with 2558 additions and 24 deletions

View File

@@ -29,4 +29,27 @@ namespace :blog do
}) })
end end
end end
task load_from_overcast: ["blog:load_environment"] do
require "nokogiri"
require "hanami/prepare"
require "down"
podcast_repo = Adamantium::Container["repos.podcast_repo"]
settings = Adamantium::Container["settings"]
doc = File.open("tmp/overcast.opml") { |f| Nokogiri::XML(f) }
doc.xpath("//outline[@type='rss']").each do |outline|
overcast_id = outline.get_attribute("overcastId")
url = "https://public.overcast-cdn.com/art/#{overcast_id}_thumb"
destination = File.join("public", "media", "podcast_art", "#{overcast_id}.jpg")
Down.download(url, destination: destination)
podcast_repo.create(
name: outline.get_attribute("title"),
url: outline.get_attribute("htmlUrl"),
overcast_id: outline.get_attribute("overcastId")
)
end
end
end end

View File

@@ -0,0 +1,13 @@
module Adamantium
module Actions
module Places
class MapPage < Action
include Deps["views.places.map_page"]
def handle(req, res)
res.render map_page
end
end
end
end
end

View File

@@ -0,0 +1,13 @@
module Adamantium
module Actions
module Podcasts
class Index < Action
include Deps["views.podcasts.index"]
def handle(req, res)
res.render index
end
end
end
end
end

15
app/repos/podcast_repo.rb Normal file
View File

@@ -0,0 +1,15 @@
module Adamantium
module Repos
class PodcastRepo < Adamantium::Repo[:podcasts]
commands :create
def listing
podcasts.order(:name).to_a
end
def delete_all
podcasts.delete
end
end
end
end

View File

@@ -118,7 +118,8 @@ module Adamantium
def places_listing(limit: nil) def places_listing(limit: nil)
posts posts
.where(post_type: "checkin") .where(post_type: ["checkin", "post"])
.exclude(location: nil)
.published .published
.combine(:tags) .combine(:tags)
.order(Sequel.desc(:published_at)) .order(Sequel.desc(:published_at))

View File

@@ -0,0 +1,34 @@
html
head
meta charest="utf-8"
meta name="viewport" content="width=device-width, initial-scale=1.0"
meta name="theme-color" content="rgb(37, 99, 235)"
title #{context.content_for(:title)} Daniel Nitsikopoulos
link rel="authorization_endpoint" href=Hanami.app.settings.micropub_authorization_endpoint
link rel="token_endpoint" href=Hanami.app.settings.micropub_token_endpoint
link rel="micropub" href="#{URI.join(Hanami.app.settings.micropub_site_url, "micropub")}"
link rel="webmention" href=Hanami.app.settings.webmention_url
link rel="pingback" href=Hanami.app.settings.pingback_url
link rel="feed" type="text/html" href="/posts"
link rel="feed alternate" type="application/rss+xml" href="/feeds/rss"
link rel="feed alternate" type="application/rss+xml" href="/feeds/statuses_rss"
link rel="me" href=Hanami.app.settings.mastodon_url
link rel="me" href=Hanami.app.settings.github_url
link rel="stylesheet" href=asset_from_manifest("index.css")
link rel="icon" type="image/x-icon" href="/assets/favicon.ico"
script src='https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.js'
link href='https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.css' rel='stylesheet'
script data-domain="dnitza.com" src="https://stats.dnitza.com/js/script.js" defer="true"
script src=asset_from_manifest("index.js")
body class="bg-white dark:bg-black selection:bg-blue-100 selection:text-blue-900 dark:selection:bg-blue-600 dark:selection:text-blue-100"
== yield

View File

@@ -15,5 +15,6 @@ div class="mb-12 max-w-prose mx-auto text-gray-800 dark:text-gray-200"
a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/hikes" 🥾 Hikes a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/hikes" 🥾 Hikes
a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/movies" 🍿 Movies a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/movies" 🍿 Movies
a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/trips" 🛫 Trips a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/trips" 🛫 Trips
a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/podcasts" 🎙️ Podcasts
/ a class="block p-1 border border-blue-200 bg-blue-300 text-blue-900 hover:bg-blue-200 text-center rounded-lg" href="/art" 🎨 Art things / a class="block p-1 border border-blue-200 bg-blue-300 text-blue-900 hover:bg-blue-200 text-center rounded-lg" href="/art" 🎨 Art things

View File

@@ -1,8 +1,14 @@
- context.content_for(:title, "Places | ") - context.content_for(:title, "Places | ")
div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200" div class="mb-4 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
h1 Places h1 Places
/ div id='map' data-markers="#{JSON.generate(places.map{|p| [p.lon,p.lat]})}" style='width: 400px; height: 300px;'
div class="mb-12 max-w-prose mx-auto text-gray-800 dark:text-gray-200"
nav class="space-x-1 text-sm md:text-sm uppercase md:block"
span
| 🗺️&nbsp;
a href="/places/map" View map
div class="mb-12 max-w-prose mx-auto" div class="mb-12 max-w-prose mx-auto"
- places.each do |post| - places.each do |post|

View File

@@ -0,0 +1,3 @@
div class="p-2 bg-white absolute bg-opacity-75 z-40 w-screen"
button id="go-back" &larr; Back
div id='map' style='width: 100%; height: 100%;' data-markers="#{JSON.generate(places.map(&:value))}"

View File

@@ -0,0 +1,20 @@
- context.content_for(:title, "Podcasts | ")
div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
h1 Podcasts
div class="mb-12 max-w-prose mx-auto"
table class="prose dark:prose-invert table-auto"
thead
tr
td
td Name
- podcasts.each do |podcast|
tr
td
img class="w-14 m-0 p-0 rounded" src="/media/podcast_art/#{podcast.overcast_id}.jpg"
td class="p-0 align-middle"
a class="block" href="#{podcast.url}"
= podcast.name
div class="max-w-screen-md mx-auto border-t-4 border-solid border-gray-400 dark:border-gray-600"

View File

@@ -0,0 +1,18 @@
module Adamantium
module Views
module Places
class MapPage < Adamantium::View
include Deps["repos.post_repo"]
config.layout = "map"
expose :places do
post_repo.places_listing.map do |post|
p = Decorators::Posts::Decorator.new(post)
[p.lon, p.lat]
end
end
end
end
end
end

View File

@@ -0,0 +1,13 @@
module Adamantium
module Views
module Podcasts
class Index < View
include Deps["repos.podcast_repo"]
expose :podcasts do
podcast_repo.listing
end
end
end
end
end

View File

@@ -34,6 +34,7 @@ module Adamantium
get "/photos", to: "photos.index" get "/photos", to: "photos.index"
get "/places", to: "places.index" get "/places", to: "places.index"
get "/places/map", to: "places.map_page"
get "/statuses", to: "statuses.index" get "/statuses", to: "statuses.index"
get "/tags", to: "tags.index" get "/tags", to: "tags.index"
@@ -56,6 +57,8 @@ module Adamantium
get "/trips", to: "trips.index" get "/trips", to: "trips.index"
get "/trips/:id", to: "trips.show" get "/trips/:id", to: "trips.show"
get "/podcasts", to: "podcasts.index"
redirect "deploying-a-hanami-app-to-fly-io", to: "/post/deploying-a-hanami-20-app-to-flyio" redirect "deploying-a-hanami-app-to-fly-io", to: "/post/deploying-a-hanami-20-app-to-flyio"
redirect "deploying-a-hanami-app-to-fly-io/", to: "/post/deploying-a-hanami-20-app-to-flyio" redirect "deploying-a-hanami-app-to-fly-io/", to: "/post/deploying-a-hanami-20-app-to-flyio"

View File

@@ -0,0 +1,12 @@
# frozen_string_literal: true
ROM::SQL.migration do
change do
create_table :podcasts do
primary_key :id
column :name, :text, null: false
column :url, :text, null: false
column :overcast_id, :text, null: false
end
end
end

View File

@@ -0,0 +1,13 @@
# frozen_string_literal: true
module Adamantium
module Persistence
module Relations
class Podcasts < ROM::Relation[:sql]
schema :podcasts, infer: true
auto_struct(true)
end
end
end
end

File diff suppressed because one or more lines are too long

View File

@@ -7,29 +7,50 @@
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
const times = document.querySelectorAll('time'); const times = document.querySelectorAll('time');
times.forEach((time) => { times.forEach((time) => {
const oldDtime = Date.parse(time.dateTime); const oldDtime = Date.parse(time.dateTime);
time.innerHTML = new Date(oldDtime).toLocaleDateString(navigator.language, { weekday:"long", year:"numeric", month:"short", day:"numeric"}); time.innerHTML = new Date(oldDtime).toLocaleDateString(navigator.language, { weekday:"long", year:"numeric", month:"short", day:"numeric"});
md_gallery({ md_gallery({
"class_name": "grid gap-4 grid-cols-2 prose-img:m-0" "class_name": "grid gap-4 grid-cols-2 prose-img:m-0"
});
htmx.on('#media_form', 'htmx:xhr:progress', function(evt) {
htmx.find('#progress').setAttribute('value', evt.detail.loaded/evt.detail.total * 100)
});
}); });
htmx.on('#media_form', 'htmx:xhr:progress', function(evt) { const mapContainer = document.getElementById("map");
htmx.find('#progress').setAttribute('value', evt.detail.loaded/evt.detail.total * 100) if (mapContainer !== undefined) {
document.getElementById("go-back").addEventListener("click", () => {
history.back();
}); });
});
// mapboxgl.accessToken = 'pk.eyJ1IjoiZG5pdHphIiwiYSI6ImNsZWIyY3ZzaTE0cjUzdm4xdnZ6czRlYjUifQ.FRETOXYRID6T2IoB7qqRLg'; mapboxgl.accessToken = 'pk.eyJ1IjoiZG5pdHphIiwiYSI6ImNsZWIyY3ZzaTE0cjUzdm4xdnZ6czRlYjUifQ.FRETOXYRID6T2IoB7qqRLg';
// var map = new mapboxgl.Map({ var map = new mapboxgl.Map({
// container: 'map', container: 'map',
// style: 'mapbox://styles/mapbox/streets-v11' style: 'mapbox://styles/mapbox/streets-v11',
// }); maxZoom: 8
// const mapContainer = document.getElementById("map"); });
// const markers = JSON.parse(mapContainer.dataset["markers"]);
// for (var i = 0; i < markers.length; i++) { const markers = JSON.parse(mapContainer.dataset["markers"]);
// const marker = markers[i];
// new mapboxgl.Marker() const bounds = new mapboxgl.LngLatBounds(markers[0], markers[0]);
// .setLngLat(marker)
// .addTo(map); for (var i = 0; i < markers.length; i++) {
// } bounds.extend(markers[i]);
}
map.fitBounds(bounds, { padding: 60 });
for (var i = 0; i < markers.length; i++) {
const marker = markers[i];
const el = document.createElement("div");
el.className = "map-marker";
new mapboxgl.Marker(el)
.setLngLat(marker)
.addTo(map);
}
}
}); });
})(); })();