summaryrefslogtreecommitdiff
path: root/internal/tui
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-07-24 13:07:37 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-07-24 13:07:37 +0200
commita675a983424f1f8d103fc12d55ef4f7129a92d62 (patch)
treeb9483bf09f03cb9047a548289556c73a9343bbb0 /internal/tui
parent55a5c793d04b55892fcddfc753d8526bd5748f03 (diff)
downloadlectio-a675a983424f1f8d103fc12d55ef4f7129a92d62.tar.gz
lectio-a675a983424f1f8d103fc12d55ef4f7129a92d62.zip
qol: tui jump-to-date (d) + lectio --citation/--week + hide bt for traditional web; v0.10.0
Diffstat (limited to 'internal/tui')
-rw-r--r--internal/tui/tui.go55
-rw-r--r--internal/tui/tui_test.go40
2 files changed, 94 insertions, 1 deletions
diff --git a/internal/tui/tui.go b/internal/tui/tui.go
index c58db6d..5f7fb52 100644
--- a/internal/tui/tui.go
+++ b/internal/tui/tui.go
@@ -32,6 +32,9 @@ type Model struct {
height int
loading bool
err error
+
+ jumping bool // date-entry ("d") mode is active
+ jumpBuf string // the date being typed in jump mode
}
// readingsMsg carries a successful fetch's sections and DayInfo back to
@@ -179,6 +182,9 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, nil
case tea.KeyMsg:
+ if m.jumping {
+ return m.updateJump(msg)
+ }
switch msg.String() {
case "q", "ctrl+c":
return m, tea.Quit
@@ -200,6 +206,10 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.loading = true
m.err = nil
return m, m.fetchCmd(true)
+ case "d":
+ m.jumping = true
+ m.jumpBuf = ""
+ return m, nil
case "j", "down":
m.scroll = m.scrollTo(m.scroll + 1)
return m, nil
@@ -223,6 +233,45 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, nil
}
+// updateJump handles keys while the "d" date-jump prompt is active: digits and
+// "-" build the buffer, Enter parses YYYY-MM-DD and navigates (invalid input
+// just cancels), Esc cancels, Backspace edits, Ctrl+C quits. Any other key is
+// ignored so the prompt stays modal.
+func (m Model) updateJump(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
+ switch msg.Type {
+ case tea.KeyCtrlC:
+ return m, tea.Quit
+ case tea.KeyEsc:
+ m.jumping = false
+ m.jumpBuf = ""
+ return m, nil
+ case tea.KeyEnter:
+ buf := m.jumpBuf
+ m.jumping = false
+ m.jumpBuf = ""
+ if t, err := time.Parse("2006-01-02", buf); err == nil {
+ m.date = t.Format("2006-01-02")
+ m.loading = true
+ m.err = nil
+ return m, m.fetchCmd(false)
+ }
+ return m, nil
+ case tea.KeyBackspace:
+ if r := []rune(m.jumpBuf); len(r) > 0 {
+ m.jumpBuf = string(r[:len(r)-1])
+ }
+ return m, nil
+ case tea.KeyRunes:
+ for _, c := range msg.Runes {
+ if (c >= '0' && c <= '9') || c == '-' {
+ m.jumpBuf += string(c)
+ }
+ }
+ return m, nil
+ }
+ return m, nil
+}
+
// headerLines is how many lines the top header block renders as: 1 (just
// the "lectio DATE [version]" bar) or 2 when a day-info line (the
// celebration name, optionally with its temporal Season) is shown beneath
@@ -295,7 +344,11 @@ func (m Model) View() string {
if line := m.dayInfoLine(); line != "" {
header += "\n" + line
}
- footer := footerStyle.Width(w).Render(i18n.Get(m.cfg.UILanguage).FooterKeys)
+ footerText := i18n.Get(m.cfg.UILanguage).FooterKeys
+ if m.jumping {
+ footerText = i18n.Get(m.cfg.UILanguage).JumpPrompt + ": " + m.jumpBuf
+ }
+ footer := footerStyle.Width(w).Render(footerText)
bodyLines := m.bodyLines(innerW)
diff --git a/internal/tui/tui_test.go b/internal/tui/tui_test.go
index 330259d..f99c4ac 100644
--- a/internal/tui/tui_test.go
+++ b/internal/tui/tui_test.go
@@ -5,6 +5,8 @@ import (
"strings"
"testing"
+ tea "github.com/charmbracelet/bubbletea"
+
"github.com/lukaszkasprzak/lectio/internal/config"
"github.com/lukaszkasprzak/lectio/internal/liturgy"
)
@@ -161,3 +163,41 @@ func TestFooterKeysLocalised(t *testing.T) {
t.Errorf("pl View() footer missing %q: %q", "q wyjście", out)
}
}
+
+func TestJumpToDate(t *testing.T) {
+ send := func(m Model, s string) Model {
+ for _, r := range s {
+ nm, _ := m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{r}})
+ m = nm.(Model)
+ }
+ return m
+ }
+
+ m := New(config.Default(), "2026-07-22", "wuj")
+ m = send(m, "d")
+ if !m.jumping {
+ t.Fatal("'d' did not enter jump mode")
+ }
+ m = send(m, "2026-01-02")
+ if m.jumpBuf != "2026-01-02" {
+ t.Fatalf("jumpBuf = %q", m.jumpBuf)
+ }
+ nm, _ := m.Update(tea.KeyMsg{Type: tea.KeyEnter})
+ m = nm.(Model)
+ if m.jumping {
+ t.Error("still in jump mode after Enter")
+ }
+ if m.date != "2026-01-02" {
+ t.Errorf("date = %q, want 2026-01-02", m.date)
+ }
+
+ // Esc cancels without changing the date.
+ m2 := New(config.Default(), "2026-07-22", "wuj")
+ m2 = send(m2, "d")
+ m2 = send(m2, "2099")
+ nm2, _ := m2.Update(tea.KeyMsg{Type: tea.KeyEsc})
+ m2 = nm2.(Model)
+ if m2.jumping || m2.jumpBuf != "" || m2.date != "2026-07-22" {
+ t.Errorf("esc did not cancel cleanly: jumping=%v buf=%q date=%q", m2.jumping, m2.jumpBuf, m2.date)
+ }
+}