Dark theme (default): Fusion-like blue-grey viewport #2e3440, darker chrome, subtle grid, light text, blue accent; light theme kept as a second Tokens set; toggle on the application bar (sun/moon), ui.set {dark}, kept between runs (eframe storage; browser local storage on the web); viewport, sketch, glyph, view cube, timeline and overlay colours all come from the theme; preview spinner and state in ui.inspect

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
bherbruckandClaude Opus 5.5 committed 2026-10-07 22:30:36 +00:00
1 parent 71a1903122
commit 956492c993
14 files changed
+290 -53

No files matched your search

+19 -1
View File
@@ -51,6 +51,8 @@ pub struct UiState {
pub hidden_origin: Vec<String>,
pub show_sketches: bool,
pub palette_open: bool,
/// Dark theme (the default); a preference kept between runs.
pub dark: bool,
}
impl Default for UiState {
@@ -66,6 +68,7 @@ impl Default for UiState {
hidden_origin: Vec::new(),
show_sketches: true,
palette_open: false,
dark: true,
}
}
}
@@ -143,6 +146,20 @@ impl SolveApp {
self.viewport.gpu = Some(gpu::install(rs, depth_bits, samples));
}
/// Preferences kept between runs (JSON), for the host to store.
pub fn prefs(&self) -> String {
json!({ "dark": self.ui.dark }).to_string()
}
/// Restore preferences saved with [`SolveApp::prefs`].
pub fn load_prefs(&mut self, prefs: &str) {
if let Ok(v) = serde_json::from_str::<Value>(prefs)
&& let Some(d) = v.get("dark").and_then(Value::as_bool)
{
self.ui.dark = d;
}
}
pub fn with_control(mut self, rx: Receiver<ControlRequest>) -> Self {
self.control_rx = Some(rx);
self
@@ -402,7 +419,8 @@ impl SolveApp {
/// Per-frame logic before layout.
pub fn logic(&mut self, ctx: &egui::Context) {
if !self.styled {
if !self.styled || theme::is_dark() != self.ui.dark {
theme::set_dark(self.ui.dark);
theme::apply(ctx);
self.styled = true;
}