bread-theme: shared component stylesheet + generator CLI

Adds the single source of truth for bread GUI styling so the apps stop
each re-implementing (and drifting on) component CSS:

- stylesheet(&Palette): full component sheet (buttons, entries, switches,
  dropdowns, lists/rows/sidebars, cards, chips, scrollbars, headings) built
  from the design tokens + a canonical @define-color block (surface=color0,
  overlay=color7, accent=color4).
- render() / shared_css_path() / write_shared_css(): render for the current
  pywal palette and write to $XDG_RUNTIME_DIR/bread/theme.css.
- gtk::apply_shared(): load that file (or a rendered fallback) at APPLICATION
  priority and watch it, so every app recolours live with no rebuild.
- new `bread-theme` CLI (generate|path|print) — gtk-free, light. Run at
  session start and on palette change; apps pick it up via the file watch.

The contract is a CSS *file*, so apps stay decoupled from this crate's gtk4
version. Tests cover the stylesheet, path, and render helpers.
This commit is contained in:
Breadway 2026-06-16 16:43:09 +08:00
parent 578067183b
commit 8305b4a58b
4 changed files with 236 additions and 0 deletions

View file

@ -0,0 +1,50 @@
//! `bread-theme` — generates the ecosystem's shared GTK stylesheet from the
//! current pywal palette and writes it to the canonical path that every bread
//! GUI loads. Run it at session start, and again after the wallpaper/palette
//! changes (e.g. from a pywal hook); apps watch the file and recolour live.
//!
//! bread-theme # same as `generate`
//! bread-theme generate # render + write the shared stylesheet
//! bread-theme path # print the stylesheet path
//! bread-theme print # render to stdout (no write)
use std::process::ExitCode;
fn main() -> ExitCode {
let cmd = std::env::args().nth(1).unwrap_or_else(|| "generate".into());
match cmd.as_str() {
"path" => {
println!("{}", bread_theme::shared_css_path().display());
ExitCode::SUCCESS
}
"print" => {
print!("{}", bread_theme::render());
ExitCode::SUCCESS
}
"generate" => match bread_theme::write_shared_css() {
Ok(path) => {
eprintln!("bread-theme: wrote {}", path.display());
ExitCode::SUCCESS
}
Err(e) => {
eprintln!("bread-theme: failed to write stylesheet: {e}");
ExitCode::FAILURE
}
},
"-h" | "--help" | "help" => {
eprintln!(
"bread-theme — shared stylesheet generator\n\n\
USAGE:\n bread-theme [generate|path|print]\n\n\
generate render the pywal palette to the shared stylesheet (default)\n\
path print the stylesheet path ({})\n\
print render to stdout without writing",
bread_theme::shared_css_path().display()
);
ExitCode::SUCCESS
}
other => {
eprintln!("bread-theme: unknown command '{other}' (try generate|path|print)");
ExitCode::FAILURE
}
}
}