@brimveyn/aimux 1.9.5 → 1.9.6
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 +1 -1
- 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
|
@@ -10,7 +10,7 @@ import { dispatchGlobal, runSideEffectGlobal } from '../../../state/dispatch-ref
|
|
|
10
10
|
import { IDLE_SESSION_STATUS } from '../../../state/types'
|
|
11
11
|
import { useBusySpinner } from '../../hooks/use-busy-spinner'
|
|
12
12
|
import { moveIdToIdPosition, orderSessionsForDisplay } from '../../session-ordering'
|
|
13
|
-
import {
|
|
13
|
+
import { useTheme } from '../../theme'
|
|
14
14
|
import { ContextMenuBox } from '../overlays/context-menu/context-menu-box'
|
|
15
15
|
|
|
16
16
|
interface SessionBarProps {
|
|
@@ -18,8 +18,8 @@ interface SessionBarProps {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export function SessionBar({ forceVisible = false }: SessionBarProps) {
|
|
21
|
-
const t =
|
|
22
|
-
const headerBg =
|
|
21
|
+
const t = useTheme()
|
|
22
|
+
const headerBg = t.backgroundPanel
|
|
23
23
|
const sessions = useAppStore((s) => s.sessions)
|
|
24
24
|
const currentId = useAppStore((s) => s.currentSessionId)
|
|
25
25
|
const bar = useAppStore((s) => s.sessionBar)
|
|
@@ -151,13 +151,13 @@ export function SessionBar({ forceVisible = false }: SessionBarProps) {
|
|
|
151
151
|
flexDirection="row"
|
|
152
152
|
paddingLeft={1}
|
|
153
153
|
paddingRight={1}
|
|
154
|
-
backgroundColor={t.
|
|
154
|
+
backgroundColor={t.backgroundElement}
|
|
155
155
|
onMouseDown={(e) => {
|
|
156
156
|
e.stopPropagation()
|
|
157
157
|
dispatchGlobal({ returnToSessionPicker: false, type: 'open-create-session-modal' })
|
|
158
158
|
}}
|
|
159
159
|
>
|
|
160
|
-
<text fg={t.
|
|
160
|
+
<text fg={t.text} selectable={false}>
|
|
161
161
|
+ New
|
|
162
162
|
</text>
|
|
163
163
|
</box>
|
|
@@ -200,16 +200,16 @@ function SessionChip({
|
|
|
200
200
|
session,
|
|
201
201
|
status,
|
|
202
202
|
}: SessionChipProps) {
|
|
203
|
-
const t =
|
|
204
|
-
const selectionBg =
|
|
203
|
+
const t = useTheme()
|
|
204
|
+
const selectionBg = t.backgroundElement
|
|
205
205
|
const showSpinner = status.working
|
|
206
206
|
const showWaiting = status.waiting
|
|
207
207
|
const spinner = useBusySpinner(showSpinner)
|
|
208
|
-
const labelColor = active ? t.
|
|
208
|
+
const labelColor = active ? t.text : t.textMuted
|
|
209
209
|
const bgColor = dragging || active ? selectionBg : undefined
|
|
210
|
-
const idleColor = t.
|
|
211
|
-
const workingColor = t.
|
|
212
|
-
const waitingColor = t.
|
|
210
|
+
const idleColor = t.success
|
|
211
|
+
const workingColor = t.primary
|
|
212
|
+
const waitingColor = t.warning
|
|
213
213
|
const [hovered, setHovered] = useState(false)
|
|
214
214
|
|
|
215
215
|
return (
|
|
@@ -264,12 +264,12 @@ function SessionChip({
|
|
|
264
264
|
runSideEffectGlobal({ sessionId: session.id, type: 'delete-session' })
|
|
265
265
|
}}
|
|
266
266
|
>
|
|
267
|
-
<text fg={t.
|
|
267
|
+
<text fg={t.textMuted} selectable={false}>
|
|
268
268
|
×
|
|
269
269
|
</text>
|
|
270
270
|
</box>
|
|
271
271
|
) : (
|
|
272
|
-
<text fg={t.
|
|
272
|
+
<text fg={t.textMuted} selectable={false}>
|
|
273
273
|
{' '}
|
|
274
274
|
</text>
|
|
275
275
|
)}
|
|
@@ -7,7 +7,7 @@ import { memo, useMemo, useRef } from 'react'
|
|
|
7
7
|
|
|
8
8
|
import { useAppStore } from '../../../../state/app-store'
|
|
9
9
|
import { dispatchGlobal } from '../../../../state/dispatch-ref'
|
|
10
|
-
import {
|
|
10
|
+
import { getCurrentTheme, type ResolvedTuiTheme, useTheme } from '../../../theme'
|
|
11
11
|
import { buildGitPaneContextMenu } from '../../git/pane/git-pane-context-menu'
|
|
12
12
|
import { GitPaneWidget } from '../../git/pane/git-pane-widget'
|
|
13
13
|
import { ContextMenuBox } from '../../overlays/context-menu/context-menu-box'
|
|
@@ -37,19 +37,19 @@ const RESIZE_HANDLE = '│'
|
|
|
37
37
|
function getRowBackground({
|
|
38
38
|
alternate,
|
|
39
39
|
isActive,
|
|
40
|
-
|
|
40
|
+
t,
|
|
41
41
|
}: {
|
|
42
42
|
isActive: boolean
|
|
43
43
|
alternate: boolean
|
|
44
|
-
|
|
44
|
+
t: ResolvedTuiTheme
|
|
45
45
|
}): string | undefined {
|
|
46
|
-
if (isActive) return
|
|
47
|
-
if (alternate) return
|
|
48
|
-
return
|
|
46
|
+
if (isActive) return t.backgroundElement
|
|
47
|
+
if (alternate) return t.backgroundPanel
|
|
48
|
+
return t.backgroundPanel
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
const SidebarTop = memo(function SidebarTop({ contentWidth }: { contentWidth: number }) {
|
|
52
|
-
const
|
|
52
|
+
const t = useTheme()
|
|
53
53
|
const currentSessionId = useAppStore((s) => s.currentSessionId)
|
|
54
54
|
const sessions = useAppStore((s) => s.sessions)
|
|
55
55
|
const currentSession = currentSessionId
|
|
@@ -60,22 +60,20 @@ const SidebarTop = memo(function SidebarTop({ contentWidth }: { contentWidth: nu
|
|
|
60
60
|
|
|
61
61
|
return (
|
|
62
62
|
<box flexDirection="column" flexShrink={0} gap={0}>
|
|
63
|
-
<text fg={
|
|
63
|
+
<text fg={t.text}>
|
|
64
64
|
<strong>aimux</strong>
|
|
65
65
|
</text>
|
|
66
|
-
<text fg={
|
|
67
|
-
{currentSession ? currentSession.name : 'No workspace selected'}
|
|
68
|
-
</text>
|
|
66
|
+
<text fg={t.text}>{currentSession ? currentSession.name : 'No workspace selected'}</text>
|
|
69
67
|
{branch ? (
|
|
70
68
|
<box flexDirection="row">
|
|
71
|
-
<text fg={
|
|
72
|
-
<text fg={
|
|
69
|
+
<text fg={t.text}>{'\u{e702}'} </text>
|
|
70
|
+
<text fg={t.text}>{branch}</text>
|
|
73
71
|
</box>
|
|
74
72
|
) : null}
|
|
75
73
|
<box
|
|
76
74
|
flexDirection="row"
|
|
77
75
|
paddingY={1}
|
|
78
|
-
backgroundColor={
|
|
76
|
+
backgroundColor={t.backgroundPanel}
|
|
79
77
|
justifyContent="center"
|
|
80
78
|
marginTop={1}
|
|
81
79
|
onMouseDown={(e) => {
|
|
@@ -83,22 +81,22 @@ const SidebarTop = memo(function SidebarTop({ contentWidth }: { contentWidth: nu
|
|
|
83
81
|
dispatchGlobal({ type: 'open-new-tab-modal' })
|
|
84
82
|
}}
|
|
85
83
|
>
|
|
86
|
-
<text fg={
|
|
84
|
+
<text fg={t.text}>+ New assistant</text>
|
|
87
85
|
</box>
|
|
88
|
-
<text fg={
|
|
86
|
+
<text fg={t.textMuted}>{'·'.repeat(Math.max(0, contentWidth - 2))}</text>
|
|
89
87
|
</box>
|
|
90
88
|
)
|
|
91
89
|
})
|
|
92
90
|
|
|
93
91
|
function renderGroupGutter(isGroupStart: boolean, isGroupMiddle: boolean, isGroupEnd: boolean) {
|
|
94
|
-
const t =
|
|
92
|
+
const t = getCurrentTheme()
|
|
95
93
|
return (
|
|
96
94
|
<box flexDirection="column" width={1} overflow="hidden">
|
|
97
|
-
<text fg={t.
|
|
95
|
+
<text fg={t.border}>
|
|
98
96
|
{/* oxlint-disable-next-line no-nested-ternary */}
|
|
99
97
|
{isGroupStart ? GUTTER_START : isGroupMiddle ? GUTTER_MIDDLE : GUTTER_PAD}
|
|
100
98
|
</text>
|
|
101
|
-
<text fg={t.
|
|
99
|
+
<text fg={t.border}>{isGroupEnd ? GUTTER_END : GUTTER_PAD}</text>
|
|
102
100
|
</box>
|
|
103
101
|
)
|
|
104
102
|
}
|
|
@@ -108,7 +106,7 @@ interface TabsBodyProps {
|
|
|
108
106
|
}
|
|
109
107
|
|
|
110
108
|
const TabsBody = memo(function TabsBody({ onTabActivate }: TabsBodyProps) {
|
|
111
|
-
const
|
|
109
|
+
const t = useTheme()
|
|
112
110
|
const tabs = useAppStore((s) => s.tabs)
|
|
113
111
|
const activeTabId = useAppStore((s) => s.activeTabId)
|
|
114
112
|
const focusMode = useAppStore((s) => s.focusMode)
|
|
@@ -138,7 +136,7 @@ const TabsBody = memo(function TabsBody({ onTabActivate }: TabsBodyProps) {
|
|
|
138
136
|
>
|
|
139
137
|
{tabs.length === 0 ? (
|
|
140
138
|
<box paddingTop={1}>
|
|
141
|
-
<text fg={
|
|
139
|
+
<text fg={t.textMuted}>No tabs yet. Press Ctrl+n.</text>
|
|
142
140
|
</box>
|
|
143
141
|
) : (
|
|
144
142
|
tabs.map((tab, index) => {
|
|
@@ -154,7 +152,7 @@ const TabsBody = memo(function TabsBody({ onTabActivate }: TabsBodyProps) {
|
|
|
154
152
|
return (
|
|
155
153
|
<box
|
|
156
154
|
key={tab.id}
|
|
157
|
-
backgroundColor={getRowBackground({ alternate, isActive,
|
|
155
|
+
backgroundColor={getRowBackground({ alternate, isActive, t })}
|
|
158
156
|
flexDirection="row"
|
|
159
157
|
onMouseDown={(event) => {
|
|
160
158
|
event.stopPropagation()
|
|
@@ -186,8 +184,8 @@ export function Sidebar({
|
|
|
186
184
|
onSidebarResizeStart,
|
|
187
185
|
onTabActivate,
|
|
188
186
|
}: SidebarProps) {
|
|
189
|
-
const
|
|
190
|
-
const sidebarBg =
|
|
187
|
+
const t = useTheme()
|
|
188
|
+
const sidebarBg = t.background
|
|
191
189
|
const sidebarVisible = useAppStore((s) => s.sidebar.visible)
|
|
192
190
|
const sidebarWidth = useAppStore((s) => s.sidebar.width)
|
|
193
191
|
const gitPane = useAppStore((s) => s.gitPane)
|
|
@@ -215,7 +213,7 @@ export function Sidebar({
|
|
|
215
213
|
const tabsGrow = gitEmbedded ? Math.max(1, Math.round((1 - gitPane.embeddedRatio) * 100)) : 1
|
|
216
214
|
const gitGrow = gitEmbedded ? Math.max(1, Math.round(gitPane.embeddedRatio * 100)) : 0
|
|
217
215
|
|
|
218
|
-
const separator = <text fg={
|
|
216
|
+
const separator = <text fg={t.textMuted}>{'·'.repeat(Math.max(0, contentWidth - 2))}</text>
|
|
219
217
|
const gitBody = gitEmbedded ? (
|
|
220
218
|
<ContextMenuBox
|
|
221
219
|
flexDirection="column"
|
|
@@ -232,7 +230,7 @@ export function Sidebar({
|
|
|
232
230
|
<box
|
|
233
231
|
minHeight={1}
|
|
234
232
|
flexShrink={0}
|
|
235
|
-
backgroundColor={
|
|
233
|
+
backgroundColor={t.border}
|
|
236
234
|
onMouseDown={(event) => {
|
|
237
235
|
const body = bodyRef.current
|
|
238
236
|
if (!body) return
|
|
@@ -245,7 +243,7 @@ export function Sidebar({
|
|
|
245
243
|
})
|
|
246
244
|
}}
|
|
247
245
|
>
|
|
248
|
-
<text fg={
|
|
246
|
+
<text fg={t.border}>{RESIZE_HANDLE.repeat(Math.max(1, contentWidth))}</text>
|
|
249
247
|
</box>
|
|
250
248
|
) : null
|
|
251
249
|
|
|
@@ -315,7 +313,7 @@ export function Sidebar({
|
|
|
315
313
|
height="100%"
|
|
316
314
|
width={1}
|
|
317
315
|
flexShrink={0}
|
|
318
|
-
backgroundColor={
|
|
316
|
+
backgroundColor={t.border}
|
|
319
317
|
onMouseDown={(event) => {
|
|
320
318
|
event.preventDefault()
|
|
321
319
|
event.stopPropagation()
|
|
@@ -4,7 +4,7 @@ import type { TabSession } from '../../../../state/types'
|
|
|
4
4
|
|
|
5
5
|
import { dispatchGlobal, runSideEffectGlobal } from '../../../../state/dispatch-ref'
|
|
6
6
|
import { useBusySpinner } from '../../../hooks/use-busy-spinner'
|
|
7
|
-
import {
|
|
7
|
+
import { getCurrentTheme, useTheme } from '../../../theme'
|
|
8
8
|
import { ContextMenuBox } from '../../overlays/context-menu/context-menu-box'
|
|
9
9
|
|
|
10
10
|
interface TabItemProps {
|
|
@@ -16,16 +16,16 @@ interface TabItemProps {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
function getStatusColor(status: TabSession['status']): string {
|
|
19
|
-
const t =
|
|
19
|
+
const t = getCurrentTheme()
|
|
20
20
|
switch (status) {
|
|
21
21
|
case 'running':
|
|
22
|
-
return t.
|
|
22
|
+
return t.success
|
|
23
23
|
case 'disconnected':
|
|
24
|
-
return t.
|
|
24
|
+
return t.warning
|
|
25
25
|
case 'error':
|
|
26
|
-
return t.
|
|
26
|
+
return t.error
|
|
27
27
|
default:
|
|
28
|
-
return t.
|
|
28
|
+
return t.textMuted
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -38,33 +38,33 @@ function getIndicator(active: boolean, focused: boolean, inLayout: boolean): str
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
function getIndicatorColor(active: boolean, focused: boolean, inLayout: boolean): string {
|
|
41
|
-
const t =
|
|
41
|
+
const t = getCurrentTheme()
|
|
42
42
|
if (active) {
|
|
43
|
-
return focused ? t.
|
|
43
|
+
return focused ? t.primary : t.text
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
return inLayout ? t.
|
|
46
|
+
return inLayout ? t.textMuted : t.textMuted
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
function BusyIndicator() {
|
|
50
|
-
const t =
|
|
50
|
+
const t = useTheme()
|
|
51
51
|
const frame = useBusySpinner()
|
|
52
|
-
return <text fg={t.
|
|
52
|
+
return <text fg={t.primary}>{frame} working</text>
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
function WaitingIndicator() {
|
|
56
|
-
const t =
|
|
57
|
-
return <text fg={t.
|
|
56
|
+
const t = useTheme()
|
|
57
|
+
return <text fg={t.warning}>? waiting</text>
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
function ActivityIndicator({ tab }: { tab: TabSession }) {
|
|
61
|
-
const t =
|
|
61
|
+
const t = useTheme()
|
|
62
62
|
if (tab.status === 'error') {
|
|
63
|
-
return <text fg={t.
|
|
63
|
+
return <text fg={t.error}>✗ error</text>
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
if (tab.status === 'disconnected') {
|
|
67
|
-
return <text fg={t.
|
|
67
|
+
return <text fg={t.warning}>⏸ restore</text>
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
if (tab.activity === 'working') {
|
|
@@ -76,14 +76,14 @@ function ActivityIndicator({ tab }: { tab: TabSession }) {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
if (tab.activity === 'idle') {
|
|
79
|
-
return <text fg={t.
|
|
79
|
+
return <text fg={t.success}>● idle</text>
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
return <text fg={getStatusColor(tab.status)}>{tab.status}</text>
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
export function TabItem({ active, focused, id, inLayout, tab }: TabItemProps) {
|
|
86
|
-
const t =
|
|
86
|
+
const t = useTheme()
|
|
87
87
|
const label = tab.command.split(' ')[0]
|
|
88
88
|
const isInLayout = inLayout ?? false
|
|
89
89
|
const indicator = getIndicator(active, focused, isInLayout)
|
|
@@ -135,7 +135,7 @@ export function TabItem({ active, focused, id, inLayout, tab }: TabItemProps) {
|
|
|
135
135
|
<box flexDirection="row" alignItems="center">
|
|
136
136
|
<text fg={indicatorColor}>{indicator} </text>
|
|
137
137
|
<box flexGrow={1}>
|
|
138
|
-
<text fg={active ? t.
|
|
138
|
+
<text fg={active ? t.text : t.textMuted}>{tab.title}</text>
|
|
139
139
|
</box>
|
|
140
140
|
{hovered ? (
|
|
141
141
|
<box
|
|
@@ -145,12 +145,12 @@ export function TabItem({ active, focused, id, inLayout, tab }: TabItemProps) {
|
|
|
145
145
|
runSideEffectGlobal({ tabId: tab.id, type: 'close-tab' })
|
|
146
146
|
}}
|
|
147
147
|
>
|
|
148
|
-
<text fg={t.
|
|
148
|
+
<text fg={t.textMuted}>×</text>
|
|
149
149
|
</box>
|
|
150
150
|
) : null}
|
|
151
151
|
</box>
|
|
152
152
|
<box flexDirection="row">
|
|
153
|
-
<text fg={t.
|
|
153
|
+
<text fg={t.textMuted}> {label} </text>
|
|
154
154
|
<ActivityIndicator tab={tab} />
|
|
155
155
|
</box>
|
|
156
156
|
</ContextMenuBox>
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
type PaneRect,
|
|
12
12
|
type SplitDirection,
|
|
13
13
|
} from '../../../state/layout-tree'
|
|
14
|
-
import {
|
|
14
|
+
import { useTheme } from '../../theme'
|
|
15
15
|
import { TerminalPane } from './terminal-pane'
|
|
16
16
|
|
|
17
17
|
const PANE_CHROME = PANE_BORDER
|
|
@@ -58,7 +58,7 @@ export function SplitLayout({
|
|
|
58
58
|
onTerminalScrollEvent,
|
|
59
59
|
tabs,
|
|
60
60
|
}: SplitLayoutProps) {
|
|
61
|
-
const t =
|
|
61
|
+
const t = useTheme()
|
|
62
62
|
if (node.type === 'leaf') {
|
|
63
63
|
const tab = tabs.find((t) => t.id === node.tabId)
|
|
64
64
|
const isActive = node.tabId === activeTabId
|
|
@@ -4,22 +4,22 @@ import { version as APP_VERSION } from '../../../../package.json'
|
|
|
4
4
|
import { useAppStore } from '../../../state/app-store'
|
|
5
5
|
import { useKeymap } from '../../keymap-context'
|
|
6
6
|
import { getStatusBarModel } from '../../status-bar-model'
|
|
7
|
-
import {
|
|
7
|
+
import { getCurrentTheme, useTheme } from '../../theme'
|
|
8
8
|
import { AIUsageIndicator } from '../overlays/ai-usage/ai-usage-indicator'
|
|
9
9
|
|
|
10
10
|
function getModeColor(focusMode: AppState['focusMode']): string {
|
|
11
|
-
const t =
|
|
11
|
+
const t = getCurrentTheme()
|
|
12
12
|
switch (focusMode) {
|
|
13
13
|
case 'terminal-input':
|
|
14
|
-
return t.
|
|
14
|
+
return t.primary
|
|
15
15
|
case 'modal':
|
|
16
16
|
case 'command-edit':
|
|
17
|
-
return t.
|
|
17
|
+
return t.warning
|
|
18
18
|
case 'git':
|
|
19
|
-
return t.
|
|
19
|
+
return t.success
|
|
20
20
|
case 'navigation':
|
|
21
21
|
default:
|
|
22
|
-
return t.
|
|
22
|
+
return t.text
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -40,8 +40,8 @@ function getModeLabel(focusMode: AppState['focusMode']): string {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export function StatusBar() {
|
|
43
|
-
const t =
|
|
44
|
-
const headerBg =
|
|
43
|
+
const t = useTheme()
|
|
44
|
+
const headerBg = t.backgroundPanel
|
|
45
45
|
const state = useAppStore((s) => s)
|
|
46
46
|
const activeTab = state.tabs.find((tab) => tab.id === state.activeTabId)
|
|
47
47
|
const config = useKeymap()
|
|
@@ -60,14 +60,14 @@ export function StatusBar() {
|
|
|
60
60
|
<box width="100%" flexDirection="row">
|
|
61
61
|
<text fg={getModeColor(state.focusMode)}>[{getModeLabel(state.focusMode)}]</text>
|
|
62
62
|
<text> </text>
|
|
63
|
-
<text fg={t.
|
|
63
|
+
<text fg={t.text}>{model.left}</text>
|
|
64
64
|
</box>
|
|
65
65
|
<box width="100%" flexDirection="row" justifyContent="space-between">
|
|
66
|
-
<text fg={t.
|
|
66
|
+
<text fg={t.textMuted}>{model.right}</text>
|
|
67
67
|
<box flexDirection="row" gap={2}>
|
|
68
|
-
{model.help ? <text fg={t.
|
|
68
|
+
{model.help ? <text fg={t.textMuted}>{model.help}</text> : null}
|
|
69
69
|
<AIUsageIndicator />
|
|
70
|
-
<text fg={t.
|
|
70
|
+
<text fg={t.textMuted}>v{APP_VERSION}</text>
|
|
71
71
|
</box>
|
|
72
72
|
</box>
|
|
73
73
|
</box>
|
|
@@ -8,7 +8,7 @@ import type { TabSession, TerminalSnapshot, TerminalSpan } from '../../../state/
|
|
|
8
8
|
import { logInputDebug } from '../../../debug/input-log'
|
|
9
9
|
import { dispatchGlobal, runSideEffectGlobal } from '../../../state/dispatch-ref'
|
|
10
10
|
import { type ContextMenuItem, openContextMenu } from '../../context-menu/controller'
|
|
11
|
-
import {
|
|
11
|
+
import { getCurrentTheme, useTheme } from '../../theme'
|
|
12
12
|
import { ContextMenuBox } from '../overlays/context-menu/context-menu-box'
|
|
13
13
|
|
|
14
14
|
interface TerminalPaneProps {
|
|
@@ -47,17 +47,9 @@ function getTitle(
|
|
|
47
47
|
return `${tab.title} · ${tab.status}`
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
function getBorderColor(isActive: boolean,
|
|
51
|
-
const t =
|
|
52
|
-
|
|
53
|
-
return t.palette.primary
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (isActive) {
|
|
57
|
-
return t.accent
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return t.hover
|
|
50
|
+
function getBorderColor(isActive: boolean, _focusMode: TerminalPaneProps['focusMode']): string {
|
|
51
|
+
const t = getCurrentTheme()
|
|
52
|
+
return isActive ? t.borderActive : t.border
|
|
61
53
|
}
|
|
62
54
|
|
|
63
55
|
function renderSpan(span: TerminalSpan, key: string): ReactNode {
|
|
@@ -76,7 +68,7 @@ function renderSpan(span: TerminalSpan, key: string): ReactNode {
|
|
|
76
68
|
}
|
|
77
69
|
|
|
78
70
|
return (
|
|
79
|
-
<span key={key} fg={span.fg ??
|
|
71
|
+
<span key={key} fg={span.fg ?? getCurrentTheme().text} bg={span.bg}>
|
|
80
72
|
{node}
|
|
81
73
|
</span>
|
|
82
74
|
)
|
|
@@ -91,11 +83,11 @@ const TerminalViewport = memo(function TerminalViewport({
|
|
|
91
83
|
buffer,
|
|
92
84
|
viewport,
|
|
93
85
|
}: TerminalViewportProps) {
|
|
94
|
-
const t =
|
|
86
|
+
const t = useTheme()
|
|
95
87
|
if (viewport && viewport.lines.length > 0) {
|
|
96
88
|
const lines = viewport.lines
|
|
97
89
|
return (
|
|
98
|
-
<text fg={t.
|
|
90
|
+
<text fg={t.text}>
|
|
99
91
|
{lines.map((line, lineIndex) => (
|
|
100
92
|
<span key={`line-${lineIndex}`}>
|
|
101
93
|
{line.spans.map((span, spanIndex) => renderSpan(span, `s-${spanIndex}`))}
|
|
@@ -106,9 +98,7 @@ const TerminalViewport = memo(function TerminalViewport({
|
|
|
106
98
|
)
|
|
107
99
|
}
|
|
108
100
|
|
|
109
|
-
return
|
|
110
|
-
<text fg={t.palette.ink}>{buffer.length > 0 ? buffer : 'Waiting for workspace output...'}</text>
|
|
111
|
-
)
|
|
101
|
+
return <text fg={t.text}>{buffer.length > 0 ? buffer : 'Waiting for workspace output...'}</text>
|
|
112
102
|
})
|
|
113
103
|
|
|
114
104
|
export function TerminalPane({
|
|
@@ -126,8 +116,8 @@ export function TerminalPane({
|
|
|
126
116
|
tab,
|
|
127
117
|
tabId,
|
|
128
118
|
}: TerminalPaneProps) {
|
|
129
|
-
const t =
|
|
130
|
-
const editorBg =
|
|
119
|
+
const t = useTheme()
|
|
120
|
+
const editorBg = t.background
|
|
131
121
|
const paneIsActive = isActive ?? true
|
|
132
122
|
const canForwardMouse = focusMode === 'terminal-input' && !!tab && mouseForwardingEnabled
|
|
133
123
|
const canUseLocalScrollback = focusMode === 'terminal-input' && !!tab && localScrollbackEnabled
|
|
@@ -232,25 +222,25 @@ export function TerminalPane({
|
|
|
232
222
|
>
|
|
233
223
|
{!tab ? (
|
|
234
224
|
<box flexGrow={1} justifyContent="center" alignItems="center" flexDirection="column">
|
|
235
|
-
<text fg={t.
|
|
236
|
-
<text fg={t.
|
|
225
|
+
<text fg={t.textMuted}>· · ·</text>
|
|
226
|
+
<text fg={t.textMuted}> </text>
|
|
237
227
|
<box flexDirection="row">
|
|
238
|
-
<text fg={t.
|
|
239
|
-
<text fg={t.
|
|
240
|
-
<text fg={t.
|
|
228
|
+
<text fg={t.textMuted}>Press </text>
|
|
229
|
+
<text fg={t.primary}>Ctrl+n</text>
|
|
230
|
+
<text fg={t.textMuted}> to launch an assistant</text>
|
|
241
231
|
</box>
|
|
242
232
|
<box
|
|
243
233
|
flexDirection="row"
|
|
244
234
|
justifyContent="center"
|
|
245
235
|
marginTop={1}
|
|
246
236
|
paddingX={2}
|
|
247
|
-
backgroundColor={t.
|
|
237
|
+
backgroundColor={t.backgroundPanel}
|
|
248
238
|
onMouseDown={(event) => {
|
|
249
239
|
event.stopPropagation()
|
|
250
240
|
dispatchGlobal({ type: 'open-new-tab-modal' })
|
|
251
241
|
}}
|
|
252
242
|
>
|
|
253
|
-
<text fg={t.
|
|
243
|
+
<text fg={t.text}>New assistant</text>
|
|
254
244
|
</box>
|
|
255
245
|
</box>
|
|
256
246
|
) : (
|
|
@@ -271,11 +261,9 @@ export function TerminalPane({
|
|
|
271
261
|
)}
|
|
272
262
|
</ContextMenuBox>
|
|
273
263
|
{tab?.status === 'disconnected' ? (
|
|
274
|
-
<text fg={t.
|
|
275
|
-
Restored snapshot. Press Ctrl+r to restart this workspace.
|
|
276
|
-
</text>
|
|
264
|
+
<text fg={t.warning}>Restored snapshot. Press Ctrl+r to restart this workspace.</text>
|
|
277
265
|
) : null}
|
|
278
|
-
{tab?.errorMessage ? <text fg={t.
|
|
266
|
+
{tab?.errorMessage ? <text fg={t.error}>{tab.errorMessage}</text> : null}
|
|
279
267
|
</box>
|
|
280
268
|
)
|
|
281
269
|
}
|