feat(desktop): theme the terminal ANSI palette + restyle the Cmd-K / Ctrl-Tab HUDs
Imported VS Code themes now carry their integrated-terminal ANSI palette (`terminal.ansi*`), keyed to the painted variant (terminal / darkTerminal). The terminal adopts it when the full base-8 set is present and keeps its VS Code defaults otherwise; withSurface still owns the background, so the pane stays translucent. Pull the command palette and session switcher into a shared top-center HUD (`floating-hud.ts`): no dim/blur backdrop, one compact text + item-padding size, sidebar-label-style section headers (brand-tinted, uppercase), and the themed portal scrollbar.
This commit is contained in:
@@ -8,6 +8,21 @@ import { buildThemeFromMarketplace } from './install'
|
||||
const themeJson = (type: 'light' | 'dark', background: string, foreground: string) =>
|
||||
JSON.stringify({ type, colors: { 'editor.background': background, 'editor.foreground': foreground } })
|
||||
|
||||
// A full base-8 ANSI set keyed off `red` so each variant is distinguishable.
|
||||
const ansiColors = (red: string) => ({
|
||||
'terminal.ansiBlack': '#000000',
|
||||
'terminal.ansiRed': red,
|
||||
'terminal.ansiGreen': '#00aa00',
|
||||
'terminal.ansiYellow': '#aaaa00',
|
||||
'terminal.ansiBlue': '#0000aa',
|
||||
'terminal.ansiMagenta': '#aa00aa',
|
||||
'terminal.ansiCyan': '#00aaaa',
|
||||
'terminal.ansiWhite': '#aaaaaa'
|
||||
})
|
||||
|
||||
const themeJsonWithAnsi = (type: 'light' | 'dark', background: string, foreground: string, red: string) =>
|
||||
JSON.stringify({ type, colors: { 'editor.background': background, 'editor.foreground': foreground, ...ansiColors(red) } })
|
||||
|
||||
describe('buildThemeFromMarketplace', () => {
|
||||
it('folds a light + dark variant into one family with both slots', () => {
|
||||
const result: DesktopMarketplaceThemeResult = {
|
||||
@@ -57,6 +72,45 @@ describe('buildThemeFromMarketplace', () => {
|
||||
expect(theme.darkColors).toBe(theme.colors)
|
||||
})
|
||||
|
||||
it('keys each variant terminal palette to its mode (terminal / darkTerminal)', () => {
|
||||
const result: DesktopMarketplaceThemeResult = {
|
||||
extensionId: 'ryanolsonx.solarized',
|
||||
displayName: 'Solarized',
|
||||
themes: [
|
||||
{ label: 'Solarized Light', uiTheme: 'vs', contents: themeJsonWithAnsi('light', '#fdf6e3', '#586e75', '#dc322f') },
|
||||
{ label: 'Solarized Dark', uiTheme: 'vs-dark', contents: themeJsonWithAnsi('dark', '#002b36', '#93a1a1', '#ff5f56') }
|
||||
]
|
||||
}
|
||||
|
||||
const theme = buildThemeFromMarketplace(result)
|
||||
expect(theme.terminal?.red).toBe('#dc322f')
|
||||
expect(theme.darkTerminal?.red).toBe('#ff5f56')
|
||||
})
|
||||
|
||||
it('reuses the sole variant terminal palette for both modes', () => {
|
||||
const result: DesktopMarketplaceThemeResult = {
|
||||
extensionId: 'dracula-theme.theme-dracula',
|
||||
displayName: 'Dracula',
|
||||
themes: [{ label: 'Dracula', uiTheme: 'vs-dark', contents: themeJsonWithAnsi('dark', '#282a36', '#f8f8f2', '#ff5555') }]
|
||||
}
|
||||
|
||||
const theme = buildThemeFromMarketplace(result)
|
||||
expect(theme.terminal?.red).toBe('#ff5555')
|
||||
expect(theme.darkTerminal?.red).toBe('#ff5555')
|
||||
})
|
||||
|
||||
it('leaves terminal slots unset when no variant ships an ANSI palette', () => {
|
||||
const result: DesktopMarketplaceThemeResult = {
|
||||
extensionId: 'x.plain',
|
||||
displayName: 'Plain',
|
||||
themes: [{ label: 'Plain', uiTheme: 'vs-dark', contents: themeJson('dark', '#101010', '#fafafa') }]
|
||||
}
|
||||
|
||||
const theme = buildThemeFromMarketplace(result)
|
||||
expect(theme.terminal).toBeUndefined()
|
||||
expect(theme.darkTerminal).toBeUndefined()
|
||||
})
|
||||
|
||||
it('throws when the extension contributes no themes', () => {
|
||||
expect(() =>
|
||||
buildThemeFromMarketplace({ extensionId: 'x.y', displayName: 'X', themes: [] })
|
||||
|
||||
@@ -110,4 +110,62 @@ describe('convertVscodeColorTheme', () => {
|
||||
it('throws when there is no colors map', () => {
|
||||
expect(() => convertVscodeColorTheme({ name: 'Empty' })).toThrow(/colors/)
|
||||
})
|
||||
|
||||
const fullAnsi = {
|
||||
'terminal.ansiBlack': '#073642',
|
||||
'terminal.ansiRed': '#dc322f',
|
||||
'terminal.ansiGreen': '#859900',
|
||||
'terminal.ansiYellow': '#b58900',
|
||||
'terminal.ansiBlue': '#268bd2',
|
||||
'terminal.ansiMagenta': '#d33682',
|
||||
'terminal.ansiCyan': '#2aa198',
|
||||
'terminal.ansiWhite': '#eee8d5',
|
||||
'terminal.ansiBrightBlack': '#002b36',
|
||||
'terminal.ansiBrightRed': '#cb4b16',
|
||||
'terminal.ansiBrightGreen': '#586e75',
|
||||
'terminal.ansiBrightYellow': '#657b83',
|
||||
'terminal.ansiBrightBlue': '#839496',
|
||||
'terminal.ansiBrightMagenta': '#6c71c4',
|
||||
'terminal.ansiBrightCyan': '#93a1a1',
|
||||
'terminal.ansiBrightWhite': '#fdf6e3'
|
||||
}
|
||||
|
||||
it('lifts the ANSI palette when the full base-8 set is present', () => {
|
||||
const { theme } = convertVscodeColorTheme({
|
||||
name: 'Solarized Dark',
|
||||
type: 'dark',
|
||||
colors: {
|
||||
'editor.background': '#002b36',
|
||||
'editor.foreground': '#93a1a1',
|
||||
'terminal.foreground': '#839496',
|
||||
'terminalCursor.foreground': '#93a1a1',
|
||||
// Alpha selection must survive un-flattened — xterm blends it.
|
||||
'terminal.selectionBackground': '#073642aa',
|
||||
...fullAnsi
|
||||
}
|
||||
})
|
||||
|
||||
expect(theme.terminal?.red).toBe('#dc322f')
|
||||
expect(theme.terminal?.brightWhite).toBe('#fdf6e3')
|
||||
expect(theme.terminal?.foreground).toBe('#839496')
|
||||
expect(theme.terminal?.cursor).toBe('#93a1a1')
|
||||
expect(theme.terminal?.selectionBackground).toBe('#073642aa')
|
||||
// No background slot — the pane keeps the live surface (transparency).
|
||||
expect('background' in (theme.terminal ?? {})).toBe(false)
|
||||
})
|
||||
|
||||
it('keeps the default palette (no terminal slot) when the ANSI set is partial', () => {
|
||||
const { theme } = convertVscodeColorTheme({
|
||||
name: 'Half',
|
||||
type: 'dark',
|
||||
colors: {
|
||||
'editor.background': '#101010',
|
||||
'editor.foreground': '#fafafa',
|
||||
'terminal.ansiRed': '#ff0000',
|
||||
'terminal.ansiGreen': '#00ff00'
|
||||
}
|
||||
})
|
||||
|
||||
expect(theme.terminal).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user