fix: Fixed the image on the homepage.

This commit is contained in:
Spencer Brower
2026-07-10 18:41:31 -04:00
parent c3574c6737
commit 1de6f58024
5 changed files with 165 additions and 63 deletions
+5
View File
@@ -3,3 +3,8 @@
- Look at the source for 3 template languages that support mustache syntax, - 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 and see how they implement the tempaltes, then pick the best one. One of them
should be Hugo / go. should be Hugo / go.
- [ ] Deal with the favicon
- [ ] Icon support.
- [ ] RSS
- [ ] sitemap
- [ ] robots.txt?
+97 -26
View File
@@ -7,22 +7,24 @@ import "core:os"
import "core:strings" import "core:strings"
Page_Type :: enum { Page_Type :: enum {
Home,
Post, Post,
Standalone, Standalone,
} }
Page :: struct { Page :: struct {
type: Page_Type, type: Page_Type,
slug: string, slug: string,
permalink: string, permalink: string,
title: string, title: string,
date: string, description: string,
draft: bool, date: string,
is_starred: bool, draft: bool,
menu: string, is_starred: bool,
body: string, menu: string,
body_html: string, body: string,
bundle_dir: string, body_html: string,
bundle_dir: string,
} }
// walk_content reads the content directory and returns all non-draft pages // walk_content reads the content directory and returns all non-draft pages
@@ -30,6 +32,7 @@ Page :: struct {
walk_content :: proc(content_path: string, include_drafts: bool) -> []Page { walk_content :: proc(content_path: string, include_drafts: bool) -> []Page {
pages: [dynamic]Page pages: [dynamic]Page
collect_home(&pages, content_path)
collect_standalone(&pages, content_path) collect_standalone(&pages, content_path)
posts_path := fmt.tprintf("%s/posts", content_path) posts_path := fmt.tprintf("%s/posts", content_path)
@@ -51,6 +54,27 @@ walk_content :: proc(content_path: string, include_drafts: bool) -> []Page {
return pages[:] return pages[:]
} }
collect_home :: proc(pages: ^[dynamic]Page, content_path: string) {
html_path := fmt.tprintf("%s/index.html", content_path)
if os.exists(html_path) {
page, ok := load_page(html_path, .Home, "")
if ok {
page.permalink = "/"
append(pages, page)
}
return
}
md_path := fmt.tprintf("%s/index.md", content_path)
if os.exists(md_path) {
page, ok := load_page(md_path, .Home, "")
if ok {
page.permalink = "/"
append(pages, page)
}
}
}
collect_standalone :: proc(pages: ^[dynamic]Page, content_path: string) { collect_standalone :: proc(pages: ^[dynamic]Page, content_path: string) {
entries, err := os.read_all_directory_by_path(content_path, context.allocator) entries, err := os.read_all_directory_by_path(content_path, context.allocator)
if err != nil { if err != nil {
@@ -60,14 +84,17 @@ collect_standalone :: proc(pages: ^[dynamic]Page, content_path: string) {
defer os.file_info_slice_delete(entries, context.allocator) defer os.file_info_slice_delete(entries, context.allocator)
for entry in entries { for entry in entries {
if !strings.has_suffix(entry.name, ".md") { if !is_content_file(entry.name) {
continue
}
if entry.name == "index.md" || entry.name == "index.html" {
continue continue
} }
if entry.type != .Regular { if entry.type != .Regular {
continue continue
} }
slug := entry.name[:len(entry.name) - 3] slug := strip_extension(entry.name)
page, ok := load_page(entry.fullpath, .Standalone, slug) page, ok := load_page(entry.fullpath, .Standalone, slug)
if ok { if ok {
append(pages, page) append(pages, page)
@@ -86,16 +113,19 @@ collect_posts :: proc(pages: ^[dynamic]Page, posts_path: string) {
for entry in entries { for entry in entries {
switch entry.type { switch entry.type {
case .Regular: case .Regular:
if !strings.has_suffix(entry.name, ".md") { if !is_content_file(entry.name) {
continue continue
} }
slug := entry.name[:len(entry.name) - 3] slug := strip_extension(entry.name)
page, ok := load_page(entry.fullpath, .Post, slug) page, ok := load_page(entry.fullpath, .Post, slug)
if ok { if ok {
append(pages, page) append(pages, page)
} }
case .Directory: case .Directory:
index_path := fmt.tprintf("%s/index.md", entry.fullpath) index_path := fmt.tprintf("%s/index.html", entry.fullpath)
if !os.exists(index_path) {
index_path = fmt.tprintf("%s/index.md", entry.fullpath)
}
if !os.exists(index_path) { if !os.exists(index_path) {
continue continue
} }
@@ -105,7 +135,6 @@ collect_posts :: proc(pages: ^[dynamic]Page, posts_path: string) {
append(pages, page) append(pages, page)
} }
case .Undetermined, .Symlink, .Named_Pipe, .Socket, .Block_Device, .Character_Device: case .Undetermined, .Symlink, .Named_Pipe, .Socket, .Block_Device, .Character_Device:
// Do nothing
} }
} }
} }
@@ -131,17 +160,25 @@ load_page :: proc(
return return
} }
page.type = page_type page.type = page_type
page.slug = slug page.slug = slug
page.title = fm.title page.title = fm.title
page.date = fm.date page.description = fm.description
page.draft = fm.draft page.date = fm.date
page.is_starred = fm.isStarred page.draft = fm.draft
page.menu = fm.menu page.is_starred = fm.isStarred
page.body = strings.clone(body) page.menu = fm.menu
page.body_html = cm.markdown_to_html_from_string(body, {.Unsafe}) page.body = strings.clone(body)
if strings.has_suffix(file_path, ".html") {
page.body_html = strings.clone(body)
} else {
page.body_html = cm.markdown_to_html_from_string(body, {.Unsafe})
}
switch page_type { switch page_type {
case .Home:
page.permalink = "/"
case .Post: case .Post:
page.permalink = fmt.aprintf("/posts/%s/", slug) page.permalink = fmt.aprintf("/posts/%s/", slug)
case .Standalone: case .Standalone:
@@ -152,3 +189,37 @@ load_page :: proc(
return return
} }
is_content_file :: proc(name: string) -> bool {
return strings.has_suffix(name, ".md") || strings.has_suffix(name, ".html")
}
strip_extension :: proc(name: string) -> string {
dot := strings.last_index(name, ".")
if dot < 0 {
return name
}
return name[:dot]
}
// copy_static_assets copies non-content files from the content root to the output directory.
copy_static_assets :: proc(content_path: string, output_dir: string) {
entries, err := os.read_all_directory_by_path(content_path, context.allocator)
if err != nil {
return
}
defer os.file_info_slice_delete(entries, context.allocator)
for entry in entries {
if entry.type != .Regular {
continue
}
if is_content_file(entry.name) {
continue
}
dest := fmt.tprintf("%s/%s", output_dir, entry.name)
if err := os.copy_file(dest, entry.fullpath); err != nil {
fmt.eprintfln("thor: cannot copy %s: %v", entry.name, err)
}
}
}
+4 -2
View File
@@ -6,6 +6,7 @@ import "core:strings"
Frontmatter :: struct { Frontmatter :: struct {
title: string, title: string,
description: string,
date: string, date: string,
publishDate: string, publishDate: string,
draft: bool, draft: bool,
@@ -44,8 +45,9 @@ parse_frontmatter :: proc(content: string) -> (fm: Frontmatter, body: string, ok
return return
} }
fm.title = json_get_string(obj, "title") fm.title = json_get_string(obj, "title")
fm.date = json_get_string(obj, "date") fm.description = json_get_string(obj, "description")
fm.date = json_get_string(obj, "date")
fm.publishDate = json_get_string(obj, "publishDate") fm.publishDate = json_get_string(obj, "publishDate")
fm.draft = json_get_bool(obj, "draft") fm.draft = json_get_bool(obj, "draft")
fm.isStarred = json_get_bool(obj, "isStarred") fm.isStarred = json_get_bool(obj, "isStarred")
+1 -1
View File
@@ -20,7 +20,7 @@ main :: proc() {
pages := walk_content(opt.content_dir, opt.drafts) pages := walk_content(opt.content_dir, opt.drafts)
render_site(pages, opt.output_dir) render_site(pages, opt.content_dir, opt.output_dir)
} }
load_default_options :: proc(opt: ^Options) { load_default_options :: proc(opt: ^Options) {
+58 -34
View File
@@ -4,45 +4,58 @@ import "core:fmt"
import "core:os" import "core:os"
import "core:strings" import "core:strings"
SITE_TITLE :: "One Idiot Developer"
SITE_DESC :: "This is fine...right?"
@(rodata)
MONTHS: [12]string = { MONTHS: [12]string = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
} }
HEADER :: ` render_site :: proc(pages: []Page, content_path: string, output_dir: string) {
<header>
<nav>
<ul>
<li class="mr-auto"><a href="/">Home</a></li>
<li><a href="/ideas/">Ideas</a></li>
<li><a href="/posts/">Posts</a></li>
</ul>
</nav>
</header>
`
render_site :: proc(pages: []Page, output_dir: string) {
sort_pages_by_date(pages) sort_pages_by_date(pages)
// Find home page and extract site title
home: Page
has_home := false
site_title := "Site"
for page in pages { for page in pages {
html := render_page_html(page) if page.type == .Home {
home = page
has_home = true
site_title = page.title
break
}
}
// 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 {
continue
}
html := render_page_html(page, site_title)
write_page(output_dir, page.permalink, html) write_page(output_dir, page.permalink, html)
} }
home_html := render_home_html(pages) // Render home page
write_file(fmt.tprintf("%s/index.html", output_dir), home_html) if has_home {
home_html := render_home_html(home, pages, site_title)
write_file(fmt.tprintf("%s/index.html", output_dir), home_html)
}
posts_html := render_posts_html(pages) // Render posts list page
posts_html := render_posts_html(pages, site_title)
write_page(output_dir, "/posts/", posts_html) write_page(output_dir, "/posts/", posts_html)
fmt.printfln("Rendered %d pages to %s", len(pages) + 2, output_dir) total := len(pages) + 1
if !has_home {
total += 1
}
fmt.printfln("Rendered %d pages to %s", total, output_dir)
} }
render_page_html :: proc(page: Page) -> string { render_page_html :: proc(page: Page, site_title: string) -> string {
body := fmt.aprintf( body := fmt.aprintf(
`<main> `<main>
<article class="prose"> <article class="prose">
@@ -55,15 +68,18 @@ render_page_html :: proc(page: Page) -> string {
render_date(page), render_date(page),
page.body_html, page.body_html,
) )
title := fmt.tprintf("%s | %s", page.title, SITE_TITLE) title := fmt.tprintf("%s | %s", page.title, site_title)
return render_chrome(title, body) return render_chrome(title, body)
} }
render_home_html :: proc(pages: []Page) -> string { render_home_html :: proc(home: Page, pages: []Page, site_title: string) -> string {
items: [dynamic]string items: [dynamic]string
defer delete(items) defer delete(items)
for page in pages { for page in pages {
if page.type == .Home {
continue
}
append(&items, render_post_item(page)) append(&items, render_post_item(page))
} }
@@ -72,24 +88,20 @@ render_home_html :: proc(pages: []Page) -> string {
body := fmt.aprintf( body := fmt.aprintf(
`<main> `<main>
<header class="text-center mb-28"> <header class="text-center mb-28">
<img class="mx-auto w-18 h-18 rounded-full" src="/avatar.jpg"> %s </header>
<h1 class="text-2xl/12 mt-2.5 mb-0 font-bold">%s</h1>
<p class="text-slate-400">%s</p>
</header>
<ul> <ul>
%s %s
</ul> </ul>
</main> </main>
`, `,
SITE_TITLE, home.body_html,
SITE_DESC,
post_list, post_list,
) )
return render_chrome(SITE_TITLE, body) return render_chrome(site_title, body)
} }
render_posts_html :: proc(pages: []Page) -> string { render_posts_html :: proc(pages: []Page, site_title: string) -> string {
parts: [dynamic]string parts: [dynamic]string
defer delete(parts) defer delete(parts)
@@ -123,7 +135,7 @@ render_posts_html :: proc(pages: []Page) -> string {
append(&parts, "</main>\n") append(&parts, "</main>\n")
body := strings.join(parts[:], "") body := strings.join(parts[:], "")
title := fmt.tprintf("Posts | %s", SITE_TITLE) title := fmt.tprintf("Posts | %s", site_title)
return render_chrome(title, body) return render_chrome(title, body)
} }
@@ -153,6 +165,18 @@ render_chrome :: proc(page_title: string, body: string) -> string {
) )
} }
HEADER :: `
<header>
<nav>
<ul>
<li class="mr-auto"><a href="/">Home</a></li>
<li><a href="/ideas/">Ideas</a></li>
<li><a href="/posts/">Posts</a></li>
</ul>
</nav>
</header>
`
render_post_item :: proc(page: Page) -> string { render_post_item :: proc(page: Page) -> string {
date_html := "" date_html := ""
if page.date != "" { if page.date != "" {