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 DB::BlogMeta;
|
||||
use DB::Post;
|
||||
|
||||
unit class Config;
|
||||
|
||||
# TODO: Support GFM admonitions
|
||||
method generate-post(Str:D $title, Str:D $content, BlogMeta:D $meta) {
|
||||
my $head = head [
|
||||
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";
|
||||
# TODO: Add style sheets
|
||||
# Use Iosevka Alie as the monospace font
|
||||
link :rel<stylesheet>,
|
||||
:href<https://static.stranger.systems/fonts/IosevkaAlie/IosevkaAile.css>;
|
||||
# Use open sans as the content font
|
||||
# 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;
|
||||
# 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>,
|
||||
: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<code.css>.slurp;
|
||||
# TODO: Add description
|
||||
# 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 =
|
||||
body [
|
||||
div :class<post-body>, [
|
||||
|
|
|
@ -78,9 +78,7 @@ class PostDB {
|
|||
mkdir $by-slug unless $by-slug.e;
|
||||
# Render all the posts and make symlinks
|
||||
for %!posts.kv -> $id, $post {
|
||||
my $html =
|
||||
$config.generate-post:
|
||||
$post.title, $post.render-html, $!meta;
|
||||
my $html = $config.generate-post: $post, $!meta;
|
||||
my $id-path = $by-id.add: "$id.html";
|
||||
$id-path.spurt: $html;
|
||||
for $post.all-slugs -> $slug {
|
||||
|
|
|
@ -14,6 +14,9 @@ unit class IdrisPost does Post is json(:pretty);
|
|||
#| cheaty way
|
||||
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
|
||||
has IO::Path:D $.ipkg
|
||||
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
|
||||
sub pack(*@args) {
|
||||
my $pack = run 'pack', @args, :out, :err;
|
||||
|
|
|
@ -11,6 +11,9 @@ unit class MarkdownPost does Post is json(:pretty);
|
|||
#| cheaty way
|
||||
has Bool:D $.markdown = True;
|
||||
|
||||
#| Override the generated description for this post
|
||||
has Str $.summary;
|
||||
|
||||
method title(--> Str:D) {
|
||||
markdown-title $!source
|
||||
}
|
||||
|
@ -19,3 +22,13 @@ method title(--> Str:D) {
|
|||
method render-html(--> Str:D) {
|
||||
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
|
||||
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;
|
||||
|
||||
#| 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 {
|
||||
#| Run pandoc with the given arguments, dieing on failure
|
||||
sub pandoc(*@args --> Str:D) {
|
||||
# Call into pandoc
|
||||
my $pandoc = run <pandoc -f gfm -t JSON>, $file, :out, :err;
|
||||
my $pandoc = run 'pandoc', @args, :out, :err;
|
||||
|
||||
# Collect the output
|
||||
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"
|
||||
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
|
||||
# pandoc here, so we won't do any error handling for pandoc's 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"
|
||||
}
|
||||
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 == 0 {
|
||||
die "No top level headers in $file";
|
||||
};
|
||||
die "More than one top level header in $file" if @headers.elems > 1;
|
||||
die "No top level headers in $file" if @headers.elems == 0;
|
||||
|
||||
# Extract the header and process it into a string
|
||||
my @header = @headers[0]<c>[2].flat;
|
||||
|
@ -55,15 +59,38 @@ sub markdown-title(IO::Path:D $file --> Str:D) is export {
|
|||
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
|
||||
sub markdown-to-html(IO::Path:D $file --> Str:D) is export {
|
||||
# Call into pandoc
|
||||
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
|
||||
pandoc <-f gfm>, $file
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue