Compare commits

..

4 Commits

Author SHA1 Message Date
Spencer Brower 0dc6cc117f feat: Added robots.txt 2026-07-11 10:45:22 -04:00
Spencer Brower d10b832f3f feat: Added comment support. 2026-07-11 10:44:08 -04:00
Spencer Brower c3efbf80f0 build: Switched site build from Hugo to Thor. 2026-07-11 10:37:23 -04:00
Spencer Brower 177117e471 feat: Added icons. 2026-07-11 10:17:42 -04:00
3 changed files with 42 additions and 12 deletions
-3
View File
@@ -3,8 +3,6 @@
- Look at the source for 3 template languages that support mustache syntax,
and see how they implement the tempaltes, then pick the best one. One of them
should be Hugo / go.
- [ ] Deal with the favicon
- [ ] Icon support.
- [ ] robots.txt?
- [ ] Evaluate Tufte CSS — borrow sidenote CSS or replace TailwindCSS entirely
- Option B: Steal Tufte's sidenote/margin-note CSS (adapt for dark theme), keep TailwindCSS
@@ -17,4 +15,3 @@
- [ ] Nix build integration — main flake runs thor + tailwindcss instead of Hugo
- [ ] Copy-to-clipboard button on code blocks (was in Hugo's custom-head.html)
- [ ] OpenGraph meta tags
- [ ] utteranc.es comments on posts
+11
View File
@@ -0,0 +1,11 @@
package main
ICON_HOME :: `<svg aria-hidden="true" class="hi-svg-inline h-6 w-6" fill="none" height="1em" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" width="1em"><path d="m3 9 9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>`
ICON_GITHUB :: `<svg aria-hidden="true" class="hi-svg-inline h-7 w-7" fill="none" height="1em" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" width="1em"><path d="M15 22v-4a4.8 4.8.0 00-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35.0-3.5.0.0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35.0 3.5A5.403 5.403.0 004 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"/><path d="M9 18c-4.51 2-5-2-7-2"/></svg>`
ICON_RSS :: `<svg aria-hidden="true" class="hi-svg-inline h-7 w-7" fill="none" height="1em" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" width="1em"><path d="M4 11a9 9 0 019 9"/><path d="M4 4a16 16 0 0116 16"/><circle cx="5" cy="19" r="1"/></svg>`
ICON_CHEVRON_UP :: `<svg aria-hidden="true" class="hi-svg-inline h-10 w-10" fill="none" height="1em" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" width="1em"><path d="m18 15-6-6-6 6"/></svg>`
ICON_STAR :: `<svg aria-hidden="true" class="hi-svg-inline h-3.5 w-3.5 text-yellow-500 align-baseline mr-2" fill="currentColor" height="1em" viewBox="0 0 16 16" width="1em"><path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/></svg>`
+31 -9
View File
@@ -26,9 +26,6 @@ render_site :: proc(pages: []Page, content_path: string, output_dir: string, bas
}
}
// Copy static assets (avatar, favicon, etc.)
copy_static_assets(content_path, output_dir)
// Render individual content pages (skip home)
for page in pages {
if page.type == .Home {
@@ -58,6 +55,13 @@ render_site :: proc(pages: []Page, content_path: string, output_dir: string, bas
sitemap := generate_sitemap(pages, base_url)
write_file(fmt.tprintf("%s/sitemap.xml", output_dir), sitemap)
// Copy static assets (avatar, favicon, etc.)
copy_static_assets(content_path, output_dir)
// Generate robots.txt
robots := fmt.aprintf("User-agent: *\nAllow: /\nSitemap: %s/sitemap.xml\n", base_url)
write_file(fmt.tprintf("%s/robots.txt", output_dir), robots)
total := len(pages) + 1
if !has_home {
total += 1
@@ -66,17 +70,30 @@ render_site :: proc(pages: []Page, content_path: string, output_dir: string, bas
}
render_page_html :: proc(page: Page, site_title: string) -> string {
comments := ""
if page.type == .Post {
comments = `
<script src="https://utteranc.es/client.js"
repo="sbrow/sbrow.github.io"
issue-term="pathname"
label="Comment"
theme="github-dark"
crossorigin="anonymous"
async></script>`
}
body := fmt.aprintf(
`<main>
<article class="prose">
<h1>%s</h1>
%s %s
</article>
</article>%s
</main>
`,
page.title,
render_date(page),
page.body_html,
comments,
)
title := fmt.tprintf("%s | %s", page.title, site_title)
return render_chrome(title, body)
@@ -150,6 +167,7 @@ render_posts_html :: proc(pages: []Page, site_title: string) -> string {
}
render_chrome :: proc(page_title: string, body: string) -> string {
header := fmt.aprintf(HEADER, ICON_HOME)
return fmt.aprintf(
`<!DOCTYPE html>
<html lang="en">
@@ -163,8 +181,9 @@ render_chrome :: proc(page_title: string, body: string) -> string {
</head>
<body>
%s%s<footer>
<a href="https://github.com/sbrow" target="_blank" rel="noopener noreferrer me" title="Github">GitHub</a>
<a href="/index.xml" target="_blank" rel="noopener noreferrer me" title="Rss">RSS</a>
<a class="goto-top opacity-0" href="#">%s</a>
<a href="https://github.com/sbrow" target="_blank" rel="noopener noreferrer me" title="Github">%s</a>
<a href="/index.xml" target="_blank" rel="noopener noreferrer me" title="Rss">%s</a>
<p class="pt-5 prose">Proudly built with <a href="https://odin-lang.org/">Odin</a> and <a href="https://tailwindcss.com/">Tailwindcss</a></p>
<p><small>&copy;</small> 2026</p>
</footer>
@@ -174,8 +193,11 @@ render_chrome :: proc(page_title: string, body: string) -> string {
</html>
`,
page_title,
HEADER,
header,
body,
ICON_CHEVRON_UP,
ICON_GITHUB,
ICON_RSS,
)
}
@@ -183,7 +205,7 @@ HEADER :: `
<header>
<nav>
<ul>
<li class="mr-auto"><a href="/">Home</a></li>
<li class="mr-auto"><a href="/">%s</a></li>
<li><a href="/ideas/">Ideas</a></li>
<li><a href="/posts/">Posts</a></li>
</ul>
@@ -202,7 +224,7 @@ render_post_item :: proc(page: Page) -> string {
}
star := ""
if page.is_starred {
star = `<span class="text-yellow-500 mr-2">★</span>`
star = ICON_STAR
}
return fmt.aprintf(
` <li class="flex justify-between"><a href="%s">%s</a><span>%s%s</span></li>`,