The look from the server's tokens, pinned; the frame and bar follow the page's theme
ui/tokens.css is no longer a hand copy that drifts: scripts/fetch-tokens.sh takes the server's tokens.css at a git ref and tokens.lock.json pins it, as fetch-cli.sh does for the CLI. build.rs reads the two themes' --bg and --border out of it, so no colour is written in Rust. The content view reports the page's theme by a navigation the app refuses (llembas-theme:<name>), and the window, the title bar and the first-run page are painted in it and remember it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
12 files changed
+994
-59
No files matched your search
@@ -1,3 +1,72 @@
|
||||
//! Besides Tauri's own build step: the two themes' colours the window itself paints, read out
|
||||
//! of `ui/tokens.css` (the server's tokens, fetched by `scripts/fetch-tokens.sh`) into
|
||||
//! `$OUT_DIR/tokens.rs`, so no colour is written in Rust. `lib.rs` includes that file.
|
||||
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
/// The themes the app knows, by the name `tokens.css` selects them with (`data-theme`), and the
|
||||
/// Rust names the constants get.
|
||||
const THEMES: [(&str, &str); 2] = [("moria", "MORIA"), ("shire", "SHIRE")];
|
||||
/// The tokens taken from each theme, by the custom property and the constant's suffix.
|
||||
const TOKENS: [(&str, &str); 2] = [("--bg", "BG"), ("--border", "BORDER")];
|
||||
|
||||
fn main() {
|
||||
let tokens = Path::new("../ui/tokens.css");
|
||||
println!("cargo:rerun-if-changed={}", tokens.display());
|
||||
let css = fs::read_to_string(tokens)
|
||||
.unwrap_or_else(|e| panic!("{}: {e}; run scripts/fetch-tokens.sh", tokens.display()));
|
||||
let mut out = String::from(
|
||||
"// Generated by build.rs from ui/tokens.css: the colours the window paints itself.\n",
|
||||
);
|
||||
for (theme, name) in THEMES {
|
||||
let block = theme_block(&css, theme).unwrap_or_else(|| {
|
||||
panic!("ui/tokens.css has no `:root[data-theme=\"{theme}\"]` block")
|
||||
});
|
||||
for (token, suffix) in TOKENS {
|
||||
let (r, g, b) = hex_token(block, token).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"ui/tokens.css: `{token}` of the {theme} theme is not a six-digit hex colour"
|
||||
)
|
||||
});
|
||||
out.push_str(&format!(
|
||||
"pub const {name}_{suffix}: (u8, u8, u8) = (0x{r:02X}, 0x{g:02X}, 0x{b:02X});\n"
|
||||
));
|
||||
}
|
||||
}
|
||||
let dest = Path::new(&env::var("OUT_DIR").expect("OUT_DIR")).join("tokens.rs");
|
||||
fs::write(&dest, out).expect("write tokens.rs");
|
||||
tauri_build::build()
|
||||
}
|
||||
|
||||
/// The declarations of the theme's block: from the selector naming it (at the start of a line,
|
||||
/// so a mention in a comment does not count) to the block's closing brace at the start of a
|
||||
/// line, which is the file's own layout, one block per theme.
|
||||
fn theme_block<'a>(css: &'a str, theme: &str) -> Option<&'a str> {
|
||||
let selector = format!("\n:root[data-theme=\"{theme}\"]");
|
||||
let at = css.find(&selector)?;
|
||||
let open = at + css[at..].find('{')?;
|
||||
let close = open + css[open..].find("\n}")?;
|
||||
Some(&css[open + 1..close])
|
||||
}
|
||||
|
||||
/// `--token: #RRGGBB;` in the block, as bytes.
|
||||
fn hex_token(block: &str, token: &str) -> Option<(u8, u8, u8)> {
|
||||
let value = block
|
||||
.lines()
|
||||
.map(str::trim)
|
||||
.find_map(|l| {
|
||||
l.strip_prefix(token)
|
||||
.and_then(|r| r.trim_start().strip_prefix(':'))
|
||||
})?
|
||||
.trim()
|
||||
.trim_end_matches(';')
|
||||
.trim();
|
||||
let hex = value.strip_prefix('#')?;
|
||||
if hex.len() != 6 {
|
||||
return None;
|
||||
}
|
||||
let byte = |i: usize| u8::from_str_radix(&hex[i..i + 2], 16).ok();
|
||||
Some((byte(0)?, byte(2)?, byte(4)?))
|
||||
}
|
||||
Reference in new issue
Block a user