diff --git a/slices/admin/decorators/bookmarks/decorator.rb b/slices/admin/decorators/bookmarks/decorator.rb new file mode 100644 index 0000000..d5f6e67 --- /dev/null +++ b/slices/admin/decorators/bookmarks/decorator.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: false + +# auto_register: false + +module Admin + module Decorators + module Bookmarks + class Decorator < SimpleDelegator + def display_published_at + published_at.strftime("%e %B, %Y") + end + + def display_title + "🔖: #{name}" + end + + def feed_content + content || "" + end + + def permalink + "#{Hanami.app.settings.micropub_site_url}/bookmark/#{slug}" + end + + def machine_published_at + published_at.rfc2822 + end + + def syndicated? + !syndication_sources.empty? + end + + def template_type + :bookmark + end + + def syndicated_to + syndication_sources.map do |source, url| + { + location: source, + url: url + } + end + end + + def youtube_embed + pattern = /watch[?]v=(\w*)/i + code = url.scan(pattern).flatten.first + if code + "
" + end + end + end + end + end +end diff --git a/slices/admin/decorators/books/decorator.rb b/slices/admin/decorators/books/decorator.rb new file mode 100644 index 0000000..e4c2402 --- /dev/null +++ b/slices/admin/decorators/books/decorator.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: false + +# auto_register: false + +module Admin + module Decorators + module Books + class Decorator < SimpleDelegator + def display_published_at + published_at.strftime("%e %B, %Y") + end + + def machine_published_at + published_at.rfc2822 + end + + def syndicated? + !syndication_sources.empty? + end + + def template_type + :book + end + + def authors + book_author.split(";").join(" ") + end + + def status_colour + case book_status + when "read" || "finished" + "text-green-100 bg-green-500" + when "to-read" + "text-blue-100 bg-blue-500" + when "reading" + "text-orange-100 bg-orange-500" + end + end + + def status_label + case book_status + when "read" || "finished" + "Read" + when "to-read" + "To read" + when "reading" + "Reading" + end + end + end + end + end +end diff --git a/slices/admin/decorators/movies/decorator.rb b/slices/admin/decorators/movies/decorator.rb new file mode 100644 index 0000000..70710be --- /dev/null +++ b/slices/admin/decorators/movies/decorator.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: false + +# auto_register: false + +module Admin + module Decorators + module Movies + class Decorator < SimpleDelegator + include Deps["clients.omdb"] + + def poster + omdb_record&.poster + end + + def omdb_record + @omdb_record ||= omdb.call(imdb_id: imdb_id) + end + end + end + end +end diff --git a/slices/admin/decorators/posts/decorator.rb b/slices/admin/decorators/posts/decorator.rb new file mode 100644 index 0000000..d16b928 --- /dev/null +++ b/slices/admin/decorators/posts/decorator.rb @@ -0,0 +1,211 @@ +# frozen_string_literal: false + +# auto_register: false + +require "rexml/parsers/pullparser" +require "sanitize" +require "nokogiri" +require "unicode/emoji" + +module Admin + module Decorators + module Posts + class Decorator < SimpleDelegator + def syndicated? + !syndication_sources.empty? + end + + def syndicated_to + syndication_sources.map do |source, url| + { + location: source, + url: url + } + end + end + + def photos? + __getobj__.photos.count { |p| !p["value"].end_with?("mp4") } > 0 + end + + def photos + __getobj__.photos.select { |p| !p["value"].end_with?("mp4") } + end + + def videos? + __getobj__.photos.count { |p| p["value"].end_with?("mp4") } > 0 + end + + def videos + __getobj__.photos.select { |p| p["value"].end_with?("mp4") } + end + + def key_image + if photos? + return photos.first["url"] + end + + inline_images.first[1] if inline_images + end + + def inline_images + doc = Nokogiri::HTML(content) + doc.at("//img") + end + + def inline_image_sources + inline_images + &.select {|attr, _value| attr == "src"} + &.map {|img| img[1] } || [] + end + + def photo_sources + photos.map{|photo| photo["value"]} + end + + def prefix_emoji + if name + nil + elsif photos? && content == "" + "📷" + elsif __getobj__.emoji + __getobj__.emoji + else + @prefix_emoji ||= if (match = content.match(Unicode::Emoji::REGEX)) + match + else + "💬" + end + end + end + + def display_title + title = name + "#{prefix_emoji} #{title}" + end + + def display_published_at + published_at.strftime("%e %B, %Y") + end + + def machine_published_at + published_at.rfc2822 + end + + def feed_content + photos? ? "
#{photos.map { |p| "" }.join("")} #{content}
" : content + end + + def raw_content + res = Sanitize.fragment(content) + res.gsub(prefix_emoji[0], "") if prefix_emoji + end + + def excerpt + name ? truncate_html(content, 240, true) : content + end + + def permalink + "#{Hanami.app.settings.micropub_site_url}/post/#{slug}" + end + + def lat + geo[0] + end + + def lon + geo[1] + end + + def small_map + "https://api.mapbox.com/styles/v1/dnitza/cleb2o734000k01pbifls5620/static/pin-s+555555(#{lon},#{lat})/#{lon},#{lat},14,0/200x100@2x?access_token=pk.eyJ1IjoiZG5pdHphIiwiYSI6ImNsZWIzOHFmazBkODIzdm9kZHgxdDF4ajQifQ.mSneE-1SKeju8AOz5gp4BQ" + end + + def large_map + "https://api.mapbox.com/styles/v1/dnitza/cleb2o734000k01pbifls5620/static/pin-s+555555(#{lon},#{lat})/#{lon},#{lat},14,0/620x310@2x?access_token=pk.eyJ1IjoiZG5pdHphIiwiYSI6ImNsZWIzOHFmazBkODIzdm9kZHgxdDF4ajQifQ.mSneE-1SKeju8AOz5gp4BQ" + end + + def template_type + :post + end + + def posted_in + if name.nil? + :statuses + elsif post_type.to_sym == :book + :bookshelf + elsif location.nil? + :posts + else + :places + end + end + + def trips + __getobj__.trips + end + + def to_h + clean_content = CGI::unescapeHTML(content.gsub(/<\/?[^>]*>/, "")).strip + clean_content = clean_content.gsub(prefix_emoji[0], "") if prefix_emoji + { + id: slug, + emoji: prefix_emoji, + content: clean_content, + images: (inline_image_sources + photo_sources).compact, + published_at: display_published_at + } + 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) + return content if content.to_s.length <= len + + p = REXML::Parsers::PullParser.new(content) + tags = [] + new_len = len + results = "" + while p.has_next? && new_len > 0 + p_e = p.pull + case p_e.event_type + when :start_element + tags.push p_e[0] + results << "<#{tags.last}#{attrs_to_s(p_e[1])}>" + when :end_element + results << "" + when :text + results << p_e[0][0..new_len] + new_len -= p_e[0].length + else + results << "" + end + end + if at_end + results << "..." + end + tags.reverse_each do |tag| + results << "" + end + results + end + + def attrs_to_s(attrs) + if attrs.empty? + "" + else + " " + attrs.to_a.map { |attr| %(#{attr[0]}="#{attr[1]}") }.join(" ") + end + end + end + end + end +end diff --git a/slices/admin/decorators/statuses/decorator.rb b/slices/admin/decorators/statuses/decorator.rb new file mode 100644 index 0000000..d8b477e --- /dev/null +++ b/slices/admin/decorators/statuses/decorator.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: false + +# auto_register: false + +require "rexml/parsers/pullparser" +require "sanitize" +require "nokogiri" + +module Admin + module Decorators + module Statuses + class Decorator < Main::Decorators::Posts::Decorator + def raw_content + res = Sanitize.fragment(content, + elements: ["img", "p"], + attributes: {"img" => ["alt", "src", "title"]}) + + res.gsub(prefix_emoji[0], "") if prefix_emoji + end + end + end + end +end diff --git a/slices/admin/templates/merge_tags/new.html.slim b/slices/admin/templates/merge_tags/new.html.slim index cd58755..b7f1004 100644 --- a/slices/admin/templates/merge_tags/new.html.slim +++ b/slices/admin/templates/merge_tags/new.html.slim @@ -2,14 +2,14 @@ div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark: h1 Admin // Merge Tags div class="max-w-prose mx-auto prose dark:prose-invert" - h3 Pick a tag to merge in to #{tag.label} + h3 Pick a tag to merge in to "#{post_tag.label}" form action="/admin/tags/merge" method="POST" - input type="hidden" name="target_id" value=tag.id + input type="hidden" name="target_id" value=post_tag.id div class="mb-4" select class="text-gray-800" name="source_id" - - tags.each do |source_tag| + - post_tags.each do |source_tag| option value=source_tag.id = source_tag.label div class="mb-4" diff --git a/slices/admin/views/merge_tags/new.rb b/slices/admin/views/merge_tags/new.rb index 3ea40ac..02ad93a 100644 --- a/slices/admin/views/merge_tags/new.rb +++ b/slices/admin/views/merge_tags/new.rb @@ -4,11 +4,11 @@ module Admin class New < Admin::View include Deps["repos.tag_repo"] - expose :tag do |id:| + expose :post_tag do |id:| tag_repo.fetch(id) end - expose :tags do |id:| + expose :post_tags do |id:| tag_repo.list.reject { |t| t.id.to_s == id.to_s } end end diff --git a/slices/admin/views/trips/show.rb b/slices/admin/views/trips/show.rb index 060fe74..a151b5f 100644 --- a/slices/admin/views/trips/show.rb +++ b/slices/admin/views/trips/show.rb @@ -16,7 +16,7 @@ module Admin expose :posts do |trip| post_repo.created_between(trip.start_date, trip.end_date).map do |post| - Adamantium::Decorators::Posts::Decorator.new(post) + Admin::Decorators::Posts::Decorator.new(post) end end end