@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
package/package.json
CHANGED
package/src/app.tsx
CHANGED
|
@@ -35,7 +35,7 @@ import { loadSnippetCatalog } from './state/snippet-catalog'
|
|
|
35
35
|
import { createInitialState } from './state/store'
|
|
36
36
|
import { KeymapContext } from './ui/keymap-context'
|
|
37
37
|
import { RootView } from './ui/root'
|
|
38
|
-
import { applyTheme, setTransparent } from './ui/theme'
|
|
38
|
+
import { applyTheme, setMode, setTransparent } from './ui/theme'
|
|
39
39
|
import { isKnownThemeId, type ThemeId } from './ui/themes'
|
|
40
40
|
import {
|
|
41
41
|
fetchLatestNpmVersion,
|
|
@@ -71,10 +71,9 @@ export function App({
|
|
|
71
71
|
const [themeId, setThemeId] = useState<ThemeId>(() => {
|
|
72
72
|
const config = loadConfig()
|
|
73
73
|
const persisted = config.themeId && isKnownThemeId(config.themeId) ? config.themeId : undefined
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
applyTheme(initial, resolvedConfig.theme?.paletteOverrides)
|
|
74
|
+
const initial: ThemeId = persisted ?? resolvedConfig.theme?.initialId ?? 'aimux'
|
|
75
|
+
applyTheme(initial)
|
|
76
|
+
if (resolvedConfig.theme?.initialMode) setMode(resolvedConfig.theme.initialMode)
|
|
78
77
|
setTransparent(config.themeTransparent ?? false)
|
|
79
78
|
return initial
|
|
80
79
|
})
|
|
@@ -2,7 +2,7 @@ import type { Terminal } from '@xterm/headless'
|
|
|
2
2
|
|
|
3
3
|
import type { TerminalLine, TerminalSnapshot, TerminalSpan } from '../state/types'
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { getCurrentTheme } from '../ui/theme'
|
|
6
6
|
|
|
7
7
|
const SNAPSHOT_TAIL_LINE_COUNT = 10
|
|
8
8
|
|
|
@@ -115,17 +115,17 @@ function buildLine(
|
|
|
115
115
|
let bg = getColorHex(current.getBgColor(), bgMode)
|
|
116
116
|
|
|
117
117
|
if (current.isInverse()) {
|
|
118
|
-
const tokens =
|
|
119
|
-
const resolvedFg = fg ?? tokens.
|
|
120
|
-
const resolvedBg = bg ?? tokens.
|
|
118
|
+
const tokens = getCurrentTheme()
|
|
119
|
+
const resolvedFg = fg ?? tokens.text
|
|
120
|
+
const resolvedBg = bg ?? tokens.background
|
|
121
121
|
;[fg, bg] = [resolvedBg, resolvedFg]
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
const isCursorCell = cursorVisible && cursorColumn === column
|
|
125
125
|
if (isCursorCell) {
|
|
126
|
-
const tokens =
|
|
127
|
-
const resolvedFg = fg ?? tokens.
|
|
128
|
-
const resolvedBg = bg ?? tokens.
|
|
126
|
+
const tokens = getCurrentTheme()
|
|
127
|
+
const resolvedFg = fg ?? tokens.text
|
|
128
|
+
const resolvedBg = bg ?? tokens.background
|
|
129
129
|
;[fg, bg] = [resolvedBg, resolvedFg]
|
|
130
130
|
}
|
|
131
131
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useTheme } from '../../../theme'
|
|
2
2
|
import { FOLD_STEP, type FoldInfo } from './build-rows'
|
|
3
3
|
import { type FoldDispatch } from './pierre-diff'
|
|
4
4
|
|
|
@@ -8,11 +8,11 @@ interface Props {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
function Button({ label, onPress }: { label: string; onPress: () => void }) {
|
|
11
|
-
const t =
|
|
12
|
-
const bg =
|
|
11
|
+
const t = useTheme()
|
|
12
|
+
const bg = t.diffContextBg
|
|
13
13
|
return (
|
|
14
14
|
<box paddingLeft={1} paddingRight={1} backgroundColor={bg} onMouseDown={onPress}>
|
|
15
|
-
<text fg={t.
|
|
15
|
+
<text fg={t.primary}>{label}</text>
|
|
16
16
|
</box>
|
|
17
17
|
)
|
|
18
18
|
}
|
|
@@ -22,8 +22,8 @@ function Spacer() {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export function FoldStrip({ dispatch, fold }: Props) {
|
|
25
|
-
const t =
|
|
26
|
-
const headerBg =
|
|
25
|
+
const t = useTheme()
|
|
26
|
+
const headerBg = t.diffContextBg
|
|
27
27
|
const { bottomExpanded, foldId, hidden, topExpanded, total } = fold
|
|
28
28
|
const stepUp = Math.min(FOLD_STEP, hidden)
|
|
29
29
|
const stepDown = Math.min(FOLD_STEP, hidden)
|
|
@@ -71,7 +71,7 @@ export function FoldStrip({ dispatch, fold }: Props) {
|
|
|
71
71
|
|
|
72
72
|
return (
|
|
73
73
|
<box flexDirection="row" backgroundColor={headerBg} paddingLeft={1} paddingRight={1}>
|
|
74
|
-
<text fg={t.
|
|
74
|
+
<text fg={t.textMuted}>{`⋯ ${hidden} hidden `}</text>
|
|
75
75
|
{controls}
|
|
76
76
|
</box>
|
|
77
77
|
)
|
|
@@ -8,7 +8,7 @@ import type { ThemeId } from '../../../themes'
|
|
|
8
8
|
import { useAppStore } from '../../../../state/app-store'
|
|
9
9
|
import { dispatchGlobal } from '../../../../state/dispatch-ref'
|
|
10
10
|
import { type FoldState } from '../../../../state/types'
|
|
11
|
-
import {
|
|
11
|
+
import { useTheme } from '../../../theme'
|
|
12
12
|
import { buildDiffSegments, firstChangeSegmentOffset, gutterWidth } from './build-rows'
|
|
13
13
|
import { SplitView, type SplitViewHandle } from './split-view'
|
|
14
14
|
import { StackedView, type StackedViewHandle } from './stacked-view'
|
|
@@ -45,7 +45,7 @@ export const PierreDiff = forwardRef<PierreDiffHandle, Props>(function PierreDif
|
|
|
45
45
|
{ cacheKey, diff, path, themeId, view },
|
|
46
46
|
ref
|
|
47
47
|
) {
|
|
48
|
-
const t =
|
|
48
|
+
const t = useTheme()
|
|
49
49
|
const preparation = useDiffPreparation(cacheKey, diff, path, themeId)
|
|
50
50
|
const file = preparation.file ?? undefined
|
|
51
51
|
const highlights: DiffHighlights = preparation.highlights
|
|
@@ -123,7 +123,7 @@ export const PierreDiff = forwardRef<PierreDiffHandle, Props>(function PierreDif
|
|
|
123
123
|
if (!file) {
|
|
124
124
|
return (
|
|
125
125
|
<box flexGrow={1} padding={1}>
|
|
126
|
-
<text fg={t.
|
|
126
|
+
<text fg={t.textMuted}>
|
|
127
127
|
{preparation.preparing ? 'Preparing diff…' : '(could not parse diff)'}
|
|
128
128
|
</text>
|
|
129
129
|
</box>
|
|
@@ -20,7 +20,7 @@ import type { DiffHighlights, FoldDispatch } from './pierre-diff'
|
|
|
20
20
|
|
|
21
21
|
import { getScrollViewportDelta } from '../../../../app-runtime/terminal-mouse-adapter'
|
|
22
22
|
import { scrollGitDiff } from '../../../git-view-controls'
|
|
23
|
-
import {
|
|
23
|
+
import { useTheme, useTransparent } from '../../../theme'
|
|
24
24
|
import {
|
|
25
25
|
type DiffSegment,
|
|
26
26
|
estimatedSegmentHeight,
|
|
@@ -67,7 +67,8 @@ export const SplitView = forwardRef<SplitViewHandle, Props>(function SplitView(
|
|
|
67
67
|
{ contentWidth, file, foldDispatch, highlights, requestSegmentHighlights, segments },
|
|
68
68
|
ref
|
|
69
69
|
) {
|
|
70
|
-
const
|
|
70
|
+
const t = useTheme()
|
|
71
|
+
const separatorBg = t.background
|
|
71
72
|
const leftRef = useRef<ScrollBoxRenderable | null>(null)
|
|
72
73
|
const rightRef = useRef<ScrollBoxRenderable | null>(null)
|
|
73
74
|
const measuredHeightsRef = useRef<Record<string, number>>({})
|
|
@@ -224,12 +225,12 @@ function SideRow({
|
|
|
224
225
|
}
|
|
225
226
|
|
|
226
227
|
function HunkHeaderRow({ row }: { row: Extract<SplitRowOrHeader, { type: 'hunk-header' }> }) {
|
|
227
|
-
const t =
|
|
228
|
-
const headerBg =
|
|
228
|
+
const t = useTheme()
|
|
229
|
+
const headerBg = t.diffContextBg
|
|
229
230
|
return (
|
|
230
231
|
<box flexDirection="row" backgroundColor={headerBg} paddingLeft={1} paddingRight={1}>
|
|
231
|
-
<text fg={t.
|
|
232
|
-
{row.context ? <text fg={t.
|
|
232
|
+
<text fg={t.text}>{row.spec}</text>
|
|
233
|
+
{row.context ? <text fg={t.textMuted}> {row.context}</text> : null}
|
|
233
234
|
</box>
|
|
234
235
|
)
|
|
235
236
|
}
|
|
@@ -245,29 +246,29 @@ function HalfRow({
|
|
|
245
246
|
height: number
|
|
246
247
|
tokens: ThemedToken[][]
|
|
247
248
|
}) {
|
|
248
|
-
const t =
|
|
249
|
-
const headerBg =
|
|
249
|
+
const t = useTheme()
|
|
250
|
+
const headerBg = t.diffContextBg
|
|
250
251
|
const transparent = useTransparent()
|
|
251
252
|
if (cell.type === 'filler') {
|
|
252
253
|
return <box backgroundColor={headerBg} height={height} />
|
|
253
254
|
}
|
|
254
255
|
let bg: string | undefined
|
|
255
256
|
let sign = ' '
|
|
256
|
-
let signColor = t.
|
|
257
|
+
let signColor = t.textMuted
|
|
257
258
|
if (cell.type === 'addition') {
|
|
258
|
-
bg = t.
|
|
259
|
+
bg = t.diffAddedBg
|
|
259
260
|
sign = '+'
|
|
260
|
-
signColor = t.
|
|
261
|
+
signColor = t.diffAdded
|
|
261
262
|
} else if (cell.type === 'deletion') {
|
|
262
|
-
bg = t.
|
|
263
|
+
bg = t.diffRemovedBg
|
|
263
264
|
sign = '-'
|
|
264
|
-
signColor = t.
|
|
265
|
+
signColor = t.diffRemoved
|
|
265
266
|
}
|
|
266
267
|
const num = String(cell.lineNumber).padStart(gw, ' ')
|
|
267
268
|
const lineTokens = tokens[cell.lineIdx]
|
|
268
269
|
return (
|
|
269
270
|
<box flexDirection="row" backgroundColor={transparent ? undefined : bg} height={height}>
|
|
270
|
-
<text fg={t.
|
|
271
|
+
<text fg={t.textMuted}>{` ${num} `}</text>
|
|
271
272
|
<text fg={signColor}>{`${sign} `}</text>
|
|
272
273
|
<LineContent content={cell.content} tokens={lineTokens} />
|
|
273
274
|
</box>
|
|
@@ -275,9 +276,9 @@ function HalfRow({
|
|
|
275
276
|
}
|
|
276
277
|
|
|
277
278
|
function LineContent({ content, tokens }: { content: string; tokens: ThemedToken[] | undefined }) {
|
|
278
|
-
const t =
|
|
279
|
+
const t = useTheme()
|
|
279
280
|
if (!tokens || tokens.length === 0) {
|
|
280
|
-
return <text fg={t.
|
|
281
|
+
return <text fg={t.text}>{content}</text>
|
|
281
282
|
}
|
|
282
283
|
return (
|
|
283
284
|
<text>
|
|
@@ -288,7 +289,7 @@ function LineContent({ content, tokens }: { content: string; tokens: ThemedToken
|
|
|
288
289
|
if (s.italic) attributes |= TextAttributes.ITALIC
|
|
289
290
|
if (s.underline) attributes |= TextAttributes.UNDERLINE
|
|
290
291
|
return (
|
|
291
|
-
<span key={i} fg={s.fg ?? t.
|
|
292
|
+
<span key={i} fg={s.fg ?? t.text} attributes={attributes}>
|
|
292
293
|
{s.text}
|
|
293
294
|
</span>
|
|
294
295
|
)
|
|
@@ -20,7 +20,7 @@ import type { DiffHighlights, FoldDispatch } from './pierre-diff'
|
|
|
20
20
|
|
|
21
21
|
import { getScrollViewportDelta } from '../../../../app-runtime/terminal-mouse-adapter'
|
|
22
22
|
import { scrollGitDiff } from '../../../git-view-controls'
|
|
23
|
-
import {
|
|
23
|
+
import { useTheme, useTransparent } from '../../../theme'
|
|
24
24
|
import {
|
|
25
25
|
type DiffSegment,
|
|
26
26
|
estimatedSegmentHeight,
|
|
@@ -179,14 +179,14 @@ function UnifiedRowRender({
|
|
|
179
179
|
highlights: DiffHighlights
|
|
180
180
|
row: UnifiedRowOrHeader
|
|
181
181
|
}) {
|
|
182
|
-
const t =
|
|
183
|
-
const headerBg =
|
|
182
|
+
const t = useTheme()
|
|
183
|
+
const headerBg = t.diffContextBg
|
|
184
184
|
const transparent = useTransparent()
|
|
185
185
|
if (row.type === 'hunk-header') {
|
|
186
186
|
return (
|
|
187
187
|
<box flexDirection="row" backgroundColor={headerBg} paddingLeft={1} paddingRight={1}>
|
|
188
|
-
<text fg={t.
|
|
189
|
-
{row.context ? <text fg={t.
|
|
188
|
+
<text fg={t.text}>{row.spec}</text>
|
|
189
|
+
{row.context ? <text fg={t.textMuted}> {row.context}</text> : null}
|
|
190
190
|
</box>
|
|
191
191
|
)
|
|
192
192
|
}
|
|
@@ -199,21 +199,21 @@ function UnifiedRowRender({
|
|
|
199
199
|
const tokens = highlights.add[row.lineIdx]
|
|
200
200
|
return (
|
|
201
201
|
<box flexDirection="row" height={row.height}>
|
|
202
|
-
<text fg={t.
|
|
203
|
-
<text fg={t.
|
|
202
|
+
<text fg={t.textMuted}>{` ${pad(row.delLineNumber)} ${pad(row.addLineNumber)} `}</text>
|
|
203
|
+
<text fg={t.text}> </text>
|
|
204
204
|
<LineContent content={row.content} tokens={tokens} />
|
|
205
205
|
</box>
|
|
206
206
|
)
|
|
207
207
|
}
|
|
208
|
-
const bg = row.type === 'addition' ? t.
|
|
208
|
+
const bg = row.type === 'addition' ? t.diffAddedBg : t.diffRemovedBg
|
|
209
209
|
const sign = row.type === 'addition' ? '+' : '-'
|
|
210
|
-
const signColor = row.type === 'addition' ? t.
|
|
210
|
+
const signColor = row.type === 'addition' ? t.diffAdded : t.diffRemoved
|
|
211
211
|
const delNum = row.type === 'deletion' ? row.lineNumber : undefined
|
|
212
212
|
const addNum = row.type === 'addition' ? row.lineNumber : undefined
|
|
213
213
|
const tokens = row.type === 'addition' ? highlights.add[row.lineIdx] : highlights.del[row.lineIdx]
|
|
214
214
|
return (
|
|
215
215
|
<box flexDirection="row" backgroundColor={transparent ? undefined : bg} height={row.height}>
|
|
216
|
-
<text fg={t.
|
|
216
|
+
<text fg={t.textMuted}>{` ${pad(delNum)} ${pad(addNum)} `}</text>
|
|
217
217
|
<text fg={signColor}>{`${sign} `}</text>
|
|
218
218
|
<LineContent content={row.content} tokens={tokens} />
|
|
219
219
|
</box>
|
|
@@ -221,9 +221,9 @@ function UnifiedRowRender({
|
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
function LineContent({ content, tokens }: { content: string; tokens: ThemedToken[] | undefined }) {
|
|
224
|
-
const t =
|
|
224
|
+
const t = useTheme()
|
|
225
225
|
if (!tokens || tokens.length === 0) {
|
|
226
|
-
return <text fg={t.
|
|
226
|
+
return <text fg={t.text}>{content}</text>
|
|
227
227
|
}
|
|
228
228
|
return (
|
|
229
229
|
<text>
|
|
@@ -234,7 +234,7 @@ function LineContent({ content, tokens }: { content: string; tokens: ThemedToken
|
|
|
234
234
|
if (s.italic) attributes |= TextAttributes.ITALIC
|
|
235
235
|
if (s.underline) attributes |= TextAttributes.UNDERLINE
|
|
236
236
|
return (
|
|
237
|
-
<span key={i} fg={s.fg ?? t.
|
|
237
|
+
<span key={i} fg={s.fg ?? t.text} attributes={attributes}>
|
|
238
238
|
{s.text}
|
|
239
239
|
</span>
|
|
240
240
|
)
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
type GitTreeFileRow,
|
|
19
19
|
type GitTreeFolderRow,
|
|
20
20
|
} from '../../../state/git-tree'
|
|
21
|
-
import {
|
|
21
|
+
import { getCurrentTheme, getTransparent, useTheme, useTransparent } from '../../theme'
|
|
22
22
|
|
|
23
23
|
interface GitPanelProps {
|
|
24
24
|
collapsedFolders?: Record<string, true>
|
|
@@ -49,19 +49,20 @@ const BASE_SECTION_ORDER: GitFileSection[] = ['staged', 'unstaged', 'untracked']
|
|
|
49
49
|
const HISTORICAL_SECTION_ORDER: GitFileSection[] = ['historical', 'untracked']
|
|
50
50
|
|
|
51
51
|
function statusColor(status: GitFileEntry['status']): string {
|
|
52
|
-
const t =
|
|
52
|
+
const t = getCurrentTheme()
|
|
53
53
|
switch (status) {
|
|
54
54
|
case '?':
|
|
55
|
+
return t.text
|
|
55
56
|
case 'A':
|
|
56
|
-
return t.
|
|
57
|
+
return t.diffAdded
|
|
57
58
|
case 'C':
|
|
58
59
|
case 'R':
|
|
59
|
-
return t.
|
|
60
|
+
return t.text
|
|
60
61
|
case 'D':
|
|
61
62
|
case 'U':
|
|
62
|
-
return t.
|
|
63
|
+
return t.diffRemoved
|
|
63
64
|
case 'M':
|
|
64
|
-
return t.
|
|
65
|
+
return t.warning
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
68
|
|
|
@@ -99,7 +100,7 @@ function renderFileLabel(
|
|
|
99
100
|
pathConfig: GitPanePathConfig,
|
|
100
101
|
fileListMode: GitFileListMode
|
|
101
102
|
): ReactNode {
|
|
102
|
-
const t =
|
|
103
|
+
const t = getCurrentTheme()
|
|
103
104
|
const transform = pathConfig.enabled ? pathConfig.pathFn : undefined
|
|
104
105
|
const displayPath = transform ? transform(file.path) : file.path
|
|
105
106
|
const { basename, prefix } = splitPath(displayPath)
|
|
@@ -108,8 +109,8 @@ function renderFileLabel(
|
|
|
108
109
|
if (!file.renamedFrom) {
|
|
109
110
|
return (
|
|
110
111
|
<text wrapMode="none">
|
|
111
|
-
<span fg={t.
|
|
112
|
-
{showDir ? <span fg={t.
|
|
112
|
+
<span fg={t.text}>{basename}</span>
|
|
113
|
+
{showDir ? <span fg={t.textMuted}> {dir}</span> : null}
|
|
113
114
|
</text>
|
|
114
115
|
)
|
|
115
116
|
}
|
|
@@ -118,11 +119,11 @@ function renderFileLabel(
|
|
|
118
119
|
const renamedDir = stripTrailingSlash(renamed.prefix)
|
|
119
120
|
return (
|
|
120
121
|
<text wrapMode="none">
|
|
121
|
-
<span fg={t.
|
|
122
|
-
{showDir && renamedDir ? <span fg={t.
|
|
123
|
-
<span fg={t.
|
|
124
|
-
<span fg={t.
|
|
125
|
-
{showDir ? <span fg={t.
|
|
122
|
+
<span fg={t.textMuted}>{renamed.basename}</span>
|
|
123
|
+
{showDir && renamedDir ? <span fg={t.textMuted}> {renamedDir}</span> : null}
|
|
124
|
+
<span fg={t.textMuted}> → </span>
|
|
125
|
+
<span fg={t.text}>{basename}</span>
|
|
126
|
+
{showDir ? <span fg={t.textMuted}> {dir}</span> : null}
|
|
126
127
|
</text>
|
|
127
128
|
)
|
|
128
129
|
}
|
|
@@ -136,28 +137,31 @@ function renderDiffCount(
|
|
|
136
137
|
hasNumstat: boolean
|
|
137
138
|
): ReactNode {
|
|
138
139
|
if (!diffCountConfig.enabled) return null
|
|
139
|
-
const t =
|
|
140
|
+
const t = getCurrentTheme()
|
|
140
141
|
if (!hasNumstat) {
|
|
141
142
|
return (
|
|
142
|
-
<text fg={t.
|
|
143
|
+
<text fg={t.textMuted} bg={bg} flexShrink={0}>
|
|
143
144
|
—
|
|
144
145
|
</text>
|
|
145
146
|
)
|
|
146
147
|
}
|
|
147
148
|
return (
|
|
148
149
|
<box flexDirection="row" flexShrink={0}>
|
|
149
|
-
<text fg={
|
|
150
|
-
<text fg={t.
|
|
150
|
+
<text fg={getCurrentTheme().diffAdded} bg={bg}>{`+${padRight(file.added, addedW)}`}</text>
|
|
151
|
+
<text fg={t.textMuted} bg={bg}>
|
|
151
152
|
{' '}
|
|
152
153
|
</text>
|
|
153
|
-
<text
|
|
154
|
+
<text
|
|
155
|
+
fg={getCurrentTheme().diffRemoved}
|
|
156
|
+
bg={bg}
|
|
157
|
+
>{`−${padRight(file.removed, removedW)}`}</text>
|
|
154
158
|
</box>
|
|
155
159
|
)
|
|
156
160
|
}
|
|
157
161
|
|
|
158
162
|
function renderFolderRow(row: GitTreeFolderRow, isSelected: boolean): ReactNode {
|
|
159
|
-
const t =
|
|
160
|
-
const bg = isSelected && !getTransparent() ? t.
|
|
163
|
+
const t = getCurrentTheme()
|
|
164
|
+
const bg = isSelected && !getTransparent() ? t.backgroundElement : undefined
|
|
161
165
|
const onSelect = (): void => {
|
|
162
166
|
dispatchGlobal({ key: row.key, type: 'git-mode-select-entry-by-key' })
|
|
163
167
|
}
|
|
@@ -168,13 +172,13 @@ function renderFolderRow(row: GitTreeFolderRow, isSelected: boolean): ReactNode
|
|
|
168
172
|
<box key={row.key} flexDirection="row" gap={1} backgroundColor={bg} onMouseDown={onSelect}>
|
|
169
173
|
<box flexGrow={1} overflow="hidden" paddingLeft={row.depth * 2}>
|
|
170
174
|
<box flexDirection="row" gap={1} onMouseDown={onToggle}>
|
|
171
|
-
<text fg={t.
|
|
175
|
+
<text fg={t.textMuted} bg={bg}>
|
|
172
176
|
{row.isCollapsed ? '▸' : '▾'}
|
|
173
177
|
</text>
|
|
174
|
-
<text fg={
|
|
178
|
+
<text fg={getCurrentTheme().textMuted} bg={bg}>
|
|
175
179
|
{row.isCollapsed ? '\uf07b' : '\uf07c'}
|
|
176
180
|
</text>
|
|
177
|
-
<text fg={t.
|
|
181
|
+
<text fg={t.textMuted} bg={bg} wrapMode="none">
|
|
178
182
|
{row.name}
|
|
179
183
|
</text>
|
|
180
184
|
</box>
|
|
@@ -193,10 +197,9 @@ function renderFileRow(
|
|
|
193
197
|
diffCountConfig: GitPaneDiffCountConfig,
|
|
194
198
|
repoPrefixes: Record<string, string>
|
|
195
199
|
): ReactNode {
|
|
196
|
-
const t = getCurrentTokens()
|
|
197
200
|
const file = row.file
|
|
198
201
|
const hasNumstat = file.added !== null || file.removed !== null
|
|
199
|
-
const bg = isSelected && !getTransparent() ?
|
|
202
|
+
const bg = isSelected && !getTransparent() ? getCurrentTheme().backgroundElement : undefined
|
|
200
203
|
const onSelect = (): void => {
|
|
201
204
|
dispatchGlobal({ key: row.key, type: 'git-mode-select-entry-by-key' })
|
|
202
205
|
}
|
|
@@ -213,7 +216,7 @@ function renderFileRow(
|
|
|
213
216
|
</box>
|
|
214
217
|
{repoTag ? (
|
|
215
218
|
<box flexShrink={0}>
|
|
216
|
-
<text fg={
|
|
219
|
+
<text fg={getCurrentTheme().primary} bg={bg}>
|
|
217
220
|
<strong>{repoTag}</strong>
|
|
218
221
|
</text>
|
|
219
222
|
</box>
|
|
@@ -242,7 +245,7 @@ function renderTreeSection(
|
|
|
242
245
|
repoPrefixes: Record<string, string>
|
|
243
246
|
): ReactNode {
|
|
244
247
|
if (files.length === 0) return null
|
|
245
|
-
const
|
|
248
|
+
const t2 = getCurrentTheme()
|
|
246
249
|
const nextFileListMode = fileListMode === 'tree' ? 'flat' : 'tree'
|
|
247
250
|
const toggleListMode = (): void => {
|
|
248
251
|
dispatchGlobal({ type: 'git-mode-toggle-file-list-mode' })
|
|
@@ -251,16 +254,16 @@ function renderTreeSection(
|
|
|
251
254
|
return (
|
|
252
255
|
<box key={section} flexDirection="column" marginTop={marginTop}>
|
|
253
256
|
<box flexDirection="row" justifyContent="space-between">
|
|
254
|
-
<text fg={
|
|
257
|
+
<text fg={t2.text}>
|
|
255
258
|
<strong>
|
|
256
259
|
{title} ({files.length})
|
|
257
260
|
</strong>
|
|
258
261
|
</text>
|
|
259
262
|
{showListModeToggle ? (
|
|
260
263
|
<box flexDirection="row" gap={1} onMouseDown={toggleListMode}>
|
|
261
|
-
<text fg={fileListMode === 'tree' ?
|
|
262
|
-
<text fg={
|
|
263
|
-
<text fg={fileListMode === 'flat' ?
|
|
264
|
+
<text fg={fileListMode === 'tree' ? t2.primary : t2.textMuted}>tree</text>
|
|
265
|
+
<text fg={t2.textMuted}>|</text>
|
|
266
|
+
<text fg={fileListMode === 'flat' ? t2.primary : t2.textMuted}>flat</text>
|
|
264
267
|
</box>
|
|
265
268
|
) : null}
|
|
266
269
|
</box>
|
|
@@ -301,18 +304,18 @@ function computeStatusPlaceholder(
|
|
|
301
304
|
gitPanel: GitPanelState,
|
|
302
305
|
hasProjectPath: boolean
|
|
303
306
|
): StatusPlaceholder | null {
|
|
304
|
-
const t =
|
|
307
|
+
const t = getCurrentTheme()
|
|
305
308
|
if (!hasProjectPath) {
|
|
306
|
-
return { label: 'No active session', labelColor: t.
|
|
309
|
+
return { label: 'No active session', labelColor: t.textMuted }
|
|
307
310
|
}
|
|
308
311
|
if (gitPanel.error === 'not-a-repo') {
|
|
309
|
-
return { label: 'Not a git repository', labelColor: t.
|
|
312
|
+
return { label: 'Not a git repository', labelColor: t.textMuted }
|
|
310
313
|
}
|
|
311
314
|
if (gitPanel.error === 'unknown') {
|
|
312
|
-
return { label: 'Git error', labelColor: t.
|
|
315
|
+
return { label: 'Git error', labelColor: t.error }
|
|
313
316
|
}
|
|
314
317
|
if (gitPanel.files.length === 0) {
|
|
315
|
-
return { label: 'Working tree clean', labelColor: t.
|
|
318
|
+
return { label: 'Working tree clean', labelColor: t.textMuted }
|
|
316
319
|
}
|
|
317
320
|
return null
|
|
318
321
|
}
|
|
@@ -331,7 +334,7 @@ export const GitPanel = memo(function GitPanel({
|
|
|
331
334
|
projectPath,
|
|
332
335
|
selectedEntryKey,
|
|
333
336
|
}: GitPanelProps) {
|
|
334
|
-
const t =
|
|
337
|
+
const t = useTheme()
|
|
335
338
|
useTransparent()
|
|
336
339
|
const repoPrefixes = useAppStore((s) => s.multiRepo.prefixes)
|
|
337
340
|
const sectionOrder = headOffset > 0 ? HISTORICAL_SECTION_ORDER : BASE_SECTION_ORDER
|
|
@@ -367,7 +370,7 @@ export const GitPanel = memo(function GitPanel({
|
|
|
367
370
|
return (
|
|
368
371
|
<box flexDirection="column" flexGrow={1} flexShrink={1} flexBasis={0} overflow="hidden" gap={0}>
|
|
369
372
|
{hasRemoteTracking ? (
|
|
370
|
-
<text fg={t.
|
|
373
|
+
<text fg={t.textMuted}>
|
|
371
374
|
↑{gitPanel.ahead} ↓{gitPanel.behind}
|
|
372
375
|
</text>
|
|
373
376
|
) : null}
|
|
@@ -12,7 +12,7 @@ import { useAppStore } from '../../../state/app-store'
|
|
|
12
12
|
import { dispatchGlobal } from '../../../state/dispatch-ref'
|
|
13
13
|
import { getSelectedGitFile, gitFileKey } from '../../../state/git-tree'
|
|
14
14
|
import { setGitDiffScroller } from '../../git-view-controls'
|
|
15
|
-
import {
|
|
15
|
+
import { useTheme } from '../../theme'
|
|
16
16
|
import { PierreDiff, type PierreDiffHandle } from './diff-renderer'
|
|
17
17
|
import { useDiffPrefetch } from './diff-renderer/use-diff-prefetch'
|
|
18
18
|
import { GitPanel } from './git-panel'
|
|
@@ -48,25 +48,25 @@ const DiffStage = memo(function DiffStage({
|
|
|
48
48
|
themeId,
|
|
49
49
|
view,
|
|
50
50
|
}: DiffStageProps) {
|
|
51
|
-
const t =
|
|
51
|
+
const t = useTheme()
|
|
52
52
|
if (loading && !diff) {
|
|
53
53
|
return (
|
|
54
54
|
<box flexGrow={1} padding={1}>
|
|
55
|
-
<text fg={t.
|
|
55
|
+
<text fg={t.textMuted}>Loading diff…</text>
|
|
56
56
|
</box>
|
|
57
57
|
)
|
|
58
58
|
}
|
|
59
59
|
if (!diff) {
|
|
60
60
|
return (
|
|
61
61
|
<box flexGrow={1} padding={1}>
|
|
62
|
-
<text fg={t.
|
|
62
|
+
<text fg={t.textMuted}>Select a file.</text>
|
|
63
63
|
</box>
|
|
64
64
|
)
|
|
65
65
|
}
|
|
66
66
|
if (diff.errorMessage) {
|
|
67
67
|
return (
|
|
68
68
|
<box flexGrow={1} padding={1}>
|
|
69
|
-
<text fg={t.
|
|
69
|
+
<text fg={t.error}>{diff.errorMessage}</text>
|
|
70
70
|
</box>
|
|
71
71
|
)
|
|
72
72
|
}
|
|
@@ -75,7 +75,7 @@ const DiffStage = memo(function DiffStage({
|
|
|
75
75
|
if (placeholder) {
|
|
76
76
|
return (
|
|
77
77
|
<box flexGrow={1} padding={1}>
|
|
78
|
-
<text fg={t.
|
|
78
|
+
<text fg={t.textMuted}>{placeholder}</text>
|
|
79
79
|
</box>
|
|
80
80
|
)
|
|
81
81
|
}
|
|
@@ -84,7 +84,7 @@ const DiffStage = memo(function DiffStage({
|
|
|
84
84
|
<box flexDirection="column" flexGrow={1} overflow="hidden">
|
|
85
85
|
{diff.oldPath ? (
|
|
86
86
|
<box paddingLeft={1} paddingRight={1}>
|
|
87
|
-
<text fg={t.
|
|
87
|
+
<text fg={t.textMuted}>
|
|
88
88
|
renamed: {diff.oldPath} → {diff.path}
|
|
89
89
|
</text>
|
|
90
90
|
</box>
|
|
@@ -106,9 +106,9 @@ interface GitViewProps {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
export const GitView = memo(function GitView({ themeId }: GitViewProps) {
|
|
109
|
-
const t =
|
|
110
|
-
const sidebarBg =
|
|
111
|
-
const actionBg =
|
|
109
|
+
const t = useTheme()
|
|
110
|
+
const sidebarBg = t.background
|
|
111
|
+
const actionBg = t.backgroundElement
|
|
112
112
|
const dimensions = useTerminalDimensions()
|
|
113
113
|
const gitPane = useAppStore((s) => s.gitPane)
|
|
114
114
|
const gitPanel = useAppStore((s) => s.gitPanel)
|
|
@@ -196,13 +196,13 @@ export const GitView = memo(function GitView({ themeId }: GitViewProps) {
|
|
|
196
196
|
let footerNode: React.ReactNode = null
|
|
197
197
|
if (pendingHint) {
|
|
198
198
|
footerNode = (
|
|
199
|
-
<text fg={t.
|
|
199
|
+
<text fg={t.warning}>
|
|
200
200
|
<strong>{pendingHint}</strong>
|
|
201
201
|
</text>
|
|
202
202
|
)
|
|
203
203
|
} else if (actionMessage) {
|
|
204
204
|
footerNode = actionMessage.split('\n').map((line, idx) => (
|
|
205
|
-
<text key={idx} fg={t.
|
|
205
|
+
<text key={idx} fg={t.primary}>
|
|
206
206
|
{line}
|
|
207
207
|
</text>
|
|
208
208
|
))
|
|
@@ -220,24 +220,24 @@ export const GitView = memo(function GitView({ themeId }: GitViewProps) {
|
|
|
220
220
|
overflow="hidden"
|
|
221
221
|
>
|
|
222
222
|
<box flexDirection="column" flexShrink={0}>
|
|
223
|
-
<text fg={t.
|
|
223
|
+
<text fg={t.text}>
|
|
224
224
|
<strong>aimux · git</strong>
|
|
225
225
|
</text>
|
|
226
226
|
{gitPanel.branch ? (
|
|
227
227
|
<box flexDirection="row">
|
|
228
|
-
<text fg={t.
|
|
229
|
-
<text fg={t.
|
|
228
|
+
<text fg={t.text}>{'\u{e702}'} </text>
|
|
229
|
+
<text fg={t.text}>{gitPanel.branch}</text>
|
|
230
230
|
</box>
|
|
231
231
|
) : null}
|
|
232
232
|
{gitMode.headOffset > 0 ? (
|
|
233
233
|
<box flexDirection="row" gap={1}>
|
|
234
|
-
<text fg={t.
|
|
234
|
+
<text fg={t.warning}>
|
|
235
235
|
<strong>HEAD~{gitMode.headOffset}</strong>
|
|
236
236
|
</text>
|
|
237
|
-
<text fg={t.
|
|
237
|
+
<text fg={t.textMuted}>[ newer · ] older</text>
|
|
238
238
|
</box>
|
|
239
239
|
) : null}
|
|
240
|
-
<text fg={t.
|
|
240
|
+
<text fg={t.textMuted}>{'·'.repeat(Math.max(0, fileBarWidth - 2))}</text>
|
|
241
241
|
</box>
|
|
242
242
|
<GitPanel
|
|
243
243
|
collapsedFolders={gitMode.collapsedFolders}
|
|
@@ -258,7 +258,7 @@ export const GitView = memo(function GitView({ themeId }: GitViewProps) {
|
|
|
258
258
|
backgroundColor={sidebarBg}
|
|
259
259
|
>
|
|
260
260
|
<box flexGrow={1}>
|
|
261
|
-
<text fg={selectedFile ? t.
|
|
261
|
+
<text fg={selectedFile ? t.text : t.textMuted}>
|
|
262
262
|
{selectedFile ? selectedFile.path : 'Diff'}
|
|
263
263
|
</text>
|
|
264
264
|
</box>
|
|
@@ -272,7 +272,7 @@ export const GitView = memo(function GitView({ themeId }: GitViewProps) {
|
|
|
272
272
|
dispatchGlobal({ type: 'exit-git-mode' })
|
|
273
273
|
}}
|
|
274
274
|
>
|
|
275
|
-
<text fg={t.
|
|
275
|
+
<text fg={t.text}>
|
|
276
276
|
<strong>Exit diff</strong>
|
|
277
277
|
</text>
|
|
278
278
|
</box>
|