all repos — www @ 83fdc3fe1e04e4ed67fc232a412247b3b4fb70f2

deserthorns.net content + generator

move site config to site.json, generate header nav breadcrumb links
sageclove
Mon, 03 Mar 2025 22:31:04 -0700
commit

83fdc3fe1e04e4ed67fc232a412247b3b4fb70f2

parent

209a98b435bfefe3af1563fe6df5aa68f4774428

8 files changed, 120 insertions(+), 174 deletions(-)

jump to
D .site

@@ -1,10 +0,0 @@

-creative - music - visual - photography -projects - keyboard -about - meta - style - sitemap
M assets/css/style.cssassets/css/style.css

@@ -5,6 +5,7 @@ }

body { margin: 0 auto; + padding: 0 1rem; max-width: 60rem; -webkit-text-size-adjust: 100%; }

@@ -59,6 +60,7 @@ }

@media screen and (max-width: 600px) { body { - margin: 0 1rem; + margin: 0 1rem; + padding: 0; } }
M build/build.gobuild/build.go

@@ -3,15 +3,13 @@

package main import ( - "bufio" + "encoding/json" "fmt" - "io" "log" "net/http" "os" "path/filepath" "strconv" - "strings" "text/template" "time" )

@@ -19,7 +17,7 @@

type PageProperties struct { Title string StylePath string - HeaderLinks [][]*HeaderLink + Breadcrumbs []*HeaderLink } type HeaderLink struct {

@@ -27,10 +25,10 @@ Name string

Active bool } -type Page struct { - Name string - Parent *Page - Children []*Page +type PageConfig struct { + Parent string + Title string + Image string } var rootPath = "."

@@ -79,139 +77,6 @@ http.NotFound(responseWriter, request)

} } -func buildSiteLinkedList() *Page { - rootNode := &Page{ - Name: "index", - Parent: nil, - } - parentNode := rootNode - tailNode := rootNode - currentDepth := 0 - siteFile, _ := os.Open(filepath.Join(rootPath, ".site")) - scanner := bufio.NewScanner(siteFile) - scanner.Split(bufio.ScanLines) - for scanner.Scan() { - depth := strings.Count(strings.TrimRight(scanner.Text(), " "), " ") - pageName := strings.TrimLeft(scanner.Text(), " ") - if len(pageName) > 0 { - if depth > currentDepth { - currentDepth = depth - parentNode = tailNode - } else if depth < currentDepth { - unwind := (currentDepth - depth) + 1 - currentDepth = depth - for range unwind { - tailNode = tailNode.Parent - } - parentNode = tailNode - } - newNode := &Page{ - Name: pageName, - Parent: parentNode, - } - parentNode.Children = append(parentNode.Children, newNode) - tailNode = newNode - } - } - return rootNode -} - -func parentLinks(page *Page) []*HeaderLink { - if page.Parent == nil { - return nil - } - if page.Parent.Parent == nil { - return nil - } - parentPages := page.Parent.Parent.Children - parentLinks := make([]*HeaderLink, len(parentPages)) - for i, parentPage := range parentPages { - parentLinks[i] = &HeaderLink{ - Name: parentPage.Name, - Active: page.Parent == parentPage, - } - } - return parentLinks -} - -func siblingLinks(page *Page) []*HeaderLink { - if page.Parent == nil { - return nil - } - siblingPages := page.Parent.Children - siblingLinks := make([]*HeaderLink, len(siblingPages)) - for i, siblingPage := range siblingPages { - siblingLinks[i] = &HeaderLink{ - Name: siblingPage.Name, - Active: page == siblingPage, - } - } - return siblingLinks -} - -func childLinks(page *Page) []*HeaderLink { - childPages := page.Children - childLinks := make([]*HeaderLink, len(childPages)) - for i, childPage := range childPages { - childLinks[i] = &HeaderLink{ - Name: childPage.Name, - Active: false, - } - } - return childLinks -} - -func buildSite(page *Page) { - outDir := filepath.Join("out") - pageSrcDir := filepath.Join(rootPath, "pages") - templateSrcDir := filepath.Join(rootPath, "templates") - parents := parentLinks(page) - siblings := siblingLinks(page) - children := childLinks(page) - headerLinks := [][]*HeaderLink{parents, siblings, children} - // https://abhinavg.net/2019/07/11/zero-alloc-slice-filter/ - filteredHeaderLinks := headerLinks[:0] - for _, headerLink := range headerLinks { - if headerLink != nil { - filteredHeaderLinks = append(filteredHeaderLinks, headerLink) - } - } - pageFilePath := filepath.Join(pageSrcDir, page.Name+".html") - pageFileInfo, _ := os.Stat(pageFilePath) - if pageFileInfo == nil { - copyFile( - filepath.Join(templateSrcDir, "page.html"), - pageFilePath, - ) - } - os.Mkdir(outDir, 0777) - outfile, _ := os.Create(filepath.Join(outDir, page.Name+".html")) - template, err := template.ParseFiles( - filepath.Join(templateSrcDir, "document.html"), - filepath.Join(templateSrcDir, "header.html"), - filepath.Join(pageSrcDir, page.Name+".html"), - ) - __(err) - template.Execute( - outfile, - &PageProperties{ - Title: page.Name, - StylePath: "/assets/css/style." + strconv.FormatInt(now.Unix(), 10) + ".css", - HeaderLinks: filteredHeaderLinks, - }, - ) - for _, child := range page.Children { - buildSite(child) - } -} - -func copyFile(srcPath string, dstPath string) { - dst, _ := os.Create(dstPath) - src, _ := os.Open(srcPath) - io.Copy(dst, src) - dst.Sync() -} - func copyDir(srcPath string, dstPath string) { srcFS := os.DirFS(srcPath) os.CopyFS(dstPath, srcFS)

@@ -238,7 +103,7 @@ os.RemoveAll(filepath.Join("out"))

os.Mkdir(filepath.Join("out"), 0777) fmt.Print("Building pages...") - buildSite(buildSiteLinkedList()) + buildPages() fmt.Println("Done") fmt.Print("Copying assets...")

@@ -256,3 +121,63 @@ fmt.Println("Done")

fmt.Println("Build complete.") } + +func buildPages() { + siteJson, err := os.ReadFile(filepath.Join(rootPath, "site.json")) + if err != nil { + fmt.Println(err) + return + } + var pageConfigs map[string]*PageConfig + err = json.Unmarshal(siteJson, &pageConfigs) + if err != nil { + fmt.Println(err) + return + } + for fileName, page := range pageConfigs { + parent := page.Parent + breadcrumbs := make([]*HeaderLink, 0) + for parent != "" { + parentPage := pageConfigs[parent] + breadcrumbs = append( + []*HeaderLink{ + { + Name: parent, + Active: false, + }, + }, + breadcrumbs..., + ) + parent = parentPage.Parent + } + pageName := page.Title + if pageName == "" { + pageName = fileName + } + breadcrumbs = append( + breadcrumbs, + &HeaderLink{ + Name: pageName, + Active: true, + }, + ) + outDir := filepath.Join("out") + pageSrcDir := filepath.Join(rootPath, "pages") + templateSrcDir := filepath.Join(rootPath, "templates") + outfile, _ := os.Create(filepath.Join(outDir, fileName+".html")) + template, _ := template.ParseFiles( + filepath.Join(templateSrcDir, "document.html"), + filepath.Join(templateSrcDir, "header.html"), + filepath.Join(pageSrcDir, fileName+".html"), + ) + pageProps := &PageProperties{ + Title: pageName, + StylePath: "/assets/css/style." + strconv.FormatInt(now.Unix(), 10) + ".css", + Breadcrumbs: breadcrumbs, + } + template.Execute( + outfile, + pageProps, + ) + } +}
M pages/keyboard.htmlpages/keyboard.html

