Refactor app in to its own slice

This commit is contained in:
2024-02-17 10:40:36 +11:00
parent b809b132d3
commit a6078f882e
161 changed files with 16176 additions and 193 deletions

View File

View File

@@ -1,15 +0,0 @@
require "time_math"
module Adamantium
module Actions
module Blogroll
class Index < Action
include Deps["views.blogroll.index"]
def handle(req, res)
res.render index
end
end
end
end
end

View File

@@ -1,15 +0,0 @@
require "time_math"
module Adamantium
module Actions
module Blogroll
class List < Action
include Deps["views.blogroll.list"]
def handle(req, res)
res.body = cache(key: "blogroll", content_proc: -> { list.call.to_str }, expiry: TimeMath.min.advance(Time.now, +60))
end
end
end
end
end

View File

@@ -1,16 +0,0 @@
require "time_math"
module Adamantium
module Actions
module Blogroll
class Opml < Action
include Deps["views.blogroll.opml"]
def handle(req, res)
res.content_type = "text/xml; charset=utf-8"
res.render opml, format: :xml
end
end
end
end
end

View File

@@ -1,13 +0,0 @@
module Adamantium
module Actions
module Bookmarks
class Index < Action
include Deps["views.bookmarks.index"]
def handle(req, res)
res.render index, query: req.params[:q]
end
end
end
end
end

View File

@@ -1,13 +0,0 @@
module Adamantium
module Actions
module Bookmarks
class Metadata < Action
include Deps["views.bookmarks.metadata"]
def handle(req, res)
res.render metadata, id: req.params[:id]
end
end
end
end
end

View File

@@ -1,12 +0,0 @@
module Adamantium
module Actions
module Bookmarks
class Show < Action
include Deps["views.bookmarks.show"]
def handle(req, res)
res.render show, slug: req.params[:slug]
end
end
end
end
end

View File

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

View File

@@ -1,14 +0,0 @@
module Adamantium
module Actions
module Feeds
class Rss < Action
include Deps["views.feeds.rss"]
def handle(req, res)
res.content_type = "text/xml; charset=utf-8"
res.render rss, format: :xml
end
end
end
end
end

View File

@@ -1,14 +0,0 @@
module Adamantium
module Actions
module Feeds
class StatusesRss < Action
include Deps["views.feeds.statuses_rss"]
def handle(req, res)
res.content_type = "text/xml; charset=utf-8"
res.render statuses_rss, format: :xml
end
end
end
end
end

View File

@@ -1,13 +0,0 @@
module Adamantium
module Actions
module Key
class Show < Action
include Deps["settings"]
def handle(req, res)
res.content_type = "text/plain"
res.body = settings.micropub_pub_key
end
end
end
end
end

View File

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

View File

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

View File

@@ -1,16 +0,0 @@
module Adamantium
module Actions
module Pages
class Show < Action
include Deps["views.pages.show"]
def handle(req, res)
slug = req.params[:slug]
res.status = File.exist?("app/content/pages/#{slug}.md") ? 200 : 404
res.render show, slug: slug
end
end
end
end
end

View File

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

View File

@@ -1,13 +0,0 @@
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

View File

@@ -1,13 +0,0 @@
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

@@ -1,13 +0,0 @@
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

View File

@@ -1,15 +0,0 @@
module Adamantium
module Actions
module Posts
class Archive < Action
include Deps["views.posts.archive"]
def handle(req, res)
year = req.params[:year]
res.render archive, year: year
end
end
end
end
end

View File

@@ -1,12 +0,0 @@
module Adamantium
module Actions
module Posts
class Index < Action
include Deps["views.posts.index"]
def handle(req, res)
res.render index, query: req.params[:q]
end
end
end
end
end

View File

@@ -1,15 +0,0 @@
module Adamantium
module Actions
module Posts
class Show < Action
include Deps["views.posts.show"]
def handle(req, res)
slug = req.params[:slug]
res.render show, slug: slug
end
end
end
end
end

View File

@@ -1,25 +0,0 @@
module Adamantium
module Actions
module Posts
class TopTracks < Action
include Deps["views.posts.top_tracks", query: "queries.posts.top_tracks"]
def handle(req, res)
res.content_type = "Application/JSON"
res.status = 200
tracks = query.call(slug: req.params[:slug])
track = if tracks.is_a? Array
tracks.first
else
tracks
end
if track
res.render top_tracks, track: track
end
end
end
end
end
end

View File

@@ -1,15 +0,0 @@
require "time_math"
module Adamantium
module Actions
module RecentlyPlayed
class Index < Action
include Deps["views.recently_played.index"]
def handle(req, res)
res.body = cache(key: "recently_played", content_proc: -> { index.call.to_str })
end
end
end
end
end

View File

@@ -1,12 +0,0 @@
module Adamantium
module Actions
module Site
class Home < Action
include Deps["views.site.home"]
def handle(req, res)
res.render home
end
end
end
end
end

View File

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

View File

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

View File

@@ -1,15 +0,0 @@
module Adamantium
module Actions
module Tags
class Show < Action
include Deps["views.tags.show"]
def handle(req, res)
slug = req.params[:slug]
res.render show, slug: slug
end
end
end
end
end

View File

@@ -1,19 +0,0 @@
module Adamantium
module Actions
module Timemachine
class Show < Action
include Deps["views.timemachine.show"]
def handle(req, res)
year, month, day = [
req.params[:year],
req.params[:month],
req.params[:day]
]
res.render show, year: year, month: month, day: day
end
end
end
end
end

View File

@@ -1,12 +0,0 @@
# frozen_string_literal: true
module Adamantium
module Actions
module Trips
class Index < Adamantium::Action
def handle(req, res)
end
end
end
end
end

View File

@@ -1,15 +0,0 @@
# frozen_string_literal: true
module Adamantium
module Actions
module Trips
class Show < Adamantium::Action
include Deps["views.trips.show"]
def handle(req, res)
res.render show, id: req.params[:id]
end
end
end
end
end

View File

@@ -1,33 +0,0 @@
module Adamantium
module Actions
module Workouts
class Create < Action
include Deps["geo.gpx_parser", "commands.workouts.create"]
def handle(req, res)
tempfile = Tempfile.new(%w[path .gpx])
if !req.params.to_h.dig(:file, :tempfile).nil?
tempfile.write req.params[:file][:tempfile].read
else
tempfile.write req.params[:file]
end
tempfile.rewind
gpxfile = gpx_parser.call(path: tempfile.path)
if gpxfile.success?
create.call(**gpxfile.value!)
res.status = 201
else
res.status = 500
end
ensure
tempfile.close
tempfile.unlink
end
end
end
end
end

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,100 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@tailwind typography;
@font-face {
font-family: "Montagu";
src: url("../fonts/MontaguSlab-VariableFont_opsz,wght.ttf") format("truetype");
font-display: swap;
}
@font-face {
font-family: "JetBrainsMono";
src: url("../fonts/JetBrainsMono-VariableFont_wght.ttf") format("truetype");
font-display: swap;
}
@font-face {
font-family: "Figtree";
src: url("../fonts/Figtree-VariableFont_wght.ttf") format("truetype");
font-display: swap;
}
* {
font-family: "Figtree", Helvetica, Arial, sans-serif;
}
h1, h2, h3, h4, h5, h6, h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
font-family: "Montagu", Times New Roman, serif;
}
.prose h1 a {
border-bottom: none;
text-decoration: none;
}
.prose h1 a:hover {
opacity: 0.8;
}
.gist tr {
border-bottom: none;
}
.gist span, pre, pre span {
font-family: "JetBrainsMono", Monaco, monospace;
}
.map-marker {
border: 3px solid blue;
border-radius: 8px;
background: RGBa(0, 0, 255, 0.1);
width: 14px;
height: 14px;
}
.prose pre code::before {
padding-left: unset
}
.prose pre code:after {
padding-right: unset
}
.prose code {
font-weight: 400;
border-radius: 0.25rem;
}
.prose code:before {
content: "";
padding: 0 0 0 0.25rem;
}
.prose pre {
padding: 0;
}
.prose code:after {
content: "";
padding: 0 0.25rem 0 0;
}
.video-container {
position: relative;
padding-bottom: 56.25%; /* 16:9 */
height: 0;
}
.video-container iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 8px;
}
.squircle {
clip-path: url(#squircleClip);
}

View File

@@ -1,76 +0,0 @@
import { md_gallery } from "./gallery.js";
(function() {
document.addEventListener("DOMContentLoaded", function () {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
localStorage.setItem("_x_darkMode", event.matches ? true : false)
});
if (window.hljs !== undefined) {
window.hljs.highlightAll();
}
const times = document.querySelectorAll('time');
times.forEach((time) => {
const oldDtime = Date.parse(time.dateTime);
time.innerHTML = new Date(oldDtime).toLocaleDateString(navigator.language, { weekday:"long", year:"numeric", month:"short", day:"numeric"});
md_gallery({
"class_name": "grid gap-4 grid-cols-2 prose-img:m-0"
});
const mediaForm = document.getElementById("media_form");
if (mediaForm !== null) {
htmx.on('#media_form', 'htmx:xhr:progress', function (evt) {
htmx.find('#progress').setAttribute('value', evt.detail.loaded / evt.detail.total * 100)
});
}
});
const videos = document.querySelectorAll('video');
videos.forEach((video) => {
video.addEventListener("click", () => {
const isPaused = video.paused;
video[isPaused ? "play" : "pause"]();
video.classList.toggle("u-none", !isPaused);
});
});
const mapContainer = document.getElementById("map");
const goBack = document.getElementById("go-back");
if (mapContainer !== null) {
if (goBack !== null) {
document.getElementById("go-back").addEventListener("click", () => {
history.back();
});
}
mapboxgl.accessToken = 'pk.eyJ1IjoiZG5pdHphIiwiYSI6ImNsZWIyY3ZzaTE0cjUzdm4xdnZ6czRlYjUifQ.FRETOXYRID6T2IoB7qqRLg';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
maxZoom: 8
});
const markers = JSON.parse(mapContainer.dataset["markers"]);
const bounds = new mapboxgl.LngLatBounds(markers[0], markers[0]);
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);
}
}
});
})();

