Skip to content

feat(tui): interactive reader — palette + fetch + bordered frame#10

Merged
ivanmaierg merged 8 commits into
mainfrom
feat/tui-reader-screen
May 12, 2026
Merged

feat(tui): interactive reader — palette + fetch + bordered frame#10
ivanmaierg merged 8 commits into
mainfrom
feat/tui-reader-screen

Conversation

@ivanmaierg

Copy link
Copy Markdown
Owner

Summary

First interactive consumer of the hexagonal architecture's TUI seam.

  • Reader screen: palette overlay accepts a reference, async fetch via useEffect + cancelled-flag calls getPassage(repo, ref), chapter renders inside an OpenTUI-native bordered frame (<box border title=... bottomTitle=...>).
  • Reducer pattern: object-with-keys handler table per Rule 13; state union covers awaiting / loading / loaded / network-error.
  • Domain extension: parseReference now accepts chapter-only refs (john 3) in addition to verse refs.
  • Welcome retained: verbum no-args boots to the welcome screen; any non-q key transitions into the reader. Welcome's hint line was also updated to list the actual commands (any key to start • / palette • ] next ch • [ prev ch • q quit).
  • Repo wiring: tuiDriver(repo) signature change; createHelloAoBibleRepository() instantiated in src/index.tsx (mirrors src/cli/run.ts).

What does NOT change

  • Domain, application, API, CLI layers are otherwise untouched.
  • Hexagonal architecture (ADR 0002) retained.
  • TS-native dialect (ADR 0010) — plain (state, action) => State reducer, useEffect + cancelled-flag for async, no Effect descriptor pattern.

Verify

Original SDD verify: PASS WITH WARNINGS (0 critical / 1 warning / 1 suggestion) — 22 REQs and 14 SCNs covered. Three follow-on commits after manual PTY smoke caught a crash and addressed UX feedback:

  1. cd9945d Crash fix: <input> cannot nest inside <text> in OpenTUI. Saved as engram observation #276 for future reference.
  2. 9b77009 Restore welcome screen as brand splash; transition to reader on first key.
  3. 5c22012 Native bordered frame (replaces hand-drawn ASCII pillars); welcome hint shows real commands.

bun test: 127/127 pass. bun run tsc --noEmit: exits 0.

Test plan

  • bun test — 127/127 pass
  • PTY smoke confirmed by user: welcome shows, any key transitions to reader, palette accepts input, parse error surfaces inline for invalid input, border renders at full terminal width.
  • Pending PTY confirmations for reviewer: chapter nav ([ / ]), palette reopen (/), q/Q quit from either welcome or reader.

Out of scope (next PR: tui-reader-paging)

  • Multi-verse pagination within a chapter ([ / ] reassigned to page nav).
  • Verse cursor with / arrow keys ( marker on focused verse, matches ui-sketches.md line 122).
  • Chapter nav rebinding to n / p to free [ / ] for paging.
  • Palette key-conflict fix: gate reader-only keybinds behind state.kind !== "awaiting" so / doesn't clear the query while typing.

Full SDD trail in openspec/changes/archive/tui-reader-screen/.

Captures exploration, proposal, spec, design, tasks, and verify report
for the reader screen change. Verify verdict: PASS WITH WARNINGS
(0 critical / 1 warning / 1 suggestion). 127/127 tests green.
OpenTUI's <text> only accepts strings, TextNodeRenderable, or StyledText
children. <input> is its own Renderable, so nesting it inside <text>
crashed the reconciler on the awaiting-state initial render:

  TextNodeRenderable only accepts strings, TextNodeRenderable instances,
  or StyledText instances

Fix: render <input> as a sibling of the surrounding <text> borders
instead of a child. Also drop the ANSI-escape fg attribute on the
parse-error line (color attrs want hex, not escape strings) and rely
on the ⚠ glyph for the error signal.

127/127 tests still pass; manual smoke now needed to confirm rendering.
App owns a phase state — boots in 'welcome', any non-q keypress
transitions to 'reader'. Q/q quits from either phase. Keeps the brand
splash as the entry impression while making the reader the working
default. Welcome source files were already retained as Rule 13
canonical example; this re-mounts them in front of the reader.
…n welcome

Replaces the hand-drawn ASCII box (┌─...─┐, side │ pillars, ├──┤ divider)
with OpenTUI's native <box border> primitive. Reference goes in the top
title slot, keybinds in the bottom title slot, body content fills the
interior. The frame now renders as a proper rectangle at full terminal
width regardless of verse length — no more bobbing right border.

Also updates the welcome screen's hint line to list the actual reader
commands the user will land in (any key to start • / palette • ] next
ch • [ prev ch • q quit), replacing the aspirational "? help" that
pointed to a help screen we haven't built.

Sweeps the file-banner and code-paraphrase comments from welcome-screen.tsx
per Rule 14 as part of the touch.
SDD cycle closed. PASS WITH WARNINGS verify + 3 user-sanctioned
post-verify fixes (crash, welcome phase, native border). 127/127
tests pass. Manual PTY smoke confirmed by user.

Out-of-scope follow-ups (paging, verse cursor, keybind rebinding,
palette key-conflict gate) tracked for the next SDD change
tui-reader-paging.
@ivanmaierg ivanmaierg merged commit a7308f4 into main May 12, 2026
1 check passed
@ivanmaierg ivanmaierg deleted the feat/tui-reader-screen branch May 12, 2026 11:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant