From 23e1a810d964aa255e878808254247d7caaf253a Mon Sep 17 00:00:00 2001 From: DarkWiiPlayer Date: Wed, 1 Feb 2023 17:38:00 +0100 Subject: [PATCH] Major refactor and dependency update --- blog-dev-1.rockspec | 25 ++++++ build | 1 + build.lua | 136 ++++-------------------------- modules.csv => config/modules.csv | 0 css/post.css | 9 +- lib/config.lua | 7 ++ lib/paramparser.lua | 24 ++++++ lib/posts.lua | 68 +++++++++++++++ lib/stringplus.lua | 11 +++ pages/index.html.skooma.yue | 16 ++++ pages/index.skooma.yue | 16 ---- pages/init.lua | 4 + tasks.lua | 44 ++++++++++ templates/init.lua | 4 + templates/main.html.skooma.yue | 16 ++++ templates/main.skooma.yue | 18 ---- templates/post.html.skooma.yue | 14 +++ templates/post.skooma.yue | 16 ---- 18 files changed, 259 insertions(+), 170 deletions(-) create mode 100644 blog-dev-1.rockspec rename modules.csv => config/modules.csv (100%) create mode 100644 lib/config.lua create mode 100644 lib/paramparser.lua create mode 100644 lib/posts.lua create mode 100644 lib/stringplus.lua create mode 100644 pages/index.html.skooma.yue delete mode 100644 pages/index.skooma.yue create mode 100644 pages/init.lua create mode 100644 tasks.lua create mode 100644 templates/init.lua create mode 100644 templates/main.html.skooma.yue delete mode 100644 templates/main.skooma.yue create mode 100644 templates/post.html.skooma.yue delete mode 100644 templates/post.skooma.yue diff --git a/blog-dev-1.rockspec b/blog-dev-1.rockspec new file mode 100644 index 0000000..26b613d --- /dev/null +++ b/blog-dev-1.rockspec @@ -0,0 +1,25 @@ +package = "blog" +version = "dev-1" +source = { + url = "" +} +description = { + homepage = "https://darkwiiplayer.github.io/blog", + license = "Proprietary" +} +dependencies = { + "arrr ~> 2.2", + "glass ~> 1.3.0", + "cmark ~> 0.29", + "fun ~> 0.1.3", + "lua-cjson ~> 2.1", + "restia", + "scaffold ~> 1.1.0", + "shapeshift ~> 1.1.0", + "skooma ~> 0.3", + "streamcsv ~> 1.1.0", +} +build = { + type = "builtin", + modules = { } +} diff --git a/build b/build index 272a36b..58248d3 100755 --- a/build +++ b/build @@ -1,4 +1,5 @@ #!/bin/sh tup || exit rm -rf blog/* +export LUA_PATH='lib/?.lua;lib/?/init.lua;;' lua build.lua --copy css --copy javascript --output blog diff --git a/build.lua b/build.lua index 91d1b15..ba78bbb 100644 --- a/build.lua +++ b/build.lua @@ -1,141 +1,39 @@ -local arrr = require 'arrr' local cmark = require 'cmark' local csv = require 'streamcsv' local fun = require 'fun' local json = require 'cjson' local restia = require 'restia' +local scaffold = require 'scaffold' local shapeshift = require 'shapeshift' -local yaml = require 'lyaml' -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 +-- Project-specific stuff +local paramparser = require 'paramparser' +local params = paramparser(...) 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 pages = restia.config.bind('pages', { - (require 'restia.config.skooma'); -}) -package.loaded.pages = pages - --- General purpose utility functions - -local function split(str, pattern) - local result = {} - for item in str:gmatch(pattern) do - table.insert(result, item) - end - return result -end - -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 - --- Handle JS modules -local modules = csv.file(io.open("modules.csv"), {header = true}) -package.loaded.modules = modules - -local posts = {} -package.loaded.posts = posts +local config = require 'config' +local pages = require 'pages' +local templates = require 'templates' +local posts = require 'posts' local tree = {} for i, path in ipairs(params.copy) do - restia.utils.deepinsert(tree, restia.utils.fs2tab(path), restia.utils.readdir(path)) + scaffold.deep(tree, path, scaffold.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; - } +local function render(name, data) + return templates.main(templates[name], data) 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) - - if "string" == type(post.head.tags) then - post.head.tags = split(post.head.tags, "%a+") - end - - 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 -local function page(name, ...) - return templates.main(pages[name], ...) +local function page(name, data) + return templates.main(pages[name], data) end -- Render Posts for idx, post in ipairs(posts) do - local body = restia.utils.deepconcat(render("post", post.body, post.head)) + local body = tostring(render("post", post)) - restia.utils.deepinsert(tree, post.path, body) + scaffold.deep(tree, post.path, body) end if params.delete then @@ -162,6 +60,6 @@ tree["posts.json"] = json.encode( :totable() ) -tree["index.html"] = page("index", posts, tree["posts.json"]) +tree["index.html"] = tostring(page("index", tree["posts.json"])) -restia.utils.builddir(params.output, tree) +scaffold.builddir(params.output, tree) diff --git a/modules.csv b/config/modules.csv similarity index 100% rename from modules.csv rename to config/modules.csv diff --git a/css/post.css b/css/post.css index 829d6b4..b068e74 100644 --- a/css/post.css +++ b/css/post.css @@ -1,10 +1,17 @@ body { + --sidebar: minmax(16em, 1fr); display: grid; - grid-template-columns: 1fr 60em 1fr; + grid-template-columns: var(--sidebar) 40em var(--sidebar); gap: 2em; } nav { grid-column: 1; + position: sticky; + height: max-content; + top: 0; + max-height: max-content; +} +nav>* { } article { grid-column: 2; diff --git a/lib/config.lua b/lib/config.lua new file mode 100644 index 0000000..39ed11d --- /dev/null +++ b/lib/config.lua @@ -0,0 +1,7 @@ +local glass = require 'glass' +return glass.bind('config', { + (require 'glass.raw'); + (require 'glass.lua'); + (require 'glass.yaml'); + (require 'glass.csv'); +}) diff --git a/lib/paramparser.lua b/lib/paramparser.lua new file mode 100644 index 0000000..40316ee --- /dev/null +++ b/lib/paramparser.lua @@ -0,0 +1,24 @@ +local arrr = require 'arrr' +local shapeshift = require 'shapeshift' + +return function(...) + local is = shapeshift.is + local parse = arrr { + { "Output directory", "--output", "-o", 'directory' }; + { "Input directory", "--input", "-i", 'directory' }; + { "Copy directory", "--copy", "-c", 'directory', 'repeatable' }; + { "Include unpublished posts", "--unpublished", "-u", nil }; + { "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) + }); + unpublished = shapeshift.default(false, shapeshift.is.boolean); + delete = shapeshift.default(false, shapeshift.is.boolean); + } + return select(2, assert(validate(parse{...}))) +end diff --git a/lib/posts.lua b/lib/posts.lua new file mode 100644 index 0000000..384a050 --- /dev/null +++ b/lib/posts.lua @@ -0,0 +1,68 @@ +local restia = require 'restia' +local params = require 'params' +local yaml = require 'lyaml' +local shapeshift = require 'shapeshift' +local string = require 'stringplus' + +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 + +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; + published = shapeshift.default(false, shapeshift.matches("^true$")) + } +end + +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 = {} + +for file in restia.utils.files(params.input, "^./posts/.*%.md$") do + print("Reading post "..file.."...") + local post = read_post(file) + post.head.file = file + + assert(validate_head(post.head)) + + post.head.timestamp = parsedate(post.head.date) + + if "string" == type(post.head.tags) then + post.head.tags = string.split(post.head.tags, "%a+") + end + + 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 = post.head.uri + + if post.head.published or params.unpublished then + table.insert(posts, post) + end +end + +table.sort(posts, function(a, b) + return a.head.timestamp > b.head.timestamp +end) + +return posts diff --git a/lib/stringplus.lua b/lib/stringplus.lua new file mode 100644 index 0000000..6d449f1 --- /dev/null +++ b/lib/stringplus.lua @@ -0,0 +1,11 @@ +local _string = {} + +function _string.split(str, pattern) + local result = {} + for item in str:gmatch(pattern) do + table.insert(result, item) + end + return result +end + +return setmetatable(_string, {__index=_G.string}) diff --git a/pages/index.html.skooma.yue b/pages/index.html.skooma.yue new file mode 100644 index 0000000..a65ac47 --- /dev/null +++ b/pages/index.html.skooma.yue @@ -0,0 +1,16 @@ +import output from require 'params' +slots, json = select 1, ... +posts = require 'posts' + +post = => + blogPost { + name: @head.slug + a @head.title, href: "/"..output..@head.uri + } + +slots.head title "Index" +slots.head script "window.posts = JSON.parse(`#{json}`)" +slots.head script type: 'module', src: "/#{output}/javascript/BlogPost.js" +slots.head script type: 'module', src: "/#{output}/javascript/LocalDate.js" + +return ul [li post p for p in *posts] diff --git a/pages/index.skooma.yue b/pages/index.skooma.yue deleted file mode 100644 index 90022ec..0000000 --- a/pages/index.skooma.yue +++ /dev/null @@ -1,16 +0,0 @@ -import output from require 'params' - -post = => - blogPost { - name: @head.slug - a @head.title, href: "/"..output..@head.uri - } - -(json) => { - title "Index" - script "window.posts = JSON.parse(`#{json}`)" - script type: 'module', src: "/#{output}/javascript/BlogPost.js" - script type: 'module', src: "/#{output}/javascript/LocalDate.js" -}, ( - ul [li post p for p in *@] -) diff --git a/pages/init.lua b/pages/init.lua new file mode 100644 index 0000000..90434b9 --- /dev/null +++ b/pages/init.lua @@ -0,0 +1,4 @@ +local glass = require 'glass' +return glass.bind('pages', { + (require 'glass.skooma.html'); +}) diff --git a/tasks.lua b/tasks.lua new file mode 100644 index 0000000..facdf2e --- /dev/null +++ b/tasks.lua @@ -0,0 +1,44 @@ +local task = require'spooder'.task + +local path = table.concat({ + "lib/?.lua", + "lib/?/init.lua", + "lua_modules/share/lua/5.4/?.lua", + "lua_modules/share/lua/5.4/?/init.lua", + ";", +}, ";") + +local cpath = path:gsub(".lua", ".so"):gsub("/share/", "/lib/") + +task.build { + description = "Builds the page"; + 'luarocks install --only-deps *.rockspec'; + 'tup'; + 'rm -rf blog/*'; + string.format( + [[ + export LUA_PATH='%s' + export LUA_CPATH='%s' + lua build.lua --copy css --copy javascript --output blog + ]], + path, cpath + ) +} + +task.deploy { + description = "Deploys the blog to latest version"; + depends = "build"; + [[ + hash=$(git log -1 --format=%h) + cd blog + find . | treh -c + git add --all + if git log -1 --format=%s | grep "$hash$" + then git commit --amend --no-edit + else git commit -m "Update blog to $hash" + fi + git push --force origin page + cd ../ + git stash pop || true + ]]; +} diff --git a/templates/init.lua b/templates/init.lua new file mode 100644 index 0000000..1995ee9 --- /dev/null +++ b/templates/init.lua @@ -0,0 +1,4 @@ +local glass = require 'glass' +return glass.bind('templates', { + (require 'glass.skooma.html'); +}) diff --git a/templates/main.html.skooma.yue b/templates/main.html.skooma.yue new file mode 100644 index 0000000..273db52 --- /dev/null +++ b/templates/main.html.skooma.yue @@ -0,0 +1,16 @@ +import output from require 'params' +import slotty from require 'skooma' +import 'config' + +slots = slotty! + +content, data = select 1, ... +html + lang: "english" + * head + * link rel: "stylesheet", href: "/#{output}/css/site.css" + * meta charset: "UTF-8" + * slots.head + * [ link rel: "modulepreload", href: module.url for module in *config.modules when module.preload ] + * body + * content slots, data diff --git a/templates/main.skooma.yue b/templates/main.skooma.yue deleted file mode 100644 index 0204575..0000000 --- a/templates/main.skooma.yue +++ /dev/null @@ -1,18 +0,0 @@ -import output from require 'params' -import 'modules' - -(...) => - head_content, body_content = @(...) - body_content = head_content unless body_content - render.html(html { - lang: "english" - head { - link rel: "stylesheet", href: "/#{output}/css/site.css" - meta charset: "UTF-8" - head_content - [ link rel: "modulepreload", href: module.url for module in *modules when module.preload ] - } - body { - body_content - } - }) diff --git a/templates/post.html.skooma.yue b/templates/post.html.skooma.yue new file mode 100644 index 0000000..0637772 --- /dev/null +++ b/templates/post.html.skooma.yue @@ -0,0 +1,14 @@ +import output from require 'params' +slots, post = select 1, ... + +url = (path) -> "/"..output..path + +slots.head title post.head.title +slots.head link rel: "stylesheet", href: "/#{output}/css/post.css" + +return (=>@) + * nav + * ul + * li a "Index", href: url "/" + * [li a post.head.title, href: url post.head.uri for post in *require("posts")] + * article { h1(post.head.title), post.body } diff --git a/templates/post.skooma.yue b/templates/post.skooma.yue deleted file mode 100644 index cac9f3e..0000000 --- a/templates/post.skooma.yue +++ /dev/null @@ -1,16 +0,0 @@ -import output from require 'params' - -url = (path) -> "/"..output..path - -(attributes) => { - title attributes.title - link rel: "stylesheet", href: "/#{output}/css/post.css" -}, { - 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), @ } -}