View File

@@ -1,103 +0,0 @@
/*
Markdown Gallery
-- v1.0 2016
-- Created by Lee Penney
-- Released under GPLv3
*/
export function md_gallery(config) {
var config = config || {},
list_type = config.list_type || 'ul',
class_name = config.class_name || 'gallery',
tag_type = config.tag_type || 'div';
function find_lists(list_type) {
var lists = document.getElementsByTagName(list_type), matching_lists = [];
for (var i = 0; i < lists.length; i++) {
var list_elements = lists[i].children;
var total_matches = 0;
for (var c = 0; c < list_elements.length; c++) {
if (!list_elements[c].textContent.length && (list_elements[c].firstChild.tagName == 'A' || list_elements[c].firstChild.tagName == 'IMG') && (!list_elements[c].firstChild.firstChild || (list_elements[c].firstChild.firstChild && list_elements[c].firstChild.firstChild.tagName == 'IMG') )) {
total_matches++;
}
}
if (total_matches == list_elements.length) {
matching_lists[matching_lists.length] = lists[i];
}
}
return matching_lists;
}
function prepend_tag(img_lists, list_tag, prepend_tag, class_name) {
for (var i = 0; i < img_lists.length; i++) {
// add_figure_tags(img_lists[i]);
add_anchor(img_lists[i]);
wrap_tag(img_lists[i], prepend_tag, class_name, null, true);
strip_tag(img_lists[i], 'li');
strip_tag(img_lists[i].parentNode, list_tag);
}
}
function append_caption(el) {
if ((el.tagName == 'A' && el.firstChild.tagName == 'IMG' && el.firstChild.hasAttribute('alt') && el.firstChild.getAttribute('alt').length > 0) || (el.tagName == 'IMG' && el.hasAttribute('alt') && el.getAttribute('alt').length > 0)) {
var caption = document.createElement('figcaption');
try {
caption.textContent = el.firstChild.getAttribute('alt')
el.appendChild(caption);
} catch (e) {
caption.textContent = el.getAttribute('alt');
el.parentNode.appendChild(caption);
}
}
}
function strip_tag(el, tag_type) {
var start_tag_regex = new RegExp('<'+tag_type+'>', 'gi');
var end_tag_regex = new RegExp('<\/'+tag_type+'>', 'gi');
el.innerHTML = el.innerHTML.replace(start_tag_regex,'').replace(end_tag_regex,'');
}
function add_figure_tags(img_list) {
var list_elements = img_list.children;
for (var i = 0; i < list_elements.length; i++) {
append_caption(list_elements[i].firstChild);
wrap_tag(list_elements[i], 'figure');
}
}
function add_anchor(img_list) {
var list_elements = img_list.children;
for (var i = 0; i < list_elements.length; i++) {
let img = list_elements[i].getElementsByTagName('img')[0];
let src = img.getAttribute("src");
let alt = img.getAttribute("alt");
wrap_tag(list_elements[i],
'a',
'hover:cursor-pointer',
"$dispatch('img-modal', { imgModalSrc: '" + src + "', imgModalDesc: '" + alt + "' })",
false
);
}
}
function wrap_tag(el, tag_type, class_name, click, root) {
var wrap = document.createElement(tag_type);
if (root) {
wrap.setAttribute('x-data', "{}");
}
if (class_name) {
wrap.setAttribute('class', class_name);
}
if (click) {
wrap.setAttribute('x-on:click.prevent', click);
wrap.setAttribute('href', '#');
}
el.parentNode.replaceChild(wrap, el);
wrap.appendChild(el);
}
var found_img_lists = find_lists(list_type);
if (found_img_lists.length) {
prepend_tag(found_img_lists, list_type, tag_type, class_name);
}
}

View File

View File

@@ -1,4 +0,0 @@
Hi! 👋 I'm Daniel, a software engineer living in Canberra, Australia.
Welcome to my personal site! This is where I post the things I have [written](/posts), the [photos](/photos) I have taken, the [bookmarks](/bookmarks) I have saved, the [places](/places) I have been, and a whole bunch [more](/more).

View File

@@ -1,56 +0,0 @@
# frozen_string_literal: false
# auto_register: false
module Adamantium
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
"<div class='video-container'><iframe width='100%' src='https://www.youtube.com/embed/#{code}' title='YouTube video player' frameborder='0' allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share' allowfullscreen></iframe></div>"
end
end
end
end
end
end

View File

@@ -1,53 +0,0 @@
# frozen_string_literal: false
# auto_register: false
module Adamantium
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

View File

@@ -1,21 +0,0 @@
# frozen_string_literal: false
# auto_register: false
module Adamantium
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

View File

@@ -1,178 +0,0 @@
# frozen_string_literal: false
# auto_register: false
require "rexml/parsers/pullparser"
require "sanitize"
require "nokogiri"
module Adamantium
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
doc = Nokogiri::HTML(content)
images = doc.at("//img")
images.first[1] if images
end
def prefix_emoji
if name
""
elsif photos? && content == ""
"📷"
else
"💬"
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? ? "<div>#{photos.map { |p| "<img src='#{p["value"]}'/>" }.join("")} #{content}</div>" : content
end
def raw_content
Sanitize.fragment(content)
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
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 << "</#{tags.pop}>"
when :text
results << p_e[0][0..new_len]
new_len -= p_e[0].length
else
results << "<!-- #{p_e.inspect} -->"
end
end
if at_end
results << "..."
end
tags.reverse_each do |tag|
results << "</#{tag}>"
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

View File

View File

@@ -1,30 +0,0 @@
require "httparty"
module Adamantium
module Queries
module Blogroll
class Index
include Deps["settings"]
def call
resp = HTTParty.get("https://#{settings.rss_url}/api/greader.php/reader/api/0/subscription/list?output=json", {
headers: {
"Authorization" => "GoogleLogin auth=#{auth_token}"
}
})
resp.body
end
private
def auth_token
auth_url = "https://#{settings.rss_url}/api/greader.php/accounts/ClientLogin?Email=#{settings.rss_username}&Passwd=#{settings.rss_password}"
resp = HTTParty.get(auth_url)
auth = resp.match(/SID=(.*)/)
auth[1].strip
end
end
end
end
end

View File

@@ -1,43 +0,0 @@
require "httparty"
require "jwt"
module Adamantium
module Queries
module Posts
class RecentlyPlayed
include Deps["settings"]
def call
resp = HTTParty.get("https://api.music.apple.com/v1/me/recent/played", {
headers: {
"Authorization" => "Bearer #{jwt}",
"Music-User-Token" => settings.apple_music_user_token
}
})
resp.body
end
private
def jwt
authentication_payload = {
iss: settings.apple_music_team,
iat: Time.now.to_i, # Issue date
exp: Time.now.to_i + 3600 # Expiry of this token.
}
# The file we got from Apple
apple_music_secret = File.read(File.join(Hanami.app.root, "config", "AuthKey_#{settings.apple_music_key}.p8"))
private_key = OpenSSL::PKey::EC.new(apple_music_secret)
JWT.encode(
authentication_payload,
private_key,
"ES256",
kid: settings.apple_music_key
)
end
end
end
end
end

View File

@@ -1,41 +0,0 @@
require "lastfm"
require "time_math"
module Adamantium
module Queries
module Posts
class TopTracks
include Deps["settings", "repos.post_repo", "repos.top_track_repo"]
def call(slug:)
ENV["TZ"] = "Australia/Melbourne"
post = post_repo.fetch!(slug)
start_date = TimeMath.week.floor(post.published_at).to_i
end_date = TimeMath.week.ceil(post.published_at).to_i
top_tracks = top_track_repo.for_post(id: post.id)
return top_tracks unless top_tracks.empty?
lastfm = Lastfm.new(settings.lastfm_api_key, settings.lastfm_secret)
tracks = lastfm.user.get_weekly_track_chart(user: "dNitza", from: start_date, to: end_date)
track = if tracks.is_a? Array
tracks.first
else
tracks
end
if track
mb_id = (track["mbid"] == {}) ? "unknown" : track["mbid"]
top_track_repo.upsert(post_id: post.id, name: track["name"], artist: track.dig("artist", "content"), url: track["url"], mb_id: mb_id)
end
ENV["TZ"] = nil
top_track_repo.for_post(id: post.id)
end
end
end
end
end

