feat(engine): Phase B home hierarchy — Continue card, hero New Game, deal-options disclosure
Test / test (pull_request) Failing after 10s

Restructures the Home overlay per docs/ui-redesign-2026-07.md Phase B:

- Continue card (mode / elapsed / score) when a game is in progress;
  clicking returns to the table
- Hero New Game replays the persisted Settings::last_mode (new field,
  serde-default Classic) with one tap; locked modes fall back to Classic
- Deal options (draw 1/3, winnable-only, difficulty tiers) move into a
  disclosure under the hero — off the Home top level (decision 2)
- Compact symmetric 2x3 mode grid; descriptions on wide viewports only
- Stats strip moves to the bottom (right pane on wide)
- Two-pane body on wide viewports (>= 1000 logical px) via new
  ui_modal::spawn_modal_sized (default card stays 720 px)
- Cancel becomes "Back to table" and only renders while a live
  (un-won) game exists

10 new home_plugin tests; all 936 engine tests + clippy green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
funman300
2026-07-13 13:08:07 -07:00
parent 1fded5ff16
commit 560470b86b
4 changed files with 1141 additions and 311 deletions
+11 -1
View File
@@ -9,7 +9,10 @@ use std::io;
use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
use solitaire_core::{DrawStockConfig, game_state::DifficultyLevel};
use solitaire_core::{
DrawStockConfig,
game_state::{DifficultyLevel, GameMode},
};
const SETTINGS_FILE_NAME: &str = "settings.json";
@@ -248,6 +251,12 @@ pub struct Settings {
/// cleanly to `None` via `#[serde(default)]`.
#[serde(default)]
pub last_difficulty: Option<DifficultyLevel>,
/// Mode of the last game the player launched from the home overlay.
/// The home hero "New Game" button replays this mode with one tap.
/// Older `settings.json` files written before this field existed
/// deserialize cleanly to `GameMode::Classic` via `#[serde(default)]`.
#[serde(default)]
pub last_mode: GameMode,
/// Custom public name displayed on the leaderboard. When `None`, the
/// player's server `username` is used instead. Trimmed to 32 characters
/// before submission. Older `settings.json` files written before this
@@ -415,6 +424,7 @@ impl Default for Settings {
disable_smart_default_size: false,
replay_move_interval_secs: default_replay_move_interval_secs(),
last_difficulty: None,
last_mode: GameMode::Classic,
leaderboard_display_name: None,
leaderboard_opted_in: false,
take_from_foundation: true,