diff options
| author | Claude <noreply@anthropic.com> | 2026-03-31 12:11:18 +0200 |
|---|---|---|
| committer | Claude <noreply@anthropic.com> | 2026-03-31 12:11:18 +0200 |
| commit | 3cb7c82cf7c4e050148f69be23590a7fbe587a27 (patch) | |
| tree | d2b6506db2de72b3a6982cfbe69925b88936de90 /internal/builder/frontmatter.go | |
| parent | 33f214f6cd9729473bb55fd7b3b923d5d960bb98 (diff) | |
| download | nebbet.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.go | 64 |
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 +} |
