summaryrefslogtreecommitdiff
path: root/packages/cli/src/ui/themes
diff options
context:
space:
mode:
authorTaylor Mullen <[email protected]>2025-04-22 18:57:47 -0700
committerN. Taylor Mullen <[email protected]>2025-04-22 22:08:13 -0700
commit4c2a5045a0d209cfda5723a4dc84fe59670b558e (patch)
tree2a874aa35a524f683a39f89d5fc288b0a09596f7 /packages/cli/src/ui/themes
parente163e024996ff8bb1152284322831c4f35696801 (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.ts122
-rw-r--r--packages/cli/src/ui/themes/dracula.ts99
-rw-r--r--packages/cli/src/ui/themes/github.ts124
-rw-r--r--packages/cli/src/ui/themes/googlecode.ts121
-rw-r--r--packages/cli/src/ui/themes/theme-manager.ts47
-rw-r--r--packages/cli/src/ui/themes/vs.ts101
-rw-r--r--packages/cli/src/ui/themes/xcode.ts129
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',
+ },
+});