View File

@@ -1,31 +0,0 @@
module Adamantium
module Repos
class MovieRepo < Adamantium::Repo[:movies]
def listing
movies.order(Sequel.lit("year desc")).to_a
end
def by_title_and_year(title:, year:)
movies.where(title: title, year: year).one
end
def from_the_archives(start_date:, end_date:)
# SELECT * FROM posts
# WHERE EXTRACT(month FROM "published_at") >= 2
# WHERE EXTRACT(month FROM "published_at") <= 2+
# AND EXTRACT(day FROM "published_at") > 20
# AND EXTRACT(day FROM "published_at") < 27
# AND post_type = 'post';
movies
.where { Sequel.extract(:year, :watched_at) >= start_date.year }
.where { Sequel.extract(:year, :watched_at) <= start_date.year }
.where { Sequel.extract(:month, :watched_at) >= start_date.month }
.where { Sequel.extract(:month, :watched_at) <= end_date.month }
.where { Sequel.extract(:day, :watched_at) >= start_date.day }
.where { Sequel.extract(:day, :watched_at) <= end_date.day }
.to_a
end
end
end
end

View File

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

View File

@@ -1,26 +0,0 @@
module Adamantium
module Repos
class PodcastScrobbleRepo < Adamantium::Repo[:podcast_scrobbles]
commands :create
def exists?(id:)
!!podcast_scrobbles
.where(overcast_id: id)
.one
end
def listing
podcast_scrobbles
.order(Sequel.desc(:listened_at))
.limit(5)
.to_a
end
def for_timemachine(date:)
podcast_scrobbles
.where(listened_at: TimeMath.day.floor(date)...TimeMath.day.advance(date, +1))
.to_a
end
end
end
end

View File

@@ -1,223 +0,0 @@
module Adamantium
module Repos
class PostRepo < Adamantium::Repo[:posts]
Sequel.extension :pg_json
Sequel.extension :pg_json_ops
def by_year(year:)
posts
.where(post_type: "post", location: nil)
.exclude(name: nil)
.published
.where { Sequel.&(Sequel.extract(:year, :published_at) =~ year) }
.combine(:tags)
.to_a
end
def week_posts(limit: nil)
posts
.where(post_type: "post")
.weekly
.published
.combine(:tags)
.order(Sequel.desc(:published_at))
.limit(limit)
.to_a
end
def post_listing(limit: nil)
posts
.where(post_type: "post", location: nil)
.exclude(name: nil)
.published
.combine(:tags)
.order(Sequel.desc(:published_at))
.limit(limit)
.to_a
end
def home_post_listing(limit: nil)
posts
.where(post_type: "post", location: nil)
.exclude(name: nil)
.non_weekly
.published
.combine(:tags)
.order(Sequel.desc(:published_at))
.limit(limit)
.to_a
end
def photo_listing(limit: nil)
posts
.where(post_type: ["post", "checkin"])
.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: ["checkin", "post"])
.exclude(location: nil)
.published
.combine(:tags)
.order(Sequel.desc(:published_at))
.limit(limit)
.to_a
end
def books_listing(limit: nil)
posts
.where(post_type: "book")
.published
.order(Sequel.asc(:name))
.limit(limit)
.to_a
end
def bookmark_listing(query: nil)
base = posts
.where(post_type: "bookmark")
.published
.combine(:tags)
.order(Sequel.desc(:published_at))
query ? base.where(Sequel.ilike(:name, "%#{query}%")).to_a : base.to_a
end
def statuses_listing(limit: nil)
posts
.where(post_type: "post", name: nil)
.exclude(Sequel.pg_jsonb_op(:syndication_sources).has_key?("instagram"))
.published
.combine(:tags, :webmentions)
.node(:webmentions) { |webmention|
webmention.published.where(type: "reply")
}
.order(Sequel.desc(:published_at))
.limit(limit)
.to_a
end
def latest_status
posts
.where(name: nil)
.published
.order(Sequel.desc(:published_at))
.limit(1)
.one
end
def last_location
posts
.where(post_type: "checkin")
.published
.order(Sequel.desc(:published_at))
.limit(1)
.one
end
def from_the_archives(start_date:, end_date:)
# SELECT * FROM posts
# WHERE EXTRACT(month FROM "published_at") >= 2
# WHERE EXTRACT(month FROM "published_at") <= 2+
# AND EXTRACT(day FROM "published_at") > 20
# AND EXTRACT(day FROM "published_at") < 27
# AND post_type = 'post';
posts
.where(post_type: "post")
.published
.where { Sequel.extract(:year, :published_at) < start_date.year }
.where { Sequel.extract(:month, :published_at) >= start_date.month }
.where { Sequel.extract(:month, :published_at) <= end_date.month }
.where { Sequel.extract(:day, :published_at) >= start_date.day }
.where { Sequel.extract(:day, :published_at) <= end_date.day }
.to_a
end
def posts_for_timemachine(date:)
posts
.where(post_type: "post")
.where(published_at: TimeMath.day.floor(date)...TimeMath.day.advance(date, +1))
.to_a
end
def bookmarks_for_timemachine(date:)
posts
.where(post_type: "bookmark")
.where(published_at: TimeMath.day.floor(date)...TimeMath.day.advance(date, +1))
.to_a
end
def all_posts
posts
.where(post_type: ["post", "bookmark"])
.published
.order(Sequel.desc(:published_at))
.to_a
end
def for_rss
posts
.where(post_type: ["post", "bookmark"], location: nil)
.exclude(name: nil)
.published
.combine(:tags)
.order(Sequel.desc(:published_at))
.to_a
end
def statuses_for_rss
posts
.where(post_type: "post", name: nil, location: nil)
.published
.combine(:tags)
.order(Sequel.desc(:published_at))
.to_a
end
def fetch!(slug)
posts
.published
.combine(:tags, :trips, :webmentions)
.node(:webmentions) { |webmention|
webmention.published.where(type: "reply")
}
.where(slug: slug)
.one!
end
def find!(id)
posts
.by_pk(id)
.one!
end
def post_years
posts
.where(post_type: "post", location: nil)
.exclude(name: nil)
.published
.dataset
.group_and_count(Sequel.extract(:year, :published_at).as(:year))
.order(:year)
.to_a
end
def search(term:)
posts
.where(post_type: "post", location: nil)
.published
.search(term: term)
.combine(:tags)
.order(Sequel.desc(:published_at))
.to_a
end
end
end
end

View File

@@ -1,26 +0,0 @@
module Adamantium
module Repos
class PostTagRepo < Adamantium::Repo[:post_tags]
def posts_tagged(tag:)
tag_id = post_tags
.tags
.where(slug: tag)
.one!
.id
post_ids = post_tags
.where(tag_id: tag_id)
.to_a
.map(&:post_id)
post_tags
.posts
.where(id: post_ids)
.published
.combine(:tags)
.order(Sequel.desc(:published_at))
.to_a
end
end
end
end

View File

@@ -1,16 +0,0 @@
module Adamantium
module Repos
class TagRepo < Adamantium::Repo[:tags]
def fetch!(slug)
tags.where(slug: slug).one!
end
def list
tags
.order(Sequel.function(:lower, :label))
.combine(:posts)
.to_a
end
end
end
end

View File

@@ -1,17 +0,0 @@
module Adamantium
module Repos
class TopTrackRepo < Adamantium::Repo[:top_tracks]
def for_post(id:)
top_tracks
.where(post_id: id)
.to_a
end
def upsert(post_id:, name:, artist:, url:, mb_id:)
top_tracks
.upsert({name: name, artist: artist, url: url, mb_id: mb_id, post_id: post_id},
{target: :post_id, update: {name: name, artist: artist, url: url, mb_id: mb_id, post_id: post_id}})
end
end
end
end

View File

@@ -1,20 +0,0 @@
module Adamantium
module Repos
class TripRepo < Adamantium::Repo[:trips]
def fetch!(id)
trips
.where(id: id)
.combine(posts: :tags)
.one!
end
def list
trips
.published
.order(:start_date)
.reverse
.to_a
end
end
end
end

View File

@@ -1,9 +0,0 @@
module Adamantium
module Repos
class WorkoutRepo < Adamantium::Repo[:workouts]
def list
workouts.order(:published_at).to_a
end
end
end
end

View File

@@ -1,23 +0,0 @@
- context.content_for(:title, "")
- context.content_for(:highlight_code, false)
article class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200 prose-em:font-bold prose-em:not-italic prose-em:bg-blue-600 prose-em:px-1 prose-em:rounded prose-a:text-blue-600 prose-a:dark:text-indigo-300 prose-a:p-0.5 prose-a:rounded-sm prose-a:no-underline hover:prose-a:underline prose-em:text-blue-100"
h1 Hello world
/ # PatternMate
/
/ ## Features
/
/ ### Accessibility
/
/ ### Paid features
/
/ ## Who is this app for?
/
/ ## Why did I build it?
/
/ ## Pricing
/
div class="max-w-screen-md mx-auto border-t border-solid border-gray-200 dark:border-gray-600"

View File

