summaryrefslogtreecommitdiffstats
path: root/internal/builder/frontmatter.go
diff options
context:
space:
mode:
authorClaude <noreply@anthropic.com>2026-03-31 12:11:18 +0200
committerClaude <noreply@anthropic.com>2026-03-31 12:11:18 +0200
commit3cb7c82cf7c4e050148f69be23590a7fbe587a27 (patch)
treed2b6506db2de72b3a6982cfbe69925b88936de90 /internal/builder/frontmatter.go
parent33f214f6cd9729473bb55fd7b3b923d5d960bb98 (diff)
downloadnebbet.no-3cb7c82cf7c4e050148f69be23590a7fbe587a27.tar.xz
nebbet.no-3cb7c82cf7c4e050148f69be23590a7fbe587a27.zip
Add static site builder: SQLite-backed MD→HTML pipeline
- cmd/nebbet: CLI with build [--watch] and user add/passwd/delete/list - internal/builder: markdown→HTML, component injection via HTML comments, auto importmap from lib/, fsnotify watch with 150ms debounce - internal/db: meta.db (page index, tag queries) + search.db (FTS5) - internal/sqlitedrv: minimal CGO database/sql driver for system libsqlite3 - internal/auth: htpasswd-compatible bcrypt password file management - templates/base.html + admin.html, styles/main.css + admin.css - nginx.conf with auth_basic for /admin, clean URLs, gzip - nebbet.service systemd unit for watch daemon - Example content/index.md and components/site-greeting.js https://claude.ai/code/session_01HTc1BCBCiMTEB54XQP1Wz9
Diffstat (limited to 'internal/builder/frontmatter.go')
-rw-r--r--internal/builder/frontmatter.go64
1 files changed, 64 insertions, 0 deletions
diff --git a/internal/builder/frontmatter.go b/internal/builder/frontmatter.go
new file mode 100644
index 0000000..34de484
--- /dev/null
+++ b/internal/builder/frontmatter.go
@@ -0,0 +1,64 @@
+package builder
+
+import (
+ "strings"
+)
+
+// Frontmatter holds parsed page metadata from YAML-style front matter.
+type Frontmatter struct {
+ Title string
+ Date string
+ Tags []string
+ Layout string // template name without extension, default "base"
+ Draft bool
+}
+
+// ParseFrontmatter splits the optional ---...--- block from the markdown body.
+// Supports: title, date, tags (comma-list or [a, b]), layout, draft.
+func ParseFrontmatter(content string) (Frontmatter, string) {
+ fm := Frontmatter{Layout: "base"}
+ if !strings.HasPrefix(content, "---") {
+ return fm, content
+ }
+ // Find closing ---
+ rest := content[3:]
+ end := strings.Index(rest, "\n---")
+ if end == -1 {
+ return fm, content
+ }
+ block := strings.TrimSpace(rest[:end])
+ body := strings.TrimSpace(rest[end+4:]) // skip \n---
+
+ for _, line := range strings.Split(block, "\n") {
+ k, v, ok := strings.Cut(strings.TrimSpace(line), ":")
+ if !ok {
+ continue
+ }
+ k = strings.TrimSpace(k)
+ v = strings.TrimSpace(v)
+ switch k {
+ case "title":
+ fm.Title = strings.Trim(v, `"'`)
+ case "date":
+ fm.Date = v
+ case "layout":
+ fm.Layout = strings.Trim(v, `"'`)
+ case "draft":
+ fm.Draft = v == "true"
+ case "tags":
+ fm.Tags = parseTags(v)
+ }
+ }
+ return fm, body
+}
+
+func parseTags(v string) []string {
+ v = strings.Trim(v, "[] ")
+ var tags []string
+ for _, p := range strings.Split(v, ",") {
+ if t := strings.Trim(strings.TrimSpace(p), `"'`); t != "" {
+ tags = append(tags, t)
+ }
+ }
+ return tags
+}