From e36ca02b62b69d316544c65b2d939e7382c276a7 Mon Sep 17 00:00:00 2001 From: akrm al-hakimi Date: Mon, 9 Mar 2026 14:57:44 -0400 Subject: [PATCH] fix(#273): user CSS now overrides selected theme --- nmrs-gui/CHANGELOG.md | 3 +++ nmrs-gui/src/style.rs | 14 ++++++++++---- nmrs-gui/src/ui/header.rs | 3 +++ nmrs-gui/src/ui/mod.rs | 4 ++++ 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/nmrs-gui/CHANGELOG.md b/nmrs-gui/CHANGELOG.md index 42c92ddd..1d90f092 100644 --- a/nmrs-gui/CHANGELOG.md +++ b/nmrs-gui/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to the `nmrs-gui` crate will be documented in this file. ## [Unreleased] +### Fixed +- Custom `~/.config/nmrs/style.css` is now applied after the saved theme, ensuring it always takes precedence over any predefined theme ([#274](https://github.com/cachebag/nmrs/pull/274)) + ## [1.1.0] - 2025-12-19 ### Fixed diff --git a/nmrs-gui/src/style.rs b/nmrs-gui/src/style.rs index d0a4ff5b..75ebec04 100644 --- a/nmrs-gui/src/style.rs +++ b/nmrs-gui/src/style.rs @@ -4,11 +4,18 @@ use gtk::{CssProvider, STYLE_PROVIDER_PRIORITY_APPLICATION, STYLE_PROVIDER_PRIOR use std::fs; use std::io::Write; -fn load_user_css_if_exists(display: &Display, default: &str) { +/// Load and apply the user's custom ~/.config/nmrs/style.css. +/// If the file does not exist it is created with the bundled defaults. +/// This must be called after any theme provider is registered so that +/// same-priority (STYLE_PROVIDER_PRIORITY_USER) rules resolve in favour of +/// the user's stylesheet. +pub fn load_user_css() { let path = dirs::config_dir() .unwrap_or_default() .join("nmrs/style.css"); + let display = Display::default().expect("No display found"); + if path.exists() { let provider = CssProvider::new(); let file = File::for_path(&path); @@ -16,7 +23,7 @@ fn load_user_css_if_exists(display: &Display, default: &str) { provider.load_from_file(&file); gtk::style_context_add_provider_for_display( - display, + &display, &provider, STYLE_PROVIDER_PRIORITY_USER, ); @@ -25,6 +32,7 @@ fn load_user_css_if_exists(display: &Display, default: &str) { fs::create_dir_all(parent).ok(); } + let default = include_str!("style.css"); let mut f = fs::File::create(&path).expect("Failed to create CSS file"); f.write_all(default.as_bytes()) .expect("Failed to write default CSS"); @@ -44,6 +52,4 @@ pub fn load_css() { &provider, STYLE_PROVIDER_PRIORITY_APPLICATION, ); - - load_user_css_if_exists(&display, css); } diff --git a/nmrs-gui/src/ui/header.rs b/nmrs-gui/src/ui/header.rs index 2f9d47c1..719aa9d4 100644 --- a/nmrs-gui/src/ui/header.rs +++ b/nmrs-gui/src/ui/header.rs @@ -97,6 +97,9 @@ pub fn build_header( ); crate::theme_config::save_theme(theme.key); + + // Re-register user CSS after the new theme so it keeps priority. + crate::style::load_user_css(); } }); diff --git a/nmrs-gui/src/ui/mod.rs b/nmrs-gui/src/ui/mod.rs index 43132ded..cc49eda0 100644 --- a/nmrs-gui/src/ui/mod.rs +++ b/nmrs-gui/src/ui/mod.rs @@ -48,6 +48,10 @@ pub fn build_ui(app: &Application) { } } + // User's custom style.css must be registered after the theme so that it + // takes precedence when both run at STYLE_PROVIDER_PRIORITY_USER. + crate::style::load_user_css(); + let vbox = GtkBox::new(Orientation::Vertical, 0); let status = Label::new(None); let list_container = GtkBox::new(Orientation::Vertical, 0);