feat: Post index gets rendered.

This commit is contained in:
Spencer Brower
2026-07-10 18:10:38 -04:00
parent 44faebee6c
commit 87bd2b828b
+127 -51
View File
@@ -7,6 +7,12 @@ import "core:strings"
SITE_TITLE :: "One Idiot Developer" SITE_TITLE :: "One Idiot Developer"
SITE_DESC :: "This is fine...right?" SITE_DESC :: "This is fine...right?"
@(rodata)
MONTHS: [12]string = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
}
CSS :: ` CSS :: `
body { background: #020617; color: #e2e8f0; font-family: system-ui, sans-serif; max-width: 720px; margin: 0 auto; padding: 2rem; line-height: 1.6; } body { background: #020617; color: #e2e8f0; font-family: system-ui, sans-serif; max-width: 720px; margin: 0 auto; padding: 2rem; line-height: 1.6; }
a { color: #7dd3fc; } a { color: #7dd3fc; }
@@ -31,6 +37,8 @@ NAV :: `
` `
render_site :: proc(pages: []Page, output_dir: string) { render_site :: proc(pages: []Page, output_dir: string) {
sort_pages_by_date(pages)
for page in pages { for page in pages {
html := render_page_html(page) html := render_page_html(page)
write_page(output_dir, page.permalink, html) write_page(output_dir, page.permalink, html)
@@ -39,37 +47,27 @@ render_site :: proc(pages: []Page, output_dir: string) {
home_html := render_home_html(pages) home_html := render_home_html(pages)
write_file(fmt.tprintf("%s/index.html", output_dir), home_html) write_file(fmt.tprintf("%s/index.html", output_dir), home_html)
fmt.printfln("Rendered %d pages to %s", len(pages) + 1, output_dir) posts_html := render_posts_html(pages)
write_page(output_dir, "/posts/", posts_html)
fmt.printfln("Rendered %d pages to %s", len(pages) + 2, output_dir)
} }
render_page_html :: proc(page: Page) -> string { render_page_html :: proc(page: Page) -> string {
return fmt.aprintf( body := fmt.aprintf(
`<!DOCTYPE html> `<main>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>%s | %s</title>
<style>%s</style>
</head>
<body>
%s<main>
<article> <article>
<h1>%s</h1> <h1>%s</h1>
%s %s %s %s
</article> </article>
</main> </main>
</body>
</html>
`, `,
page.title,
SITE_TITLE,
CSS,
NAV,
page.title, page.title,
render_date(page), render_date(page),
page.body_html, page.body_html,
) )
title := fmt.tprintf("%s | %s", page.title, SITE_TITLE)
return render_chrome(title, body)
} }
render_home_html :: proc(pages: []Page) -> string { render_home_html :: proc(pages: []Page) -> string {
@@ -77,25 +75,65 @@ render_home_html :: proc(pages: []Page) -> string {
defer delete(items) defer delete(items)
for page in pages { for page in pages {
if page.type != .Post { append(&items, render_post_item(page))
continue
}
date_short := page.date
if len(date_short) > 10 {
date_short = date_short[:10]
}
star := ""
if page.is_starred {
star = " \xe2\x98\x85"
}
append(
&items,
fmt.aprintf(` <li><a href="%s">%s</a> <time>%s</time>%s</li>`, page.permalink, page.title, date_short, star),
)
} }
post_list := strings.join(items[:], "\n") post_list := strings.join(items[:], "\n")
body := fmt.aprintf(
`<main>
<header>
<h1>%s</h1>
<p>%s</p>
</header>
<ul>
%s
</ul>
</main>
`,
SITE_TITLE,
SITE_DESC,
post_list,
)
return render_chrome(SITE_TITLE, body)
}
render_posts_html :: proc(pages: []Page) -> string {
parts: [dynamic]string
defer delete(parts)
append(&parts, "<main>\n <h1>Posts</h1>\n")
current_year := ""
open := false
for page in pages {
if page.type != .Post {
continue
}
year := get_year(page.date)
if year != current_year {
if open {
append(&parts, " </ul>\n")
}
open = true
current_year = year
append(&parts, fmt.aprintf(" <h2>%s</h2>\n <hr>\n <ul>\n", year))
}
append(&parts, render_post_item(page))
append(&parts, "\n")
}
if open {
append(&parts, " </ul>\n")
}
append(&parts, "</main>\n")
body := strings.join(parts[:], "")
title := fmt.tprintf("Posts | %s", SITE_TITLE)
return render_chrome(title, body)
}
render_chrome :: proc(page_title: string, body: string) -> string {
return fmt.aprintf( return fmt.aprintf(
`<!DOCTYPE html> `<!DOCTYPE html>
<html lang="en"> <html lang="en">
@@ -106,24 +144,32 @@ render_home_html :: proc(pages: []Page) -> string {
<style>%s</style> <style>%s</style>
</head> </head>
<body> <body>
%s<main> %s%s
<header>
<h1>%s</h1>
<p>%s</p>
</header>
<ul>
%s
</ul>
</main>
</body> </body>
</html> </html>
`, `,
SITE_TITLE, page_title,
CSS, CSS,
NAV, NAV,
SITE_TITLE, body,
SITE_DESC, )
post_list, }
render_post_item :: proc(page: Page) -> string {
date_html := ""
if page.date != "" {
date_html = fmt.aprintf(" <time>%s</time>", format_date(page.date))
}
star := ""
if page.is_starred {
star = " \xe2\x98\x85"
}
return fmt.aprintf(
` <li><a href="%s">%s</a>%s%s</li>`,
page.permalink,
page.title,
date_html,
star,
) )
} }
@@ -131,11 +177,41 @@ render_date :: proc(page: Page) -> string {
if page.date == "" { if page.date == "" {
return "" return ""
} }
date_short := page.date return fmt.aprintf(` <time datetime="%s">%s</time>` + "\n", page.date, format_date(page.date))
if len(date_short) > 10 { }
date_short = date_short[:10]
format_date :: proc(iso: string) -> string {
if len(iso) < 10 {
return iso
}
year := iso[:4]
month_num := (int(iso[5]) - 0x30) * 10 + (int(iso[6]) - 0x30)
day_num := (int(iso[8]) - 0x30) * 10 + (int(iso[9]) - 0x30)
if month_num < 1 || month_num > 12 {
return iso[:10]
}
return fmt.aprintf("%d %s %s", day_num, MONTHS[month_num - 1], year)
}
get_year :: proc(iso: string) -> string {
if len(iso) < 4 {
return ""
}
return iso[:4]
}
sort_pages_by_date :: proc(pages: []Page) {
for i in 1..<len(pages) {
key := pages[i]
j := i - 1
for j >= 0 && pages[j].date < key.date {
pages[j + 1] = pages[j]
j -= 1
}
pages[j + 1] = key
} }
return fmt.aprintf(` <time datetime="%s">%s</time>` + "\n", page.date, date_short)
} }
write_page :: proc(output_dir: string, permalink: string, html: string) { write_page :: proc(output_dir: string, permalink: string, html: string) {
@@ -145,7 +221,7 @@ write_page :: proc(output_dir: string, permalink: string, html: string) {
} }
dir := fmt.tprintf("%s/%s", output_dir, rel) dir := fmt.tprintf("%s/%s", output_dir, rel)
if err := os.make_directory_all(dir); err != nil { if err := os.make_directory_all(dir); err != nil && err != .Exist {
fmt.eprintfln("thor: cannot create %s: %v", dir, err) fmt.eprintfln("thor: cannot create %s: %v", dir, err)
return return
} }