authorgravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-10-02 11:45:09-07:00
committergravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-10-02 12:53:12-07:00
log678a46da0816b22d6b37cd361abf395870595796
tree103a141a38b8f394a055b5e20f7009207597b104
parentf4abeb10328178d4685cc9788c296516e6b186a6
signature Signed by SSH key SHA256:52mNGHRsVFBDED9IAX5pe+LRWUefqTbxEReunq21QvU

fix: what the page area shows in place of a page takes the page's colours

In a dark appearance with Pages Match UI Theme off, the locked section's notice drew the dark theme's light text on the light page, and the welcome and empty notebook notices sat on the chrome's surfaces, which a translucent backdrop lets the desktop show through. They now fill with the page's colour and build their text and buttons in the theme matching it: the light theme's on white pages. Fixes #67. Assisted-by: claude-opus-5.5

3 files changed, 30 insertions(+), 14 deletions(-)

crates/snowbound/src/main.rs+17-3
......@@ -1474,7 +1474,7 @@ impl State {
14741474 && self.locked.is_none();
14751475 self.toolbar(&theme, !welcome)?;
14761476 if welcome {
1477 self.welcome(&theme);
1477 self.welcome();
14781478 return Ok((section, Id::ROOT, None));
14791479 }
14801480 self.ui.open(
......@@ -1704,7 +1704,7 @@ impl State {
17041704 recycle::bar(&mut self.ui);
17051705 }
17061706 if self.session.is_none() && self.locked.is_some() {
1707 self.locked_page(&theme);
1707 self.locked_page();
17081708 self.ui.close();
17091709 self.ui.close();
17101710 self.ui.close();
......@@ -1717,7 +1717,7 @@ impl State {
17171717 return Ok((section, open_tab, None));
17181718 }
17191719 if let Some(library) = self.sectionless.clone().filter(|_| self.session.is_none()) {
1720 self.no_sections(&theme, library);
1720 self.no_sections(library);
17211721 self.ui.close();
17221722 self.ui.close();
17231723 self.ui.close();
......@@ -4193,6 +4193,20 @@ impl State {
41934193 .colored(self.view.editor.page_color())
41944194 }
41954195
4196 /// The colours of what the page area shows in place of a page, which follow the page's:
4197 /// the light theme's on white pages, as Pages Match UI Theme off keeps them in a dark
4198 /// appearance.
4199 pub(crate) fn page_area_theme(&self) -> Theme {
4200 if self.light_pages {
4201 Theme {
4202 accent: self.ui.theme.accent,
4203 ..Theme::light()
4204 }
4205 } else {
4206 self.ui.theme.clone()
4207 }
4208 }
4209
41964210 /// Paints the interface with the page in its box.
41974211 fn paint(&mut self, target: &draw::Target) -> Result<(), Box<dyn Error>> {
41984212 let start = Instant::now();
crates/snowbound/src/protection.rs+5-2
......@@ -2,7 +2,7 @@
22//! dialogs that unlock one and set, change or remove its password, Lock All, and locking a
33//! section after a while unused or as it is left. Keys live in memory only (`Library`).
44
5use crate::{Command, Library, State, Theme, art, manage::Structure};
5use crate::{Command, Library, State, art, manage::Structure};
66use accesskit::Role;
77use std::{error::Error, sync::Arc, time::Duration};
88use ui::{Anchor, Axis, Flags, Id, Spec, Ui, children, fill, px};
......@@ -155,11 +155,13 @@ impl State {
155155 }
156156
157157 /// The locked section's page, as OneNote 2010 draws it: a click or Enter unlocks.
158 pub(crate) fn locked_page(&mut self, theme: &Theme) {
158 pub(crate) fn locked_page(&mut self) {
159159 let Some(locked) = &self.locked else {
160160 return;
161161 };
162162 let (library, path) = (Arc::clone(&locked.library), locked.path.clone());
163 let theme = &self.page_area_theme();
164 let chrome = std::mem::replace(&mut self.ui.theme, theme.clone());
163165 let ui = &mut self.ui;
164166 let entered =
165167 ui::popup::navigation(ui, &[notice()], &[NamedKey::Enter]).contains(&NamedKey::Enter);
......@@ -229,6 +231,7 @@ impl State {
229231 ui.close();
230232 ui.close();
231233 ui.close();
234 ui.theme = chrome;
232235 if ui.signal(open).clicked || entered {
233236 self.ask_password(library, path, Dialog::Unlock(Zeroizing::default(), false));
234237 }
crates/snowbound/src/sidebar.rs+8-9
......@@ -1150,7 +1150,7 @@ impl crate::State {
11501150
11511151 /// The window below the title bar on the first run, or once every notebook is closed:
11521152 /// what is missing, and the ways to start.
1153 pub(crate) fn welcome(&mut self, theme: &Theme) {
1153 pub(crate) fn welcome(&mut self) {
11541154 let id = self.ui.id("welcome");
11551155 #[cfg(target_os = "linux")]
11561156 let install = crate::desktop::installable().then_some((
......@@ -1163,9 +1163,7 @@ impl crate::State {
11631163 let install = None;
11641164 let servers = self.servers.clone();
11651165 self.notice(
1166 theme,
11671166 id,
1168 theme.base,
11691167 "No notebooks open",
11701168 &servers,
11711169 [
......@@ -1202,7 +1200,7 @@ impl crate::State {
12021200
12031201 /// The page's place while notebook `library` has no sections, as OneNote 2010 shows
12041202 /// it, with a button to add one; or while none is on this computer yet.
1205 pub(crate) fn no_sections(&mut self, theme: &Theme, library: Arc<Library>) {
1203 pub(crate) fn no_sections(&mut self, library: Arc<Library>) {
12061204 let downloading = library.downloading();
12071205 let new = crate::Command::Structure(
12081206 library,
......@@ -1219,27 +1217,27 @@ impl crate::State {
12191217 vec![("new", art::PLUS, "New Section", new)],
12201218 )
12211219 };
1222 self.notice(theme, id, theme.strip, title, &[], buttons);
1220 self.notice(id, title, &[], buttons);
12231221 }
12241222
1225 /// A box `id` filled with `background`, showing `title` above `buttons` in its middle: each
1223 /// A box `id` in the page's colours, showing `title` above `buttons` in its middle: each
12261224 /// a part, an icon, a label and what it does; then the saved `servers` to reconnect to.
12271225 fn notice(
12281226 &mut self,
1229 theme: &Theme,
12301227 id: ui::Id,
1231 background: [f32; 4],
12321228 title: &str,
12331229 servers: &[String],
12341230 buttons: Vec<(&str, &'static [&'static str], &str, crate::Command)>,
12351231 ) {
12361232 const BUTTON: [f32; 2] = [240.0, 32.0];
1233 let theme = self.page_area_theme();
1234 let chrome = std::mem::replace(&mut self.ui.theme, theme.clone());
12371235 let [left, top, right, bottom] = self.ui.rect(id).unwrap_or_default();
12381236 self.ui.open_as(
12391237 id,
12401238 Spec {
12411239 size: [fill(), fill()],
1242 fill: Some(background),
1240 fill: Some(theme.paper),
12431241 ..Spec::default()
12441242 },
12451243 );
......@@ -1292,6 +1290,7 @@ impl crate::State {
12921290 let saved = crate::server::saved_servers(&mut self.ui, servers);
12931291 self.ui.close();
12941292 self.ui.close();
1293 self.ui.theme = chrome;
12951294 if let Some(saved) = saved {
12961295 self.saved_server(saved);
12971296 }