@@ -1,11 +0,0 @@
- context.content_for(:title, "Blogroll | ")
div class="mb-4 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
h1 Blogroll
div class="h-feed mb-12 max-w-prose mx-auto prose dark:prose-invert"
p Here's the list of all the sites & blogs I enjoy reading, taken directly from my RSS aggregator!
p
a href="/blogroll/opml" Get the OPML
div class="grow" hx-get="/blogroll/list" hx-trigger="load"

View File

@@ -1,13 +0,0 @@
- blogroll.each do |blog|
div class="flex mb-4"
img loading="lazy" class="w-8 h-8 rounded mx-0 my-0 mr-4" src=blog[:icon]
div
div
= "#{blog[:title]} — ("
a href=blog[:url] RSS
= " | "
a href=blog[:html_url] Website
= ")"
div
small Categories:
small = " #{blog[:categories].join(",")}"

View File

@@ -1,16 +0,0 @@
# xml.instruct! "xml-stylesheet", {href: "/assets/style.xslt", type: "text/xsl"}
xml.opml("xmlns:frss" => "https://freshrss.org/opml", version: "2.0") do
xml.head do |head|
head.title "Daniel Nitsikopoulos's RSS subscriptions"
head.link "https://dnitza.com/blogroll/opml"
head.lastBuildDate Time.now.rfc2822
head.pubDate Time.now.rfc2822
head.ttl 1800
end
xml.body do
blogroll.each do |blog|
xml.outline(text: blog[:title], type: "rss", xmlUrl: blog[:url], htmlUrl: blog[:html_url])
end
end
end

View File

@@ -1,22 +0,0 @@
- context.content_for(:title, "Bookmarks | ")
div class="flex justify-between prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
div
h1 Bookmarks
div class="h-feed mb-12 max-w-prose mx-auto"
form action="/bookmarks" method="GET"
div class="flex"
div class="flex-auto basis-auto mr-4"
input id="search" type="text" class="p-1 rounded w-full bg-indigo-50 dark:bg-indigo-400" name="q" value=q
div class="mr-4"
input type="submit" class="bg-indigo-300 p-1 rounded text-indigo-900" value="Search"
-if q
div class=""
a href="/bookmarks" class="text-gray-400 dark:text-gray-100 pt-1" Clear search
div class="mb-12 max-w-prose mx-auto"
- bookmarks.each do |bookmark|
== render "shared/bookmark", bookmark: bookmark
div class="max-w-screen-md mx-auto border-t border-solid border-gray-200 dark:border-gray-600"

View File

@@ -1,7 +0,0 @@
- if image
div class="col-span-1"
img class="rounded h-16" src=image
div class="#{image ? 'col-span-4' : 'col-span-5'}"
h6= title
small= description

View File

@@ -1,45 +0,0 @@
- context.content_for(:title, "Bookmark | ")
div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
h1 = bookmark.name
div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200" x-data="{ open: false }"
a class="text-blue-600 dark:text-amber-500 no-underline hover:underline" href=bookmark.url
p class="text-xl text-ellipsis overflow-hidden"
= bookmark.url
div class="mb-6"
== bookmark.youtube_embed
== bookmark.content
- unless bookmark.cached_content.nil?
button class="hover:text-gray-400" @click="open = ! open" Toggle cached version
span x-show="open"
div class="mt-4 rounded bg-blue-50 dark:bg-blue-900 px-4 py-2"
== bookmark.cached_content
div class="prose max-w-prose mx-auto text-gray-800 dark:text-gray-200 grid grid-cols-5 gap-2" hx-get="/bookmarks/metadata/#{bookmark.id}" hx-trigger="load"
div class="mb-8 max-w-screen-md mx-auto border-t border-solid border-gray-200 dark:border-gray-600"
div class="max-w-prose mx-auto text-gray-600 dark:text-gray-200 flex"
div class=""
= "Published "
time class="dt-published" datetime=bookmark.machine_published_at
= bookmark.display_published_at
p
span in&nbsp;
a class="hover:underline" href="/bookmarks" bookmarks
span class="text-right flex-1"
== render "shared/tags", tags: bookmark.tags
div class="mb-2 max-w-prose mx-auto text-gray-600 dark:text-gray-200 flex"
- if bookmark.syndicated?
span Also on: &nbsp;
- bookmark.syndicated_to.each do |loc|
a href=loc[:url]
== "shared/#{render loc[:location]}"

View File

@@ -1,44 +0,0 @@
- context.content_for(:title, "Books | ")
div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
h1 📚 Bookshelf
div class="mb-12 prose dark:prose-invert max-w-prose mx-auto"
table class="text-gray-800 dark:text-white table-auto"
thead
tr
td
td class="p-2" Title
td class="p-2" Author(s)
- reading.each do |book|
tr
td
div class="rounded-md uppercase text-xs #{book.status_colour} px-2 w-full text-center"
= book.status_label
td
a href="/post/#{book.slug}"
= book.name
td
= book.authors
- to_read.each do |book|
tr
td
div class="rounded-md uppercase text-xs #{book.status_colour} px-2 w-full text-center"
= book.status_label
td
a href="/post/#{book.slug}"
= book.name
td
= book.authors
- read.each do |book|
tr
td
div class="rounded-md uppercase text-xs #{book.status_colour} px-2 w-full text-center"
= book.status_label
td
a href="/post/#{book.slug}"
= book.name
td
= book.authors
div class="max-w-screen-md mx-auto border-t border-solid border-gray-200 dark:border-gray-600"

View File

@@ -1,35 +0,0 @@
xml.instruct! "xml-stylesheet", {href: "/assets/style.xslt", type: "text/xsl"}
xml.channel do |channel|
channel.title "Daniel Nitsikopoulos"
channel.description "The personal blog of Daniel Nitsikopoulos, software engineer from Canberra, ACT"
channel.link "https://dnitza.com"
channel.name "dnitza.com"
channel.lastBuildDate Time.now.rfc2822
channel.pubDate Time.now.rfc2822
channel.ttl 1800
channel.alternate_feed do |item|
item.link "/feeds/rss"
item.title "Main feed (this feed)"
item.description "Containing longer text posts and bookmarks"
end
channel.alternate_feed do |item|
item.link "/feeds/statuses_rss"
item.title "Statuses / Microblog"
item.description "Only shorter posts and photo posts, usually also appearing on Mastodon"
end
posts.each do |post|
channel.item do |item|
item.title post.display_title
item.description do |desc|
desc.cdata! post.feed_content
end
item.link(post.permalink)
item.guid(post.slug, isPermaLink: true)
item.pubDate post.machine_published_at
end
end
end

View File

@@ -1,35 +0,0 @@
xml.instruct! "xml-stylesheet", {href: "/assets/style.xslt", type: "text/xsl"}
xml.channel do |channel|
channel.title "Daniel Nitsikopoulos"
channel.description "The personal blog of Daniel Nitsikopoulos, software engineer from Canberra, ACT"
channel.link "https://dnitza.com"
channel.name "dnitza.com"
channel.lastBuildDate Time.now.rfc2822
channel.pubDate Time.now.rfc2822
channel.ttl 1800
channel.alternate_feed do |item|
item.link "/feeds/rss"
item.title "Main feed"
item.description "Containing longer text posts and bookmarks"
end
channel.alternate_feed do |item|
item.link "/feeds/statuses_rss"
item.title "Statuses / Microblog (this feed)"
item.description "Only shorter posts and photo posts, usually also appearing on Mastodon"
end
posts.each do |post|
channel.item do |item|
item.title post.raw_content
item.description do |desc|
desc.cdata! post.feed_content
end
item.link(post.permalink)
item.guid(post.slug, isPermaLink: true)
item.pubDate post.machine_published_at
end
end
end

View File

