@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.
- package/package.json +2 -2
- package/src/app.tsx +4 -5
- package/src/pty/terminal-snapshot.ts +7 -7
- package/src/ui/components/git/diff-renderer/fold-strip.tsx +7 -7
- package/src/ui/components/git/diff-renderer/pierre-diff.tsx +3 -3
- package/src/ui/components/git/diff-renderer/split-view.tsx +18 -17
- package/src/ui/components/git/diff-renderer/stacked-view.tsx +13 -13
- package/src/ui/components/git/git-panel.tsx +42 -39
- package/src/ui/components/git/git-view.tsx +20 -20
- package/src/ui/components/layout/session-bar.tsx +13 -13
- package/src/ui/components/layout/sidebar/sidebar.tsx +26 -28
- package/src/ui/components/layout/sidebar/tab-item.tsx +21 -21
- package/src/ui/components/layout/split-layout.tsx +2 -2
- package/src/ui/components/layout/status-bar.tsx +12 -12
- package/src/ui/components/layout/terminal-pane.tsx +19 -31
- package/src/ui/components/modals/app/ai-usage-modal.tsx +21 -21
- package/src/ui/components/modals/app/help-modal.tsx +5 -6
- package/src/ui/components/modals/app/update-available-modal.tsx +3 -3
- package/src/ui/components/modals/git/git-commit-modal.tsx +17 -17
- package/src/ui/components/modals/sessions/create-session-modal.tsx +8 -8
- package/src/ui/components/modals/sessions/session-picker-modal.tsx +6 -6
- package/src/ui/components/modals/shared/form.tsx +4 -4
- package/src/ui/components/modals/shared/modal-keybinds-overlay.tsx +4 -4
- package/src/ui/components/modals/shared/modal-shell.tsx +6 -6
- package/src/ui/components/modals/shared/picker.tsx +6 -6
- package/src/ui/components/modals/snippets/snippet-picker-modal.tsx +5 -5
- package/src/ui/components/modals/tabs/new-tab-modal.tsx +6 -6
- package/src/ui/components/modals/themes/theme-picker-modal.tsx +17 -20
- package/src/ui/components/overlays/ai-usage/ai-usage-indicator.tsx +12 -12
- package/src/ui/components/overlays/context-menu/context-menu-overlay.tsx +6 -6
- package/src/ui/components/overlays/pending-chord-overlay.tsx +5 -5
- package/src/ui/components/primitives/bare-input.tsx +5 -5
- package/src/ui/components/primitives/input-field.tsx +5 -5
- package/src/ui/components/primitives/list-item.tsx +27 -22
- package/src/ui/components/primitives/surface.tsx +12 -9
- package/src/ui/filter-themes.ts +9 -8
- package/src/ui/root.tsx +5 -4
- package/src/ui/shiki.ts +8 -11
- package/src/ui/theme-store.ts +48 -118
- package/src/ui/theme.ts +8 -8
- 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 {
|
|
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 =
|
|
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.
|
|
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 =
|
|
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.
|
|
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.
|
|
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.
|
|
119
|
+
<text fg={t.text} selectable={false}>
|
|
120
120
|
{TOOL_TITLE[tool]}
|
|
121
121
|
</text>
|
|
122
122
|
{snap.planTier ? (
|
|
123
|
-
<text fg={t.
|
|
123
|
+
<text fg={t.textMuted} selectable={false}>
|
|
124
124
|
{snap.planTier}
|
|
125
125
|
</text>
|
|
126
126
|
) : null}
|
|
127
127
|
</box>
|
|
128
|
-
<text fg={t.
|
|
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 =
|
|
137
|
+
const t = useTheme()
|
|
138
138
|
const percent = window.percent
|
|
139
139
|
const { empty, filled } = buildBar(percent)
|
|
140
140
|
|
|
141
|
-
let barColor = t.
|
|
141
|
+
let barColor = t.success
|
|
142
142
|
if (percent !== null) {
|
|
143
|
-
if (percent >= 85) barColor = t.
|
|
144
|
-
else if (percent >= 60) barColor = t.
|
|
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.
|
|
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.
|
|
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.
|
|
164
|
+
<text fg={t.textMuted} selectable={false}>
|
|
165
165
|
{pctText}
|
|
166
166
|
</text>
|
|
167
167
|
{resetText ? (
|
|
168
|
-
<text fg={t.
|
|
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 =
|
|
180
|
-
let color = t.
|
|
181
|
-
if (paceStageIsBehind(pace.stage)) color = t.
|
|
182
|
-
else if (paceStageIsAhead(pace.stage)) color = t.
|
|
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 {
|
|
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 =
|
|
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={
|
|
56
|
+
<text fg={t.textMuted} wrapMode="none">
|
|
58
57
|
{entry.description ?? ''}
|
|
59
58
|
</text>
|
|
60
59
|
),
|
|
61
60
|
trailing: (
|
|
62
|
-
<text fg={
|
|
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.
|
|
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 {
|
|
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 =
|
|
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.
|
|
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 {
|
|
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 =
|
|
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.
|
|
63
|
+
<text fg={t.primary}>🪄</text>
|
|
64
64
|
<box marginTop={1} flexDirection="row" gap={1}>
|
|
65
|
-
<text fg={t.
|
|
66
|
-
<text fg={t.
|
|
65
|
+
<text fg={t.primary}>{frame}</text>
|
|
66
|
+
<text fg={t.text}>Generating commit message</text>
|
|
67
67
|
</box>
|
|
68
|
-
<text fg={t.
|
|
68
|
+
<text fg={t.textMuted}>via {providerLabel}</text>
|
|
69
69
|
<box marginTop={1}>
|
|
70
|
-
<text fg={t.
|
|
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 =
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
179
|
-
<text fg={t.
|
|
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.
|
|
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 {
|
|
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 =
|
|
18
|
-
if (result.type === 'worktree') return t.
|
|
19
|
-
if (result.type === 'workspace') return t.
|
|
20
|
-
return t.
|
|
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 =
|
|
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.
|
|
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.
|
|
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 {
|
|
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 =
|
|
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.
|
|
60
|
+
<text fg={t.textMuted}>{abbreviatePath(session.projectPath)}</text>
|
|
61
61
|
) : undefined,
|
|
62
62
|
title: (
|
|
63
|
-
<text fg={active ? t.
|
|
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.
|
|
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.
|
|
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 {
|
|
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 =
|
|
84
|
+
const t = useTheme()
|
|
85
85
|
return (
|
|
86
86
|
<box flexDirection="column">
|
|
87
|
-
{children ? <text fg={active ? t.
|
|
88
|
-
{description ? <text fg={t.
|
|
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 {
|
|
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 =
|
|
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.
|
|
32
|
+
<text fg={t.textMuted}>{binding.keysDisplay}</text>
|
|
33
33
|
</box>
|
|
34
|
-
<text fg={t.
|
|
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 {
|
|
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 =
|
|
60
|
+
const t = useTheme()
|
|
61
61
|
const transparent = useTransparent()
|
|
62
|
-
const bg = transparent ? 'transparent' : t.
|
|
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.
|
|
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.
|
|
84
|
-
{subtitle ? <text fg={t.
|
|
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 {
|
|
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 =
|
|
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.
|
|
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.
|
|
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 =
|
|
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.
|
|
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 {
|
|
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 =
|
|
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.
|
|
43
|
+
subtitle: <text fg={t.textMuted}>{truncateContent(snippet.content)}</text>,
|
|
44
44
|
title: (
|
|
45
|
-
<text fg={active ? t.
|
|
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.
|
|
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 {
|
|
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 =
|
|
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.
|
|
64
|
-
{customCmd ? <text fg={t.
|
|
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.
|
|
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.
|
|
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
|
)
|