feat: add theme configuration for ghostty-web terminal
- Add 8 predefined themes: dark, light, dracula, catppuccin, nord, gruvbox, solarized, tokyo - Support data-theme attribute for theme selection - Support custom JSON themes via data-theme attribute - Set dark theme as default - Export THEMES object for programmatic access
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "textual-webterm"
|
name = "textual-webterm"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
description = "Serve terminal sessions over the web"
|
description = "Serve terminal sessions over the web"
|
||||||
authors = ["Will McGugan <will@textualize.io>"]
|
authors = ["Will McGugan <will@textualize.io>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -14,6 +14,195 @@ const DEFAULT_FONT_FAMILY =
|
|||||||
'"Fira Code", "Roboto Mono", Menlo, Monaco, Consolas, "Liberation Mono", ' +
|
'"Fira Code", "Roboto Mono", Menlo, Monaco, Consolas, "Liberation Mono", ' +
|
||||||
'"DejaVu Sans Mono", "Courier New", monospace';
|
'"DejaVu Sans Mono", "Courier New", monospace';
|
||||||
|
|
||||||
|
/** Predefined terminal themes */
|
||||||
|
const THEMES: Record<string, ITheme> = {
|
||||||
|
// Dark themes
|
||||||
|
dark: {
|
||||||
|
background: "#1e1e1e",
|
||||||
|
foreground: "#d4d4d4",
|
||||||
|
cursor: "#aeafad",
|
||||||
|
cursorAccent: "#1e1e1e",
|
||||||
|
selection: "#264f78",
|
||||||
|
black: "#000000",
|
||||||
|
red: "#cd3131",
|
||||||
|
green: "#0dbc79",
|
||||||
|
yellow: "#e5e510",
|
||||||
|
blue: "#2472c8",
|
||||||
|
magenta: "#bc3fbc",
|
||||||
|
cyan: "#11a8cd",
|
||||||
|
white: "#e5e5e5",
|
||||||
|
brightBlack: "#666666",
|
||||||
|
brightRed: "#f14c4c",
|
||||||
|
brightGreen: "#23d18b",
|
||||||
|
brightYellow: "#f5f543",
|
||||||
|
brightBlue: "#3b8eea",
|
||||||
|
brightMagenta: "#d670d6",
|
||||||
|
brightCyan: "#29b8db",
|
||||||
|
brightWhite: "#ffffff",
|
||||||
|
},
|
||||||
|
light: {
|
||||||
|
background: "#ffffff",
|
||||||
|
foreground: "#383a42",
|
||||||
|
cursor: "#526eff",
|
||||||
|
cursorAccent: "#ffffff",
|
||||||
|
selection: "#add6ff",
|
||||||
|
black: "#000000",
|
||||||
|
red: "#e45649",
|
||||||
|
green: "#50a14f",
|
||||||
|
yellow: "#c18401",
|
||||||
|
blue: "#4078f2",
|
||||||
|
magenta: "#a626a4",
|
||||||
|
cyan: "#0184bc",
|
||||||
|
white: "#a0a1a7",
|
||||||
|
brightBlack: "#5c6370",
|
||||||
|
brightRed: "#e06c75",
|
||||||
|
brightGreen: "#98c379",
|
||||||
|
brightYellow: "#d19a66",
|
||||||
|
brightBlue: "#61afef",
|
||||||
|
brightMagenta: "#c678dd",
|
||||||
|
brightCyan: "#56b6c2",
|
||||||
|
brightWhite: "#ffffff",
|
||||||
|
},
|
||||||
|
dracula: {
|
||||||
|
background: "#282a36",
|
||||||
|
foreground: "#f8f8f2",
|
||||||
|
cursor: "#f8f8f2",
|
||||||
|
cursorAccent: "#282a36",
|
||||||
|
selection: "#44475a",
|
||||||
|
black: "#21222c",
|
||||||
|
red: "#ff5555",
|
||||||
|
green: "#50fa7b",
|
||||||
|
yellow: "#f1fa8c",
|
||||||
|
blue: "#bd93f9",
|
||||||
|
magenta: "#ff79c6",
|
||||||
|
cyan: "#8be9fd",
|
||||||
|
white: "#f8f8f2",
|
||||||
|
brightBlack: "#6272a4",
|
||||||
|
brightRed: "#ff6e6e",
|
||||||
|
brightGreen: "#69ff94",
|
||||||
|
brightYellow: "#ffffa5",
|
||||||
|
brightBlue: "#d6acff",
|
||||||
|
brightMagenta: "#ff92df",
|
||||||
|
brightCyan: "#a4ffff",
|
||||||
|
brightWhite: "#ffffff",
|
||||||
|
},
|
||||||
|
catppuccin: {
|
||||||
|
background: "#1e1e2e",
|
||||||
|
foreground: "#cdd6f4",
|
||||||
|
cursor: "#f5e0dc",
|
||||||
|
cursorAccent: "#1e1e2e",
|
||||||
|
selection: "#45475a",
|
||||||
|
black: "#45475a",
|
||||||
|
red: "#f38ba8",
|
||||||
|
green: "#a6e3a1",
|
||||||
|
yellow: "#f9e2af",
|
||||||
|
blue: "#89b4fa",
|
||||||
|
magenta: "#f5c2e7",
|
||||||
|
cyan: "#94e2d5",
|
||||||
|
white: "#bac2de",
|
||||||
|
brightBlack: "#585b70",
|
||||||
|
brightRed: "#f38ba8",
|
||||||
|
brightGreen: "#a6e3a1",
|
||||||
|
brightYellow: "#f9e2af",
|
||||||
|
brightBlue: "#89b4fa",
|
||||||
|
brightMagenta: "#f5c2e7",
|
||||||
|
brightCyan: "#94e2d5",
|
||||||
|
brightWhite: "#a6adc8",
|
||||||
|
},
|
||||||
|
nord: {
|
||||||
|
background: "#2e3440",
|
||||||
|
foreground: "#d8dee9",
|
||||||
|
cursor: "#d8dee9",
|
||||||
|
cursorAccent: "#2e3440",
|
||||||
|
selection: "#434c5e",
|
||||||
|
black: "#3b4252",
|
||||||
|
red: "#bf616a",
|
||||||
|
green: "#a3be8c",
|
||||||
|
yellow: "#ebcb8b",
|
||||||
|
blue: "#81a1c1",
|
||||||
|
magenta: "#b48ead",
|
||||||
|
cyan: "#88c0d0",
|
||||||
|
white: "#e5e9f0",
|
||||||
|
brightBlack: "#4c566a",
|
||||||
|
brightRed: "#bf616a",
|
||||||
|
brightGreen: "#a3be8c",
|
||||||
|
brightYellow: "#ebcb8b",
|
||||||
|
brightBlue: "#81a1c1",
|
||||||
|
brightMagenta: "#b48ead",
|
||||||
|
brightCyan: "#8fbcbb",
|
||||||
|
brightWhite: "#eceff4",
|
||||||
|
},
|
||||||
|
gruvbox: {
|
||||||
|
background: "#282828",
|
||||||
|
foreground: "#ebdbb2",
|
||||||
|
cursor: "#ebdbb2",
|
||||||
|
cursorAccent: "#282828",
|
||||||
|
selection: "#504945",
|
||||||
|
black: "#282828",
|
||||||
|
red: "#cc241d",
|
||||||
|
green: "#98971a",
|
||||||
|
yellow: "#d79921",
|
||||||
|
blue: "#458588",
|
||||||
|
magenta: "#b16286",
|
||||||
|
cyan: "#689d6a",
|
||||||
|
white: "#a89984",
|
||||||
|
brightBlack: "#928374",
|
||||||
|
brightRed: "#fb4934",
|
||||||
|
brightGreen: "#b8bb26",
|
||||||
|
brightYellow: "#fabd2f",
|
||||||
|
brightBlue: "#83a598",
|
||||||
|
brightMagenta: "#d3869b",
|
||||||
|
brightCyan: "#8ec07c",
|
||||||
|
brightWhite: "#ebdbb2",
|
||||||
|
},
|
||||||
|
solarized: {
|
||||||
|
background: "#002b36",
|
||||||
|
foreground: "#839496",
|
||||||
|
cursor: "#839496",
|
||||||
|
cursorAccent: "#002b36",
|
||||||
|
selection: "#073642",
|
||||||
|
black: "#073642",
|
||||||
|
red: "#dc322f",
|
||||||
|
green: "#859900",
|
||||||
|
yellow: "#b58900",
|
||||||
|
blue: "#268bd2",
|
||||||
|
magenta: "#d33682",
|
||||||
|
cyan: "#2aa198",
|
||||||
|
white: "#eee8d5",
|
||||||
|
brightBlack: "#586e75",
|
||||||
|
brightRed: "#cb4b16",
|
||||||
|
brightGreen: "#586e75",
|
||||||
|
brightYellow: "#657b83",
|
||||||
|
brightBlue: "#839496",
|
||||||
|
brightMagenta: "#6c71c4",
|
||||||
|
brightCyan: "#93a1a1",
|
||||||
|
brightWhite: "#fdf6e3",
|
||||||
|
},
|
||||||
|
tokyo: {
|
||||||
|
background: "#1a1b26",
|
||||||
|
foreground: "#a9b1d6",
|
||||||
|
cursor: "#c0caf5",
|
||||||
|
cursorAccent: "#1a1b26",
|
||||||
|
selection: "#33467c",
|
||||||
|
black: "#15161e",
|
||||||
|
red: "#f7768e",
|
||||||
|
green: "#9ece6a",
|
||||||
|
yellow: "#e0af68",
|
||||||
|
blue: "#7aa2f7",
|
||||||
|
magenta: "#bb9af7",
|
||||||
|
cyan: "#7dcfff",
|
||||||
|
white: "#a9b1d6",
|
||||||
|
brightBlack: "#414868",
|
||||||
|
brightRed: "#f7768e",
|
||||||
|
brightGreen: "#9ece6a",
|
||||||
|
brightYellow: "#e0af68",
|
||||||
|
brightBlue: "#7aa2f7",
|
||||||
|
brightMagenta: "#bb9af7",
|
||||||
|
brightCyan: "#7dcfff",
|
||||||
|
brightWhite: "#c0caf5",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/** Configuration options passed via data attributes or window config */
|
/** Configuration options passed via data attributes or window config */
|
||||||
interface TerminalConfig {
|
interface TerminalConfig {
|
||||||
fontFamily?: string;
|
fontFamily?: string;
|
||||||
@@ -35,6 +224,19 @@ function parseConfig(element: HTMLElement): TerminalConfig {
|
|||||||
if (element.dataset.scrollback) {
|
if (element.dataset.scrollback) {
|
||||||
config.scrollback = parseInt(element.dataset.scrollback, 10);
|
config.scrollback = parseInt(element.dataset.scrollback, 10);
|
||||||
}
|
}
|
||||||
|
if (element.dataset.theme) {
|
||||||
|
const themeName = element.dataset.theme.toLowerCase();
|
||||||
|
if (themeName in THEMES) {
|
||||||
|
config.theme = THEMES[themeName];
|
||||||
|
} else {
|
||||||
|
// Try parsing as JSON for custom themes
|
||||||
|
try {
|
||||||
|
config.theme = JSON.parse(element.dataset.theme) as ITheme;
|
||||||
|
} catch {
|
||||||
|
console.warn(`Unknown theme "${element.dataset.theme}", using default`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
@@ -95,7 +297,7 @@ class WebTerminal {
|
|||||||
scrollback: config.scrollback ?? 1000,
|
scrollback: config.scrollback ?? 1000,
|
||||||
cursorBlink: true,
|
cursorBlink: true,
|
||||||
cursorStyle: "block",
|
cursorStyle: "block",
|
||||||
theme: config.theme,
|
theme: config.theme ?? THEMES.dark,
|
||||||
wasmPath,
|
wasmPath,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -318,4 +520,4 @@ if (document.readyState === "loading") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Export for potential external use
|
// Export for potential external use
|
||||||
export { WebTerminal, initTerminals, instances };
|
export { WebTerminal, initTerminals, instances, THEMES };
|
||||||
|
|||||||
Reference in New Issue
Block a user