@@ -1,78 +0,0 @@
doctype html
html x-data="{darkMode: $persist(false)}" :class="{'dark' : darkMode === true}"
head
meta charest="utf-8"
meta name="viewport" content="width=device-width, initial-scale=1.0"
meta name="theme-color" content="#2563eb" media="(prefers-color-scheme: light)"
meta name="theme-color" content="#1e1b4b" media="(prefers-color-scheme: dark)"
title #{context.content_for(:title)} #{Hanami.app.settings.site_name}
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="#{Hanami.app.settings.micropub_site_url}/statuses"
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="alternate" type="text/mf2+html" href="#{Hanami.app.settings.micropub_site_url}/statuses"
link rel="me" href=Hanami.app.settings.mastodon_url
link rel="me" href=Hanami.app.settings.github_url
link rel="me" href=Hanami.app.settings.fed_bridge_url
= stylesheet_tag "app"
link rel="icon" type="image/x-icon" href="/assets/favicon.ico"
script data-domain="dnitza.com" src="https://stats.dnitza.com/js/script.js" defer=""
script src="https://unpkg.com/htmx.org@1.9.2/dist/htmx.min.js" integrity="sha384-L6OqL9pRWyyFU3+/bjdSri+iIphTN/bvYyM37tICVyOJkWZLpP2vGn6VUEXgzg6h" crossorigin="anonymous"
script src="https://cdn.jsdelivr.net/npm/@alpinejs/persist@3.13.3/dist/cdn.min.js"
= javascript_tag "app"
script src="https://cdn.jsdelivr.net/npm/alpinejs@3.13.3/dist/cdn.min.js" defer=""
link rel="stylesheet" href="https://unpkg.com/@highlightjs/cdn-assets@11.8.0/styles/github-dark.min.css"
script src="https://unpkg.com/@highlightjs/cdn-assets@11.8.0/highlight.min.js" defer=""
meta property="og:title" content="#{context.content_for(:title)}"
meta property="og:type" content="website"
meta property="og:url" content="#{context.content_for(:url)}"
- if context.content_for(:image)
meta property="og:image" content="#{context.content_for(:image)}"
- if Hanami.app.settings.micropub_pub_key
link rel="pgpkey" href="/key"
body class="transition-colors bg-white dark:bg-indigo-950 selection:bg-blue-100 selection:text-blue-900 dark:selection:bg-amber-600 dark:selection:text-amber-400" x-data="{ imgModal : false, imgModalSrc : '', imgModalDesc : '' }" x-on:keydown.escape="imgModal=false"
main class="pb-8 px-4 pt-4 md:pt-8"
header class="mb-12 max-w-screen-md mx-auto items-center md:items-justify"
div class="flex mb-8 md:mb-12 text-lg md:text-xl text-gray-400 dark:text-gray-600 grid grid-cols-1 md:grid-cols-2"
div class="flex-none mx-auto md:flex-auto md:mx-0"
div class="h-card flex items-center"
img class="u-photo w-6 h6 md:w-10 md:h-10 mr-1" alt="Memoji profile picture" src="/assets/memoji.png"
a href="/" rel="me" class="u-url u-uid"
h1 class="p-name text-sm md:text-sm text-gray-600 dark:text-gray-400" = Hanami.app.settings.site_name
nav class="space-x-1 text-sm md:text-sm mx-auto md:flex-auto uppercase md:block mt-4 md:mt-3"
- pages.each do |page|
a class="transition-colors p-1 rounded text-gray-400 hover:bg-#{page.light_colour}-100 hover:text-#{page.light_colour}-400 dark:hover:bg-#{page.dark_colour}-800 #{context.current_path.start_with?("/#{page.slug}") ? "text-#{page.light_colour}-400 bg-#{page.light_colour}-50 dark:bg-#{page.dark_colour}-900 dark:text-#{page.dark_colour}-400" : 'text-gray-400'}" href="/#{page.slug}" #{page.name}
span class="text-gray-400 dark:text-gray-600"
= "/"
a class="transition-colors p-1 rounded hover:bg-emerald-100 hover:text-emerald-400 dark:hover:bg-emerald-800 #{context.current_path.start_with?('/post') ? 'text-emerald-400 bg-emerald-50 dark:bg-emerald-900 dark:text-emerald-400' : 'text-gray-400'}" href="/posts" Writing
span class="text-gray-400 dark:text-gray-600"
= "/"
a class="transition-colors p-1 rounded text-gray-400 hover:bg-orange-100 hover:text-orange-400 dark:hover:bg-orange-800" href="#{Hanami.app.settings.micropub_site_url}/feeds/rss" RSS
span class="text-gray-400 dark:text-gray-600"
= "/"
button x-data="" @click="darkMode = ! darkMode"
span class="opacity-80 hover:opacity-100 hidden dark:block" ☀️
span class="opacity-80 hover:opacity-100 block dark:hidden" 🌝
== yield
div class="px-4 max-w-screen-md mx-auto pb-10"
p class="float-left text-gray-200 dark:text-indigo-900" © 2010 - 2024 Daniel Nitsikopoulos. All rights reserved.
p class="float-right text-gray-200 dark:text-gray-600"
a href="https://xn--sr8hvo.ws/%F0%9F%8D%93%E2%9E%97%F0%9F%8E%B0/previous" &larr;
a href="https://xn--sr8hvo.ws" 🕸💍
a href="https://xn--sr8hvo.ws/%F0%9F%8D%93%E2%9E%97%F0%9F%8E%B0/next" &nbsp; &rarr;

View File

@@ -1,2 +0,0 @@
xml.instruct!
xml << yield

View File

@@ -1,34 +0,0 @@
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
= stylesheet_tag "app"
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"
= javascript_tag "app"
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

@@ -1,26 +0,0 @@
div class="mb-12 max-w-prose mx-auto text-gray-800 dark:text-gray-200"
h1 class="text-4xl font-extrabold" More
h2 class="text-xl" Explore posts
div class="grid grid-cols-2 gap-2 mb-6"
a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/tags" 🔖 By tag
/ a class="block p-1 border border-blue-200 bg-blue-300 text-blue-900 hover:bg-blue-200 text-center rounded-lg" href="/years" 🗓️ By year
a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/posts" 🪧 All posts
a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/tagged/weekly" 🔄 Week posts
a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/timemachine/#{Time.now.strftime("%Y/%m/%d")}" ⏳ Time machine
h2 class="text-xl" Explore everything else
div class="grid grid-cols-2 gap-2 mb-6"
a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/blogroll" 🪵 Blogroll
a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/bookshelf" 📚️ Bookshelf
a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/collections" 📦 Collections
a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/colophon" 🧱 Colophon
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="/podcasts" 🎙️ Podcasts
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-300 text-blue-900 hover:bg-blue-200 text-center rounded-lg" href="/art" 🎨 Art things

View File

@@ -1,26 +0,0 @@
- context.content_for(:title, "Movies | ")
div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
h1 🍿 Movies
div class="mb-12 max-w-prose mx-auto"
table class="prose dark:prose-invert table-auto"
thead
tr
td Title
td Year
td Rating
- movies.each do |movie|
tr
td
a href="#{movie.url}"
= movie.title
td
= movie.year
td class="min-w-32"
- if movie.rating > 0
== "#{'🌕' * movie.rating.floor}#{'🌗' * (movie.rating % movie.rating.floor).ceil}"
- else
== "&nbsp;"
div class="max-w-screen-md mx-auto border-t border-solid border-gray-200 dark:border-gray-600"

View File

@@ -1,8 +0,0 @@
- context.content_for(:title, "")
- context.content_for(:highlight_code, false)
article class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200 prose-em:font-bold prose-em:not-italic prose-em:bg-blue-600 prose-em:px-1 prose-em:rounded prose-a:text-blue-600 prose-a:dark:text-indigo-300 prose-a:p-0.5 prose-a:rounded-sm prose-a:no-underline hover:prose-a:underline prose-em:text-blue-100"
h1= page_name
== page_content
div class="max-w-screen-md mx-auto border-t border-solid border-gray-200 dark:border-gray-600"

View File

@@ -1,10 +0,0 @@
- context.content_for(:title, "Photos | ")
div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
h1 Photos
div class="grid grid-cols-3 gap-4 mb-4 max-w-prose mx-auto"
- photos.each do |post|
== render "shared/photo_post", post: post, extended: true
div class="max-w-screen-md mx-auto border-t border-solid border-gray-200 dark:border-gray-600"

View File

@@ -1,17 +0,0 @@
- context.content_for(:title, "Places | ")
div class="mb-4 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 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"
- places.each do |post|
== render "shared/post", post: post
div class="max-w-screen-md mx-auto border-t border-solid border-gray-200 dark:border-gray-600"

View File

@@ -1,3 +0,0 @@
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

@@ -1,29 +0,0 @@
- 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"
- if listens && listens.count > 0
div class="p-4 bg-pink-200 dark:bg-pink-900 rounded"
h4 class="p-0 m-0 text-pink-900 dark:text-pink-200" Recent listens
- listens.each do |listen|
div
a class="text-pink-800 dark:text-pink-100 no-underline hover:decoration-wavy hover:underline" href=listen.url
span = listen.title
em= " — #{listen.podcast_name}"
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="#{Hanami.app.settings.micropub_site_url}/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 border-solid border-gray-200 dark:border-gray-600"

View File

@@ -1,16 +0,0 @@
div class="mb-4 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
h1 Archive: #{year}
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 Archive:
- post_years.each do |y|
a href="/posts/archive/#{y}" class="text-sm hover:text-gray-400 #{year.to_s == y.to_s ? 'underline decoration-wavy' : ''}"= y
- if y != post_years.last
span &middot;
div class="h-feed mb-12 max-w-prose mx-auto"
- posts.each do |post|
== render "shared/post", post: post
div class="max-w-screen-md mx-auto border-t border-solid border-gray-200 dark:border-gray-600"

View File

@@ -1,27 +0,0 @@
- context.content_for(:title, "Writing | ")
div class="mb-4 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
h1 Writing
div class="mb-4 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 Archive:
- post_years.each do |year|
a href="/posts/archive/#{year}" class="text-sm hover:text-gray-400"= year
- if year != post_years.last
span &middot;
div class="h-feed mb-12 max-w-prose mx-auto"
form action="/posts" method="GET"
div class="flex"
div class="flex-auto basis-auto mr-4"
input id="search" type="text" class="p-1 rounded w-full bg-indigo-50 dark:bg-indigo-400" name="q" value=query
div class="mr-4"
input type="submit" class="bg-indigo-300 p-1 rounded text-indigo-900" value="Search"
-if query
div class=""
a href="/posts" class="text-gray-400 dark:text-gray-100 pt-1" Clear search
div class="h-feed mb-12 max-w-prose mx-auto"
- posts.each do |post|
== render "shared/post", post: post
div class="max-w-screen-md mx-auto border-t border-solid border-gray-200 dark:border-gray-600"

