Skip to main content

max / goingson

Take themes from published makeover instead of the MNW checkout theme-common was reachable only as ../../MNW/shared/theme-common, and tauri.conf.json globbed ../../../MNW/shared/themes/*.toml, so both code and theme data came from a sibling repo. build.rs materializes makeover's embedded set into a gitignored src-tauri/themes/ that the bundler globs, since Tauri resource globs are resolved by the Tauri CLI against the crate directory and cannot reach a registry checkout. No theme files are vendored here.
Author: Max Johnson <me@maxj.phd> · 2026-07-19 20:09 UTC
Commit: 024ccedc009cbdd3b0b3c5a6441df9242cb23582
Parent: df74aed
7 files changed, +50 insertions, -22 deletions
M .gitignore +3
@@ -34,3 +34,6 @@ CLAUDE.md
34 34
35 35 # Private working files — live in _private/, synced via Syncthing
36 36 todo.md
37 +
38 + # Generated by src-tauri/build.rs from makeover's embedded theme set
39 + /src-tauri/themes/
M Cargo.lock +1 -9
@@ -2172,6 +2172,7 @@ dependencies = [
2172 2172 "lettre",
2173 2173 "libsqlite3-sys",
2174 2174 "mailparse",
2175 + "makeover",
2175 2176 "notify",
2176 2177 "notify-debouncer-mini",
2177 2178 "open",
@@ -2194,7 +2195,6 @@ dependencies = [
2194 2195 "tauri-plugin-updater",
2195 2196 "tauri-plugin-window-state",
2196 2197 "tempfile",
2197 - "theme-common",
2198 2198 "thiserror 2.0.18",
2199 2199 "tokio",
2200 2200 "tokio-native-tls",
@@ -6877,14 +6877,6 @@ dependencies = [
6877 6877 ]
6878 6878
6879 6879 [[package]]
6880 - name = "theme-common"
6881 - version = "0.7.0"
6882 - dependencies = [
6883 - "serde",
6884 - "toml 0.8.2",
6885 - ]
6886 -
6887 - [[package]]
6888 6880 name = "thiserror"
6889 6881 version = "1.0.69"
6890 6882 source = "registry+https://github.com/rust-lang/crates.io-index"
M Cargo.toml +1 -1
@@ -69,7 +69,7 @@ tauri-plugin-process = "2"
69 69 # Filesystem watching (db change notifications)
70 70 notify = "6.0"
71 71 notify-debouncer-mini = "0.4"
72 - theme-common = { path = "../../MNW/shared/theme-common" }
72 + makeover = "0.9.0"
73 73 toml = "0.8"
74 74
75 75 # Enums
@@ -14,6 +14,7 @@ crate-type = ["staticlib", "cdylib", "lib"]
14 14
15 15 [build-dependencies]
16 16 tauri-build = { workspace = true }
17 + makeover.workspace = true
17 18
18 19 [dependencies]
19 20 goingson-core = { workspace = true }
@@ -70,7 +71,7 @@ icalendar = { workspace = true }
70 71 flate2 = { workspace = true }
71 72
72 73 # Theme loading
73 - theme-common = { workspace = true }
74 + makeover = { workspace = true }
74 75 toml = { workspace = true }
75 76 # Browser opening
76 77 open = { workspace = true }
@@ -1,3 +1,32 @@
1 + use std::path::Path;
2 +
3 + /// Write the themes `makeover` ships into `themes/`, where `tauri.conf.json`
4 + /// picks them up as a bundled resource.
5 + ///
6 + /// Tauri's resource globs are read by the Tauri CLI against the crate
7 + /// directory, so they cannot point into a registry checkout or `OUT_DIR`.
8 + /// Materializing the embedded set here keeps `makeover` the single source of
9 + /// truth without vendoring a second copy of the theme files into this repo.
10 + /// The directory is generated, and gitignored.
11 + fn materialize_themes() {
12 + let dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("themes");
13 + std::fs::create_dir_all(&dir).expect("create themes/");
14 +
15 + // Clear stale files first, so a theme removed upstream (or renamed) does
16 + // not linger in the bundle from an earlier build.
17 + for entry in std::fs::read_dir(&dir).expect("read themes/").flatten() {
18 + let path = entry.path();
19 + if path.extension().is_some_and(|e| e == "toml") {
20 + std::fs::remove_file(&path).expect("remove stale theme");
21 + }
22 + }
23 +
24 + for (id, source) in makeover::embedded_themes() {
25 + std::fs::write(dir.join(format!("{id}.toml")), source).expect("write theme");
26 + }
27 + }
28 +
1 29 fn main() {
30 + materialize_themes();
2 31 tauri_build::build()
3 32 }
@@ -1,4 +1,4 @@
1 - //! Theme loading commands — thin Tauri wrappers over `theme_common`.
1 + //! Theme loading commands — thin Tauri wrappers over `makeover`.
2 2
3 3 use std::path::PathBuf;
4 4 use tauri::{AppHandle, Manager};
@@ -6,7 +6,7 @@ use tracing::instrument;
6 6
7 7 use super::ApiError;
8 8
9 - pub use theme_common::{SemanticTokens, ThemeMeta};
9 + pub use makeover::{SemanticTokens, ThemeMeta};
10 10
11 11 /// Returns theme directories in priority order (later overrides earlier by ID).
12 12 /// Each entry is `(path, is_custom)`.
@@ -21,9 +21,12 @@ fn theme_dirs(app: &AppHandle) -> Vec<(PathBuf, bool)> {
21 21 }
22 22 }
23 23
24 - // 2. Dev fallback: CARGO_MANIFEST_DIR → 3 parents up → Git/themes/
25 - if let Some(dev_path) = theme_common::dev_themes_dir(env!("CARGO_MANIFEST_DIR").as_ref(), 3) {
26 - dirs.push((dev_path, false));
24 + // 2. Dev fallback: the themes build.rs materialized from makeover. In a
25 + // dev run there is no bundled resource dir, so this is what supplies the
26 + // stock set; in production it is redundant with (1) and harmless.
27 + let generated = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("themes");
28 + if generated.is_dir() {
29 + dirs.push((generated, false));
27 30 }
28 31
29 32 // 3. User custom themes (highest priority)
@@ -41,14 +44,14 @@ fn theme_dirs(app: &AppHandle) -> Vec<(PathBuf, bool)> {
41 44 #[instrument(skip_all)]
42 45 pub fn list_themes(app: AppHandle) -> Result<Vec<ThemeMeta>, ApiError> {
43 46 let dirs = theme_dirs(&app);
44 - Ok(theme_common::list_themes_from_dirs(&dirs))
47 + Ok(makeover::list_themes_from_dirs(&dirs))
45 48 }
46 49
47 50 #[tauri::command]
48 51 #[instrument(skip_all)]
49 52 pub fn get_theme(app: AppHandle, id: String) -> Result<SemanticTokens, ApiError> {
50 53 let dirs = theme_dirs(&app);
51 - theme_common::load_semantic(&dirs, &id).map_err(ApiError::internal)
54 + makeover::load_semantic(&dirs, &id).map_err(ApiError::internal)
52 55 }
53 56
54 57 #[tauri::command]
@@ -72,7 +75,7 @@ pub fn import_theme(app: AppHandle, path: String) -> Result<ThemeMeta, ApiError>
72 75 .app_config_dir()
73 76 .map_err(|e| ApiError::internal(e.to_string()))?
74 77 .join("themes");
75 - theme_common::import_theme(std::path::Path::new(&path), &custom_dir)
78 + makeover::import_theme(std::path::Path::new(&path), &custom_dir)
76 79 .map_err(ApiError::internal)
77 80 }
78 81
@@ -80,12 +83,12 @@ pub fn import_theme(app: AppHandle, path: String) -> Result<ThemeMeta, ApiError>
80 83 #[instrument(skip_all)]
81 84 pub fn export_theme(app: AppHandle, id: String, path: String) -> Result<(), ApiError> {
82 85 let dirs = theme_dirs(&app);
83 - theme_common::export_theme(&dirs, &id, std::path::Path::new(&path))
86 + makeover::export_theme(&dirs, &id, std::path::Path::new(&path))
84 87 .map_err(ApiError::internal)
85 88 }
86 89
87 90 #[cfg(test)]
88 91 mod tests {
89 - // Core theme logic tests live in theme-common crate.
92 + // Core theme logic tests live in makeover crate.
90 93 // App-specific tests here only if needed for theme_dirs behavior.
91 94 }
@@ -39,7 +39,7 @@
39 39 "icons/icon.ico"
40 40 ],
41 41 "resources": [
42 - "../../../MNW/shared/themes/*.toml"
42 + "themes/*.toml"
43 43 ],
44 44 "iOS": {
45 45 "developmentTeam": "93C54W92UP"