diff options
| author | Taylor Mullen <[email protected]> | 2025-04-22 18:57:47 -0700 |
|---|---|---|
| committer | N. Taylor Mullen <[email protected]> | 2025-04-22 22:08:13 -0700 |
| commit | 4c2a5045a0d209cfda5723a4dc84fe59670b558e (patch) | |
| tree | 2a874aa35a524f683a39f89d5fc288b0a09596f7 /packages/cli/src/ui/themes | |
| parent | e163e024996ff8bb1152284322831c4f35696801 (diff) | |
Add theming support.
- Added a number of common themes to our support matrix:
- AtomOneDark
- Dracula
- VS
- GitHub
- GoogleCode
- XCode
- ... Admittedly these all were randomly picked, we could probably curate these better...
- Added a new `ThemeDialog` UI that can be accessed via `/theme`. It shows your currentlyt available themes and allows you to change them freely. It does **not**:
- Save the theme between sessions
- Allow you to hit escape
- Show a preview prior to selection.
- These themes are from reacts highlight js library.
Fixes https://b.corp.google.com/issues/412797985
Diffstat (limited to 'packages/cli/src/ui/themes')
| -rw-r--r-- | packages/cli/src/ui/themes/atom-one-dark.ts | 122 | ||||
| -rw-r--r-- | packages/cli/src/ui/themes/dracula.ts | 99 | ||||
| -rw-r--r-- | packages/cli/src/ui/themes/github.ts | 124 | ||||
| -rw-r--r-- | packages/cli/src/ui/themes/googlecode.ts | 121 | ||||
| -rw-r--r-- | packages/cli/src/ui/themes/theme-manager.ts | 47 | ||||
| -rw-r--r-- | packages/cli/src/ui/themes/vs.ts | 101 | ||||
| -rw-r--r-- | packages/cli/src/ui/themes/xcode.ts | 129 |
7 files changed, 742 insertions, 1 deletions
diff --git a/packages/cli/src/ui/themes/atom-one-dark.ts b/packages/cli/src/ui/themes/atom-one-dark.ts new file mode 100644 index 00000000..316b9048 --- /dev/null +++ b/packages/cli/src/ui/themes/atom-one-dark.ts @@ -0,0 +1,122 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Theme } from './theme.js'; + +export const AtomOneDark: Theme = new Theme('Atom One Dark', { + hljs: { + display: 'block', + overflowX: 'auto', + padding: '0.5em', + color: '#abb2bf', + background: '#282c34', + }, + 'hljs-comment': { + color: '#5c6370', + fontStyle: 'italic', + }, + 'hljs-quote': { + color: '#5c6370', + fontStyle: 'italic', + }, + 'hljs-doctag': { + color: '#c678dd', + }, + 'hljs-keyword': { + color: '#c678dd', + }, + 'hljs-formula': { + color: '#c678dd', + }, + 'hljs-section': { + color: '#e06c75', + }, + 'hljs-name': { + color: '#e06c75', + }, + 'hljs-selector-tag': { + color: '#e06c75', + }, + 'hljs-deletion': { + color: '#e06c75', + }, + 'hljs-subst': { + color: '#e06c75', + }, + 'hljs-literal': { + color: '#56b6c2', + }, + 'hljs-string': { + color: '#98c379', + }, + 'hljs-regexp': { + color: '#98c379', + }, + 'hljs-addition': { + color: '#98c379', + }, + 'hljs-attribute': { + color: '#98c379', + }, + 'hljs-meta-string': { + color: '#98c379', + }, + 'hljs-built_in': { + color: '#e6c07b', + }, + 'hljs-class .hljs-title': { + color: '#e6c07b', + }, + 'hljs-attr': { + color: '#d19a66', + }, + 'hljs-variable': { + color: '#d19a66', + }, + 'hljs-template-variable': { + color: '#d19a66', + }, + 'hljs-type': { + color: '#d19a66', + }, + 'hljs-selector-class': { + color: '#d19a66', + }, + 'hljs-selector-attr': { + color: '#d19a66', + }, + 'hljs-selector-pseudo': { + color: '#d19a66', + }, + 'hljs-number': { + color: '#d19a66', + }, + 'hljs-symbol': { + color: '#61aeee', + }, + 'hljs-bullet': { + color: '#61aeee', + }, + 'hljs-link': { + color: '#61aeee', + textDecoration: 'underline', + }, + 'hljs-meta': { + color: '#61aeee', + }, + 'hljs-selector-id': { + color: '#61aeee', + }, + 'hljs-title': { + color: '#61aeee', + }, + 'hljs-emphasis': { + fontStyle: 'italic', + }, + 'hljs-strong': { + fontWeight: 'bold', + }, +}); diff --git a/packages/cli/src/ui/themes/dracula.ts b/packages/cli/src/ui/themes/dracula.ts new file mode 100644 index 00000000..0b55435a --- /dev/null +++ b/packages/cli/src/ui/themes/dracula.ts @@ -0,0 +1,99 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Theme } from './theme.js'; + +export const Dracula: Theme = new Theme('Dracula', { + hljs: { + display: 'block', + overflowX: 'auto', + padding: '0.5em', + background: '#282a36', + color: '#f8f8f2', + }, + 'hljs-keyword': { + color: '#8be9fd', + fontWeight: 'bold', + }, + 'hljs-selector-tag': { + color: '#8be9fd', + fontWeight: 'bold', + }, + 'hljs-literal': { + color: '#8be9fd', + fontWeight: 'bold', + }, + 'hljs-section': { + color: '#8be9fd', + fontWeight: 'bold', + }, + 'hljs-link': { + color: '#8be9fd', + }, + 'hljs-function .hljs-keyword': { + color: '#ff79c6', + }, + 'hljs-subst': { + color: '#f8f8f2', + }, + 'hljs-string': { + color: '#f1fa8c', + }, + 'hljs-title': { + color: '#f1fa8c', + fontWeight: 'bold', + }, + 'hljs-name': { + color: '#f1fa8c', + fontWeight: 'bold', + }, + 'hljs-type': { + color: '#f1fa8c', + fontWeight: 'bold', + }, + 'hljs-attribute': { + color: '#f1fa8c', + }, + 'hljs-symbol': { + color: '#f1fa8c', + }, + 'hljs-bullet': { + color: '#f1fa8c', + }, + 'hljs-addition': { + color: '#f1fa8c', + }, + 'hljs-variable': { + color: '#f1fa8c', + }, + 'hljs-template-tag': { + color: '#f1fa8c', + }, + 'hljs-template-variable': { + color: '#f1fa8c', + }, + 'hljs-comment': { + color: '#6272a4', + }, + 'hljs-quote': { + color: '#6272a4', + }, + 'hljs-deletion': { + color: '#6272a4', + }, + 'hljs-meta': { + color: '#6272a4', + }, + 'hljs-doctag': { + fontWeight: 'bold', + }, + 'hljs-strong': { + fontWeight: 'bold', + }, + 'hljs-emphasis': { + fontStyle: 'italic', + }, +}); diff --git a/packages/cli/src/ui/themes/github.ts b/packages/cli/src/ui/themes/github.ts new file mode 100644 index 00000000..fb4080e6 --- /dev/null +++ b/packages/cli/src/ui/themes/github.ts @@ -0,0 +1,124 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Theme } from './theme.js'; + +export const GitHub: Theme = new Theme('GitHub', { + hljs: { + display: 'block', + overflowX: 'auto', + padding: '0.5em', + color: '#333', + background: '#f8f8f8', + }, + 'hljs-comment': { + color: '#998', + fontStyle: 'italic', + }, + 'hljs-quote': { + color: '#998', + fontStyle: 'italic', + }, + 'hljs-keyword': { + color: '#333', + fontWeight: 'bold', + }, + 'hljs-selector-tag': { + color: '#333', + fontWeight: 'bold', + }, + 'hljs-subst': { + color: '#333', + fontWeight: 'normal', + }, + 'hljs-number': { + color: '#008080', + }, + 'hljs-literal': { + color: '#008080', + }, + 'hljs-variable': { + color: '#008080', + }, + 'hljs-template-variable': { + color: '#008080', + }, + 'hljs-tag .hljs-attr': { + color: '#008080', + }, + 'hljs-string': { + color: '#d14', + }, + 'hljs-doctag': { + color: '#d14', + }, + 'hljs-title': { + color: '#900', + fontWeight: 'bold', + }, + 'hljs-section': { + color: '#900', + fontWeight: 'bold', + }, + 'hljs-selector-id': { + color: '#900', + fontWeight: 'bold', + }, + 'hljs-type': { + color: '#458', + fontWeight: 'bold', + }, + 'hljs-class .hljs-title': { + color: '#458', + fontWeight: 'bold', + }, + 'hljs-tag': { + color: '#000080', + fontWeight: 'normal', + }, + 'hljs-name': { + color: '#000080', + fontWeight: 'normal', + }, + 'hljs-attribute': { + color: '#000080', + fontWeight: 'normal', + }, + 'hljs-regexp': { + color: '#009926', + }, + 'hljs-link': { + color: '#009926', + }, + 'hljs-symbol': { + color: '#990073', + }, + 'hljs-bullet': { + color: '#990073', + }, + 'hljs-built_in': { + color: '#0086b3', + }, + 'hljs-builtin-name': { + color: '#0086b3', + }, + 'hljs-meta': { + color: '#999', + fontWeight: 'bold', + }, + 'hljs-deletion': { + background: '#fdd', + }, + 'hljs-addition': { + background: '#dfd', + }, + 'hljs-emphasis': { + fontStyle: 'italic', + }, + 'hljs-strong': { + fontWeight: 'bold', + }, +}); diff --git a/packages/cli/src/ui/themes/googlecode.ts b/packages/cli/src/ui/themes/googlecode.ts new file mode 100644 index 00000000..ff01d8b6 --- /dev/null +++ b/packages/cli/src/ui/themes/googlecode.ts @@ -0,0 +1,121 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Theme } from './theme.js'; + +export const GoogleCode: Theme = new Theme('Google Code', { + hljs: { + display: 'block', + overflowX: 'auto', + padding: '0.5em', + background: 'white', + color: 'black', + }, + 'hljs-comment': { + color: '#800', + }, + 'hljs-quote': { + color: '#800', + }, + 'hljs-keyword': { + color: '#008', + }, + 'hljs-selector-tag': { + color: '#008', + }, + 'hljs-section': { + color: '#008', + }, + 'hljs-title': { + color: '#606', + }, + 'hljs-name': { + color: '#008', + }, + 'hljs-variable': { + color: '#660', + }, + 'hljs-template-variable': { + color: '#660', + }, + 'hljs-string': { + color: '#080', + }, + 'hljs-selector-attr': { + color: '#080', + }, + 'hljs-selector-pseudo': { + color: '#080', + }, + 'hljs-regexp': { + color: '#080', + }, + 'hljs-literal': { + color: '#066', + }, + 'hljs-symbol': { + color: '#066', + }, + 'hljs-bullet': { + color: '#066', + }, + 'hljs-meta': { + color: '#066', + }, + 'hljs-number': { + color: '#066', + }, + 'hljs-link': { + color: '#066', + }, + 'hljs-doctag': { + color: '#606', + fontWeight: 'bold', + }, + 'hljs-type': { + color: '#606', + }, + 'hljs-attr': { + color: '#606', + }, + 'hljs-built_in': { + color: '#606', + }, + 'hljs-builtin-name': { + color: '#606', + }, + 'hljs-params': { + color: '#606', + }, + 'hljs-attribute': { + color: '#000', + }, + 'hljs-subst': { + color: '#000', + }, + 'hljs-formula': { + backgroundColor: '#eee', + fontStyle: 'italic', + }, + 'hljs-selector-id': { + color: '#9B703F', + }, + 'hljs-selector-class': { + color: '#9B703F', + }, + 'hljs-addition': { + backgroundColor: '#baeeba', + }, + 'hljs-deletion': { + backgroundColor: '#ffc8bd', + }, + 'hljs-strong': { + fontWeight: 'bold', + }, + 'hljs-emphasis': { + fontStyle: 'italic', + }, +}); diff --git a/packages/cli/src/ui/themes/theme-manager.ts b/packages/cli/src/ui/themes/theme-manager.ts index e083575c..7e375574 100644 --- a/packages/cli/src/ui/themes/theme-manager.ts +++ b/packages/cli/src/ui/themes/theme-manager.ts @@ -4,20 +4,65 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { AtomOneDark } from './atom-one-dark.js'; +import { Dracula } from './dracula.js'; +import { GitHub } from './github.js'; +import { GoogleCode } from './googlecode.js'; +import { VS } from './vs.js'; import { VS2015 } from './vs2015.js'; +import { XCode } from './xcode.js'; import { Theme } from './theme.js'; +export interface ThemeDisplay { + name: string; + active: boolean; +} + class ThemeManager { private static readonly DEFAULT_THEME: Theme = VS2015; private readonly availableThemes: Theme[]; private activeTheme: Theme; constructor() { - this.availableThemes = [VS2015]; + this.availableThemes = [ + AtomOneDark, + Dracula, + VS, + VS2015, + GitHub, + GoogleCode, + XCode, + ]; this.activeTheme = ThemeManager.DEFAULT_THEME; } /** + * Returns a list of available theme names. + */ + getAvailableThemes(): ThemeDisplay[] { + return this.availableThemes.map((theme) => ({ + name: theme.name, + active: theme === this.activeTheme, + })); + } + + /** + * Sets the active theme. + * @param themeName The name of the theme to activate. + */ + setActiveTheme(themeName: string): void { + const foundTheme = this.availableThemes.find( + (theme) => theme.name === themeName, + ); + + if (foundTheme) { + this.activeTheme = foundTheme; + } else { + throw new Error(`Theme "${themeName}" not found.`); + } + } + + /** * Returns the currently active theme object. */ getActiveTheme(): Theme { diff --git a/packages/cli/src/ui/themes/vs.ts b/packages/cli/src/ui/themes/vs.ts new file mode 100644 index 00000000..a87e9e80 --- /dev/null +++ b/packages/cli/src/ui/themes/vs.ts @@ -0,0 +1,101 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Theme } from './theme.js'; + +export const VS: Theme = new Theme('VS', { + hljs: { + display: 'block', + overflowX: 'auto', + padding: '0.5em', + background: 'white', + color: 'black', + }, + 'hljs-comment': { + color: '#008000', + }, + 'hljs-quote': { + color: '#008000', + }, + 'hljs-variable': { + color: '#008000', + }, + 'hljs-keyword': { + color: '#00f', + }, + 'hljs-selector-tag': { + color: '#00f', + }, + 'hljs-built_in': { + color: '#00f', + }, + 'hljs-name': { + color: '#00f', + }, + 'hljs-tag': { + color: '#00f', + }, + 'hljs-string': { + color: '#a31515', + }, + 'hljs-title': { + color: '#a31515', + }, + 'hljs-section': { + color: '#a31515', + }, + 'hljs-attribute': { + color: '#a31515', + }, + 'hljs-literal': { + color: '#a31515', + }, + 'hljs-template-tag': { + color: '#a31515', + }, + 'hljs-template-variable': { + color: '#a31515', + }, + 'hljs-type': { + color: '#a31515', + }, + 'hljs-addition': { + color: '#a31515', + }, + 'hljs-deletion': { + color: '#2b91af', + }, + 'hljs-selector-attr': { + color: '#2b91af', + }, + 'hljs-selector-pseudo': { + color: '#2b91af', + }, + 'hljs-meta': { + color: '#2b91af', + }, + 'hljs-doctag': { + color: '#808080', + }, + 'hljs-attr': { + color: '#f00', + }, + 'hljs-symbol': { + color: '#00b0e8', + }, + 'hljs-bullet': { + color: '#00b0e8', + }, + 'hljs-link': { + color: '#00b0e8', + }, + 'hljs-emphasis': { + fontStyle: 'italic', + }, + 'hljs-strong': { + fontWeight: 'bold', + }, +}); diff --git a/packages/cli/src/ui/themes/xcode.ts b/packages/cli/src/ui/themes/xcode.ts new file mode 100644 index 00000000..ff2fb852 --- /dev/null +++ b/packages/cli/src/ui/themes/xcode.ts @@ -0,0 +1,129 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Theme } from './theme.js'; + +export const XCode: Theme = new Theme('XCode', { + hljs: { + display: 'block', + overflowX: 'auto', + padding: '0.5em', + background: '#fff', + color: 'black', + }, + 'xml .hljs-meta': { + color: '#c0c0c0', + }, + 'hljs-comment': { + color: '#007400', + }, + 'hljs-quote': { + color: '#007400', + }, + 'hljs-tag': { + color: '#aa0d91', + }, + 'hljs-attribute': { + color: '#aa0d91', + }, + 'hljs-keyword': { + color: '#aa0d91', + }, + 'hljs-selector-tag': { + color: '#aa0d91', + }, + 'hljs-literal': { + color: '#aa0d91', + }, + 'hljs-name': { + color: '#aa0d91', + }, + 'hljs-variable': { + color: '#3F6E74', + }, + 'hljs-template-variable': { + color: '#3F6E74', + }, + 'hljs-code': { + color: '#c41a16', + }, + 'hljs-string': { + color: '#c41a16', + }, + 'hljs-meta-string': { + color: '#c41a16', + }, + 'hljs-regexp': { + color: '#0E0EFF', + }, + 'hljs-link': { + color: '#0E0EFF', + }, + 'hljs-title': { + color: '#1c00cf', + }, + 'hljs-symbol': { + color: '#1c00cf', + }, + 'hljs-bullet': { + color: '#1c00cf', + }, + 'hljs-number': { + color: '#1c00cf', + }, + 'hljs-section': { + color: '#643820', + }, + 'hljs-meta': { + color: '#643820', + }, + 'hljs-class .hljs-title': { + color: '#5c2699', + }, + 'hljs-type': { + color: '#5c2699', + }, + 'hljs-built_in': { + color: '#5c2699', + }, + 'hljs-builtin-name': { + color: '#5c2699', + }, + 'hljs-params': { + color: '#5c2699', + }, + 'hljs-attr': { + color: '#836C28', + }, + 'hljs-subst': { + color: '#000', + }, + 'hljs-formula': { + backgroundColor: '#eee', + fontStyle: 'italic', + }, + 'hljs-addition': { + backgroundColor: '#baeeba', + }, + 'hljs-deletion': { + backgroundColor: '#ffc8bd', + }, + 'hljs-selector-id': { + color: '#9b703f', + }, + 'hljs-selector-class': { + color: '#9b703f', + }, + 'hljs-doctag': { + fontWeight: 'bold', + }, + 'hljs-strong': { + fontWeight: 'bold', + }, + 'hljs-emphasis': { + fontStyle: 'italic', + }, +}); |