View File

@@ -1,137 +0,0 @@
- context.content_for(:title, "#{post.display_title} | ")
- context.content_for(:url, post.permalink)
- context.content_for(:image, post.key_image)
article class="h-entry"
template @img-modal.window="imgModal = true; imgModalSrc = $event.detail.imgModalSrc; imgModalDesc = $event.detail.imgModalDesc;" x-if="imgModal"
div @mousedown.outside="imgModalSrc = ''" class="p-2 fixed w-full h-100 inset-0 z-50 overflow-hidden flex justify-center items-center bg-black bg-opacity-75"
div @mousedown.outside="imgModal = ''" class="flex flex-col max-w-3xl max-h-full overflow-auto"
div class="z-50"
button @click="imgModal = ''" class="float-right pt-2 pr-2 outline-none focus:outline-none"
svg class="fill-current text-white" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18"
path d="M14.53 4.53l-1.06-1.06L9 7.94 4.53 3.47 3.47 4.53 7.94 9l-4.47 4.47 1.06 1.06L9 10.06l4.47 4.47 1.06-1.06L10.06 9z">
div class="p-2 text-center w-full"
img class="rounded object-contain h-1/2-screen shadow-solid shadow-pink-100 dark:shadow-pink-200 mb-4 mx-auto" :src="imgModalSrc" :alt="imgModalSrc"
p x-text="imgModalDesc" class="text-center text-white"
div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
h1 class="p-name mb-2"
a class="u-url" href=post.permalink
= post.display_title
nav class="space-x-1 text-sm md:text-sm md:block dark:text-gray-600"
- if post.location || post.photos? || post.videos?
span See more:
- if post.location
a class="dark:text-gray-400" href="/places" places
- if post.photos? || post.videos?
a class="dark:text-gray-400" href="/photos" photos
article class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200 prose-a:text-blue-600 prose-a:no-underline hover:prose-a:underline prose-img:rounded prose-video:rounded"
div class="e-content prose-code:bg-pink-100 prose-code:text-pink-900"
== post.content
- if post.photos?
- post.photos.each_with_index do |photo, idx|
figure id="photo-#{idx}"
img class="u-photo shadow-solid shadow-pink-100 dark:shadow-pink-200 mb-4" src=photo["value"] alt=photo["alt"]
figcaption
= photo["alt"]
- if post.videos?
- post.videos.each_with_index do |video, index|
figure id="video-#{index}"
video loop=false muted=true controls=true
source type="video/mp4" src="#{video["value"]}"
figcaption= video["alt"]
a href="#" data-replay="video-#{index}" Replay
- if post.location
img class="shadow-solid shadow-pink-100 dark:shadow-pink-200 rounded mb-4" src=post.large_map
-if post.webmentions && post.webmentions.count > 0
div class="mt-12"
h3 #{post.webmentions.count} Comment#{post.webmentions.count != 1 ? "s" : ""}
- post.webmentions.each do |mention|
div class="prose-p:m-1 mb-6 p-8 bg-orange-100 dark:bg-indigo-900 squircle"
div class="flex h-8"
img class="w-8 rounded-full m-0 mr-2" src=mention.author_photo
a class="block text-orange-700 dark:text-violet-300 no-underline hover:underline" href=mention.author_url
= mention.author_name
div class="prose dark:prose-invert dark:text-indigo-250 prose-a:text-orange-700 dark:prose-a:text-violet-300 prose-a:no-underline hover:prose-a:underline"
== mention.content_html
div class="text-sm"
a class="no-underline hover:underline text-orange-900 dark:text-violet-400" href=mention.source_url
= mention.published_at.strftime("%e %B, %Y")
div class="mb-12"
- if trip
div class="max-w-prose mx-auto text-gray-600 dark:text-gray-200 flex gap-4"
a href="/trips/#{trip.id}" class="block grow bg-orange-100 hover:bg-orange-200 dark:bg-orange-600 hover:dark:bg-orange-900 rounded px-4 py-2 mb-2"
span class="pr-8"✈️
= "Part of the trip: "
strong #{trip.name}
- if post.tags.map(&:label).include? "weekly"
div class="max-w-prose mx-auto text-gray-600 dark:text-gray-200 flex gap-4"
div class="grow" hx-get="/post/top_tracks/#{post.slug}" hx-trigger="load"
- if past_movies.count > 0
div class="max-w-prose mx-auto text-gray-600 dark:text-gray-200 mb-4"
h3 class="text-xl" Movies watched for the first time this week
div class="flex gap-4 pb-4 mt-4"
- past_movies.map do |movie|
a href=movie.url
figure class="w-24"
img class="rounded hover:opacity-80" src=movie.poster
/ figcaption= movie.title
hr
- if text_posts.count > 0 || photo_posts.count > 0
div class="max-w-prose mx-auto text-gray-600 dark:text-gray-200 mb-4"
h3 class="text-xl mb-0" This week, years ago
- if text_posts.count > 0
div class="max-w-prose mx-auto text-gray-600 dark:text-gray-200 mb-4"
div class="block grow bg-blue-100 dark:bg-blue-600 rounded px-4 py-2 mb-12"
ul class="mt-0"
- text_posts.each do |past_post|
li class="m-0"
a class="hover:underline" href=past_post.permalink
= "#{past_post.display_title} (#{past_post.published_at.year})"
div class="max-w-prose mx-auto text-gray-600 dark:text-gray-200 flex"
div class="grid grid-cols-3 gap-4 mb-4 max-w-prose mx-auto"
- photo_posts.group_by{ |p| p.published_at.year }.each do |year, posts|
-posts.each_with_index do |post, index|
div
-if index == 0
p class="mb-1 px-1" = year
- else
p class="mb-1 px-1" &nbsp;
== render "shared/photo_post", post: post, extended: false
div class="mb-4 max-w-screen-md mx-auto border-t border-solid border-gray-200 dark:border-gray-600"
div class="max-w-prose mx-auto text-gray-600 dark:text-gray-200 flex"
div class=""
= "Published "
time class="dt-published" datetime=post.machine_published_at
= post.display_published_at
p
a class="p-author h-card" href=Hanami.app.settings.micropub_site_url
= "by #{Hanami.app.settings.site_name}"
p
span in&nbsp;
- if post.posted_in == :posts
a class="hover:underline text-blue-400 dark:text-indigo-300" href="/posts" posts
- if post.posted_in == :places
a class="hover:underline text-blue-400 dark:text-indigo-300" href="/places" places
- if post.posted_in == :statuses
a class="hover:underline text-blue-400 dark:text-indigo-300" href="/statuses" statuses
- if post.posted_in == :bookshelf
a class="hover:underline text-blue-400 dark:text-indigo-300" href="/bookshelf" bookshelf
span class="text-right flex-1 leading-6"
== render "shared/tags", tags: post.tags
div class="mb-2 max-w-prose mx-auto text-gray-600 dark:text-gray-200 flex"
- if post.syndicated?
span Also on:&nbsp;
- post.syndicated_to.each do |loc|
- next if loc[:location] == ""
a rel="syndication" class="u-syndication" href=loc[:url]
== render "shared/#{loc[:location]}"
svg width="10" height="10" viewBox="0 0 10 10"
clipPath id="squircleClip" clipPathUnits="objectBoundingBox"
path fill="red" stroke="none" d="M 0,0.5 C 0,0 0,0 0.5,0 S 1,0 1,0.5 1,1 0.5,1 0,1 0,0.5"

View File

@@ -1,11 +0,0 @@
div class="mx-auto"
a href=url class="block flex bg-pink-100 hover:bg-pink-200 dark:bg-pink-600 hover:dark:bg-pink-900 rounded px-4 py-2 mb-12"
div class="mr-4 my-auto"
div class="w-34 h-34 my-auto text-[2.041rem] block dark:hidden" 👩🏼‍🎤
div class="w-34 h-34 my-auto text-[2.041rem] hidden dark:block" 👨🏽‍🎤
div
p class="text-sm" Top track
p class="hover:underline"
p class="font-semibold"= name
p class=""= artist

View File

@@ -1,10 +0,0 @@
div class="grid grid-cols-4 gap-2"
- recently_played_music.each do |album|
a href="#{album[:href]}"
div
img class="m-0 rounded transition-transform ease-out hover:scale-105" src="#{album[:image]}"
span class="inline-block text-sm"
= album[:name]
br
span class="inline-block text-sm font-bold"
= album[:artist]

View File

@@ -1,2 +0,0 @@
- w_class = defined?(width) ? width : "w-6"
<svg class="fill-blue-100 hover:fill-blue-400 #{w_class}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M433 179.11c0-97.2-63.71-125.7-63.71-125.7-62.52-28.7-228.56-28.4-290.48 0 0 0-63.72 28.5-63.72 125.7 0 115.7-6.6 259.4 105.63 289.1 40.51 10.7 75.32 13 103.33 11.4 50.81-2.8 79.32-18.1 79.32-18.1l-1.7-36.9s-36.31 11.4-77.12 10.1c-40.41-1.4-83-4.4-89.63-54a102.54 102.54 0 0 1-.9-13.9c85.63 20.9 158.65 9.1 178.75 6.7 56.12-6.7 105-41.3 111.23-72.9 9.8-49.8 9-121.5 9-121.5zm-75.12 125.2h-46.63v-114.2c0-49.7-64-51.6-64 6.9v62.5h-46.33V197c0-58.5-64-56.6-64-6.9v114.2H90.19c0-122.1-5.2-147.9 18.41-175 25.9-28.9 79.82-30.8 103.83 6.1l11.6 19.5 11.6-19.5c24.11-37.1 78.12-34.8 103.83-6.1 23.71 27.3 18.4 53 18.4 175z"/></svg>

