mirror of
https://github.com/block/buzz.git
synced 2026-11-14 05:12:27 +00:00
feat(terminal): add semantic --terminal-background/foreground CSS vars
Adds terminal color tokens to the adaptive theme system, derived from the Shiki syntax theme's raw bg/fg colors. Registered in Tailwind as bg-terminal / text-terminal-foreground. Terminal panel and xterm instance now adapt automatically to whatever syntax theme the user picks. - adaptive-theme.ts: emit --terminal-background, --terminal-foreground - tailwind.config.js: register terminal.DEFAULT + terminal.foreground - TerminalInstance already reads these vars with Tokyo Night fallbacks
This commit is contained in:
@@ -8,59 +8,62 @@ import { listen, type UnlistenFn } from "@tauri-apps/api/event";
|
||||
|
||||
import "@xterm/xterm/css/xterm.css";
|
||||
|
||||
// Tokyo Night — high-contrast dark terminal surface.
|
||||
const DARK_THEME: ITheme = {
|
||||
background: "#1a1b26",
|
||||
foreground: "#c0caf5",
|
||||
cursor: "#c0caf5",
|
||||
selectionBackground: "#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",
|
||||
};
|
||||
|
||||
// Light mode: terminal stays dark (high contrast against light app chrome).
|
||||
// Uses the same Tokyo Night bg with slightly warmer foreground for readability.
|
||||
const LIGHT_THEME: ITheme = {
|
||||
background: "#1a1b26",
|
||||
foreground: "#c8d3f5",
|
||||
cursor: "#c8d3f5",
|
||||
selectionBackground: "#2f3549",
|
||||
black: "#1a1b26",
|
||||
red: "#ff757f",
|
||||
green: "#c3e88d",
|
||||
yellow: "#ffc777",
|
||||
blue: "#82aaff",
|
||||
magenta: "#c099ff",
|
||||
cyan: "#86e1fc",
|
||||
white: "#c8d3f5",
|
||||
brightBlack: "#545c7e",
|
||||
brightRed: "#ff757f",
|
||||
brightGreen: "#c3e88d",
|
||||
brightYellow: "#ffc777",
|
||||
brightBlue: "#82aaff",
|
||||
brightMagenta: "#c099ff",
|
||||
brightCyan: "#86e1fc",
|
||||
brightWhite: "#e4f0fb",
|
||||
};
|
||||
|
||||
/**
|
||||
* Read the semantic terminal CSS vars and build an xterm.js ITheme.
|
||||
* Falls back to a neutral dark palette if vars are not yet applied.
|
||||
*/
|
||||
function getTerminalTheme(): ITheme {
|
||||
return document.documentElement.classList.contains("dark")
|
||||
? DARK_THEME
|
||||
: LIGHT_THEME;
|
||||
const style = getComputedStyle(document.documentElement);
|
||||
|
||||
const hslToHex = (hslValue: string): string | undefined => {
|
||||
if (!hslValue?.trim()) return undefined;
|
||||
// Parse "H S% L%" format from CSS var
|
||||
const parts = hslValue.trim().split(/\s+/);
|
||||
if (parts.length < 3) return undefined;
|
||||
const h = Number.parseFloat(parts[0]);
|
||||
const s = Number.parseFloat(parts[1]) / 100;
|
||||
const l = Number.parseFloat(parts[2]) / 100;
|
||||
|
||||
const a = s * Math.min(l, 1 - l);
|
||||
const f = (n: number) => {
|
||||
const k = (n + h / 30) % 12;
|
||||
const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
|
||||
return Math.round(255 * color)
|
||||
.toString(16)
|
||||
.padStart(2, "0");
|
||||
};
|
||||
return `#${f(0)}${f(8)}${f(4)}`;
|
||||
};
|
||||
|
||||
const bg =
|
||||
hslToHex(style.getPropertyValue("--terminal-background")) ?? "#1a1b26";
|
||||
const fg =
|
||||
hslToHex(style.getPropertyValue("--terminal-foreground")) ?? "#c0caf5";
|
||||
|
||||
const isDark = document.documentElement.classList.contains("dark");
|
||||
|
||||
return {
|
||||
background: bg,
|
||||
foreground: fg,
|
||||
cursor: fg,
|
||||
selectionBackground: isDark ? "#33467c" : "#2f3549",
|
||||
black: bg,
|
||||
red: isDark ? "#f7768e" : "#ff757f",
|
||||
green: isDark ? "#9ece6a" : "#c3e88d",
|
||||
yellow: isDark ? "#e0af68" : "#ffc777",
|
||||
blue: isDark ? "#7aa2f7" : "#82aaff",
|
||||
magenta: isDark ? "#bb9af7" : "#c099ff",
|
||||
cyan: isDark ? "#7dcfff" : "#86e1fc",
|
||||
white: fg,
|
||||
brightBlack: isDark ? "#414868" : "#545c7e",
|
||||
brightRed: isDark ? "#f7768e" : "#ff757f",
|
||||
brightGreen: isDark ? "#9ece6a" : "#c3e88d",
|
||||
brightYellow: isDark ? "#e0af68" : "#ffc777",
|
||||
brightBlue: isDark ? "#7aa2f7" : "#82aaff",
|
||||
brightMagenta: isDark ? "#bb9af7" : "#c099ff",
|
||||
brightCyan: isDark ? "#7dcfff" : "#86e1fc",
|
||||
brightWhite: fg,
|
||||
};
|
||||
}
|
||||
|
||||
type TerminalDataPayload = {
|
||||
|
||||
@@ -90,7 +90,7 @@ export function TerminalPanel({ channelId, isOpen }: TerminalPanelProps) {
|
||||
onPointerDown={handleResizeStart}
|
||||
>
|
||||
{/* Terminal content */}
|
||||
<div className="min-h-0 flex-1 bg-[#1a1b26] p-2">
|
||||
<div className="min-h-0 flex-1 bg-terminal p-2">
|
||||
<TerminalInstance channelId={channelId} isVisible={isOpen} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -258,6 +258,10 @@ export function createThemeVars(
|
||||
"--status-deleted": accentRed,
|
||||
"--status-modified": accentOrange,
|
||||
|
||||
// Terminal
|
||||
"--terminal-background": hexToHsl(syntaxBg),
|
||||
"--terminal-foreground": hexToHsl(syntaxFg),
|
||||
|
||||
// Warning
|
||||
"--ui-warning": accentOrange,
|
||||
"--ui-warning-bg": overlay(accentOrange, isDark ? 0.1 : 0.08),
|
||||
|
||||
@@ -45,6 +45,10 @@ export default {
|
||||
border: "hsl(var(--border))",
|
||||
input: "hsl(var(--input))",
|
||||
ring: "hsl(var(--ring))",
|
||||
terminal: {
|
||||
DEFAULT: "hsl(var(--terminal-background))",
|
||||
foreground: "hsl(var(--terminal-foreground))",
|
||||
},
|
||||
sidebar: {
|
||||
DEFAULT: "hsl(var(--sidebar-background))",
|
||||
foreground: "hsl(var(--sidebar-foreground))",
|
||||
|
||||
Reference in New Issue
Block a user