read the shell prompt again and stop the reconnect loop
The terminal was the last surface in the chat tool panel still wearing someone else's design system, and it had two defects underneath that. The font stack named no Nerd Font, so the private-use glyphs a default zsh prompt draws its separators and branch marks from rendered as notdef boxes. The ~ and the path after it drew fine, which is what made it read as a font bug rather than a missing-glyph one. Both components also carried their own copy of the palette -- four themes in one, fifteen in the other, drifting, defaulting to a near-black that appears nowhere in the token set. Changing --code-bg did nothing to the terminal because the terminal never read a token. They now share one module built from the tokens, so an error in the terminal is the same red as an error anywhere else. TerminalView reconnected on a bare setTimeout with no attempt cap and no error surface, retrying invisibly every three seconds forever against an unreachable backend. It now shares the panel's cap of three and renders the same retry affordance, counting down again once a session is created. Also drops a dead ws.onopen assignment and a 21px padding that was on no spacing scale, and records what the chat page still owes the prototype.
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
import type { ITheme } from "@xterm/xterm";
|
||||
|
||||
/**
|
||||
* 终端配色与字体。
|
||||
*
|
||||
* xterm 的 ITheme 只接受 hex / rgba 字符串,拿不到 CSS 自定义属性,所以这里的
|
||||
* 色值是从 variables.scss 的 OKLCH 令牌换算而来的,改令牌时必须同步改这里。
|
||||
* 换算关系(oklch → sRGB)见 docs 里的对照表,不要凭肉眼调色。
|
||||
*
|
||||
* CYBER 默认配色沿用三色语义:
|
||||
* 青 = 系统本体(光标 / 选区 / dim 之外的强调)
|
||||
* 绿 = 机器在动(目录 / 链接)
|
||||
* 橙 = 需要你介入(提示 / 可执行文件)
|
||||
* ANSI 16 色沿用 One Dark 的色相做基底,只把 background / foreground / cursor
|
||||
* 换成 CYBER 的深底与霓虹青,保证终端落进页面时不显得是另一个产品。
|
||||
*/
|
||||
|
||||
// ─── Font ────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Nerd Font 必须排在等宽字体之前。默认 shell(zsh 的 powerlevel10k / oh-my-zsh)
|
||||
* 会输出 U+E0A0–U+E0D4 段的私有区字形(分支、箭头、分隔符),普通等宽字体没有
|
||||
* 这些字形,浏览器会画成豆腐块。缺这一段时提示符会整片糊掉。
|
||||
*/
|
||||
export const TERMINAL_FONT_FAMILY = [
|
||||
"ui-monospace",
|
||||
"'JetBrains Mono'",
|
||||
"'JetBrainsMono Nerd Font'",
|
||||
"'Nerd Font'",
|
||||
"'SF Mono'",
|
||||
"Menlo",
|
||||
"'Cascadia Code'",
|
||||
"'MesloLGS NF'",
|
||||
"'Hack Nerd Font'",
|
||||
"monospace",
|
||||
].join(", ");
|
||||
|
||||
// ─── Themes ──────────────────────────────────────────────────────
|
||||
|
||||
export interface TerminalThemeEntry {
|
||||
label: string;
|
||||
theme: ITheme;
|
||||
}
|
||||
|
||||
const CYBER: ITheme = {
|
||||
// oklch(0.105 0.012 252) → #020407,与 $bg-input 同源:终端是凹陷区
|
||||
background: "#020407",
|
||||
// oklch(0.860 0.008 210) → #cbd2d4
|
||||
foreground: "#cbd2d4",
|
||||
// oklch(0.805 0.148 188) → #00ddd1,与全局主色同值
|
||||
cursor: "#00ddd1",
|
||||
cursorAccent: "#020407",
|
||||
selectionBackground: "rgba(0, 221, 209, 0.30)",
|
||||
black: "#020407",
|
||||
// 语义色直接映射,终端里的报错 / 提示与页面读起来是同一套语言
|
||||
red: "#f05a5e", // oklch(0.665 0.185 22) → --error
|
||||
green: "#ade74e", // oklch(0.860 0.190 128) → --success
|
||||
yellow: "#f7a232", // oklch(0.780 0.155 68) → --warning
|
||||
blue: "#5fa5de", // oklch(0.700 0.110 245) → --accent-info
|
||||
magenta: "#c678dd",
|
||||
// 青色让位给 neon cyan:ANSI cyan 太暗,跟主色抢不到注意力
|
||||
cyan: "#3f8fa8",
|
||||
white: "#98a2a7", // oklch(0.705 0.014 230) → --text-muted
|
||||
brightBlack: "#626a70", // oklch(0.520 0.014 236) → --text-faint
|
||||
brightRed: "#ff7b7e",
|
||||
brightGreen: "#c9f56d",
|
||||
brightYellow: "#ffbe5c",
|
||||
brightBlue: "#84c2f0",
|
||||
brightMagenta: "#d9a2e8",
|
||||
brightCyan: "#00ddd1",
|
||||
brightWhite: "#e8eeee", // oklch(0.945 0.006 200) → --text-primary
|
||||
};
|
||||
|
||||
const TOKYO_NIGHT: ITheme = {
|
||||
background: "#1a1b26",
|
||||
foreground: "#a9b1d6",
|
||||
cursor: "#c0caf5",
|
||||
cursorAccent: "#1a1b26",
|
||||
selectionBackground: "rgba(192, 202, 245, 0.2)",
|
||||
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",
|
||||
};
|
||||
|
||||
const GITHUB_DARK: ITheme = {
|
||||
background: "#0d1117",
|
||||
foreground: "#c9d1d9",
|
||||
cursor: "#58a6ff",
|
||||
cursorAccent: "#0d1117",
|
||||
selectionBackground: "rgba(88, 166, 255, 0.25)",
|
||||
black: "#484f58",
|
||||
red: "#ff7b72",
|
||||
green: "#7ee787",
|
||||
yellow: "#ffa657",
|
||||
blue: "#79c0ff",
|
||||
magenta: "#d2a8ff",
|
||||
cyan: "#a5d6ff",
|
||||
white: "#c9d1d9",
|
||||
brightBlack: "#6e7681",
|
||||
brightRed: "#ffa198",
|
||||
brightGreen: "#56d364",
|
||||
brightYellow: "#e3b341",
|
||||
brightBlue: "#58a6ff",
|
||||
brightMagenta: "#bc8cff",
|
||||
brightCyan: "#79c0ff",
|
||||
brightWhite: "#f0f6fc",
|
||||
};
|
||||
|
||||
/**
|
||||
* CYBER 是唯一的品牌主题,放在首位并作为默认值。
|
||||
* 其余主题是用户自选,不参与品牌表达。
|
||||
*/
|
||||
export const TERMINAL_THEMES: Record<string, TerminalThemeEntry> = {
|
||||
cyber: { label: "CYBER", theme: CYBER },
|
||||
"tokyo-night": { label: "Tokyo Night", theme: TOKYO_NIGHT },
|
||||
"github-dark": { label: "GitHub Dark", theme: GITHUB_DARK },
|
||||
};
|
||||
|
||||
export const DEFAULT_TERMINAL_THEME = "cyber";
|
||||
|
||||
export function getTerminalTheme(name: string): ITheme {
|
||||
return TERMINAL_THEMES[name]?.theme ?? CYBER;
|
||||
}
|
||||
|
||||
export function terminalThemeOptions(): { label: string; value: string }[] {
|
||||
return Object.entries(TERMINAL_THEMES).map(([value, entry]) => ({
|
||||
label: entry.label,
|
||||
value,
|
||||
}));
|
||||
}
|
||||
Reference in New Issue
Block a user