View File

@@ -1,20 +0,0 @@
div class="mb-4"
div class="mb-4"
h3 class="text-xl text-blue-600 dark:text-slate-200 mb-2"
a class="u-url hover:text-blue-900 hover:dark:text-slate-600" href="/bookmark/#{bookmark.slug}"
= "#{bookmark.name} "
small class="text-gray-400 hover:text-gray-600"
a href=bookmark.url
= bookmark.url
== render("link_arrow")
p class="e-content leading-relaxed md:text-lg text-gray-800 dark:text-gray-200"
= bookmark.content
== bookmark.youtube_embed
p class="text-sm text-blue-400 mb-4"
a href="/bookmark/#{bookmark.slug}"
time class="dt-published" datetime=bookmark.machine_published_at
= bookmark.display_published_at
hr

View File

@@ -1,28 +0,0 @@
div class="mb-5 h-entry relative"
- if !first
div class="-top-4 -left-1 absolute rounded-full border-2 bg-orange-100 border-orange-200 p-1 w-1 h-2 inline-block dark:border-amber-400 dark:bg-amber-400"
- if first
div class="inline-block mb-2 dark:text-indigo-400"
span class="mr-2"
= "🛬"
= trip.start_date
div class="ml-[5] #{ last ? '' : 'mb-[20]'} pl-6 border-solid border-l-2 border-orange-200 dark:border-amber-400"
h3 class="text-xl font-semibold text-blue-600 dark:text-indigo-300"
a class="border-b-2 border-transparent hover:border-blue-600 hover:border-b-2" href="/post/#{post.slug}"
= post.name
div class="e-content prose-p:mb-0 prose-img:my-2 prose-a:text-blue-600 prose-a:no-underline hover:prose-a:underline p-name text-base prose prose-ul:list-none prose-ul:pl-0 prose-li:pl-0 text-gray-800 dark:text-gray-200 prose-a:dark:text-gray-100"
== post.excerpt
div class="grid gap-4 grid-flow-row grid-cols-4 grid-rows-1"
-post.photos.each do |photo|
img class="w-44 h-44 object-cover rounded" src=photo["value"]
p class="text-sm text-blue-400 dark:text-indigo-50"
a class="u-url" href="#{post.permalink}"
time class="dt-published" datetime=post.machine_published_at
= post.display_published_at
- if last
div class="inline-block mb-6 dark:text-indigo-400"
span class="mr-2"
= "🛫"
= trip.end_date

View File

@@ -1 +0,0 @@
<svg class="fill-purple-100 hover:fill-purple-400 w-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M224.1 141c-63.6 0-114.9 51.3-114.9 114.9s51.3 114.9 114.9 114.9S339 319.5 339 255.9 287.7 141 224.1 141zm0 189.6c-41.1 0-74.7-33.5-74.7-74.7s33.5-74.7 74.7-74.7 74.7 33.5 74.7 74.7-33.6 74.7-74.7 74.7zm146.4-194.3c0 14.9-12 26.8-26.8 26.8-14.9 0-26.8-12-26.8-26.8s12-26.8 26.8-26.8 26.8 12 26.8 26.8zm76.1 27.2c-1.7-35.9-9.9-67.7-36.2-93.9-26.2-26.2-58-34.4-93.9-36.2-37-2.1-147.9-2.1-184.9 0-35.8 1.7-67.6 9.9-93.9 36.1s-34.4 58-36.2 93.9c-2.1 37-2.1 147.9 0 184.9 1.7 35.9 9.9 67.7 36.2 93.9s58 34.4 93.9 36.2c37 2.1 147.9 2.1 184.9 0 35.9-1.7 67.7-9.9 93.9-36.2 26.2-26.2 34.4-58 36.2-93.9 2.1-37 2.1-147.8 0-184.8zM398.8 388c-7.8 19.6-22.9 34.7-42.6 42.6-29.5 11.7-99.5 9-132.1 9s-102.7 2.6-132.1-9c-19.6-7.8-34.7-22.9-42.6-42.6-11.7-29.5-9-99.5-9-132.1s-2.6-102.7 9-132.1c7.8-19.6 22.9-34.7 42.6-42.6 29.5-11.7 99.5-9 132.1-9s102.7-2.6 132.1 9c19.6 7.8 34.7 22.9 42.6 42.6 11.7 29.5 9 99.5 9 132.1s2.7 102.7-9 132.1z"/></svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,4 +0,0 @@
svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="inline w-2 h2 md:w-3 md:h-3 mt-0.5 ml-1.5"
g
rect height="12.4434" opacity="0" width="12.4238" x="0" y="0"
path d="M14.4238 10.8008L14.4141 0.976562C14.4141 0.419922 14.0527 0.0292969 13.4668 0.0292969L3.64258 0.0292969C3.0957 0.0292969 2.72461 0.449219 2.72461 0.917969C2.72461 1.38672 3.14453 1.78711 3.60352 1.78711L7.00195 1.78711L11.7676 1.63086L9.95117 3.22266L0.273438 12.9199C0.0976562 13.0957 0 13.3203 0 13.5352C0 14.0039 0.419922 14.4434 0.908203 14.4434C1.13281 14.4434 1.34766 14.3652 1.52344 14.1797L11.2207 4.49219L12.832 2.66602L12.6562 7.22656L12.6562 10.8398C12.6562 11.2988 13.0566 11.7285 13.5352 11.7285C14.0039 11.7285 14.4238 11.3281 14.4238 10.8008Z"

View File

@@ -1,2 +0,0 @@
- w_class = defined?(width) ? width : "w-6"
<svg class="fill-blue-100 hover:fill-blue-400 #{w_class}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M433 179.11c0-97.2-63.71-125.7-63.71-125.7-62.52-28.7-228.56-28.4-290.48 0 0 0-63.72 28.5-63.72 125.7 0 115.7-6.6 259.4 105.63 289.1 40.51 10.7 75.32 13 103.33 11.4 50.81-2.8 79.32-18.1 79.32-18.1l-1.7-36.9s-36.31 11.4-77.12 10.1c-40.41-1.4-83-4.4-89.63-54a102.54 102.54 0 0 1-.9-13.9c85.63 20.9 158.65 9.1 178.75 6.7 56.12-6.7 105-41.3 111.23-72.9 9.8-49.8 9-121.5 9-121.5zm-75.12 125.2h-46.63v-114.2c0-49.7-64-51.6-64 6.9v62.5h-46.33V197c0-58.5-64-56.6-64-6.9v114.2H90.19c0-122.1-5.2-147.9 18.41-175 25.9-28.9 79.82-30.8 103.83 6.1l11.6 19.5 11.6-19.5c24.11-37.1 78.12-34.8 103.83-6.1 23.71 27.3 18.4 53 18.4 175z"/></svg>

View File

@@ -1,9 +0,0 @@
- if extended
- post.photos.each_with_index do |photo, idx|
div class="rounded max-w-xs"
a href="#{post.permalink}#photo-#{idx}"
img class="rounded object-cover transition-transform ease-out hover:scale-105 h-48 w-48" src="#{photo["value"]}" alt="#{photo["alt"]}"
- else
div class="rounded max-w-xs"
a href="#{post.permalink}"
img class="rounded object-cover transition-transform ease-out hover:scale-105 h-48 w-48" src="#{post.photos[0]["value"]}" alt="#{post.photos[0]["alt"]}"

View File

@@ -1,3 +0,0 @@
- w_class = defined?(width) ? width : "w-6"
<svg class="fill-blue-100 hover:fill-blue-400 #{w_class} -rotate-45" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M32 32C32 14.3 46.3 0 64 0H320c17.7 0 32 14.3 32 32s-14.3 32-32 32H290.5l11.4 148.2c36.7 19.9 65.7 53.2 79.5 94.7l1 3c3.3 9.8 1.6 20.5-4.4 28.8s-15.7 13.3-26 13.3H32c-10.3 0-19.9-4.9-26-13.3s-7.7-19.1-4.4-28.8l1-3c13.8-41.5 42.8-74.8 79.5-94.7L93.5 64H64C46.3 64 32 49.7 32 32zM160 384h64v96c0 17.7-14.3 32-32 32s-32-14.3-32-32V384z"/></svg>

View File

@@ -1,15 +0,0 @@
div class="mb-8 h-entry"
h3 class="text-xl text-blue-500 dark:text-indigo-300 mb-2"
a class="u-url hover:text-blue-900" href="/post/#{post.slug}"
= post.display_title
div class="e-content prose-p:mb-0 prose-img:my-2 prose-a:text-blue-600 prose-a:no-underline hover:prose-a:underline p-name text-base prose prose-ul:list-none prose-ul:pl-0 prose-li:pl-0 text-gray-800 dark:text-gray-200 prose-a:dark:text-gray-100"
== post.excerpt
div class="grid gap-4 grid-flow-row grid-cols-#{post.photos.count} grid-rows-1"
-post.photos.each do |photo|
img class="w-44 h-44 object-cover rounded" src=photo["value"]
/ == render "shared/tags", tags: post.tags
p class="text-sm text-blue-400 dark:text-indigo-400"
a class="u-url" href="#{post.permalink}"
time class="dt-published" datetime=post.machine_published_at
= post.display_published_at

