@brimveyn/aimux 1.9.5 → 1.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/package.json +2 -2
  2. package/src/app.tsx +4 -5
  3. package/src/pty/terminal-snapshot.ts +7 -7
  4. package/src/ui/components/git/diff-renderer/fold-strip.tsx +7 -7
  5. package/src/ui/components/git/diff-renderer/pierre-diff.tsx +3 -3
  6. package/src/ui/components/git/diff-renderer/split-view.tsx +18 -17
  7. package/src/ui/components/git/diff-renderer/stacked-view.tsx +13 -13
  8. package/src/ui/components/git/git-panel.tsx +42 -39
  9. package/src/ui/components/git/git-view.tsx +20 -20
  10. package/src/ui/components/layout/session-bar.tsx +13 -13
  11. package/src/ui/components/layout/sidebar/sidebar.tsx +26 -28
  12. package/src/ui/components/layout/sidebar/tab-item.tsx +21 -21
  13. package/src/ui/components/layout/split-layout.tsx +2 -2
  14. package/src/ui/components/layout/status-bar.tsx +12 -12
  15. package/src/ui/components/layout/terminal-pane.tsx +19 -31
  16. package/src/ui/components/modals/app/ai-usage-modal.tsx +21 -21
  17. package/src/ui/components/modals/app/help-modal.tsx +5 -6
  18. package/src/ui/components/modals/app/update-available-modal.tsx +3 -3
  19. package/src/ui/components/modals/git/git-commit-modal.tsx +17 -17
  20. package/src/ui/components/modals/sessions/create-session-modal.tsx +8 -8
  21. package/src/ui/components/modals/sessions/session-picker-modal.tsx +6 -6
  22. package/src/ui/components/modals/shared/form.tsx +4 -4
  23. package/src/ui/components/modals/shared/modal-keybinds-overlay.tsx +4 -4
  24. package/src/ui/components/modals/shared/modal-shell.tsx +6 -6
  25. package/src/ui/components/modals/shared/picker.tsx +6 -6
  26. package/src/ui/components/modals/snippets/snippet-picker-modal.tsx +5 -5
  27. package/src/ui/components/modals/tabs/new-tab-modal.tsx +6 -6
  28. package/src/ui/components/modals/themes/theme-picker-modal.tsx +17 -20
  29. package/src/ui/components/overlays/ai-usage/ai-usage-indicator.tsx +12 -12
  30. package/src/ui/components/overlays/context-menu/context-menu-overlay.tsx +6 -6
  31. package/src/ui/components/overlays/pending-chord-overlay.tsx +5 -5
  32. package/src/ui/components/primitives/bare-input.tsx +5 -5
  33. package/src/ui/components/primitives/input-field.tsx +5 -5
  34. package/src/ui/components/primitives/list-item.tsx +27 -22
  35. package/src/ui/components/primitives/surface.tsx +12 -9
  36. package/src/ui/filter-themes.ts +9 -8
  37. package/src/ui/root.tsx +5 -4
  38. package/src/ui/shiki.ts +8 -11
  39. package/src/ui/theme-store.ts +48 -118
  40. package/src/ui/theme.ts +8 -8
  41. package/src/ui/themes.ts +9 -20
@@ -8,7 +8,7 @@ import type {
8
8
  } from '../../../../services/ai-usage/types'
9
9
 
10
10
  import { useAIUsageStore } from '../../../../state/ai-usage-store'
11
- import { useTokens } from '../../../theme'
11
+ import { useTheme } from '../../../theme'
12
12
  import { uiTokens } from '../../../ui-tokens'
13
13
  import { ModalShell } from '../shared/modal-shell'
14
14
 
@@ -56,7 +56,7 @@ function paceStageIsBehind(stage: UsagePaceStage): boolean {
56
56
  }
57
57
 
