samhuri.net/lib/pressa/views/layout.rb
Sami Samhuri 007b1058b6
Migrate from Swift to Ruby (#33)
Replace the Swift site generator with a Ruby and Phlex implementation.
Loads site and projects from TOML, derive site metadata from posts.

Migrate from make to bake and add standardrb and code coverage tasks.

Update CI and docs to match the new workflow, and remove unused
assets/dependencies plus obsolete tooling.
2026-02-07 21:19:03 -08:00

208 lines
6.1 KiB
Ruby

require "phlex"
require "pressa/views/icons"
module Pressa
module Views
class Layout < Phlex::HTML
attr_reader :site,
:page_subtitle,
:page_description,
:page_type,
:canonical_url,
:page_scripts,
:page_styles,
:content
def initialize(
site:,
canonical_url:, page_subtitle: nil,
page_description: nil,
page_type: "website",
page_scripts: [],
page_styles: [],
content: nil
)
@site = site
@page_subtitle = page_subtitle
@page_description = page_description
@page_type = page_type
@canonical_url = canonical_url
@page_scripts = page_scripts
@page_styles = page_styles
@content = content
end
def view_template
doctype
html(lang: "en") do
comment { "meow" }
head do
meta(charset: "UTF-8")
title { full_title }
meta(name: "twitter:title", content: full_title)
meta(property: "og:title", content: full_title)
meta(name: "description", content: description)
meta(name: "twitter:description", content: description)
meta(property: "og:description", content: description)
meta(property: "og:site_name", content: site.title)
link(rel: "canonical", href: canonical_url)
meta(name: "twitter:url", content: canonical_url)
meta(property: "og:url", content: canonical_url)
meta(property: "og:image", content: og_image_url) if og_image_url
meta(property: "og:type", content: page_type)
meta(property: "article:author", content: site.author)
meta(name: "twitter:card", content: "summary")
link(
rel: "alternate",
href: site.url_for("/feed.xml"),
type: "application/rss+xml",
title: site.title
)
link(
rel: "alternate",
href: site.url_for("/feed.json"),
type: "application/json",
title: site.title
)
meta(name: "fediverse:creator", content: "@sjs@techhub.social")
link(rel: "author", type: "text/plain", href: site.url_for("/humans.txt"))
link(rel: "icon", type: "image/png", href: site.url_for("/images/favicon-32x32.png"))
link(rel: "shortcut icon", href: site.url_for("/images/favicon.icon"))
link(rel: "apple-touch-icon", href: site.url_for("/images/apple-touch-icon.png"))
link(rel: "mask-icon", color: "#aa0000", href: site.url_for("/images/safari-pinned-tab.svg"))
link(rel: "manifest", href: site.url_for("/images/manifest.json"))
meta(name: "msapplication-config", content: site.url_for("/images/browserconfig.xml"))
meta(name: "theme-color", content: "#121212")
meta(name: "viewport", content: "width=device-width, initial-scale=1.0, viewport-fit=cover")
link(rel: "dns-prefetch", href: "https://gist.github.com")
all_styles.each do |style|
link(rel: "stylesheet", type: "text/css", href: style_href(style.href))
end
end
body do
render_header
render(content) if content
render_footer
render_scripts
end
end
end
private
def description
page_description || site.description
end
def full_title
return site.title unless page_subtitle
"#{site.title}: #{page_subtitle}"
end
def og_image_url
site.image_url
end
def all_styles
site.styles + page_styles
end
def all_scripts
site.scripts + page_scripts
end
def render_header
header(class: "primary") do
div(class: "title") do
h1 do
a(href: site.url) { site.title }
end
br
h4 do
plain "By "
a(href: site.url_for("/about")) { site.author }
end
end
nav(class: "remote") do
ul do
li(class: "mastodon") do
a(rel: "me", "aria-label": "Mastodon", href: "https://techhub.social/@sjs") do
raw(safe(Icons.mastodon))
end
end
li(class: "github") do
a("aria-label": "GitHub", href: "https://github.com/samsonjs") do
raw(safe(Icons.github))
end
end
li(class: "rss") do
a("aria-label": "RSS", href: site.url_for("/feed.xml")) do
raw(safe(Icons.rss))
end
end
end
end
nav(class: "local") do
ul do
li { a(href: site.url_for("/about")) { "About" } }
li { a(href: site.url_for("/posts")) { "Archive" } }
li { a(href: site.url_for("/projects")) { "Projects" } }
end
end
div(class: "clearfix")
end
end
def render_footer
footer do
plain "© #{footer_years} "
a(href: site.url_for("/about")) { site.author }
end
end
def render_scripts
all_scripts.each do |scr|
attrs = {src: script_src(scr.src)}
attrs[:defer] = true if scr.defer
script(**attrs)
end
end
def script_src(src)
return src if src.start_with?("http://", "https://")
absolute_asset(src)
end
def style_href(href)
return href if href.start_with?("http://", "https://")
absolute_asset(href)
end
def absolute_asset(path)
normalized = path.start_with?("/") ? path : "/#{path}"
site.url_for(normalized)
end
def footer_years
current_year = Time.now.year
start_year = site.copyright_start_year || current_year
return current_year.to_s if start_year >= current_year
"#{start_year} - #{current_year}"
end
end
end
end