From d9faa8cf672369802f39c754afb282a0ee60b88c Mon Sep 17 00:00:00 2001 From: UnbreakableMJ Date: Tue, 16 Jun 2026 17:04:34 +0300 Subject: [PATCH] feat(vault-tui): scroll the detail pane to keep the field cursor visible The granular identity detail is ~18 fields and could overflow the detail pane (a single non-scrolling Paragraph), pushing the lower fields and the per-field cursor off-screen. render_detail now applies a scroll offset keyed to the cursor field (`2 + detail_field`, the body's header being Name+Type), reusing the form's pure `scroll_offset`. Only the detail-focused view scrolls; browsing/other panes are unchanged (offset 0). - docs: CHANGELOG. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 5 +++++ crates/vault-tui/src/ui.rs | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c0239f..6c49054 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,11 @@ range may break in any release. ### Added +- **Scrolling detail pane.** The detail pane now scrolls to keep the focused + field visible — the granular identity view is ~18 fields and could overflow a + shorter terminal. Reuses the form's `scroll_offset`; only the detail-focused + view scrolls (browsing is unchanged). + - **Granular identity field selectors.** 16 new `--field` selectors expose every identity field individually — `identity-{title,first-name,middle-name, last-name,username,company,ssn,passport,license,address1,address2,address3, diff --git a/crates/vault-tui/src/ui.rs b/crates/vault-tui/src/ui.rs index 621b260..b438ce9 100644 --- a/crates/vault-tui/src/ui.rs +++ b/crates/vault-tui/src/ui.rs @@ -316,8 +316,19 @@ fn render_detail(frame: &mut Frame, app: &App, area: Rect) { lines }, ); + // Scroll to keep the focused field visible (the identity detail can be + // taller than the pane). The body is [Name, Type, , Folder, Id, + // "", hint], so the cursor field's line is `2 + detail_field`. Only the + // detail-focused path scrolls; every other state keeps offset 0. + let focused_line = if app.detail_focused() { + 2 + app.detail_field + } else { + 0 + }; + let offset = scroll_offset(focused_line, (area.height.saturating_sub(2)) as usize); let para = Paragraph::new(lines) .block(pane_block("Detail", app.detail_focused())) + .scroll((u16::try_from(offset).unwrap_or(u16::MAX), 0)) .wrap(Wrap { trim: true }); frame.render_widget(para, area); }