@@ -14,11 +14,15 @@ </style>

<img src="/assets/img/keyboard.jpg"/> <p> - My keyboard is a hand-built (except for the PCB) Atreus62 from Profet Keyboards. - This project was a few firsts for me: it was my first soldering project (all those surface-mount diodes were a challenge) and it was my first time using a laser cutter to cut the acrylic for the case. + My keyboard is a hand-built Atreus62 from Profet Keyboards. + This project was a few firsts for me: it was my first soldering + project (all those surface-mount diodes were a challenge) and + it was my first time using a laser cutter to cut the acrylic for the case. </p> +<h2>hardware</h2> <p> - The keyswitches for the alphanumerics are Cherry MX Clears, while the modifiers use Cherry MX Browns. + The keyswitches for the alphanumerics are Cherry MX Clears, while the + modifiers use Cherry MX Browns. </p> <h2>firmware</h2> <p>
D pages/sitemap.html

@@ -1,11 +0,0 @@

-{{ define "head" }} -<link rel="stylesheet" href="{{.StylePath}}"> -{{ end }} - -{{ define "body" }} -{{ template "header" . }} - -{{ end }} - -{{ define "scripts" }} -{{ end }}
M readme.mdreadme.md

@@ -15,7 +15,7 @@ `<ROOT>` should be a path to the site's source directory. The source directory must contain the following subdirectories and files:

- `pages/` - `templates/` - `assets/` -- `.site` +- `site.json` If `<ROOT>` is omitted, the current directory will be used as the source directory.

@@ -25,9 +25,6 @@

#### Flags - `--serve`, `-s`: Builds site, then serves built site on port 8000. For previewing site, not for use in a live environment. Live environment should serve the static files from the `/out` directory. -#### Creating a new page -Add a new name to `.site` at its proper place in the hierarchy and rerun `./build`. A new file will be created in the `/pages` source directory with the proper template tags. ### TODOs -- Sitemap/index of all pages - Typography styling pass
A site.json

@@ -0,0 +1,33 @@

+{ + "index": { + "title": "deserthorns" + }, + "creative": { + "parent": "index" + }, + "music": { + "parent": "creative" + }, + "visual": { + "parent": "creative" + }, + "photography": { + "parent": "visual" + }, + "projects": { + "parent": "index" + }, + "keyboard": { + "parent": "projects", + "image": "/assets/img/keyboard.jpg" + }, + "about": { + "parent": "index" + }, + "meta": { + "parent": "about" + }, + "style": { + "parent": "meta" + } +}
M templates/header.htmltemplates/header.html

@@ -5,7 +5,7 @@ width: 4rem;

margin: 1rem auto; display: block; } -.breadcrumbs { +.bread-crumbs { box-shadow: 4px 4px var(--b_low); border: 1px solid var(--b_low); padding: 0.5rem;

@@ -16,8 +16,14 @@ }

</style> <div> <img class="logo" src="/assets/svg/logo-light.svg"> - <nav class="breadcrumbs"> - <a href="/">home</a> / <a href="/about">about</a> / <a href="/meta">meta</a> / <span style="font-weight: bold;">style</span> + <nav class="bread-crumbs"> + {{ range .Breadcrumbs }} + {{ if .Active }} + <span style="font-weight: bold;">{{ .Name }}</span> + {{ else }} + <a href="{{ .Name }}">{{ .Name }}</a> / + {{ end }} + {{ end }} </nav> </div> {{ end }}