|
(function () { |
|
const LIGHT_THEME = { |
|
'name': 'GitHub Light (Primer)', |
|
'canvas': { |
|
'foreground': '#1f2328', |
|
'background': '#ffffff' |
|
}, |
|
'cursor': { |
|
'background': 'rgba(31,35,40,0.5)' |
|
}, |
|
'palette': { |
|
'black': '#1f2328', |
|
'red': '#a40e26', // a40e26 cf222e fa4549 ff8182 |
|
'green': '#2da44e', // 1a7f37 2da44e 4ac26b 6fdd8b |
|
'yellow': '#d4a72c', // 9a6700 bf8700 d4a72c eac54f |
|
'blue': '#0969da', |
|
'magenta': '#8250df', |
|
'cyan': '#3192aa', // 1b7c83 3192aa 6cb6ff |
|
'white': '#c9d1d9', // d0d7de eaeef2 |
|
'brightBlack': '#30363d', |
|
'brightRed': '#cf222e', |
|
'brightGreen': '#4ac26b', |
|
'brightYellow': '#eac54f', |
|
'brightBlue': '#2188ff', |
|
'brightMagenta': '#a475e6', |
|
'brightCyan': '#35adb9', |
|
'brightWhite': '#f6f8fa', |
|
} |
|
}; |
|
|
|
const DARK_THEME = { |
|
'name': 'GitHub Dark (Primer)', |
|
'canvas': { |
|
'foreground': '#c9d1d9', |
|
'background': '#0d1117' |
|
}, |
|
'cursor': { |
|
'background': 'rgba(201,209,217,0.5)' |
|
}, |
|
'palette': { |
|
'black': '#161b22', |
|
'red': '#da3633', |
|
'green': '#2ea043', |
|
'yellow': '#bf8700', |
|
'blue': '#388bfd', |
|
'magenta': '#a371f7', |
|
'cyan': '#39c5cf', |
|
'white': '#d0d7de', // c9d1d9 e6edf3 |
|
'brightBlack': '#30363d', |
|
'brightRed': '#f85149', |
|
'brightGreen': '#3fb950', |
|
'brightYellow': '#d29922', |
|
'brightBlue': '#58a6ff', |
|
'brightMagenta': '#bc8cff', |
|
'brightCyan': '#56d4dd', |
|
'brightWhite': '#f0f6fc', |
|
} |
|
}; |
|
|
|
const ANSI16_ORDERED_KEYS = [ |
|
'black', |
|
'red', |
|
'green', |
|
'yellow', |
|
'blue', |
|
'magenta', |
|
'cyan', |
|
'white', |
|
'brightBlack', |
|
'brightRed', |
|
'brightGreen', |
|
'brightYellow', |
|
'brightBlue', |
|
'brightMagenta', |
|
'brightCyan', |
|
'brightWhite' |
|
] |
|
|
|
const cssSupports = (typeof CSS !== 'undefined' && typeof CSS.supports === 'function') |
|
? CSS.supports.bind(CSS) |
|
: null |
|
const _probeEl = typeof document !== 'undefined' && document.createElement |
|
? document.createElement('span') |
|
: null |
|
|
|
function isColor(value) { |
|
if (typeof value !== 'string') return false |
|
const s = value.trim() |
|
if (!s) return false |
|
|
|
// Prefer CSS.supports if available |
|
if (cssSupports) return cssSupports('color', s) |
|
|
|
// Fallback: assign to a style property and check whether it “sticks” |
|
if (_probeEl) { |
|
_probeEl.style.color = '' |
|
_probeEl.style.color = s |
|
return _probeEl.style.color !== '' |
|
} |
|
|
|
return false |
|
} |
|
|
|
function buildPaletteArray(paletteObj) { |
|
// Canonical ANSI16 order as required by hterm/Blink. |
|
return ANSI16_ORDERED_KEYS.map((k) => paletteObj[k]) |
|
} |
|
|
|
function validateTheme(theme) { |
|
if (!theme || typeof theme !== 'object') return 'theme is missing' |
|
if (!theme.canvas || typeof theme.canvas !== 'object') return 'canvas is missing' |
|
if (!theme.cursor || typeof theme.cursor !== 'object') return 'cursor is missing' |
|
if (!theme.palette || typeof theme.palette !== 'object') return 'palette is missing' |
|
|
|
if (!isColor(theme.canvas.background)) return 'canvas.background is invalid' |
|
if (!isColor(theme.canvas.foreground)) return 'canvas.foreground is invalid' |
|
if (!isColor(theme.cursor.background)) return 'cursor.background is invalid' |
|
|
|
for (const k of ANSI16_ORDERED_KEYS) { |
|
if (!isColor(theme.palette[k])) return `palette.${k} is invalid` |
|
} |
|
|
|
return null |
|
} |
|
|
|
function applyTheme(theme) { |
|
const themeName = |
|
theme && typeof theme.name === 'string' ? theme.name : 'Theme' |
|
|
|
const term = |
|
typeof t !== 'undefined' |
|
? t |
|
: typeof window !== 'undefined' |
|
? window.t |
|
: undefined |
|
|
|
if (!term || !term.prefs_ || typeof term.prefs_.set !== 'function') { |
|
console.error(`${themeName} error: terminal preferences API is unavailable.`) |
|
return |
|
} |
|
|
|
const problem = validateTheme(theme) |
|
if (problem) { |
|
console.error(`${themeName} error: ${problem}; aborting.`) |
|
return |
|
} |
|
|
|
const paletteArray = buildPaletteArray(theme.palette) |
|
|
|
try { |
|
term.prefs_.set('color-palette-overrides', paletteArray) |
|
term.prefs_.set('background-color', theme.canvas.background) |
|
term.prefs_.set('foreground-color', theme.canvas.foreground) |
|
term.prefs_.set('cursor-color', theme.cursor.background) |
|
} catch (err) { |
|
console.error(`${themeName} error:`, err) |
|
} |
|
} |
|
|
|
function setupTheme() { |
|
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') { |
|
console.error('Theme error: matchMedia is unavailable; aborting.') |
|
return |
|
} |
|
|
|
const mq = window.matchMedia('(prefers-color-scheme: dark)') |
|
|
|
const apply = (e) => { |
|
const isDark = e && typeof e.matches === 'boolean' ? e.matches : mq.matches |
|
applyTheme(isDark ? DARK_THEME : LIGHT_THEME) |
|
} |
|
|
|
apply() |
|
|
|
if (typeof mq.addEventListener === 'function') { |
|
mq.addEventListener('change', apply) |
|
} else if (typeof mq.addListener === 'function') { |
|
mq.addListener(apply) |
|
} else { |
|
console.warn( 'Theme warning: neither addEventListener nor addListener' |
|
+ ' are available; dynamic appearance switch will not be supported.' |
|
) |
|
} |
|
} |
|
|
|
setupTheme() |
|
})() |