leaftext’s theme system is built around a semantic token contract — a set of approximately 100Documentation Index
Fetch the complete documentation index at: https://mintlify.com/ryanallen/leaftext/llms.txt
Use this file to discover all available pages before exploring further.
--leaf-* CSS custom properties that every theme must define. This contract is verified at compile time, guaranteeing that no token is ever undefined in any theme. If a token is missing, the Rust build fails with an explicit assertion error.
The token contract
LEAF_SEMANTIC_TOKEN_CONTRACT in src/lib.rs defines the authoritative list of required properties. Every theme source must map a value to each token in this list. The tokens are organized into semantic categories:
Reader chrome
Reader chrome
Core app surface and foreground colors:
--leaf-app-background, --leaf-app-foreground, --leaf-app-surface, --leaf-app-surface-raised, --leaf-app-surface-elevated, --leaf-app-surface-muted, --leaf-app-surface-sunken, --leaf-app-surface-inset, --leaf-app-surface-card, --leaf-app-border, --leaf-app-border-strong, and semantic role tokens for primary, secondary, accent, danger, warning, success, done, link, shadow, and focus states.Editor and Markdown elements
Editor and Markdown elements
Tokens for inline code background/foreground, code block background/foreground/border, blockquote border and foreground, headings, muted foreground, links, tables, thematic breaks, math inline background, and keyboard key styling.
Alert callout colors
Alert callout colors
Per-severity accent colors for GitHub-style alert callouts:
--leaf-markdown-alert-note, --leaf-markdown-alert-tip, --leaf-markdown-alert-important, --leaf-markdown-alert-warning, --leaf-markdown-alert-caution, and --leaf-markdown-alert-done.Syntax highlighting tokens
Syntax highlighting tokens
One token per syntactic role:
--leaf-syntax-background, --leaf-syntax-foreground, --leaf-syntax-comment, --leaf-syntax-keyword, --leaf-syntax-string, --leaf-syntax-number, --leaf-syntax-function, --leaf-syntax-variable, --leaf-syntax-type, --leaf-syntax-operator, --leaf-syntax-punctuation, and per-channel inserted/deleted/changed diff tokens.Minimap colors
Minimap colors
--leaf-minimap-background, --leaf-minimap-border, --leaf-minimap-viewport-border, --leaf-minimap-viewport-background, --leaf-minimap-heading, --leaf-minimap-paragraph, --leaf-minimap-blank, --leaf-minimap-list, --leaf-minimap-blockquote, --leaf-minimap-code.Navigation chrome
Navigation chrome
Theme sources
Three theme sources are defined insrc/lib.rs. Each is a ThemeSource struct with an id, a CSS selector, a kind, and a flat tokens slice mapping every contract property to a value:
| Theme ID | Selector trigger | Token strategy |
|---|---|---|
primer-light | [data-color-mode="light"][data-light-theme="light"] and [data-color-mode="auto"][data-light-theme="light"] | Maps --leaf-* tokens to GitHub Primer CSS primitive var(--bgColor-*), var(--fgColor-*), etc. |
primer-dark | [data-color-mode="dark"][data-dark-theme="dark"] and [data-color-mode="auto"][data-light-theme="dark"] | Same Primer primitive variables; Primer’s dark-mode cascade supplies different resolved values. |
dracula | :root[data-leaf-theme-source="dracula"] | Maps every --leaf-* token directly to Dracula palette hex values (e.g. #282a36, #f8f8f2, #bd93f9). No dependency on Primer primitives. |
primer-light and primer-dark sources share the same PRIMER_THEME_TOKENS slice. Because they use CSS var() references into the Primer primitive cascade, the same token map produces the correct resolved color in both light and dark contexts.
The dracula source uses ThemeSourceKind::Dracula and activates through the data-leaf-theme-source="dracula" attribute, deliberately isolated from the Primer color-mode selectors.
Compile-time assertion
assert_theme_sources_cover_contract() in src/lib.rs runs at startup (called from compiled_theme_css(), which is called from reading_mode_css(), which is called from app_shell_html()). It performs the following checks for every theme source:
- No duplicate theme source IDs.
- Every source has a non-empty
display_name. - Dracula-kind sources use the
data-leaf-theme-sourceselector (not the shared Primer color-mode selectors). - No duplicate token declarations within a single source.
- Every token in
LEAF_SEMANTIC_TOKEN_CONTRACTis covered by the source.
reading_mode_css() is cached in a OnceLock<String> and called on the first paint, a missing token causes a panic! with a message like:
compiled_theme_css()
compiled_theme_css() generates the final CSS block that follows the Primer primitive stylesheets in the cascade. For each ThemeSource, it emits:
reading_mode_css() then assembles the full style block in this order:
- Noto font
@font-facedeclarations (embedded asdata:URIs) - Primer primitives light CSS (
primer-primitives-11.9.0-light.css) - Primer primitives dark CSS (
primer-primitives-11.9.0-dark.css) - Compiled theme CSS from
compiled_theme_css() - Application layout and document body CSS
OnceLock<String> — computed once per process lifetime.
Adding a theme
Define a new token map
In
src/lib.rs, create a new const slice (e.g. MY_THEME_TOKENS: &[(&str, &str)]) that maps every property name in LEAF_SEMANTIC_TOKEN_CONTRACT to a value. Each entry is ("--leaf-property-name", "value").Run the verification suite
LEAF_SEMANTIC_TOKEN_CONTRACT is missing from your new source, assert_theme_sources_cover_contract() will panic and the test run will fail.