From ead8be96fdd676de222b11824bd307266647c921 Mon Sep 17 00:00:00 2001 From: Val Alexander <68980965+BunsDev@users.noreply.github.com> Date: Fri, 24 Apr 2026 20:36:45 -0500 Subject: [PATCH] Add tweakcn custom theme import Adds a browser-local custom tweakcn theme slot while preserving the existing built-in themes. Includes: - tweakcn share-link import, validation, persistence, and custom theme rendering - Custom option in Appearance and Quick Settings - responsive/config toolbar and chat tool-card polish from follow-up review - security hardening for bounded fetches, CSS token validation, redirect handling, and fail-closed unreadable payloads Verification: - OPENCLAW_LOCAL_CHECK=0 pnpm check:changed - GitHub CI clean on 6ff13a1b332e2e25dc40d99f791a5f32a3871839 --- ...4-22-tweakcn-custom-theme-import-design.md | 317 ++++++++++ scripts/test-projects.test-support.mjs | 15 +- test/scripts/test-projects.test.ts | 17 +- ui/src/styles/base.css | 8 +- ui/src/styles/chat/grouped.css | 33 + ui/src/styles/chat/tool-cards.css | 79 ++- ui/src/styles/config.css | 182 +++++- ui/src/ui/app-render.ts | 23 + ui/src/ui/app-settings.test.ts | 90 +++ ui/src/ui/app-settings.ts | 13 +- ui/src/ui/app-view-state.ts | 9 + ui/src/ui/app.ts | 61 ++ ui/src/ui/chat/grouped-render.test.ts | 1 + ui/src/ui/chat/grouped-render.ts | 9 +- ui/src/ui/custom-theme.test.ts | 267 ++++++++ ui/src/ui/custom-theme.ts | 593 ++++++++++++++++++ ui/src/ui/storage.node.test.ts | 142 +++++ ui/src/ui/storage.ts | 7 +- ui/src/ui/theme.ts | 13 +- ui/src/ui/views/config-quick.test.ts | 66 ++ ui/src/ui/views/config-quick.ts | 12 +- ui/src/ui/views/config.browser.test.ts | 98 +++ ui/src/ui/views/config.ts | 199 +++++- 23 files changed, 2199 insertions(+), 55 deletions(-) create mode 100644 docs/superpowers/specs/2026-04-22-tweakcn-custom-theme-import-design.md create mode 100644 ui/src/ui/custom-theme.test.ts create mode 100644 ui/src/ui/custom-theme.ts diff --git a/docs/superpowers/specs/2026-04-22-tweakcn-custom-theme-import-design.md b/docs/superpowers/specs/2026-04-22-tweakcn-custom-theme-import-design.md new file mode 100644 index 00000000000..59e07c97eec --- /dev/null +++ b/docs/superpowers/specs/2026-04-22-tweakcn-custom-theme-import-design.md @@ -0,0 +1,317 @@ +# Tweakcn Custom Theme Import Design + +Status: approved in terminal on 2026-04-22 + +## Summary + +Add exactly one browser-local custom Control UI theme slot that can be imported from a tweakcn share link. The existing built-in theme families remain `claw`, `knot`, and `dash`. The new `custom` family behaves like a normal OpenClaw theme family and supports `light`, `dark`, and `system` mode when the imported tweakcn payload includes both light and dark token sets. + +The imported theme is stored only in the current browser profile with the rest of the Control UI settings. It is not written to gateway config and does not sync across devices or browsers. + +## Problem + +The Control UI theme system is currently closed over three hard-coded theme families: + +- `ui/src/ui/theme.ts` +- `ui/src/ui/views/config.ts` +- `ui/src/styles/base.css` + +Users can switch among built-in families and mode variants, but they cannot bring in a theme from tweakcn without editing repo CSS. The requested outcome is smaller than a general theming system: keep the three built-ins and add one user-controlled imported slot that can be replaced from a tweakcn link. + +## Goals + +- Keep the existing built-in theme families unchanged. +- Add exactly one imported custom slot, not a theme library. +- Accept a tweakcn share link or a direct `https://tweakcn.com/r/themes/{id}` URL. +- Persist the imported theme in browser local storage only. +- Make the imported slot work with existing `light`, `dark`, and `system` mode controls. +- Keep failure behavior safe: a bad import never breaks the active UI theme. + +## Non goals + +- No multi-theme library or browser-local list of imports. +- No gateway-side persistence or cross-device sync. +- No arbitrary CSS editor or raw theme JSON editor. +- No automatic loading of remote font assets from tweakcn. +- No attempt to support tweakcn payloads that only expose one mode. +- No repo-wide theming refactor beyond the seams required for the Control UI. + +## User decisions already made + +- Keep the three built-in themes. +- Add one tweakcn-powered import slot. +- Store the imported theme in the browser, not gateway config. +- Support `light`, `dark`, and `system` for the imported slot. +- Overwriting the custom slot with the next import is the intended behavior. + +## Recommended approach + +Add a fourth theme family id, `custom`, to the Control UI theme model. The `custom` family becomes selectable only when a valid tweakcn import is present. The imported payload is normalized into an OpenClaw-specific custom theme record and stored in browser local storage with the rest of the UI settings. + +At runtime, OpenClaw renders a managed `