add static site generator

This commit is contained in:
2025-05-07 17:14:45 -07:00
parent ae66d51f22
commit 1faa6dad4f
9 changed files with 168 additions and 0 deletions

9
www/build.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/bash
(cd src; hy build.hy)
mkdir -p site/{html,assets,scripts}
cp -r src/output/* site/html
echo 'html generated'
cp -r src/scripts site/
echo 'scripts copied'
cp -r src/assets site/
echo 'assets copied'

30
www/src/build.hy Normal file
View File

@ -0,0 +1,30 @@
(import glob [glob])
(import os [mkdir])
(import os.path [isfile :as file? isdir :as dir?])
(import templates *)
(import utils *)
(require hyrule.control [defmain])
(defmain []
(when (not (dir? "output"))
(mkdir "output"))
(for [path (glob "./pages/**/*" :recursive True)]
(when (in "__pycache__" path)
(continue))
(cond
(and (dir? path) (not (dir? (.replace path "pages" "output"))))
(do
(print f"creating {path}")
(mkdir (.replace path "pages" "output")))
(file? path)
(do
(print f"building {path}")
(setv page-name (.split (cut path 2 -3) "/"))
(with [target (open (+ "./output/" (.join "/" (cut page-name 1 None)) ".html") "w")]
(.write target (form->html
(hy.eval (hy.read (with [source (open path "r")]
(.read source)))))))))))

View File

@ -0,0 +1,5 @@
(import .footer [footer])
(import .header [header])
(import .page [page])
(import .comments [comments])
(import .link [link])

View File

@ -0,0 +1,12 @@
(import urllib.parse [quote-plus])
(defn comments [route]
`(section (:class comments)
(h2 comments)
(form (:id comment :method post :action ~f"/comment?route={route}" :autocomplete off)
(textarea (:id comment :name comment :placeholder comment :required True :maxlength 2048))
(input (:id name :type text :name name :placeholder username :required True :maxlength 32))
(input (:id website :type text :name site :placeholder "website (not required)" :maxlength 256))
(input (:id submit :type submit :value post)))
(~f"$[ls -r ./www/data/comments/{(quote-plus route :safe "")} | xargs -I# cat ./www/data/comments/{(quote-plus route :safe "")}/#]")))

View File

@ -0,0 +1,18 @@
(import utils [run])
(defn footer []
`(footer
(div
"page rendered at $[date +%s]"
(br)
"page compiled at " ~(run "date +%s"))
(img (:src "/assets/88x31/natalieee.net.png" :alt "natalieee.net 88x31" :width "88" :height "31"))
(div
(footnote (:style "margin-top: 5px") "all content, with the exception of 88x31 buttons or unless otherwise noted is created by natalie and is licensed under a CC BY-NC-SA 4.0 license."))
(a (:href "https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en")
(img (:src "/assets/88x31/by-nc-sa.png" :alt "license 88x31" :width "88" :height "31")))
(footnote (:style "margin-top: 5px") "▖▖▖▖▘▖▖▖▖▘▌▖▖▖▘"
(div (:style "flex-direction: row; width: 14ch; gap: 1ch; margin-right: 5px;")
(a (:href "https://stellophiliac.github.io/roboring/0x6e6174/previous") "<-")
(a (:href "https://stellophiliac.github.io/roboring") "roboring")
(a (:href "https://stellophiliac.github.io/roboring/0x6e6174/next") "->")))))

View File

@ -0,0 +1,14 @@
(defn header []
`(header
(nav
(ul
(li
(a (:href "/") "natalieee.net"))
(li
(a (:href "./..") "back"))
(li
(a (:href "/html/about-site.html") "about (site)"))
(li
(a (:href "/html/about-natalie.html") "about (natalie)"))
(li
(a (:href "/html/thoughts.html") "thoughts (blog)"))))))

View File

@ -0,0 +1,2 @@
(defn link [link [label None]]
`(a (:href ~link) ~(if label label link)))

30
www/src/templates/page.hy Normal file
View File

@ -0,0 +1,30 @@
(import templates.header [header])
(import templates.footer [footer])
(import utils [run hy-env])
(import random [randint])
(defn page [html
[title "natalieee.net"]
[author "natalie roentgen connolly"]
[description ""]
[extra-head None]]
(run "echo > /tmp/footnote_count")
`(html (:lang "en")
(head ()
(link (:rel "stylesheet" :href "/assets/style.css" :type "text/css"))
(link (:rel preload :href "/assets/style.css"))
(meta (:http-equiv "content-type" :content "text/html; charset=utf-8"))
(meta (:name "viewport" :content "width=device-width, initial-scale=1"))
(meta (:name "author" :content ~author))
(meta (:name "fediverse:creator" :content "@0x6e6174@catgirl.cloud"))
~(when description `(meta (:name "description" :content ~description)))
~(when description `(meta (:name "og:description" :content ~description)))
(link (:rel "me" :href "https://mastodon.catgirl.cloud/@0x6e6174"))
~(when extra-head extra-head)
(title ~title))
(body ()
~(header)
(main ()
~html)
~(footer))))

48
www/src/utils.hy Normal file
View File

@ -0,0 +1,48 @@
(import html [escape])
(import itertools [batched])
(import subprocess [run :as subprocess/run PIPE])
(import os [environ :as hy-env])
(require hyrule.destructure [setv+])
(setv self-closing-tags ['area 'base 'br 'col 'embed 'hr 'img 'input 'link 'meta 'param 'source 'track 'wbr])
(defn run [command]
(setv env hy-env)
(setv (get env "PATH") (+ (get hy-env "PATH") ":./scripts"))
(.decode (getattr (subprocess/run command :env env :shell True :stdout PIPE :stderr None) "stdout")))
(defn form->html [html]
(when (is html None)
(return ""))
(cond
(isinstance html str) (str html)
(or (isinstance html int) (isinstance html float)) (str html)
(isinstance html hy.models.Expression)
(cond
(not (isinstance (get html 0) hy.models.Symbol))
(.join "" (map form->html html))
True
(do
(setv+ [tag attrs :& rest] html)
(when (is attrs None) (setv attrs []))
(when (len attrs)
(when (not (isinstance (get attrs 0) hy.models.Keyword))
(do
(setv rest (+ [attrs] rest))
(setv attrs []))))
(when (not (isinstance tag hy.models.Symbol))
(return ""))
(.format "<{}{}>{}{}"
(.lower tag)
(+ (if (len attrs) " " "") (.join " " (lfor [k v] (batched attrs :n 2)
f"{(cut (str k) 1 None)}=\"{v}\"")))
(.join "" (map form->html rest))
(if (not-in tag self-closing-tags)
f"</{(.lower tag)}>"
""))))))