feat(dashboard): reskin extension points for themes and plugins (#14776)

Themes and plugins can now pull off arbitrary dashboard reskins (cockpit
HUD, retro terminal, etc.) without touching core code.

Themes gain four new fields:
- layoutVariant: standard | cockpit | tiled — shell layout selector
- assets: {bg, hero, logo, crest, sidebar, header, custom: {...}} —
  artwork URLs exposed as --theme-asset-* CSS vars
- customCSS: raw CSS injected as a scoped <style> tag on theme apply
  (32 KiB cap, cleaned up on theme switch)
- componentStyles: per-component CSS-var overrides (clipPath,
  borderImage, background, boxShadow, ...) for card/header/sidebar/
  backdrop/tab/progress/badge/footer/page

Plugin manifests gain three new fields:
- tab.override: replaces a built-in route instead of adding a tab
- tab.hidden: register component + slots without adding a nav entry
- slots: declares shell slots the plugin populates

10 named shell slots: backdrop, header-left/right/banner, sidebar,
pre-main, post-main, footer-left/right, overlay. Plugins register via
window.__HERMES_PLUGINS__.registerSlot(name, slot, Component). A
<PluginSlot> React helper is exported on the plugin SDK.

Ships a full demo at plugins/strike-freedom-cockpit/ — theme YAML +
slot-only plugin that reproduces a Gundam cockpit dashboard: MS-STATUS
sidebar with live telemetry, COMPASS crest in header, notched card
corners via componentStyles, scanline overlay via customCSS, gold/cyan
palette, Orbitron typography.

Validation:
- 15 new tests in test_web_server.py covering every extended field
- tests/hermes_cli/: 2615 passed (3 pre-existing unrelated failures)
- tsc -b --noEmit: clean
- vite build: 418 kB bundle, ~2 kB delta for slots/theme extensions

Co-authored-by: Teknium <p@nousresearch.com>
This commit is contained in:
Teknium 2026-04-23 15:31:01 -07:00 committed by GitHub
parent 470389e6a3
commit f593c367be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 1576 additions and 40 deletions

View file

@ -28,6 +28,7 @@ import { Select, SelectOption } from "@/components/ui/select";
import { Separator } from "@/components/ui/separator";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { useI18n } from "@/i18n";
import { registerSlot, PluginSlot } from "./slots";
// ---------------------------------------------------------------------------
// Plugin registry — plugins call register() to add their component.
@ -75,6 +76,7 @@ declare global {
__HERMES_PLUGIN_SDK__: unknown;
__HERMES_PLUGINS__: {
register: typeof registerPlugin;
registerSlot: typeof registerSlot;
};
}
}
@ -82,6 +84,7 @@ declare global {
export function exposePluginSDK() {
window.__HERMES_PLUGINS__ = {
register: registerPlugin,
registerSlot,
};
window.__HERMES_PLUGIN_SDK__ = {
@ -118,6 +121,7 @@ export function exposePluginSDK() {
Tabs,
TabsList,
TabsTrigger,
PluginSlot,
},
// Utilities