vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Offer instance theme packs in the appearance picker
f7a34d8749054b7ff9e1a304a3fc90ccf3786877 · Keenan Nemetz · 1d ago · parent bc95767f
Offer instance theme packs in the appearance picker Add profile/themes/index.json and one scoped stylesheet per theme. The loader validates ids and names, pairs each manifest entry with profile/themes/<id>.css, and exposes the list to the account picker and to theme.js before first paint. Theme stylesheets are linked before profile/custom.css, so an instance-wide override still wins. The starter repository now includes an empty manifest and documents the format in its root README. The configuration docs and the Admin Configuration path table describe the same convention.
docs/configuration.md +73−4
| @@ -154,7 +154,9 @@ visitors either way. | |||
| 154 | 154 | |---|---| | |
| 155 | 155 | | `profile/README.md` | Landing page introduction; markdown, sanitized like an issue body | | |
| 156 | 156 | | `profile/private/README.md` | Replaces it for signed-in viewers when present | | |
| 157 | | `profile/custom.css` | Loaded after the built-in stylesheets | | ||
| 157 | | `profile/custom.css` | Instance-wide styles, loaded last | | ||
| 158 | | `profile/themes/index.json` | Lists the themes the Appearance picker offers | | ||
| 159 | | `profile/themes/<id>.css` | One stylesheet per selectable theme | | ||
| 158 | 160 | | `profile/favicon.svg` | Replaces the favicon links | | |
| 159 | 161 | | `assets/` | Served at `/static/custom/assets/`; CSS, images and fonts only | | |
| 160 | 162 | ||
| @@ -177,9 +179,76 @@ None of this changes the `vole` wordmark in the top bar. | |||
| 177 | 179 | ||
| 178 | 180 | ### Theming | |
| 179 | 181 | ||
| 180 | `profile/custom.css` is loaded after the built-in `vole.css` and | ||
| 181 | `everforest.css`. Override the design tokens rather than copying rules; the | ||
| 182 | layout, contrast, and responsive behaviour then stay intact. | ||
| 182 | `profile/custom.css` is loaded after the built-in `vole.css` and `everforest.css` | ||
| 183 | and after any theme pack, so it can override every theme. Override the design | ||
| 184 | tokens rather than copying rules; the layout, contrast, and responsive behaviour | ||
| 185 | then stay intact. | ||
| 186 | |||
| 187 | #### Theme packs | ||
| 188 | |||
| 189 | Account → Appearance lists the built-in Everforest variants plus every theme in | ||
| 190 | `profile/themes/index.json`. A theme is a stylesheet named after its id, and its | ||
| 191 | rules apply only while that theme is selected: | ||
| 192 | |||
| 193 | ```text | ||
| 194 | profile/themes/index.json | ||
| 195 | profile/themes/acme-ocean.css | ||
| 196 | profile/themes/acme-paper.css | ||
| 197 | ``` | ||
| 198 | |||
| 199 | ```json | ||
| 200 | { | ||
| 201 | "themes": [ | ||
| 202 | { "id": "acme-ocean", "name": "Acme Ocean" }, | ||
| 203 | { "id": "acme-paper", "name": "Acme Paper" } | ||
| 204 | ] | ||
| 205 | } | ||
| 206 | ``` | ||
| 207 | |||
| 208 | ```css | ||
| 209 | /* profile/themes/acme-ocean.css */ | ||
| 210 | :root[data-theme="acme-ocean"] { | ||
| 211 | color-scheme: dark; | ||
| 212 | --bg: #0b1720; | ||
| 213 | --bg-panel: #102433; | ||
| 214 | --bg-raised: #163041; | ||
| 215 | --fg: #d7e8f0; | ||
| 216 | --fg-muted: #8fb0c0; | ||
| 217 | --fg-faint: #6f8f9f; | ||
| 218 | --accent: #38bdf8; | ||
| 219 | --accent-fg: #04121a; | ||
| 220 | --accent-soft: color-mix(in srgb, var(--accent) 14%, transparent); | ||
| 221 | } | ||
| 222 | ``` | ||
| 223 | |||
| 224 | ```css | ||
| 225 | /* profile/themes/acme-paper.css */ | ||
| 226 | :root[data-theme="acme-paper"] { | ||
| 227 | color-scheme: light; | ||
| 228 | --bg: #fffdf7; | ||
| 229 | --bg-panel: #f8f3e8; | ||
| 230 | --bg-raised: #f1eadc; | ||
| 231 | --fg: #2b2a26; | ||
| 232 | --fg-muted: #6b675d; | ||
| 233 | --fg-faint: #8d887c; | ||
| 234 | --accent: #9a5b13; | ||
| 235 | --accent-fg: #fffdf7; | ||
| 236 | --accent-soft: color-mix(in srgb, var(--accent) 14%, transparent); | ||
| 237 | } | ||
| 238 | ``` | ||
| 239 | |||
| 240 | The id must use lowercase letters, digits, and dashes (at most 41 characters), | ||
| 241 | and cannot be `system` or start with `everforest-`. A theme listed without its | ||
| 242 | stylesheet, a duplicate id, or an empty name fails the snapshot load with a | ||
| 243 | message on the Admin page; the previous theme stays in use. A light theme must | ||
| 244 | set `color-scheme: light` and light surface and text tokens, or form controls and | ||
| 245 | inherited colours stay dark. | ||
| 246 | |||
| 247 | Every listed theme is linked on every page, so keep the files small. The | ||
| 248 | selection is a browser preference, not an account setting: it lives in | ||
| 249 | `localStorage`, and a theme removed from the manifest falls back to System. | ||
| 250 | |||
| 251 | #### Tokens | ||
| 183 | 252 | ||
| 184 | 253 | Use `:root[data-theme]`, not plain `:root`. Everforest sets its tokens on | |
| 185 | 254 | `:root[data-theme^="everforest-"]`, which is more specific than `:root`, so a | |