@brimveyn/aimux-config 0.3.3 → 0.4.0

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/README.md CHANGED
@@ -149,41 +149,58 @@ You can also bind a custom `ActionFn` for dynamic behavior.
149
149
 
150
150
  ## Themes
151
151
 
152
- Built-in theme IDs:
153
-
154
- - `aimux`
155
- - `dracula`
156
- - `dracula-at-night`
157
- - `everforest`
158
- - `tokyo-night`
159
- - `gruvbox-dark`
160
- - `catppuccin-mocha`
161
- - `nord`
162
- - `solarized-dark`
163
- - `one-dark`
164
- - `kanagawa`
165
-
166
- Helpers:
152
+ aimux themes are [Shiki](https://shiki.style/themes) themes. Two house themes
153
+ (`aimux`, `dracula-at-night`) ship alongside the full Shiki catalog — 67
154
+ themes total. The same `Theme` object powers UI colors and code highlighting.
155
+
156
+ Declare your own themes in config:
167
157
 
168
158
  ```ts
169
- themes.extend(baseThemeId, overrides)
170
- themes.create(colors)
159
+ import { defineConfig, themes } from '@brimveyn/aimux-config'
160
+
161
+ export default defineConfig({
162
+ theme: 'my-neon',
163
+ themes: {
164
+ // Palette shortcut — patch VSCode color keys on top of a base theme.
165
+ 'my-neon': themes.define('My Neon', 'aimux', {
166
+ 'textLink.foreground': '#ff00aa',
167
+ 'terminal.ansiMagenta': '#00ffcc',
168
+ }),
169
+ // Or drop a full VSCode theme JSON verbatim:
170
+ 'custom': themes.full({
171
+ name: 'custom',
172
+ displayName: 'Custom',
173
+ type: 'dark',
174
+ fg: '#eee',
175
+ bg: '#1a1a1a',
176
+ colors: {
177
+ /* VSCode workbench keys */
178
+ },
179
+ settings: [
180
+ /* TextMate token rules */
181
+ ],
182
+ }),
183
+ },
184
+ })
171
185
  ```
172
186
 
173
- Typed theme config is currently only `Partially supported` by the runtime.
187
+ See [`../../docs/guide/themes.md`](../../docs/guide/themes.md) for picker
188
+ shortcuts, the VSCode color key reference, and migration notes if you're
189
+ coming from the old palette alias API.
174
190
 
175
191
  ## Support Status
176
192
 
177
- | Surface | Status | Notes |
178
- | ------------ | ------------------- | --------------------------------------------------------------------- |
179
- | `keymaps` | Supported | Fully registered by the runtime |
180
- | `sessionBar` | Supported | Used during app initialization |
181
- | `gitPane` | Supported | Placement and rendering of the git file list (see docs reference) |
182
- | `theme` | Partially supported | Package surface exists, but runtime startup uses `aimux.json.themeId` |
183
- | `backends` | Typed surface only | Runtime wiring deferred |
184
- | `sidebar` | Typed surface only | Type exists, runtime not currently driven by this field |
185
- | `hooks` | Typed surface only | Type exists, runtime use not currently wired |
186
- | `snippets` | Typed surface only | Runtime currently uses `aimux-snippets.json` |
193
+ | Surface | Status | Notes |
194
+ | ------------ | ------------------ | -------------------------------------------------------------------- |
195
+ | `keymaps` | Supported | Fully registered by the runtime |
196
+ | `sessionBar` | Supported | Used during app initialization |
197
+ | `gitPane` | Supported | Placement and rendering of the git file list (see docs reference) |
198
+ | `theme` | Supported | Initial theme id; `aimux.json.themeId` wins if still known |
199
+ | `themes` | Supported | User themes; appear in the picker and power synthesized highlighting |
200
+ | `backends` | Typed surface only | Runtime wiring deferred |
201
+ | `sidebar` | Typed surface only | Type exists, runtime not currently driven by this field |
202
+ | `hooks` | Typed surface only | Type exists, runtime use not currently wired |
203
+ | `snippets` | Typed surface only | Runtime currently uses `aimux-snippets.json` |
187
204
 
188
205
  ## Backends Subpath
189
206
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brimveyn/aimux-config",
3
- "version": "0.3.3",
3
+ "version": "0.4.0",
4
4
  "description": "TypeScript configuration API for aimux — keymaps, themes, and backends with a fluent builder.",
5
5
  "keywords": [
6
6
  "aimux",
@@ -36,5 +36,8 @@
36
36
  },
37
37
  "publishConfig": {
38
38
  "access": "public"
39
+ },
40
+ "dependencies": {
41
+ "shiki": "^4.0.2"
39
42
  }
40
43
  }
