;
viewText: jotai.Atom;
viewName: jotai.Atom;
+ blockBg: jotai.Atom;
constructor(blockId: string) {
this.blockId = blockId;
@@ -152,6 +139,15 @@ class TermViewModel {
const blockData = get(this.blockAtom);
return blockData?.meta?.title ?? "";
});
+ this.blockBg = jotai.atom((get) => {
+ const blockData = get(this.blockAtom);
+ const settings = globalStore.get(atoms.settingsConfigAtom);
+ const theme = computeTheme(settings, blockData?.meta?.["term:theme"]);
+ if (theme != null && theme.background != null) {
+ return { bg: theme.background };
+ }
+ return null;
+ });
}
giveFocus(): boolean {
@@ -169,6 +165,23 @@ class TermViewModel {
}
return false;
}
+
+ setTerminalTheme(themeName: string) {
+ WshServer.SetMetaCommand({ oref: WOS.makeORef("block", this.blockId), meta: { "term:theme": themeName } });
+ }
+
+ getSettingsMenuItems(): ContextMenuItem[] {
+ return [
+ {
+ label: "Themes",
+ submenu: [
+ { label: "Default Dark", click: () => this.setTerminalTheme("default") },
+ { label: "Dracula", click: () => this.setTerminalTheme("dracula") },
+ { label: "Campbell", click: () => this.setTerminalTheme("campbell") },
+ ],
+ },
+ ];
+ }
}
function makeTerminalModel(blockId: string): TermViewModel {
@@ -220,11 +233,13 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
}
const settings = globalStore.get(atoms.settingsConfigAtom);
const termTheme = computeTheme(settings, blockData?.meta?.["term:theme"]);
+ const themeCopy = { ...termTheme };
+ themeCopy.background = "#00000000";
const termWrap = new TermWrap(
blockId,
connectElemRef.current,
{
- theme: termTheme,
+ theme: themeCopy,
fontSize: termSettings?.fontsize ?? 12,
fontFamily: termSettings?.fontfamily ?? "Hack",
drawBoldTextInBrightColors: false,
diff --git a/frontend/app/view/term/termtheme.ts b/frontend/app/view/term/termtheme.ts
index e39c18fc4..5f8b22ce6 100644
--- a/frontend/app/view/term/termtheme.ts
+++ b/frontend/app/view/term/termtheme.ts
@@ -29,7 +29,9 @@ const TermThemeUpdater = ({ blockId, termRef }: TermThemeProps) => {
}
}
if (termRef.current?.terminal) {
- termRef.current.terminal.options.theme = combinedTheme;
+ let themeCopy = { ...combinedTheme };
+ themeCopy.background = "#00000000";
+ termRef.current.terminal.options.theme = themeCopy;
}
}, [defaultTheme, theme]);
diff --git a/frontend/app/view/term/termutil.ts b/frontend/app/view/term/termutil.ts
new file mode 100644
index 000000000..574864048
--- /dev/null
+++ b/frontend/app/view/term/termutil.ts
@@ -0,0 +1,20 @@
+// Copyright 2024, Command Line Inc.
+// SPDX-License-Identifier: Apache-2.0
+
+import * as util from "@/util/util";
+
+function computeTheme(settings: SettingsConfigType, themeName: string): TermThemeType {
+ let defaultThemeName = "default-dark";
+ themeName = themeName ?? "default-dark";
+ const defaultTheme: TermThemeType = settings?.termthemes?.[defaultThemeName] || ({} as any);
+ const theme: TermThemeType = settings?.termthemes?.[themeName] || ({} as any);
+ const combinedTheme = { ...defaultTheme };
+ for (const key in theme) {
+ if (!util.isBlank(theme[key])) {
+ combinedTheme[key] = theme[key];
+ }
+ }
+ return combinedTheme;
+}
+
+export { computeTheme };
diff --git a/frontend/types/custom.d.ts b/frontend/types/custom.d.ts
index d3bec07df..c7efbfce4 100644
--- a/frontend/types/custom.d.ts
+++ b/frontend/types/custom.d.ts
@@ -166,6 +166,7 @@ declare global {
viewText?: jotai.Atom;
preIconButton?: jotai.Atom;
endIconButtons?: jotai.Atom;
+ blockBg?: jotai.Atom;
onBack?: () => void;
onForward?: () => void;
diff --git a/pkg/wconfig/settingsconfig.go b/pkg/wconfig/settingsconfig.go
index 06a90502d..b55f51724 100644
--- a/pkg/wconfig/settingsconfig.go
+++ b/pkg/wconfig/settingsconfig.go
@@ -125,10 +125,60 @@ var DefaultTermDarkTheme = TermThemeType{
CmdText: "#f0f0f0",
Foreground: "#c1c1c1",
SelectionBackground: "",
- Background: "#00000000",
+ Background: "#00000077",
CursorAccent: "",
}
+var DraculaTheme = TermThemeType{
+ Black: "#21222C", // AnsiBlack
+ Red: "#FF5555", // AnsiRed
+ Green: "#50FA7B", // AnsiGreen
+ Yellow: "#F1FA8C", // AnsiYellow
+ Blue: "#BD93F9", // AnsiBlue
+ Magenta: "#FF79C6", // AnsiMagenta
+ Cyan: "#8BE9FD", // AnsiCyan
+ White: "#F8F8F2", // AnsiWhite
+ BrightBlack: "#6272A4", // AnsiBrightBlack
+ BrightRed: "#FF6E6E", // AnsiBrightRed
+ BrightGreen: "#69FF94", // AnsiBrightGreen
+ BrightYellow: "#FFFFA5", // AnsiBrightYellow
+ BrightBlue: "#D6ACFF", // AnsiBrightBlue
+ BrightMagenta: "#FF92DF", // AnsiBrightMagenta
+ BrightCyan: "#A4FFFF", // AnsiBrightCyan
+ BrightWhite: "#FFFFFF", // AnsiBrightWhite
+ Gray: "#6272A4", // Comment or closest approximation
+ CmdText: "#F8F8F2", // Foreground
+ Foreground: "#F8F8F2", // Foreground
+ SelectionBackground: "#44475a", // Selection
+ Background: "#282a36", // Background
+ CursorAccent: "#f8f8f2", // Foreground (used for cursor accent)
+}
+
+var CampbellTheme = TermThemeType{
+ Black: "#0C0C0C", // Black
+ Red: "#C50F1F", // Red
+ Green: "#13A10E", // Green
+ Yellow: "#C19C00", // Yellow
+ Blue: "#0037DA", // Blue
+ Magenta: "#881798", // Purple (used as Magenta)
+ Cyan: "#3A96DD", // Cyan
+ White: "#CCCCCC", // White
+ BrightBlack: "#767676", // BrightBlack
+ BrightRed: "#E74856", // BrightRed
+ BrightGreen: "#16C60C", // BrightGreen
+ BrightYellow: "#F9F1A5", // BrightYellow
+ BrightBlue: "#3B78FF", // BrightBlue
+ BrightMagenta: "#B4009E", // BrightPurple (used as BrightMagenta)
+ BrightCyan: "#61D6D6", // BrightCyan
+ BrightWhite: "#F2F2F2", // BrightWhite
+ Gray: "#767676", // BrightBlack or closest approximation
+ CmdText: "#CCCCCC", // Foreground
+ Foreground: "#CCCCCC", // Foreground
+ SelectionBackground: "#3A96DD", // Cyan (chosen for selection background)
+ Background: "#0C0C0C", // Background
+ CursorAccent: "#CCCCCC", // Foreground (used for cursor accent)
+}
+
func applyDefaultSettings(settings *SettingsConfigType) {
defaultMimeTypes := map[string]MimeTypeConfigType{
"audio": {Icon: "file-audio"},
@@ -229,4 +279,10 @@ func applyDefaultSettings(settings *SettingsConfigType) {
if _, found := settings.TermThemes["default-dark"]; !found {
settings.TermThemes["default-dark"] = DefaultTermDarkTheme
}
+ if _, found := settings.TermThemes["dracula"]; !found {
+ settings.TermThemes["dracula"] = DraculaTheme
+ }
+ if _, found := settings.TermThemes["campbell"]; !found {
+ settings.TermThemes["campbell"] = CampbellTheme
+ }
}