feat(11.1-02): add the documentation theme, chroma highlighting and docs:serve

- WinterCMS-style shell: header with search and theme toggle, grouped
  sidebar, on-page TOC, pager, page actions, callouts, heading
  permalinks, footer and a 404 page
- fenced code highlighted at build time by chroma/v2 into tok-* classes,
  with a copy button; no inline script, style or handler
- vendored DM Sans/DM Mono fonts and Lucide icons with their licences
- client-side search over search-index.json built with textContent only
- summer docs:serve builds into a temp dir, serves on loopback by default,
  returns 404.html with status 404 and rebuilds on change
This commit is contained in:
Jakub Zych
2026-09-30 21:57:55 +02:00
parent d89e18bc8e
commit dd11bdb0c7
39 changed files with 3114 additions and 145 deletions

View File

@@ -3,6 +3,10 @@ package main
import (
"context"
"errors"
"os"
"os/signal"
"sync"
"syscall"
"git.golem15.com/golem15/summercms/internal/docsite"
"git.golem15.com/golem15/summercms/modules/backpack"
@@ -79,6 +83,43 @@ func docsSyncCommand() bonfire.Command {
}
}
func docsServeCommand() bonfire.Command {
return bonfire.Command{
Name: "docs:serve",
Description: "Build the documentation site and preview it on a local address",
Flags: []bonfire.Flag{
{Name: "root", Description: "Repository root; src= paths and modules/ resolve against it", Default: "."},
{Name: "src", Description: "Docs source directory (default <root>/docs)"},
{Name: "base-url", Description: "Base URL for site links (overrides site.yaml base_url)"},
{Name: "addr", Description: "Listen address; must be loopback unless --allow-remote", Default: docsite.DefaultServeAddr},
{Name: "allow-remote", Description: "Allow a non-loopback --addr (serves the docs on the network)", Bare: true},
},
Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error {
addr, _ := in.Flag("addr")
if addr == "" {
addr = docsite.DefaultServeAddr
}
ctx, stop := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM)
defer stop()
return docsite.Serve(ctx, docsOptions(in), addr, flagTrue(in, "allow-remote"), outputWriter{mu: &sync.Mutex{}, out: out})
},
}
}
// outputWriter adapts bonfire.Output to io.Writer for docsite.Serve, which
// writes from its watch goroutine too.
type outputWriter struct {
mu *sync.Mutex
out bonfire.Output
}
func (w outputWriter) Write(p []byte) (int, error) {
w.mu.Lock()
defer w.mu.Unlock()
w.out.Printf("%s", p)
return len(p), nil
}
func docsOptions(in bonfire.Input) docsite.Options {
opts := docsite.Options{Commands: docsCommands()}
opts.Root, _ = in.Flag("root")