feat: custom terminal background image + theme editor hardening

- settings: backgroundImage/backgroundImageOpacity (10..100, default 60)
- main: otimg:// protocol serves only the configured background file
  (path-allowlisted, 403 otherwise); dev http origin cannot load file:
- TerminalView: allowTransparency + transparent theme background while an
  image is set; .term-bg-image layer behind the xterm surface
- terminal.css: .has-bg-image keeps .xterm-viewport transparent — the old
  chrome-bg pin covered the image layer (root cause of image not showing)
- ThemeSettingsTab: image picker + opacity slider
- ThemeEditor: duplicate-name hint now covers builtin names too; seed
  colors normalized to #rrggbb
- settingsStore: sanitize theme colors, reject non-hex values
This commit is contained in:
Bill committed 2026-09-20 23:24:43 +08:00
1 parent c94e0fbac7
commit 481f54ed59
13 files changed
+187 -17

No files matched your search

+7 -3
View File
@@ -138,11 +138,15 @@ function sanitizeThemes(value: unknown, warnings: Warnings): TerminalTheme[] {
: null
const colors: ThemeColors = { ...DEFAULT_DARK.colors }
const target = colors as unknown as Record<string, string>
const HEX_COLOR = /^#(?:[0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i
for (const key of THEME_COLOR_KEYS) {
const color = candidate?.[key]
if (typeof color === 'string' && color !== '') target[key] = color
else if (color !== undefined) {
warnings.push(`customThemes[${index}].colors.${key} repaired → built-in default`)
// Only well-formed hex colours survive: xterm would render anything else
// as black, and the theme editor's native colour input needs #rrggbb.
if (typeof color === 'string' && HEX_COLOR.test(color.trim())) {
target[key] = color.trim()
} else if (color !== undefined) {
warnings.push(`customThemes[${index}].colors.${key}: not a hex color — repaired`)
}
}
themes.push({