Description generation
This commit is contained in:
parent
804b51aaa6
commit
ce364c01d8
6 changed files with 102 additions and 33 deletions
|
@ -2,29 +2,42 @@ use v6.e.PREVIEW;
|
||||||
|
|
||||||
use HTML::Functional;
|
use HTML::Functional;
|
||||||
use DB::BlogMeta;
|
use DB::BlogMeta;
|
||||||
|
use DB::Post;
|
||||||
|
|
||||||
unit class Config;
|
unit class Config;
|
||||||
|
|
||||||
# TODO: Support GFM admonitions
|
method generate-head(Str:D $title, BlogMeta:D $meta, $description?) {
|
||||||
method generate-post(Str:D $title, Str:D $content, BlogMeta:D $meta) {
|
head [
|
||||||
my $head = head [
|
|
||||||
meta :charset<utf-8>;
|
meta :charset<utf-8>;
|
||||||
meta :name<viewport>, :content<width=device-width, initial-scale=1>;
|
meta :name<viewport>, :content<width=device-width, initial-scale=1>;
|
||||||
|
meta :author :content<Nathan McCarty>;
|
||||||
title "{$meta.title} — $title";
|
title "{$meta.title} — $title";
|
||||||
# TODO: Add style sheets
|
# Add description, if one exists
|
||||||
# Use Iosevka Alie as the monospace font
|
do if $description ~~ Str:D {
|
||||||
link :rel<stylesheet>,
|
meta :description :content($description)
|
||||||
:href<https://static.stranger.systems/fonts/IosevkaAlie/IosevkaAile.css>;
|
} else {
|
||||||
# Use open sans as the content font
|
[]
|
||||||
|
}
|
||||||
|
# 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.googleapis.com>;
|
||||||
link :rel<preconnect> :href<https://fonts.gstatic.com> :crossorigin;
|
link :rel<preconnect> :href<https://fonts.gstatic.com> :crossorigin;
|
||||||
|
# Load fonts, Iosevka Alie for code, and Open Sans for content
|
||||||
|
link :rel<stylesheet>,
|
||||||
|
:href<https://static.stranger.systems/fonts/IosevkaAlie/IosevkaAile.css>;
|
||||||
link :rel<stylesheet>,
|
link :rel<stylesheet>,
|
||||||
:href<https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap>;
|
:href<https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap>;
|
||||||
|
# Inline our style sheets
|
||||||
style %?RESOURCES<main.css>.slurp;
|
style %?RESOURCES<main.css>.slurp;
|
||||||
style %?RESOURCES<code.css>.slurp;
|
style %?RESOURCES<code.css>.slurp;
|
||||||
# TODO: Add description
|
|
||||||
# TODO: Add header links
|
# TODO: Add header links
|
||||||
];
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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 =
|
my $body =
|
||||||
body [
|
body [
|
||||||
div :class<post-body>, [
|
div :class<post-body>, [
|
||||||
|
|
|
@ -78,9 +78,7 @@ class PostDB {
|
||||||
mkdir $by-slug unless $by-slug.e;
|
mkdir $by-slug unless $by-slug.e;
|
||||||
# Render all the posts and make symlinks
|
# Render all the posts and make symlinks
|
||||||
for %!posts.kv -> $id, $post {
|
for %!posts.kv -> $id, $post {
|
||||||
my $html =
|
my $html = $config.generate-post: $post, $!meta;
|
||||||
$config.generate-post:
|
|
||||||
$post.title, $post.render-html, $!meta;
|
|
||||||
my $id-path = $by-id.add: "$id.html";
|
my $id-path = $by-id.add: "$id.html";
|
||||||
$id-path.spurt: $html;
|
$id-path.spurt: $html;
|
||||||
for $post.all-slugs -> $slug {
|
for $post.all-slugs -> $slug {
|
||||||
|
|
|
@ -14,6 +14,9 @@ unit class IdrisPost does Post is json(:pretty);
|
||||||
#| cheaty way
|
#| cheaty way
|
||||||
has Bool:D $.idris is json = True;
|
has Bool:D $.idris is json = True;
|
||||||
|
|
||||||
|
#| Override the generated description for this post
|
||||||
|
has Str $.summary is json;
|
||||||
|
|
||||||
#| Location of the ipkg for the package containing the post
|
#| Location of the ipkg for the package containing the post
|
||||||
has IO::Path:D $.ipkg
|
has IO::Path:D $.ipkg
|
||||||
is required
|
is required
|
||||||
|
@ -48,6 +51,16 @@ method render-html(--> Str:D) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Return our summary, if we have one, otherwise extract the first paragraph of
|
||||||
|
# the markdown document
|
||||||
|
method description(--> Str) {
|
||||||
|
if $!summary {
|
||||||
|
$!summary
|
||||||
|
} else {
|
||||||
|
markdown-first-paragraph $!source
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Run a pack command, erroring on failure
|
# Run a pack command, erroring on failure
|
||||||
sub pack(*@args) {
|
sub pack(*@args) {
|
||||||
my $pack = run 'pack', @args, :out, :err;
|
my $pack = run 'pack', @args, :out, :err;
|
||||||
|
|
|
@ -11,6 +11,9 @@ unit class MarkdownPost does Post is json(:pretty);
|
||||||
#| cheaty way
|
#| cheaty way
|
||||||
has Bool:D $.markdown = True;
|
has Bool:D $.markdown = True;
|
||||||
|
|
||||||
|
#| Override the generated description for this post
|
||||||
|
has Str $.summary;
|
||||||
|
|
||||||
method title(--> Str:D) {
|
method title(--> Str:D) {
|
||||||
markdown-title $!source
|
markdown-title $!source
|
||||||
}
|
}
|
||||||
|
@ -19,3 +22,13 @@ method title(--> Str:D) {
|
||||||
method render-html(--> Str:D) {
|
method render-html(--> Str:D) {
|
||||||
markdown-to-html $!source
|
markdown-to-html $!source
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Return our summary, if we have one, otherwise extract the first paragraph of
|
||||||
|
# the markdown document
|
||||||
|
method description(--> Str) {
|
||||||
|
if $!summary {
|
||||||
|
$!summary
|
||||||
|
} else {
|
||||||
|
markdown-first-paragraph $!source
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -53,3 +53,8 @@ method all-slugs(--> Array[Str:D]) {
|
||||||
|
|
||||||
#| Render this post to an html body
|
#| Render this post to an html body
|
||||||
method render-html(--> Str:D) {...}
|
method render-html(--> Str:D) {...}
|
||||||
|
|
||||||
|
#| Get the description for this post, returning nil if there is none
|
||||||
|
method description(--> Str) {
|
||||||
|
Nil
|
||||||
|
}
|
||||||
|
|
|
@ -3,13 +3,10 @@ unit module Pandoc;
|
||||||
|
|
||||||
use JSON::Fast;
|
use JSON::Fast;
|
||||||
|
|
||||||
#| Extract the title from a markdown document
|
#| Run pandoc with the given arguments, dieing on failure
|
||||||
#|
|
sub pandoc(*@args --> Str:D) {
|
||||||
#| The title is the only top level header, will throw an error if there are
|
|
||||||
#| multiple top level headers or are none
|
|
||||||
sub markdown-title(IO::Path:D $file --> Str:D) is export {
|
|
||||||
# Call into pandoc
|
# Call into pandoc
|
||||||
my $pandoc = run <pandoc -f gfm -t JSON>, $file, :out, :err;
|
my $pandoc = run 'pandoc', @args, :out, :err;
|
||||||
|
|
||||||
# Collect the output
|
# Collect the output
|
||||||
my $output = $pandoc.out.slurp: :close;
|
my $output = $pandoc.out.slurp: :close;
|
||||||
|
@ -17,6 +14,17 @@ sub markdown-title(IO::Path:D $file --> Str:D) is export {
|
||||||
die "Pandoc exited with {$pandoc.exitcode}\nout: $output\nerr: $stderr"
|
die "Pandoc exited with {$pandoc.exitcode}\nout: $output\nerr: $stderr"
|
||||||
unless $pandoc;
|
unless $pandoc;
|
||||||
|
|
||||||
|
$output
|
||||||
|
}
|
||||||
|
|
||||||
|
#| Extract the title from a markdown document
|
||||||
|
#|
|
||||||
|
#| The title is the only top level header, will throw an error if there are
|
||||||
|
#| multiple top level headers or are none
|
||||||
|
sub markdown-title(IO::Path:D $file --> Str:D) is export {
|
||||||
|
# Collect the output
|
||||||
|
my $output = pandoc <-f gfm -t JSON>, $file;
|
||||||
|
|
||||||
# Parse out output from pandoc, we are making an executive decision to trust
|
# Parse out output from pandoc, we are making an executive decision to trust
|
||||||
# pandoc here, so we won't do any error handling for pandoc's output
|
# pandoc here, so we won't do any error handling for pandoc's output
|
||||||
my %parsed = from-json $output;
|
my %parsed = from-json $output;
|
||||||
|
@ -27,12 +35,8 @@ sub markdown-title(IO::Path:D $file --> Str:D) is export {
|
||||||
$v ~~ Associative && $v<t> ~~ "Header"
|
$v ~~ Associative && $v<t> ~~ "Header"
|
||||||
}
|
}
|
||||||
my @headers = %parsed<blocks>.grep(&is-header).grep(*<c>[0] == 1);
|
my @headers = %parsed<blocks>.grep(&is-header).grep(*<c>[0] == 1);
|
||||||
if @headers.elems > 1 {
|
die "More than one top level header in $file" if @headers.elems > 1;
|
||||||
die "More than one top level header in $file";
|
die "No top level headers in $file" if @headers.elems == 0;
|
||||||
};
|
|
||||||
if @headers.elems == 0 {
|
|
||||||
die "No top level headers in $file";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Extract the header and process it into a string
|
# Extract the header and process it into a string
|
||||||
my @header = @headers[0]<c>[2].flat;
|
my @header = @headers[0]<c>[2].flat;
|
||||||
|
@ -55,15 +59,38 @@ sub markdown-title(IO::Path:D $file --> Str:D) is export {
|
||||||
return $title;
|
return $title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#| Use pandoc to extract the first paragraph of a markdown document
|
||||||
|
sub markdown-first-paragraph(IO::Path:D $file --> Str:D) is export {
|
||||||
|
my $output = pandoc <-f gfm -t JSON>, $file;
|
||||||
|
my %parsed = from-json $output;
|
||||||
|
# Extract a list of paragraphs from the pandoc output
|
||||||
|
my sub is-para($v) {
|
||||||
|
$v ~~ Associative && $v<t> ~~ 'Para'
|
||||||
|
}
|
||||||
|
my @paras = %parsed<blocks>.grep(&is-para);
|
||||||
|
die "No paragraphs in markdown" if @paras.elems == 0;
|
||||||
|
my @para = @paras[0][0]<c>.flat;
|
||||||
|
# Proces it into a string
|
||||||
|
my $para = "";
|
||||||
|
for @para -> $component {
|
||||||
|
next unless $component ~~ Associative;
|
||||||
|
given $component<t> {
|
||||||
|
when "Str" {
|
||||||
|
$para ~= $component<c>;
|
||||||
|
}
|
||||||
|
when "Space" {
|
||||||
|
$para ~= " ";
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
die "Invalid component type: $_";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$para
|
||||||
|
}
|
||||||
|
|
||||||
#| Use pandoc to render a markdown document to html
|
#| Use pandoc to render a markdown document to html
|
||||||
sub markdown-to-html(IO::Path:D $file --> Str:D) is export {
|
sub markdown-to-html(IO::Path:D $file --> Str:D) is export {
|
||||||
# Call into pandoc
|
pandoc <-f gfm>, $file
|
||||||
my $pandoc = run <pandoc -f gfm>, $file, :out, :err;
|
|
||||||
# Collect the output
|
|
||||||
my $output = $pandoc.out.slurp: :close;
|
|
||||||
my $stderr = $pandoc.err.slurp: :close;
|
|
||||||
die "Pandoc exited with {$pandoc.exitcode}\nout: $output\nerr: $stderr"
|
|
||||||
unless $pandoc;
|
|
||||||
|
|
||||||
$output
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue