Generate series pages
This commit is contained in:
parent
7cf4827d0c
commit
baf8d6556b
8 changed files with 168 additions and 41 deletions
|
@ -10,14 +10,6 @@ use DB::Post;
|
||||||
|
|
||||||
unit class Config;
|
unit class Config;
|
||||||
|
|
||||||
sub show-html($html) {
|
|
||||||
my $out = "<!doctype html>$html";
|
|
||||||
# Work around HTML::Functional automatically putting newlines between tags
|
|
||||||
$out ~~ s:g/'</i>' \v+ '<span>'/<\/i><span>/;
|
|
||||||
$out ~~ s:g/\v+ '</a>'/<\/a>/;
|
|
||||||
$out
|
|
||||||
}
|
|
||||||
|
|
||||||
# TODO: Support GFM admonitions
|
# TODO: Support GFM admonitions
|
||||||
method generate-post(Int:D $id, Post:D $post, $db) {
|
method generate-post(Int:D $id, Post:D $post, $db) {
|
||||||
my $meta = $db.meta;
|
my $meta = $db.meta;
|
||||||
|
@ -45,34 +37,13 @@ method generate-post(Int:D $id, Post:D $post, $db) {
|
||||||
show-html $html
|
show-html $html
|
||||||
}
|
}
|
||||||
|
|
||||||
method generate-blurb(Int:D $id, $db) {
|
|
||||||
my $post = $db.posts{$id};
|
|
||||||
my $desc = $post.description;
|
|
||||||
my $link = post-link $id, $post;
|
|
||||||
div :class<post-blurb>, [
|
|
||||||
div :class<post-blurb-title>, [
|
|
||||||
a :href($link), span [
|
|
||||||
h2 $post.title;
|
|
||||||
];
|
|
||||||
];
|
|
||||||
post-info $id, $post, $db;
|
|
||||||
if $desc ~~ Str:D {
|
|
||||||
div :class<post-blurb-description>, [
|
|
||||||
p $post.description;
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
[]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
method generate-index($db) {
|
method generate-index($db) {
|
||||||
my @most-recent =
|
my @most-recent =
|
||||||
$db.sorted-posts
|
$db.sorted-posts
|
||||||
.head(10)
|
.head(10)
|
||||||
.grep(!*.value.hidden)
|
.grep(!*.value.hidden)
|
||||||
.map(-> $pair {
|
.map(-> $pair {
|
||||||
self.generate-blurb: $pair.key, $db
|
generate-blurb $pair.key, $db
|
||||||
});
|
});
|
||||||
|
|
||||||
my $head = generate-head($db.meta);
|
my $head = generate-head($db.meta);
|
||||||
|
@ -97,7 +68,7 @@ method generate-archive($db) {
|
||||||
$db.sorted-posts
|
$db.sorted-posts
|
||||||
.grep(!*.value.hidden)
|
.grep(!*.value.hidden)
|
||||||
.map(-> $pair {
|
.map(-> $pair {
|
||||||
self.generate-blurb: $pair.key, $db
|
generate-blurb $pair.key, $db
|
||||||
});
|
});
|
||||||
|
|
||||||
my $head = generate-head($db.meta);
|
my $head = generate-head($db.meta);
|
||||||
|
|
|
@ -14,6 +14,7 @@ use DB::BlogMeta;
|
||||||
use DB::MarkdownPost;
|
use DB::MarkdownPost;
|
||||||
use DB::IdrisPost;
|
use DB::IdrisPost;
|
||||||
use DB::PlaceholderPost;
|
use DB::PlaceholderPost;
|
||||||
|
use Render::Series;
|
||||||
use Atom;
|
use Atom;
|
||||||
use Config;
|
use Config;
|
||||||
|
|
||||||
|
@ -140,6 +141,13 @@ class PostDB {
|
||||||
$config.generate-tag-page(self, $tag);
|
$config.generate-tag-page(self, $tag);
|
||||||
}
|
}
|
||||||
# TODO: Generate the series pages
|
# TODO: Generate the series pages
|
||||||
|
my $series-dir = $out-dir.add('series/');
|
||||||
|
mkdir $series-dir unless $series-dir.e;
|
||||||
|
for %!series.kv -> $key, $value {
|
||||||
|
$series-dir.add("$key.html").spurt:
|
||||||
|
series-page($key, self);
|
||||||
|
}
|
||||||
|
# TODO: Generate the main series page
|
||||||
# Render the rss/atom feed
|
# Render the rss/atom feed
|
||||||
my $atom-path = $out-dir.add('atom.xml');
|
my $atom-path = $out-dir.add('atom.xml');
|
||||||
my $atom = posts-to-atom self;
|
my $atom = posts-to-atom self;
|
||||||
|
|
|
@ -22,3 +22,14 @@ method contains-post(Int:D $post-id --> Bool:D) {
|
||||||
False
|
False
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#| Returns the date of the lastest post
|
||||||
|
method latest-post($db) {
|
||||||
|
my @posts = @!post-ids.map(-> $i {$db.posts{$i}});
|
||||||
|
if @posts {
|
||||||
|
my $most-recent-post = @posts.max(*.posted-at);
|
||||||
|
$most-recent-post.posted-at
|
||||||
|
} else {
|
||||||
|
Nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -131,3 +131,24 @@ sub post-header(Int:D $id, Post:D $post, $db) is export {
|
||||||
post-info $id, $post, $db;
|
post-info $id, $post, $db;
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub generate-blurb(Int:D $id, $db) is export {
|
||||||
|
my $post = $db.posts{$id};
|
||||||
|
my $desc = $post.description;
|
||||||
|
my $link = post-link $id, $post;
|
||||||
|
div :class<post-blurb>, [
|
||||||
|
div :class<post-blurb-title>, [
|
||||||
|
a :href($link), span [
|
||||||
|
h2 $post.title;
|
||||||
|
];
|
||||||
|
];
|
||||||
|
post-info $id, $post, $db;
|
||||||
|
if $desc ~~ Str:D {
|
||||||
|
div :class<post-blurb-description>, [
|
||||||
|
p $post.description;
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
[]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
105
lib/Render/Series.rakumod
Normal file
105
lib/Render/Series.rakumod
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
use v6.e.PREVIEW;
|
||||||
|
unit module Render::Series;
|
||||||
|
|
||||||
|
use Render::Util;
|
||||||
|
use Render::Head;
|
||||||
|
use Render::Post;
|
||||||
|
use DB::Post;
|
||||||
|
use DB::Series;
|
||||||
|
|
||||||
|
use HTML::Functional;
|
||||||
|
|
||||||
|
sub series-date(Series:D $series, $db) is export {
|
||||||
|
my $datetime = $series.latest-post: $db;
|
||||||
|
if $datetime {
|
||||||
|
my $timestamp = sprintf(
|
||||||
|
"%s %02d:%02d%s",
|
||||||
|
$datetime.yyyy-mm-dd,
|
||||||
|
($datetime.hour % 12) || 12,
|
||||||
|
$datetime.minute,
|
||||||
|
$datetime.hour < 12 ?? 'am' !! 'pm'
|
||||||
|
);
|
||||||
|
|
||||||
|
div :class<series-time>, :title("Latest post made at $timestamp"), [
|
||||||
|
icon 'calendar';
|
||||||
|
' ';
|
||||||
|
$datetime.Date.Str
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub series-read-time(Series:D $series, $db) is export {
|
||||||
|
my @readtimes = $series.post-ids.map(-> $i {$db.posts{$i}.readtimes});
|
||||||
|
my ($slow, $average, $fast) = 0, 0, 0;
|
||||||
|
for @readtimes -> ($s, $a, $f) {
|
||||||
|
$slow += $s;
|
||||||
|
$average += $a;
|
||||||
|
$fast += $f;
|
||||||
|
}
|
||||||
|
div :class<series-read-time>, :title<Estimated read time at 140/180/220 WPM>, [
|
||||||
|
icon 'timer';
|
||||||
|
' ';
|
||||||
|
mins-to-string $slow;
|
||||||
|
' ';
|
||||||
|
'/';
|
||||||
|
' ';
|
||||||
|
mins-to-string $average;
|
||||||
|
' ';
|
||||||
|
'/';
|
||||||
|
' ';
|
||||||
|
mins-to-string $fast;
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
sub series-count(Series:D $series, $db) is export {
|
||||||
|
my $count = $series.post-ids.elems;
|
||||||
|
div :class<series-article-count>, :title("Series has $count articles"), [
|
||||||
|
icon 'add-to-queue';
|
||||||
|
' ';
|
||||||
|
"$count articles";
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
sub series-info(Series:D $series, $db) is export {
|
||||||
|
div :class<series-info>, [
|
||||||
|
series-date $series, $db;
|
||||||
|
series-read-time $series, $db;
|
||||||
|
series-count $series, $db;
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
sub series-header(Series:D $series, $db) is export {
|
||||||
|
header :class<series-header>, [
|
||||||
|
div :class<series-title>, [
|
||||||
|
h1 $series.title;
|
||||||
|
];
|
||||||
|
div :class<series-desc>, [
|
||||||
|
p $series.desc;
|
||||||
|
];
|
||||||
|
series-info $series, $db;
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
sub series-page(Int:D $series-id, $db) is export {
|
||||||
|
my $meta = $db.meta;
|
||||||
|
my $series = $db.series{$series-id};
|
||||||
|
my $head = generate-head($meta, $series.title, $series.desc);
|
||||||
|
my $body =
|
||||||
|
body [
|
||||||
|
site-header $meta;
|
||||||
|
article :class<series>, [
|
||||||
|
series-header $series, $db;
|
||||||
|
div :class<series-blurbs>,
|
||||||
|
$series.post-ids.map(*.&generate-blurb($db));
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
my $html = html :lang<en>, [
|
||||||
|
$head;
|
||||||
|
$body
|
||||||
|
];
|
||||||
|
|
||||||
|
show-html $html;
|
||||||
|
}
|
|
@ -5,6 +5,15 @@ use DB::Post;
|
||||||
|
|
||||||
use HTML::Functional;
|
use HTML::Functional;
|
||||||
|
|
||||||
|
sub show-html($html) is export {
|
||||||
|
my $out = "<!doctype html>$html";
|
||||||
|
# Work around HTML::Functional automatically putting newlines between tags
|
||||||
|
$out ~~ s:g/'</i>' \v+ '<span>'/<\/i><span>/;
|
||||||
|
$out ~~ s:g/\v+ '</a>'/<\/a>/;
|
||||||
|
$out ~~ s:g/',' \v+ '<span'/,<span/;
|
||||||
|
$out
|
||||||
|
}
|
||||||
|
|
||||||
sub opt($test, $item) is export {
|
sub opt($test, $item) is export {
|
||||||
if $test {
|
if $test {
|
||||||
$item
|
$item
|
||||||
|
|
|
@ -53,7 +53,8 @@ a:visited {
|
||||||
.site-tagline {
|
.site-tagline {
|
||||||
color: var(--dim-0);
|
color: var(--dim-0);
|
||||||
}
|
}
|
||||||
.post-body, .post-header, .post-blurbs, .tags, .tags .tag-blurb-post {
|
.post-body, .post-header, .post-blurbs, .tags, .tags .tag-blurb-post,
|
||||||
|
.series-header, .series-blurbs {
|
||||||
background-color: var(--bg-0);
|
background-color: var(--bg-0);
|
||||||
}
|
}
|
||||||
.post-blurb, .tags .tag-blurb {
|
.post-blurb, .tags .tag-blurb {
|
||||||
|
@ -65,13 +66,13 @@ a:visited {
|
||||||
:not(.tags) .tag-blurb-post {
|
:not(.tags) .tag-blurb-post {
|
||||||
background-color: var(--bg-1);
|
background-color: var(--bg-1);
|
||||||
}
|
}
|
||||||
.post-title, .post-blurbs h1 {
|
.post-title, .post-blurbs h1, .series-header h1 {
|
||||||
color: var(--green);
|
color: var(--green);
|
||||||
}
|
}
|
||||||
.post-body h2, .post-body h3, .post-body h4 {
|
.post-body h2, .post-body h3, .post-body h4 {
|
||||||
color: var(--fg-1);
|
color: var(--fg-1);
|
||||||
}
|
}
|
||||||
.post-info > * {
|
.post-info > *, .series-info > * {
|
||||||
background-color: var(--bg-2);
|
background-color: var(--bg-2);
|
||||||
}
|
}
|
||||||
blockquote {
|
blockquote {
|
||||||
|
|
|
@ -27,13 +27,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Main Body and Post Flexboxs */
|
/* Main Body and Post Flexboxs */
|
||||||
body, .post {
|
body, .post, .series {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--box-gap);
|
gap: var(--box-gap);
|
||||||
}
|
}
|
||||||
.post {
|
.post, .series {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ body, .post {
|
||||||
|
|
||||||
/* Style the post header, body, and blurbs */
|
/* Style the post header, body, and blurbs */
|
||||||
/* TODO: Style footnotes and get footnote hover working */
|
/* TODO: Style footnotes and get footnote hover working */
|
||||||
.post-header, .post-body {
|
.post-header, .post-body, .series-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -90,11 +90,11 @@ body, .post {
|
||||||
margin: auto var(--box-margin-horz);
|
margin: auto var(--box-margin-horz);
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
}
|
}
|
||||||
.post-title h1 {
|
.post-title h1, .series-title h1 {
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
}
|
}
|
||||||
.post-info {
|
.post-info, .series-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -108,7 +108,7 @@ body, .post {
|
||||||
.post-body h2, .post-body h3, .post-body h4 {
|
.post-body h2, .post-body h3, .post-body h4 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.post-blurbs {
|
.post-blurbs, .series-blurbs {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -116,6 +116,7 @@ body, .post {
|
||||||
max-width: var(--content-width);
|
max-width: var(--content-width);
|
||||||
padding: var(--box-padding-vert) var(--box-padding-horz);
|
padding: var(--box-padding-vert) var(--box-padding-horz);
|
||||||
border-radius: var(--box-radius);
|
border-radius: var(--box-radius);
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
.post-blurb {
|
.post-blurb {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -128,7 +129,7 @@ body, .post {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
.post-info > * {
|
.post-info > *, .series-info > * {
|
||||||
padding: 0.25em;
|
padding: 0.25em;
|
||||||
border-radius: 0.25em;
|
border-radius: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue