diff --git a/webapp/src/components/Docs.tsx b/webapp/src/components/Docs.tsx index d244e8d..62f732b 100644 --- a/webapp/src/components/Docs.tsx +++ b/webapp/src/components/Docs.tsx @@ -50,9 +50,10 @@ const SECTIONS: DocSection[] = [

Settings

- One settings file per machine holds the colour scheme, imported/linked CSS, the ntfy sink, and - which profile is active. Settings only tracks profile pointers — the profiles themselves (params, metrics, - dashboards) are stored separately, next to the settings file by default. + One settings file per machine holds the active style (a built-in colour scheme or an + imported/linked stylesheet — see below), the ntfy sink, and which profile is active. Settings only tracks + profile pointers — the profiles themselves (params, metrics, dashboards) are stored separately, next to the + settings file by default.

Profiles

@@ -424,9 +425,10 @@ const SECTIONS: DocSection[] = [ body: (

- The Settings panel controls process-wide state: colour scheme, the ntfy sink alert rules deliver to, the - max number of logs kept in memory (blank means unlimited), and imported/linked CSS. Changes apply - immediately and persist to the settings file on disk. There is no save button. + The Settings panel controls process-wide state: the active style — one unified list of built-in colour + schemes and any imported/linked stylesheets, any of which can be a simple palette or a full layout + redesign — the ntfy sink alert rules deliver to, and the max number of logs kept in memory (blank means + unlimited). Changes apply immediately and persist to the settings file on disk. There is no save button.

Worked example

diff --git a/webapp/src/components/NavMenu.tsx b/webapp/src/components/NavMenu.tsx index e35a974..c9e491e 100644 --- a/webapp/src/components/NavMenu.tsx +++ b/webapp/src/components/NavMenu.tsx @@ -258,8 +258,10 @@ function SettingsPanel({ panel }: { panel: ReturnType } setCssUploadError(null) } - // Every imported/linked stylesheet is always a selectable theme (ticket 020), so it's always - // validated against the canonical `--c-*` variable set before it's sent. + // Every imported/linked stylesheet is always a selectable style, listed alongside the built-in + // colour schemes (ticket 020/047), so it's always validated against the canonical `--c-*` + // variable set before it's sent — that's a floor, not a ceiling: the stylesheet is free to also + // carry rules for any other selector, up to and including a full layout redesign. async function handleCssImport(e: React.FormEvent) { e.preventDefault() setCssUploadError(null) @@ -300,8 +302,14 @@ function SettingsPanel({ panel }: { panel: ReturnType } return (

-

Colour scheme

-
+
+

Style

+ + one list of interchangeable styles — a built-in palette or your own imported/linked stylesheet. Any of + them can be a simple colour swap or a full layout redesign; only one is active at a time. + +
+
{COLOR_SCHEMES.map((scheme) => (
))}
+ + {panel.cssEntries.length === 0 ? ( +
No styles imported or linked yet.
+ ) : ( +
    + {panel.cssEntries.map((entry) => ( +
  • +
    + +
    {entry.kind}
    +
    +
    + + {entry.kind === 'imported' ? ( + + ) : ( + + — + + )} +
    +
  • + ))} +
+ )} + +

+ Add your own style below — a stylesheet, uploaded or linked by URL/path. It must at least define every{' '} + --c-* variable the built-ins do, but nothing stops it from also targeting any other selector + in the app (layout, spacing, fonts, anything) — it isn't limited to palette overrides. +

+ +
+ + setCssFilename(e.target.value)} + className="rounded border border-border-soft bg-surface-1 px-2 py-1 text-xs text-text placeholder:text-text-subtle focus:border-border-strong focus:outline-none" + /> +