From cbf248302835a926f64a1cb88723978b49145af4 Mon Sep 17 00:00:00 2001 From: funman300 Date: Wed, 6 May 2026 00:47:02 +0000 Subject: [PATCH] feat(engine): opt Profile / Leaderboard / Home into scrim-click dismiss MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to a54201e. The previous commit added ScrimDismissible to Stats, Achievements, and Help; this one extends the same one-line opt-in to the remaining three read-only modals so the click-outside- to-close gesture is consistent across every informational surface. Each modal now has the same shape: capture the scrim from spawn_modal, attach ScrimDismissible after the build closure returns. Three lines per file plus the import; no behaviour change to the modal content itself. Settings, Onboarding, Pause, Forfeit confirm, ConfirmNewGame, and the win/game-over modals continue to opt OUT — all carry unsaved or destructive state where an accidental scrim click would lose work. Co-Authored-By: Claude Opus 4.7 (1M context) --- solitaire_engine/src/home_plugin.rs | 5 ++++- solitaire_engine/src/leaderboard_plugin.rs | 5 ++++- solitaire_engine/src/profile_plugin.rs | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/solitaire_engine/src/home_plugin.rs b/solitaire_engine/src/home_plugin.rs index 78df54d..7e730f9 100644 --- a/solitaire_engine/src/home_plugin.rs +++ b/solitaire_engine/src/home_plugin.rs @@ -26,6 +26,7 @@ use crate::progress_plugin::ProgressResource; use crate::ui_focus::{Disabled, FocusGroup, Focusable}; use crate::ui_modal::{ spawn_modal, spawn_modal_actions, spawn_modal_button, spawn_modal_header, ButtonVariant, + ScrimDismissible, }; use crate::ui_theme::{ ACCENT_PRIMARY, BG_ELEVATED_HI, BORDER_STRONG, BORDER_SUBTLE, RADIUS_MD, STATE_INFO, @@ -359,7 +360,7 @@ fn handle_home_digit_keys( /// Spawns the Home modal with five mode cards plus a Cancel button. fn spawn_home_screen(commands: &mut Commands, level: u32, font_res: Option<&FontResource>) { - spawn_modal(commands, HomeScreen, Z_MODAL_PANEL, |card| { + let scrim = spawn_modal(commands, HomeScreen, Z_MODAL_PANEL, |card| { spawn_modal_header(card, "Choose a Mode", font_res); for mode in [ @@ -383,6 +384,8 @@ fn spawn_home_screen(commands: &mut Commands, level: u32, font_res: Option<&Font ); }); }); + // Home is read-only — opt into click-outside-to-dismiss. + commands.entity(scrim).insert(ScrimDismissible); } /// Tab-walk order for each mode card, matching the visual top-to-bottom diff --git a/solitaire_engine/src/leaderboard_plugin.rs b/solitaire_engine/src/leaderboard_plugin.rs index 200e377..1f59d5e 100644 --- a/solitaire_engine/src/leaderboard_plugin.rs +++ b/solitaire_engine/src/leaderboard_plugin.rs @@ -21,6 +21,7 @@ use crate::settings_plugin::SettingsResource; use crate::sync_plugin::SyncProviderResource; use crate::ui_modal::{ spawn_modal, spawn_modal_actions, spawn_modal_button, spawn_modal_header, ButtonVariant, + ScrimDismissible, }; use crate::ui_theme::{ ACCENT_PRIMARY, BORDER_SUBTLE, STATE_INFO, TEXT_PRIMARY, TEXT_SECONDARY, TYPE_BODY, @@ -392,7 +393,7 @@ fn spawn_leaderboard_screen( remote_available: bool, font_res: Option<&FontResource>, ) { - spawn_modal(commands, LeaderboardScreen, Z_MODAL_PANEL, |card| { + let scrim = spawn_modal(commands, LeaderboardScreen, Z_MODAL_PANEL, |card| { spawn_modal_header(card, "Leaderboard", font_res); // Subhead — what the screen does + what the buttons control. @@ -566,6 +567,8 @@ fn spawn_leaderboard_screen( ); }); }); + // Leaderboard is read-only — opt into click-outside-to-dismiss. + commands.entity(scrim).insert(ScrimDismissible); } fn header_cell(parent: &mut ChildSpawnerCommands, text: &str, width: f32, font: &TextFont) { diff --git a/solitaire_engine/src/profile_plugin.rs b/solitaire_engine/src/profile_plugin.rs index 4548edd..9d0d7de 100644 --- a/solitaire_engine/src/profile_plugin.rs +++ b/solitaire_engine/src/profile_plugin.rs @@ -20,6 +20,7 @@ use crate::settings_plugin::SettingsResource; use crate::stats_plugin::{format_fastest_win, format_win_rate, StatsResource}; use crate::ui_modal::{ spawn_modal, spawn_modal_actions, spawn_modal_button, spawn_modal_header, ButtonVariant, + ScrimDismissible, }; use crate::ui_theme::{ ACCENT_PRIMARY, BG_ELEVATED, BORDER_STRONG, SPACE_1, STATE_INFO, STATE_SUCCESS, TEXT_PRIMARY, @@ -184,7 +185,7 @@ fn spawn_profile_screen( ..default() }; - spawn_modal(commands, ProfileScreen, Z_MODAL_PANEL, |card| { + let scrim = spawn_modal(commands, ProfileScreen, Z_MODAL_PANEL, |card| { spawn_modal_header(card, "Profile", font_res); // Scrollable body — the Profile panel renders sync info, @@ -395,6 +396,8 @@ fn spawn_profile_screen( ); }); }); + // Profile is read-only — opt into click-outside-to-dismiss. + commands.entity(scrim).insert(ScrimDismissible); } /// Spawn a fixed-height vertical spacer node.