feat(replay): add HC bump for WIN MOVE scrub-bar marker; extend HighContrastBackground
HighContrastBackground gains an optional hc_color field so sites can specify a domain-specific HC variant rather than always bumping to BORDER_SUBTLE_HC (gray). with_default() fills hc_color = BORDER_SUBTLE_HC preserving all existing behaviour; new with_hc(default, hc) lets callers specify both ends. update_high_contrast_backgrounds reads marker.hc_color instead of the hardcoded constant. STATE_SUCCESS_HC (#c8e862, L≈0.73) added to ui_theme — a brighter lime that maintains the success hue while standing out from bumped notch ticks (BORDER_SUBTLE_HC gray, L≈0.60) under HC mode. WIN MOVE marker now carries HighContrastBackground::with_hc(STATE_SUCCESS, STATE_SUCCESS_HC): lime stays lime under HC instead of turning gray. Unit test pins both the default and hc color fields on the spawned marker. 1276 tests pass / 0 failing. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -38,8 +38,8 @@ use solitaire_data::ReplayMove;
|
|||||||
use crate::ui_modal::{spawn_modal_button, ButtonVariant};
|
use crate::ui_modal::{spawn_modal_button, ButtonVariant};
|
||||||
use crate::ui_theme::{
|
use crate::ui_theme::{
|
||||||
ACCENT_PRIMARY, BG_ELEVATED_HI, BORDER_SUBTLE, HighContrastBackground, HighContrastBorder,
|
ACCENT_PRIMARY, BG_ELEVATED_HI, BORDER_SUBTLE, HighContrastBackground, HighContrastBorder,
|
||||||
STATE_SUCCESS, TEXT_PRIMARY, TEXT_PRIMARY_HC, TEXT_SECONDARY, TYPE_BODY, TYPE_CAPTION,
|
STATE_SUCCESS, STATE_SUCCESS_HC, TEXT_PRIMARY, TEXT_PRIMARY_HC, TEXT_SECONDARY, TYPE_BODY,
|
||||||
TYPE_HEADLINE, VAL_SPACE_1, VAL_SPACE_2, VAL_SPACE_4, Z_DROP_OVERLAY,
|
TYPE_CAPTION, TYPE_HEADLINE, VAL_SPACE_1, VAL_SPACE_2, VAL_SPACE_4, Z_DROP_OVERLAY,
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -779,6 +779,11 @@ fn spawn_overlay(
|
|||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
BackgroundColor(STATE_SUCCESS),
|
BackgroundColor(STATE_SUCCESS),
|
||||||
|
// HC bump: lime → brighter lime so the win
|
||||||
|
// marker reads clearly above the bumped
|
||||||
|
// notch ticks (BORDER_SUBTLE_HC gray) under
|
||||||
|
// high-contrast mode.
|
||||||
|
HighContrastBackground::with_hc(STATE_SUCCESS, STATE_SUCCESS_HC),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
// Fixed quarter-mark notches: five 1px vertical
|
// Fixed quarter-mark notches: five 1px vertical
|
||||||
@@ -2349,6 +2354,44 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The WIN MOVE marker carries `HighContrastBackground::with_hc(
|
||||||
|
/// STATE_SUCCESS, STATE_SUCCESS_HC)` so the lime bumps to brighter
|
||||||
|
/// lime under HC mode rather than to a neutral gray. Pin the
|
||||||
|
/// presence of the marker so a future refactor can't accidentally
|
||||||
|
/// drop it and silently regress HC legibility.
|
||||||
|
#[test]
|
||||||
|
fn win_move_marker_carries_hc_background_marker() {
|
||||||
|
let mut app = headless_app();
|
||||||
|
set_state(
|
||||||
|
&mut app,
|
||||||
|
ReplayPlaybackState::Playing {
|
||||||
|
replay: synthetic_replay(8).with_win_move_index(Some(7)),
|
||||||
|
cursor: 0,
|
||||||
|
secs_to_next: 0.5,
|
||||||
|
paused: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
app.update();
|
||||||
|
|
||||||
|
let mut q = app
|
||||||
|
.world_mut()
|
||||||
|
.query_filtered::<&HighContrastBackground, With<ReplayOverlayWinMoveMarker>>();
|
||||||
|
let marker = q
|
||||||
|
.iter(app.world())
|
||||||
|
.next()
|
||||||
|
.expect("WIN MOVE marker must carry HighContrastBackground");
|
||||||
|
assert_eq!(
|
||||||
|
marker.default_color,
|
||||||
|
STATE_SUCCESS,
|
||||||
|
"default colour must be STATE_SUCCESS"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
marker.hc_color,
|
||||||
|
STATE_SUCCESS_HC,
|
||||||
|
"HC colour must be STATE_SUCCESS_HC (brighter lime, not gray)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
// scrub_notch_positions + ReplayOverlayScrubNotch spawn behaviour
|
// scrub_notch_positions + ReplayOverlayScrubNotch spawn behaviour
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|||||||
@@ -701,7 +701,7 @@ pub(crate) fn update_high_contrast_backgrounds(
|
|||||||
let high_contrast = settings.0.high_contrast_mode;
|
let high_contrast = settings.0.high_contrast_mode;
|
||||||
for (marker, mut bg) in backgrounds.iter_mut() {
|
for (marker, mut bg) in backgrounds.iter_mut() {
|
||||||
let target = if high_contrast {
|
let target = if high_contrast {
|
||||||
BORDER_SUBTLE_HC
|
marker.hc_color
|
||||||
} else {
|
} else {
|
||||||
marker.default_color
|
marker.default_color
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -93,6 +93,13 @@ pub const ACCENT_SECONDARY: Color = Color::srgb(0.882, 0.639, 0.933);
|
|||||||
/// from base16-eighties. `#acc267`.
|
/// from base16-eighties. `#acc267`.
|
||||||
pub const STATE_SUCCESS: Color = Color::srgb(0.675, 0.761, 0.404);
|
pub const STATE_SUCCESS: Color = Color::srgb(0.675, 0.761, 0.404);
|
||||||
|
|
||||||
|
/// High-contrast variant of [`STATE_SUCCESS`] — `#c8e862`. Brighter
|
||||||
|
/// lime that maintains the success hue while lifting luminance from
|
||||||
|
/// ~0.51 → ~0.73 so the WIN MOVE scrub-bar marker stands out from
|
||||||
|
/// the bumped notch ticks (`BORDER_SUBTLE_HC` `#a0a0a0`, L≈0.60) in
|
||||||
|
/// high-contrast mode.
|
||||||
|
pub const STATE_SUCCESS_HC: Color = Color::srgb(0.784, 0.910, 0.384);
|
||||||
|
|
||||||
/// Warning — penalty signal, daily-seed expiry countdown, sync-pending
|
/// Warning — penalty signal, daily-seed expiry countdown, sync-pending
|
||||||
/// status. Gold from base16-eighties. **Both** Undo and Recycle
|
/// status. Gold from base16-eighties. **Both** Undo and Recycle
|
||||||
/// counters use this when non-zero. `#ddb26f`.
|
/// counters use this when non-zero. `#ddb26f`.
|
||||||
@@ -260,24 +267,45 @@ impl HighContrastBorder {
|
|||||||
/// often render as tiny full-bleed `Node`s, not as borders, so the
|
/// often render as tiny full-bleed `Node`s, not as borders, so the
|
||||||
/// border-marker pattern doesn't apply.
|
/// border-marker pattern doesn't apply.
|
||||||
///
|
///
|
||||||
/// `default_color` records the off-state colour the entity was
|
/// `default_color` records the off-state colour; `hc_color` the on-
|
||||||
/// spawned with so the system can revert when HC is toggled back
|
/// state colour. [`with_default`] fills `hc_color` with
|
||||||
/// off. The accompanying paint system is
|
/// [`BORDER_SUBTLE_HC`] so the 90 % of sites that just need the
|
||||||
/// [`update_high_contrast_backgrounds`](crate::settings_plugin::update_high_contrast_backgrounds).
|
/// standard subtle-border bump can continue using a one-argument
|
||||||
|
/// constructor. [`with_hc`] overrides the HC colour for the rare
|
||||||
|
/// site (currently only the WIN MOVE scrub-bar marker) that needs a
|
||||||
|
/// domain-specific HC variant (`STATE_SUCCESS_HC` instead of a gray).
|
||||||
///
|
///
|
||||||
|
/// [`with_default`]: HighContrastBackground::with_default
|
||||||
|
/// [`with_hc`]: HighContrastBackground::with_hc
|
||||||
/// [`BackgroundColor`]: bevy::prelude::BackgroundColor
|
/// [`BackgroundColor`]: bevy::prelude::BackgroundColor
|
||||||
#[derive(bevy::prelude::Component, Debug, Clone, Copy)]
|
#[derive(bevy::prelude::Component, Debug, Clone, Copy)]
|
||||||
pub struct HighContrastBackground {
|
pub struct HighContrastBackground {
|
||||||
/// Background colour to use when high-contrast mode is *off* —
|
/// Background colour to use when high-contrast mode is *off* —
|
||||||
/// the site's normal idle / active-state colour.
|
/// the site's normal idle / active-state colour.
|
||||||
pub default_color: bevy::prelude::Color,
|
pub default_color: bevy::prelude::Color,
|
||||||
|
/// Background colour to use when high-contrast mode is *on*.
|
||||||
|
/// Defaults to [`BORDER_SUBTLE_HC`] via [`with_default`].
|
||||||
|
///
|
||||||
|
/// [`with_default`]: HighContrastBackground::with_default
|
||||||
|
pub hc_color: bevy::prelude::Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HighContrastBackground {
|
impl HighContrastBackground {
|
||||||
/// Convenience constructor —
|
/// Convenience constructor — HC colour defaults to
|
||||||
/// `HighContrastBackground::with_default(BORDER_SUBTLE)`.
|
/// [`BORDER_SUBTLE_HC`].
|
||||||
pub const fn with_default(default_color: bevy::prelude::Color) -> Self {
|
pub const fn with_default(default_color: bevy::prelude::Color) -> Self {
|
||||||
Self { default_color }
|
Self { default_color, hc_color: BORDER_SUBTLE_HC }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructor for sites whose HC colour differs from the standard
|
||||||
|
/// [`BORDER_SUBTLE_HC`]. Currently used by the WIN MOVE scrub-bar
|
||||||
|
/// marker which bumps `STATE_SUCCESS` → `STATE_SUCCESS_HC` rather
|
||||||
|
/// than to a neutral gray.
|
||||||
|
pub const fn with_hc(
|
||||||
|
default_color: bevy::prelude::Color,
|
||||||
|
hc_color: bevy::prelude::Color,
|
||||||
|
) -> Self {
|
||||||
|
Self { default_color, hc_color }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user