makeover 0.8.0

Shared theme loading for the make-family apps: TOML theme files parsed into intent-based color tokens, with perceptual derivations and WCAG contrast.
Documentation

makeover

Shared theme loading for the make-family apps. Parses theme metadata and color values from .toml files on disk, resolves them into intent-based tokens, and derives the rest perceptually (OKLab) with WCAG contrast checks.

The crate ships the theme set it loads, in themes/. Consumers get working themes from a clean checkout without depending on any sibling repo.

Used by MNW server, GoingsOn, Balanced Breakfast, audiofiles, and Alloy.

Usage

use makeover::{load_theme, list_themes_from_dirs, bundled_themes_dir};
use std::path::PathBuf;

// Set up theme directories (later entries override earlier ones)
let bundled = bundled_themes_dir().expect("makeover ships themes/");
let custom = PathBuf::from("/path/to/user/custom-themes");
let dirs = vec![(bundled, false), (custom, true)];

// List available themes (sorted by name)
let themes = list_themes_from_dirs(&dirs);
for t in &themes {
    println!("{} ({}, {})", t.name, t.id, t.variant);
}

// Load a specific theme by ID
let theme = load_theme(&dirs, "catppuccin-mocha").unwrap();
println!("Name: {}", theme.meta.name);         // "Catppuccin Mocha"
println!("Variant: {}", theme.meta.variant);     // "dark"
println!("BG: {}", theme.colors["background.primary"]); // "#181825"

// Build-from-source fallback: the themes this crate ships
if let Some(dir) = bundled_themes_dir() {
    // dir = <makeover checkout>/themes
}

Theme File Format

Theme files are TOML with four color sections. See themes/ for the 31 bundled themes.

# Attribution comment (optional, for credit)
# Based on Catppuccin by Catppuccin Org -- MIT License

[meta]
name = "Theme Name"       # Display name (required)
variant = "dark"           # "dark", "light", or "high-contrast" (default: "dark")

[background]
primary   = "#181825"      # Main background
secondary = "#11111b"      # Sidebar / panel background (optional)
tertiary  = "#313244"      # Hover / selection background (optional)
surface   = "#1e1e2e"      # Card / elevated surface (optional)

[foreground]
primary   = "#cdd6f4"      # Main text
secondary = "#bac2de"      # Secondary text (optional)
muted     = "#9399b2"      # Placeholder / disabled text (optional)

[accent]
red    = "#f38ba8"         # Error, destructive actions
green  = "#a6e3a1"         # Success, positive actions
blue   = "#89b4fa"         # Links, primary accent
yellow = "#f9e2af"         # Warnings
purple = "#cba6f7"         # Tags, special elements
cyan   = "#89dceb"         # Info, secondary accent

[border]
default = "#45475a"        # Default border color

Color Key Flattening

Colors are loaded into a flat HashMap<String, String> with dotted keys:

"background.primary"   -> "#181825"
"foreground.muted"     -> "#9399b2"
"accent.blue"          -> "#89b4fa"
"border.default"       -> "#45475a"

Apps map these keys to CSS variables or egui color values.

Theme ID

The theme ID is the filename without .toml (e.g., catppuccin-mocha.toml has ID catppuccin-mocha). IDs must contain only alphanumeric characters, hyphens, and underscores. Path traversal characters are rejected.

API

Function Description
list_themes_from_dirs(dirs) Scan directories for .toml files, return sorted Vec<ThemeMeta>
load_theme(dirs, id) Load a theme by ID, returning ThemeColors (metadata + color map)
find_theme_path(dirs, id) Find the file path for a theme ID (highest-priority directory wins)
parse_meta(id, table, is_custom) Parse [meta] from a TOML table into ThemeMeta
extract_colors(table) Flatten color sections into a HashMap<String, String>
validate_theme_id(id) Check that an ID contains only safe characters
bundled_themes_dir() The themes/ directory this crate ships, for build-from-source fallback

Directory Priority

list_themes_from_dirs and load_theme accept a list of (PathBuf, bool) pairs. Later directories override earlier ones by theme ID. The bool marks whether the directory contains user-custom themes (is_custom on ThemeMeta).

Typical setup for a Tauri app:

  1. Bundled themes, packaged by the app or from bundled_themes_dir() (is_custom = false)
  2. User themes from an app data directory (is_custom = true)

License

MIT.

The themes in themes/ are adapted from third-party color schemes (Catppuccin, Dracula, Nord, gruvbox, Tokyo Night, Rose Pine, and others), each MIT-licensed. Every adapted file carries an attribution comment naming its source and author; keep those in place when editing or redistributing.