docs: spec for New Session dialog UX refinements
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,90 @@
|
|||||||
|
# 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 a `Vertical(id="sandbox-options")` container so
|
||||||
|
they toggle as a single unit.
|
||||||
|
- Set `display = False` on the container at compose time.
|
||||||
|
- Add `on_switch_changed(self, event: Switch.Changed)`: when
|
||||||
|
`event.switch.id == "sandbox-switch"`, set `#sandbox-options` `display` to
|
||||||
|
`event.value`.
|
||||||
|
- The sandbox switch starts off — and is `disabled` when 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-switch` unconditionally. 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:
|
||||||
|
|
||||||
|
```css
|
||||||
|
#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:
|
||||||
|
|
||||||
|
```python
|
||||||
|
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` `.display` is `False` initially, flip the sandbox switch,
|
||||||
|
assert it becomes `True`, flip back, assert `False`.
|
||||||
|
- **j/k navigation:** assert the `j` / `k` bindings map to
|
||||||
|
`focus_next` / `focus_previous`; drive the pilot to confirm focus moves
|
||||||
|
between toggles and that j/k typed into a focused `Input` land as literal text
|
||||||
|
rather than moving focus.
|
||||||
|
- **Focus highlight:** the color is visual, but the presence of the scoped
|
||||||
|
`:focus` rule 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.
|
||||||
Reference in New Issue
Block a user