#![forbid(unsafe_code)]
use std::path::Path;
pub use makeover_webview::Emit;
pub fn themes(dir: impl AsRef<Path>) {
let dir = dir.as_ref();
std::fs::create_dir_all(dir).expect("create themes dir");
for entry in std::fs::read_dir(dir).expect("read themes dir").flatten() {
let path = entry.path();
if path.extension().is_some_and(|e| e == "toml") {
std::fs::remove_file(&path).expect("remove stale theme");
}
}
for (id, source) in makeover::embedded_themes() {
std::fs::write(dir.join(format!("{id}.toml")), source).expect("write theme");
}
}
pub fn layout_css(path: impl AsRef<Path>, opts: &makeover_webview::Emit) {
std::fs::write(path, makeover_webview::stylesheet(opts)).expect("write layout css");
}
pub fn geometry_css(path: impl AsRef<Path>, explicit_touch: Option<&str>) {
let mut css = String::from(
"/* Generated by makeover-build from makeover-geometry. Do not edit.\n \
Spacing is named by relationship, not by size. Touch density is a\n \
capability question: a narrow desktop window still has a pointer, a\n \
full-width tablet still has a finger. */\n",
);
css.push_str(&makeover_geometry::density_css(explicit_touch));
std::fs::write(path, css).expect("write geometry css");
}
pub fn tauri_frontend(
manifest_dir: impl AsRef<Path>,
opts: &makeover_webview::Emit,
explicit_touch: Option<&str>,
) {
let root = manifest_dir.as_ref();
let css = root.join("frontend").join("css");
themes(root.join("themes"));
geometry_css(css.join("geometry.css"), explicit_touch);
layout_css(css.join("layout.css"), opts);
}
#[cfg(test)]
mod tests {
use super::*;
fn scratch(name: &str) -> std::path::PathBuf {
let dir =
std::env::temp_dir().join(format!("makeover-build-{}-{name}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).expect("create scratch");
dir
}
#[test]
fn themes_are_written_one_file_per_id() {
let dir = scratch("themes");
themes(&dir);
let count = std::fs::read_dir(&dir).unwrap().count();
assert_eq!(count, makeover::embedded_themes().count());
assert!(count > 0, "makeover ships no themes?");
}
#[test]
fn a_theme_removed_upstream_does_not_linger() {
let dir = scratch("stale");
std::fs::write(dir.join("gone-upstream.toml"), "# stale").unwrap();
themes(&dir);
assert!(!dir.join("gone-upstream.toml").exists());
}
#[test]
fn a_non_theme_file_is_left_alone() {
let dir = scratch("keep");
std::fs::write(dir.join("README.md"), "not a theme").unwrap();
themes(&dir);
assert!(dir.join("README.md").exists());
}
#[test]
fn the_stylesheet_lands_and_names_no_colour() {
let dir = scratch("css");
let path = dir.join("layout.css");
layout_css(&path, &makeover_webview::Emit::default());
let css = std::fs::read_to_string(&path).unwrap();
assert!(css.contains("--bevel-raised"));
assert!(
!css.contains('#'),
"a colour literal reached a build output"
);
}
#[test]
fn the_geometry_file_carries_the_crates_policy_and_a_banner() {
let dir = scratch("geometry");
let path = dir.join("geometry.css");
geometry_css(&path, Some(".ui-mode-mobile"));
let css = std::fs::read_to_string(&path).unwrap();
assert!(css.starts_with("/* Generated by makeover-build"));
assert!(css.contains("@media (hover: none), (pointer: coarse)"));
assert!(css.contains(".ui-mode-mobile"));
}
#[test]
fn the_tauri_layout_puts_all_three_where_the_apps_look() {
let root = scratch("tauri");
std::fs::create_dir_all(root.join("frontend").join("css")).unwrap();
tauri_frontend(&root, &makeover_webview::Emit::default(), None);
assert!(
root.join("frontend")
.join("css")
.join("geometry.css")
.exists()
);
assert!(
root.join("frontend")
.join("css")
.join("layout.css")
.exists()
);
assert!(root.join("themes").is_dir());
}
}