commit 1a3a8088db1c0df5007ed46837c03131d3248803 Author: DarkWiiPlayer Date: Thu Mar 24 11:45:01 2022 +0100 Initialise repository with basic restia blog SSG diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d18d9f7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.tup +*.skooma diff --git a/Tupfile b/Tupfile new file mode 100644 index 0000000..e69de29 diff --git a/Tupfile.ini b/Tupfile.ini new file mode 100644 index 0000000..e69de29 diff --git a/Tuprules.tup b/Tuprules.tup new file mode 100644 index 0000000..7886f99 --- /dev/null +++ b/Tuprules.tup @@ -0,0 +1 @@ +: foreach *.skooma.yue |> yue %f -o %o |> %B diff --git a/build b/build new file mode 100755 index 0000000..524197f --- /dev/null +++ b/build @@ -0,0 +1,4 @@ +#!/bin/sh +tup +rm -rf blog/* +lua build.lua --copy css --copy javascript --output blog diff --git a/build.lua b/build.lua new file mode 100644 index 0000000..2e69657 --- /dev/null +++ b/build.lua @@ -0,0 +1,118 @@ +local arrr = require 'arrr' +local restia = require 'restia' +local shapeshift = require 'shapeshift' +local yaml = require 'lyaml' +local cmark = require 'cmark' + +local params do + local is = shapeshift.is + local parse = arrr { + { "Output directory", "--output", "-o", 'directory' }; + { "Input directory", "--input", "-i", 'directory' }; + { "Copy directory", "--copy", "-c", 'directory', 'repeatable' }; + { "Delete everything first", "--delete", "-d" }; + } + local validate = shapeshift.table { + output = shapeshift.default("output", is.string); + input = shapeshift.default(".", is.string); + copy = shapeshift.default({}, shapeshift.all{ + is.table, + shapeshift.each(is.string) + }); + delete = shapeshift.default(false, shapeshift.is.boolean); + } + params = select(2, assert(validate(parse{...}))) +end +package.loaded.params = params + +local config = restia.config.bind('config', { + (require 'restia.config.readfile'); + (require 'restia.config.lua'); + (require 'restia.config.yaml'); +}) +package.loaded.config = config + +local templates = restia.config.bind('templates', { + (require 'restia.config.skooma'); +}) +package.loaded.templates = templates + +local function read_post(file) + local content = io.open(file):read("*a") + local head, body = restia.utils.frontmatter(content) + return { + head = head and yaml.load(head) or {}; + body = cmark.render_html(cmark.parse_document(body, #body, cmark.OPT_DEFAULT), cmark.OPT_DEFAULT); + } +end + +local posts = {} +package.loaded.posts = posts + +local tree = {} + +for i, path in ipairs(params.copy) do + restia.utils.deepinsert(tree, restia.utils.fs2tab(path), restia.utils.readdir(path)) +end + +local validate_head do + local is = shapeshift.is + validate_head = shapeshift.table { + __extra = 'keep'; + title = is.string; + date = shapeshift.matches("%d%d%d%d%-%d%d%-%d%d"); + file = is.string; + } +end + +local function parsedate(date) + local year, month, day = date:match("(%d+)%-(%d+)%-(%d+)") + return os.time { + year = tonumber(year); + month = tonumber(month); + day = tonumber(day); + } +end + +-- Load Posts +for file in restia.utils.files(params.input, "%.md$") do + local post = read_post(file) + post.head.file = file + + assert(validate_head(post.head)) + + post.head.timestamp = parsedate(post.head.date) + + post.head.slug = post.head.title + :gsub(' ', '_') + :lower() + :gsub('[^a-z0-9-_]', '') + + post.head.uri = string.format("/%s/%s.html", post.head.date:gsub("%-", "/"), post.head.slug) + post.path = restia.utils.fs2tab(post.head.uri) + + table.insert(posts, post) +end + +table.sort(posts, function(a, b) + return a.head.timestamp > b.head.timestamp +end) + +local function render(name, ...) + return templates.main(templates[name], ...) +end + +-- Render Posts +for idx, post in ipairs(posts) do + local body = restia.utils.deepconcat(render("post", post.body, post.head)) + + restia.utils.deepinsert(tree, post.path, body) +end + +tree["index.html"] = render("index", posts) + +if params.delete then + restia.utils.delete(params.output) +end + +restia.utils.builddir(params.output, tree) diff --git a/css/post.css b/css/post.css new file mode 100644 index 0000000..829d6b4 --- /dev/null +++ b/css/post.css @@ -0,0 +1,11 @@ +body { + display: grid; + grid-template-columns: 1fr 60em 1fr; + gap: 2em; +} +nav { + grid-column: 1; +} +article { + grid-column: 2; +} diff --git a/css/reset.css b/css/reset.css new file mode 100644 index 0000000..b217a1e --- /dev/null +++ b/css/reset.css @@ -0,0 +1,3 @@ +* { + box-sizing: border-box; +} diff --git a/css/site.css b/css/site.css new file mode 100644 index 0000000..7968df1 --- /dev/null +++ b/css/site.css @@ -0,0 +1 @@ +@import url('reset.css'); diff --git a/templates/Tupfile b/templates/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/templates/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/templates/index.skooma.yue b/templates/index.skooma.yue new file mode 100644 index 0000000..c91191e --- /dev/null +++ b/templates/index.skooma.yue @@ -0,0 +1,6 @@ +import output from require 'params' + +link = => + a @title, href: "/"..output..@uri + +(prefix) => ul [li link post.head, prefix for post in *@], title "Index" diff --git a/templates/main.skooma.yue b/templates/main.skooma.yue new file mode 100644 index 0000000..b37301a --- /dev/null +++ b/templates/main.skooma.yue @@ -0,0 +1,15 @@ +import output from require 'params' + +(...) => + content, head_content = @(...) + return render.html(html { + lang: "english" + head { + link rel: "stylesheet", href: "/#{output}/css/site.css" + meta charset: "UTF-8" + head_content + } + body { + content + } + }) diff --git a/templates/post.skooma.yue b/templates/post.skooma.yue new file mode 100644 index 0000000..22fe010 --- /dev/null +++ b/templates/post.skooma.yue @@ -0,0 +1,17 @@ +import output from require 'params' + +url = (path) -> "/"..output..path + +(attributes) => + { + nav { + ul { + li a "Index", href: url "/" + [li a post.head.title, href: url post.head.uri for post in *require("posts")] + } + } + article { h1(attributes.title), @ } + }, { + title attributes.title + link rel: "stylesheet", href: "/#{output}/css/post.css" + }