Get started
Tweakcn-ontwerp voor import van aangepast thema
Tweakcn-ontwerp voor import van aangepast thema
Status: goedgekeurd in terminal op 2026-04-22
Samenvatting
Voeg precies één browser-lokaal aangepast Control UI-themaslot toe dat kan worden geïmporteerd vanuit een tweakcn-deellink. De bestaande ingebouwde themafamilies blijven claw, knot en dash. De nieuwe familie custom gedraagt zich als een normale OpenClaw-themafamilie en ondersteunt de modus light, dark en system wanneer de geïmporteerde tweakcn-payload zowel lichte als donkere tokensets bevat.
Het geïmporteerde thema wordt alleen opgeslagen in het huidige browserprofiel, samen met de rest van de Control UI-instellingen. Het wordt niet naar de Gateway-configuratie geschreven en synchroniseert niet tussen apparaten of browsers.
Probleem
Het themasysteem van de Control UI is momenteel gesloten rond drie hard-gecodeerde themafamilies:
ui/src/ui/theme.tsui/src/ui/views/config.tsui/src/styles/base.css
Gebruikers kunnen schakelen tussen ingebouwde families en modusvarianten, maar ze kunnen geen thema van tweakcn gebruiken zonder repo-CSS te bewerken. Het gevraagde resultaat is kleiner dan een algemeen themasysteem: behoud de drie ingebouwde thema’s en voeg één door de gebruiker beheerd importsleuf toe dat kan worden vervangen vanuit een tweakcn-link.
Doelen
- Houd de bestaande ingebouwde themafamilies ongewijzigd.
- Voeg precies één geïmporteerd aangepast slot toe, geen themabibliotheek.
- Accepteer een tweakcn-deellink of een directe
https://tweakcn.com/r/themes/{id}-URL. - Bewaar het geïmporteerde thema alleen in browser local storage.
- Laat het geïmporteerde slot werken met de bestaande modusbesturingen
light,darkensystem. - Houd foutgedrag veilig: een mislukte import breekt nooit het actieve UI-thema.
Niet-doelen
- Geen bibliotheek met meerdere thema’s of browser-lokale lijst met imports.
- Geen Gateway-persistentie of synchronisatie tussen apparaten.
- Geen willekeurige CSS-editor of editor voor ruwe thema-JSON.
- Geen automatisch laden van externe lettertype-assets van tweakcn.
- Geen poging om tweakcn-payloads te ondersteunen die slechts één modus blootleggen.
- Geen repo-brede themarefactor buiten de naden die nodig zijn voor de Control UI.
Gebruikersbeslissingen die al zijn genomen
- Behoud de drie ingebouwde thema’s.
- Voeg één door tweakcn aangedreven importsleuf toe.
- Sla het geïmporteerde thema op in de browser, niet in Gateway-configuratie.
- Ondersteun
light,darkensystemvoor het geïmporteerde slot. - Het aangepaste slot overschrijven met de volgende import is het beoogde gedrag.
Aanbevolen aanpak
Voeg een vierde themafamilie-id toe, custom, aan het themamodel van de Control UI. De familie custom wordt alleen selecteerbaar wanneer er een geldige tweakcn-import aanwezig is. De geïmporteerde payload wordt genormaliseerd naar een OpenClaw-specifiek aangepast themarecord en opgeslagen in browser local storage samen met de rest van de UI-instellingen.
Tijdens runtime rendert OpenClaw een beheerde <style>-tag die de opgeloste aangepaste CSS-variabelenblokken definieert:
:root[data-theme="custom"] { ... }
:root[data-theme="custom-light"] { ... }
Dit houdt aangepaste themavariabelen beperkt tot de familie custom en voorkomt dat inline CSS-variabelen lekken naar de ingebouwde families.
Architectuur
Themamodel
Werk ui/src/ui/theme.ts bij:
- Breid
ThemeNameuit metcustom. - Breid
ResolvedThemeuit metcustomencustom-light. - Breid
VALID_THEME_NAMESuit. - Werk
resolveTheme()bij zodatcustomhet bestaande familiegedrag weerspiegelt:custom + dark->customcustom + light->custom-lightcustom + system->customofcustom-lightop basis van OS-voorkeur
Er worden geen legacy-aliassen toegevoegd voor custom.
Persistentiemodel
Breid UiSettings-persistentie in ui/src/ui/storage.ts uit met één optionele aangepaste thema-payload:
customTheme?: ImportedCustomTheme
Aanbevolen opgeslagen vorm:
type ImportedCustomTheme = {
sourceUrl: string;
themeId: string;
label: string;
importedAt: string;
light: Record<string, string>;
dark: Record<string, string>;
};
Opmerkingen:
sourceUrlslaat de oorspronkelijke gebruikersinvoer op na normalisatie.themeIdis de tweakcn-thema-id die uit de URL is geëxtraheerd.labelis het tweakcn-veldnamewanneer aanwezig, andersCustom.lightendarkzijn al genormaliseerde OpenClaw-tokenmaps, geen ruwe tweakcn-payloads.- De geïmporteerde payload leeft naast andere browser-lokale instellingen en wordt geserialiseerd in hetzelfde local-storage-document.
- Als opgeslagen aangepaste themagegevens ontbreken of ongeldig zijn bij het laden, negeer de payload en val terug naar
theme: "claw"wanneer de gepersisteerde familiecustomwas.
Toepassing tijdens runtime
Voeg een smalle aangepaste-thema-stylesheetbeheerder toe in de Control UI-runtime, in de buurt van ui/src/ui/app-settings.ts en ui/src/ui/theme.ts.
Verantwoordelijkheden:
- Maak of werk één stabiele
<style id="openclaw-custom-theme">-tag bij indocument.head. - Emit CSS alleen wanneer er een geldige aangepaste thema-payload bestaat.
- Verwijder de inhoud van de style-tag wanneer de payload wordt gewist.
- Houd ingebouwde familie-CSS in
ui/src/styles/base.css; voeg geïmporteerde tokens niet in de ingecheckte stylesheet in.
Deze beheerder draait telkens wanneer instellingen worden geladen, opgeslagen, geïmporteerd of gewist.
Light-modus-selectors
De implementatie moet de voorkeur geven aan data-theme-mode="light" voor light-styling over families heen in plaats van custom-light speciaal te behandelen. Als een bestaande selector vastzit aan data-theme="light" en op elke lichte familie moet worden toegepast, verbreed die dan als onderdeel van dit werk.
Import-UX
Werk ui/src/ui/views/config.ts bij in de sectie Appearance:
- Voeg een themakaart
Customtoe naastClaw,KnotenDash. - Toon de kaart als uitgeschakeld wanneer er geen geïmporteerd aangepast thema bestaat.
- Voeg een importpaneel toe onder het themaraster met:
- één tekstinvoer voor een tweakcn-deellink of
/r/themes/{id}-URL - één knop
Import - één pad
Replacewanneer er al een aangepaste payload bestaat - één actie
Clearwanneer er al een aangepaste payload bestaat
- één tekstinvoer voor een tweakcn-deellink of
- Toon het geïmporteerde themalabel en de bronhost wanneer er een payload bestaat.
- Als het actieve thema
customis, wordt een geïmporteerde vervanging onmiddellijk toegepast. - Als het actieve thema niet
customis, slaat importeren alleen de nieuwe payload op totdat de gebruiker de kaartCustomselecteert.
De snelle thema-kiezer in instellingen in ui/src/ui/views/config-quick.ts moet Custom ook alleen tonen wanneer er een payload bestaat.
URL-parsing en externe fetch
Het browser-importpad accepteert:
https://tweakcn.com/themes/{id}https://tweakcn.com/r/themes/{id}
De implementatie moet beide vormen normaliseren naar:
https://tweakcn.com/r/themes/{id}
De browser haalt vervolgens het genormaliseerde eindpunt /r/themes/{id} rechtstreeks op.
Gebruik een smalle schemavalidator voor de externe payload. Een zod-schema heeft de voorkeur omdat dit een onvertrouwde externe grens is.
Vereiste externe velden:
- top-level
nameals optionele string cssVars.themeals optioneel objectcssVars.lightals objectcssVars.darkals object
Als cssVars.light of cssVars.dark ontbreekt, wijs de import af. Dit is bewust: het goedgekeurde productgedrag is volledige modusondersteuning, geen best-effort synthese van een ontbrekende kant.
Tokenmapping
Spiegel tweakcn-variabelen niet blind. Normaliseer een begrensde subset naar OpenClaw-tokens en leid de rest af in een helper.
Rechtstreeks geïmporteerde tokens
Uit elk tweakcn-modusblok:
backgroundforegroundcardcard-foregroundpopoverpopover-foregroundprimaryprimary-foregroundsecondarysecondary-foregroundmutedmuted-foregroundaccentaccent-foregrounddestructivedestructive-foregroundborderinputringradius
Uit gedeelde cssVars.theme wanneer aanwezig:
font-sansfont-mono
Als een modusblok font-sans, font-mono of radius overschrijft, wint de modus-lokale waarde.
Tokens afgeleid voor OpenClaw
De importer leidt OpenClaw-only variabelen af uit de geïmporteerde basiskleuren:
--bg-accent--bg-elevated--bg-hover--panel--panel-strong--panel-hover--chrome--chrome-strong--text--text-strong--chat-text--muted--muted-strong--accent-hover--accent-muted--accent-subtle--accent-glow--focus--focus-ring--focus-glow--secondary--secondary-foreground--danger--danger-muted--danger-subtle
Afleidingsregels staan in een pure helper zodat ze onafhankelijk kunnen worden getest. Exacte kleurmengformules zijn een implementatiedetail, maar de helper moet aan twee beperkingen voldoen:
- behoud leesbaar contrast dicht bij de intentie van het geïmporteerde thema
- produceer stabiele output voor dezelfde geïmporteerde payload
Tokens genegeerd in v1
Deze tweakcn-tokens worden bewust genegeerd in de eerste versie:
chart-*sidebar-*font-serifshadow-*tracking-*letter-spacingspacing
Dit houdt de scope gericht op de tokens die de huidige Control UI daadwerkelijk nodig heeft.
Lettertypen
Lettertypestackstrings worden geïmporteerd als ze aanwezig zijn, maar OpenClaw laadt geen externe lettertype-assets in v1. Als de geïmporteerde stack verwijst naar lettertypen die niet beschikbaar zijn in de browser, geldt normaal fallbackgedrag.
Foutgedrag
Mislukte imports moeten gesloten falen.
- Ongeldig URL-formaat: toon inline validatiefout, fetch niet.
- Niet-ondersteunde host of padvorm: toon inline validatiefout, fetch niet.
- Netwerkfout, niet-OK-respons of misvormde JSON: toon inline fout, laat de huidige opgeslagen payload ongemoeid.
- Schemafout of ontbrekende light/dark-blokken: toon inline fout, laat de huidige opgeslagen payload ongemoeid.
- Wisactie:
- verwijdert de opgeslagen aangepaste payload
- verwijdert de inhoud van de beheerde aangepaste style-tag
- als
customactief is, schakelt de themafamilie terug naarclaw
- Ongeldige opgeslagen aangepaste payload bij eerste laadactie:
- negeer de opgeslagen payload
- emit geen aangepaste CSS
- als de gepersisteerde themafamilie
customwas, val terug naarclaw
Op geen enkel moment mag een mislukte import het actieve document achterlaten met gedeeltelijk toegepaste aangepaste CSS-variabelen.
Bestanden die naar verwachting wijzigen in de implementatie
Primaire bestanden:
ui/src/ui/theme.tsui/src/ui/storage.tsui/src/ui/app-settings.tsui/src/ui/views/config.tsui/src/ui/views/config-quick.tsui/src/styles/base.css
Waarschijnlijke nieuwe helpers:
ui/src/ui/custom-theme.ts
Tests:
ui/src/ui/app-settings.test.tsui/src/ui/storage.node.test.tsui/src/ui/views/config.browser.test.ts- nieuwe gerichte tests voor URL-parsing en payloadnormalisatie
Testen
Minimale implementatiedekking:
- parse de URL van een deellink naar een tweakcn-thema-id
- normaliseer
/themes/{id}en/r/themes/{id}naar de fetch-URL - wijs niet-ondersteunde hosts en misvormde id’s af
- valideer de vorm van de tweakcn-payload
- map een geldige tweakcn-payload naar genormaliseerde OpenClaw-tokenmaps voor light en dark
- laad en sla de aangepaste payload op in browser-lokale instellingen
- los
customop voorlight,darkensystem - schakel selectie van
Customuit wanneer er geen payload bestaat - pas het geïmporteerde thema onmiddellijk toe wanneer
customal actief is - val terug naar
clawwanneer het actieve aangepaste thema wordt gewist
Doel voor handmatige verificatie:
- importeer een bekend tweakcn-thema vanuit Settings
- schakel tussen
light,darkensystem - schakel tussen
customen de ingebouwde families - herlaad de pagina en bevestig dat het geïmporteerde aangepaste thema lokaal behouden blijft
Uitrolnotities
Deze functie is bewust klein. Als gebruikers later vragen om meerdere geïmporteerde thema’s, hernoemen, exporteren of synchronisatie tussen apparaten, behandel dat dan als een vervolgontwerp. Bouw in deze implementatie niet vooraf een themabibliotheekabstractie.