deepseek-harness-background 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -3
- package/README.zh.md +11 -3
- package/lib/client.js +1264 -101
- package/lib/client.js.map +1 -1
- package/lib/index.js +78 -31
- package/package.json +86 -88
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["useState","useRef","css","useSyncExternalStore","useCallback"],"sources":["../src/client/background-css.ts","../src/settings.ts","../src/client/backdrop.ts","../src/client/locales.ts","../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs","../src/client/settings-client.ts","../src/client/SettingsRow.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * Background CSS — the stylesheet injected once into the document when the\n * plugin first runs. It defines the behind-body wallpaper layer, the scrim,\n * and the frosted-glass panels, all driven by CSS variables the painter writes\n * onto `document.body`. Kept in a single idempotent `<style data-plugin-css>`\n * tag (mirrors the reference `dsh-wallpaper-engine` bundle).\n */\n\n/** Unique id stamped on the injected style element (dedup key). */\nexport const BACKGROUND_CSS_TAG = 'deepseek-harness-background/styles'\n\n/** Body attribute the painter sets while a wallpaper is active. */\nexport const ACTIVE_ATTR = 'data-dsh-bg'\n\n/**\n * The backdrop CSS. The wallpaper is a fixed `z-index:-2` element (below the\n * scrim at `-1`, below the UI). While active, the official surface tokens are\n * made transparent (so the wallpaper shows through every column) and the\n * opaque input / bubble surfaces turn into translucent frosted glass.\n * Selectors target authored attributes (`data-dsh-bg`, `data-composer-card`)\n * and CSS-module SUFFIX conventions (`_bubble`) — the same stable anchors the\n * reference engine uses, since hashed prefixes change across shell rebuilds.\n */\nexport const BACKGROUND_CSS = `\n .dsh-bg-layer {\n position: fixed; inset: 0; z-index: -2; overflow: hidden; pointer-events: none;\n }\n .dsh-bg-layer .dsh-bg-image {\n width: 100%; height: 100%; display: block; border: 0; background: transparent;\n object-fit: var(--bg-object-fit, cover);\n opacity: var(--bg-opacity, 1);\n filter: blur(var(--bg-wallpaper-blur, 0px));\n /* Blur thins the edges; scale the image up to hide the fringe. */\n transform: scale(var(--bg-wallpaper-scale, 1));\n transform-origin: center;\n }\n /* Scrim is theme-aware: a WHITE veil in the light scheme (it lifts the art\n toward the near-white surface so dark text keeps contrast) and a BLACK veil\n in the dark scheme (it dims the art so light text keeps contrast). */\n .dsh-bg-scrim {\n position: fixed; inset: 0; z-index: -1; pointer-events: none;\n background: rgba(255, 255, 255, var(--bg-scrim, 0.25));\n }\n body[data-ds-dark-theme] .dsh-bg-scrim {\n background: rgba(0, 0, 0, var(--bg-scrim, 0.25));\n }\n\n /* Active: make the app frame + sidebar background transparent so all columns\n share the same wallpaper + scrim backdrop. */\n body[data-dsh-bg] {\n --dsw-alias-bg-base: transparent;\n --dsw-specific-sidebar-fill: transparent;\n }\n\n /* Frosted glass over the opaque conversation surfaces (composer + bubbles).\n The surface translucency is driven by --dsw-specific-input-major /\n --dsw-specific-bubble, which the painter writes (theme-aware) so that a\n fully-opaque panel restores the official surfaces. The blur here comes\n from --bg-glass-blur; a faint top-weighted specular sheen makes the\n translucent surfaces read as wet glass. */\n body[data-dsh-bg] [data-composer-card],\n body[data-dsh-bg] [class*=\"_bubble\"] {\n background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.16), rgba(255, 255, 255, 0.05) 38%, rgba(255, 255, 255, 0.02));\n -webkit-backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.6)) brightness(var(--bg-glass-brightness, 1.04)) contrast(1.01);\n backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.6)) brightness(var(--bg-glass-brightness, 1.04)) contrast(1.01);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, var(--bg-glass-highlight, 0.32)),\n inset 0 -1px 0 rgba(255, 255, 255, 0.08),\n inset 0 0 0 0.5px rgba(255, 255, 255, 0.08),\n 0 12px 40px rgba(0, 0, 0, var(--bg-glass-shadow, 0.12));\n }\n`\n\n/**\n * Inject the backdrop stylesheet once. Safe to call repeatedly; a second call\n * is a no-op (dedup key on the style tag).\n */\nexport function injectBackgroundCss(): void {\n if (document.querySelector(`style[data-plugin-css=\"${BACKGROUND_CSS_TAG}\"]`)) return\n const tag = document.createElement('style')\n tag.dataset.plugin = 'deepseek-harness-background'\n tag.dataset.pluginCss = BACKGROUND_CSS_TAG\n tag.textContent = BACKGROUND_CSS\n document.head.appendChild(tag)\n}\n","/** Durable background settings — pure constants/types shared by both halves. */\r\n\r\n/** Settings namespace owned by the background plugin. */\r\nexport const BACKGROUND_SETTINGS_NAMESPACE = 'ui-background'\r\n\r\n/**\r\n * The schema's field names, in schema order. Used as a whitelist when a\r\n * section write commits: the settings layer keeps unknown keys in the user\r\n * document (a legacy schema field would linger forever under a merge-only\r\n * write), so the write path strips everything outside this list.\r\n */\r\nexport const BACKGROUND_SETTINGS_FIELDS = [\r\n 'enabled', 'uploadId', 'url', 'opacity', 'scrim',\r\n 'panelOpacity', 'blur', 'wallpaperBlur', 'fit',\r\n] as const\r\n\r\n/** Browser-facing base path of the background API (shared with the host routes). */\r\nexport const BACKGROUND_API_PREFIX = '/api/bg-wallpaper'\r\n\r\n/** Minimum scrim opacity (0 = no veil at all). */\r\nexport const SCRIM_MIN = 0\r\n\r\n/** Maximum scrim opacity (a nearly opaque veil keeps text legible over any art). */\r\nexport const SCRIM_MAX = 0.95\r\n\r\n/** Default scrim strength applied over user art (a light readability veil). */\r\nexport const DEFAULT_SCRIM = 0.25\r\n\r\n/** Default background image opacity (1 = fully opaque). */\r\nexport const DEFAULT_OPACITY = 1\r\n\r\n/** Minimum background image opacity (0 = fully invisible). */\r\nexport const OPACITY_MIN = 0\r\n\r\n/** Maximum background image opacity (1 = fully opaque). */\r\nexport const OPACITY_MAX = 1\r\n\r\n/** Default panel opacity (0..1); 1 = fully opaque official surfaces, 0 = fully transparent glass. */\r\nexport const DEFAULT_PANEL_OPACITY = 0.15\r\n\r\n/** Minimum panel opacity. */\r\nexport const PANEL_OPACITY_MIN = 0\r\n\r\n/** Maximum panel opacity (opaque — effectively disables the glass). */\r\nexport const PANEL_OPACITY_MAX = 1\r\n\r\n/** Default frosted-glass blur radius in px (0 disables backdrop-filter). */\r\nexport const DEFAULT_BLUR = 16\r\n\r\n/** Minimum glass blur radius. */\r\nexport const BLUR_MIN = 0\r\n\r\n/** Maximum glass blur radius. */\r\nexport const BLUR_MAX = 40\r\n\r\n/** Default wallpaper blur radius in px (blurs the image itself). */\r\nexport const DEFAULT_WALLPAPER_BLUR = 0\r\n\r\n/** Maximum wallpaper blur radius. */\r\nexport const WALLPAPER_BLUR_MAX = 60\r\n\r\n/** Default background rendering mode. */\r\nexport const DEFAULT_FIT = 'cover'\r\n\r\n/** Image positioning modes. `cover` fills the frame (cropping as needed); `contain` fits the whole image inside the frame (letterboxing). */\r\nexport const FIT_MODES = ['cover', 'contain'] as const\r\n\r\n/** Background rendering mode. */\r\nexport type BackgroundFit = typeof FIT_MODES[number]\r\n\r\n/**\r\n * User-owned background section, resolved from schema defaults + user layer.\r\n * The active source is either a local upload id (host serves it via\r\n * `/api/bg-wallpaper/image/<id>`) or a raw HTTP(S) image URL the browser\r\n * loads; exactly one of `uploadId` / `url` is set — when both are empty no\r\n * background renders.\r\n */\r\nexport interface BackgroundSettings {\r\n /** Whether the custom background renders at all. */\r\n enabled: boolean\r\n /** Local upload id when the active source is an uploaded file. */\r\n uploadId: string\r\n /** Image URL when the active source is a remote URL. */\r\n url: string\r\n /** Background image opacity (0..1); the image fades toward the surface color. */\r\n opacity: number\r\n /** Readability scrim strength (0..1) layered between the art and the UI. */\r\n scrim: number\r\n /** Panel transparency (0..1): 0 = fully transparent surfaces, 1 = unaffected. */\r\n panelOpacity: number\r\n /** Frosted-glass blur radius on opaque surfaces (px; 0 disables). */\r\n blur: number\r\n /** Blur of the wallpaper image itself (px; 0 disables). */\r\n wallpaperBlur: number\r\n /** How the image fits the frame. */\r\n fit: BackgroundFit\r\n}\r\n","/**\n * Background painter — renders the user background behind the whole app frame:\n * a fixed `z-index:-2` wallpaper element plus a `z-index:-1` scrim on\n * `document.body`, driven by the `data-dsh-bg` body attribute and a set of\n * CSS variables. It also applies the frosted-glass surface tokens so the\n * wallpaper shows through translucent input / bubble panels.\n *\n * Retraction discipline mirrors the reference skin plugins: every property /\n * DOM node this painter owns is restored to its prior state on dispose, and\n * the `data-ds-dark-theme` observer is disconnected.\n */\n\nimport { ACTIVE_ATTR, injectBackgroundCss } from './background-css.ts'\nimport { BACKGROUND_API_PREFIX, type BackgroundSettings } from '../settings.ts'\n\n/** Class names the layer and scrim elements carry. */\nconst LAYER_CLASS = 'dsh-bg-layer'\nconst IMAGE_CLASS = 'dsh-bg-image'\nconst SCRIM_CLASS = 'dsh-bg-scrim'\n\n/** Surface tokens this painter overwrites (restored on dispose). */\nconst SURFACE_TOKENS = [\n '--dsw-specific-input-major',\n '--dsw-specific-bubble',\n] as const\n\n/** Fraction of the official white surface alpha kept at the most transparent panel setting. */\nconst GLASS_MIN_ALPHA = 0.05\n\n/**\n * Resolve the effective background image url for a section.\n * @param settings - resolved background section.\n * @returns the image url, or '' when no source is set.\n */\nexport function backgroundImageUrl(settings: BackgroundSettings, uploadBase: string): string {\n if (settings.uploadId) return `${uploadBase}/image/${settings.uploadId}`\n return settings.url\n}\n\n/**\n * Manage the behind-body wallpaper + scrim layers and the glass surface.\n */\nexport class BackgroundPainter {\n private layer: HTMLDivElement | null = null\n private img: HTMLImageElement | null = null\n private scrim: HTMLDivElement | null = null\n private observer: MutationObserver | undefined\n private active = false\n private settings: BackgroundSettings | undefined\n private readonly savedTokens = new Map<string, string>()\n private readonly savedVars = new Map<string, string>()\n\n /** Remember + hijack a property only once so dispose restores the original. */\n private rememberOnce(prop: string): void {\n if (this.savedTokens.has(prop) || this.savedVars.has(prop)) return\n const value = document.body.style.getPropertyValue(prop)\n if (SURFACE_TOKENS.includes(prop as (typeof SURFACE_TOKENS)[number])) {\n this.savedTokens.set(prop, value)\n } else {\n this.savedVars.set(prop, value)\n }\n }\n\n /**\n * Apply the latest settings. Idempotent.\n * @param settings - resolved background section.\n * @param uploadBase - the API base for resolving uploads.\n */\n apply(settings: BackgroundSettings, uploadBase: string): void {\n this.settings = settings\n if (!settings.enabled) {\n this.dispose()\n return\n }\n injectBackgroundCss()\n this.rememberOnce('--dsw-alias-bg-base')\n this.rememberOnce('--dsw-specific-sidebar-fill')\n document.body.style.setProperty('--dsw-alias-bg-base', 'transparent')\n document.body.style.setProperty('--dsw-specific-sidebar-fill', 'transparent')\n\n const url = backgroundImageUrl(settings, uploadBase)\n if (url === '') {\n // No source: leave the frame alone, restore the removed layers and any\n // glass-token overrides we may have written on a previous apply.\n this.applySurfaceGlass(settings, true)\n this.active = false\n this.removeLayers()\n document.body.removeAttribute(ACTIVE_ATTR)\n return\n }\n\n // Wallpaper layer + scrim.\n if (!this.layer) {\n this.layer = document.createElement('div')\n this.layer.className = LAYER_CLASS\n this.img = document.createElement('img')\n this.img.className = IMAGE_CLASS\n this.img.alt = ''\n this.layer.appendChild(this.img)\n document.body.appendChild(this.layer)\n }\n if (this.img && this.img.src !== url) this.img.src = url\n\n if (!this.scrim) {\n this.scrim = document.createElement('div')\n this.scrim.className = SCRIM_CLASS\n document.body.appendChild(this.scrim)\n }\n document.body.setAttribute(ACTIVE_ATTR, 'on')\n this.active = true\n\n // Push the knobs into CSS variables.\n const s = document.body.style\n this.setVar('--bg-object-fit', settings.fit)\n this.setVar('--bg-opacity', String(settings.opacity))\n this.setVar('--bg-wallpaper-blur', `${settings.wallpaperBlur}px`)\n this.setVar('--bg-wallpaper-scale', (1 + settings.wallpaperBlur * 0.006).toFixed(4))\n this.setVar('--bg-scrim', String(settings.scrim))\n this.setVar('--bg-glass-blur', `${settings.blur}px`)\n this.setVar('--bg-glass-saturate', String(1.15 + settings.blur * 0.03))\n\n // Glass surface: theme-aware translucent token (panelOpacity === 1 keeps\n // the official opaque surfaces and disables the blur).\n this.applySurfaceGlass(settings, false)\n\n // Theme observer: repaint the glass tokens when the light/dark scheme\n // flips (the surface translucency differs between schemes). Disconnects\n // on dispose.\n if (!this.observer) {\n this.observer = new MutationObserver(() => this.applySurfaceGlass(this.settings, false))\n this.observer.observe(document.body, { attributes: true, attributeFilter: ['data-ds-dark-theme'] })\n }\n }\n\n/** Write one owned CSS variable onto body. */\nprivate setVar(name: string, value: string): void {\n this.rememberOnce(name)\n document.body.style.setProperty(name, value)\n}\n\n/**\n * Update one effect knob without re-running the full apply. This is the hot\n * path for slider drags (many events per second): only the single CSS\n * variable changes, the DOM layers are untouched.\n * @param key - the knob to update.\n * @param value - its new value in its canonical unit.\n */\nsetKnob(key: 'opacity' | 'scrim' | 'blur' | 'wallpaperBlur' | 'fit', value: number | BackgroundSettings['fit']): void {\n if (this.settings === undefined || !this.settings.enabled) return\n switch (key) {\n case 'opacity':\n this.setVar('--bg-opacity', String(value))\n break\n case 'scrim':\n this.setVar('--bg-scrim', String(value))\n break\n case 'blur': {\n this.setVar('--bg-glass-blur', `${value}px`)\n this.setVar('--bg-glass-saturate', String(1.15 + Number(value) * 0.03))\n break\n }\n case 'wallpaperBlur': {\n this.setVar('--bg-wallpaper-blur', `${value}px`)\n this.setVar('--bg-wallpaper-scale', (1 + Number(value) * 0.006).toFixed(4))\n break\n }\n case 'fit':\n this.setVar('--bg-object-fit', String(value))\n break\n }\n}\n\n /**\n * Apply the translucent-glass surface tokens (or restore the official ones\n * when the panel is fully opaque / there is no background).\n * @param settings - resolved section (for panelOpacity).\n * @param forceRestore - true to restore official surfaces regardless (used\n * when no source is set, so leftover glass tokens never linger).\n */\n private applySurfaceGlass(settings: BackgroundSettings | undefined, forceRestore: boolean): void {\n const s = document.body.style\n const inDark = document.body.dataset.dsDarkTheme !== undefined\n // Always remember the original surface values so a restore / dispose\n // returns them cleanly.\n for (const token of SURFACE_TOKENS) this.rememberOnce(token)\n\n const restore = () => {\n for (const token of SURFACE_TOKENS) {\n const original = this.savedTokens.get(token)\n if (original !== undefined && original !== '') s.setProperty(token, original)\n else s.removeProperty(token)\n }\n }\n\n if (forceRestore || settings === undefined || settings.panelOpacity >= 1) {\n restore()\n // No blur when glass is off.\n this.setVar('--bg-glass-blur', '0px')\n return\n }\n\n // glassAlpha brightens from GLASS_MIN_ALPHA at opacity 0 toward 0.9 at\n // opacity 1. Dark scheme uses a lower white alpha (the wallpaper stays\n // visible without washing the surface), mirroring the reference engine.\n const alpha = GLASS_MIN_ALPHA + settings.panelOpacity * (0.9 - GLASS_MIN_ALPHA)\n const clamped = Math.max(0, Math.min(0.9, alpha))\n const factor = inDark ? 0.4 : 0.8\n s.setProperty('--dsw-specific-input-major', `rgba(255, 255, 255, ${(clamped * factor).toFixed(3)})`)\n s.setProperty('--dsw-specific-bubble', `rgba(255, 255, 255, ${(clamped * factor * 0.8).toFixed(3)})`)\n }\n\n /** Remove the wallpaper + scrim layers and clear the active attribute. */\n private removeLayers(): void {\n if (this.layer) { this.layer.remove(); this.layer = null; this.img = null }\n if (this.scrim) { this.scrim.remove(); this.scrim = null }\n }\n\n /** Restore every owned property and remove the layers. */\n dispose(): void {\n this.observer?.disconnect()\n this.observer = undefined\n this.removeLayers()\n const s = document.body.style\n document.body.removeAttribute(ACTIVE_ATTR)\n for (const [prop, value] of this.savedTokens) s.setProperty(prop, value)\n for (const [prop, value] of this.savedVars) s.setProperty(prop, value)\n this.savedTokens.clear()\n this.savedVars.clear()\n this.active = false\n this.settings = undefined\n }\n\n /** @returns whether a wallpaper is currently rendered. */\n isActive(): boolean {\n return this.active\n }\n}\n\n/** Module-level painter singleton shared by the settings row preview and the live apply. */\nexport const backgroundPainter = new BackgroundPainter()\n\n/**\n * Apply the given settings through the shared painter (idempotent). Convenience\n * used by the settings row for live previews and by the plugin apply to render\n * the persisted section.\n * @param settings - settings to apply (may be an unsaved draft for preview).\n */\nexport function paintBackground(settings: BackgroundSettings): void {\n backgroundPainter.apply(settings, BACKGROUND_API_PREFIX)\n}\n\n/** Numeric effect knobs the slider drag path repaints. */\nexport type BackgroundKnob = 'opacity' | 'scrim' | 'blur' | 'wallpaperBlur' | 'fit'\n\n/**\n * Update one effect knob on the live backdrop without re-running the full\n * apply — the hot path for slider drags (see BackgroundPainter.setKnob).\n * @param key - the knob to update.\n * @param value - its new value.\n */\nexport function paintBackgroundKnob(key: BackgroundKnob, value: number | BackgroundSettings['fit']): void {\n backgroundPainter.setKnob(key, value)\n}\n\n/** Preview variables the settings-surface preview card consumes. */\nconst PREVIEW_VARS = [\n '--bg-opacity', '--bg-scrim', '--bg-object-fit',\n '--bg-wallpaper-blur', '--bg-wallpaper-scale',\n '--bg-glass-blur', '--bg-glass-saturate', '--bg-preview-glass',\n] as const\n\n/**\n * Push the effect knobs onto one element (the settings-surface preview card)\n * so dragging a slider updates the card without touching the live backdrop.\n * The card's CSS reads the same variable names as the painter writes on body.\n * @param el - the preview element.\n * @param settings - the draft settings to render (may be unsaved).\n */\nexport function paintPreviewSurface(el: HTMLElement, settings: BackgroundSettings): void {\n const s = el.style\n s.setProperty('--bg-object-fit', settings.fit)\n s.setProperty('--bg-opacity', String(settings.opacity))\n s.setProperty('--bg-scrim', String(settings.scrim))\n s.setProperty('--bg-wallpaper-blur', `${settings.wallpaperBlur}px`)\n s.setProperty('--bg-wallpaper-scale', (1 + settings.wallpaperBlur * 0.006).toFixed(4))\n // The glass bubble mirrors the live panel surface: below panelOpacity 1 its\n // alpha follows the same theme-aware curve as --dsw-specific-bubble (so the\n // panel-opacity slider is visible in the preview); at 1 the official opaque\n // surface returns — the bubble turns opaque and the blur switches off, just\n // like applySurfaceGlass does on the real backdrop.\n const inDark = document.body.dataset.dsDarkTheme !== undefined\n if (settings.panelOpacity >= 1) {\n s.setProperty('--bg-glass-blur', '0px')\n s.setProperty('--bg-preview-glass', 'var(--dsw-alias-bg-layer-1)')\n return\n }\n s.setProperty('--bg-glass-blur', `${settings.blur}px`)\n s.setProperty('--bg-glass-saturate', String(1.15 + settings.blur * 0.03))\n const alpha = GLASS_MIN_ALPHA + settings.panelOpacity * (0.9 - GLASS_MIN_ALPHA)\n const clamped = Math.max(0, Math.min(0.9, alpha))\n const factor = inDark ? 0.4 : 0.8\n s.setProperty('--bg-preview-glass', `rgba(255, 255, 255, ${(clamped * factor * 0.8).toFixed(3)})`)\n}\n\n/** Remove every preview variable from an element (restores CSS defaults). */\nexport function clearPreviewSurface(el: HTMLElement): void {\n for (const name of PREVIEW_VARS) el.style.removeProperty(name)\n}\n","/** Locale dictionaries for the background plugin. */\n\nimport type { BackgroundCardLocaleKey } from './types.ts'\n\n/** Dictionary of the namespace this plugin owns. */\nexport type BackgroundCardDict = Record<BackgroundCardLocaleKey, string>\n\n/** Chinese copy. */\nexport const zh: BackgroundCardDict = {\n 'background.title': '自定义背景',\n 'background.description': '为整个应用界面设置背景图片,可调不透明度、遮罩、面板透明与毛玻璃模糊',\n 'background.upload': '上传图片',\n 'background.uploading': '上传中…',\n 'background.uploadMinetypes': '支持 JPG / PNG / WebP / GIF',\n 'background.urlPlaceholder': '或粘贴图片 http(s) 链接后回车',\n 'background.applyUrl': '应用链接',\n 'background.enabled': '背景已启用',\n 'background.source': '图片',\n 'background.effects': '效果',\n 'background.noPreview': '上传图片或粘贴链接后,此处实时预览效果',\n 'background.previewGlass': '毛玻璃',\n 'background.opacity': '不透明度',\n 'background.scrim': '遮罩',\n 'background.panelOpacity': '面板不透明度',\n 'background.blur': '毛玻璃模糊',\n 'background.wallpaperBlur': '壁纸模糊',\n 'background.fit': '填充方式',\n 'background.cover': '铺满',\n 'background.contain': '完整',\n 'background.clear': '清除背景',\n 'background.uploadFailed': '上传失败,请重试',\n 'background.saveFailed': '保存失败,请重试',\n}\n\n/** English copy. */\nexport const en: BackgroundCardDict = {\n 'background.title': 'Custom Background',\n 'background.description': 'Set a background image behind the whole app surface with adjustable opacity, scrim, panel transparency and glass blur',\n 'background.upload': 'Upload image',\n 'background.uploading': 'Uploading…',\n 'background.uploadMinetypes': 'JPG / PNG / WebP / GIF',\n 'background.urlPlaceholder': 'Or paste an image http(s) link and press Enter',\n 'background.applyUrl': 'Apply URL',\n 'background.enabled': 'Background on',\n 'background.source': 'Image',\n 'background.effects': 'Effects',\n 'background.noPreview': 'Upload an image or paste a link to preview live here',\n 'background.previewGlass': 'Glass',\n 'background.opacity': 'Opacity',\n 'background.scrim': 'Scrim',\n 'background.panelOpacity': 'Panel opacity',\n 'background.blur': 'Glass blur',\n 'background.wallpaperBlur': 'Wallpaper blur',\n 'background.fit': 'Fit',\n 'background.cover': 'Cover',\n 'background.contain': 'Contain',\n 'background.clear': 'Clear background',\n 'background.uploadFailed': 'Upload failed, try again',\n 'background.saveFailed': 'Save failed, try again',\n}\n","function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;","/**\n * Background settings transport — reads and writes the `ui-background`\n * section, and uploads local images, through the plugin's own same-origin\n * HTTP routes (see src/routes.ts). A custom route family keeps the section\n * usable even though the api-proxy settings allowlist does not expose\n * third-party namespaces over the settings RPC. One module-level client\n * serves the painter and the settings row.\n */\n\nimport type { BackgroundSettings } from '../settings.ts'\nimport { BACKGROUND_API_PREFIX } from '../settings.ts'\n\n/** One snapshot of the section as last seen by the transport. */\nexport interface SettingsSnapshot {\n status: 'loading' | 'ready' | 'error'\n value?: BackgroundSettings\n}\n\ntype Listener = () => void\n\n/**\n * Observable settings client (getSnapshot/subscribe — the uSES currency).\n * Methods are arrow properties so React's useSyncExternalStore can call them\n * without an owning `this`.\n */\nexport class SettingsClient {\n private snapshot: SettingsSnapshot = { status: 'loading' }\n private readonly listeners = new Set<Listener>()\n /** Monotonic request id; the latest save wins even when POSTs interleave. */\n private saveSeq = 0\n /** Pending save promise (used by the row's flush-on-unmount). */\n private pending: Promise<boolean> | undefined\n\n /** @returns the current sync snapshot (stable reference until the next change). */\n getSnapshot = (): SettingsSnapshot => this.snapshot\n\n /** Observe snapshot replacements. @returns the disposer removing this listener. */\n subscribe = (listener: Listener): (() => void) => {\n this.listeners.add(listener)\n return () => { this.listeners.delete(listener) }\n }\n\n private notify(): void {\n for (const listener of this.listeners) listener()\n }\n\n /** Await any in-flight save (used before teardown so edits are not dropped). */\n async flush(): Promise<void> {\n await this.pending\n }\n\n /** Fetch the section from the host. */\n async load(): Promise<void> {\n try {\n const response = await fetch(`${BACKGROUND_API_PREFIX}/settings`)\n if (!response.ok) throw new Error(`HTTP ${response.status}`)\n const body = await response.json() as { ok: boolean; value?: BackgroundSettings }\n if (!body.ok || body.value === undefined) throw new Error('unexpected payload')\n this.snapshot = { status: 'ready', value: body.value }\n } catch {\n this.snapshot = { status: 'error' }\n }\n this.notify()\n }\n\n /**\n * Persist the section through the host route. Concurrent calls are\n * serialized by a request sequence: an older save that resolves after a\n * newer one must not clobber the newer snapshot with its stale value.\n * @param section - the complete next section.\n * @returns whether the host accepted the write.\n */\n async save(section: BackgroundSettings): Promise<boolean> {\n const seq = ++this.saveSeq\n const run = async (): Promise<boolean> => {\n try {\n const response = await fetch(`${BACKGROUND_API_PREFIX}/settings`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(section),\n })\n const body = await response.json() as { ok: boolean; value?: BackgroundSettings }\n if (!response.ok || !body.ok || body.value === undefined) return false\n // Discard the response of a superseded save — it reflects an older\n // document that must not overwrite the latest one.\n if (seq !== this.saveSeq) return true\n this.snapshot = { status: 'ready', value: body.value }\n this.notify()\n return true\n } catch {\n return false\n }\n }\n const promise = run()\n this.pending = promise\n return promise\n }\n\n /**\n * Upload a local image file; on success stores its id into the snapshot and\n * returns the resolved background url (or null on failure).\n * @param file - the chosen image file.\n * @returns the resolved image url, or null.\n */\n async upload(file: File): Promise<string | null> {\n try {\n const response = await fetch(`${BACKGROUND_API_PREFIX}/upload`, {\n method: 'POST',\n headers: { 'content-type': file.type },\n body: file,\n })\n const body = await response.json() as { ok: boolean; id?: string; url?: string }\n if (!response.ok || !body.ok || body.id === undefined || body.url === undefined) return null\n return body.url ?? null\n } catch {\n return null\n }\n }\n}\n\n/** Shared client for the painter and the settings row. */\nexport const settingsClient = new SettingsClient()\n","/**\n * Background settings row — the editable form rendered inside the General\n * settings section (`settings.general.item` slot), in the same visual area as\n * the official Appearance row. Layout mirrors the reference wallpaper engine\n * picker (preview surface + grouped sections), styled with the harness alias\n * tokens so it reads as part of the settings chrome.\n *\n * Interaction model (fixes the previous jank):\n * - Sliders STEP in 5% (or 2px/5px) increments, so dragging snaps between\n * discrete values instead of firing dozens of sub-percent updates.\n * - While dragging, only the CSS variables change: the slider holds its own\n * state (no parent re-render) and the preview card repaints in isolation.\n * React's onChange maps to the native `input` event and would fire on every\n * step, so a commit is deferred to release (pointerup / keyup / blur) and\n * debounced — one POST per gesture, never per tick.\n * - A `lastSavedRef` distinguishes our own saves from external changes, so\n * the snapshot sync can never clobber a draft the user is still editing.\n */\n\nimport { useCallback, useEffect, useRef, useState, type ChangeEvent } from 'react'\nimport { useSyncExternalStore } from 'react'\nimport type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport clsx from 'clsx'\nimport {\n BACKGROUND_API_PREFIX, BLUR_MAX, BLUR_MIN, DEFAULT_BLUR, DEFAULT_FIT,\n DEFAULT_OPACITY, DEFAULT_PANEL_OPACITY, DEFAULT_SCRIM, DEFAULT_WALLPAPER_BLUR,\n FIT_MODES, OPACITY_MAX, OPACITY_MIN, PANEL_OPACITY_MAX, PANEL_OPACITY_MIN,\n SCRIM_MAX, SCRIM_MIN, WALLPAPER_BLUR_MAX, type BackgroundFit,\n type BackgroundSettings,\n} from '../settings.ts'\nimport { clearPreviewSurface, paintBackground, paintBackgroundKnob, paintPreviewSurface } from './backdrop.ts'\nimport { settingsClient, type SettingsSnapshot } from './settings-client.ts'\nimport css from './SettingsRow.module.css'\n\n/** Full component props: runtime share + locale seat. */\nexport type BackgroundRowProps =\n PropsRuntime<'settings.general.item'> & PropsLocale<'ui-background'>\n\n/** Defaults mirror the host schema (also the pre-load draft fallback). */\nconst DEFAULTS: BackgroundSettings = {\n enabled: false,\n uploadId: '',\n url: '',\n opacity: DEFAULT_OPACITY,\n scrim: DEFAULT_SCRIM,\n panelOpacity: DEFAULT_PANEL_OPACITY,\n blur: DEFAULT_BLUR,\n wallpaperBlur: DEFAULT_WALLPAPER_BLUR,\n fit: DEFAULT_FIT,\n}\n\n/** The numeric field keys a slider edits. */\ntype NumField = 'opacity' | 'scrim' | 'panelOpacity' | 'blur' | 'wallpaperBlur'\n\n/** Per-field slider geometry: 5% steps for ratios, fine px steps for radii so\n * the two blur sliders feel smooth near small values. Bounds come from the\n * shared settings constants so the schema boundary and the UI cannot drift. */\nconst SLIDER_SPEC: Record<NumField, { min: number; max: number; step: number; unit: 'percent' | 'px' }> = {\n opacity: { min: OPACITY_MIN, max: OPACITY_MAX, step: 0.05, unit: 'percent' },\n scrim: { min: SCRIM_MIN, max: SCRIM_MAX, step: 0.05, unit: 'percent' },\n panelOpacity: { min: PANEL_OPACITY_MIN, max: PANEL_OPACITY_MAX, step: 0.05, unit: 'percent' },\n blur: { min: BLUR_MIN, max: BLUR_MAX, step: 1, unit: 'px' },\n wallpaperBlur: { min: BLUR_MIN, max: WALLPAPER_BLUR_MAX, step: 2, unit: 'px' },\n}\n\n/** Derive the bare upload id from a resolve url like /api/bg-wallpaper/image/<id>. */\nfunction stripId(url: string): string {\n const prefix = `${BACKGROUND_API_PREFIX}/image/`\n return url.startsWith(prefix) ? url.slice(prefix.length) : ''\n}\n\n/** Read the settings store (uSES-friendly). */\nfunction readSnapshot(): SettingsSnapshot {\n return settingsClient.getSnapshot()\n}\n\n/** Field-wise equality for distinguishing our own saves from external changes. */\nfunction sameSettings(a: BackgroundSettings, b: BackgroundSettings): boolean {\n return a.enabled === b.enabled && a.uploadId === b.uploadId && a.url === b.url\n && a.opacity === b.opacity && a.scrim === b.scrim && a.panelOpacity === b.panelOpacity\n && a.blur === b.blur && a.wallpaperBlur === b.wallpaperBlur && a.fit === b.fit\n}\n\n/**\n * A stepped range control. While dragging it re-renders only itself: the value\n * is local state, `onLive(name, value)` repaints (CSS variables, no React\n * state), and `onCommit()` fires once on release through a debounced save.\n */\nfunction ControlSlider(props: {\n name: NumField\n label: string\n value: number\n onLive: (name: NumField, value: number) => void\n onCommit: () => void\n}) {\n const { name, label, value, onLive, onCommit } = props\n const spec = SLIDER_SPEC[name]\n const [local, setLocal] = useState(value)\n const localRef = useRef(value)\n const dragging = useRef(false)\n const onLiveRef = useRef(onLive)\n const onCommitRef = useRef(onCommit)\n onLiveRef.current = onLive\n onCommitRef.current = onCommit\n\n // Adopt an external value (load / save) when not mid-drag.\n useEffect(() => {\n if (!dragging.current && localRef.current !== value) {\n localRef.current = value\n setLocal(value)\n }\n }, [value])\n\n const handleLive = (e: ChangeEvent<HTMLInputElement>): void => {\n dragging.current = true\n const v = Number(e.currentTarget.value)\n localRef.current = v\n setLocal(v)\n syncTrackFill(e.currentTarget)\n onLiveRef.current(name, v)\n }\n\n const handleCommit = (): void => {\n if (!dragging.current) return\n dragging.current = false\n onCommitRef.current()\n }\n\n const text = spec.unit === 'percent'\n ? `${Math.round(local * 100)}%`\n : `${local}px`\n\n return (\n <div className={css.sliderRow}>\n <span className={css.sliderLabel}>{label}</span>\n <input\n type=\"range\"\n className={css.slider}\n ref={(el) => {\n // Sync the \"filled\" track fraction on mount and on every external\n // value adoption (the webkit track reads --bg-fill; moz draws its\n // own ::-moz-range-progress).\n if (el) syncTrackFill(el)\n }}\n min={spec.min} max={spec.max} step={spec.step}\n value={String(local)}\n aria-label={label}\n onInput={handleLive}\n onPointerUp={handleCommit}\n onKeyUp={(e) => {\n if (e.key.startsWith('Arrow') || e.key === 'Home' || e.key === 'End'\n || e.key === 'PageUp' || e.key === 'PageDown') handleCommit()\n }}\n onBlur={handleCommit}\n />\n <span className={css.sliderValue}>{text}</span>\n </div>\n )\n}\n\n/** Write the filled-track fraction (%) of a range input into its --bg-fill\n * variable (webkit has no range-progress pseudo-element; moz draws its own). */\nfunction syncTrackFill(el: HTMLInputElement): void {\n const min = Number(el.min)\n const max = Number(el.max)\n const value = Number(el.value)\n const pct = max === min ? 0 : ((value - min) / (max - min)) * 100\n el.style.setProperty('--bg-fill', `${pct}%`)\n}\n\n/**\n * The background settings row. A draft mirrors the persisted section; dragging\n * repaints the preview card and the live backdrop through CSS variables, and a\n * release commits once through the plugin's own host route.\n */\nexport function BackgroundSettingsRow({ t }: BackgroundRowProps) {\n const snapshot = useSyncExternalStore(settingsClient.subscribe, readSnapshot)\n const [draft, setDraft] = useState<BackgroundSettings>(DEFAULTS)\n const [uploading, setUploading] = useState(false)\n const [urlText, setUrlText] = useState('')\n const [error, setError] = useState('')\n const fileInput = useRef<HTMLInputElement>(null)\n const previewRef = useRef<HTMLDivElement>(null)\n // The latest draft, read by every handler (never a stale closure).\n const draftRef = useRef<BackgroundSettings>(DEFAULTS)\n // True while a drag/gesture is in flight: hold off snapshot sync.\n const editingRef = useRef(false)\n // The last section this row saved; external changes are snapshots that differ.\n const lastSavedRef = useRef<BackgroundSettings | null>(null)\n // True while an edit has not yet reached the host (drives flush-on-unmount).\n const dirtyRef = useRef(false)\n const commitTimer = useRef<number | undefined>(undefined)\n const editingTimer = useRef<number | undefined>(undefined)\n\n /** Repaint the live backdrop + preview card from one draft (no React state). */\n const paintLive = useCallback((next: BackgroundSettings): void => {\n paintBackground(next)\n if (previewRef.current) paintPreviewSurface(previewRef.current, next)\n }, [])\n\n /** Mark the row as being edited; clears after a quiet 600ms window. */\n const markEditing = useCallback((): void => {\n editingRef.current = true\n clearTimeout(editingTimer.current)\n editingTimer.current = window.setTimeout(() => { editingRef.current = false }, 600)\n }, [])\n\n /** Slider live handler (stable identity for the memoized sliders). */\n const onLive = useCallback((key: NumField, value: number): void => {\n const next = { ...draftRef.current, [key]: value }\n draftRef.current = next\n markEditing()\n // Hot path: most knobs repaint through the painter's single-variable\n // writer (no DOM layer churn). panelOpacity drives the glass surface\n // tokens, which need the full apply.\n if (key === 'panelOpacity') {\n paintBackground(next)\n } else {\n paintBackgroundKnob(key, value)\n }\n if (previewRef.current) paintPreviewSurface(previewRef.current, next)\n }, [markEditing])\n\n /** Persist one section through the host route and adopt it on success. */\n const saveNow = useCallback(async (next: BackgroundSettings): Promise<void> => {\n dirtyRef.current = true\n const ok = await settingsClient.save(next)\n if (ok) dirtyRef.current = false\n setError(ok ? '' : t('background.saveFailed'))\n if (ok) {\n lastSavedRef.current = next\n draftRef.current = next\n setDraft(next)\n if (!next.uploadId) setUrlText(next.url)\n }\n }, [t])\n\n /** Debounced commit: one POST per drag gesture, from the latest draft. */\n const onCommit = useCallback((): void => {\n clearTimeout(commitTimer.current)\n commitTimer.current = window.setTimeout(() => { void saveNow(draftRef.current) }, 120)\n }, [saveNow])\n\n // Sync the draft from the persisted value when it changes externally, but\n // never overwrite a draft the user is mid-editing.\n useEffect(() => {\n if (snapshot.status !== 'ready' || snapshot.value === undefined) return\n const saved = lastSavedRef.current\n const external = saved === null || !sameSettings(saved, snapshot.value)\n if (external && !editingRef.current) {\n lastSavedRef.current = snapshot.value\n draftRef.current = snapshot.value\n setDraft(snapshot.value)\n setUrlText(snapshot.value.uploadId ? '' : snapshot.value.url)\n if (previewRef.current) paintPreviewSurface(previewRef.current, snapshot.value)\n }\n }, [snapshot])\n\n // Teardown: flush any pending debounced save before the row unmounts so a\n // quick panel close after a release cannot drop the edit.\n useEffect(() => () => {\n clearTimeout(commitTimer.current)\n clearTimeout(editingTimer.current)\n if (dirtyRef.current) void settingsClient.flush()\n }, [])\n\n const handleFile = async (file?: File): Promise<void> => {\n if (!file) return\n markEditing()\n setUploading(true)\n setError('')\n try {\n const url = await settingsClient.upload(file)\n if (url === null) {\n setError(t('background.uploadFailed'))\n return\n }\n const next: BackgroundSettings = { ...draftRef.current, uploadId: stripId(url), url: '', enabled: true }\n draftRef.current = next\n setDraft(next)\n setUrlText('')\n paintLive(next)\n await saveNow(next)\n } finally {\n setUploading(false)\n }\n }\n\n const handleUrlSubmit = (): void => {\n const url = urlText.trim()\n if (!/^https?:\\/\\//i.test(url)) {\n setError(t('background.saveFailed'))\n return\n }\n markEditing()\n const next: BackgroundSettings = { ...draftRef.current, uploadId: '', url, enabled: true }\n draftRef.current = next\n setDraft(next)\n paintLive(next)\n void saveNow(next)\n }\n\n const handleClear = (): void => {\n const next: BackgroundSettings = { ...draftRef.current, uploadId: '', url: '', enabled: false }\n draftRef.current = next\n setDraft(next)\n setUrlText('')\n if (previewRef.current) clearPreviewSurface(previewRef.current)\n paintBackground(next)\n void saveNow(next)\n }\n\n const handleFit = (mode: BackgroundFit): void => {\n markEditing()\n const next: BackgroundSettings = { ...draftRef.current, fit: mode }\n draftRef.current = next\n setDraft(next)\n paintLive(next)\n void saveNow(next)\n }\n\n const sourceUrl = draft.uploadId ? `${BACKGROUND_API_PREFIX}/image/${draft.uploadId}` : draft.url\n const hasImage = sourceUrl !== ''\n\n return (\n <div className={css.row}>\n <div className={css.header}>\n <div className={css.titleRow}>\n <div className={css.title}>{t('background.title')}</div>\n {hasImage && (\n <button type=\"button\" className={clsx(css.btn, css.btnDanger, css.clearBtn)} onClick={handleClear}>\n {t('background.clear')}\n </button>\n )}\n </div>\n <div className={css.desc}>{t('background.description')}</div>\n </div>\n\n {/* Live preview surface: image + theme-aware scrim + frosted glass bubble. */}\n <div className={css.preview} ref={previewRef}>\n {hasImage\n ? (\n <>\n <img className={css.previewImg} src={sourceUrl} alt=\"\" draggable={false} />\n <div className={css.previewScrim} />\n <div className={css.previewGlass}>\n <span className={css.previewGlassText}>{t('background.previewGlass')}</span>\n </div>\n </>\n )\n : (\n <div className={css.previewEmpty}>{t('background.noPreview')}</div>\n )}\n </div>\n\n {/* Image source: upload or paste an http(s) link. */}\n <div className={css.section}>\n <div className={css.sectionLabel}>{t('background.source')}</div>\n <div className={css.sourceRow}>\n <input\n type=\"file\"\n ref={fileInput}\n hidden\n accept=\"image/jpeg,image/png,image/webp,image/gif\"\n onChange={(e) => {\n void handleFile(e.currentTarget.files?.[0])\n e.currentTarget.value = ''\n }}\n />\n <button\n type=\"button\"\n className={clsx(css.btn, css.btnPrimary)}\n disabled={uploading}\n onClick={() => fileInput.current?.click()}\n >\n {uploading ? t('background.uploading') : t('background.upload')}\n </button>\n <span className={css.hint}>{t('background.uploadMinetypes')}</span>\n {draft.uploadId && <span className={css.enabledBadge}>✓ {t('background.enabled')}</span>}\n </div>\n <div className={css.urlRow}>\n <input\n className={css.urlInput}\n value={urlText}\n placeholder={t('background.urlPlaceholder')}\n onKeyDown={(e) => { if (e.key === 'Enter') handleUrlSubmit() }}\n onChange={(e) => setUrlText(e.currentTarget.value)}\n />\n <button\n type=\"button\"\n className={css.btn}\n disabled={!urlText.trim()}\n onClick={handleUrlSubmit}\n >\n {t('background.applyUrl')}\n </button>\n </div>\n </div>\n\n {/* Effects: stepped sliders + fit segmented control. */}\n <div className={css.section}>\n <div className={css.sectionLabel}>{t('background.effects')}</div>\n <ControlSlider name=\"opacity\" label={t('background.opacity')} value={draft.opacity} onLive={onLive} onCommit={onCommit} />\n <ControlSlider name=\"scrim\" label={t('background.scrim')} value={draft.scrim} onLive={onLive} onCommit={onCommit} />\n <ControlSlider name=\"panelOpacity\" label={t('background.panelOpacity')} value={draft.panelOpacity} onLive={onLive} onCommit={onCommit} />\n <ControlSlider name=\"blur\" label={t('background.blur')} value={draft.blur} onLive={onLive} onCommit={onCommit} />\n <ControlSlider name=\"wallpaperBlur\" label={t('background.wallpaperBlur')} value={draft.wallpaperBlur} onLive={onLive} onCommit={onCommit} />\n <div className={css.segRow}>\n <span className={css.segLabel}>{t('background.fit')}</span>\n <div className={css.segGroup} role=\"group\" aria-label={t('background.fit')}>\n {FIT_MODES.map((mode) => (\n <button\n key={mode}\n type=\"button\"\n className={clsx(css.segBtn, draft.fit === mode && css.segActive)}\n onClick={() => handleFit(mode)}\n >\n {t(mode === 'cover' ? 'background.cover' : 'background.contain')}\n </button>\n ))}\n </div>\n </div>\n </div>\n\n {error && <div className={css.error} role=\"alert\">{error}</div>}\n\n {hasImage && (\n <div className={css.clearRow}>\n <button type=\"button\" className={clsx(css.btn, css.btnDanger)} onClick={handleClear}>\n {t('background.clear')}\n </button>\n </div>\n )}\n </div>\n )\n}\n","/**\n * Browser half of the background plugin: paints the background behind the\n * whole app frame and provides the settings surface — a live row inside the\n * official General settings section (next to the Appearance row). Data flows\n * through the plugin's own host route (`/api/bg-wallpaper/*`), not the\n * settings RPC, because the api-proxy settings allowlist does not expose\n * third-party namespaces. Retraction discipline mirrors the skin plugins:\n * every property and DOM node the painter owns is restored on dispose.\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport { backgroundPainter, paintBackground } from './backdrop.ts'\nimport { en, zh } from './locales.ts'\nimport { BackgroundSettingsRow } from './SettingsRow.tsx'\nimport { settingsClient } from './settings-client.ts'\nimport type {} from './types.ts'\n\n/**\n * Service injections this entry declares: the `slots` (runtime) and `locale`\n * services only — the settings surface talks to the plugin's own host route\n * over plain same-origin fetch, so no settings/connection service is needed.\n */\nexport const inject = ['slots', 'locale']\n\n/**\n * Client plugin body: paint the persisted background live and register the\n * General-settings row.\n * @param ctx - client cordis context (slots/locale injected).\n */\nexport function apply(ctx: Context): void {\n // Paint from the plugin's own transport; repaint on every snapshot change.\n const paint = (): void => {\n const snapshot = settingsClient.getSnapshot()\n const value = snapshot.status === 'ready' ? snapshot.value : undefined\n if (value === undefined || !value.enabled) {\n backgroundPainter.dispose()\n return\n }\n paintBackground(value)\n }\n const unsubscribe = settingsClient.subscribe(paint)\n void settingsClient.load()\n\n ctx.effect(() => ctx.locale.register('ui-background', { zh, en }), 'deepseek-harness-background: dictionaries')\n\n // Live settings row in the General section (same slot as the Appearance row).\n ctx.slots.inject('settings.general.item', () => ctx.slots.register({\n name: 'settings.general.item',\n id: 'deepseek-harness-background',\n order: 600,\n locale: 'ui-background',\n }, BackgroundSettingsRow))\n\n ctx.effect(() => () => {\n unsubscribe()\n backgroundPainter.dispose()\n }, 'deepseek-harness-background: background surface')\n}\n"],"x_google_ignoreList":[4],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["useState","useRef","css","useSyncExternalStore","useCallback","reactDom"],"sources":["../src/client/background-css.ts","../src/settings.ts","../src/client/backdrop.ts","../src/client/locales.ts","../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs","../src/client/settings-client.ts","../src/client/SettingsRow.tsx","../src/client/timeline-css.ts","../src/client/timeline.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * Background CSS — the stylesheet injected once into the document when the\n * plugin first runs. It defines the behind-body wallpaper layer, the scrim,\n * and the frosted-glass surfaces, all driven by CSS variables the painter\n * writes onto `document.body`. Kept in a single idempotent\n * `<style data-plugin-css>` tag (mirrors the reference `dsh-wallpaper-engine`\n * bundle).\n */\n\n/** Unique id stamped on the injected style element (dedup key). */\nexport const BACKGROUND_CSS_TAG = 'deepseek-harness-background/styles'\n\n/** Body attribute the painter sets while a wallpaper is active. */\nexport const ACTIVE_ATTR = 'data-dsh-bg'\n\n/**\n * Body attribute the painter sets only while the glass is actually on (a\n * wallpaper is active AND panelOpacity < 1). The explicit-fill rules below —\n * whitelisted buttons, popovers and badges whose official fills are not\n * token-mediated — key on this gate so they return to the exact official\n * paints when the user maxes the panel-opacity slider.\n */\nexport const GLASS_ATTR = 'data-dsh-bg-glass'\n\n/**\n * The backdrop CSS. The wallpaper is a fixed `z-index:-2` element (below the\n * scrim at `-1`, below the UI). While active, the app frame + sidebar fills\n * turn transparent so all columns share one backdrop.\n *\n * Frosted glass is a WHITELIST, not a blanket: only the surfaces that float\n * as small cards/buttons over the wallpaper are glassed — composer card,\n * message bubbles, code surfaces (blocks, inline code, tool IO cards,\n * skill/MCP call cards), the three chrome buttons (new session, composer +\n * button, scroll-to-bottom), the agent task strip family (`\n * --dsw-specific-tip`), the subagent lineage popover, the home hero\n * \"preview\" badge, and the timeline rail (timeline-css.ts). Every glassed\n * surface shares ONE recipe: fill from the painter's --dsw-specific-input-\n * major token (same alpha curve + theme dimming), the full shared\n * blur/saturate/brightness chain driven by the glass-blur slider, and the\n * shared sheen vars — so no surface reads heavier than the composer card.\n * Dialogs, the settings UI, menus, tooltips, toasts and every hover/accent\n * fill keep the OFFICIAL opaque paints — they are reading surfaces and must\n * stay legible.\n *\n * Selectors target authored attributes (`data-dsh-bg`, `data-composer-card`,\n * `data-terminal`…), the `:global` `.md-code-block` anchor, and CSS-module\n * SUFFIX conventions (`_bubble`, `_newSession`…) audited for collisions:\n * `_bubble` excludes `role=\"tooltip\"` (Tooltip.module.css shares the suffix),\n * `_add` is scoped under `[data-composer-card]` (DiffBlock line markers share\n * it), `_newSession` excludes `Label` (the button's inner label span) and\n * `_toBottom` excludes `Slot` (the zero-height sticky wrapper) — both share\n * the substring with the chrome control but must keep their own paint, and\n * the subagent popover is `role=\"tree\"` + `_menu` so the generic menu\n * surface stays untouched.\n */\nexport const BACKGROUND_CSS = `\n .dsh-bg-layer {\n position: fixed; inset: 0; z-index: -2; overflow: hidden; pointer-events: none;\n }\n .dsh-bg-layer .dsh-bg-image {\n width: 100%; height: 100%; display: block; border: 0; background: transparent;\n object-fit: var(--bg-object-fit, cover);\n opacity: var(--bg-opacity, 1);\n filter: blur(var(--bg-wallpaper-blur, 0px));\n /* Blur thins the edges; scale the image up to hide the fringe. */\n transform: scale(var(--bg-wallpaper-scale, 1));\n transform-origin: center;\n }\n /* Scrim is theme-aware: a WHITE veil in the light scheme (it lifts the art\n toward the near-white surface so dark text keeps contrast) and a BLACK veil\n in the dark scheme (it dims the art so light text keeps contrast). */\n .dsh-bg-scrim {\n position: fixed; inset: 0; z-index: -1; pointer-events: none;\n background: rgba(255, 255, 255, var(--bg-scrim, 0.25));\n }\n body[data-ds-dark-theme] .dsh-bg-scrim {\n background: rgba(0, 0, 0, var(--bg-scrim, 0.25));\n }\n\n /* Active: make the app frame + sidebar background transparent so all columns\n share the same wallpaper + scrim backdrop. */\n body[data-dsh-bg] {\n --dsw-alias-bg-base: transparent;\n --dsw-specific-sidebar-fill: transparent;\n }\n\n /* ---- Whitelisted frosted-glass sheet ---------------------------------\n Fills come from the --dsw-* tokens the painter overrides on body ONLY for\n this list's own surfaces (input/bubble/code/tip); this block adds the\n shared wet-glass sheen + blur from --bg-glass-blur. Exposure is calibrated\n per scheme (the painter writes --bg-glass-brightness / --bg-glass-sheen):\n light glass slightly DIMS, dark glass keeps a slight lift. Gated on the\n GLASS ATTR (wallpaper active AND panelOpacity < 1): maxing the panel\n slider returns these surfaces to the exact official paints. */\n body[data-dsh-bg-glass] [data-composer-card],\n body[data-dsh-bg-glass] [class*=\"_bubble\"]:not([role=\"tooltip\"]),\n body[data-dsh-bg-glass] .md-code-block,\n body[data-dsh-bg-glass] [data-terminal],\n body[data-dsh-bg-glass] [data-diff],\n body[data-dsh-bg-glass] [data-read],\n body[data-dsh-bg-glass] [data-search],\n body[data-dsh-bg-glass] [data-web],\n body[data-dsh-bg-glass] [class*=\"_ioCard\"],\n body[data-dsh-bg-glass] [class*=\"_instructionsCard\"],\n body[data-dsh-bg-glass] [class*=\"_markdown\"] :not(pre) > code {\n background-image: linear-gradient(180deg, rgba(255, 255, 255, var(--bg-glass-sheen, 0.07)), rgba(255, 255, 255, var(--bg-glass-sheen-mid, 0.02)) 38%, rgba(255, 255, 255, 0.01));\n -webkit-backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);\n backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.32),\n inset 0 -1px 0 rgba(255, 255, 255, 0.08),\n inset 0 0 0 0.5px rgba(255, 255, 255, 0.08),\n 0 12px 40px rgba(0, 0, 0, 0.12);\n }\n\n /* The sticky code-block header officially occludes scrolled code with\n bg-base (transparent under a wallpaper): refill it with the banner token\n (itself translucent glass) so code stays hidden beneath the sticky bar. */\n body[data-dsh-bg] .md-code-block [class*=\"_bannerWrap\"] {\n background-color: var(--dsw-alias-markdown-code-block-banner);\n }\n\n /* The sidebar build badge paints with the label-ink token — a TEXT token we\n must not override globally — so it gets a theme-aware translucent ink. */\n body[data-dsh-bg] [class*=\"_buildRevision\"] {\n background-color: rgba(15, 17, 21, 0.62);\n }\n body[data-ds-dark-theme][data-dsh-bg] [class*=\"_buildRevision\"] {\n background-color: rgba(249, 250, 251, 0.62);\n }\n\n /* The empty-state hero glow asset would wash out the wallpaper behind the\n welcome message — dim it so the art stays visible. */\n body[data-dsh-bg] [class*=\"_heroGlow\"] {\n opacity: 0.2;\n }\n\n /* ---- Whitelisted chrome buttons --------------------------------------\n These three buttons' official fills ride button-* tokens shared with\n unrelated surfaces, so instead of overriding the tokens they get explicit\n paints — but the SAME glass recipe as the composer card and bubbles:\n fill = the painter's --dsw-specific-input-major token (the identical\n translucent white + theme curve), filter = the sheet's exact\n blur/saturate/brightness chain (blur follows the glass-blur slider, no\n caps), sheen = the shared sheen vars. Hover = the same white glass at the\n boosted alpha var. Gated on data-dsh-bg-glass (off when the panel is\n fully opaque). */\n body[data-dsh-bg-glass] [class*=\"_newSession\"]:not([class*=\"Label\"]),\n body[data-dsh-bg-glass] [data-composer-card] [class*=\"_add\"],\n body[data-dsh-bg-glass] [class*=\"_toBottom\"]:not([class*=\"Slot\"]) {\n background-color: var(--dsw-specific-input-major);\n background-image: linear-gradient(180deg, rgba(255, 255, 255, var(--bg-glass-sheen, 0.07)), rgba(255, 255, 255, var(--bg-glass-sheen-mid, 0.02)) 38%, rgba(255, 255, 255, 0.01));\n -webkit-backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);\n backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.32),\n inset 0 0 0 0.5px rgba(255, 255, 255, 0.12),\n 0 4px 14px rgba(0, 0, 0, 0.08);\n }\n body[data-dsh-bg-glass] [class*=\"_newSession\"]:not([class*=\"Label\"]):hover,\n body[data-dsh-bg-glass] [data-composer-card] [class*=\"_add\"]:hover:not(:disabled),\n body[data-dsh-bg-glass] [class*=\"_toBottom\"]:not([class*=\"Slot\"]):hover {\n background-color: color-mix(in srgb, rgb(255 255 255) calc(var(--bg-glass-alpha-strong, 0.8) * 100%), transparent);\n }\n /* Collapsed rail renders the new-session control as a bare icon — keep the\n official transparent paint (and its official translucent hover). */\n body[data-dsh-bg-glass] [class*=\"_collapsed\"] [class*=\"_newSession\"],\n body[data-dsh-bg-glass] [class*=\"_collapsed\"] [class*=\"_newSession\"]:hover {\n background-color: transparent;\n background-image: none;\n box-shadow: none;\n }\n\n /* ---- Subagent lineage popover (title-bar expanded list) --------------\n Its official fill rides the menu token shared with every dropdown; glass\n THIS popover explicitly via its role=\"tree\" + _menu combination so real\n menus stay officially opaque and legible. Same unified recipe: the\n composer fill token + the full shared filter chain (the official\n elevation shadow stays). */\n body[data-dsh-bg-glass] [role=\"tree\"][class*=\"_menu\"] {\n background-color: var(--dsw-specific-input-major);\n background-image: linear-gradient(180deg, rgba(255, 255, 255, var(--bg-glass-sheen, 0.07)), rgba(255, 255, 255, var(--bg-glass-sheen-mid, 0.02)) 38%, rgba(255, 255, 255, 0.01));\n -webkit-backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);\n backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);\n }\n\n /* ---- Home hero \"preview\" badge (top-right superscript pill) ----------\n Officially the state-business-tertiary pastel; re-emit the same hue as\n glass but with the UNIFIED alpha curve (color-mix against the painter's\n --bg-glass-alpha) and the shared blur chain, so it sits on the wallpaper\n with exactly the glass strength of the composer card. */\n body[data-dsh-bg-glass] [class*=\"_previewBadge\"] {\n background-color: color-mix(in srgb, rgb(228 237 253) calc(var(--bg-glass-alpha, 0.72) * 100%), transparent);\n -webkit-backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);\n backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);\n }\n body[data-ds-dark-theme][data-dsh-bg-glass] [class*=\"_previewBadge\"] {\n background-color: color-mix(in srgb, rgb(52 65 91) calc(var(--bg-glass-alpha, 0.72) * 100%), transparent);\n }\n`\n\n/**\n * Inject the backdrop stylesheet once. Safe to call repeatedly; a second call\n * is a no-op (dedup key on the style tag).\n */\nexport function injectBackgroundCss(): void {\n if (document.querySelector(`style[data-plugin-css=\"${BACKGROUND_CSS_TAG}\"]`)) return\n const tag = document.createElement('style')\n tag.dataset.plugin = 'deepseek-harness-background'\n tag.dataset.pluginCss = BACKGROUND_CSS_TAG\n tag.textContent = BACKGROUND_CSS\n document.head.appendChild(tag)\n}\n","/** Durable background settings — pure constants/types shared by both halves. */\r\n\r\n/** Settings namespace owned by the background plugin. */\r\nexport const BACKGROUND_SETTINGS_NAMESPACE = 'ui-background'\r\n\r\n/**\r\n * The schema's field names, in schema order. Used as a whitelist when a\r\n * section write commits: the settings layer keeps unknown keys in the user\r\n * document (a legacy schema field would linger forever under a merge-only\r\n * write), so the write path strips everything outside this list.\r\n */\r\nexport const BACKGROUND_SETTINGS_FIELDS = [\r\n 'enabled', 'uploadId', 'url', 'opacity', 'scrim',\r\n 'panelOpacity', 'blur', 'wallpaperBlur', 'fit', 'timeline',\r\n] as const\r\n\r\n/** Browser-facing base path of the background API (shared with the host routes). */\r\nexport const BACKGROUND_API_PREFIX = '/api/bg-wallpaper'\r\n\r\n/** Minimum scrim opacity (0 = no veil at all). */\r\nexport const SCRIM_MIN = 0\r\n\r\n/** Maximum scrim opacity (1 = fully opaque veil — hides the wallpaper entirely).\r\n * Kept at 1 so every percent-unit slider shares one 0..1 domain: the same\r\n * displayed percentage puts every thumb at the same fraction of its track. */\r\nexport const SCRIM_MAX = 1\r\n\r\n/** Default scrim strength applied over user art (a light readability veil). */\r\nexport const DEFAULT_SCRIM = 0.25\r\n\r\n/** Default background image opacity (1 = fully opaque). */\r\nexport const DEFAULT_OPACITY = 1\r\n\r\n/** Minimum background image opacity (0 = fully invisible). */\r\nexport const OPACITY_MIN = 0\r\n\r\n/** Maximum background image opacity (1 = fully opaque). */\r\nexport const OPACITY_MAX = 1\r\n\r\n/** Default panel opacity (0..1); 1 = fully opaque official surfaces, 0 = fully transparent glass. */\r\nexport const DEFAULT_PANEL_OPACITY = 0.15\r\n\r\n/** Minimum panel opacity. */\r\nexport const PANEL_OPACITY_MIN = 0\r\n\r\n/** Maximum panel opacity (opaque — effectively disables the glass). */\r\nexport const PANEL_OPACITY_MAX = 1\r\n\r\n/** Default frosted-glass blur radius in px (0 disables backdrop-filter). */\r\nexport const DEFAULT_BLUR = 16\r\n\r\n/** Minimum glass blur radius. */\r\nexport const BLUR_MIN = 0\r\n\r\n/** Maximum glass blur radius. */\r\nexport const BLUR_MAX = 40\r\n\r\n/** Default wallpaper blur radius in px (blurs the image itself). */\r\nexport const DEFAULT_WALLPAPER_BLUR = 0\r\n\r\n/** Maximum wallpaper blur radius. */\r\nexport const WALLPAPER_BLUR_MAX = 60\r\n\r\n/** Whether the DeepSeek-style conversation timeline rail renders (default on). */\r\nexport const DEFAULT_TIMELINE = true\r\n\r\n/** Default background rendering mode. */\r\nexport const DEFAULT_FIT = 'cover'\r\n\r\n/** Image positioning modes. `cover` fills the frame (cropping as needed); `contain` fits the whole image inside the frame (letterboxing). */\r\nexport const FIT_MODES = ['cover', 'contain'] as const\r\n\r\n/** Background rendering mode. */\r\nexport type BackgroundFit = typeof FIT_MODES[number]\r\n\r\n/**\r\n * User-owned background section, resolved from schema defaults + user layer.\r\n * The active source is either a local upload id (host serves it via\r\n * `/api/bg-wallpaper/image/<id>`) or a raw HTTP(S) image URL the browser\r\n * loads; exactly one of `uploadId` / `url` is set — when both are empty no\r\n * background renders.\r\n */\r\nexport interface BackgroundSettings {\r\n /** Whether the custom background renders at all. */\r\n enabled: boolean\r\n /** Local upload id when the active source is an uploaded file. */\r\n uploadId: string\r\n /** Image URL when the active source is a remote URL. */\r\n url: string\r\n /** Background image opacity (0..1); the image fades toward the surface color. */\r\n opacity: number\r\n /** Readability scrim strength (0..1) layered between the art and the UI. */\r\n scrim: number\r\n /** Panel transparency (0..1): 0 = fully transparent surfaces, 1 = unaffected. */\r\n panelOpacity: number\r\n /** Frosted-glass blur radius on opaque surfaces (px; 0 disables). */\r\n blur: number\r\n /** Blur of the wallpaper image itself (px; 0 disables). */\r\n wallpaperBlur: number\r\n /** How the image fits the frame. */\r\n fit: BackgroundFit\r\n /** Whether the conversation timeline rail renders at the right edge. */\r\n timeline: boolean\r\n}\r\n","/**\n * Background painter — renders the user background behind the whole app frame:\n * a fixed `z-index:-2` wallpaper element plus a `z-index:-1` scrim on\n * `document.body`, driven by the `data-dsh-bg` body attribute and a set of\n * CSS variables. It also applies the frosted-glass surface tokens so the\n * wallpaper shows through translucent input / bubble panels.\n *\n * Retraction discipline mirrors the reference skin plugins: every property /\n * DOM node this painter owns is restored to its prior state on dispose, and\n * the `data-ds-dark-theme` observer is disconnected.\n */\n\nimport { ACTIVE_ATTR, GLASS_ATTR, injectBackgroundCss } from './background-css.ts'\nimport { BACKGROUND_API_PREFIX, type BackgroundSettings } from '../settings.ts'\n\n/** Class names the layer and scrim elements carry. */\nconst LAYER_CLASS = 'dsh-bg-layer'\nconst IMAGE_CLASS = 'dsh-bg-image'\nconst SCRIM_CLASS = 'dsh-bg-scrim'\n\n/**\n * White-glass tokens — the WHITELISTED surfaces only. Everything that floats\n * as a small card over the wallpaper: the composer input stack, message\n * bubbles, the markdown code surfaces (blocks + banner + inline code), and\n * the agent task strip family (`--dsw-specific-tip`: TodoPanel + GoalBar +\n * QueueDock share one dock column and one fill token). Menus, dialogs, the\n * settings UI, tooltips, toasts, hover fills and every accent keep the\n * OFFICIAL token values — they are reading surfaces and must stay legible.\n * `factor` scales the alpha relative to the input surface.\n */\nconst GLASS_SURFACE_TOKENS: readonly { token: string; factor: number }[] = [\n { token: '--dsw-specific-input-major', factor: 1 },\n { token: '--dsw-specific-bubble', factor: 0.8 },\n { token: '--dsw-alias-markdown-code-block', factor: 1 },\n { token: '--dsw-alias-markdown-code-block-banner', factor: 1 },\n { token: '--dsw-alias-markdown-inline-code', factor: 0.9 },\n { token: '--dsw-specific-tip', factor: 1 },\n]\n\n/** Every token the glass owns (save/restore key set). */\nconst GLASS_TOKENS: readonly string[] = GLASS_SURFACE_TOKENS.map(({ token }) => token)\n\n/** Fraction of the official white surface alpha kept at the most transparent panel setting. */\nconst GLASS_MIN_ALPHA = 0.05\n\n/** Base white-glass alpha for one panelOpacity (the curve every surface shares). */\nfunction glassAlpha(panelOpacity: number): number {\n const alpha = GLASS_MIN_ALPHA + panelOpacity * (0.9 - GLASS_MIN_ALPHA)\n return Math.max(0, Math.min(0.9, alpha))\n}\n\n/**\n * Saturation boost that rides the blur radius. Gentler than the reference\n * engine (1.1 + blur * 0.02, capped at 1.6): stacking a hot saturate on top of\n * the brightness/sheen layers pushed bright wallpapers into clipping.\n */\nfunction glassSaturate(blur: number): number {\n if (blur <= 0) return 1\n // Round off float dust (1.1 + 16 * 0.02 is 1.4200000000000002 raw).\n return Math.round(Math.min(1.6, 1.1 + blur * 0.02) * 1000) / 1000\n}\n\n/**\n * Exposure calibration per scheme. Light glass neither boosts brightness nor\n * stacks a heavy sheen (mainstream frosted recipes — macOS vibrancy, Windows\n * acrylic, common web glass — blur + saturate + tint without a positive\n * brightness gain); dark glass keeps the reference engine's slight lift, which\n * stops the white-glass fills from turning muddy.\n */\nfunction glassExposure(inDark: boolean): { brightness: string; sheen: string; sheenMid: string } {\n return inDark\n ? { brightness: '1.04', sheen: '0.16', sheenMid: '0.05' }\n : { brightness: '0.98', sheen: '0.07', sheenMid: '0.02' }\n}\n\n/**\n * The theme-aware glass surface alphas for one panelOpacity: the input-surface\n * token and the bubble token share one curve, dimmed per scheme. Shared by the\n * live painter and the settings-row preview card so the two cannot drift.\n */\nfunction glassSurfaceAlphas(panelOpacity: number, inDark: boolean): { major: string; bubble: string } {\n const alpha = glassAlpha(panelOpacity) * (inDark ? 0.4 : 0.8)\n return {\n major: `rgba(255, 255, 255, ${alpha.toFixed(3)})`,\n bubble: `rgba(255, 255, 255, ${(alpha * 0.8).toFixed(3)})`,\n }\n}\n\n/**\n * Resolve the effective background image url for a section.\n * @param settings - resolved background section.\n * @returns the image url, or '' when no source is set.\n */\nexport function backgroundImageUrl(settings: BackgroundSettings, uploadBase: string): string {\n if (settings.uploadId) return `${uploadBase}/image/${settings.uploadId}`\n return settings.url\n}\n\n/**\n * Manage the behind-body wallpaper + scrim layers and the glass surface.\n */\nexport class BackgroundPainter {\n private layer: HTMLDivElement | null = null\n private img: HTMLImageElement | null = null\n private scrim: HTMLDivElement | null = null\n private observer: MutationObserver | undefined\n private active = false\n private settings: BackgroundSettings | undefined\n private readonly savedTokens = new Map<string, string>()\n private readonly savedVars = new Map<string, string>()\n\n /** Remember + hijack a property only once so dispose restores the original. */\n private rememberOnce(prop: string): void {\n if (this.savedTokens.has(prop) || this.savedVars.has(prop)) return\n const value = document.body.style.getPropertyValue(prop)\n if (GLASS_TOKENS.includes(prop)) {\n this.savedTokens.set(prop, value)\n } else {\n this.savedVars.set(prop, value)\n }\n }\n\n /**\n * Apply the latest settings. Idempotent.\n * @param settings - resolved background section.\n * @param uploadBase - the API base for resolving uploads.\n */\n apply(settings: BackgroundSettings, uploadBase: string): void {\n this.settings = settings\n if (!settings.enabled) {\n this.dispose()\n return\n }\n injectBackgroundCss()\n this.rememberOnce('--dsw-alias-bg-base')\n this.rememberOnce('--dsw-specific-sidebar-fill')\n document.body.style.setProperty('--dsw-alias-bg-base', 'transparent')\n document.body.style.setProperty('--dsw-specific-sidebar-fill', 'transparent')\n\n const url = backgroundImageUrl(settings, uploadBase)\n if (url === '') {\n // No source: leave the frame alone, restore the removed layers and any\n // glass-token overrides we may have written on a previous apply. The\n // theme observer must go too — a later light/dark flip would re-run\n // applySurfaceGlass with forceRestore=false and write the translucent\n // tokens back onto panels that no longer sit over a wallpaper.\n this.observer?.disconnect()\n this.observer = undefined\n this.applySurfaceGlass(settings, true)\n this.active = false\n this.removeLayers()\n document.body.removeAttribute(ACTIVE_ATTR)\n return\n }\n\n // Wallpaper layer + scrim.\n if (!this.layer) {\n this.layer = document.createElement('div')\n this.layer.className = LAYER_CLASS\n this.img = document.createElement('img')\n this.img.className = IMAGE_CLASS\n this.img.alt = ''\n // Remote-url sources must not leak the local origin via Referer.\n this.img.referrerPolicy = 'no-referrer'\n this.layer.appendChild(this.img)\n document.body.appendChild(this.layer)\n }\n // Compare the *attribute* (the raw value we set) rather than the .src\n // property, which resolves to an absolute URL and would make this check\n // always-true for relative urls. Same-value writes are no-ops in the DOM,\n // so this is a clarity fix, not a behavior fix.\n if (this.img && this.img.getAttribute('src') !== url) this.img.src = url\n\n if (!this.scrim) {\n this.scrim = document.createElement('div')\n this.scrim.className = SCRIM_CLASS\n document.body.appendChild(this.scrim)\n }\n document.body.setAttribute(ACTIVE_ATTR, 'on')\n this.active = true\n\n // Push the knobs into CSS variables.\n const s = document.body.style\n this.setVar('--bg-object-fit', settings.fit)\n this.setVar('--bg-opacity', String(settings.opacity))\n this.setVar('--bg-wallpaper-blur', `${settings.wallpaperBlur}px`)\n this.setVar('--bg-wallpaper-scale', (1 + settings.wallpaperBlur * 0.006).toFixed(4))\n this.setVar('--bg-scrim', String(settings.scrim))\n this.setVar('--bg-glass-blur', `${settings.blur}px`)\n this.setVar('--bg-glass-saturate', String(glassSaturate(settings.blur)))\n\n // Glass surface: theme-aware translucent token (panelOpacity === 1 keeps\n // the official opaque surfaces and disables the blur).\n this.applySurfaceGlass(settings, false)\n\n // Theme observer: repaint the glass tokens when the light/dark scheme\n // flips (the surface translucency differs between schemes). Disconnects\n // on dispose.\n if (!this.observer) {\n this.observer = new MutationObserver(() => this.applySurfaceGlass(this.settings, false))\n this.observer.observe(document.body, { attributes: true, attributeFilter: ['data-ds-dark-theme'] })\n }\n }\n\n/** Write one owned CSS variable onto body. */\nprivate setVar(name: string, value: string): void {\n this.rememberOnce(name)\n document.body.style.setProperty(name, value)\n}\n\n/**\n * Update one effect knob without re-running the full apply. This is the hot\n * path for slider drags (many events per second): only the single CSS\n * variable changes, the DOM layers are untouched.\n * @param key - the knob to update.\n * @param value - its new value in its canonical unit.\n */\nsetKnob(key: 'opacity' | 'scrim' | 'blur' | 'wallpaperBlur' | 'fit', value: number | BackgroundSettings['fit']): void {\n if (this.settings === undefined || !this.settings.enabled) return\n switch (key) {\n case 'opacity':\n this.setVar('--bg-opacity', String(value))\n break\n case 'scrim':\n this.setVar('--bg-scrim', String(value))\n break\n case 'blur': {\n this.setVar('--bg-glass-blur', `${value}px`)\n this.setVar('--bg-glass-saturate', String(glassSaturate(Number(value))))\n break\n }\n case 'wallpaperBlur': {\n this.setVar('--bg-wallpaper-blur', `${value}px`)\n this.setVar('--bg-wallpaper-scale', (1 + Number(value) * 0.006).toFixed(4))\n break\n }\n case 'fit':\n this.setVar('--bg-object-fit', String(value))\n break\n }\n}\n\n /**\n * Apply the translucent-glass surface tokens (or restore the official ones\n * when the panel is fully opaque / there is no background).\n * @param settings - resolved section (for panelOpacity).\n * @param forceRestore - true to restore official surfaces regardless (used\n * when no source is set, so leftover glass tokens never linger).\n */\n private applySurfaceGlass(settings: BackgroundSettings | undefined, forceRestore: boolean): void {\n const s = document.body.style\n const inDark = document.body.dataset.dsDarkTheme !== undefined\n // Always remember the original surface values so a restore / dispose\n // returns them cleanly.\n for (const token of GLASS_TOKENS) this.rememberOnce(token)\n\n const restore = () => {\n for (const token of GLASS_TOKENS) {\n const original = this.savedTokens.get(token)\n if (original !== undefined && original !== '') s.setProperty(token, original)\n else s.removeProperty(token)\n }\n }\n\n if (forceRestore || settings === undefined || settings.panelOpacity >= 1) {\n restore()\n document.body.removeAttribute(GLASS_ATTR)\n // No blur and a neutral exposure when glass is off; the bare alpha\n // knobs only matter under the glass gate.\n this.setVar('--bg-glass-blur', '0px')\n this.setVar('--bg-glass-brightness', '1')\n s.removeProperty('--bg-glass-alpha')\n s.removeProperty('--bg-glass-alpha-strong')\n return\n }\n\n document.body.setAttribute(GLASS_ATTR, 'on')\n\n // Exposure calibration (theme-aware, mirrored by the preview surface).\n const exposure = glassExposure(inDark)\n this.setVar('--bg-glass-brightness', exposure.brightness)\n this.setVar('--bg-glass-sheen', exposure.sheen)\n this.setVar('--bg-glass-sheen-mid', exposure.sheenMid)\n\n // Dark scheme uses a lower white alpha (the wallpaper stays visible\n // without washing the surface), mirroring the reference engine.\n const base = glassAlpha(settings.panelOpacity) * (inDark ? 0.4 : 0.8)\n for (const { token, factor } of GLASS_SURFACE_TOKENS) {\n s.setProperty(token, `rgba(255, 255, 255, ${(base * factor).toFixed(3)})`)\n }\n // Bare alpha knobs for the surfaces that keep their own hue (preview\n // badge, via color-mix) or need a hover boost (chrome buttons): the same\n // curve every glass surface shares.\n this.setVar('--bg-glass-alpha', base.toFixed(3))\n this.setVar('--bg-glass-alpha-strong', Math.min(0.9, base * 1.5).toFixed(3))\n }\n\n /** Remove the wallpaper + scrim layers and clear the active attribute. */\n private removeLayers(): void {\n if (this.layer) { this.layer.remove(); this.layer = null; this.img = null }\n if (this.scrim) { this.scrim.remove(); this.scrim = null }\n }\n\n /** Restore every owned property and remove the layers. */\n dispose(): void {\n this.observer?.disconnect()\n this.observer = undefined\n this.removeLayers()\n const s = document.body.style\n document.body.removeAttribute(ACTIVE_ATTR)\n document.body.removeAttribute(GLASS_ATTR)\n for (const [prop, value] of this.savedTokens) s.setProperty(prop, value)\n for (const [prop, value] of this.savedVars) s.setProperty(prop, value)\n this.savedTokens.clear()\n this.savedVars.clear()\n this.active = false\n this.settings = undefined\n }\n\n /** @returns whether a wallpaper is currently rendered. */\n isActive(): boolean {\n return this.active\n }\n}\n\n/** Module-level painter singleton shared by the settings row preview and the live apply. */\nexport const backgroundPainter = new BackgroundPainter()\n\n/**\n * Apply the given settings through the shared painter (idempotent). Convenience\n * used by the settings row for live previews and by the plugin apply to render\n * the persisted section.\n * @param settings - settings to apply (may be an unsaved draft for preview).\n */\nexport function paintBackground(settings: BackgroundSettings): void {\n backgroundPainter.apply(settings, BACKGROUND_API_PREFIX)\n}\n\n/** Numeric effect knobs the slider drag path repaints. */\nexport type BackgroundKnob = 'opacity' | 'scrim' | 'blur' | 'wallpaperBlur' | 'fit'\n\n/**\n * Update one effect knob on the live backdrop without re-running the full\n * apply — the hot path for slider drags (see BackgroundPainter.setKnob).\n * @param key - the knob to update.\n * @param value - its new value.\n */\nexport function paintBackgroundKnob(key: BackgroundKnob, value: number | BackgroundSettings['fit']): void {\n backgroundPainter.setKnob(key, value)\n}\n\n/** Preview variables the settings-surface preview card consumes. */\nconst PREVIEW_VARS = [\n '--bg-opacity', '--bg-scrim', '--bg-object-fit',\n '--bg-wallpaper-blur', '--bg-wallpaper-scale',\n '--bg-glass-blur', '--bg-glass-saturate', '--bg-glass-brightness',\n '--bg-preview-glass',\n] as const\n\n/**\n * Push the effect knobs onto one element (the settings-surface preview card)\n * so dragging a slider updates the card without touching the live backdrop.\n * The card's CSS reads the same variable names as the painter writes on body.\n * @param el - the preview element.\n * @param settings - the draft settings to render (may be unsaved).\n */\nexport function paintPreviewSurface(el: HTMLElement, settings: BackgroundSettings): void {\n const s = el.style\n s.setProperty('--bg-object-fit', settings.fit)\n s.setProperty('--bg-opacity', String(settings.opacity))\n s.setProperty('--bg-scrim', String(settings.scrim))\n s.setProperty('--bg-wallpaper-blur', `${settings.wallpaperBlur}px`)\n s.setProperty('--bg-wallpaper-scale', (1 + settings.wallpaperBlur * 0.006).toFixed(4))\n // The glass bubble mirrors the live panel surface: below panelOpacity 1 its\n // alpha follows the same theme-aware curve as --dsw-specific-bubble (so the\n // panel-opacity slider is visible in the preview); at 1 the official opaque\n // surface returns — the bubble turns opaque and the blur switches off, just\n // like applySurfaceGlass does on the real backdrop.\n const inDark = document.body.dataset.dsDarkTheme !== undefined\n if (settings.panelOpacity >= 1) {\n s.setProperty('--bg-glass-blur', '0px')\n s.setProperty('--bg-glass-brightness', '1')\n s.setProperty('--bg-preview-glass', 'var(--dsw-alias-bg-layer-1)')\n return\n }\n s.setProperty('--bg-glass-blur', `${settings.blur}px`)\n s.setProperty('--bg-glass-saturate', String(glassSaturate(settings.blur)))\n // The preview filter mirrors the live exposure calibration (slightly dimmed\n // in light, lifted in dark) so the card never reads brighter than the app.\n s.setProperty('--bg-glass-brightness', glassExposure(inDark).brightness)\n // The preview bubble mirrors the live --dsw-specific-bubble token.\n s.setProperty('--bg-preview-glass', glassSurfaceAlphas(settings.panelOpacity, inDark).bubble)\n}\n\n/** Remove every preview variable from an element (restores CSS defaults). */\nexport function clearPreviewSurface(el: HTMLElement): void {\n for (const name of PREVIEW_VARS) el.style.removeProperty(name)\n}\n","/** Locale dictionaries for the background plugin. */\n\nimport type { BackgroundCardLocaleKey } from './types.ts'\n\n/** Dictionary of the namespace this plugin owns. */\nexport type BackgroundCardDict = Record<BackgroundCardLocaleKey, string>\n\n/** Chinese copy. */\nexport const zh: BackgroundCardDict = {\n 'background.title': '自定义背景',\n 'background.description': '为整个应用界面设置背景图片,可调不透明度、遮罩、面板透明与毛玻璃模糊',\n 'background.upload': '上传图片',\n 'background.uploading': '上传中…',\n 'background.uploadMediaTypes': '支持 JPG / PNG / WebP / GIF',\n 'background.urlPlaceholder': '或粘贴图片 http(s) 链接后回车',\n 'background.invalidUrl': '链接无效,请粘贴 http(s) 开头的图片链接',\n 'background.applyUrl': '应用链接',\n 'background.enabled': '背景已启用',\n 'background.source': '图片',\n 'background.effects': '效果',\n 'background.noPreview': '上传图片或粘贴链接后,此处实时预览效果',\n 'background.previewGlass': '毛玻璃',\n 'background.opacity': '不透明度',\n 'background.scrim': '遮罩',\n 'background.panelOpacity': '面板不透明度',\n 'background.blur': '毛玻璃模糊',\n 'background.wallpaperBlur': '壁纸模糊',\n 'background.fit': '填充方式',\n 'background.cover': '铺满',\n 'background.contain': '完整',\n 'background.clear': '清除背景',\n 'background.uploadFailed': '上传失败,请重试',\n 'background.saveFailed': '保存失败,请重试',\n 'background.timeline': '会话时间线',\n 'background.timelineHint': '右侧消息导航轨,悬停展开问题列表(DeepSeek 官网风格)',\n 'timeline.railLabel': '对话时间线',\n 'timeline.roleUser': '用户',\n 'timeline.noText': '(无文本内容)',\n 'timeline.marksOnly': '★ 只看标记',\n 'timeline.mark': '标记为重点',\n 'timeline.unmark': '取消重点标记',\n 'timeline.noMarks': '还没有标记的重点',\n}\n\n/** English copy. */\nexport const en: BackgroundCardDict = {\n 'background.title': 'Custom Background',\n 'background.description': 'Set a background image behind the whole app surface with adjustable opacity, scrim, panel transparency and glass blur',\n 'background.upload': 'Upload image',\n 'background.uploading': 'Uploading…',\n 'background.uploadMediaTypes': 'JPG / PNG / WebP / GIF',\n 'background.urlPlaceholder': 'Or paste an image http(s) link and press Enter',\n 'background.invalidUrl': 'Invalid link — paste an image link starting with http(s)',\n 'background.applyUrl': 'Apply URL',\n 'background.enabled': 'Background on',\n 'background.source': 'Image',\n 'background.effects': 'Effects',\n 'background.noPreview': 'Upload an image or paste a link to preview live here',\n 'background.previewGlass': 'Glass',\n 'background.opacity': 'Opacity',\n 'background.scrim': 'Scrim',\n 'background.panelOpacity': 'Panel opacity',\n 'background.blur': 'Glass blur',\n 'background.wallpaperBlur': 'Wallpaper blur',\n 'background.fit': 'Fit',\n 'background.cover': 'Cover',\n 'background.contain': 'Contain',\n 'background.clear': 'Clear background',\n 'background.uploadFailed': 'Upload failed, try again',\n 'background.saveFailed': 'Save failed, try again',\n 'background.timeline': 'Conversation timeline',\n 'background.timelineHint': 'Message rail at the right edge; hover to expand the question list (DeepSeek web style)',\n 'timeline.railLabel': 'Chat timeline',\n 'timeline.roleUser': 'User',\n 'timeline.noText': '(no text)',\n 'timeline.marksOnly': '★ Marked only',\n 'timeline.mark': 'Mark as key point',\n 'timeline.unmark': 'Unmark key point',\n 'timeline.noMarks': 'No marked key points',\n}\n","function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;","/**\n * Background settings transport — reads and writes the `ui-background`\n * section, and uploads local images, through the plugin's own same-origin\n * HTTP routes (see src/routes.ts). A custom route family keeps the section\n * usable even though the api-proxy settings allowlist does not expose\n * third-party namespaces over the settings RPC. One module-level client\n * serves the painter and the settings row.\n */\n\nimport type { BackgroundSettings } from '../settings.ts'\nimport { BACKGROUND_API_PREFIX } from '../settings.ts'\n\n/** One snapshot of the section as last seen by the transport. */\nexport interface SettingsSnapshot {\n status: 'loading' | 'ready' | 'error'\n value?: BackgroundSettings\n}\n\ntype Listener = () => void\n\n/** Outcome of one save attempt: committed, displaced by a newer save (the\n * caller must not adopt its own section back into the draft), or rejected. */\nexport type SaveResult = 'ok' | 'superseded' | 'failed'\n\n/**\n * Observable settings client (getSnapshot/subscribe — the uSES currency).\n * Methods are arrow properties so React's useSyncExternalStore can call them\n * without an owning `this`.\n */\nexport class SettingsClient {\n private snapshot: SettingsSnapshot = { status: 'loading' }\n private readonly listeners = new Set<Listener>()\n /** Monotonic request id; the latest save wins even when POSTs interleave. */\n private saveSeq = 0\n /** Pending save promise (used by the row's flush-on-unmount). */\n private pending: Promise<SaveResult> | undefined\n\n /** @returns the current sync snapshot (stable reference until the next change). */\n getSnapshot = (): SettingsSnapshot => this.snapshot\n\n /** Observe snapshot replacements. @returns the disposer removing this listener. */\n subscribe = (listener: Listener): (() => void) => {\n this.listeners.add(listener)\n return () => { this.listeners.delete(listener) }\n }\n\n private notify(): void {\n for (const listener of this.listeners) listener()\n }\n\n /** Await any in-flight save (used before teardown so edits are not dropped). */\n async flush(): Promise<void> {\n await this.pending\n }\n\n /** Fetch the section from the host. */\n async load(): Promise<void> {\n try {\n const response = await fetch(`${BACKGROUND_API_PREFIX}/settings`)\n if (!response.ok) throw new Error(`HTTP ${response.status}`)\n const body = await response.json() as { ok: boolean; value?: BackgroundSettings }\n if (!body.ok || body.value === undefined) throw new Error('unexpected payload')\n this.snapshot = { status: 'ready', value: body.value }\n } catch {\n this.snapshot = { status: 'error' }\n }\n this.notify()\n }\n\n /**\n * Persist the section through the host route. Concurrent calls are\n * serialized by a request sequence: an older save that resolves after a\n * newer one answers 'superseded' instead of 'ok', so the caller can never\n * mistake a stale write for success and adopt its outdated section.\n * @param section - the complete next section.\n * @returns whether the write committed, was displaced by a newer save, or failed.\n */\n async save(section: BackgroundSettings): Promise<SaveResult> {\n const seq = ++this.saveSeq\n const run = async (): Promise<SaveResult> => {\n try {\n const response = await fetch(`${BACKGROUND_API_PREFIX}/settings`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(section),\n })\n const body = await response.json() as { ok: boolean; value?: BackgroundSettings }\n if (!response.ok || !body.ok || body.value === undefined) return 'failed'\n // Discard the response of a superseded save — it reflects an older\n // document that must not overwrite the latest one.\n if (seq !== this.saveSeq) return 'superseded'\n this.snapshot = { status: 'ready', value: body.value }\n this.notify()\n return 'ok'\n } catch {\n return 'failed'\n }\n }\n const promise = run()\n this.pending = promise\n return promise\n }\n\n /**\n * Upload a local image file; on success stores its id into the snapshot and\n * returns the resolved background url (or null on failure).\n * @param file - the chosen image file.\n * @returns the resolved image url, or null.\n */\n async upload(file: File): Promise<string | null> {\n try {\n const response = await fetch(`${BACKGROUND_API_PREFIX}/upload`, {\n method: 'POST',\n headers: { 'content-type': file.type },\n body: file,\n })\n const body = await response.json() as { ok: boolean; id?: string; url?: string }\n if (!response.ok || !body.ok || body.id === undefined || body.url === undefined) return null\n return body.url ?? null\n } catch {\n return null\n }\n }\n}\n\n/** Shared client for the painter and the settings row. */\nexport const settingsClient = new SettingsClient()\n","/**\n * Background settings row — the editable form rendered inside the General\n * settings section (`settings.general.item` slot), in the same visual area as\n * the official Appearance row. Layout mirrors the reference wallpaper engine\n * picker (preview surface + grouped sections), styled with the harness alias\n * tokens so it reads as part of the settings chrome.\n *\n * Interaction model (fixes the previous jank):\n * - Sliders STEP in 5% (or 2px/5px) increments, so dragging snaps between\n * discrete values instead of firing dozens of sub-percent updates.\n * - While dragging, only the CSS variables change: the slider holds its own\n * state (no parent re-render) and the preview card repaints in isolation.\n * React's onChange maps to the native `input` event and would fire on every\n * step, so a commit is deferred to release (pointerup / keyup / blur) and\n * debounced — one POST per gesture, never per tick.\n * - A `lastSavedRef` distinguishes our own saves from external changes, so\n * the snapshot sync can never clobber a draft the user is still editing.\n */\n\nimport { useCallback, useEffect, useRef, useState, type ChangeEvent } from 'react'\nimport { useSyncExternalStore } from 'react'\nimport type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport clsx from 'clsx'\nimport {\n BACKGROUND_API_PREFIX, BLUR_MAX, BLUR_MIN, DEFAULT_BLUR, DEFAULT_FIT,\n DEFAULT_OPACITY, DEFAULT_PANEL_OPACITY, DEFAULT_SCRIM, DEFAULT_TIMELINE,\n DEFAULT_WALLPAPER_BLUR, FIT_MODES, OPACITY_MAX, OPACITY_MIN, PANEL_OPACITY_MAX,\n PANEL_OPACITY_MIN, SCRIM_MAX, SCRIM_MIN, WALLPAPER_BLUR_MAX, type BackgroundFit,\n type BackgroundSettings,\n} from '../settings.ts'\nimport { clearPreviewSurface, paintBackground, paintBackgroundKnob, paintPreviewSurface } from './backdrop.ts'\nimport { settingsClient, type SettingsSnapshot } from './settings-client.ts'\nimport css from './SettingsRow.module.css'\n\n/** Full component props: runtime share + locale seat. */\nexport type BackgroundRowProps =\n PropsRuntime<'settings.general.item'> & PropsLocale<'ui-background'>\n\n/** Defaults mirror the host schema (also the pre-load draft fallback). */\nconst DEFAULTS: BackgroundSettings = {\n enabled: false,\n uploadId: '',\n url: '',\n opacity: DEFAULT_OPACITY,\n scrim: DEFAULT_SCRIM,\n panelOpacity: DEFAULT_PANEL_OPACITY,\n blur: DEFAULT_BLUR,\n wallpaperBlur: DEFAULT_WALLPAPER_BLUR,\n fit: DEFAULT_FIT,\n timeline: DEFAULT_TIMELINE,\n}\n\n/** The numeric field keys a slider edits. */\ntype NumField = 'opacity' | 'scrim' | 'panelOpacity' | 'blur' | 'wallpaperBlur'\n\n/** Per-field slider geometry: 5% steps for ratios, fine px steps for radii so\n * the two blur sliders feel smooth near small values. Bounds come from the\n * shared settings constants so the schema boundary and the UI cannot drift. */\nconst SLIDER_SPEC: Record<NumField, { min: number; max: number; step: number; unit: 'percent' | 'px' }> = {\n opacity: { min: OPACITY_MIN, max: OPACITY_MAX, step: 0.05, unit: 'percent' },\n scrim: { min: SCRIM_MIN, max: SCRIM_MAX, step: 0.05, unit: 'percent' },\n panelOpacity: { min: PANEL_OPACITY_MIN, max: PANEL_OPACITY_MAX, step: 0.05, unit: 'percent' },\n blur: { min: BLUR_MIN, max: BLUR_MAX, step: 1, unit: 'px' },\n wallpaperBlur: { min: BLUR_MIN, max: WALLPAPER_BLUR_MAX, step: 2, unit: 'px' },\n}\n\n/** Derive the bare upload id from a resolve url like /api/bg-wallpaper/image/<id>. */\nfunction stripId(url: string): string {\n const prefix = `${BACKGROUND_API_PREFIX}/image/`\n return url.startsWith(prefix) ? url.slice(prefix.length) : ''\n}\n\n/** Read the settings store (uSES-friendly). */\nfunction readSnapshot(): SettingsSnapshot {\n return settingsClient.getSnapshot()\n}\n\n/** Field-wise equality for distinguishing our own saves from external changes. */\nfunction sameSettings(a: BackgroundSettings, b: BackgroundSettings): boolean {\n return a.enabled === b.enabled && a.uploadId === b.uploadId && a.url === b.url\n && a.opacity === b.opacity && a.scrim === b.scrim && a.panelOpacity === b.panelOpacity\n && a.blur === b.blur && a.wallpaperBlur === b.wallpaperBlur && a.fit === b.fit\n && a.timeline === b.timeline\n}\n\n/**\n * A stepped range control. While dragging it re-renders only itself: the value\n * is local state, `onLive(name, value)` repaints (CSS variables, no React\n * state), and `onCommit()` fires once on release through a debounced save.\n */\nfunction ControlSlider(props: {\n name: NumField\n label: string\n value: number\n onLive: (name: NumField, value: number) => void\n onCommit: () => void\n}) {\n const { name, label, value, onLive, onCommit } = props\n const spec = SLIDER_SPEC[name]\n const [local, setLocal] = useState(value)\n const localRef = useRef(value)\n const dragging = useRef(false)\n const onLiveRef = useRef(onLive)\n const onCommitRef = useRef(onCommit)\n onLiveRef.current = onLive\n onCommitRef.current = onCommit\n\n // Adopt an external value (load / save) when not mid-drag.\n useEffect(() => {\n if (!dragging.current && localRef.current !== value) {\n localRef.current = value\n setLocal(value)\n }\n }, [value])\n\n const handleLive = (e: ChangeEvent<HTMLInputElement>): void => {\n dragging.current = true\n const v = Number(e.currentTarget.value)\n localRef.current = v\n setLocal(v)\n syncTrackFill(e.currentTarget)\n onLiveRef.current(name, v)\n }\n\n const handleCommit = (): void => {\n if (!dragging.current) return\n dragging.current = false\n onCommitRef.current()\n }\n\n const text = spec.unit === 'percent'\n ? `${Math.round(local * 100)}%`\n : `${local}px`\n\n return (\n <div className={css.sliderRow}>\n <span className={css.sliderLabel}>{label}</span>\n <input\n type=\"range\"\n className={css.slider}\n ref={(el) => {\n // Sync the \"filled\" track fraction on mount and on every external\n // value adoption (the webkit track reads --bg-fill; moz draws its\n // own ::-moz-range-progress).\n if (el) syncTrackFill(el)\n }}\n min={spec.min} max={spec.max} step={spec.step}\n value={String(local)}\n aria-label={label}\n onInput={handleLive}\n onPointerUp={handleCommit}\n onKeyUp={(e) => {\n if (e.key.startsWith('Arrow') || e.key === 'Home' || e.key === 'End'\n || e.key === 'PageUp' || e.key === 'PageDown') handleCommit()\n }}\n onBlur={handleCommit}\n />\n <span className={css.sliderValue}>{text}</span>\n </div>\n )\n}\n\n/** Write the filled-track fraction (%) of a range input into its --bg-fill\n * variable (webkit has no range-progress pseudo-element; moz draws its own). */\nfunction syncTrackFill(el: HTMLInputElement): void {\n const min = Number(el.min)\n const max = Number(el.max)\n const value = Number(el.value)\n const pct = max === min ? 0 : ((value - min) / (max - min)) * 100\n el.style.setProperty('--bg-fill', `${pct}%`)\n}\n\n/**\n * The background settings row. A draft mirrors the persisted section; dragging\n * repaints the preview card and the live backdrop through CSS variables, and a\n * release commits once through the plugin's own host route.\n */\nexport function BackgroundSettingsRow({ t }: BackgroundRowProps) {\n const snapshot = useSyncExternalStore(settingsClient.subscribe, readSnapshot)\n const [draft, setDraft] = useState<BackgroundSettings>(DEFAULTS)\n const [uploading, setUploading] = useState(false)\n const [urlText, setUrlText] = useState('')\n const [error, setError] = useState('')\n const fileInput = useRef<HTMLInputElement>(null)\n const previewRef = useRef<HTMLDivElement>(null)\n // The latest draft, read by every handler (never a stale closure).\n const draftRef = useRef<BackgroundSettings>(DEFAULTS)\n // True while a drag/gesture is in flight: hold off snapshot sync.\n const editingRef = useRef(false)\n // The last section this row saved; external changes are snapshots that differ.\n const lastSavedRef = useRef<BackgroundSettings | null>(null)\n // True while an edit has not yet reached the host (drives flush-on-unmount).\n const dirtyRef = useRef(false)\n const commitTimer = useRef<number | undefined>(undefined)\n const editingTimer = useRef<number | undefined>(undefined)\n\n /** Repaint the live backdrop + preview card from one draft (no React state). */\n const paintLive = useCallback((next: BackgroundSettings): void => {\n paintBackground(next)\n if (previewRef.current) paintPreviewSurface(previewRef.current, next)\n }, [])\n\n /** Mark the row as being edited; clears after a quiet 600ms window. */\n const markEditing = useCallback((): void => {\n editingRef.current = true\n clearTimeout(editingTimer.current)\n editingTimer.current = window.setTimeout(() => { editingRef.current = false }, 600)\n }, [])\n\n /** Slider live handler (stable identity for the memoized sliders). */\n const onLive = useCallback((key: NumField, value: number): void => {\n const next = { ...draftRef.current, [key]: value }\n draftRef.current = next\n markEditing()\n // Hot path: most knobs repaint through the painter's single-variable\n // writer (no DOM layer churn). panelOpacity drives the glass surface\n // tokens, which need the full apply.\n if (key === 'panelOpacity') {\n paintBackground(next)\n } else {\n paintBackgroundKnob(key, value)\n }\n if (previewRef.current) paintPreviewSurface(previewRef.current, next)\n }, [markEditing])\n\n /** Persist one section through the host route and adopt it on success. */\n const saveNow = useCallback(async (next: BackgroundSettings): Promise<void> => {\n dirtyRef.current = true\n const result = await settingsClient.save(next)\n if (result === 'failed') {\n setError(t('background.saveFailed'))\n return\n }\n // A superseded save lost to a newer one: that newer save owns adoption\n // and the dirty flag — adopting here would resurrect an outdated section.\n if (result === 'superseded') return\n dirtyRef.current = false\n setError('')\n lastSavedRef.current = next\n draftRef.current = next\n setDraft(next)\n if (!next.uploadId) setUrlText(next.url)\n }, [t])\n\n // The latest saveNow, readable from stable callbacks and the unmount\n // cleanup (never a stale closure).\n const saveNowRef = useRef(saveNow)\n saveNowRef.current = saveNow\n\n /** Debounced commit: one POST per drag gesture, from the latest draft. */\n const onCommit = useCallback((): void => {\n clearTimeout(commitTimer.current)\n commitTimer.current = window.setTimeout(() => {\n // Reset before saving: a fired timer must never look like an armed one,\n // or the unmount flush would re-save an already-committed gesture.\n commitTimer.current = undefined\n void saveNowRef.current(draftRef.current)\n }, 120)\n }, [])\n\n // Sync the draft from the persisted value when it changes externally, but\n // never overwrite a draft the user is mid-editing.\n useEffect(() => {\n if (snapshot.status !== 'ready' || snapshot.value === undefined) return\n const saved = lastSavedRef.current\n const external = saved === null || !sameSettings(saved, snapshot.value)\n if (external && !editingRef.current) {\n lastSavedRef.current = snapshot.value\n draftRef.current = snapshot.value\n setDraft(snapshot.value)\n setUrlText(snapshot.value.uploadId ? '' : snapshot.value.url)\n if (previewRef.current) paintPreviewSurface(previewRef.current, snapshot.value)\n }\n }, [snapshot])\n\n // Teardown: a pending debounced commit must not die with the row. If the\n // timer is still armed, fire the save NOW (the timer callback would never\n // run after unmount, and dirtyRef is only set inside saveNow — clearing\n // the timer alone would silently drop the last slider adjustment). Then\n // wait out any save already in flight. The effect runs once per mount:\n // saveNow is reached through its ref, so an identity change mid-session\n // cannot re-trigger this teardown, and editingRef is reset so a cleared\n // editing window can never block snapshot sync forever.\n useEffect(() => () => {\n clearTimeout(editingTimer.current)\n editingRef.current = false\n if (commitTimer.current !== undefined) {\n clearTimeout(commitTimer.current)\n commitTimer.current = undefined\n void saveNowRef.current(draftRef.current)\n }\n if (dirtyRef.current) void settingsClient.flush()\n }, [])\n\n const handleFile = async (file?: File): Promise<void> => {\n if (!file) return\n markEditing()\n setUploading(true)\n setError('')\n try {\n const url = await settingsClient.upload(file)\n if (url === null) {\n setError(t('background.uploadFailed'))\n return\n }\n const next: BackgroundSettings = { ...draftRef.current, uploadId: stripId(url), url: '', enabled: true }\n draftRef.current = next\n setDraft(next)\n setUrlText('')\n paintLive(next)\n await saveNow(next)\n } finally {\n setUploading(false)\n }\n }\n\n const handleUrlSubmit = (): void => {\n const url = urlText.trim()\n if (!/^https?:\\/\\//i.test(url)) {\n setError(t('background.invalidUrl'))\n return\n }\n markEditing()\n const next: BackgroundSettings = { ...draftRef.current, uploadId: '', url, enabled: true }\n draftRef.current = next\n setDraft(next)\n paintLive(next)\n void saveNow(next)\n }\n\n const handleClear = (): void => {\n const next: BackgroundSettings = { ...draftRef.current, uploadId: '', url: '', enabled: false }\n draftRef.current = next\n setDraft(next)\n setUrlText('')\n if (previewRef.current) clearPreviewSurface(previewRef.current)\n paintBackground(next)\n void saveNow(next)\n }\n\n const handleFit = (mode: BackgroundFit): void => {\n markEditing()\n const next: BackgroundSettings = { ...draftRef.current, fit: mode }\n draftRef.current = next\n setDraft(next)\n paintLive(next)\n void saveNow(next)\n }\n\n const handleTimelineToggle = (): void => {\n markEditing()\n const next: BackgroundSettings = { ...draftRef.current, timeline: !draftRef.current.timeline }\n draftRef.current = next\n setDraft(next)\n // The rail reads the shared snapshot itself; no painter repaint needed.\n void saveNow(next)\n }\n\n const sourceUrl = draft.uploadId ? `${BACKGROUND_API_PREFIX}/image/${draft.uploadId}` : draft.url\n const hasImage = sourceUrl !== ''\n\n return (\n <div className={css.row}>\n <div className={css.header}>\n <div className={css.titleRow}>\n <div className={css.title}>{t('background.title')}</div>\n {hasImage && (\n <button type=\"button\" className={clsx(css.btn, css.btnDanger, css.clearBtn)} onClick={handleClear}>\n {t('background.clear')}\n </button>\n )}\n </div>\n <div className={css.desc}>{t('background.description')}</div>\n </div>\n\n {/* Live preview surface: image + theme-aware scrim + frosted glass bubble. */}\n <div className={css.preview} ref={previewRef}>\n {hasImage\n ? (\n <>\n <img className={css.previewImg} src={sourceUrl} alt=\"\" draggable={false} referrerPolicy=\"no-referrer\" />\n <div className={css.previewScrim} />\n <div className={css.previewGlass}>\n <span className={css.previewGlassText}>{t('background.previewGlass')}</span>\n </div>\n </>\n )\n : (\n <div className={css.previewEmpty}>{t('background.noPreview')}</div>\n )}\n </div>\n\n {/* Image source: upload or paste an http(s) link. */}\n <div className={css.section}>\n <div className={css.sectionLabel}>{t('background.source')}</div>\n <div className={css.sourceRow}>\n <input\n type=\"file\"\n ref={fileInput}\n hidden\n accept=\"image/jpeg,image/png,image/webp,image/gif\"\n onChange={(e) => {\n void handleFile(e.currentTarget.files?.[0])\n e.currentTarget.value = ''\n }}\n />\n <button\n type=\"button\"\n className={clsx(css.btn, css.btnPrimary)}\n disabled={uploading}\n onClick={() => fileInput.current?.click()}\n >\n {uploading ? t('background.uploading') : t('background.upload')}\n </button>\n <span className={css.hint}>{t('background.uploadMediaTypes')}</span>\n {draft.uploadId && <span className={css.enabledBadge}>✓ {t('background.enabled')}</span>}\n </div>\n <div className={css.urlRow}>\n <input\n className={css.urlInput}\n value={urlText}\n placeholder={t('background.urlPlaceholder')}\n onKeyDown={(e) => { if (e.key === 'Enter') handleUrlSubmit() }}\n onChange={(e) => setUrlText(e.currentTarget.value)}\n />\n <button\n type=\"button\"\n className={css.btn}\n disabled={!urlText.trim()}\n onClick={handleUrlSubmit}\n >\n {t('background.applyUrl')}\n </button>\n </div>\n </div>\n\n {/* Effects: stepped sliders + fit segmented control. */}\n <div className={css.section}>\n <div className={css.sectionLabel}>{t('background.effects')}</div>\n <ControlSlider name=\"opacity\" label={t('background.opacity')} value={draft.opacity} onLive={onLive} onCommit={onCommit} />\n <ControlSlider name=\"scrim\" label={t('background.scrim')} value={draft.scrim} onLive={onLive} onCommit={onCommit} />\n <ControlSlider name=\"panelOpacity\" label={t('background.panelOpacity')} value={draft.panelOpacity} onLive={onLive} onCommit={onCommit} />\n <ControlSlider name=\"blur\" label={t('background.blur')} value={draft.blur} onLive={onLive} onCommit={onCommit} />\n <ControlSlider name=\"wallpaperBlur\" label={t('background.wallpaperBlur')} value={draft.wallpaperBlur} onLive={onLive} onCommit={onCommit} />\n <div className={css.segRow}>\n <span className={css.segLabel}>{t('background.fit')}</span>\n <div className={css.segGroup} role=\"group\" aria-label={t('background.fit')}>\n {FIT_MODES.map((mode) => (\n <button\n key={mode}\n type=\"button\"\n className={clsx(css.segBtn, draft.fit === mode && css.segActive)}\n onClick={() => handleFit(mode)}\n >\n {t(mode === 'cover' ? 'background.cover' : 'background.contain')}\n </button>\n ))}\n </div>\n </div>\n <div className={css.segRow}>\n <span className={css.segLabel}>{t('background.timeline')}</span>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={draft.timeline}\n aria-label={t('background.timeline')}\n title={t('background.timelineHint')}\n className={css.switch}\n onClick={handleTimelineToggle}\n >\n <span className={css.switchKnob} />\n </button>\n <span className={css.hint}>{t('background.timelineHint')}</span>\n </div>\n </div>\n\n {error && <div className={css.error} role=\"alert\">{error}</div>}\n\n {hasImage && (\n <div className={css.clearRow}>\n <button type=\"button\" className={clsx(css.btn, css.btnDanger)} onClick={handleClear}>\n {t('background.clear')}\n </button>\n </div>\n )}\n </div>\n )\n}\n","/**\n * Timeline CSS — the conversation scroll-navigation rail (DeepSeek web\n * ScrollNav structure, rebuilt on this plugin's frosted-glass system).\n *\n * Structure and metrics mirror the official chat.deepseek.com stylesheet\n * (module map extracted from the shipped bundle; v0.1.4 of the reference port\n * dsh-chat-timeline widens the panel to 260px and adds bookmarks):\n * nav 34px-wide rail, fixed right edge, vertically centered; collapsed\n * blurred capsule (height − 8px); expanding panel (max 260px, radius 16)\n * whose scroll area holds 30px rows (tick indicator + fading-in title);\n * 32px gradient fade veils top/bottom shown while that side clips.\n *\n * Glass integration: the official chat.deepseek.com paints (light\n * rgba(255,255,255,.8)/.94, dark rgba(21,21,23,.6)/rgba(28,28,32,.95),\n * 5px collapsed / 16px expanded blur) remain as the NO-GLASS fallback.\n * While the plugin's glass system is on (`body[data-dsh-bg-glass]`), the\n * rail joins the SAME unified recipe as the composer card and bubbles:\n * fill = the painter's `--dsw-specific-input-major` token, blur/saturate/\n * brightness = the shared `--bg-glass-*` variables, i.e. the glass-blur\n * slider. Class prefix `dsbt-` deliberately avoids every\n * `[class*=\"_xxx\"]` anchor of the plugin's glass sheet (underscores only).\n */\n\n/** Unique id stamped on the injected style element (dedup key). */\nexport const TIMELINE_CSS_TAG = 'deepseek-harness-background/timeline'\n\n/** Inject the timeline stylesheet once. Idempotent (dedup key on the tag). */\nexport function injectTimelineCss(): void {\n if (typeof document === 'undefined') return\n if (document.querySelector(`style[data-plugin-css=\"${TIMELINE_CSS_TAG}\"]`)) return\n const tag = document.createElement('style')\n tag.dataset.plugin = 'deepseek-harness-background'\n tag.dataset.pluginCss = TIMELINE_CSS_TAG\n tag.textContent = TIMELINE_CSS\n document.head.appendChild(tag)\n}\n\nexport const TIMELINE_CSS = `\n .dsbt-nav {\n user-select: none; -webkit-user-select: none;\n z-index: 90; align-items: center; width: 34px;\n height: var(--dsbt-h, 300px);\n transition: right .2s ease, opacity .2s ease;\n display: flex; position: fixed; top: 50%; right: 16px;\n transform: translateY(-50%); pointer-events: auto;\n }\n @media (max-width: 767px) { .dsbt-nav { display: none; } }\n\n /* Collapsed capsule — frosted strip behind the tick marks. Official paint:\n light rgba(255,255,255,.8), dark rgba(21,21,23,.6), 5px blur. */\n .dsbt-bg {\n background-color: rgba(255, 255, 255, .8);\n -webkit-backdrop-filter: blur(5px);\n backdrop-filter: blur(5px);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, .28),\n inset 0 0 0 .5px rgba(255, 255, 255, .1),\n 0 6px 18px rgba(0, 0, 0, .07);\n border-radius: 16px; width: 34px;\n height: calc(var(--dsbt-h, 300px) - 8px); max-height: calc(var(--dsbt-h, 300px) - 8px);\n position: absolute; top: 50%; right: 0; transform: translateY(-50%);\n transition: opacity .2s ease; pointer-events: none;\n }\n body[data-ds-dark-theme] .dsbt-bg {\n background-color: rgba(21, 21, 23, .6);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, .09),\n inset 0 0 0 .5px rgba(255, 255, 255, .05),\n 0 6px 18px rgba(0, 0, 0, .3);\n }\n .dsbt-bg.dsbt-bg-hide { opacity: 0; }\n\n /* Expanding panel — exactly the capsule's box (identical height in both\n states), width animates 34px -> measured fit (max 260px). Official\n hover-state paint: white/black frosted glass at ~94% alpha, 16px blur. */\n .dsbt-wrap {\n width: 34px;\n height: calc(var(--dsbt-h, 300px) - 8px); max-height: calc(var(--dsbt-h, 300px) - 8px);\n border: 1px solid transparent; border-radius: 16px;\n flex-direction: column; align-items: stretch;\n transition: width .22s cubic-bezier(.4, 0, .2, 1), background-color .2s ease,\n box-shadow .2s ease, border-color .2s ease;\n display: flex; position: absolute; top: 50%; right: 0;\n transform: translateY(-50%);\n overflow: hidden; box-sizing: border-box; background: transparent;\n pointer-events: none;\n }\n .dsbt-wrap.dsbt-show {\n pointer-events: auto;\n width: min(var(--dsbt-w, 260px), 260px);\n background-color: rgba(255, 255, 255, .94);\n -webkit-backdrop-filter: blur(16px);\n backdrop-filter: blur(16px);\n border-color: rgba(0, 0, 0, .06);\n box-shadow: 0 10px 30px rgba(0, 0, 0, .08), 0 2px 8px rgba(0, 0, 0, .04);\n }\n body[data-ds-dark-theme] .dsbt-wrap.dsbt-show {\n background-color: rgba(28, 28, 32, .95);\n border-color: rgba(255, 255, 255, .08);\n box-shadow: 0 10px 30px rgba(0, 0, 0, .45), 0 2px 8px rgba(0, 0, 0, .25);\n }\n\n /* Content fade veils — the official ::before/::after pair rebuilt as\n elements: a bar of the panel's OWN fill color masked to nothing over\n 32px (solid -> mask == gradient-to-transparent, but works with the\n translucent fill). Shown only while that side actually clips. */\n .dsbt-fade {\n z-index: 2; pointer-events: none; opacity: 0;\n background-color: rgba(255, 255, 255, .94);\n -webkit-mask-image: linear-gradient(#000 20.19%, transparent 100%);\n mask-image: linear-gradient(#000 20.19%, transparent 100%);\n width: 100%; height: 32px; transition: opacity .2s ease;\n position: absolute; left: 0; top: 0;\n }\n body[data-ds-dark-theme] .dsbt-fade { background-color: rgba(28, 28, 32, .95); }\n .dsbt-fade.dsbt-fade-bot { top: auto; bottom: 0; transform: rotate(180deg); }\n .dsbt-fade.dsbt-fade-on { opacity: 1; }\n\n /* Filter bar — \"marked only\" toggle pinned above the scroll area. */\n .dsbt-filterbar {\n padding: 8px 12px 4px; display: flex; justify-content: flex-end;\n align-items: center; border-bottom: 1px solid rgba(0, 0, 0, .05);\n box-sizing: border-box; flex: none; transition: opacity .2s ease;\n }\n .dsbt-wrap:not(.dsbt-show) .dsbt-filterbar { opacity: 0; }\n body[data-ds-dark-theme] .dsbt-filterbar { border-bottom-color: rgba(255, 255, 255, .06); }\n .dsbt-filterbtn {\n font-size: 11px; line-height: 16px; padding: 2px 8px; border-radius: 10px;\n border: 1px solid rgba(0, 0, 0, .1); background: rgba(0, 0, 0, .03);\n color: rgba(0, 0, 0, .65); cursor: pointer; transition: all .15s ease;\n display: inline-flex; align-items: center; gap: 3px; font-family: inherit;\n }\n .dsbt-filterbtn:hover { background: rgba(0, 0, 0, .07); color: rgba(0, 0, 0, .9); }\n .dsbt-filterbtn.dsbt-filteron {\n background: rgba(245, 158, 11, .12); border-color: #f59e0b;\n color: #b45309; font-weight: 600;\n }\n body[data-ds-dark-theme] .dsbt-filterbtn {\n border-color: rgba(255, 255, 255, .12); background: rgba(255, 255, 255, .05);\n color: rgba(255, 255, 255, .7);\n }\n body[data-ds-dark-theme] .dsbt-filterbtn:hover { background: rgba(255, 255, 255, .1); color: rgba(255, 255, 255, .95); }\n body[data-ds-dark-theme] .dsbt-filterbtn.dsbt-filteron {\n background: rgba(251, 191, 36, .18); border-color: #fbbf24; color: #fbbf24;\n }\n\n /* Scroll area — rows hug the right edge; scrolls only when overfull. */\n .dsbt-page {\n padding: 15px 0 15px 24px; box-sizing: border-box;\n overscroll-behavior: contain; flex: 1 1 auto; min-height: 0;\n flex-direction: column; align-items: flex-end; display: flex;\n position: relative; width: 100%; overflow: hidden;\n }\n .dsbt-wrap.dsbt-show .dsbt-page {\n overflow-y: auto; overflow-x: hidden;\n scrollbar-width: thin; scrollbar-color: rgba(0, 0, 0, .15) transparent;\n }\n body[data-ds-dark-theme] .dsbt-wrap.dsbt-show .dsbt-page { scrollbar-color: rgba(255, 255, 255, .25) transparent; }\n .dsbt-page::-webkit-scrollbar { width: 4px; }\n .dsbt-page::-webkit-scrollbar-track { background: transparent; }\n .dsbt-page::-webkit-scrollbar-thumb { background: rgba(0, 0, 0, .15); border-radius: 4px; }\n body[data-ds-dark-theme] .dsbt-page::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .25); }\n\n /* Empty state (filtered list with no marks). */\n .dsbt-empty {\n font-size: 12px; line-height: 18px; padding: 16px 12px;\n color: rgba(0, 0, 0, .45); text-align: center; width: 100%; box-sizing: border-box;\n }\n body[data-ds-dark-theme] .dsbt-empty { color: rgba(255, 255, 255, .45); }\n\n /* One message row: 30px, star bookmark + tick indicator at the right,\n title fading in. */\n .dsbt-item {\n cursor: pointer; height: 30px; min-height: 30px; flex-shrink: 0;\n justify-content: flex-end; align-items: center;\n width: calc(100% - 4px); margin-right: 4px; line-height: 20px;\n display: flex; background: none; border: none; font: inherit;\n text-align: right; box-sizing: border-box; padding: 0;\n color: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, .65));\n transition: color .15s ease;\n }\n .dsbt-item:hover { color: var(--dsw-alias-label-primary, rgba(0, 0, 0, .95)); }\n body[data-ds-dark-theme] .dsbt-item { color: rgba(255, 255, 255, .65); }\n body[data-ds-dark-theme] .dsbt-item:hover { color: rgba(255, 255, 255, .95); }\n .dsbt-title {\n font-size: 13px; line-height: 20px; flex: 1 1 auto; min-width: 0;\n text-overflow: ellipsis; white-space: nowrap; overflow: hidden;\n margin-right: 6px; text-align: right; color: inherit;\n opacity: 0; transition: opacity .12s ease, color .15s ease;\n }\n .dsbt-show .dsbt-title { opacity: 1; }\n\n /* Star bookmark — appears on row hover while the panel is expanded; gold\n when marked. Keyboard-operable (span[role=button]). */\n .dsbt-star {\n font-size: 13px; line-height: 16px; width: 18px; height: 18px;\n display: inline-flex; align-items: center; justify-content: center;\n opacity: 0; cursor: pointer; transition: all .15s ease; margin-right: 6px;\n flex-shrink: 0; color: rgba(0, 0, 0, .25); border-radius: 4px; user-select: none;\n -webkit-user-select: none;\n }\n .dsbt-wrap.dsbt-show .dsbt-item:hover .dsbt-star { opacity: .75; }\n .dsbt-wrap.dsbt-show .dsbt-star:hover { opacity: 1; transform: scale(1.2); color: #d97706; }\n .dsbt-wrap.dsbt-show .dsbt-star.dsbt-staron { opacity: 1; color: #f59e0b; }\n body[data-ds-dark-theme] .dsbt-star { color: rgba(255, 255, 255, .25); }\n body[data-ds-dark-theme] .dsbt-wrap.dsbt-show .dsbt-star:hover { color: #fde047; }\n body[data-ds-dark-theme] .dsbt-wrap.dsbt-show .dsbt-star.dsbt-staron { opacity: 1; color: #fbbf24; }\n\n .dsbt-ind { flex-shrink: 0; justify-content: center; align-items: center; width: 16px; height: 20px; display: flex; }\n .dsbt-line {\n background-color: var(--dsw-alias-border-l4, rgba(0, 0, 0, .16));\n border-radius: 4px; flex-shrink: 0; width: 8px; height: 2px;\n transition: background-color .2s ease, transform .2s ease, width .2s ease, height .2s ease;\n }\n .dsbt-item:hover .dsbt-line { background-color: var(--dsw-alias-label-primary, rgba(0, 0, 0, .9)); }\n .dsbt-item.dsbt-active { color: var(--dsw-alias-state-business-primary, #4d6bfe); }\n .dsbt-item.dsbt-active .dsbt-title { color: var(--dsw-alias-state-business-primary, #4d6bfe); font-weight: 500; }\n .dsbt-item.dsbt-active .dsbt-line {\n background-color: var(--dsw-alias-state-business-primary, #4d6bfe);\n transform-origin: 50%; transform: scale(1.5);\n }\n body[data-ds-dark-theme] .dsbt-item.dsbt-active { color: var(--dsw-alias-state-business-primary, #4d6bfe); }\n body[data-ds-dark-theme] .dsbt-line { background-color: rgba(255, 255, 255, .2); }\n body[data-ds-dark-theme] .dsbt-item:hover .dsbt-line { background-color: rgba(255, 255, 255, .9); }\n\n /* Marked (key-point) rows: a wider golden tick in both themes; the active\n state keeps its brand-blue scale so reading position always wins. */\n .dsbt-item.dsbt-marked .dsbt-line { background-color: #d97706; width: 10px; height: 2.5px; }\n .dsbt-item.dsbt-marked:hover .dsbt-line { background-color: #b45309; }\n .dsbt-item.dsbt-marked.dsbt-active .dsbt-line {\n background-color: var(--dsw-alias-state-business-primary, #4d6bfe);\n transform-origin: 50%; transform: scale(1.5);\n }\n body[data-ds-dark-theme] .dsbt-item.dsbt-marked .dsbt-line { background-color: #fbbf24; width: 10px; height: 2.5px; }\n body[data-ds-dark-theme] .dsbt-item.dsbt-marked:hover .dsbt-line { background-color: #fde047; }\n\n /* ---- Unified glass integration -----------------------------------------\n Glass system on (wallpaper active + panelOpacity < 1): the rail joins\n the composer/bubble recipe — the same translucent fill token and the\n same blur/saturate/brightness chain (the glass-blur slider drives it,\n no fixed 5/16px). Placed after the dark-theme rules so equal-specificity\n overrides win in both schemes. */\n body[data-dsh-bg-glass] .dsbt-bg,\n body[data-dsh-bg-glass] .dsbt-wrap.dsbt-show {\n background-color: var(--dsw-specific-input-major);\n -webkit-backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);\n backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);\n }\n body[data-dsh-bg-glass] .dsbt-fade {\n background-color: var(--dsw-specific-input-major);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .dsbt-nav, .dsbt-bg, .dsbt-wrap, .dsbt-fade, .dsbt-title, .dsbt-line, .dsbt-star, .dsbt-filterbtn, .dsbt-filterbar { transition: none; }\n }\n`\n","/**\n * Conversation timeline rail — DeepSeek web ScrollNav rebuilt on this\n * plugin's frosted-glass system (styles: ./timeline-css.ts).\n *\n * Collapsed: a fixed 34px-wide frosted capsule at the right edge, vertically\n * centered, one tick per user message (active tick scaled + brand blue,\n * key-point bookmarks golden). Hovering expands the SAME box into a frosted\n * panel listing every user question (title fades in; >8 messages widen to\n * 260px, otherwise the width fits the longest title). Both states share one\n * computed outer height, so expanding never jumps, and 32px fade veils mask\n * the clipped edge on each side while that side actually scrolls.\n *\n * Enhancements ported from dsh-chat-timeline v0.1.4 (MIT):\n * - Key-point bookmarks: star a question in the expanded panel, persisted per\n * session in localStorage; marked rows show a golden tick in the capsule\n * and a \"marked only\" filter narrows the list.\n * - Jump stabilization: the reading-position tracker freezes while a smooth\n * jump animates (cleared 150ms after the last scroll event, plus an 800ms\n * fallback), so the panel cannot jitter mid-jump.\n * - Rewind integration: messages withdrawn by a rewind command node are\n * filtered out of the rail.\n *\n * Data source (client-side only): loaded chat nodes -> background loadOlder\n * loop until complete. Clicking a row loads older history on demand, scrolls\n * the conversation to the target row, and keeps the rail's own active row\n * visible.\n *\n * The rail reads the shared settings transport: it renders unless\n * `timeline: false`. Its glass paints are self-contained official values\n * (see timeline-css.ts), independent of the plugin's token overrides.\n */\n\nimport react from 'react'\nimport reactDom from 'react-dom'\nimport { settingsClient } from './settings-client.ts'\nimport { injectTimelineCss } from './timeline-css.ts'\n\n// Inject the stylesheet once at module evaluation (the loader removes\n// plugin-owned tags on unload; re-evaluation dedupes on the tag id).\nif (typeof document !== 'undefined') injectTimelineCss()\n\n/** Structural view of one chat node this rail consumes. */\ninterface ChatNodeLike {\n kind?: string\n key?: string\n anchorSeq?: number\n data?: {\n time?: number\n content?: unknown\n name?: unknown\n seq?: unknown\n args?: unknown\n outcome?: { kind?: unknown; sourceEventSeq?: unknown; text?: unknown }\n }\n}\n\n/** One normalized user-message entry in the rail. */\nexport interface TimelineMessage {\n seq: number\n time: number\n text: string\n key?: string\n}\n\n/** Session handle face the rail needs off the runtime sessions service. */\nexport interface TimelineSessionHandle {\n subscribe(listener: () => void): () => void\n getSnapshot(): unknown\n loadOlder(): Promise<unknown>\n}\n\n/** Sessions service face (narrowed to what jump/data collection touches). */\nexport interface TimelineSessionsService {\n binding(sessionId: string): { session: TimelineSessionHandle } | undefined\n}\n\n/** Component props delivered by the dock slot registration. */\nexport interface TimelineRailProps {\n sessionId?: string\n sessionsService?: TimelineSessionsService\n t: (key: string) => string\n}\n\nconst delay = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms))\n\n/** Extract preview text from a user message's ContentBlock list. */\nfunction userTextOf(content: unknown): string {\n if (!Array.isArray(content)) return ''\n let out = ''\n for (const block of content) {\n if (block !== null && typeof block === 'object' && (block as { type?: unknown }).type === 'text') {\n const text = (block as { text?: unknown }).text\n if (typeof text === 'string') out += text\n }\n }\n return out.trim().slice(0, 80)\n}\n\n/* ---- Key-point bookmarks (ported from dsh-chat-timeline v0.1.4) --------- */\n\n/**\n * Stable bookmark key for one entry: the durable message key, falling back to\n * the anchor seq — so marks survive history reloads. Entries with neither are\n * not markable (empty key).\n * @param m - the entry (or any shaped object).\n */\nexport function markKeyOf(m: unknown): string {\n if (m === null || typeof m !== 'object') return ''\n const rec = m as { key?: unknown; seq?: unknown }\n if (typeof rec.key === 'string' && rec.key !== '') return `key:${rec.key}`\n return typeof rec.seq === 'number' ? `seq:${rec.seq}` : ''\n}\n\n/** localStorage key prefix for the per-session marked-key lists. */\nexport const MARKS_STORAGE_PREFIX = 'dsbt_marks_'\n\n/**\n * Read the marked keys for one session from localStorage.\n * @param sessionId - the session the marks belong to.\n */\nexport function readMarks(sessionId: string | undefined): string[] {\n if (typeof window === 'undefined' || !sessionId) return []\n try {\n const raw = window.localStorage.getItem(MARKS_STORAGE_PREFIX + sessionId)\n if (!raw) return []\n const parsed: unknown = JSON.parse(raw)\n return Array.isArray(parsed) ? parsed.filter((k): k is string => typeof k === 'string') : []\n } catch {\n return []\n }\n}\n\n/**\n * Persist the marked keys for one session (removes the key when empty).\n * @param sessionId - the session the marks belong to.\n * @param marks - the marked-key list.\n */\nexport function writeMarks(sessionId: string | undefined, marks: string[]): void {\n if (typeof window === 'undefined' || !sessionId) return\n try {\n if (!Array.isArray(marks) || marks.length === 0) window.localStorage.removeItem(MARKS_STORAGE_PREFIX + sessionId)\n else window.localStorage.setItem(MARKS_STORAGE_PREFIX + sessionId, JSON.stringify(marks))\n } catch { /* storage unavailable — marks stay in-memory */ }\n}\n\n/* ---- Rewind integration (ported from dsh-chat-timeline v0.1.4) ---------- */\n\n/**\n * Extract the rewind target seq from a rewind outcome text.\n * @param text - the command outcome text.\n */\nexport function rewindTargetOfOutcome(text: unknown): number | undefined {\n if (typeof text !== 'string') return undefined\n const match = /rewound.*?(?:target\\s+)?(\\d+)/i.exec(text) ?? /#(\\d+)/.exec(text)\n const digits = match?.[1]\n if (digits === undefined) return undefined\n const n = Number.parseInt(digits, 10)\n return Number.isFinite(n) ? n : undefined\n}\n\n/**\n * Is this rewind command a preview/dry-run (marks the target hidden without\n * an outcome)?\n * @param command - the command payload.\n */\nfunction isRewindPreviewCommand(command: { args?: unknown }): boolean {\n if (command.args === null || typeof command.args !== 'object') return false\n const args = command.args as { preview?: unknown; dryRun?: unknown }\n return args.preview === true || args.dryRun === true\n}\n\n/**\n * Collect the seq numbers a rewind hid: preview commands hide their target\n * directly; successful commands hide their own row plus every node anchored\n * inside the rewound span [target, sourceEventSeq].\n * @param chat - a chat snapshot (loosely typed on purpose).\n */\nexport function hiddenSeqsOfChat(chat: unknown): Set<number> {\n const hidden = new Set<number>()\n if (chat === null || typeof chat !== 'object') return hidden\n const nodes = (chat as { nodes?: Map<string, ChatNodeLike> }).nodes\n if (nodes === undefined || typeof nodes.values !== 'function') return hidden\n const all = [...nodes.values()]\n const spans: { start: number; end: number }[] = []\n for (const node of all) {\n if (node === null || typeof node !== 'object') continue\n if (node.kind !== 'command') continue\n const command = node.data\n if (command === null || typeof command !== 'object') continue\n if (command.name !== 'rewind') continue\n if (isRewindPreviewCommand(command)) {\n if (typeof command.seq === 'number') hidden.add(command.seq)\n continue\n }\n const outcome = command.outcome\n if (outcome === null || typeof outcome !== 'object' || outcome.kind !== 'success') continue\n const marker = outcome.sourceEventSeq\n if (typeof marker !== 'number') continue\n if (typeof command.seq === 'number') hidden.add(command.seq)\n const target = rewindTargetOfOutcome(outcome.text)\n if (target !== undefined) spans.push({ start: target, end: marker })\n }\n if (spans.length === 0) return hidden\n for (const node of all) {\n if (node === null || typeof node !== 'object') continue\n const anchor = typeof node.anchorSeq === 'number' ? node.anchorSeq : undefined\n if (anchor === undefined) continue\n if (spans.some((span) => anchor >= span.start && anchor <= span.end)) hidden.add(anchor)\n }\n return hidden\n}\n\n/**\n * Enumerate user messages from the loaded chat-node snapshot (the client-side\n * collector; sorted by anchor sequence, rewind-hidden entries dropped).\n * @param snapshot - a session snapshot (loosely typed on purpose).\n */\nexport function collectMessages(snapshot: unknown): TimelineMessage[] {\n const chat = (snapshot as { chat?: { nodes?: Map<string, ChatNodeLike> } } | undefined)?.chat\n const nodes = chat?.nodes\n if (nodes === undefined || typeof nodes.values !== 'function') return []\n const hidden = hiddenSeqsOfChat(chat)\n const out: TimelineMessage[] = []\n for (const node of nodes.values()) {\n if (node === null || typeof node !== 'object') continue\n if (node.kind !== 'user') continue\n const data = node.data\n if (data === null || typeof data !== 'object' || typeof data.time !== 'number' || !Array.isArray(data.content)) continue\n const key = typeof node.key === 'string' ? node.key : undefined\n if (key === undefined) continue\n const seq = typeof node.anchorSeq === 'number' ? node.anchorSeq : 0\n if (hidden.has(seq)) continue\n out.push({ seq, time: data.time, text: userTextOf(data.content), key })\n }\n out.sort((a, b) => a.seq - b.seq)\n return out\n}\n\n/** Resolve the DOM anchor key of one entry (direct key form only). */\nexport function resolveAnchorKey(m: TimelineMessage): string | undefined {\n return typeof m.key === 'string' && m.key !== '' ? m.key : undefined\n}\n\n/**\n * Outer rail height for a message count: rows + breathing room, clamped so\n * both states always share the exact same height (never jumps on expand).\n * @param count - number of user messages.\n */\nexport function railHeightFor(count: number): number {\n return Math.max(140, Math.min(300, count * 30 + 38))\n}\n\n/** Longest-title width estimate bounds. */\nconst RAIL_MIN_WIDTH = 96\nconst RAIL_MAX_WIDTH = 260\n\n/**\n * Measure the expanded-panel width for the given titles (canvas text metrics;\n * falls back to the max width when measurement is unavailable). Accounts for\n * the star column so a marked row never clips its tick.\n * @param texts - the message previews.\n */\nexport function railWidthFor(texts: string[]): number {\n if (texts.length > 8) return RAIL_MAX_WIDTH\n let widest = 0\n if (typeof document !== 'undefined') {\n const canvas = document.createElement('canvas')\n const ctx = canvas.getContext('2d')\n if (ctx) {\n ctx.font = '13px -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif'\n for (const t of texts) {\n const w = ctx.measureText(t === '' ? '…' : t).width\n if (w > widest) widest = w\n }\n }\n }\n // Title + title gap + star column + indicator + item gutters + border/padding.\n return Math.round(Math.max(RAIL_MIN_WIDTH, Math.min(RAIL_MAX_WIDTH, widest + 6 + 24 + 16 + 12)))\n}\n\n/** Ensure the target node is loaded, then scroll its row into view. */\nasync function jumpToMessage(sessionsService: TimelineSessionsService, sessionId: string, key: string): Promise<boolean> {\n const session = sessionsService.binding(sessionId)?.session\n if (session === undefined) return false\n let guard = 0\n while (guard++ < 120) {\n const snapshot = session.getSnapshot() as { chat?: { nodes?: Map<string, unknown> }; hasMore?: boolean; loadingOlder?: boolean }\n if (snapshot?.chat?.nodes?.get(key) !== undefined) break\n if (snapshot?.hasMore !== true) return false\n if (snapshot.loadingOlder === true) {\n await delay(50)\n continue\n }\n await session.loadOlder()\n }\n const scrollport = document.querySelector('[data-conversation-scroll]')\n const row = scrollport?.querySelector(`[data-chat-anchor-key=\"${CSS.escape(key)}\"]`) ?? null\n if (row === null) return false\n const reducedMotion = typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches\n row.scrollIntoView({ behavior: reducedMotion ? 'auto' : 'smooth', block: 'center' })\n return true\n}\n\n/**\n * Scroll only the rail itself so the active row stays visible (min distance).\n * offsetTop math instead of getBoundingClientRect: stable while the panel's\n * own smooth scroll animates (no feedback loop with live rects).\n */\nfunction scrollTimelineItemIntoView(page: HTMLElement, item: HTMLElement): void {\n const pageTop = page.scrollTop\n const pageBottom = pageTop + page.clientHeight\n const itemTop = item.offsetTop\n const itemBottom = itemTop + item.offsetHeight\n if (itemTop < pageTop) page.scrollTop = Math.max(0, itemTop - 10)\n else if (itemBottom > pageBottom) page.scrollTop = itemBottom - page.clientHeight + 10\n}\n\n/** Is another timeline rail already mounted (e.g. dsh-chat-timeline)? */\nfunction otherRailPresent(): boolean {\n return document.querySelector('.dsct_nav') !== null\n}\n\n/**\n * The timeline rail component. Portaled to body; registered into the\n * conversation input dock purely to bind per-session lifecycle.\n */\nexport function TimelineRail(props: TimelineRailProps): react.ReactElement | null {\n const { sessionId, sessionsService, t } = props\n\n // Shared settings: the rail hides while timeline === false. Read through a\n // hook like every other store here, but the gate itself must sit with the\n // FINAL early return below — an early return between hooks would crash\n // React (\"rendered fewer hooks\") the moment the toggle flips mid-session.\n const settings = react.useSyncExternalStore(settingsClient.subscribe, settingsClient.getSnapshot)\n // Hide only while the persisted toggle is UNKNOWN (no wrong-state flash for\n // timeline:false users); once loading settles the default-on rail renders\n // even if the section errored.\n const timelineUnknown = settings.status === 'loading'\n const timelineDisabled = settings.value?.timeline === false\n\n const session = sessionId !== undefined && sessionsService !== undefined ? sessionsService.binding(sessionId)?.session : undefined\n // SessionFace methods are prototype methods reading \"this\"; React invokes\n // store callbacks as bare functions, so keep the receiver via closures\n // (same shape as the host's own wiring, e.g. ModelSelect). Identity stays\n // stable per session so uSES does not resubscribe on every render.\n const subscribeSession = react.useCallback(\n (listener: () => void) => session === undefined ? () => {} : session.subscribe(listener),\n [session],\n )\n const snapshotSession = react.useCallback(\n () => session === undefined ? undefined : session.getSnapshot(),\n [session],\n )\n const nodeSnapshot = react.useSyncExternalStore(subscribeSession, snapshotSession)\n\n // Collected per snapshot change (the collector allocates + sorts); memoized\n // so width measurement and tracking effects key on content, not renders.\n const messages = react.useMemo(() => collectMessages(nodeSnapshot), [nodeSnapshot])\n\n const [loadedAll, setLoadedAll] = react.useState(false)\n const [activeIndex, setActiveIndex] = react.useState(-1)\n const [show, setShow] = react.useState(false)\n const [rightOffset, setRightOffset] = react.useState(16)\n const [railWidth, setRailWidth] = react.useState(RAIL_MAX_WIDTH)\n const [fades, setFades] = react.useState({ top: false, bottom: false })\n const [hidden, setHidden] = react.useState(() => otherRailPresent())\n // Key-point bookmarks: per-session list + the \"marked only\" filter toggle.\n const [marks, setMarks] = react.useState<string[]>(() => readMarks(sessionId))\n const [marksOnly, setMarksOnly] = react.useState(false)\n const [isNarrow, setIsNarrow] = react.useState(\n () => typeof window !== 'undefined' && typeof window.matchMedia === 'function'\n && window.matchMedia('(max-width: 767px)').matches,\n )\n const pageRef = react.useRef<HTMLDivElement | null>(null)\n const activeItemRef = react.useRef<HTMLButtonElement | null>(null)\n // Jump-stabilization lock: freezes the reading-position tracker while a\n // click-triggered smooth jump animates (cleared by the settle timer below\n // or the 800ms fallback in the click handler). The fallback timeout is\n // tracked so the settle path can cancel it and unmount cannot leak it.\n const jumpPendingRef = react.useRef(false)\n const jumpFallbackRef = react.useRef<number | undefined>(undefined)\n\n // Marks follow the session switch; the filter resets with them.\n react.useEffect(() => {\n setMarks(readMarks(sessionId))\n setMarksOnly(false)\n }, [sessionId])\n\n const markedSet = react.useMemo(() => new Set(marks), [marks])\n // Mirror ref so rapid successive toggles always see the latest list (the\n // handler writes storage directly, outside the setState updater — updaters\n // must stay pure and StrictMode re-runs them).\n const marksRef = react.useRef(marks)\n marksRef.current = marks\n const toggleMark = react.useCallback((m: TimelineMessage) => {\n const k = markKeyOf(m)\n if (k === '') return\n const prev = marksRef.current\n const next = prev.includes(k) ? prev.filter((x) => x !== k) : [...prev, k]\n marksRef.current = next\n setMarks(next)\n writeMarks(sessionId, next)\n }, [sessionId])\n\n // Narrow-viewport guard (matches the official breakpoint).\n react.useEffect(() => {\n if (typeof window.matchMedia !== 'function') return\n const mql = window.matchMedia('(max-width: 767px)')\n const onChange = (e: MediaQueryListEvent): void => setIsNarrow(e.matches)\n mql.addEventListener('change', onChange)\n return () => mql.removeEventListener('change', onChange)\n }, [])\n\n // Background full-history load: follow hasMore until complete. Skipped\n // entirely while the rail is switched off (or standing aside for another\n // rail) — paging the whole history into the client window is wasted work\n // when nothing renders.\n react.useEffect(() => {\n if (session === undefined || isNarrow || sessionId === undefined || timelineUnknown || timelineDisabled || hidden) return\n setLoadedAll(false)\n let cancelled = false\n const run = async (): Promise<void> => {\n let guard = 0\n while (!cancelled && guard++ < 120) {\n const snap = session.getSnapshot() as { hasMore?: boolean; loadingOlder?: boolean }\n if (snap?.hasMore !== true) break\n if (snap.loadingOlder === true) {\n await delay(50)\n continue\n }\n await session.loadOlder()\n }\n if (!cancelled) setLoadedAll(true)\n }\n void run().catch(() => { if (!cancelled) setLoadedAll(true) })\n return () => { cancelled = true }\n }, [sessionId, isNarrow, session, timelineUnknown, timelineDisabled, hidden])\n\n // Width follows the longest title (remeasured when messages arrive/change);\n // loadedAll gates it so late history cannot leave a stale narrow rail.\n react.useEffect(() => {\n if (!loadedAll && messages.length > 0) return\n setRailWidth(railWidthFor(messages.map((m) => m.text)))\n }, [loadedAll, messages])\n\n // Reading position tracking: nearest user row to the 40% viewport line.\n react.useEffect(() => {\n if (messages.length === 0) return\n const indexByKey = new Map<string, number>()\n messages.forEach((m, i) => {\n const key = resolveAnchorKey(m)\n if (key !== undefined) indexByKey.set(key, i)\n })\n const updateActive = (): void => {\n // A jump is animating: freeze the highlight so the panel cannot jitter.\n if (jumpPendingRef.current) return\n const sp = document.querySelector('[data-conversation-scroll]')\n if (sp === null) return\n const rect = sp.getBoundingClientRect()\n if (rect.height === 0) return\n const line = rect.top + rect.height * 0.4\n const rows = sp.querySelectorAll('[data-chat-anchor-key]')\n let best = -1\n let bestDist = Infinity\n for (const row of rows) {\n const key = row.getAttribute('data-chat-anchor-key')\n if (key === null) continue\n const idx = indexByKey.get(key) ?? -1\n if (idx === -1) continue\n const r = row.getBoundingClientRect()\n const dist = Math.abs(r.top + r.height / 2 - line)\n if (dist < bestDist) {\n bestDist = dist\n best = idx\n }\n }\n setActiveIndex(best)\n }\n updateActive()\n const el = document.querySelector('[data-conversation-scroll]')\n let timer: number | undefined\n let settleTimer: number | undefined\n const onScroll = (): void => {\n // Detect the true end of scrolling: 150ms after the LAST scroll event\n // release the jump lock and refresh the highlight exactly once.\n if (settleTimer !== undefined) clearTimeout(settleTimer)\n settleTimer = window.setTimeout(() => {\n settleTimer = undefined\n if (jumpPendingRef.current) {\n jumpPendingRef.current = false\n if (jumpFallbackRef.current !== undefined) {\n clearTimeout(jumpFallbackRef.current)\n jumpFallbackRef.current = undefined\n }\n updateActive()\n }\n }, 150)\n if (timer !== undefined) return\n timer = window.setTimeout(() => {\n timer = undefined\n updateActive()\n }, 60)\n }\n el?.addEventListener('scroll', onScroll, { passive: true })\n const interval = window.setInterval(updateActive, 2000)\n return () => {\n if (timer !== undefined) clearTimeout(timer)\n if (settleTimer !== undefined) clearTimeout(settleTimer)\n if (jumpFallbackRef.current !== undefined) {\n clearTimeout(jumpFallbackRef.current)\n jumpFallbackRef.current = undefined\n }\n el?.removeEventListener('scroll', onScroll)\n clearInterval(interval)\n }\n }, [messages])\n\n // Fade veils reflect the page's actual clip state (scroll position).\n const syncFades = react.useCallback((): void => {\n const page = pageRef.current\n if (page === null) {\n setFades({ top: false, bottom: false })\n return\n }\n const canTop = page.scrollTop > 2\n const canBot = page.scrollTop + page.clientHeight < page.scrollHeight - 2\n setFades((prev) => (prev.top === canTop && prev.bottom === canBot ? prev : { top: canTop, bottom: canBot }))\n }, [])\n react.useEffect(syncFades, [syncFades, show, messages.length, loadedAll, marksOnly])\n\n // Keep the active row visible inside the rail without moving the chat.\n react.useLayoutEffect(() => {\n if (!show) return\n const page = pageRef.current\n const item = activeItemRef.current\n if (page === null || item === null) return\n scrollTimelineItemIntoView(page, item)\n syncFades()\n }, [activeIndex, messages.length, marksOnly, show, syncFades])\n\n // Avoid right-side workbenches: derive the offset from the chat scrollport.\n react.useEffect(() => {\n let raf = 0\n const measure = (): void => {\n raf = 0\n const sp = document.querySelector('[data-conversation-scroll]')\n if (sp === null) return\n const rect = sp.getBoundingClientRect()\n if (rect.width === 0 && rect.height === 0) return\n const next = Math.max(8, Math.round(window.innerWidth - rect.right + 12))\n setRightOffset((prev) => (Math.abs(prev - next) > 0.5 ? next : prev))\n }\n const schedule = (): void => {\n if (raf === 0) raf = window.requestAnimationFrame(measure)\n }\n const sp = document.querySelector('[data-conversation-scroll]')\n const ro = typeof ResizeObserver === 'function' && sp !== null ? new ResizeObserver(schedule) : null\n if (ro !== null && sp !== null) ro.observe(sp)\n window.addEventListener('resize', schedule)\n // Slow guard: pick up a competing rail (un)mounting mid-session.\n const guard = window.setInterval(() => setHidden(otherRailPresent()), 2000)\n measure()\n return () => {\n if (raf !== 0) cancelAnimationFrame(raf)\n ro?.disconnect()\n window.removeEventListener('resize', schedule)\n clearInterval(guard)\n }\n }, [])\n\n if (timelineUnknown || timelineDisabled\n || sessionId === undefined || sessionsService === undefined || isNarrow || hidden || messages.length < 2) {\n return null\n }\n\n const height = railHeightFor(messages.length)\n // Compare actives by bookmark key, not index: the filtered display list\n // reindexes rows, and the active ref must track the SAME question.\n const activeKey = activeIndex >= 0 && activeIndex < messages.length ? markKeyOf(messages[activeIndex]) : ''\n const displayMessages = marksOnly ? messages.filter((m) => markedSet.has(markKeyOf(m))) : messages\n\n return reactDom.createPortal(\n <div\n className=\"dsbt-nav\"\n style={{ right: rightOffset, ['--dsbt-h' as string]: `${height}px`, ['--dsbt-w' as string]: `${railWidth}px` }}\n role=\"navigation\"\n aria-label={t('timeline.railLabel')}\n onMouseEnter={() => setShow(true)}\n onMouseLeave={() => setShow(false)}\n >\n <div className={show ? 'dsbt-bg dsbt-bg-hide' : 'dsbt-bg'} />\n <div className={show ? 'dsbt-wrap dsbt-show' : 'dsbt-wrap'}>\n <div className=\"dsbt-filterbar\">\n <button\n type=\"button\"\n className={marksOnly ? 'dsbt-filterbtn dsbt-filteron' : 'dsbt-filterbtn'}\n aria-pressed={marksOnly}\n onClick={() => setMarksOnly((v) => !v)}\n >\n {t('timeline.marksOnly')}{marks.length > 0 ? ` (${marks.length})` : ''}\n </button>\n </div>\n <div className={fades.top ? 'dsbt-fade dsbt-fade-on' : 'dsbt-fade'} aria-hidden />\n <div className={fades.bottom ? 'dsbt-fade dsbt-fade-bot dsbt-fade-on' : 'dsbt-fade dsbt-fade-bot'} aria-hidden />\n <div\n className=\"dsbt-page\"\n ref={pageRef}\n onScroll={syncFades}\n >\n {displayMessages.length === 0\n ? <div className=\"dsbt-empty\">{t('timeline.noMarks')}</div>\n : displayMessages.map((m) => {\n const key = resolveAnchorKey(m)\n const mk = markKeyOf(m)\n const marked = markedSet.has(mk)\n const isActive = activeKey !== '' && mk === activeKey\n const cls = `dsbt-item${isActive ? ' dsbt-active' : ''}${marked ? ' dsbt-marked' : ''}`\n const label = `${marked ? '★ ' : ''}${t('timeline.roleUser')}: ${m.text.slice(0, 60) || t('timeline.noText')}`\n return (\n <button\n type=\"button\"\n key={m.seq}\n ref={isActive ? activeItemRef : undefined}\n className={cls}\n title={`${marked ? '★ ' : ''}${m.text === '' ? t('timeline.noText') : m.text}`}\n aria-label={label}\n aria-current={isActive ? 'location' : undefined}\n onClick={() => {\n if (key === undefined) return\n // Engage the stabilization lock with a fallback timeout:\n // the settle timer normally releases it after the jump.\n // A fresh click replaces the pending fallback so a rapid\n // second jump cannot be unlocked by the first one's timer.\n jumpPendingRef.current = true\n if (jumpFallbackRef.current !== undefined) clearTimeout(jumpFallbackRef.current)\n jumpFallbackRef.current = window.setTimeout(() => {\n jumpFallbackRef.current = undefined\n jumpPendingRef.current = false\n }, 800)\n void jumpToMessage(sessionsService, sessionId, key).catch(() => {})\n }}\n >\n <span className=\"dsbt-title\">{m.text === '' ? t('timeline.noText') : m.text}</span>\n <span\n className={marked ? 'dsbt-star dsbt-staron' : 'dsbt-star'}\n role=\"button\"\n tabIndex={0}\n aria-pressed={marked}\n aria-label={marked ? t('timeline.unmark') : t('timeline.mark')}\n onMouseDown={(e) => { e.stopPropagation(); e.preventDefault() }}\n onClick={(e) => { e.stopPropagation(); toggleMark(m) }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n e.stopPropagation()\n toggleMark(m)\n }\n }}\n >\n ★\n </span>\n <span className=\"dsbt-ind\" aria-hidden>\n <span className=\"dsbt-line\" />\n </span>\n </button>\n )\n })}\n </div>\n </div>\n </div>,\n document.body,\n )\n}\n","/**\n * Browser half of the background plugin: paints the background behind the\n * whole app frame, provides the settings surface (a live row inside the\n * official General settings section), and renders the conversation timeline\n * rail (DeepSeek ScrollNav style) on the same frosted-glass system. Data\n * flows through the plugin's own host route (`/api/bg-wallpaper/*`), not the\n * settings RPC. Retraction discipline mirrors the skin plugins: every\n * property and DOM node the painter owns is restored on dispose.\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport { backgroundPainter, paintBackground } from './backdrop.ts'\nimport { en, zh } from './locales.ts'\nimport { BackgroundSettingsRow } from './SettingsRow.tsx'\nimport { settingsClient } from './settings-client.ts'\nimport { TimelineRail } from './timeline.tsx'\nimport type {} from './types.ts'\n\n/**\n * Service injections this entry declares: `slots` + `locale` for the settings\n * surface and the timeline slot seat, and `sessions` so the timeline rail can\n * enumerate user messages and jump between them. The settings surface itself\n * talks to the plugin's own host route over plain same-origin fetch.\n */\nexport const inject = ['slots', 'locale', 'sessions']\n\n/**\n * Client plugin body: paint the persisted background live, register the\n * General-settings row, and mount the conversation timeline rail.\n * @param ctx - client cordis context (slots/locale/sessions injected).\n */\nexport function apply(ctx: Context): void {\n // Paint from the plugin's own transport; repaint on every snapshot change.\n const paint = (): void => {\n const snapshot = settingsClient.getSnapshot()\n const value = snapshot.status === 'ready' ? snapshot.value : undefined\n if (value === undefined || !value.enabled) {\n backgroundPainter.dispose()\n return\n }\n paintBackground(value)\n }\n const unsubscribe = settingsClient.subscribe(paint)\n void settingsClient.load()\n\n ctx.effect(() => ctx.locale.register('ui-background', { zh, en }), 'deepseek-harness-background: dictionaries')\n\n // Live settings row in the General section (same slot as the Appearance row).\n ctx.slots.inject('settings.general.item', () => ctx.slots.register({\n name: 'settings.general.item',\n id: 'deepseek-harness-background',\n order: 600,\n locale: 'ui-background',\n }, BackgroundSettingsRow))\n\n // Conversation timeline rail: takes a per-session dock seat only to bind\n // its lifecycle; the rail portals to body. The sessions service is handed\n // to the component through the registration's inject face — resolved\n // lazily inside the factory so a runtime-side service rebuild can never\n // leave the rail holding a stale reference.\n ctx.slots.inject('conversation.input.dock', () => ctx.slots.register({\n name: 'conversation.input.dock',\n id: 'deepseek-harness-background.timeline',\n order: 45,\n locale: 'ui-background',\n inject: () => ({ sessionsService: ctx.sessions }),\n }, TimelineRail))\n\n ctx.effect(() => () => {\n unsubscribe()\n backgroundPainter.dispose()\n }, 'deepseek-harness-background: background surface')\n}\n"],"x_google_ignoreList":[4],"mappings":"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"}
|