Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3.6 KiB
New Session Dialog UX Refinements — Design
Goal: Three focused UX improvements to the New Session modal: hide sandbox sub-options until sandboxing is enabled, unify the focus highlight to the dialog's Peach accent, and add context-aware j/k field navigation.
Scope: src/hqt/tui/screens/new_session.py and src/hqt/tui/styles.tcss.
No service, DB, or sandbox-policy changes.
1. Hide sandbox sub-options until the toggle is on
The "Filesystem access" and "Network" rows are sub-options of the sandbox switch and should only appear when sandboxing is enabled — mirroring the existing worktree-checkbox → branch-input reveal pattern already in this screen.
- Wrap the two label/widget pairs (
Filesystem access:+#fs-select,Network:+#net-switch) in aVertical(id="sandbox-options")container so they toggle as a single unit. - Set
display = Falseon the container at compose time. - Add
on_switch_changed(self, event: Switch.Changed): whenevent.switch.id == "sandbox-switch", set#sandbox-optionsdisplaytoevent.value. - The sandbox switch starts off — and is
disabledwhen bwrap is absent — so the sub-options start hidden in every case. No separate handling for the unavailable case is needed. _submit()still reads#fs-select/#net-switchunconditionally. Their values are valid defaults (rw/ net on) even while hidden, and the policy is only built when the sandbox switch is on, so hidden values are never used.
2. Unify the focus highlight to Peach ($accent)
Buttons already get a Peach focus highlight from styles.tcss, but
Switch / Checkbox / Select / Input fall back to Textual's default
Lavender ($border) focus border. That inconsistency is the "off-palette"
highlight. Add scoped rules so every focusable control in the dialog shares the
Peach accent:
#new-session-dialog Switch:focus,
#new-session-dialog Checkbox:focus,
#new-session-dialog Select:focus,
#new-session-dialog Input:focus {
border: tall $accent;
}
Switch / Checkbox / Input use a tall border by default, so matching
tall keeps layout height identical — only the color changes.
3. Soft context-aware j/k navigation
Add screen-level bindings that walk the dialog's focus chain:
BINDINGS = [
Binding("j", "focus_next", "Next field", show=False),
Binding("k", "focus_previous", "Prev field", show=False),
]
Input consumes printable keys before screen bindings fire, so j/k type
literally while editing a text field and only move focus when the focused widget
is a toggle / select / button — the "soft" (context-aware) model the user chose.
focus_next / focus_previous are built-in Textual screen actions. Tab /
Shift+Tab / arrows keep working unchanged.
Testing
All three are testable against the screen in isolation via Textual's
run_test() pilot:
- Sub-options reveal: mount with
sandbox_available=True; assert#sandbox-options.displayisFalseinitially, flip the sandbox switch, assert it becomesTrue, flip back, assertFalse. - j/k navigation: assert the
j/kbindings map tofocus_next/focus_previous; drive the pilot to confirm focus moves between toggles and that j/k typed into a focusedInputland as literal text rather than moving focus. - Focus highlight: the color is visual, but the presence of the scoped
:focusrule is assertable by reading the compiled CSS /styles.tcss.
Out of scope
- No modal (normal/insert) vim mode — the soft model was chosen deliberately.
- No change to Enter-to-submit behavior.
- No restyling of controls outside the New Session dialog.