From 2453b598def94649cc7ce9af7155bfaad40cce12 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Fri, 24 Jul 2026 15:01:03 +0200 Subject: web: /settings page to edit config + books.toml, persisted and applied live; v0.14.0 --- internal/web/server.go | 193 +++++++++++++++++++++++++++++++++-- internal/web/server_test.go | 68 ++++++++++++ internal/web/static/base.css | 7 ++ internal/web/templates/index.html | 1 + internal/web/templates/reader.html | 1 + internal/web/templates/settings.html | 115 +++++++++++++++++++++ 6 files changed, 379 insertions(+), 6 deletions(-) create mode 100644 internal/web/templates/settings.html (limited to 'internal/web') diff --git a/internal/web/server.go b/internal/web/server.go index 7c90e9e..34371b7 100644 --- a/internal/web/server.go +++ b/internal/web/server.go @@ -12,11 +12,13 @@ import ( "io/fs" "net" "net/http" + "os" "os/exec" "regexp" "runtime" "strconv" "strings" + "sync" "time" "github.com/lukaszkasprzak/lectio/internal/bible" @@ -32,18 +34,40 @@ import ( // every visitor sees the same five choices regardless of their config file. var bibleVersions = []string{"bt", "wuj", "vul", "grb", "drb"} +// server holds the live, mutable config + book table so /settings can apply +// changes to the running process. All handlers read a snapshot via get()/table(). +type server struct { + mu sync.RWMutex + cfg config.Config + tbl *bible.BookTable +} + +func (s *server) get() config.Config { s.mu.RLock(); defer s.mu.RUnlock(); return s.cfg } +func (s *server) table() *bible.BookTable { s.mu.RLock(); defer s.mu.RUnlock(); return s.tbl } +func (s *server) apply(cfg config.Config, tbl *bible.BookTable) { + s.mu.Lock() + defer s.mu.Unlock() + s.cfg = cfg + if tbl != nil { + s.tbl = tbl + } +} + // NewServer builds lectio-web's route tree. cfg supplies the defaults // (lectionary, versions, theme, offline) that requests can override via -// query parameters; it is never mutated. +// query parameters; it is never mutated -- /settings applies changes to a +// live, mutable copy held by server, which every handler reads per request. func NewServer(cfg config.Config) http.Handler { tbl, _ := bible.LoadBookTable(config.UserBooksTOML()) + s := &server{cfg: cfg, tbl: tbl} mux := http.NewServeMux() - - mux.HandleFunc("GET /{$}", indexHandler(cfg)) - mux.HandleFunc("GET /readings", readingsHandler(cfg)) - mux.HandleFunc("GET /reader", readerHandler(cfg, tbl)) - mux.HandleFunc("GET /theme.css", themeCSSHandler(cfg)) + mux.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) { indexHandler(s.get())(w, r) }) + mux.HandleFunc("GET /readings", func(w http.ResponseWriter, r *http.Request) { readingsHandler(s.get())(w, r) }) + mux.HandleFunc("GET /reader", func(w http.ResponseWriter, r *http.Request) { readerHandler(s.get(), s.table())(w, r) }) + mux.HandleFunc("GET /theme.css", func(w http.ResponseWriter, r *http.Request) { themeCSSHandler(s.get())(w, r) }) + mux.HandleFunc("GET /settings", settingsGet(s)) + mux.HandleFunc("POST /settings", settingsPost(s)) staticSub, err := fs.Sub(staticFS, "static") if err != nil { @@ -508,6 +532,163 @@ func themeCSSHandler(cfg config.Config) http.HandlerFunc { } } +// settingsData drives templates/settings.html. +type settingsData struct { + Cfg config.Config + Books string // current books.toml text (user override, else the embedded default) + ThemeOpts []themeOpt // for the web_theme diff --git a/internal/web/templates/settings.html b/internal/web/templates/settings.html new file mode 100644 index 0000000..bea6fb9 --- /dev/null +++ b/internal/web/templates/settings.html @@ -0,0 +1,115 @@ +{{/* settings.html — lectio-web /settings page: a form for every config + setting plus a raw books.toml editor. A plain POST form (no htmx) -- + saving redirects (PRG) back here with ?saved=1. On a validation error + the form re-renders with the submitted values and an inline message + instead of redirecting. Self-contained and theme-aware, like index.html. */}} + + + + + +lectio — settings + + + + + +
+ +

← {{.L.BannerReadings}}

+ + {{if .Saved}}

Saved.

{{end}} + {{if .Error}}

{{.Error}}

{{end}} + +
+ + + + + + + + + + + + + + + +
+ versions + {{range .VersionOpts}}{{end}} +
+ +
+ web versions + {{range .WebVersionOpts}}{{end}} +
+ +
+ + + +
+ + + + + + + + + +
+ +
+ +
+ +
+ + -- cgit v1.3