Files
deepseek-harness/packages/client/ui-theme/src/boot-theme.ts
T
Turtle 849e9ebd8d feat(client): configure text, code, and terminal fonts and sizes independently
The General font-size row gains a More font settings disclosure that expands
a font field for each of text, code, and the sidebar terminal, plus code
(10-16 px) and terminal (10-20 px) size steppers. Font lists are normalized,
stored in the ui-theme namespace, embedded by the boot script, and placed
ahead of each role's built-in stack; the code size moves the code typography
tokens; the terminal applies font and size live and refits without replacing
the shell. ThemeRuntime adopts Host sections only after its own writes settle.

Refs #5217
2026-10-08 10:26:16 +08:00

65 lines
3.1 KiB
TypeScript

/**
* Theme bootstrap row for the browser's pre-plugin interval. Each index
* render embeds the current durable built-in preference, font sizes, and
* font-family lists. Head CSS colors the document canvas before script
* execution; the body script installs the palette selector and font variables
* that the client presenters adopt.
*/
import type { IndexInjection } from '@deepseek-ai/dsh-host-webserver'
import {
DEFAULT_FONT_SIZES, DEFAULT_PREFERENCE, FONT_ROLES, FONT_SIZE_SPECS, fontFamilyVariable, normalizeFontFamily,
type FontFamilies, type FontSizes, type ThemePreference,
} from './theme-settings.ts'
const LIGHT_BACKGROUND = '#fff'
const DARK_BACKGROUND = '#151517'
/** CSS that colors the document canvas before any script executes. */
function bootThemeStyle(preference: ThemePreference): string {
const light = `:root{color-scheme:light}body{background-color:${LIGHT_BACKGROUND};--dsh-boot-bg:${LIGHT_BACKGROUND}}`
const dark = `:root{color-scheme:dark}body{background-color:${DARK_BACKGROUND};--dsh-boot-bg:${DARK_BACKGROUND}}`
if (preference === 'light') return light
if (preference === 'dark') return dark
return `${light}@media(prefers-color-scheme:dark){${dark}}`
}
/** Build the body script that installs the palette selector and font variables. */
function bootThemeBodyScript(preference: ThemePreference, fontSizes: FontSizes, fontFamilies: FontFamilies): string {
const sizes = FONT_ROLES.map(role =>
`\n document.body.style.setProperty(${JSON.stringify(FONT_SIZE_SPECS[role].variable)}, ${JSON.stringify(`${fontSizes[role]}px`)})`).join('')
const families = FONT_ROLES.flatMap((kind) => {
const list = normalizeFontFamily(fontFamilies[kind])
return list === '' ? [] : [`\n document.body.style.setProperty(${JSON.stringify(fontFamilyVariable(kind))}, ${JSON.stringify(list)})`]
}).join('')
return `(() => {
const preference = ${JSON.stringify(preference)}
const systemDark = preference === 'system'
&& typeof matchMedia !== 'undefined'
&& matchMedia('(prefers-color-scheme: dark)').matches
const dark = preference === 'dark' || systemDark
document.documentElement.dataset.dsThemeSource = preference
document.body.toggleAttribute('data-ds-dark-theme', dark)${sizes}${families}
})()`
}
/**
* Theme bootstrap rows: head CSS colors the document canvas before
* first paint, then the body script installs the palette selector and font
* size and font families before the shell mount and module script.
* @param preference - Current Host-backed built-in preference.
* @param fontSizes - Current Host-backed font sizes in px by role.
* @param fontFamilies - Current Host-backed font lists; each is normalized before embedding.
* @returns head and body script rows in execution order.
*/
export function bootThemeInjections(
preference: ThemePreference = DEFAULT_PREFERENCE,
fontSizes: FontSizes = DEFAULT_FONT_SIZES,
fontFamilies: FontFamilies = { text: '', code: '', terminal: '' },
): IndexInjection[] {
return [
{ kind: 'style', text: bootThemeStyle(preference) },
{ kind: 'script', placement: 'body', text: bootThemeBodyScript(preference, fontSizes, fontFamilies) },
]
}