mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-10-23 03:27:43 +09:00
Drop docs/screenshots/themes/ from the panel repo; THEMING.md and the README roadmap now link to the registry's gallery instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
169 lines
7.2 KiB
Markdown
169 lines
7.2 KiB
Markdown
# Theming ServerKit
|
|
|
|
A ServerKit theme is **data, not code**: a small JSON file that maps color
|
|
tokens to values. There's no JavaScript, no build step, no permissions, and no
|
|
sandbox — the whole panel is already painted through CSS custom properties, so a
|
|
theme just supplies new values for them at runtime. Reviewing a theme is reading
|
|
a diff of colors.
|
|
|
|
- **Use a theme:** Settings → Appearance → **Theme**. Pick a card; it applies
|
|
instantly and stays your personal choice. The dark/light toggle keeps working
|
|
on top of it.
|
|
- **Make a theme:** Settings → Appearance → **Create theme** (Theme Studio) —
|
|
edit colors over the live panel, then Export a `theme.json`, save it to this
|
|
panel, or submit it to the registry.
|
|
- **Share a theme:** open a PR to the
|
|
[`serverkit-themes`](https://github.com/jhd3197/serverkit-themes) registry.
|
|
Merged = published.
|
|
- **See them:** every theme, screenshotted on the live panel — the
|
|
[gallery in the themes registry](https://github.com/jhd3197/serverkit-themes#gallery).
|
|
|
|
---
|
|
|
|
## `theme.json` (schema_version 1)
|
|
|
|
```jsonc
|
|
{
|
|
"schema_version": 1,
|
|
"slug": "nord-deep", // required, kebab-case, unique, matches the folder
|
|
"name": "Nord Deep", // required, display name
|
|
"author": "your-handle", // GitHub handle
|
|
"version": "1.0.0",
|
|
"description": "Cool arctic blues.",
|
|
"base": "dark", // "dark" | "light" — which mode this is a skin OF
|
|
"tokens": {
|
|
"dark": { "--bg-body": "#2e3440", "--surface": "#3b4252", "…": "…" },
|
|
"light": { "…": "…" } // optional — omit and the stock light theme is used
|
|
},
|
|
"accent": "#88c0d0", // optional — the panel derives the accent ramp from this
|
|
"preview": ["#2e3440", "#3b4252", "#88c0d0", "#eceff4"] // 4 gallery swatches
|
|
}
|
|
```
|
|
|
|
A **dark-only** theme omits `tokens.light` (the stock light theme is used when a
|
|
user toggles to light). A **light-only** theme (`base: "light"`) omits
|
|
`tokens.dark`. Provide both for a theme that should look intentional in either
|
|
mode.
|
|
|
|
---
|
|
|
|
## The token whitelist
|
|
|
|
A theme may set only these canonical tokens. You write ~37 names; the panel
|
|
fans each out to the legacy `--bg-*/--text-*/--border-*` aliases automatically,
|
|
so the whole UI tracks your theme. Accent tokens are **not** in this list — they
|
|
are derived from the single top-level `accent` field.
|
|
|
|
### Surfaces (colors)
|
|
| Token | Paints |
|
|
|---|---|
|
|
| `--bg-body` | App background (behind everything) |
|
|
| `--bg-sidebar` | Sidebar background |
|
|
| `--surface` | Card / panel surface (→ `--bg-card`) |
|
|
| `--surface-2` | Elevated / secondary surface (→ `--bg-elevated`, `--bg-secondary`) |
|
|
| `--surface-3` | Tertiary surface (→ `--bg-tertiary`) |
|
|
| `--surface-hover` | Hover surface (→ `--bg-hover`) |
|
|
|
|
### Borders (colors)
|
|
| Token | Paints |
|
|
|---|---|
|
|
| `--border` | Default border (→ `--border-default`) |
|
|
| `--border-soft` | Subtle divider (→ `--border-subtle`) |
|
|
| `--border-strong` | Active / strong border (→ `--border-active`, `--border-hover`) |
|
|
|
|
### Text (colors)
|
|
| Token | Paints |
|
|
|---|---|
|
|
| `--text` | Primary text (→ `--text-primary`) |
|
|
| `--text-dim` | Secondary text (→ `--text-secondary`) |
|
|
| `--text-faint` | Tertiary text (→ `--text-tertiary`) |
|
|
| `--text-ghost` | Faintest text / placeholders |
|
|
|
|
### Semantic (colors)
|
|
`--green`, `--green-bg`, `--amber`, `--amber-bg`, `--red`, `--red-bg`,
|
|
`--cyan`, `--cyan-bg`, `--violet`, `--violet-bg`.
|
|
The `*-bg` tokens are the translucent wash behind the matching accent (use an
|
|
`rgba()` at low alpha, e.g. `rgba(61,220,151,0.12)`).
|
|
|
|
### Chrome
|
|
| Token | Type | Paints |
|
|
|---|---|---|
|
|
| `--radius`, `--radius-sm`, `--radius-lg` | length | Corner radii |
|
|
| `--sans`, `--mono` | font stack | UI + monospace fonts (bundled families only) |
|
|
| `--shadow-sm`, `--shadow-md`, `--shadow-lg` | shadow | Elevation shadows |
|
|
| `--scrollbar-track`, `--scrollbar-thumb`, `--scrollbar-thumb-hover` | color | Scrollbars |
|
|
| `--bg-code`, `--text-code` | color | Code / terminal blocks |
|
|
| `--grid-color` | color | The faint background grid |
|
|
|
|
---
|
|
|
|
## Value rules (enforced client-side, server-side, and in registry CI)
|
|
|
|
- **Colors:** hex (`#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`), `rgb()/rgba()`,
|
|
`hsl()/hsla()`, or a bare CSS named color.
|
|
- **Lengths:** a number with an optional `px/rem/em/%/vh/vw` unit (or `0`).
|
|
- **Fonts:** a font-family stack using only the families the panel already ships
|
|
(IBM Plex Sans / Mono and the system fallbacks). **No `url()` — no remote
|
|
fonts.** Most themes should omit `--sans`/`--mono` entirely.
|
|
- **Shadows:** standard `box-shadow` syntax, or `none`.
|
|
- **Never allowed anywhere:** `url(`, `@`, `;`, `}`, `{`, `<`, `>`,
|
|
`expression(`, or `/*`. Values over 200 characters are rejected. Unknown
|
|
tokens are dropped.
|
|
|
|
There is **no `custom_css` and no JavaScript** in a v1 theme. The moment
|
|
arbitrary CSS enters, a theme becomes code (exfiltration via
|
|
`background: url(...)`, UI spoofing) and the trust story collapses to the
|
|
extension one. Themes stay data on purpose.
|
|
|
|
Because every value is validated and applied per-token via
|
|
`CSSStyleDeclaration.setProperty`, a theme can't break out of its declaration or
|
|
smuggle a network request even if a validation rule is missed.
|
|
|
|
---
|
|
|
|
## Theme Studio (the authoring loop)
|
|
|
|
Settings → Appearance → **Create theme**:
|
|
|
|
1. **Start from** any installed theme to inherit its palette.
|
|
2. Edit colors with grouped pickers — every change applies to the **live panel**
|
|
instantly, in the mode (dark/light) you're editing.
|
|
3. Set the **accent** once; the panel derives the hover/bright/dim/wash ramp.
|
|
4. **Export theme.json** (a valid, ready-to-share file), **Save to this panel**
|
|
(admins — adds it to the gallery), or **Submit to registry** (opens a
|
|
prefilled new-file PR against `serverkit-themes`).
|
|
|
|
No tooling to install — the whole authoring loop lives in the panel.
|
|
|
|
---
|
|
|
|
## Submit to the registry
|
|
|
|
The registry is the [`serverkit-themes`](https://github.com/jhd3197/serverkit-themes)
|
|
repo. Themes live **in** the repo — submission is a PR, publication is a merge:
|
|
|
|
1. Fork it. Add `themes/<slug>/theme.json` (or export one from Theme Studio).
|
|
2. Run `node scripts/build-index.mjs` and commit the updated `index.json`.
|
|
3. Open a PR. CI validates against the schema + token whitelist + value rules.
|
|
4. A maintainer merges — panels pick it up on their next registry refresh.
|
|
|
|
Operators can point a panel at a different registry with
|
|
`SERVERKIT_THEMES_REGISTRY_URL` (unset = the public registry; set-but-empty =
|
|
bundled seeds only). The panel is offline-tolerant: a failed fetch falls back to
|
|
the last good cache, then to the themes bundled with the panel — the gallery
|
|
never blanks.
|
|
|
|
---
|
|
|
|
## Notes & limits (v1)
|
|
|
|
- **Charts, xterm terminal, and the code/diff viewers** read their own color
|
|
configs; they track the semantic tokens where feasible but are otherwise
|
|
documented as unthemed for v1.
|
|
- **Hardcoded colors:** any page style not reading a token will ignore a skin.
|
|
The panel's styles route through tokens; if you spot a straggler, it's a bug
|
|
worth reporting.
|
|
- **The token names never change** — themes ride the existing names, so a theme
|
|
authored today keeps working. A newer theme on an older panel degrades
|
|
gracefully (unknown tokens are simply dropped).
|