diff --git a/app/actions/places/index.rb b/app/actions/places/index.rb new file mode 100644 index 0000000..abdeb51 --- /dev/null +++ b/app/actions/places/index.rb @@ -0,0 +1,13 @@ +module Adamantium + module Actions + module Places + class Index < Action + include Deps["views.places.index"] + + def handle(req, res) + res.render index + end + end + end + end +end diff --git a/app/decorators/posts/decorator.rb b/app/decorators/posts/decorator.rb index 31a874d..deaad60 100644 --- a/app/decorators/posts/decorator.rb +++ b/app/decorators/posts/decorator.rb @@ -26,7 +26,8 @@ module Adamantium end def prefix_emoji - name ? "" : "πŸ“―" + prefix = name ? "" : "πŸ“―" + location ? "πŸ—ΊοΈ" : prefix end def display_title @@ -54,8 +55,24 @@ module Adamantium "#{Hanami.app.settings.micropub_site_url}/post/#{slug}" end + def lat + geo[0] + end + + def lon + geo[1] + end + private + # e.g. geo:-37.75188,144.90417;u=35 + def geo + loc = location.split(":")[1] + p = loc.split(";")[0] + + p.split(",") + end + def truncate_html(content, len = 30, at_end = nil) p = REXML::Parsers::PullParser.new(content) tags = [] diff --git a/app/entities/bookmark_request.rb b/app/entities/bookmark_request.rb index e916c8a..6571b82 100644 --- a/app/entities/bookmark_request.rb +++ b/app/entities/bookmark_request.rb @@ -12,6 +12,7 @@ module Adamantium attribute :post_type, Types::Coercible::String attribute :syndicate_to, Types::Array.of(Types::Coercible::String) attribute :photos, Types::Array.of(Types::Hash) + attribute :location, Types::Coercible::String.optional end end end diff --git a/app/entities/post_request.rb b/app/entities/post_request.rb index cd6ab7c..adec9ff 100644 --- a/app/entities/post_request.rb +++ b/app/entities/post_request.rb @@ -11,6 +11,7 @@ module Adamantium attribute :post_type, Types::Coercible::String attribute :syndicate_to, Types::Array.of(Types::Coercible::String) attribute :photos, Types::Array.of(Types::Hash) + attribute :location, Types::Coercible::String.optional end end end diff --git a/app/repos/post_repo.rb b/app/repos/post_repo.rb index 4cdfa44..09a14a2 100644 --- a/app/repos/post_repo.rb +++ b/app/repos/post_repo.rb @@ -1,6 +1,7 @@ module Adamantium module Repos class PostRepo < Adamantium::Repo[:posts] + Sequel.extension :pg_json_ops commands update: :by_pk def create(post_attrs) @@ -52,8 +53,30 @@ module Adamantium end def post_listing(limit: nil) + posts + .where(post_type: "post", location: nil) + .published + .combine(:tags) + .order(Sequel.desc(:published_at)) + .limit(limit) + .to_a + end + + def photo_listing(limit: nil) posts .where(post_type: "post") + .where(Sequel[:photos].pg_json.array_length > 0) + .published + .combine(:tags) + .order(Sequel.desc(:published_at)) + .limit(limit) + .to_a + end + + def places_listing(limit: nil) + posts + .where(post_type: "post") + .exclude(location: nil) .published .combine(:tags) .order(Sequel.desc(:published_at)) @@ -73,7 +96,7 @@ module Adamantium def for_rss posts - .where(post_type: "post") + .where(post_type: "post", location: nil) .published .combine(:tags) .order(Sequel.desc(:published_at)) diff --git a/app/templates/places/index.html.slim b/app/templates/places/index.html.slim new file mode 100644 index 0000000..d10944c --- /dev/null +++ b/app/templates/places/index.html.slim @@ -0,0 +1,8 @@ +div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200" + h1 Places + +div class="mb-12 max-w-prose mx-auto" + - places.each do |post| + == render :post, post: post + +div class="max-w-screen-md mx-auto border-t-4 border-solid border-gray-400 dark:border-gray-600" diff --git a/app/templates/posts/show.html.slim b/app/templates/posts/show.html.slim index 0816ae7..fb8ca59 100644 --- a/app/templates/posts/show.html.slim +++ b/app/templates/posts/show.html.slim @@ -14,6 +14,9 @@ article class="h-entry" div class="e-content" == post.content + - if post.location + img class="shadow-solid shadow-pink-100 dark:shadow-pink-200 rounded mb-4" src="https://api.mapbox.com/styles/v1/dnitza/cleb2o734000k01pbifls5620/static/#{post.lat},#{post.lon},14,0/300x400@2x?access_token=pk.eyJ1IjoiZG5pdHphIiwiYSI6ImNsZWIzOHFmazBkODIzdm9kZHgxdDF4ajQifQ.mSneE-1SKeju8AOz5gp4BQ" + div class="mb-4 max-w-screen-md mx-auto border-t-4 border-solid border-gray-400 dark:border-gray-600" div class="max-w-prose mx-auto text-gray-600 dark:text-gray-200 flex" diff --git a/app/templates/shared/_photo_post.html.slim b/app/templates/shared/_photo_post.html.slim new file mode 100644 index 0000000..b97a216 --- /dev/null +++ b/app/templates/shared/_photo_post.html.slim @@ -0,0 +1,2 @@ +a href="#{post.permalink}" + img class="rounded object-cover hover:opacity-80 h-48 w-48 mr-4 mb-4" src="#{post.photos[0]["value"]}" alt="#{post.photos[0]["alt"]}" diff --git a/app/templates/shared/_post.html.slim b/app/templates/shared/_post.html.slim index 1f570e6..d7be600 100644 --- a/app/templates/shared/_post.html.slim +++ b/app/templates/shared/_post.html.slim @@ -4,6 +4,8 @@ div class="mb-8 h-entry" = post.display_title div class="e-content p-name text-base prose prose-ul:list-none prose-ul:pl-0 prose-li:pl-0 text-gray-800 dark:text-gray-200" == post.excerpt + -if post.location + img src="https://api.mapbox.com/styles/v1/dnitza/cleb2o734000k01pbifls5620/static/#{post.lat},#{post.lon},14,0/50x50@2x?access_token=pk.eyJ1IjoiZG5pdHphIiwiYSI6ImNsZWIzOHFmazBkODIzdm9kZHgxdDF4ajQifQ.mSneE-1SKeju8AOz5gp4BQ" == render :tags, tags: post.tags p class="text-sm text-blue-400" diff --git a/app/views/places/index.rb b/app/views/places/index.rb new file mode 100644 index 0000000..45cb8dc --- /dev/null +++ b/app/views/places/index.rb @@ -0,0 +1,15 @@ +module Adamantium + module Views + module Places + class Index < Adamantium::View + include Deps["repos.post_repo"] + + expose :places do + post_repo.places_listing.map do |post| + Decorators::Posts::Decorator.new(post) + end + end + end + end + end +end diff --git a/config/app.rb b/config/app.rb index 2d4c427..b5268dd 100644 --- a/config/app.rb +++ b/config/app.rb @@ -6,6 +6,7 @@ module Adamantium class App < Hanami::App config.actions.content_security_policy[:script_src] += " https://gist.github.com" config.actions.content_security_policy[:script_src] += " *.dnitza.com" + config.actions.content_security_policy[:media_src] += " https://dnitza.com" config.actions.content_security_policy[:script_src] += " https://unpkg.com/htmx.org@1.8.4" config.actions.content_security_policy[:connect_src] += " https://stats.dnitza.com/api/event" diff --git a/config/routes.rb b/config/routes.rb index bf43394..600c08f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -23,6 +23,8 @@ module Adamantium get "/bookmarks/metadata/:id", to: "bookmarks.metadata" get "/bookmark/:slug", to: "bookmarks.show" + get "/places", to: "places.index" + get "/tagged/:slug", to: "tags.show" get "/key", to: "key.show" if Hanami.app.settings.micropub_pub_key diff --git a/db/migrate/20230219064027_add_location_to_posts.rb b/db/migrate/20230219064027_add_location_to_posts.rb new file mode 100644 index 0000000..6093580 --- /dev/null +++ b/db/migrate/20230219064027_add_location_to_posts.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +ROM::SQL.migration do + change do + alter_table :posts do + add_column :location, :text, default: nil + end + end +end diff --git a/lib/adamantium/micropub_request_parser.rb b/lib/adamantium/micropub_request_parser.rb index b0127e0..3120fcf 100644 --- a/lib/adamantium/micropub_request_parser.rb +++ b/lib/adamantium/micropub_request_parser.rb @@ -49,6 +49,7 @@ module Adamantium new_params[:slug] = params[:slug] || params["mp-slug"] new_params[:syndicate_to] = params[:properties][:"mp-syndicate-to"] || [] new_params[:photos] = params[:properties][:photo] || [] + new_params[:location] = params[:properties][:location] else new_params[:syndicate_to] = params[:"mp-syndicate-to"] || [] new_params[:name] = params[:name] @@ -56,6 +57,7 @@ module Adamantium new_params[:published_at] = (params[:"post-status"] == "draft") ? nil : publish_time new_params[:category] = params[:category] || [] new_params[:photos] = params[:photo] || [] + new_params[:location] = params[:location] content = if params[:content] if params[:content].is_a?(Hash) && params[:content][:html] diff --git a/public/assets/index.css b/public/assets/index.css index 1d0176f..e63ff45 100644 --- a/public/assets/index.css +++ b/public/assets/index.css @@ -983,6 +983,10 @@ video { grid-column: span 5 / span 5; } +.m-4 { + margin: 1rem; +} + .mx-auto { margin-left: auto; margin-right: auto; @@ -1024,6 +1028,10 @@ video { margin-top: 0px; } +.mr-4 { + margin-right: 1rem; +} + .inline { display: inline; } @@ -1040,6 +1048,10 @@ video { height: 4rem; } +.h-48 { + height: 12rem; +} + .w-36 { width: 9rem; } @@ -1060,6 +1072,10 @@ video { width: 1rem; } +.w-48 { + width: 12rem; +} + .max-w-prose { max-width: 65ch; } @@ -1149,6 +1165,11 @@ video { border-color: transparent; } +.border-gray-200 { + --tw-border-opacity: 1; + border-color: rgb(229 231 235 / var(--tw-border-opacity)); +} + .bg-blue-400 { --tw-bg-opacity: 1; background-color: rgb(96 165 250 / var(--tw-bg-opacity)); @@ -1167,6 +1188,11 @@ video { fill: #dbeafe; } +.object-cover { + -o-object-fit: cover; + object-fit: cover; +} + .p-1 { padding: 0.25rem; } @@ -1433,6 +1459,16 @@ h1, h2, h3, h4, h5, h6, h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { fill: #60a5fa; } +.hover\:object-fill:hover { + -o-object-fit: fill; + object-fit: fill; +} + +.hover\:object-scale-down:hover { + -o-object-fit: scale-down; + object-fit: scale-down; +} + .hover\:text-blue-100:hover { --tw-text-opacity: 1; color: rgb(219 234 254 / var(--tw-text-opacity)); @@ -1472,6 +1508,10 @@ h1, h2, h3, h4, h5, h6, h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { text-decoration-line: underline; } +.hover\:opacity-80:hover { + opacity: 0.8; +} + .prose-a\:rounded-sm :is(:where(a):not(:where([class~="not-prose"] *))) { border-radius: 0.125rem; } diff --git a/spec/syndication/unit/mastodon_spec.rb b/spec/syndication/unit/mastodon_spec.rb index 266f78c..b372397 100644 --- a/spec/syndication/unit/mastodon_spec.rb +++ b/spec/syndication/unit/mastodon_spec.rb @@ -19,7 +19,8 @@ RSpec.describe Adamantium::Syndication::Mastodon do published_at: Time.now, post_type: "post", syndicate_to: [], - photos: [] + photos: [], + location: nil ) }