package/src/actions.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ActionFn, AppAction, KeyResult, ModeContext } from './types'
1
+ import type { ActionFn, AppAction, KeyResult, ModeContext, ModeId } from './types'
2
2
 
3
3
  function r(
4
4
  actions: KeyResult['actions'] = [],
@@ -32,7 +32,9 @@ export const themePicker: KeyResult = r(
32
32
  [{ action: 'open', type: 'apply-theme' }],
33
33
  'modal.theme-picker'
34
34
  )
35
- export const helpModal: KeyResult = r([{ type: 'open-help-modal' }], [], 'modal.help')
35
+ export function helpModal(scope?: ModeId): KeyResult {
36
+ return r([{ scope, type: 'open-help-modal' }])
37
+ }
36
38
 
37
39
  export const toggleSidebar: KeyResult = r([{ type: 'toggle-sidebar' }])
38
40
  export const toggleGitPane: KeyResult = r([{ type: 'toggle-git-pane' }])
@@ -69,6 +71,8 @@ export const enterInsert: ActionFn = (ctx: ModeContext) => {
69
71
 
70
72
  export const closeModal: KeyResult = r([{ type: 'close-modal' }], [], 'navigation')
71
73
 
74
+ export const closeOverlayModal: KeyResult = r([{ type: 'close-modal' }])
75
+
72
76
  // ---------------------------------------------------------------------------
73
77
  // Dynamic actions (need ctx at runtime — ActionFn)
74
78
  // ---------------------------------------------------------------------------
@@ -109,6 +113,17 @@ export function resizeGitPane(delta: number): KeyResult {
109
113
  return r([{ delta, type: 'resize-git-pane' }])
110
114
  }
111
115
 
116
+ export function resizeGitDiffPane(delta: number): ActionFn {
117
+ return (ctx: ModeContext) => {
118
+ const nextRatio = Math.max(0.2, Math.min(0.8, ctx.state.gitPane.diffModeRatio + delta))
119
+ if (nextRatio === ctx.state.gitPane.diffModeRatio) return r([])
120
+ return r(
121
+ [{ delta, type: 'resize-git-diff-pane' }],
122
+ [{ ratio: nextRatio, type: 'persist-git-diff-mode-ratio' }]
123
+ )
124
+ }
125
+ }
126
+
112
127
  export function focusPane(direction: 'left' | 'right' | 'up' | 'down'): KeyResult {
113
128
  return r(
114
129
  [
@@ -214,6 +229,12 @@ export const beginHelpFilter: KeyResult = r(
214
229
  'modal.help.filtering'
215
230
  )
216
231
 
232
+ export const beginThemeFilter: KeyResult = r(
233
+ [{ type: 'begin-theme-filter' }],
234
+ [],
235
+ 'modal.theme-picker.filtering'
236
+ )
237
+
217
238
  export const confirmSplit: KeyResult = r([], [{ type: 'confirm-split' }])
218
239
 
219
240
  export const restoreTheme: KeyResult = r(
@@ -385,25 +406,65 @@ function clearPendingDelete(ctx: ModeContext): AppAction[] {
385
406
  return [{ path: null, type: 'git-mode-set-pending-delete' }]
386
407
  }
387
408
 
409
+ function gitFileKey(section: string, path: string): string {
410
+ return `${section}:${path}`
411
+ }
412
+
413
+ function selectedGitFile(ctx: ModeContext) {
414
+ const key = ctx.state.gitMode.selectedEntryKey
415
+ if (!key) return null
416
+ return (
417
+ ctx.state.gitPanel.files.find((file) => gitFileKey(file.section, file.path) === key) ?? null
418
+ )
419
+ }
420
+
388
421
  export const exitGitMode: KeyResult = r([{ type: 'exit-git-mode' }], [], 'navigation')
389
422
 
390
423
  export function selectGitFile(delta: -1 | 1): ActionFn {
391
424
  return (ctx: ModeContext) => {
392
- const total = ctx.state.gitPanel.files.length
393
- if (total === 0) return r([])
394
- const current = ctx.state.gitMode.selectedFileIndex
395
- const next = (current + delta + total) % total
396
- if (next === current) return r([])
397
- return r([{ delta, type: 'git-mode-select-file' }])
425
+ if (ctx.state.gitPanel.files.length === 0) return r([])
426
+ return r([{ delta, type: 'git-mode-move-selection' }])
398
427
  }
399
428
  }
400
429
 
430
+ export function selectGitFileOnly(delta: -1 | 1): ActionFn {
431
+ return (ctx: ModeContext) => {
432
+ if (ctx.state.gitPanel.files.length === 0) return r([])
433
+ return r([{ delta, type: 'git-mode-move-file-selection' }])
434
+ }
435
+ }
436
+
437
+ export const toggleSelectedGitFolder: ActionFn = (ctx: ModeContext) => {
438
+ if (!ctx.state.gitMode.selectedEntryKey) return r([])
439
+ return r([{ type: 'git-mode-toggle-selected-folder' }])
440
+ }
441
+
442
+ export const collapseGitSelection: ActionFn = (ctx: ModeContext) => {
443
+ if (!ctx.state.gitMode.selectedEntryKey) return r([])
444
+ return r([{ type: 'git-mode-collapse-selection' }])
445
+ }
446
+
447
+ export const expandGitSelection: ActionFn = (ctx: ModeContext) => {
448
+ if (!ctx.state.gitMode.selectedEntryKey) return r([])
449
+ return r([{ type: 'git-mode-expand-selection' }])
450
+ }
451
+
452
+ export const toggleGitFileListMode: ActionFn = (ctx: ModeContext) => {
453
+ const mode = ctx.state.gitPane.fileListMode === 'tree' ? 'flat' : 'tree'
454
+ return r(
455
+ [{ type: 'git-mode-toggle-file-list-mode' }],
456
+ [{ mode, type: 'persist-git-file-list-mode' }]
457
+ )
458
+ }
459
+
401
460
  export function scrollGitDiff(delta: number): KeyResult {
402
461
  return r([], [{ delta, type: 'scroll-git-diff' }])
403
462
  }
404
463
 
464
+ export const toggleGitDiffView: KeyResult = r([{ type: 'git-mode-toggle-diff-view' }])
465
+
405
466
  export const gitStageSelected: ActionFn = (ctx: ModeContext) => {
406
- const file = ctx.state.gitPanel.files[ctx.state.gitMode.selectedFileIndex]
467
+ const file = selectedGitFile(ctx)
407
468
  if (!file) return r(clearPendingDelete(ctx))
408
469
  const actions = clearPendingDelete(ctx)
409
470
  if (file.section === 'staged') return r(actions)
@@ -417,7 +478,7 @@ export const gitStageSelected: ActionFn = (ctx: ModeContext) => {
417
478
  }
418
479
 
419
480
  export const gitDestructiveSelected: ActionFn = (ctx: ModeContext) => {
420
- const file = ctx.state.gitPanel.files[ctx.state.gitMode.selectedFileIndex]
481
+ const file = selectedGitFile(ctx)
421
482
  if (!file) return r(clearPendingDelete(ctx))
422
483
 
423
484
  if (file.section === 'staged') {
package/src/defaults.ts CHANGED
@@ -37,7 +37,7 @@ export function getDefaultKeymapConfig(): ResolvedKeymapConfig {
37
37
  .map('k', actions.prevTab, 'Prev tab')
38
38
  .map('r', actions.renameTab, 'Rename tab')
39
39
  .map('i', actions.enterInsert, 'Focus terminal')
40
- .map('?', actions.helpModal, 'Help')
40
+ .map('?', actions.helpModal(), 'Help')
41
41
  )
42
42
 
43
43
  // -----------------------------------------------------------------------
@@ -82,17 +82,29 @@ export function getDefaultKeymapConfig(): ResolvedKeymapConfig {
82
82
  // -----------------------------------------------------------------------
83
83
  .mode('git-mode', (m) =>
84
84
  m
85
+ .map('a', actions.gitStageSelected, 'Stage')
86
+ .map('d', actions.gitDestructiveSelected, 'Unstage/delete')
87
+ .map('c', actions.gitCommitOpen, 'Commit')
88
+ .map('p', actions.gitPush, 'Push')
89
+ .map('v', actions.toggleGitDiffView, 'Toggle split/stacked')
90
+ .map('t', actions.toggleGitFileListMode, 'Toggle flat/tree')
91
+ .map('?', actions.helpModal('git-mode'), 'Help')
85
92
  .map('<Esc>', actions.exitGitMode, 'Exit git')
86
- .map('j', actions.selectGitFile(1), 'Next file')
87
- .map('k', actions.selectGitFile(-1), 'Prev file')
93
+ .map('j', actions.selectGitFile(1), 'Next entry')
94
+ .map('k', actions.selectGitFile(-1), 'Prev entry')
95
+ .map('<C-n>', actions.selectGitFileOnly(1), 'Next file')
96
+ .map('<C-p>', actions.selectGitFileOnly(-1), 'Prev file')
97
+ .map('h', actions.toggleSelectedGitFolder, 'Toggle folder')
98
+ .map('l', actions.toggleSelectedGitFolder, 'Toggle folder')
88
99
  .map('<C-d>', actions.scrollGitDiff(20), 'Page down')
100
+ .map('<BS>', actions.resizeGitDiffPane(-0.05), 'File bar narrower')
101
+ .map('<C-h>', actions.resizeGitDiffPane(-0.05), 'File bar narrower')
102
+ .map('<C-l>', actions.resizeGitDiffPane(0.05), 'File bar wider')
89
103
  .map('<C-u>', actions.scrollGitDiff(-20), 'Page up')
104
+ .map('<Left>', actions.collapseGitSelection, 'Collapse folder')
105
+ .map('<Right>', actions.expandGitSelection, 'Expand folder')
90
106
  .map('<Down>', actions.scrollGitDiff(1), 'Scroll down')
91
107
  .map('<Up>', actions.scrollGitDiff(-1), 'Scroll up')
92
- .map('a', actions.gitStageSelected, 'Stage')
93
- .map('d', actions.gitDestructiveSelected, 'Unstage/delete')
94
- .map('c', actions.gitCommitOpen, 'Commit')
95
- .map('p', actions.gitPush, 'Push')
96
108
  )
97
109
 
98
110
  // -----------------------------------------------------------------------
@@ -100,7 +112,7 @@ export function getDefaultKeymapConfig(): ResolvedKeymapConfig {
100
112
  // -----------------------------------------------------------------------
101
113
  .mode('modal.help', (m) =>
102
114
  m
103
- .map('<Esc>', actions.closeModal, 'Close')
115
+ .map('<Esc>', actions.closeOverlayModal, 'Close')
104
116
  .map('j', actions.moveModalSelection(1), 'Next')
105
117
  .map('k', actions.moveModalSelection(-1), 'Prev')
106
118
  .map('<Down>', actions.moveModalSelection(1))
@@ -136,6 +148,21 @@ export function getDefaultKeymapConfig(): ResolvedKeymapConfig {
136
148
  .map('<C-n>', actions.previewTheme(1))
137
149
  .map('<C-p>', actions.previewTheme(-1))
138
150
  .map('<CR>', actions.confirmTheme, 'Confirm')
151
+ .map('/', actions.beginThemeFilter, 'Filter')
152
+ )
153
+
154
+ // -----------------------------------------------------------------------
155
+ // Modal: theme-picker filtering
156
+ // -----------------------------------------------------------------------
157
+ .mode('modal.theme-picker.filtering', (m) =>
158
+ m
159
+ .map('<Esc>', actions.cancelCommandEdit('modal.theme-picker'), 'Cancel')
160
+ .map('<C-n>', actions.previewTheme(1), 'Next')
161
+ .map('<C-p>', actions.previewTheme(-1), 'Prev')
162
+ .map('<Down>', actions.previewTheme(1))
163
+ .map('<Up>', actions.previewTheme(-1))
164
+ .map('<CR>', actions.confirmTheme, 'Confirm')
165
+ .passthrough()
139
166
  )
140
167
 
141
168
  // -----------------------------------------------------------------------
@@ -0,0 +1,313 @@
1
+ // Hand-curated aimux house themes, full Shiki theme shape. Colors follow the
2
+ // VSCode workbench color key namespace; `settings` is a TextMate token rule
3
+ // array shared by the in-repo diff highlighter and `shiki.loadTheme`.
4
+ /* eslint-disable perfectionist/sort-objects */
5
+
6
+ import type { Theme, ThemeColorMap } from './types'
7
+
8
+ // --- aimux --------------------------------------------------------------
9
+ //
10
+ // Teal accents on a deep blue-black background. Designed to look at home
11
+ // inside the aimux chrome.
12
+ const AIMUX_BG = '#11151b'
13
+ const AIMUX_FG = '#edf4ff'
14
+
15
+ const AIMUX_COLORS: ThemeColorMap = {
16
+ 'contrastBorder': '#3a4c60',
17
+ 'descriptionForeground': '#6b829a',
18
+ 'diffEditor.insertedLineBackground': '#1e3d2b',
19
+ 'diffEditor.removedLineBackground': '#3b1e27',
20
+ 'editor.background': AIMUX_BG,
21
+ 'editor.foreground': AIMUX_FG,
22
+ 'editor.lineHighlightBackground': '#1a2330',
23
+ 'editor.selectionBackground': '#1f3344',
24
+ 'editorCursor.foreground': '#7cd1b8',
25
+ 'editorError.foreground': '#f38ba8',
26
+ 'editorGroup.border': '#2d3f52',
27
+ 'editorGroupHeader.tabsBackground': '#16202b',
28
+ 'editorLineNumber.foreground': '#3e506a',
29
+ 'editorWarning.foreground': '#f6c177',
30
+ 'editorWidget.background': '#0b1016',
31
+ 'errorForeground': '#f38ba8',
32
+ 'focusBorder': '#7cd1b8',
33
+ 'foreground': AIMUX_FG,
34
+ 'gitDecoration.addedResourceForeground': '#8bd5ca',
35
+ 'gitDecoration.deletedResourceForeground': '#f38ba8',
36
+ 'gitDecoration.modifiedResourceForeground': '#f6c177',
37
+ 'gitDecoration.untrackedResourceForeground': '#8bd5ca',
38
+ 'input.background': '#1c2734',
39
+ 'input.border': '#2d3f52',
40
+ 'input.foreground': AIMUX_FG,
41
+ 'list.activeSelectionBackground': '#1f3344',
42
+ 'list.activeSelectionForeground': AIMUX_FG,
43
+ 'list.hoverBackground': '#1a2330',
44
+ 'panel.background': '#16202b',
45
+ 'panel.border': '#2d3f52',
46
+ 'sideBar.background': '#16202b',
47
+ 'sideBar.foreground': AIMUX_FG,
48
+ 'sideBarSectionHeader.background': '#1c2734',
49
+ 'sideBarSectionHeader.foreground': '#b8c5d6',
50
+ 'terminal.ansiBlue': '#7cb3ff',
51
+ 'terminal.ansiCyan': '#7cd1b8',
52
+ 'terminal.ansiGreen': '#8bd5ca',
53
+ 'terminal.ansiMagenta': '#c4a7e7',
54
+ 'terminal.ansiRed': '#f38ba8',
55
+ 'terminal.ansiYellow': '#f6c177',
56
+ 'textLink.activeForeground': '#7cd1b8',
57
+ 'textLink.foreground': '#7cd1b8',
58
+ }
59
+
60
+ // --- dracula-at-night --------------------------------------------------
61
+ const DAN_BG = '#0e1419'
62
+ const DAN_FG = '#f8f8f2'
63
+
64
+ const DAN_COLORS: ThemeColorMap = {
65
+ 'contrastBorder': '#44475a',
66
+ 'descriptionForeground': '#6272a4',
67
+ 'diffEditor.insertedLineBackground': '#162b1d',
68
+ 'diffEditor.removedLineBackground': '#2a1820',
69
+ 'editor.background': DAN_BG,
70
+ 'editor.foreground': DAN_FG,
71
+ 'editor.lineHighlightBackground': '#1a2129',
72
+ 'editor.selectionBackground': '#222a33',
73
+ 'editorCursor.foreground': '#f8f8f0',
74
+ 'editorError.foreground': '#ff5555',
75
+ 'editorGroup.border': '#2a3440',
76
+ 'editorGroupHeader.tabsBackground': '#131920',
77
+ 'editorLineNumber.foreground': '#495466',
78
+ 'editorWarning.foreground': '#f1fa8c',
79
+ 'editorWidget.background': '#090d11',
80
+ 'errorForeground': '#ff5555',
81
+ 'focusBorder': '#bd93f9',
82
+ 'foreground': DAN_FG,
83
+ 'gitDecoration.addedResourceForeground': '#50fa7b',
84
+ 'gitDecoration.deletedResourceForeground': '#ff5555',
85
+ 'gitDecoration.modifiedResourceForeground': '#f1fa8c',
86
+ 'gitDecoration.untrackedResourceForeground': '#50fa7b',
87
+ 'input.background': '#1a2129',
88
+ 'input.border': '#2a3440',
89
+ 'input.foreground': DAN_FG,
90
+ 'list.activeSelectionBackground': '#222a33',
91
+ 'list.activeSelectionForeground': DAN_FG,
92
+ 'list.hoverBackground': '#1a2129',
93
+ 'panel.background': '#131920',
94
+ 'panel.border': '#2a3440',
95
+ 'sideBar.background': '#131920',
96
+ 'sideBar.foreground': DAN_FG,
97
+ 'sideBarSectionHeader.background': '#1a2129',
98
+ 'sideBarSectionHeader.foreground': '#bdc3cf',
99
+ 'terminal.ansiBlue': '#6272a4',
100
+ 'terminal.ansiCyan': '#8be9fd',
101
+ 'terminal.ansiGreen': '#50fa7b',
102
+ 'terminal.ansiMagenta': '#ff79c6',
103
+ 'terminal.ansiRed': '#ff5555',
104
+ 'terminal.ansiYellow': '#f1fa8c',
105
+ 'textLink.activeForeground': '#ff79c6',
106
+ 'textLink.foreground': '#bd93f9',
107
+ }
108
+
109
+ // --- Shared TextMate rule helpers --------------------------------------
110
+
111
+ const AIMUX_SETTINGS = [
112
+ { settings: { background: AIMUX_BG, foreground: AIMUX_FG } },
113
+ {
114
+ scope: ['comment', 'punctuation.definition.comment'],
115
+ settings: { fontStyle: 'italic', foreground: '#6b829a' },
116
+ },
117
+ { scope: ['comment.documentation'], settings: { foreground: '#8fa6bf', fontStyle: 'italic' } },
118
+ { scope: ['string', 'string.quoted'], settings: { foreground: '#f6c177' } },
119
+ { scope: ['string.template'], settings: { foreground: '#f6c177' } },
120
+ {
121
+ scope: ['string.regexp', 'string.escape', 'constant.character.escape'],
122
+ settings: { foreground: '#c4a7e7' },
123
+ },
124
+ {
125
+ scope: ['constant.numeric', 'constant.language', 'constant.language.boolean'],
126
+ settings: { foreground: '#f38ba8' },
127
+ },
128
+ { scope: ['constant.character', 'constant.other'], settings: { foreground: '#f38ba8' } },
129
+ {
130
+ scope: ['keyword', 'keyword.control', 'keyword.operator.new', 'keyword.other'],
131
+ settings: { fontStyle: 'bold', foreground: '#c4a7e7' },
132
+ },
133
+ {
134
+ scope: ['storage', 'storage.type', 'storage.modifier'],
135
+ settings: { fontStyle: 'bold', foreground: '#c4a7e7' },
136
+ },
137
+ {
138
+ scope: ['keyword.operator', 'punctuation', 'meta.brace', 'punctuation.separator'],
139
+ settings: { foreground: '#6b829a' },
140
+ },
141
+ {
142
+ scope: [
143
+ 'entity.name.function',
144
+ 'support.function',
145
+ 'meta.function-call',
146
+ 'entity.name.function.member',
147
+ ],
148
+ settings: { foreground: '#8bd5ca' },
149
+ },
150
+ {
151
+ scope: [
152
+ 'entity.name.type',
153
+ 'support.type',
154
+ 'support.class',
155
+ 'entity.name.class',
156
+ 'entity.name.interface',
157
+ 'entity.name.namespace',
158
+ ],
159
+ settings: { fontStyle: 'italic', foreground: '#7cd1b8' },
160
+ },
161
+ {
162
+ scope: ['entity.name.type.enum', 'entity.name.type.alias'],
163
+ settings: { foreground: '#7cd1b8' },
164
+ },
165
+ { scope: ['variable', 'meta.variable'], settings: { foreground: AIMUX_FG } },
166
+ {
167
+ scope: ['variable.parameter', 'meta.function.parameters'],
168
+ settings: { fontStyle: 'italic', foreground: AIMUX_FG },
169
+ },
170
+ {
171
+ scope: ['variable.other.property', 'variable.other.member', 'meta.object-literal.key'],
172
+ settings: { foreground: '#7cd1b8' },
173
+ },
174
+ {
175
+ scope: ['variable.language', 'variable.language.this'],
176
+ settings: { foreground: '#f38ba8', fontStyle: 'italic' },
177
+ },
178
+ { scope: ['entity.name.tag', 'meta.tag'], settings: { foreground: '#f38ba8' } },
179
+ {
180
+ scope: ['entity.other.attribute-name'],
181
+ settings: { fontStyle: 'italic', foreground: '#f6c177' },
182
+ },
183
+ { scope: ['support.constant'], settings: { foreground: '#f38ba8' } },
184
+ { scope: ['support.variable'], settings: { foreground: AIMUX_FG } },
185
+ // Markdown
186
+ { scope: ['markup.heading'], settings: { fontStyle: 'bold', foreground: '#7cd1b8' } },
187
+ { scope: ['markup.bold'], settings: { fontStyle: 'bold', foreground: AIMUX_FG } },
188
+ { scope: ['markup.italic'], settings: { fontStyle: 'italic', foreground: AIMUX_FG } },
189
+ { scope: ['markup.underline.link', 'markup.inline.raw'], settings: { foreground: '#8bd5ca' } },
190
+ { scope: ['markup.list'], settings: { foreground: '#c4a7e7' } },
191
+ { scope: ['markup.quote'], settings: { foreground: '#6b829a', fontStyle: 'italic' } },
192
+ { scope: ['markup.raw'], settings: { foreground: '#f6c177' } },
193
+ // JSX / TSX
194
+ {
195
+ scope: ['entity.name.tag.jsx', 'support.class.component'],
196
+ settings: { foreground: '#7cd1b8' },
197
+ },
198
+ { scope: ['meta.jsx.children'], settings: { foreground: AIMUX_FG } },
199
+ // Diff
200
+ { scope: ['markup.inserted', 'meta.diff.header.to-file'], settings: { foreground: '#8bd5ca' } },
201
+ { scope: ['markup.deleted', 'meta.diff.header.from-file'], settings: { foreground: '#f38ba8' } },
202
+ { scope: ['markup.changed'], settings: { foreground: '#f6c177' } },
203
+ { scope: ['meta.diff.range'], settings: { foreground: '#c4a7e7' } },
204
+ ]
205
+
206
+ const DAN_SETTINGS = [
207
+ { settings: { background: DAN_BG, foreground: DAN_FG } },
208
+ {
209
+ scope: ['comment', 'punctuation.definition.comment'],
210
+ settings: { fontStyle: 'italic', foreground: '#6272a4' },
211
+ },
212
+ { scope: ['comment.documentation'], settings: { fontStyle: 'italic', foreground: '#8a96b4' } },
213
+ { scope: ['string', 'string.quoted'], settings: { foreground: '#f1fa8c' } },
214
+ { scope: ['string.template'], settings: { foreground: '#f1fa8c' } },
215
+ {
216
+ scope: ['string.regexp', 'string.escape', 'constant.character.escape'],
217
+ settings: { foreground: '#ff79c6' },
218
+ },
219
+ {
220
+ scope: ['constant.numeric', 'constant.language', 'constant.language.boolean'],
221
+ settings: { foreground: '#bd93f9' },
222
+ },
223
+ { scope: ['constant.character', 'constant.other'], settings: { foreground: '#bd93f9' } },
224
+ {
225
+ scope: ['keyword', 'keyword.control', 'keyword.other'],
226
+ settings: { fontStyle: 'bold', foreground: '#ff79c6' },
227
+ },
228
+ {
229
+ scope: ['storage', 'storage.type', 'storage.modifier'],
230
+ settings: { fontStyle: 'bold italic', foreground: '#ff79c6' },
231
+ },
232
+ {
233
+ scope: ['keyword.operator', 'punctuation', 'meta.brace', 'punctuation.separator'],
234
+ settings: { foreground: '#f8f8f2' },
235
+ },
236
+ {
237
+ scope: ['entity.name.function', 'support.function', 'meta.function-call'],
238
+ settings: { foreground: '#50fa7b' },
239
+ },
240
+ {
241
+ scope: [
242
+ 'entity.name.type',
243
+ 'support.type',
244
+ 'support.class',
245
+ 'entity.name.class',
246
+ 'entity.name.interface',
247
+ ],
248
+ settings: { fontStyle: 'italic', foreground: '#8be9fd' },
249
+ },
250
+ {
251
+ scope: ['entity.name.type.enum', 'entity.name.type.alias'],
252
+ settings: { foreground: '#8be9fd' },
253
+ },
254
+ { scope: ['variable', 'meta.variable'], settings: { foreground: DAN_FG } },
255
+ {
256
+ scope: ['variable.parameter', 'meta.function.parameters'],
257
+ settings: { fontStyle: 'italic', foreground: '#ffb86c' },
258
+ },
259
+ {
260
+ scope: ['variable.other.property', 'variable.other.member', 'meta.object-literal.key'],
261
+ settings: { foreground: '#8be9fd' },
262
+ },
263
+ {
264
+ scope: ['variable.language', 'variable.language.this'],
265
+ settings: { foreground: '#bd93f9', fontStyle: 'italic' },
266
+ },
267
+ { scope: ['entity.name.tag', 'meta.tag'], settings: { foreground: '#ff79c6' } },
268
+ {
269
+ scope: ['entity.other.attribute-name'],
270
+ settings: { fontStyle: 'italic', foreground: '#50fa7b' },
271
+ },
272
+ { scope: ['support.constant'], settings: { foreground: '#bd93f9' } },
273
+ // Markdown
274
+ { scope: ['markup.heading'], settings: { fontStyle: 'bold', foreground: '#bd93f9' } },
275
+ { scope: ['markup.bold'], settings: { fontStyle: 'bold', foreground: '#ffb86c' } },
276
+ { scope: ['markup.italic'], settings: { fontStyle: 'italic', foreground: '#f1fa8c' } },
277
+ { scope: ['markup.underline.link', 'markup.inline.raw'], settings: { foreground: '#8be9fd' } },
278
+ { scope: ['markup.list'], settings: { foreground: '#ff79c6' } },
279
+ { scope: ['markup.quote'], settings: { foreground: '#6272a4', fontStyle: 'italic' } },
280
+ { scope: ['markup.raw'], settings: { foreground: '#f1fa8c' } },
281
+ // JSX / TSX
282
+ {
283
+ scope: ['entity.name.tag.jsx', 'support.class.component'],
284
+ settings: { foreground: '#8be9fd' },
285
+ },
286
+ // Diff
287
+ { scope: ['markup.inserted'], settings: { foreground: '#50fa7b' } },
288
+ { scope: ['markup.deleted'], settings: { foreground: '#ff5555' } },
289
+ { scope: ['markup.changed'], settings: { foreground: '#f1fa8c' } },
290
+ ]
291
+
292
+ export const HOUSE_THEMES: Record<string, Theme> = {
293
+ 'aimux': {
294
+ bg: AIMUX_BG,
295
+ colors: AIMUX_COLORS,
296
+ displayName: 'Aimux',
297
+ fg: AIMUX_FG,
298
+ name: 'aimux',
299
+ settings: AIMUX_SETTINGS,
300
+ type: 'dark',
301
+ },
302
+ 'dracula-at-night': {
303
+ bg: DAN_BG,
304
+ colors: DAN_COLORS,
305
+ displayName: 'Dracula At Night',
306
+ fg: DAN_FG,
307
+ name: 'dracula-at-night',
308
+ settings: DAN_SETTINGS,
309
+ type: 'dark',
310
+ },
311
+ }
312
+
313
+ export const HOUSE_THEME_IDS: string[] = Object.keys(HOUSE_THEMES)
package/src/index.ts CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  export { defineConfig } from './define-config'
4
4
  export * as actions from './actions'
5
- export { THEME_IDS, themes, THEMES } from './themes'
5
+ export { migrateThemeId, THEME_IDS, themes, THEMES } from './themes'
6
6
  export { GroupBuilder, KeymapBuilder, ModeBindingBuilder } from './keymap-builder'
7
7
  export { getDefaultKeymapConfig } from './defaults'
8
8
  export { resolveConfig } from './resolver'
@@ -12,6 +12,7 @@ export type {
12
12
  // Action types
13
13
  Action,
14
14
  ActionFn,
15
+ AimuxColorKey,
15
16
  // User-facing config
16
17
  AimuxUserConfig,
17
18
  AppAction,
@@ -19,6 +20,7 @@ export type {
19
20
  BackendConfig,
20
21
  BindingDef,
21
22
  FocusMode,
23
+ GitFileListMode,
22
24
  GitPaneConfig,
23
25
  GitPaneDiffCountConfig,
24
26
  GitPaneEmbeddedConfig,
@@ -39,6 +41,8 @@ export type {
39
41
  // Mode / state
40
42
  ModeId,
41
43
  ModeKeymapDef,
44
+ NamedTheme,
45
+ NamedThemeDefinition,
42
46
  // Resolved config (internal, but exported for tooling)
43
47
  ResolvedConfig,
44
48
  ResolvedKeymapConfig,
@@ -49,8 +53,11 @@ export type {
49
53
  SnippetRecord,
50
54
  SplitDirection,
51
55
  TabSession,
52
- // Themes
53
- ThemeColors,
56
+ Theme,
57
+ ThemeColorMap,
54
58
  ThemeDefinition,
55
59
  ThemeId,
60
+ ThemeSettings,
61
+ ThemeTokenRule,
56
62
  } from './types'
63
+ export { AIMUX_COLOR_KEYS } from './types'