Files
browser/platform_web/theme
..
2026-07-11 14:56:10 +08:00
2026-07-11 14:56:10 +08:00
2026-07-11 14:56:10 +08:00
2026-07-11 14:56:10 +08:00

platform_web/theme

This directory owns the platform_web visual system. Keep the console in a unified game-operations style with two first-party theme families: the default black mecha console and the optional magical-girl console.

Style Contract

  • The UI is a game operations console, not a landing page and not a generic SaaS dashboard.
  • The default visual language is black mecha: dark cockpit panels, cyan scanner light, angular frame cuts, tactical grid lines, and amber energy accents.
  • The optional magical-girl visual language uses pink moonlight, jelly glass, gold star borders, ribbon glow, and large visible magic-circle motifs.
  • The primary menu is a compact admin sidebar with two states: an expanded text menu and a collapsed icon rail. It must keep the same route order, readable Chinese labels, icon-only tooltips in collapsed mode, and active state framing. In the magical-girl theme it should feel like a pink moonlit operations rail; in the default theme it should feel like a black mecha console rail with restrained scanner accents.
  • Global floating decoration must come from components/MagicalParticleLayer.tsx, using a full-workspace background image layer plus a lightweight global particle DOM layer that reads the active theme variables. Do not add fixed page-local decorative spans or page-local backdrop systems for sparkles, hearts, moons, sigils, or snowflakes.
  • Each theme must have its own visible low-cost ultimate effect: mecha themes use scanner/core/targeting effects, and magical-girl themes use large magic circles, star glints, and ribbon bursts. Do not implement the global effect as dozens of tiny rotating particles.
  • The background desktop is part of the interface. Major surfaces must remain translucent enough for the selected built-in or uploaded background to show through while preserving readable text.
  • Operational clarity wins over decoration. Logs, diffs, forms, errors, warning states, destructive confirmations, LLM review output, and operation/job feedback must stay readable and traceable.
  • Default visual assets must be original CSS/generated motifs. Do not bundle recognizable third-party character art. Users may upload their own backgrounds.

Files

  • tokens.ts: theme palette IDs, built-in desktop preset IDs, CSS variable values, local-storage keys, apply/persist helpers, and the live palette-change event used to keep shell chrome synchronized after theme switches.
  • base.css: shared CSS primitives for the shell, collapsible sidebar navigation, account/profile panel, cards, panels, tables, drawers, dialogs, logs, diffs, plugin groups, command buttons, mecha frame cuts, magical star frames, global background/particle layer placement, and responsive behavior.
  • tokens.test.ts: tests that lock the default black mecha palette, built-in mecha/magical desktop presets, palette-variable cleanup, and theme-change notifications.
  • base-css.test.js: CSS contract tests for shared frame behavior that should not be represented in TypeScript token tests.

Background Rules

  • defaultThemePaletteId must remain mecha-black unless an OpenSpec change explicitly replaces the visual direction.
  • defaultThemeBackgroundId should point to a built-in mecha desktop preset that works without uploaded imagery.
  • Built-in presets use CSS variables named --workspace-background-pattern-* and render behind the app shell.
  • Uploaded backgrounds use --workspace-background-image, set data-custom-background="true", and take visual precedence over the selected preset.
  • Removing an uploaded background must reveal the selected built-in preset again.
  • Theme palette switches must keep uploaded backgrounds intact. Changing from magical-girl to black mecha, or back again, must not clear --workspace-background-image or alter the custom-background fallback preset.
  • Any new preset must include an id, label, summary, preview, and all required --workspace-background-pattern-* variables. Current presets are 机甲格纳库 and 粉月魔法阵.

Theme Switching Rules

  • applyThemePalette() is the single writer for active palette variables. It must remove the union of known palette variables before applying the selected palette so previous-theme variables, such as magical-girl accessory SVGs, cannot leak into black mecha.
  • After applying a palette, applyThemePalette() must dispatch themePaletteChangeEvent. Shell chrome such as the sidebar subtitle and mini swatch strip should subscribe to that event instead of keeping stale local theme labels.
  • data-theme-palette on the document root is the source of truth for theme-specific CSS selectors. Do not infer the active theme from route state, component-local state, or background preset IDs.
  • Theme changes must be visually atomic: root marker, CSS variables, menu/sidebar chrome, active navigation frame, and shared surface accessories should all reflect the same selected palette immediately.

Surface Rules

  • Use shared classes such as metric-card, overview-card, console-panel, catalog-card, server-card, server-detail-header, resource-table-wrap, provider-table-wrap, drawer-panel, confirm-panel, plugin-group, and operation-item instead of creating page-local card styles.
  • Shared framed surfaces should use var(--panel-material), var(--panel-shadow), var(--frame-corner), and var(--frame-accent) so each theme can change structure, fill, and glow style beyond simple color swaps.
  • A visual region should have only one ornamental frame at a hierarchy level. If a .state-view is nested inside a shared framed parent such as .console-panel, .catalog-card, .server-card, .resource-table-wrap, .provider-table-wrap, .server-table-wrap, .plugin-group, or .operation-item, the parent owns the frame and the nested state view must render as transparent, borderless content with no ::before or ::after accessory.
  • Standalone .state-view instances may keep their own readable state treatment when they are not inside an already framed surface.
  • Menu frames should use var(--menu-item-bg), var(--menu-item-active-bg), var(--menu-glyph-bg), var(--menu-title-shadow), and var(--menu-active-outline) so each theme changes active-state treatment, icon material, and rail/sidebar structure.
  • Shared decoration variables are part of the contract: --frosted-edge, --frosted-surface, --corner-sparkle, --jelly-highlight, --sugar-dust, --crystal-edge-glow, and --jelly-inset. In mecha themes these become scanner/grid/bevel materials; in magical themes they become star, ribbon, and jelly-glass materials.
  • Full-screen ambient motifs use the shared MagicalParticleLayer background layer and global particle DOM layer. They should remain non-interactive, theme-colored, reduced-motion aware, and behind operational surfaces. Page code should not create one-off fixed decoration containers.
  • Keep framed repeated items at 8px radius or less. Pills and circular avatars are allowed for native pill/circle controls.
  • Do not replace shared panels with opaque white cards, heavy dark themes, unthemed gradients, or one-off color systems.
  • Do not use color as the only status signal. Pair color with text or familiar status icons.

Adding UI

  1. Reuse existing shared surface, command, table, form, status, and state-view classes first.
  2. If a new shared pattern is truly needed, add it in base.css and describe its intended use here.
  3. When placing empty/loading/error states inside an existing shared panel, verify the state view does not introduce a second framed panel or accessory layer.
  4. If a new palette or background preset is added, update tokens.ts, tokens.test.ts, and any CSS contract tests together.
  5. Run npm run typecheck, npm test, npm run build, scripts/check-structure.sh, and openspec validate <change> --strict before claiming completion.
  6. For page or interaction changes, perform a browser walkthrough before marking visual acceptance tasks complete. At minimum, switch black mecha -> magical-girl -> black mecha with both built-in and uploaded backgrounds when the change touches theme switching, frame accessories, or custom-background styling.