mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-12 21:03:05 -07:00
feat(ui): add Tokyo Night theme (#24054)
Co-authored-by: Gal Zahavi <38544478+galz10@users.noreply.github.com>
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
@@ -19,6 +19,7 @@ using the `/theme` command within Gemini CLI:
|
|||||||
- `Holiday`
|
- `Holiday`
|
||||||
- `Shades Of Purple`
|
- `Shades Of Purple`
|
||||||
- `Solarized Dark`
|
- `Solarized Dark`
|
||||||
|
- `Tokyo Night`
|
||||||
- **Light themes:**
|
- **Light themes:**
|
||||||
- `ANSI Light`
|
- `ANSI Light`
|
||||||
- `Ayu Light`
|
- `Ayu Light`
|
||||||
@@ -252,6 +253,10 @@ identify their source, for example: `shades-of-green (green-extension)`.
|
|||||||
|
|
||||||
<img src="/docs/assets/theme-solarized-dark.png" alt="Solarized Dark theme" width="600">
|
<img src="/docs/assets/theme-solarized-dark.png" alt="Solarized Dark theme" width="600">
|
||||||
|
|
||||||
|
### Tokyo Night
|
||||||
|
|
||||||
|
<img src="/docs/assets/theme-tokyonight-dark.png" alt="Tokyo Night theme" width="600">
|
||||||
|
|
||||||
## Light themes
|
## Light themes
|
||||||
|
|
||||||
### ANSI Light
|
### ANSI Light
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ import {
|
|||||||
} from '../hooks/useConfirmingTool.js';
|
} from '../hooks/useConfirmingTool.js';
|
||||||
|
|
||||||
// Mock dependencies
|
// Mock dependencies
|
||||||
|
vi.mock('ink-spinner', () => ({
|
||||||
|
default: () => <Text>⠋</Text>,
|
||||||
|
}));
|
||||||
|
|
||||||
const mockUseSettings = vi.fn().mockReturnValue({
|
const mockUseSettings = vi.fn().mockReturnValue({
|
||||||
merged: {
|
merged: {
|
||||||
ui: {
|
ui: {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ exports[`MainContent > MainContent Tool Output Height Logic > 'ASB mode - Focuse
|
|||||||
"ScrollableList
|
"ScrollableList
|
||||||
AppHeader(full)
|
AppHeader(full)
|
||||||
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||||
│ ⊶ Shell Command Running a long command... │
|
│ ⠋ Shell Command Running a long command... │
|
||||||
│ │
|
│ │
|
||||||
│ Line 11 │
|
│ Line 11 │
|
||||||
│ Line 12 │
|
│ Line 12 │
|
||||||
@@ -24,7 +24,7 @@ exports[`MainContent > MainContent Tool Output Height Logic > 'ASB mode - Unfocu
|
|||||||
"ScrollableList
|
"ScrollableList
|
||||||
AppHeader(full)
|
AppHeader(full)
|
||||||
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||||
│ ⊶ Shell Command Running a long command... │
|
│ ⠋ Shell Command Running a long command... │
|
||||||
│ │
|
│ │
|
||||||
│ Line 11 │
|
│ Line 11 │
|
||||||
│ Line 12 │
|
│ Line 12 │
|
||||||
@@ -43,7 +43,7 @@ AppHeader(full)
|
|||||||
exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Constrained height' 1`] = `
|
exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Constrained height' 1`] = `
|
||||||
"AppHeader(full)
|
"AppHeader(full)
|
||||||
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||||
│ ⊶ Shell Command Running a long command... │
|
│ ⠋ Shell Command Running a long command... │
|
||||||
│ │
|
│ │
|
||||||
│ ... first 11 lines hidden (Ctrl+O to show) ... │
|
│ ... first 11 lines hidden (Ctrl+O to show) ... │
|
||||||
│ Line 12 │
|
│ Line 12 │
|
||||||
@@ -62,7 +62,7 @@ exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Con
|
|||||||
exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Unconstrained height' 1`] = `
|
exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Unconstrained height' 1`] = `
|
||||||
"AppHeader(full)
|
"AppHeader(full)
|
||||||
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
╭──────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||||
│ ⊶ Shell Command Running a long command... │
|
│ ⠋ Shell Command Running a long command... │
|
||||||
│ │
|
│ │
|
||||||
│ Line 1 │
|
│ Line 1 │
|
||||||
│ Line 2 │
|
│ Line 2 │
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ exports[`Initial Theme Selection > should default to a dark theme when terminal
|
|||||||
│ 7. Holiday Dark │ 6 return a │ │
|
│ 7. Holiday Dark │ 6 return a │ │
|
||||||
│ 8. Shades Of Purple Dark │ │ │
|
│ 8. Shades Of Purple Dark │ │ │
|
||||||
│ 9. Solarized Dark │ 1 - print("Hello, " + name) │ │
|
│ 9. Solarized Dark │ 1 - print("Hello, " + name) │ │
|
||||||
│ 10. ANSI Light │ 1 + print(f"Hello, {name}!") │ │
|
│ 10. Tokyo Night Dark │ 1 + print(f"Hello, {name}!") │ │
|
||||||
│ 11. Ayu Light │ │ │
|
│ 11. ANSI Light │ │ │
|
||||||
│ 12. Default Light └─────────────────────────────────────────────────┘ │
|
│ 12. Ayu Light └─────────────────────────────────────────────────┘ │
|
||||||
│ ▼ │
|
│ ▼ │
|
||||||
│ │
|
│ │
|
||||||
│ (Use Enter to select, Tab to configure scope, Esc to close) │
|
│ (Use Enter to select, Tab to configure scope, Esc to close) │
|
||||||
@@ -64,9 +64,9 @@ exports[`Initial Theme Selection > should use the theme from settings even if te
|
|||||||
│ 7. Holiday Dark │ 6 return a │ │
|
│ 7. Holiday Dark │ 6 return a │ │
|
||||||
│ 8. Shades Of Purple Dark │ │ │
|
│ 8. Shades Of Purple Dark │ │ │
|
||||||
│ 9. Solarized Dark │ 1 - print("Hello, " + name) │ │
|
│ 9. Solarized Dark │ 1 - print("Hello, " + name) │ │
|
||||||
│ 10. ANSI Light │ 1 + print(f"Hello, {name}!") │ │
|
│ 10. Tokyo Night Dark │ 1 + print(f"Hello, {name}!") │ │
|
||||||
│ 11. Ayu Light │ │ │
|
│ 11. ANSI Light │ │ │
|
||||||
│ 12. Default Light └─────────────────────────────────────────────────┘ │
|
│ 12. Ayu Light └─────────────────────────────────────────────────┘ │
|
||||||
│ ▼ │
|
│ ▼ │
|
||||||
│ │
|
│ │
|
||||||
│ (Use Enter to select, Tab to configure scope, Esc to close) │
|
│ (Use Enter to select, Tab to configure scope, Esc to close) │
|
||||||
@@ -103,9 +103,9 @@ exports[`ThemeDialog Snapshots > should render correctly in theme selection mode
|
|||||||
│ 7. Holiday Dark │ 6 return a │ │
|
│ 7. Holiday Dark │ 6 return a │ │
|
||||||
│ 8. Shades Of Purple Dark │ │ │
|
│ 8. Shades Of Purple Dark │ │ │
|
||||||
│ 9. Solarized Dark │ 1 - print("Hello, " + name) │ │
|
│ 9. Solarized Dark │ 1 - print("Hello, " + name) │ │
|
||||||
│ 10. ANSI Light │ 1 + print(f"Hello, {name}!") │ │
|
│ 10. Tokyo Night Dark │ 1 + print(f"Hello, {name}!") │ │
|
||||||
│ 11. Ayu Light │ │ │
|
│ 11. ANSI Light │ │ │
|
||||||
│ 12. Default Light └─────────────────────────────────────────────────┘ │
|
│ 12. Ayu Light └─────────────────────────────────────────────────┘ │
|
||||||
│ ▼ │
|
│ ▼ │
|
||||||
│ │
|
│ │
|
||||||
│ (Use Enter to select, Tab to configure scope, Esc to close) │
|
│ (Use Enter to select, Tab to configure scope, Esc to close) │
|
||||||
@@ -128,9 +128,9 @@ exports[`ThemeDialog Snapshots > should render correctly in theme selection mode
|
|||||||
│ 7. Holiday Dark │ 6 return a │ │
|
│ 7. Holiday Dark │ 6 return a │ │
|
||||||
│ 8. Shades Of Purple Dark │ │ │
|
│ 8. Shades Of Purple Dark │ │ │
|
||||||
│ 9. Solarized Dark │ 1 - print("Hello, " + name) │ │
|
│ 9. Solarized Dark │ 1 - print("Hello, " + name) │ │
|
||||||
│ 10. ANSI Light │ 1 + print(f"Hello, {name}!") │ │
|
│ 10. Tokyo Night Dark │ 1 + print(f"Hello, {name}!") │ │
|
||||||
│ 11. Ayu Light │ │ │
|
│ 11. ANSI Light │ │ │
|
||||||
│ 12. Default Light └─────────────────────────────────────────────────┘ │
|
│ 12. Ayu Light └─────────────────────────────────────────────────┘ │
|
||||||
│ ▼ │
|
│ ▼ │
|
||||||
│ ╭─────────────────────────────────────────────────╮ │
|
│ ╭─────────────────────────────────────────────────╮ │
|
||||||
│ │ DEVELOPER TOOLS (Not visible to users) │ │
|
│ │ DEVELOPER TOOLS (Not visible to users) │ │
|
||||||
|
|||||||
@@ -0,0 +1,155 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2026 Google LLC
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { type ColorsTheme, Theme } from '../../theme.js';
|
||||||
|
import { interpolateColor } from '../../color-utils.js';
|
||||||
|
|
||||||
|
const palette = {
|
||||||
|
bg: '#1a1b26',
|
||||||
|
bg_dark: '#16161e',
|
||||||
|
bg_dark1: '#0C0E14',
|
||||||
|
bg_highlight: '#292e42',
|
||||||
|
blue: '#7aa2f7',
|
||||||
|
blue0: '#3d59a1',
|
||||||
|
blue1: '#2ac3de',
|
||||||
|
blue2: '#0db9d7',
|
||||||
|
blue5: '#89ddff',
|
||||||
|
blue6: '#b4f9f8',
|
||||||
|
blue7: '#394b70',
|
||||||
|
comment: '#565f89',
|
||||||
|
cyan: '#7dcfff',
|
||||||
|
fg: '#c0caf5',
|
||||||
|
fg_dark: '#a9b1d6',
|
||||||
|
fg_gutter: '#3b4261',
|
||||||
|
green: '#9ece6a',
|
||||||
|
green1: '#73daca',
|
||||||
|
green2: '#41a6b5',
|
||||||
|
magenta: '#bb9af7',
|
||||||
|
magenta2: '#ff007c',
|
||||||
|
orange: '#ff9e64',
|
||||||
|
purple: '#9d7cd8',
|
||||||
|
red: '#f7768e',
|
||||||
|
red1: '#db4b4b',
|
||||||
|
teal: '#1abc9c',
|
||||||
|
yellow: '#e0af68',
|
||||||
|
diff: {
|
||||||
|
add: '#243e4a',
|
||||||
|
change: '#1f2231',
|
||||||
|
delete: '#4a272f',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const tokyoNightColors: ColorsTheme = {
|
||||||
|
type: 'dark',
|
||||||
|
Background: palette.bg,
|
||||||
|
Foreground: palette.fg,
|
||||||
|
LightBlue: palette.purple,
|
||||||
|
AccentBlue: palette.magenta,
|
||||||
|
AccentPurple: palette.blue,
|
||||||
|
AccentCyan: palette.cyan,
|
||||||
|
AccentGreen: palette.teal,
|
||||||
|
AccentYellow: palette.yellow,
|
||||||
|
AccentRed: palette.red1,
|
||||||
|
DiffAdded: palette.diff.add,
|
||||||
|
DiffRemoved: palette.diff.delete,
|
||||||
|
Comment: palette.comment,
|
||||||
|
Gray: palette.fg_dark,
|
||||||
|
DarkGray: palette.fg_gutter,
|
||||||
|
FocusColor: palette.blue,
|
||||||
|
GradientColors: [palette.blue, palette.magenta, palette.cyan],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TokyoNight: Theme = new Theme(
|
||||||
|
'Tokyo Night',
|
||||||
|
'dark',
|
||||||
|
{
|
||||||
|
hljs: {
|
||||||
|
display: 'block',
|
||||||
|
overflowX: 'auto',
|
||||||
|
padding: '0.5em',
|
||||||
|
background: palette.bg,
|
||||||
|
color: palette.fg,
|
||||||
|
},
|
||||||
|
'hljs-addition': { background: palette.diff.add },
|
||||||
|
'hljs-attr': { color: palette.green1 },
|
||||||
|
'hljs-attribute': { color: palette.green1 },
|
||||||
|
'hljs-brace': { color: palette.fg_dark },
|
||||||
|
'hljs-built_in': { color: palette.blue1 },
|
||||||
|
'hljs-builtin-symbol': { color: palette.blue1 },
|
||||||
|
'hljs-bullet': {
|
||||||
|
color: palette.orange,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
'hljs-char': { color: palette.green },
|
||||||
|
'hljs-char-escape': { color: palette.magenta },
|
||||||
|
'hljs-character': { color: palette.green },
|
||||||
|
'hljs-class': { color: palette.blue1 },
|
||||||
|
'hljs-class-title': { color: palette.blue1 },
|
||||||
|
'hljs-code': { color: palette.green },
|
||||||
|
'hljs-comment': {
|
||||||
|
color: palette.comment,
|
||||||
|
fontStyle: 'italic',
|
||||||
|
},
|
||||||
|
'hljs-computation-expression': { color: palette.cyan },
|
||||||
|
'hljs-deletion': { background: palette.diff.delete },
|
||||||
|
'hljs-doctag': { color: palette.yellow },
|
||||||
|
'hljs-emphasis': { fontStyle: 'italic' },
|
||||||
|
'hljs-function': { color: palette.blue },
|
||||||
|
'hljs-function-dispatch': { color: palette.blue },
|
||||||
|
'hljs-keyword': {
|
||||||
|
color: palette.magenta,
|
||||||
|
fontStyle: 'italic',
|
||||||
|
},
|
||||||
|
'hljs-label': { color: palette.blue },
|
||||||
|
'hljs-link': { color: palette.teal },
|
||||||
|
'hljs-literal': { color: palette.orange },
|
||||||
|
'hljs-message-name': { color: palette.blue },
|
||||||
|
'hljs-meta': { color: palette.cyan },
|
||||||
|
'hljs-meta-prompt': { color: palette.fg_dark },
|
||||||
|
'hljs-name': { color: palette.magenta },
|
||||||
|
'hljs-named-character': { color: palette.blue1 },
|
||||||
|
'hljs-number': { color: palette.orange },
|
||||||
|
'hljs-operator': { color: palette.blue5 },
|
||||||
|
'hljs-params': { color: palette.yellow },
|
||||||
|
'hljs-property': { color: palette.green1 },
|
||||||
|
'hljs-punctuation': { color: palette.fg_dark },
|
||||||
|
'hljs-quote': {
|
||||||
|
color: palette.comment,
|
||||||
|
fontStyle: 'italic',
|
||||||
|
},
|
||||||
|
'hljs-regex': { color: palette.blue6 },
|
||||||
|
'hljs-regexp': { color: palette.blue6 },
|
||||||
|
'hljs-rest_arg': {
|
||||||
|
color: interpolateColor(palette.yellow, palette.fg, 0.8),
|
||||||
|
},
|
||||||
|
'hljs-section': {
|
||||||
|
color: palette.blue,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
'hljs-selector-attr': { color: palette.cyan },
|
||||||
|
'hljs-selector-class': { color: palette.green1 },
|
||||||
|
'hljs-selector-id': { color: palette.green1 },
|
||||||
|
'hljs-selector-pseudo': { color: palette.cyan },
|
||||||
|
'hljs-selector-tag': { color: palette.magenta },
|
||||||
|
'hljs-string': { color: palette.green },
|
||||||
|
'hljs-strong': { fontWeight: 'bold' },
|
||||||
|
'hljs-subst': { color: palette.blue5 },
|
||||||
|
'hljs-symbol': { color: palette.magenta },
|
||||||
|
'hljs-tag': { color: palette.blue1 },
|
||||||
|
'hljs-template-tag': { color: palette.blue5 },
|
||||||
|
'hljs-template-variable': { color: palette.fg },
|
||||||
|
'hljs-title': { color: palette.blue },
|
||||||
|
'hljs-title-class': { color: palette.blue1 },
|
||||||
|
'hljs-title-class-inherited': { color: palette.blue1 },
|
||||||
|
'hljs-title-function': { color: palette.blue },
|
||||||
|
'hljs-title-function-invoke': { color: palette.blue },
|
||||||
|
'hljs-type': { color: palette.blue1 },
|
||||||
|
'hljs-variable': { color: palette.fg },
|
||||||
|
'hljs-variable-constant': { color: palette.orange },
|
||||||
|
'hljs-variable-language': { color: palette.red },
|
||||||
|
},
|
||||||
|
tokyoNightColors,
|
||||||
|
);
|
||||||
@@ -18,6 +18,7 @@ import { ShadesOfPurple } from './builtin/dark/shades-of-purple-dark.js';
|
|||||||
import { SolarizedDark } from './builtin/dark/solarized-dark.js';
|
import { SolarizedDark } from './builtin/dark/solarized-dark.js';
|
||||||
import { SolarizedLight } from './builtin/light/solarized-light.js';
|
import { SolarizedLight } from './builtin/light/solarized-light.js';
|
||||||
import { XCode } from './builtin/light/xcode-light.js';
|
import { XCode } from './builtin/light/xcode-light.js';
|
||||||
|
import { TokyoNight } from './builtin/dark/tokyonight-dark.js';
|
||||||
import * as fs from 'node:fs';
|
import * as fs from 'node:fs';
|
||||||
import * as path from 'node:path';
|
import * as path from 'node:path';
|
||||||
import type { Theme, ThemeType, ColorsTheme, CustomTheme } from './theme.js';
|
import type { Theme, ThemeType, ColorsTheme, CustomTheme } from './theme.js';
|
||||||
@@ -84,6 +85,7 @@ class ThemeManager {
|
|||||||
SolarizedDark,
|
SolarizedDark,
|
||||||
SolarizedLight,
|
SolarizedLight,
|
||||||
XCode,
|
XCode,
|
||||||
|
TokyoNight,
|
||||||
ANSI,
|
ANSI,
|
||||||
ANSILight,
|
ANSILight,
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user