aboutsummaryrefslogtreecommitdiff
path: root/internal/config
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-07-23 15:00:17 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-07-23 15:00:17 +0200
commitaa6c9dad764089a3f0e287b5f90937e97dde3921 (patch)
tree213f7f56bf3c5ca1db82f0eee7c482886fa9ce43 /internal/config
parent66a17fda33e44e9022d6724f850323f754715259 (diff)
downloadlectio-aa6c9dad764089a3f0e287b5f90937e97dde3921.tar.gz
lectio-aa6c9dad764089a3f0e287b5f90937e97dde3921.zip
web: horizontal/vertical/interlinear display modes + web_display config
Adds a display-layout option to lectio-web alongside the existing colour themes: - config: WebDisplay field (toml web_display), default "horizontal", normalized on load via the new exported config.NormalizeDisplay (unknown -> "horizontal", same lenient style as the other web_* fields). - render: extracts the citation/ToEnglishRef resolution shared by GatherVersion into an unexported resolveRef helper (GatherVersion's signature/behavior unchanged) and adds GatherVerses(version, sec, lectionary) returning raw bible.Verse structs plus a versified flag, for column/interlinear alignment. - web/render: RenderReadings gains a display parameter. "horizontal" is the original stacked layout, byte-for-byte the same code path as before. "vertical" reuses the same per-version column data in a .display-vertical/.vcol grid (the CLI compare view, browser-side). "interlinear" maps versions through render.OfflineVersions' pl->wuj substitution (pl has no verse numbers), gathers GatherVerses per version, and interleaves them by chapter:verse into .ilverse/.illine blocks (ordered union of keys, first versified version's order first). - server: adds a display <select> to the top bar wired into the existing #controls HTMX form; a resolveQuery(cfg, r) helper replaces the duplicated date/lectionary/all/versions(+now display) resolution in indexHandler and readingsHandler. - fold-in from the B2 review: indexHandler now populates indexData.Lookup via a shared renderLookup(ref, versions) helper (also used by lookupHandler), so a bookmarked "/?ref=...&v=..." link shows its lookup result instead of an empty pane. - base.css: layout-only rules for the two new modes (no colours; themes stay colour-only). go test ./..., go vet ./..., gofmt clean; go build ./cmd/lectio-web ok.
Diffstat (limited to 'internal/config')
-rw-r--r--internal/config/config.go24
-rw-r--r--internal/config/config.toml1
-rw-r--r--internal/config/config_test.go40
3 files changed, 65 insertions, 0 deletions
diff --git a/internal/config/config.go b/internal/config/config.go
index 9c3c3cd..c15b5a0 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -11,6 +11,7 @@ import (
"fmt"
"os"
"path/filepath"
+ "strings"
"github.com/pelletier/go-toml/v2"
)
@@ -30,6 +31,26 @@ var validVersions = map[string]bool{
"drb": true,
}
+// validDisplays are the lectio-web reading-pane layouts.
+var validDisplays = map[string]bool{
+ "horizontal": true,
+ "vertical": true,
+ "interlinear": true,
+}
+
+// NormalizeDisplay lower-cases display and falls back to "horizontal" when
+// it is not one of validDisplays -- the same lenient style as the rest of
+// lectio-web's config fields (no error, just a safe default). Exported so
+// internal/web can apply the identical normalization to an explicit
+// ?display= query override, keeping the valid set in this one place.
+func NormalizeDisplay(display string) string {
+ d := strings.ToLower(display)
+ if !validDisplays[d] {
+ return "horizontal"
+ }
+ return d
+}
+
// Config holds lectio's user-configurable settings.
type Config struct {
SchemaVersion int `toml:"schema_version"`
@@ -42,6 +63,7 @@ type Config struct {
Offline bool `toml:"offline"`
WebTheme string `toml:"web_theme"`
WebPort int `toml:"web_port"`
+ WebDisplay string `toml:"web_display"`
Parts map[string]map[string]bool `toml:"parts"`
}
@@ -69,6 +91,7 @@ func Default() Config {
Offline: false,
WebTheme: "transfiguration",
WebPort: 0,
+ WebDisplay: "horizontal",
Parts: nil,
}
}
@@ -134,6 +157,7 @@ func Load() (Config, error) {
fmt.Fprintf(os.Stderr, "lectio: warning: invalid config at %s: %v; using defaults\n", path, err)
return def, nil
}
+ cfg.WebDisplay = NormalizeDisplay(cfg.WebDisplay)
if err := validate(cfg); err != nil {
return Config{}, err
diff --git a/internal/config/config.toml b/internal/config/config.toml
index 4ad3289..9c379e7 100644
--- a/internal/config/config.toml
+++ b/internal/config/config.toml
@@ -8,6 +8,7 @@ all = false # default to all parts (true) or just the gospel (fa
offline = false # true = never fetch; read only harvested sigla + cache
web_theme = "transfiguration" # built-in order/season theme or a user theme in ~/.config/lectio/themes/
web_port = 0 # lectio-web port; 0 = auto-pick a free port
+web_display = "horizontal" # lectio-web layout: "horizontal" (stacked), "vertical" (columns), "interlinear" (verse-by-verse)
# Which parts to show. Both tables are commented out -> every part is shown.
# Uncomment a table and set a part to false to hide it; parts you don't list
diff --git a/internal/config/config_test.go b/internal/config/config_test.go
index 9b72bc7..9ca311b 100644
--- a/internal/config/config_test.go
+++ b/internal/config/config_test.go
@@ -59,6 +59,46 @@ func TestWebLoadsFromSeed(t *testing.T) {
if cfg.WebPort != 0 {
t.Errorf("WebPort from seed wrong: got %d, want 0", cfg.WebPort)
}
+ if cfg.WebDisplay != "horizontal" {
+ t.Errorf("WebDisplay from seed wrong: got %q, want %q", cfg.WebDisplay, "horizontal")
+ }
+}
+
+func TestWebDisplayDefault(t *testing.T) {
+ def := Default()
+ if def.WebDisplay != "horizontal" {
+ t.Errorf("WebDisplay default wrong: got %q, want %q", def.WebDisplay, "horizontal")
+ }
+}
+
+func TestWebDisplayLoadsSetting(t *testing.T) {
+ dir := t.TempDir()
+ t.Setenv("XDG_CONFIG_HOME", dir)
+ os.MkdirAll(filepath.Join(dir, "lectio"), 0o755)
+ os.WriteFile(filepath.Join(dir, "lectio", "config.toml"),
+ []byte("web_display = \"vertical\"\n"), 0o644)
+ cfg, err := Load()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if cfg.WebDisplay != "vertical" {
+ t.Errorf("WebDisplay = %q, want %q", cfg.WebDisplay, "vertical")
+ }
+}
+
+func TestWebDisplayNormalizesUnknown(t *testing.T) {
+ dir := t.TempDir()
+ t.Setenv("XDG_CONFIG_HOME", dir)
+ os.MkdirAll(filepath.Join(dir, "lectio"), 0o755)
+ os.WriteFile(filepath.Join(dir, "lectio", "config.toml"),
+ []byte("web_display = \"bogus\"\n"), 0o644)
+ cfg, err := Load()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if cfg.WebDisplay != "horizontal" {
+ t.Errorf("WebDisplay = %q, want %q (normalized from bogus)", cfg.WebDisplay, "horizontal")
+ }
}
func TestPartShown(t *testing.T) {