Theming¶
zer0-mistakes separates color mode (light/dark/auto) from skin (decorative palette + SVG backgrounds). Both can be configured at build time in _config.yml, adjusted at runtime via JavaScript APIs, and previewed in the admin theme pages.
Related docs: Design system · Configuration · JavaScript API · Customization
Concepts¶
| Concept | Attribute | Config key | What it controls |
|---|---|---|---|
| Color mode | data-bs-theme on <html> |
— (runtime) | Bootstrap light/dark palette, body text, form controls |
| Skin | data-theme-skin on <html> |
theme_skin |
SVG backgrounds, skin-specific --zer0-color-*, buttons/links |
| Backgrounds | data-zer0-bg on <html> |
theme_background.enabled |
Master toggle for SVG gradient/pattern/noise layers |
Color mode and skin are independent — you can run Mint skin in dark color mode, for example.
Built-in skins¶
Registered in _data/theme_skins.yml (order) and _data/theme_backgrounds.yml (assets + colors):
| Skin | Label | Accent feel |
|---|---|---|
air |
Air | Soft blue, airy gradients |
aqua |
Aqua | Ocean blues and teals |
contrast |
Contrast | High-contrast black/white/yellow |
dark |
Dark | Deep navy (default) |
dirt |
Dirt | Earth tones |
neon |
Neon | Magenta/purple/blue |
mint |
Mint | Forest greens |
plum |
Plum | Purple/violet |
sunrise |
Sunrise | Orange/peach |
Compile-time skin selection¶
Restart Jekyll after changing _config.yml.
Background layer tuning¶
theme_background:
enabled: true # Master toggle (sets data-zer0-bg on <html>)
gradient_opacity: 0.6 # Hero/header gradient layer
texture_opacity: 0.04 # Body noise overlay
pattern_opacity: 0.08 # Surface/card pattern overlay
blend_mode: overlay # CSS mix-blend-mode for all layers
Per-skin SVG paths and zone metadata live in _data/theme_backgrounds.yml:
# excerpt — _data/theme_backgrounds.yml
skins:
mint:
label: "Mint"
colors:
primary: "#2d6a4f"
secondary: "#52b788"
accent: "#95d5b2"
gradient: "assets/backgrounds/gradients/mint.svg"
pattern: "assets/backgrounds/patterns/mint.svg"
noise: "assets/backgrounds/noise/mint.svg"
SCSS wiring:
_sass/theme/_backgrounds.scss—--zer0-bg-gradient, zone classes (.zer0-bg-hero,.zer0-bg-body,.zer0-bg-surface)_sass/theme/_skins.scss—[data-theme-skin="mint"]palette overrides for buttons, links, cards, forms
Brand colors (theme_color)¶
Orthogonal to skins — sets semantic tokens via _includes/core/tokens-inline.html:
theme_color:
main: "#007bff" # --zer0-color-primary
secondary: "#6c757d"
red: "#a11111" # --zer0-color-danger
yellow: "#ffe900" # --zer0-color-warning
green: "#28a745" # --zer0-color-success
teal: "#376986" # --zer0-color-info
blue: "#007bff" # --zer0-color-link
purple: "#6f42c1" # --zer0-color-accent
When a skin is active, _sass/theme/_skins.scss may override primary/link tokens for that skin. theme_color.main still applies when no skin-specific rule wins, and always applies to keys the skin does not remap.
Color mode (light / dark / auto)¶
Navbar dropdown (halfmoon.js)¶
The Settings offcanvas and navbar include a color-mode dropdown (_includes/components/halfmoon.html) with Light, Dark, and Auto. Selection:
- Sets
data-bs-themeon<html> - Persists to
localStorage["theme"]
Appearance panel (appearance_panel)¶
When enabled in _config.yml, a runtime panel mounts in the Settings offcanvas:
Features (from assets/js/modules/theme/appearance.js):
- Color mode buttons — same
localStorage["theme"]key ashalfmoon.js(they stay in sync) - Primary color picker — writes
--zer0-color-primarylive; persists tolocalStorage["zer0-appearance"] - Reset — clears runtime overrides
Mount elsewhere by adding a host element:
The script mounts into the first [data-appearance-panel-host], or falls back to #info-section .offcanvas-body.
Initial paint is handled by the script block in _includes/core/tokens-inline.html so there is no flash of the default primary color.
Runtime JavaScript APIs¶
window.zer0Bg — skins and backgrounds¶
From assets/js/background-customizer.js:
// Switch skin (persists to localStorage["zer0-theme-skin"])
window.zer0Bg.setSkin('aqua');
// Toggle SVG backgrounds on/off
window.zer0Bg.toggle(); // flip
window.zer0Bg.toggle(true); // force on
// Adjust layer opacity at runtime
window.zer0Bg.setOpacity('gradient', 0.5);
window.zer0Bg.setOpacity('texture', 0.08);
window.zer0Bg.setOpacity('pattern', 0.12);
// Query current skin
window.zer0Bg.currentSkin(); // e.g. "dark"
Events:
document.addEventListener('zer0:skin-change', (e) => {
console.log('Skin is now:', e.detail.skin);
});
document.addEventListener('zer0:bg-toggle', (e) => {
console.log('Backgrounds enabled:', e.detail.enabled);
});
localStorage["zer0-appearance"]¶
JSON written by the Appearance panel:
Read from custom scripts:
const prefs = JSON.parse(localStorage.getItem('zer0-appearance') || '{}');
if (prefs.primary) {
document.documentElement.style.setProperty('--zer0-color-primary', prefs.primary);
}
Admin theme pages¶
Available after running ./scripts/migrate.sh (or on the theme demo site):
| Page | URL | Purpose |
|---|---|---|
| Theme Customizer | /about/settings/theme/ |
Skin grid, color editor, YAML export |
| Theme Preview | /about/settings/theme-preview/ |
Live style guide across all skins |
Theme customizer¶
Powered by _includes/components/theme-customizer.html and assets/js/theme-customizer.js:
- Click a skin card → calls
zer0Bg.setSkin()for live preview - Color pickers sync with YAML export
- Export YAML tab builds a paste-ready
_config.ymlsnippet:
Preview changes are session-only until you copy YAML into _config.yml and rebuild.
Theme preview gallery¶
_includes/components/theme-preview-gallery.html renders sections for typography, buttons, alerts, cards, forms, tabs, badges, code, links, and a sample navbar. Pair with theme-controls-bar.html for quick skin switching.
Open on your site: /about/settings/theme-preview/
Background zone classes¶
Apply SVG layers to layout regions:
| Class | Layer | Typical use |
|---|---|---|
.zer0-bg-hero |
Gradient + pattern | Landing hero, page headers |
.zer0-bg-body |
Noise texture | <body> (set in root.html) |
.zer0-bg-surface |
Pattern | Cards, sidebars, panels |
Example in a layout:
<header class="bg-primary zer0-bg-hero py-5">
<div class="container-xl"><!-- content --></div>
</header>
_includes/components/svg-background.html emits per-site opacity overrides from theme_background config.
Adding a custom skin¶
See extending.md § Add a new skin. Summary:
- Add SVG assets under
assets/backgrounds/gradients|patterns|noise/<name>.svg - Register in
_data/theme_backgrounds.yml - Add
[data-theme-skin="<name>"]rules in_sass/theme/_backgrounds.scssand_sass/theme/_skins.scss - Append the id to
_data/theme_skins.yml→order - Set
theme_skin: <name>or callzer0Bg.setSkin('<name>')
Decision guide¶
| Goal | Approach |
|---|---|
| Change default skin site-wide | theme_skin in _config.yml |
| Let visitors pick a skin | zer0Bg.setSkin() or Theme Customizer admin page |
| Toggle light/dark | Navbar dropdown, Appearance panel, or halfmoon.js |
| Tweak primary brand color | theme_color.main or Appearance panel |
| Disable SVG backgrounds | theme_background.enabled: false or zer0Bg.toggle(false) |
| Preview all components | /about/settings/theme-preview/ |
Further reading¶
- configuration.md — all
_config.ymlstyling keys - design-system.md — SCSS architecture and tokens
- js-api.md — full JavaScript surface area
- customization.md — layered customization workflow
User guide: For usage and configuration examples (how to customize as a theme user), see Styles & Customization in the user documentation.