diff --git a/src/common/user-store/preferences-helpers.ts b/src/common/user-store/preferences-helpers.ts index 1ded307f0d..e26692c905 100644 --- a/src/common/user-store/preferences-helpers.ts +++ b/src/common/user-store/preferences-helpers.ts @@ -233,6 +233,19 @@ const terminalCopyOnSelect: PreferenceDescription = { }, }; +const terminalUseDarkTheme: PreferenceDescription = { + fromStore(val) { + return val ?? false; + }, + toStore(val) { + if (!val) { + return undefined; + } + + return val; + }, +}; + const hiddenTableColumns: PreferenceDescription<[string, string[]][], Map>> = { fromStore(val) { return new Map( @@ -364,6 +377,7 @@ export const DESCRIPTORS = { syncKubeconfigEntries, editorConfiguration, terminalCopyOnSelect, + terminalUseDarkTheme, updateChannel, extensionRegistryUrl, }; diff --git a/src/common/user-store/user-store.ts b/src/common/user-store/user-store.ts index 31238f0ded..202924eb4d 100644 --- a/src/common/user-store/user-store.ts +++ b/src/common/user-store/user-store.ts @@ -74,6 +74,7 @@ export class UserStore extends BaseStore /* implements UserStore @observable downloadBinariesPath?: string; @observable kubectlBinariesPath?: string; @observable terminalCopyOnSelect: boolean; + @observable terminalUseDarkTheme: boolean; @observable updateChannel?: string; @observable extensionRegistryUrl: ExtensionRegistry; @@ -201,6 +202,7 @@ export class UserStore extends BaseStore /* implements UserStore this.syncKubeconfigEntries.replace(DESCRIPTORS.syncKubeconfigEntries.fromStore(preferences?.syncKubeconfigEntries)); this.editorConfiguration = DESCRIPTORS.editorConfiguration.fromStore(preferences?.editorConfiguration); this.terminalCopyOnSelect = DESCRIPTORS.terminalCopyOnSelect.fromStore(preferences?.terminalCopyOnSelect); + this.terminalUseDarkTheme = DESCRIPTORS.terminalUseDarkTheme.fromStore(preferences?.terminalUseDarkTheme); this.updateChannel = DESCRIPTORS.updateChannel.fromStore(preferences?.updateChannel); this.extensionRegistryUrl = DESCRIPTORS.extensionRegistryUrl.fromStore(preferences?.extensionRegistryUrl); } @@ -225,6 +227,7 @@ export class UserStore extends BaseStore /* implements UserStore syncKubeconfigEntries: DESCRIPTORS.syncKubeconfigEntries.toStore(this.syncKubeconfigEntries), editorConfiguration: DESCRIPTORS.editorConfiguration.toStore(this.editorConfiguration), terminalCopyOnSelect: DESCRIPTORS.terminalCopyOnSelect.toStore(this.terminalCopyOnSelect), + terminalUseDarkTheme: DESCRIPTORS.terminalUseDarkTheme.toStore(this.terminalUseDarkTheme), updateChannel: DESCRIPTORS.updateChannel.toStore(this.updateChannel), extensionRegistryUrl: DESCRIPTORS.extensionRegistryUrl.toStore(this.extensionRegistryUrl), }, diff --git a/src/renderer/components/+preferences/application.tsx b/src/renderer/components/+preferences/application.tsx index 1e3c75b68f..4422eb3313 100644 --- a/src/renderer/components/+preferences/application.tsx +++ b/src/renderer/components/+preferences/application.tsx @@ -94,6 +94,16 @@ export const Application = observer(() => { +
+ + userStore.terminalUseDarkTheme = !userStore.terminalUseDarkTheme} + > + Always use dark terminal theme colors + +
+
diff --git a/src/renderer/components/dock/dock.scss b/src/renderer/components/dock/dock.scss index d473a089fa..63657fcc02 100644 --- a/src/renderer/components/dock/dock.scss +++ b/src/renderer/components/dock/dock.scss @@ -76,7 +76,6 @@ .tab-content { position: relative; - background: var(--terminalBackground); flex: 1; overflow: hidden; transition: flex-basis 25ms ease-in; diff --git a/src/renderer/components/dock/terminal-window.scss b/src/renderer/components/dock/terminal-window.scss index 630916f5e0..fa0d897b0d 100644 --- a/src/renderer/components/dock/terminal-window.scss +++ b/src/renderer/components/dock/terminal-window.scss @@ -26,7 +26,8 @@ flex: 1; overflow: hidden; - left: var(--spacing) !important; - top: var(--spacing) !important; - bottom: var(--spacing) !important; + + > .xterm { + padding: var(--spacing); + } } \ No newline at end of file diff --git a/src/renderer/components/dock/terminal.ts b/src/renderer/components/dock/terminal.ts index 383accab20..908818d268 100644 --- a/src/renderer/components/dock/terminal.ts +++ b/src/renderer/components/dock/terminal.ts @@ -26,9 +26,9 @@ import { FitAddon } from "xterm-addon-fit"; import { dockStore, TabId } from "./dock.store"; import { TerminalApi, TerminalChannels } from "../../api/terminal-api"; import { ThemeStore } from "../../theme.store"; -import { boundMethod, disposer } from "../../utils"; +import { disposer } from "../../utils"; import { isMac } from "../../../common/vars"; -import { camelCase, once } from "lodash"; +import { once } from "lodash"; import { UserStore } from "../../../common/user-store"; import { clipboard } from "electron"; import logger from "../../../common/logger"; @@ -56,23 +56,6 @@ export class Terminal { private scrollPos = 0; private disposer = disposer(); - @boundMethod - protected setTheme(colors: Record) { - if (!this.xterm) { - return; - } - - // Replacing keys stored in styles to format accepted by terminal - // E.g. terminalBrightBlack -> brightBlack - const colorPrefix = "terminal"; - const terminalColorEntries = Object.entries(colors) - .filter(([name]) => name.startsWith(colorPrefix)) - .map(([name, color]) => [camelCase(name.slice(colorPrefix.length)), color]); - const terminalColors = Object.fromEntries(terminalColorEntries); - - this.xterm.setOption("theme", terminalColors); - } - get elem() { return this.xterm?.element; } @@ -121,7 +104,9 @@ export class Terminal { window.addEventListener("resize", this.onResize); this.disposer.push( - reaction(() => ThemeStore.getInstance().activeTheme.colors, this.setTheme, { + reaction(() => ThemeStore.getInstance().terminalColors, themeColors => { + this.xterm?.setOption("theme", themeColors); + }, { fireImmediately: true, }), dockStore.onResize(this.onResize), diff --git a/src/renderer/theme.store.ts b/src/renderer/theme.store.ts index 15aa055f92..ff670ce85a 100644 --- a/src/renderer/theme.store.ts +++ b/src/renderer/theme.store.ts @@ -28,6 +28,7 @@ import lensLightThemeJson from "./themes/lens-light.json"; import type { SelectOption } from "./components/select"; import type { MonacoEditorProps } from "./components/monaco-editor"; import { defaultTheme } from "../common/vars"; +import { camelCase } from "lodash"; export type ThemeId = string; @@ -41,7 +42,8 @@ export interface Theme { } export class ThemeStore extends Singleton { - protected styles: HTMLStyleElement; + private styles: HTMLStyleElement; + private terminalColorPrefix = "terminal"; // bundled themes from `themes/${themeId}.json` private themes = observable.map({ @@ -57,6 +59,24 @@ export class ThemeStore extends Singleton { return this.themes.get(this.activeThemeId) ?? this.themes.get(defaultTheme); } + @computed get terminalColors(): Record { + const useDarkThemeColors = UserStore.getInstance().terminalUseDarkTheme; + const theme = useDarkThemeColors ? this.themes.get("lens-dark") : this.activeTheme; + const xtermColors: Record = {}; // see also "terminal.ts" + + // Replacing keys stored in styles to format accepted by terminal + // E.g. terminalBrightBlack -> brightBlack + for (const [name, color] of Object.entries(theme.colors)) { + if (!name.startsWith(this.terminalColorPrefix)) continue; // skip + + const xtermColorName = camelCase(name.replace(this.terminalColorPrefix, "")); + + xtermColors[xtermColorName] = color; + } + + return xtermColors; + } + @computed get themeOptions(): SelectOption[] { return Array.from(this.themes).map(([themeId, theme]) => ({ label: theme.name, diff --git a/src/renderer/themes/lens-light.json b/src/renderer/themes/lens-light.json index 8525d31a56..d78b7b618c 100644 --- a/src/renderer/themes/lens-light.json +++ b/src/renderer/themes/lens-light.json @@ -76,26 +76,26 @@ "logsBackground": "#24292e", "logsForeground": "#ffffff", "logRowHoverBackground": "#35373a", - "terminalBackground": "#24292e", - "terminalForeground": "#ffffff", - "terminalCursor": "#ffffff", - "terminalCursorAccent": "#000000", - "terminalSelection": "#ffffff77", - "terminalBlack": "#2e3436", - "terminalRed": "#cc0000", - "terminalGreen": "#4e9a06", - "terminalYellow": "#c4a000", - "terminalBlue": "#3465a4", - "terminalMagenta": "#75507b", - "terminalCyan": "#06989a", + "terminalBackground": "#ffffff", + "terminalForeground": "#2d2d2d", + "terminalCursor": "#2d2d2d", + "terminalCursorAccent": "#ffffff", + "terminalSelection": "#bfbfbf", + "terminalBlack": "#2d2d2d", + "terminalRed": "#cd3734 ", + "terminalGreen": "#18cf12", + "terminalYellow": "#acb300", + "terminalBlue": "#3d90ce", + "terminalMagenta": "#c100cd", + "terminalCyan": "#07c4b9", "terminalWhite": "#d3d7cf", - "terminalBrightBlack": "#555753", - "terminalBrightRed": "#ef2929", - "terminalBrightGreen": "#8ae234", - "terminalBrightYellow": "#fce94f", - "terminalBrightBlue": "#729fcf", - "terminalBrightMagenta": "#ad7fa8", - "terminalBrightCyan": "#34e2e2", + "terminalBrightBlack": "#a8a8a8", + "terminalBrightRed": "#ff6259", + "terminalBrightGreen": "#5cdb59", + "terminalBrightYellow": "#f8c000", + "terminalBrightBlue": "#008db6", + "terminalBrightMagenta": "#ee55f8", + "terminalBrightCyan": "#50e8df", "terminalBrightWhite": "#eeeeec", "dialogTextColor": "#87909c", "dialogBackground": "#ffffff",