feat(web): add install metadata

This commit is contained in:
Tianyi Cui
2026-08-06 23:00:01 +08:00
parent d67116eb8c
commit 8f2168303b
21 changed files with 305 additions and 24 deletions
@@ -1,10 +1,11 @@
/**
* Global theme DOM applier: projects the resolved ThemeSnapshot onto the
* document — `html { color-scheme }` for native UA chrome (scrollbars, form
* controls), `body[data-ds-dark-theme]` for the token palette, and the active
* theme's alias-token overrides as inline CSS variables on body. Pure DOM
* writes, no React involvement; the presenter only ever retracts what it wrote
* itself, so foreign attributes and inline styles survive apply/dispose.
* controls), `body[data-ds-dark-theme]` for the token palette, the active
* theme's alias-token overrides as inline CSS variables on body, and one
* presenter-owned `meta[name="theme-color"]` for surrounding browser UI. Pure
* DOM writes, no React involvement; the presenter only ever retracts what it
* wrote itself, so foreign attributes, metadata, and inline styles survive.
*/
import type { ThemeSnapshot } from '@deepseek-ai/dsh-client-ui-theme/client'
@@ -15,12 +16,22 @@ export const DARK_ATTRIBUTE = 'data-ds-dark-theme'
export class ThemePresenter {
/** Token names this presenter wrote in the last apply (its retraction set). */
private appliedTokens: string[] = []
/** The single metadata node this presenter inserts and removes. */
private readonly themeColorMeta: HTMLMetaElement
/** Create the presenter-owned metadata node before the first snapshot arrives. */
constructor() {
this.themeColorMeta = document.createElement('meta')
this.themeColorMeta.name = 'theme-color'
}
/**
* Project a snapshot onto the document: set root `color-scheme` and the body
* palette attribute from `active.colorScheme` (never the id — `system` is
* resolved upstream), then replace the previously applied token variables
* with `active.tokens`.
* with `active.tokens`. Browser theme-color metadata follows the computed
* body background after those writes, so the rendered palette remains the
* color authority.
* @param snapshot - resolved theme snapshot from ctx.theme.
*/
apply(snapshot: ThemeSnapshot): void {
@@ -35,14 +46,17 @@ export class ThemePresenter {
body.style.setProperty(name, value)
this.appliedTokens.push(name)
}
this.themeColorMeta.content = getComputedStyle(body).backgroundColor
if (!this.themeColorMeta.isConnected) document.head.append(this.themeColorMeta)
}
/** Retract everything this presenter wrote: root color-scheme, the palette attribute, and all applied token variables. */
/** Retract root color-scheme, the palette attribute, token variables, and the owned metadata node. */
dispose(): void {
document.documentElement.style.removeProperty('color-scheme')
const body = document.body
body.removeAttribute(DARK_ATTRIBUTE)
for (const name of this.appliedTokens) body.style.removeProperty(name)
this.appliedTokens = []
this.themeColorMeta.remove()
}
}