58
58
  export function AIUsageModal() {
59
- const t = useTokens()
59
+ const t = useTheme()
60
60
  const snapshots = useAIUsageStore((s) => s.snapshots)
61
61
 
62
62
  const tools: AIUsageTool[] = ['claude', 'codex']
@@ -72,7 +72,7 @@ export function AIUsageModal() {
72
72
  listGap={1}
73
73
  >
74
74
  {sections.length === 0 ? (
75
- <text fg={t.muted} selectable={false}>
75
+ <text fg={t.textMuted} selectable={false}>
76
76
  no data yet — collecting…
77
77
  </text>
78
78
  ) : (
@@ -92,20 +92,20 @@ interface ToolSectionProps {
92
92
  }
93
93
 
94
94
  function ToolSection({ snap, tool }: ToolSectionProps) {
95
- const t = useTokens()
95
+ const t = useTheme()
96
96
  const isHardError = Boolean(snap.error) && !snap.stale
97
97
  const relative = formatRelative(snap.lastUpdated)
98
98
 
99
99
  let body: ReactNode
100
100
  if (isHardError) {
101
101
  body = (
102
- <text fg={t.palette.error} selectable={false}>
102
+ <text fg={t.error} selectable={false}>
103
103
  {`error: ${snap.error ?? ''}`}
104
104
  </text>
105
105
  )
106
106
  } else if (snap.windows.length === 0) {
107
107
  body = (
108
- <text fg={t.muted} selectable={false}>
108
+ <text fg={t.textMuted} selectable={false}>
109
109
  no window data
110
110
  </text>
111
111
  )
@@ -116,16 +116,16 @@ function ToolSection({ snap, tool }: ToolSectionProps) {
116
116
  return (
117
117
  <box flexDirection="column">
118
118
  <box flexDirection="row" justifyContent="space-between">
119
- <text fg={t.accent} selectable={false}>
119
+ <text fg={t.text} selectable={false}>
120
120
  {TOOL_TITLE[tool]}
121
121
  </text>
122
122
  {snap.planTier ? (
123
- <text fg={t.muted} selectable={false}>
123
+ <text fg={t.textMuted} selectable={false}>
124
124
  {snap.planTier}
125
125
  </text>
126
126
  ) : null}
127
127
  </box>
128
- <text fg={t.muted} selectable={false}>
128
+ <text fg={t.textMuted} selectable={false}>
129
129
  {`Updated ${relative}`}
130
130
  </text>
131
131
  {body}
@@ -134,14 +134,14 @@ function ToolSection({ snap, tool }: ToolSectionProps) {
134
134
  }
135
135
 
136
136
  function WindowRow({ window }: { window: UsageWindow }) {
137
- const t = useTokens()
137
+ const t = useTheme()
138
138
  const percent = window.percent
139
139
  const { empty, filled } = buildBar(percent)
140
140
 
141
- let barColor = t.palette.success
141
+ let barColor = t.success
142
142
  if (percent !== null) {
143
- if (percent >= 85) barColor = t.palette.error
144
- else if (percent >= 60) barColor = t.palette.warning
143
+ if (percent >= 85) barColor = t.error
144
+ else if (percent >= 60) barColor = t.warning
145
145
  }
146
146
 
147
147
  const pctText = percent === null ? '—' : `${Math.round(percent)}% used`
@@ -149,23 +149,23 @@ function WindowRow({ window }: { window: UsageWindow }) {
149
149
 
150
150
  return (
151
151
  <box flexDirection="column" paddingTop={1}>
152
- <text fg={t.palette.ink} selectable={false}>
152
+ <text fg={t.text} selectable={false}>
153
153
  {window.label}
154
154
  </text>
155
155
  <box flexDirection="row">
156
156
  <text fg={barColor} selectable={false}>
157
157
  {filled}
158
158
  </text>
159
- <text fg={t.muted} selectable={false}>
159
+ <text fg={t.textMuted} selectable={false}>
160
160
  {empty}
161
161
  </text>
162
162
  </box>
163
163
  <box flexDirection="row" justifyContent="space-between">
164
- <text fg={t.muted} selectable={false}>
164
+ <text fg={t.textMuted} selectable={false}>
165
165
  {pctText}
166
166
  </text>
167
167
  {resetText ? (
168
- <text fg={t.muted} selectable={false}>
168
+ <text fg={t.textMuted} selectable={false}>
169
169
  {resetText}
170
170
  </text>
171
171
  ) : null}
@@ -176,10 +176,10 @@ function WindowRow({ window }: { window: UsageWindow }) {
176
176
  }
177
177
 
178
178
  function PaceLine({ pace }: { pace: NonNullable<UsageWindow['pace']> }) {
179
- const t = useTokens()
180
- let color = t.muted
181
- if (paceStageIsBehind(pace.stage)) color = t.palette.warning
182
- else if (paceStageIsAhead(pace.stage)) color = t.palette.success
179
+ const t = useTheme()
180
+ let color = t.textMuted
181
+ if (paceStageIsBehind(pace.stage)) color = t.warning
182
+ else if (paceStageIsAhead(pace.stage)) color = t.success
183
183
 
184
184
  const suffix = pace.rightText ? ` · ${pace.rightText}` : ''
185
185
  return (
@@ -5,7 +5,7 @@ import { useLayoutEffect, useMemo } from 'react'
5
5
  import { collectHelpEntries, HELP_MODE_LABELS } from '../../../../input/keymap/help-entries'
6
6
  import { dispatchGlobal } from '../../../../state/dispatch-ref'
7
7
  import { useKeymap } from '../../../keymap-context'
8
- import { useTokens } from '../../../theme'
8
+ import { useTheme } from '../../../theme'
9
9
  import { uiTokens } from '../../../ui-tokens'
10
10
  import { Picker, type PickerItem } from '../shared/picker'
11
11
 
@@ -23,7 +23,7 @@ function matchesFilter(needle: string, ...fields: (string | undefined)[]): boole
23
23
  }
24
24
 
25
25
  export function HelpModal({ cursorPos, filter, scope, selectedIndex }: HelpModalProps) {
26
- const t = useTokens()
26
+ const t = useTheme()
27
27
  const config = useKeymap()
28
28
  const allEntries = useMemo(() => collectHelpEntries(config), [config])
29
29
  const scoped = useMemo(
@@ -49,17 +49,16 @@ export function HelpModal({ cursorPos, filter, scope, selectedIndex }: HelpModal
49
49
  }, [filtered.length])
50
50
 
51
51
  const items: PickerItem[] = filtered.map((entry, index) => {
52
- const active = index === selectedIndex
53
52
  return {
54
53
  group: entry.modeLabel,
55
54
  key: `${entry.mode}::${entry.keysDisplay}::${entry.description ?? ''}::${index}`,
56
55
  title: (
57
- <text fg={active ? t.palette.ink : t.muted} wrapMode="none">
56
+ <text fg={t.textMuted} wrapMode="none">
58
57
  {entry.description ?? ''}
59
58
  </text>
60
59
  ),
61
60
  trailing: (
62
- <text fg={active ? t.palette.primary : t.accent} wrapMode="none">
61
+ <text fg={t.textMuted} wrapMode="none">
63
62
  {entry.keysDisplay}
64
63
  </text>
65
64
  ),
@@ -76,7 +75,7 @@ export function HelpModal({ cursorPos, filter, scope, selectedIndex }: HelpModal
76
75
  items={items}
77
76
  selectedIndex={selectedIndex}
78
77
  emptyState={
79
- <text fg={t.muted}>{filter ? 'No matching bindings.' : 'No bindings registered.'}</text>
78
+ <text fg={t.textMuted}>{filter ? 'No matching bindings.' : 'No bindings registered.'}</text>
80
79
  }
81
80
  onHover={(index) => dispatchGlobal({ index, type: 'set-modal-selection-index' })}
82
81
  />
@@ -1,4 +1,4 @@
1
- import { useTokens } from '../../../theme'
1
+ import { useTheme } from '../../../theme'
2
2
  import { uiTokens } from '../../../ui-tokens'
3
3
  import { ListItem } from '../../primitives/list-item'
4
4
  import { ModalShell } from '../shared/modal-shell'
@@ -19,7 +19,7 @@ export function UpdateAvailableModal({
19
19
  latestVersion,
20
20
  selectedIndex,
21
21
  }: UpdateAvailableModalProps) {
22
- const t = useTokens()
22
+ const t = useTheme()
23
23
  return (
24
24
  <ModalShell
25
25
  title="Update available"
@@ -36,7 +36,7 @@ export function UpdateAvailableModal({
36
36
  key={option.label}
37
37
  active={active}
38
38
  direction="row"
39
- title={<text fg={active ? t.palette.ink : t.muted}>{option.label}</text>}
39
+ title={<text fg={active ? t.text : t.textMuted}>{option.label}</text>}
40
40
  />
41
41
  )
42
42
  })}
@@ -5,7 +5,7 @@ import type { ModeId } from '../../../../input/modes/types'
5
5
 
6
6
  import { useAppStore } from '../../../../state/app-store'
7
7
  import { dispatchGlobal, runSideEffectGlobal } from '../../../../state/dispatch-ref'
8
- import { useTokens } from '../../../theme'
8
+ import { useTheme } from '../../../theme'
9
9
  import { uiTokens } from '../../../ui-tokens'
10
10
  import { InputField } from '../../primitives/input-field'
11
11
  import { ModalShell } from '../shared/modal-shell'
@@ -49,7 +49,7 @@ function pickShellTitle(stage: 'edit' | 'generating' | 'confirm'): string {
49
49
  }
50
50
 
51
51
  function GeneratingOverlay({ assistant, model }: { assistant?: string; model?: string }) {
52
- const t = useTokens()
52
+ const t = useTheme()
53
53
  const frame = useSpinnerFrame(true)
54
54
  const providerLabel = [assistant, model].filter(Boolean).join(' · ') || 'configured provider'
55
55
  return (
@@ -60,14 +60,14 @@ function GeneratingOverlay({ assistant, model }: { assistant?: string; model?: s
60
60
  paddingTop={2}
61
61
  paddingBottom={2}
62
62
  >
63
- <text fg={t.palette.primary}>🪄</text>
63
+ <text fg={t.primary}>🪄</text>
64
64
  <box marginTop={1} flexDirection="row" gap={1}>
65
- <text fg={t.palette.primary}>{frame}</text>
66
- <text fg={t.palette.ink}>Generating commit message</text>
65
+ <text fg={t.primary}>{frame}</text>
66
+ <text fg={t.text}>Generating commit message</text>
67
67
  </box>
68
- <text fg={t.muted}>via {providerLabel}</text>
68
+ <text fg={t.textMuted}>via {providerLabel}</text>
69
69
  <box marginTop={1}>
70
- <text fg={t.muted}>Esc to cancel</text>
70
+ <text fg={t.textMuted}>Esc to cancel</text>
71
71
  </box>
72
72
  </box>
73
73
  )
@@ -82,7 +82,7 @@ export function GitCommitModal({
82
82
  stage,
83
83
  title,
84
84
  }: GitCommitModalProps) {
85
- const t = useTokens()
85
+ const t = useTheme()
86
86
  const titleActive = activeField === 'title'
87
87
  const bodyActive = activeField === 'body'
88
88
  const isConfirm = stage === 'confirm'
@@ -125,22 +125,22 @@ export function GitCommitModal({
125
125
  {isConfirm ? (
126
126
  <box flexDirection="column">
127
127
  {stagedCount > 0 ? (
128
- <text fg={t.palette.warning}>
128
+ <text fg={t.warning}>
129
129
  Commit will include the <strong>{stagedCount} staged file(s)</strong> only.
130
130
  </text>
131
131
  ) : (
132
- <text fg={t.palette.warning}>
132
+ <text fg={t.warning}>
133
133
  <strong>git add -A</strong> will stage every change before committing.
134
134
  </text>
135
135
  )}
136
- <text fg={t.muted}>Enter to confirm · Esc to cancel · edits below still apply.</text>
136
+ <text fg={t.textMuted}>Enter to confirm · Esc to cancel · edits below still apply.</text>
137
137
  </box>
138
138
  ) : null}
139
139
 
140
140
  {isGenerating ? null : (
141
141
  <>
142
142
  <box flexDirection="column">
143
- <text fg={titleActive ? t.palette.ink : t.muted}>Title</text>
143
+ <text fg={titleActive ? t.text : t.textMuted}>Title</text>
144
144
  <InputField
145
145
  active={titleActive}
146
146
  cursorPos={titleActive ? cursorPos : undefined}
@@ -149,7 +149,7 @@ export function GitCommitModal({
149
149
  </box>
150
150
 
151
151
  <box flexDirection="column">
152
- <text fg={bodyActive ? t.palette.ink : t.muted}>Body (optional)</text>
152
+ <text fg={bodyActive ? t.text : t.textMuted}>Body (optional)</text>
153
153
  <InputField
154
154
  active={bodyActive}
155
155
  cursorPos={bodyActive ? cursorPos : undefined}
@@ -163,7 +163,7 @@ export function GitCommitModal({
163
163
  <box flexDirection="row" gap={1} marginTop={1} alignItems="center">
164
164
  <box
165
165
  border
166
- borderColor={t.palette.primary}
166
+ borderColor={t.border}
167
167
  paddingLeft={1}
168
168
  paddingRight={1}
169
169
  flexDirection="row"
@@ -175,12 +175,12 @@ export function GitCommitModal({
175
175
  onAutoCommitClick()
176
176
  }}
177
177
  >
178
- {showBgSpinner ? <text fg={t.palette.primary}>{bgSpinnerFrame}</text> : null}
179
- <text fg={t.palette.primary}>
178
+ {showBgSpinner ? <text fg={t.primary}>{bgSpinnerFrame}</text> : null}
179
+ <text fg={t.text}>
180
180
  <strong>Auto-commit</strong>
181
181
  </text>
182
182
  </box>
183
- <text fg={t.muted}>C-a · stages all changes (AI-suggests message if empty)</text>
183
+ <text fg={t.textMuted}>C-a · stages all changes (AI-suggests message if empty)</text>
184
184
  </box>
185
185
  )}
186
186
  </ModalShell>
@@ -1,7 +1,7 @@
1
1
  import type { DirectoryResult } from '../../../../state/types'
2
2
 
3
3
  import { abbreviatePath } from '../../../path-format'
4
- import { getCurrentTokens, useTokens } from '../../../theme'
4
+ import { getCurrentTheme, useTheme } from '../../../theme'
5
5
  import { uiTokens } from '../../../ui-tokens'
6
6
  import { AutoComplete, Form, type FormOptionItem, TextField } from '../shared/form'
7
7
 
@@ -14,10 +14,10 @@ function getDirectoryResultIcon(result: DirectoryResult): string {
14
14
  }
15
15
 
16
16
  function getDirectoryResultColor(result: DirectoryResult): string {
17
- const t = getCurrentTokens()
18
- if (result.type === 'worktree') return t.palette.warning
19
- if (result.type === 'workspace') return t.accent
20
- return t.palette.primary
17
+ const t = getCurrentTheme()
18
+ if (result.type === 'worktree') return t.warning
19
+ if (result.type === 'workspace') return t.info
20
+ return t.text
21
21
  }
22
22
 
23
23
  interface CreateSessionModalProps {
@@ -37,7 +37,7 @@ export function CreateSessionModal({
37
37
  selectedIndex,
38
38
  sessionName,
39
39
  }: CreateSessionModalProps) {
40
- const t = useTokens()
40
+ const t = useTheme()
41
41
  const dirActive = activeField === 'directory'
42
42
  const nameActive = activeField === 'name'
43
43
 
@@ -46,7 +46,7 @@ export function CreateSessionModal({
46
46
  key: result.path,
47
47
  leading: <text fg={getDirectoryResultColor(result)}>{getDirectoryResultIcon(result)}</text>,
48
48
  title: (active) => (
49
- <text fg={active ? t.palette.ink : t.muted}>{abbreviatePath(result.path)}</text>
49
+ <text fg={active ? t.text : t.textMuted}>{abbreviatePath(result.path)}</text>
50
50
  ),
51
51
  }
52
52
  })
@@ -67,7 +67,7 @@ export function CreateSessionModal({
67
67
  selectedIndex={selectedIndex}
68
68
  maxVisibleRows={VISIBLE_ROWS}
69
69
  emptyState={
70
- <text fg={t.muted}>
70
+ <text fg={t.textMuted}>
71
71
  {directoryQuery.length > 0 ? 'No matches' : 'Type a project name to search...'}
72
72
  </text>
73
73
  }
@@ -4,7 +4,7 @@ import { dispatchGlobal, runSideEffectGlobal } from '../../../../state/dispatch-
4
4
  import { filterSessions } from '../../../../state/selectors'
5
5
  import { abbreviatePath } from '../../../path-format'
6
6
  import { orderSessionsForDisplay } from '../../../session-ordering'
7
- import { useTokens } from '../../../theme'
7
+ import { useTheme } from '../../../theme'
8
8
  import { uiTokens } from '../../../ui-tokens'
9
9
  import { Picker, type PickerItem } from '../shared/picker'
10
10
 
@@ -43,7 +43,7 @@ export function SessionPickerModal({
43
43
  selectedIndex,
44
44
  sessions,
45
45
  }: SessionPickerModalProps) {
46
- const t = useTokens()
46
+ const t = useTheme()
47
47
  const ordered = orderSessionsForDisplay(sessions)
48
48
  const baselineOrder = ordered.map((s) => s.id)
49
49
  const filtered = filterSessions(ordered, filter)
@@ -57,10 +57,10 @@ export function SessionPickerModal({
57
57
  onClick: () => runSideEffectGlobal({ type: 'confirm-selected-session' }),
58
58
  onDelete: () => runSideEffectGlobal({ type: 'delete-selected-session' }),
59
59
  subtitle: session.projectPath ? (
60
- <text fg={t.muted}>{abbreviatePath(session.projectPath)}</text>
60
+ <text fg={t.textMuted}>{abbreviatePath(session.projectPath)}</text>
61
61
  ) : undefined,
62
62
  title: (
63
- <text fg={active ? t.palette.ink : t.muted}>
63
+ <text fg={active ? t.text : t.textMuted}>
64
64
  {formatSessionLine(session, currentSessionId, currentTabCount, displayIndex)}
65
65
  </text>
66
66
  ),
@@ -71,7 +71,7 @@ export function SessionPickerModal({
71
71
  key: '__create-new__',
72
72
  onClick: () => runSideEffectGlobal({ type: 'confirm-selected-session' }),
73
73
  title: (
74
- <text fg={selectedIndex === filtered.length ? t.palette.ink : t.muted}>
74
+ <text fg={selectedIndex === filtered.length ? t.text : t.textMuted}>
75
75
  Create new workspace
76
76
  </text>
77
77
  ),
@@ -91,7 +91,7 @@ export function SessionPickerModal({
91
91
  selectedIndex={selectedIndex}
92
92
  emptyState={
93
93
  filtered.length === 0 ? (
94
- <text fg={t.muted}>{getEmptyStateMessage(hasFilter)}</text>
94
+ <text fg={t.textMuted}>{getEmptyStateMessage(hasFilter)}</text>
95
95
  ) : undefined
96
96
  }
97
97
  onHover={(index) => dispatchGlobal({ index, type: 'set-modal-selection-index' })}
@@ -2,7 +2,7 @@ import type { ModeId } from '@brimveyn/aimux-config'
2
2
 
3
3
  import { type ReactNode } from 'react'
4
4
 
5
- import { useTokens } from '../../../theme'
5
+ import { useTheme } from '../../../theme'
6
6
  import { InputField } from '../../primitives/input-field'
7
7
  import { ListItem } from '../../primitives/list-item'
8
8
  import { ModalShell } from './modal-shell'
@@ -81,11 +81,11 @@ export function Form({
81
81
  }
82
82
 
83
83
  export function FieldLabel({ active = false, children, description }: FieldLabelProps) {
84
- const t = useTokens()
84
+ const t = useTheme()
85
85
  return (
86
86
  <box flexDirection="column">
87
- {children ? <text fg={active ? t.palette.ink : t.muted}>{children}</text> : null}
88
- {description ? <text fg={t.muted}>{description}</text> : null}
87
+ {children ? <text fg={active ? t.text : t.textMuted}>{children}</text> : null}
88
+ {description ? <text fg={t.textMuted}>{description}</text> : null}
89
89
  </box>
90
90
  )
91
91
  }
@@ -2,7 +2,7 @@ import type { ModeId } from '@brimveyn/aimux-config'
2
2
 
3
3
  import { describeBindings } from '../../../../input/keymap/describe-bindings'
4
4
  import { useKeymap } from '../../../keymap-context'
5
- import { useTokens } from '../../../theme'
5
+ import { useTheme } from '../../../theme'
6
6
  import { Surface } from '../../primitives/surface'
7
7
 
8
8
  const KEYS_COLUMN_WIDTH = 12
@@ -13,7 +13,7 @@ interface ModalKeybindsOverlayProps {
13
13
  }
14
14
 
15
15
  export function ModalKeybindsOverlay({ limit, modeId }: ModalKeybindsOverlayProps) {
16
- const t = useTokens()
16
+ const t = useTheme()
17
17
  const config = useKeymap()
18
18
  const bindings = describeBindings(config, modeId, {
19
19
  mergeAlternativesByDescription: true,
@@ -29,9 +29,9 @@ export function ModalKeybindsOverlay({ limit, modeId }: ModalKeybindsOverlayProp
29
29
  {entries.map((binding) => (
30
30
  <box key={binding.description ?? binding.keys} flexDirection="row">
31
31
  <box width={KEYS_COLUMN_WIDTH}>
32
- <text fg={t.accent}>{binding.keysDisplay}</text>
32
+ <text fg={t.textMuted}>{binding.keysDisplay}</text>
33
33
  </box>
34
- <text fg={t.muted}>{binding.description ?? ''}</text>
34
+ <text fg={t.textMuted}>{binding.description ?? ''}</text>
35
35
  </box>
36
36
  ))}
37
37
  </Surface>
@@ -3,7 +3,7 @@ import type { ModeId } from '@brimveyn/aimux-config'
3
3
  import { type BoxRenderable, type OptimizedBuffer, RGBA } from '@opentui/core'
4
4
  import { type ReactNode } from 'react'
5
5
 
6
- import { useTokens, useTransparent } from '../../../theme'
6
+ import { useTheme, useTransparent } from '../../../theme'
7
7
  import { ModalKeybindsOverlay } from './modal-keybinds-overlay'
8
8
 
9
9
  interface ModalShellProps {
@@ -57,9 +57,9 @@ export function ModalShell({
57
57
  title,
58
58
  width,
59
59
  }: ModalShellProps) {
60
- const t = useTokens()
60
+ const t = useTheme()
61
61
  const transparent = useTransparent()
62
- const bg = transparent ? 'transparent' : t.elevated
62
+ const bg = transparent ? 'transparent' : t.backgroundPanel
63
63
  return (
64
64
  <box
65
65
  position="absolute"
@@ -72,7 +72,7 @@ export function ModalShell({
72
72
  >
73
73
  <box
74
74
  border
75
- borderColor={t.palette.primary}
75
+ borderColor={t.border}
76
76
  backgroundColor={bg}
77
77
  padding={1}
78
78
  width={width}
@@ -80,8 +80,8 @@ export function ModalShell({
80
80
  >
81
81
  <box width="100%" flexDirection="column" gap={listGap}>
82
82
  <box flexDirection="column">
83
- <text fg={t.accent}>{title}</text>
84
- {subtitle ? <text fg={t.muted}>{subtitle}</text> : null}
83
+ <text fg={t.text}>{title}</text>
84
+ {subtitle ? <text fg={t.textMuted}>{subtitle}</text> : null}
85
85
  </box>
86
86
  {children}
87
87
  {footer ? <box>{footer}</box> : null}
@@ -4,7 +4,7 @@ import type { ScrollBoxRenderable } from '@opentui/core'
4
4
  import { useTerminalDimensions } from '@opentui/react'
5
5
  import { type ReactNode, useLayoutEffect, useRef } from 'react'
6
6
 
7
- import { useTokens } from '../../../theme'
7
+ import { useTheme } from '../../../theme'
8
8
  import { BareInput } from '../../primitives/bare-input'
9
9
  import { ListItem } from '../../primitives/list-item'
10
10
  import { ModalShell } from './modal-shell'
@@ -39,7 +39,7 @@ const VIEWPORT_HEIGHT_RATIO = 0.6
39
39
  const MODAL_CHROME_ROWS = 6
40
40
 
41
41
  function PickerItemCtas({ onDelete, onEdit }: { onEdit?: () => void; onDelete?: () => void }) {
42
- const t = useTokens()
42
+ const t = useTheme()
43
43
  return (
44
44
  <box flexDirection="row" gap={1}>
45
45
  {onEdit ? (
@@ -49,7 +49,7 @@ function PickerItemCtas({ onDelete, onEdit }: { onEdit?: () => void; onDelete?:
49
49
  onEdit()
50
50
  }}
51
51
  >
52
- <text fg={t.palette.primary}>[edit]</text>
52
+ <text fg={t.primary}>[edit]</text>
53
53
  </box>
54
54
  ) : null}
55
55
  {onDelete ? (
@@ -59,7 +59,7 @@ function PickerItemCtas({ onDelete, onEdit }: { onEdit?: () => void; onDelete?:
59
59
  onDelete()
60
60
  }}
61
61
  >
62
- <text fg={t.palette.error}>[del]</text>
62
+ <text fg={t.error}>[del]</text>
63
63
  </box>
64
64
  ) : null}
65
65
  </box>
@@ -80,7 +80,7 @@ export function Picker({
80
80
  title,
81
81
  width,
82
82
  }: PickerProps) {
83
- const t = useTokens()
83
+ const t = useTheme()
84
84
  const dimensions = useTerminalDimensions()
85
85
  const maxHeight = Math.max(6, Math.floor(dimensions.height * VIEWPORT_HEIGHT_RATIO))
86
86
  const listHeight = Math.max(1, maxHeight - MODAL_CHROME_ROWS)
@@ -140,7 +140,7 @@ export function Picker({
140
140
  if (item.group && item.group !== prevGroup) {
141
141
  nodes.push(
142
142
  <box key={`group::${item.group}`} paddingLeft={1} paddingTop={index === 0 ? 0 : 1}>
143
- <text fg={t.palette.warning} wrapMode="none">
143
+ <text fg={t.textMuted} wrapMode="none">
144
144
  {item.group}
145
145
  </text>
146
146
  </box>
@@ -2,7 +2,7 @@ import type { SnippetRecord } from '../../../../state/types'
2
2
 
3
3
  import { dispatchGlobal, runSideEffectGlobal } from '../../../../state/dispatch-ref'
4
4
  import { filterSnippets } from '../../../../state/selectors'
5
- import { useTokens } from '../../../theme'
5
+ import { useTheme } from '../../../theme'
6
6
  import { uiTokens } from '../../../ui-tokens'
7
7
  import { Picker, type PickerItem } from '../shared/picker'
8
8
 
@@ -27,7 +27,7 @@ export function SnippetPickerModal({
27
27
  selectedIndex,
28
28
  snippets,
29
29
  }: SnippetPickerModalProps) {
30
- const t = useTokens()
30
+ const t = useTheme()
31
31
  const filtered = filterSnippets(snippets, filter)
32
32
 
33
33
  const items: PickerItem[] = filtered.map((snippet, index) => {
@@ -40,9 +40,9 @@ export function SnippetPickerModal({
40
40
  },
41
41
  onDelete: () => runSideEffectGlobal({ type: 'delete-selected-snippet' }),
42
42
  onEdit: () => runSideEffectGlobal({ type: 'edit-selected-snippet' }),
43
- subtitle: <text fg={t.muted}>{truncateContent(snippet.content)}</text>,
43
+ subtitle: <text fg={t.textMuted}>{truncateContent(snippet.content)}</text>,
44
44
  title: (
45
- <text fg={active ? t.palette.ink : t.muted}>
45
+ <text fg={active ? t.text : t.textMuted}>
46
46
  <strong>{snippet.name}</strong>
47
47
  </text>
48
48
  ),
@@ -60,7 +60,7 @@ export function SnippetPickerModal({
60
60
  items={items}
61
61
  selectedIndex={selectedIndex}
62
62
  emptyState={
63
- <text fg={t.muted}>
63
+ <text fg={t.textMuted}>
64
64
  {filter ? 'No matching snippets.' : 'No snippets yet. Press n to create one.'}
65
65
  </text>
66
66
  }
@@ -3,7 +3,7 @@ import type { AssistantId } from '../../../../state/types'
3
3
  import { getAllAssistantOptions, getAssistantOption } from '../../../../pty/command-registry'
4
4
  import { dispatchGlobal, runSideEffectGlobal } from '../../../../state/dispatch-ref'
5
5
  import { filterAssistants } from '../../../../state/selectors'
6
- import { useTokens } from '../../../theme'
6
+ import { useTheme } from '../../../theme'
7
7
  import { uiTokens } from '../../../ui-tokens'
8
8
  import { Form, TextField } from '../shared/form'
9
9
  import { Picker, type PickerItem } from '../shared/picker'
@@ -25,7 +25,7 @@ export function NewTabModal({
25
25
  filter,
26
26
  selectedIndex,
27
27
  }: NewTabModalProps) {
28
- const t = useTokens()
28
+ const t = useTheme()
29
29
 
30
30
  if (editingCommand !== null) {
31
31
  const option =
@@ -60,11 +60,11 @@ export function NewTabModal({
60
60
  onEdit: () => dispatchGlobal({ assistantId: option.id, type: 'open-edit-custom-command' }),
61
61
  subtitle: (
62
62
  <box flexDirection="column">
63
- <text fg={t.muted}>{option.description}</text>
64
- {customCmd ? <text fg={t.palette.primary}>{customCmd}</text> : null}
63
+ <text fg={t.textMuted}>{option.description}</text>
64
+ {customCmd ? <text fg={t.primary}>{customCmd}</text> : null}
65
65
  </box>
66
66
  ),
67
- title: <text fg={active ? t.palette.ink : t.muted}>{option.label}</text>,
67
+ title: <text fg={active ? t.text : t.textMuted}>{option.label}</text>,
68
68
  }
69
69
  })
70
70
 
@@ -78,7 +78,7 @@ export function NewTabModal({
78
78
  cursorPos={cursorPos}
79
79
  items={items}
80
80
  selectedIndex={selectedIndex}
81
- emptyState={<text fg={t.muted}>No matching assistants.</text>}
81
+ emptyState={<text fg={t.textMuted}>No matching assistants.</text>}
82
82
  onHover={(index) => dispatchGlobal({ index, type: 'set-modal-selection-index' })}
83
83
  />
84
84
  )