diff options
| author | Ahmed <git@gumx.cc> | 2026-06-14 16:30:47 +0300 |
|---|---|---|
| committer | Ahmed <git@gumx.cc> | 2026-06-14 16:30:47 +0300 |
| commit | 307ff4912bac1095ebf382d70241f19409b2f8b8 (patch) | |
| tree | a2c3d36634fa86705e48db4fc797437ba816e5e0 /_shared | |
| parent | fa568e13d04c0aacdb29ca252b783f1dcdb6bf23 (diff) | |
add: templating
Diffstat (limited to '_shared')
| -rw-r--r-- | _shared/build.py | 94 | ||||
| -rw-r--r-- | _shared/footer.html | 12 | ||||
| -rw-r--r-- | _shared/style.css | 22 |
3 files changed, 128 insertions, 0 deletions
diff --git a/_shared/build.py b/_shared/build.py new file mode 100644 index 0000000..935bf5c --- /dev/null +++ b/_shared/build.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +"""Build sites from body.html + meta into index.html using shared templates.""" +import json +import os +import sys + +FAVICON = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1IDUiPjxyZWN0IHg9IjEiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIxIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMCIgeT0iMiIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjEiIHk9IjIiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIyIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PC9zdmc+" + + +def render(title, breadcrumb, style, extra_css, body, footer): + css = style + ("\n" + extra_css if extra_css.strip() else "") + return f"""<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<link rel="icon" type="image/svg+xml" href="{FAVICON}"> +<meta name="viewport" content="width=device-width,initial-scale=1"> +<title>{title}</title> +<style> +{css} +</style> +</head> +<body> +<header> +<h1><a href="https://gumx.cc">gumx</a> / {breadcrumb}</h1> +</header> +<main> +{body} +</main> +{footer} +</body> +</html> +""" + + +def build_demo_body(demos_file): + demos = json.load(open(demos_file)) + parts = [] + for d in demos: + url = d.get("url", "#") + title = d.get("title", d.get("name", "")) + desc = d.get("description", "") + src = d.get("source", "") + src_link = f' / <a href="{src}">source</a>' if src else "" + parts.append(f'<p><a href="{url}">{title}</a>{src_link}</p>\n<p>{desc}</p>') + return "\n".join(parts) + + +def build(sites_dir): + shared = os.path.join(sites_dir, "_shared") + style = open(os.path.join(shared, "style.css")).read() + footer = open(os.path.join(shared, "footer.html")).read() + + for site in sorted(os.listdir(sites_dir)): + if site.startswith("_") or site == "fonts" or site == "hooks": + continue + site_dir = os.path.join(sites_dir, site) + if not os.path.isdir(site_dir): + continue + + body_file = os.path.join(site_dir, "body.html") + demos_file = os.path.join(site_dir, "demos.json") + + if site == "demo.gumx.cc" and os.path.exists(demos_file): + body = build_demo_body(demos_file) + elif os.path.exists(body_file): + body = open(body_file).read() + else: + continue + + title = site + breadcrumb = site + meta_file = os.path.join(site_dir, "meta") + if os.path.exists(meta_file): + for line in open(meta_file): + k, _, v = line.strip().partition("=") + if k == "TITLE": + title = v.strip('"') + elif k == "BREADCRUMB": + breadcrumb = v.strip('"') + + extra_css = "" + extra_file = os.path.join(site_dir, "extra.css") + if os.path.exists(extra_file): + extra_css = open(extra_file).read() + + out = render(title, breadcrumb, style, extra_css, body, footer) + with open(os.path.join(site_dir, "index.html"), "w") as f: + f.write(out) + print(f"built: {site}") + + +if __name__ == "__main__": + build(sys.argv[1] if len(sys.argv) > 1 else ".") diff --git a/_shared/footer.html b/_shared/footer.html new file mode 100644 index 0000000..3aedfc6 --- /dev/null +++ b/_shared/footer.html @@ -0,0 +1,12 @@ +<footer> +<hr> +<a href="https://twt.gumx.cc">twt</a> / +<a href="https://git.gumx.cc">git</a> / +<a href="https://mail.gumx.cc">mail</a> / +<a href="https://irc.gumx.cc">irc</a> / +<a href="https://files.gumx.cc">files</a> / +<a href="https://vpn.gumx.cc">vpn</a> / +<a href="https://pgp.gumx.cc">pgp</a> / +<a href="https://demo.gumx.cc">demo</a> / +<a href="https://wk.fo">wk.fo</a> +</footer> diff --git a/_shared/style.css b/_shared/style.css new file mode 100644 index 0000000..0f7e7cf --- /dev/null +++ b/_shared/style.css @@ -0,0 +1,22 @@ +@font-face { font-family: "Kawkab Mono"; src: url(/fonts/KawkabMono-Regular.woff2); font-weight: normal; } +@font-face { font-family: "Kawkab Mono"; src: url(/fonts/KawkabMono-Bold.woff2); font-weight: bold; } +* { unicode-bidi: plaintext; box-sizing: border-box; } +html { color: black; background-color: white; } +body { font-family: "Kawkab Mono"; font-size: 16px; line-height: 1.4; margin: 0; padding: 4rem 0; min-height: 100%; overflow-wrap: break-word; } +main, header, footer { max-width: 800px; margin-inline: auto; padding: 0 2rem; } +h1, header, footer { text-align: center; } +main { text-align: justify; } +p, h2, h3, h4 { margin: 1em 0 0 0; } +ol { margin: 0.5em 0 0 0; } +table { margin: auto; border-collapse: collapse; } +th, td { border: 1px solid; padding: 0.3em 0.8em; } +pre { margin: 1em 0; } +pre code { border: thin solid; padding: 1em; display: block; text-align: start; overflow-x: scroll; } +code { font-size: 85%; } +hr { border: none; border-top: thin solid; margin: 1.25rem 0; } +header { margin-bottom: 1em; } +footer { margin-top: 3em; } +a { color: inherit; } +@media (max-width: 600px) { body { font-size: 0.9em; } h1 { font-size: 1.8em; } } +@media (max-width: 400px) { body { font-size: 0.8em; } h1 { font-size: 1.6em; } } +@media (prefers-color-scheme: dark) { html { filter: invert(1); } img { filter: invert(1); } } |
