fix(tui): simplify focus model — tab toggles capture ↔ list only

Tag rail removed from tab cycle to reduce focus confusion.
Rail is now ambient-by-default, focusable via h from list (spatial).

- Tab: capture ↔ list (no rail, no detail in cycle)
- h from list: focus tag rail (when visible)
- l from rail: back to list
- Split detail reachable via l/enter, not tab
- Remove nextFocusFromCapture helper
This commit is contained in:
2026-05-20 15:08:11 -04:00
parent b5b7f6b6ee
commit 60705463c1
3 changed files with 17 additions and 21 deletions
+3 -1
View File
@@ -8,9 +8,11 @@ func renderHelp(width, height int) string {
binds [][2]string binds [][2]string
}{ }{
{"Focus", [][2]string{ {"Focus", [][2]string{
{"tab", "cycle focus: capture → tags → list → detail"}, {"tab", "toggle capture ↔ list"},
{"esc", "back / clear filter / to capture"}, {"esc", "back / clear filter / to capture"},
{"a", "focus capture bar"}, {"a", "focus capture bar"},
{"h", "focus tag rail (from list)"},
{"l", "focus detail (split view)"},
{"ctrl+b", "toggle tag rail"}, {"ctrl+b", "toggle tag rail"},
}}, }},
{"Capture Bar", [][2]string{ {"Capture Bar", [][2]string{
+13 -19
View File
@@ -333,13 +333,6 @@ func (m model) updateKeys(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
return m.updateBrowse(msg) return m.updateBrowse(msg)
} }
func (m model) nextFocusFromCapture() focusPane {
if m.railVisible() {
return focusTagRail
}
return focusList
}
func (m model) updateCapture(msg tea.KeyMsg) (tea.Model, tea.Cmd) { func (m model) updateCapture(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
switch msg.String() { switch msg.String() {
case "enter": case "enter":
@@ -364,12 +357,9 @@ func (m model) updateCapture(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
return m, createEntity(m.store, result.entity) return m, createEntity(m.store, result.entity)
} }
return m, nil return m, nil
case "esc": case "esc", "tab":
cmd := m.setFocus(focusList) cmd := m.setFocus(focusList)
return m, cmd return m, cmd
case "tab":
cmd := m.setFocus(m.nextFocusFromCapture())
return m, cmd
} }
m.input = m.input.updateKey(msg) m.input = m.input.updateKey(msg)
return m, nil return m, nil
@@ -396,10 +386,7 @@ func (m model) updateBrowse(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
return m, loadEntities(m.store, m.listParams()) return m, loadEntities(m.store, m.listParams())
} }
return m, nil return m, nil
case "tab": case "l", "tab", "esc":
m.focus = focusList
return m, nil
case "esc":
m.focus = focusList m.focus = focusList
return m, nil return m, nil
case "ctrl+b": case "ctrl+b":
@@ -423,10 +410,6 @@ func (m model) updateBrowse(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
if m.splitDetail && m.state == stateList { if m.splitDetail && m.state == stateList {
switch msg.String() { switch msg.String() {
case "tab": case "tab":
if m.focus == focusList {
m.focus = focusDetail
return m, nil
}
cmd := m.setFocus(focusCapture) cmd := m.setFocus(focusCapture)
return m, cmd return m, cmd
case "l": case "l":
@@ -439,6 +422,10 @@ func (m model) updateBrowse(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
m.focus = focusList m.focus = focusList
return m, nil return m, nil
} }
if m.focus == focusList && m.railVisible() {
m.focus = focusTagRail
return m, nil
}
case "esc": case "esc":
if m.focus == focusDetail { if m.focus == focusDetail {
m.focus = focusList m.focus = focusList
@@ -559,6 +546,13 @@ func (m model) updateBrowse(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
cmd := m.setFocus(focusCapture) cmd := m.setFocus(focusCapture)
return m, cmd return m, cmd
case "h":
if m.state == stateList && m.railVisible() && m.focus == focusList {
m.focus = focusTagRail
return m, nil
}
return m, nil
case "a": case "a":
if m.state == stateList { if m.state == stateList {
cmd := m.setFocus(focusCapture) cmd := m.setFocus(focusCapture)
+1 -1
View File
@@ -88,7 +88,7 @@ func contextHints(m model) []hint {
case focusCapture: case focusCapture:
return []hint{{"enter", "submit"}, {"esc", "browse"}, {"?…", "search"}, {"-", "todo"}, {"@", "event"}} return []hint{{"enter", "submit"}, {"esc", "browse"}, {"?…", "search"}, {"-", "todo"}, {"@", "event"}}
case focusTagRail: case focusTagRail:
return []hint{{"j/k", "nav"}, {"enter", "filter"}, {"ctrl+b", "hide"}, {"tab", "list"}, {"esc", "list"}} return []hint{{"j/k", "nav"}, {"enter", "filter"}, {"l", "list"}, {"ctrl+b", "hide"}}
case focusDetail: case focusDetail:
if m.splitDetail { if m.splitDetail {
return []hint{{"h", "list"}, {"c", "copy"}, {"e", "edit"}, {"p", "promote"}, {"!", "pin"}, {"tab", "capture"}} return []hint{{"h", "list"}, {"c", "copy"}, {"e", "edit"}, {"p", "promote"}, {"!", "pin"}, {"tab", "capture"}}