Files
nib-v1/internal/tui/statusbar.go
T
lerko f89ca8acb9 feat(tui): add split-pane detail, compact date headers, and input drawer
Three layout improvements for better space utilization:

- Compact date headers: date labels render as left gutter column instead
  of standalone lines, saving one line per date group in stream view
- Input drawer: capture bar expands to 4-line drawer with border, hints,
  and live preview of parsed entity/search query
- Split-pane detail: wide terminals (>=100 cols) show list and detail
  side-by-side with h/l focus switching, falling back to full-screen
  detail on narrow terminals
2026-05-19 19:55:37 -04:00

72 lines
1.7 KiB
Go

package tui
import (
"fmt"
"github.com/charmbracelet/lipgloss"
)
func renderStatusBar(m model, width int) string {
left := countText(m)
right := contextHints(m)
leftRendered := statusStyle.Render(left)
rightRendered := helpStyle.Render(right)
gap := width - lipgloss.Width(leftRendered) - lipgloss.Width(rightRendered)
if gap < 0 {
gap = 0
}
pad := lipgloss.NewStyle().Width(gap).Render("")
return leftRendered + pad + rightRendered
}
func countText(m model) string {
var total int
if m.mode == modeCards {
total = len(m.cards.filtered)
} else {
total = len(m.list.displayEntities())
}
if m.filterTag != "" {
return fmt.Sprintf("%d entities #%s", total, m.filterTag)
}
return fmt.Sprintf("%d entities", total)
}
func contextHints(m model) string {
switch m.state {
case stateDetail:
switch m.detail.mode {
case detailRun:
return "space:toggle j/k:nav r:reset esc:save+exit"
case detailFill:
return "tab:next shift+tab:prev enter:copy esc:cancel"
default:
return "p:promote D:demote c:copy e:edit r:run f:fill !:pin esc:back"
}
case stateInput:
return ""
case stateTagFilter:
return "j/k:nav enter:select esc:cancel"
case stateConfirm:
return "y:confirm n:cancel"
case statePromote:
return "j/k:nav enter:select esc:cancel"
case stateAbsorb:
return "j/k:nav enter:absorb esc:cancel"
default:
if m.splitDetail {
if m.focus == focusDetail {
return "h:list c:copy e:edit p:promote D:demote !:pin esc:back"
}
return "l:detail a:add d:del #:filter esc:close ?:help q:quit"
}
if m.mode == modeCards {
return "1:stream 2:cards s:sort tab:intent a:add ?:help q:quit"
}
return "1:stream 2:cards a:add/?search m:absorb d:del #:filter ?:help q:quit"
}
}