website/lib/Config.rakumod
2025-02-04 23:43:42 -05:00

139 lines
3.6 KiB
Raku

use v6.e.PREVIEW;
use HTML::Functional;
use DB::BlogMeta;
use DB::Post;
unit class Config;
method generate-head(Str:D $title, BlogMeta:D $meta, $description?) {
head [
meta :charset<utf-8>;
meta :name<viewport>, :content<width=device-width, initial-scale=1>;
meta :author :content<Nathan McCarty>;
title "{$meta.title} $title";
# Add description, if one exists
do if $description ~~ Str:D {
meta :description :content($description)
} else {
[]
}
# Preconnect to all our resource sources
link :rel<preconnect> :href<https://static.stranger.systems>;
link :rel<preconnect> :href<https://fonts.googleapis.com>;
link :rel<preconnect> :href<https://fonts.gstatic.com> :crossorigin;
link :rel<preconnect> :href<https://unpkg.com>;
# Load fonts, Iosevka for code, Open Sans for content, and boxicons for
# icons
link :rel<stylesheet>,
:href<https://static.stranger.systems/fonts/Iosevka/Iosevka.css>;
link :rel<stylesheet>,
:href<https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap>;
link :rel<stylesheet>,
:href<https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css>;
# Inline our style sheets
style %?RESOURCES<main.css>.slurp;
style %?RESOURCES<code.css>.slurp;
];
}
method site-header(BlogMeta:D $meta) {
header :class<site-header>, [
div :class<site-logo>, [
# TODO: Use a real image here
$meta.title
];
div :class<site-tagline>, [
$meta.tagline
];
div :class<header-links>, [
]
]
}
method post-date(Post:D $post) {
my $datetime = $post.posted-at;
my $timestamp = sprintf(
"%s %02d:%02d %s",
$datetime.yyyy-mm-dd,
($datetime.hour % 12) || 12,
$datetime.minute,
$datetime.hour < 12 ?? 'am' !! 'pm'
);
div :class<post-time>, :title("Posted At $timestamp"), [
icon 'time';
'&nbsp;';
$timestamp
]
}
sub mins-to-string($mins) {
if $mins < 60 {
$mins.Str ~ "m"
} else {
my $h = $mins div 60;
my $m = $mins mod 60;
$h.Str ~ "h" ~ $m.Str ~ "m"
}
}
method post-read-time(Post:D $post) {
my ($slow, $average, $fast) = $post.readtimes;
div :class<post-read-time>, :title<Estimated read time at 140/180/220 WPM>, [
icon 'timer';
'&nbsp;';
mins-to-string $slow;
'&nbsp;';
'/';
'&nbsp;';
mins-to-string $average;
'&nbsp;';
'/';
'&nbsp;';
mins-to-string $fast;
]
}
method post-header(Post:D $post) {
header :class<post-header>, [
div :class<post-title>, [
h1 $post.title;
];
div :class<post-info>, [
self.post-date: $post;
self.post-read-time: $post;
];
# TODO: Add tags once we have support for that
]
}
# TODO: Support GFM admonitions
method generate-post(Post:D $post, BlogMeta:D $meta) {
my $content = $post.render-html;
my $head = self.generate-head($post.title, $meta, $post.description);
my $body =
body [
self.site-header: $meta;
article :class<post>, [
self.post-header: $post;
div :class<post-body>, [
$content;
]
]
];
# TODO: Setup footer
# my $footer;
my $html = html :lang<en>, [
$head,
$body
];
"<!doctype html>$html"
}
sub icon($icon) {
i(:class("bx bx-$icon"))
}