Org-Mode Static Site
I like org-mode, and I want to generate content for a static site (blog, cv, etc). I'll use emacs to edit and export org-mode files to html, then tweak the results for aesthetics.
tldr
Do this after using org-export-to-html for each org file in the pages/ and posts/ directories:
./gen.ijs pages/ posts/ templates/page.html
Using this script:
#!/usr/bin/env jj
usage =: {{)n
usage:
./gen.ijs "path/to/pages/" "path/to/posts/" "path/to/template.html"
Results:
pages/foo.html => public/foo.html
posts/bar.html => public/posts/bar.html
=> public/index.html
}}
{{ if. 3~:#args =: 2}.y do. exit 1[echo usage end. }} ARGV NB. right number of args?
'pages posts template' =: args
pages =: 1 dir pages,'/*html' NB. pages don't have any particular naming convention
posts =: 1 dir posts,'20*-*-*-*html' NB. posts start with a date like 2021-02-18-
template =: fread template
stem =: {{ '/'&taketo &.|. y }} NB. 'a/b/c' => 'c'
titleof =: {{ '.'taketo 11}. '- 'charsub stem y }} NB. '/a/b/2021-10-10-a-b-c.html' => 'a b c'
dateof =: {{ 10{. stem y }} NB. '2021-10-10-foo-bar.html' => '2021-10-10'
tag =: {{ '<', x, '>', y, '>',~ '</', 0{::;: x }} NB. 'a href="foo"' tag 'y' => '<a href="foo">y</a>'
link =: {{ ('a href="',x,'"') tag y }}
gist =: {{ 'p class="post"' tag y link ('span class="post-name"' tag titleof name),'span class="post-date"'&tag dateof name =. stem y }}
post_proc =: {{
page =. fread y
name =. stem y
post_date =. dateof name
post_title =. titleof name
extra_style =. ,>'<style type="text/css">pre.src.*</style>' rxall page
t =. template rplc '<!-- TITLE -->'; extra_style, 'title' tag post_title
t =. t rplc '<!-- CANON -->';'<link rel="canonical" href="alexshroyer.com/posts/',name,'">'
r =. ('public/posts/',name) fwrite~ t rplc'<!-- CONTENT -->';'<!-- NAV -->',~ '<body>'takeafter'</body>'taketo page
if. r>0 do. echo 'wrote public/posts/',name, ' (',(":r),' bytes)' end.}}
page_proc =: {{
page =. fread y
name =. stem y
page_title =. titleof name
t =. template rplc '<!-- TITLE -->'; 'title' tag page_title
t =. t rplc '<!-- CANON -->';'<link rel="canonical" href="alexshroyer.com/',name,'">'
r =. ('public/',name) fwrite~ t rplc'<!-- CONTENT -->';'<body>'takeafter'</body>'taketo page
if. r>0 do. echo 'wrote public/',name, ' (',(":r),' bytes)' end.}}
toc =: {{)n <div id="preamble" class="status"><h1 class="title">Posts</h1></div> <div class="content"><div class="outline-2"> <!-- GISTS --> </div></div> }}
gen_index =: {{
t =. template rplc '<!-- TITLE -->'; 'title' tag 'Home'
t =. t rplc '<!-- CANON -->';'<link rel="canonical" href="alexshroyer.com">'
names =. \:~ 'public/'&takeafter each 1 dir 'public/posts/20**-**-**-*html'
r =. 'public/index.html' fwrite~ t rplc '<!-- CONTENT -->' ; toc rplc '<!-- GISTS -->'; LF joinstring gist each names
if. r>0 do. echo 'wrote public/index.html (', (":r), ' bytes)' end. }}
post_proc each posts
page_proc each pages
gen_index ''
exit ''
Creating
For the most part, write and edit in org-mode. When it's time to publish something, generate the corresponding html from within emacs. Preview the page - org-mode links should become html links, as long as the linked page is also published as html.
First, put org mode files and images under one folder:
+ site/2020-01-18-first-post.org + site/2021-10-08-example-post.org + site/images/background.png + site/images/favicon.ico + site/my-projects.org + site/style.css
Converting
Next, convert org to html:
+ site/2020-01-18-first-post.html site/2020-01-18-first-post.org + site/2021-10-08-example-post.html site/2021-10-08-example-post.org site/images/background.png site/images/favicon.ico + site/my-projects.html site/my-projects.org site/style.css
Post-Processing
Post-process the html. This means extracting the body from the html files, and fitting it into the page template for the site. I don't want to mess with org's html conversion, so I'll mostly throw away the exported header and replace it with my template. However, some bits need to be spliced in, such as the canonical url, keywords, and page title. For simplicity, extract these bits from the original org file.
Generate Index
Finally, generate a homepage (index.html).
This page has links to all posts, and possibly short excerpts from each one.
If posts have metadata like "tags", they can show up in the index page too.
site/2020-01-18-first-post.html site/2020-01-18-first-post.org site/2021-10-08-example-post.html site/2021-10-08-example-post.org site/images/background.png site/images/favicon.ico + site/index.html site/my-projects.html site/my-projects.org site/style.css