View File

@@ -1,22 +0,0 @@
div class="mb-8 h-entry border border-gray-200 m-2 p-4 bg-gray-50 hover:bg-gray-100 dark:border-slate-800 dark:bg-slate-900 dark:hover:bg-slate-950 hover:dark:border-slate-900 rounded"
a class="border-b-2 border-transparent hover:border-blue-600 hover:border-b-2" href="/post/#{post.slug}"
div class="e-content prose-p:mb-0 prose-img:my-2 prose-a:text-blue-600 prose-a:no-underline hover:prose-a:underline p-name text-base prose prose-ul:list-none prose-ul:pl-0 prose-li:pl-0 text-gray-800 dark:text-gray-200 prose-a:dark:text-gray-100 mb-4 prose-img:rounded"
== " 💬 #{post.content}"
div class="grid gap-4 grid-flow-row grid-cols-4 grid-rows-1"
-post.photos.each do |photo|
img class="w-32 h-32 object-cover rounded" src=photo["value"]
== render "shared/tags", tags: post.tags
div class="mb-8"
p class="text-sm text-blue-400 dark:text-indigo-400"
a class="u-url float-left mr-0" href="#{post.permalink}"
time class="dt-published" datetime=post.machine_published_at
= post.display_published_at
- if post.webmentions.count > 0
== " &middot; #{post.webmentions.count} comment(s)"
- post.syndicated_to.each do |loc|
== " &middot;"
a rel="syndication" class="u-syndication inline-block ml-1 float-left" href=loc[:url]
- if loc[:location] != ""
== render "shared/#{loc[:location]}", width: "w-4"

View File

@@ -1,2 +0,0 @@
- w_class = defined?(width) ? width : "w-4"
<svg class="fill-pink-100 hover:fill-pink-400 #{w_class}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 368 512"><!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M323.1 3H49.9C12.4 3 0 31.3 0 49.1v433.8c0 20.3 12.1 27.7 18.2 30.1 6.2 2.5 22.8 4.6 32.9-7.1C180 356.5 182.2 354 182.2 354c3.1-3.4 3.4-3.1 6.8-3.1h83.4c35.1 0 40.6-25.2 44.3-39.7l48.6-243C373.8 25.8 363.1 3 323.1 3zm-16.3 73.8l-11.4 59.7c-1.2 6.5-9.5 13.2-16.9 13.2H172.1c-12 0-20.6 8.3-20.6 20.3v13c0 12 8.6 20.6 20.6 20.6h90.4c8.3 0 16.6 9.2 14.8 18.2-1.8 8.9-10.5 53.8-11.4 58.8-.9 4.9-6.8 13.5-16.9 13.5h-73.5c-13.5 0-17.2 1.8-26.5 12.6 0 0-8.9 11.4-89.5 108.3-.9.9-1.8.6-1.8-.3V75.9c0-7.7 6.8-16.6 16.6-16.6h219c8.2 0 15.6 7.7 13.5 17.5z"/></svg>

View File

@@ -1,8 +0,0 @@
- if tags.count > 0
p class="mb-2"
= "Tagged"
div class="mb-2 justify-end gap-x-1.5"
- tags.each do |post_tag|
span
a class="p-category rounded mr-1 u-url text-pink-400 hover:text-pink-600 dark:text-pink-400 dark:hover:text-pink-100 text-gray-600" href="/tagged/#{post_tag.slug}"
= "##{post_tag.label}"

View File

@@ -1,2 +0,0 @@
- w_class = defined?(width) ? width : "w-6"
<svg xmlns="http://www.w3.org/2000/svg" class="fill-blue-200 hover:fill-blue-600 #{w_class}" viewBox="0 0 512 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2023 Fonticons, Inc.--><path d="M459.4 151.7c.3 4.5 .3 9.1 .3 13.6 0 138.7-105.6 298.6-298.6 298.6-59.5 0-114.7-17.2-161.1-47.1 8.4 1 16.6 1.3 25.3 1.3 49.1 0 94.2-16.6 130.3-44.8-46.1-1-84.8-31.2-98.1-72.8 6.5 1 13 1.6 19.8 1.6 9.4 0 18.8-1.3 27.6-3.6-48.1-9.7-84.1-52-84.1-103v-1.3c14 7.8 30.2 12.7 47.4 13.3-28.3-18.8-46.8-51-46.8-87.4 0-19.5 5.2-37.4 14.3-53 51.7 63.7 129.3 105.3 216.4 109.8-1.6-7.8-2.6-15.9-2.6-24 0-57.8 46.8-104.9 104.9-104.9 30.2 0 57.5 12.7 76.7 33.1 23.7-4.5 46.5-13.3 66.6-25.3-7.8 24.4-24.4 44.8-46.1 57.8 21.1-2.3 41.6-8.1 60.4-16.2-14.3 20.8-32.2 39.3-52.6 54.3z"/></svg>

View File

@@ -1,60 +0,0 @@
- context.content_for(:title, "")
div class="h-card prose dark:prose-invert mb-12 prose-a:decoration-wavy hover:prose-a:text-blue-400 max-w-prose mx-auto text-gray-800 dark:text-gray-200"
p class="p-note"
== home_content
div class="mb-8 max-w-screen-md mx-auto border-t border-solid border-gray-200 dark:border-gray-600"
- if latest_status
div class="h-entry mb-12 p-2 grid grid-cols-7 gap-4 min-h-16 max-w-prose mx-auto bg-fuchsia-100 dark:bg-fuchsia-800 dark:text-gray-200 rounded"
div class="col-span-7 sm:col-span-6 text-left"
a class="u-url block my-auto hover:underline decoration-wavy" href=latest_status.permalink
span class="e-content status-body"
- if latest_status.key_image
img class="float-start max-w-32 rounded mr-2" src=latest_status.key_image
p
== latest_status.raw_content
- latest_status.syndicated_to.each do |loc|
small class="text-fuchsia-900 dark:text-fuchsia-300"
a rel="syndication" class="u-syndication" href=loc[:url] Read on #{loc[:location]}
a class="col-span-7 sm:col-span-1 px-2 text-center transition-colors rounded bg-fuchsia-50 hover:bg-fuchsia-200 dark:bg-fuchsia-900 dark:hover:bg-fuchsia-700 inline-block grid content-center max-h-12 my-auto" href="/statuses"
p See all
div class="flex justify-between max-w-prose mx-auto mb-2"
h2 class="text-xl text-amber-600 dark:text-amber-200" Weekly posts
a class="rounded px-2 text-amber-600 hover:dark:bg-amber-900 hover:dark:text-amber-100 dark:text-amber-200 hover:text-amber-600 hover:bg-amber-100" href="/tagged/weekly" See all &rarr;
div class="mb-12 max-w-prose mx-auto bg-amber-100 rounded dark:bg-amber-900 dark:text-gray-100"
ul class="columns-1"
- week_posts.each do |post|
li class=""
a class="block content-justify hover:bg-amber-200 decoration-wavy rounded py-1.5 px-2" href="/post/#{post.slug}"
div class="flex justify-between"
span class="grow-0 inline-block pr-2" = post.name
span class="border-b border-amber-400 dark:border-amber-600 -top-3 relative border-dashed grow inline-block"
span class="grow-0 inline-block pl-2" = post.display_published_at
div class="flex justify-between max-w-prose mx-auto mb-2"
h2 class="text-xl text-blue-600 dark:text-blue-200" 📯 Posts
a class="rounded px-2 h-6 text-blue-600 hover:dark:bg-blue-900 hover:dark:text-blue-100 dark:text-blue-200 hover:text-blue-600 hover:bg-blue-100" href="/posts" See all &rarr;
div class="h-feed mb-12 max-w-prose mx-auto"
- posts.each do |post|
== render "shared/post", post: post
div class="flex justify-between max-w-prose mx-auto mb-2"
h2 class="text-xl text-blue-600 dark:text-blue-200" 📸 Photos
a class="rounded px-2 h-6 text-blue-600 hover:dark:bg-blue-900 hover:dark:text-blue-100 dark:text-blue-200 hover:text-blue-600 hover:bg-blue-100" href="/photos" See all &rarr;
div class="grid grid-cols-3 gap-4 max-w-prose mx-auto"
- photo_posts.each do |post|
== render "shared/photo_post", post: post, extended: false
- if last_location
div class="mb-12 mt-6 max-w-prose mx-auto text-gray-600 dark:text-gray-200 rounded p-2 bg-blue-50 dark:bg-blue-900/60"
div
= "🗺️ Last seen at "
a class="text-blue-400 hover:text-blue-600" href=last_location.permalink
= last_location.display_title
div class="max-w-screen-md mx-auto border-t border-solid border-gray-200 dark:border-gray-600"

Some files were not shown because too many files have changed in this diff Show More