fix(client_web): show opponent's dice animation
This commit is contained in:
parent
72c5e16ea3
commit
68ecafd0dc
3 changed files with 39 additions and 25 deletions
|
|
@ -450,8 +450,8 @@ body {
|
|||
strip after a few seconds, and reveal fully on hover. */
|
||||
.side-panel {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
right: -8px;
|
||||
top: 10px;
|
||||
z-index: 20;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -645,8 +645,7 @@ body {
|
|||
/* ── Wrapper: handles slide-in → peek → reveal lifecycle ──────────────
|
||||
The wrapper starts off-screen right (translateX(100%)), slides in on
|
||||
mount via animation, then Leptos adds .peeked after 3.4s to slide it
|
||||
back to a 28px peek strip. First hover adds .revealed for permanent
|
||||
visibility. pointer-events: auto overrides the parent's none. */
|
||||
back to a 28px peek strip. */
|
||||
@keyframes scoring-panel-enter {
|
||||
from { transform: translateX(100%); }
|
||||
to { transform: translateX(0); }
|
||||
|
|
@ -662,7 +661,7 @@ body {
|
|||
|
||||
/* Peeked: slide right by the full panel width so the board is 100% clear.
|
||||
The panel's left portion stays visible in whatever free space exists to
|
||||
the right of the board (depends on viewport width). */
|
||||
the right of the board. */
|
||||
.scoring-panel-wrapper.peeked {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
|
@ -868,8 +867,8 @@ body {
|
|||
.board-quarter .field.zone-retour:nth-child(odd) { --fc: #6a2810; }
|
||||
.board-quarter .field.zone-retour:nth-child(even) { --fc: #f2dfa0; }
|
||||
|
||||
/* ── Rest corner (§3) — before .clickable so green wins when interactive ── */
|
||||
.field.corner { --fc: var(--field-corner) !important; }
|
||||
/* ── Rest corner — before .clickable so green wins when interactive ── */
|
||||
/* .field.corner { --fc: var(--field-corner) !important; } */
|
||||
|
||||
/* Crown glyph sits behind checkers (z-index:-1) so it shows only on empty corners */
|
||||
.field.corner::after {
|
||||
|
|
|
|||
|
|
@ -256,6 +256,7 @@ pub fn Board(
|
|||
/// Whether we're in the move stage (determines used/unused die appearance).
|
||||
#[prop(default = false)]
|
||||
bar_is_move: bool,
|
||||
#[prop(default = false)] is_my_turn: bool,
|
||||
/// Whether the dice are a double (golden glow).
|
||||
#[prop(default = false)]
|
||||
bar_is_double: bool,
|
||||
|
|
@ -344,6 +345,9 @@ pub fn Board(
|
|||
cls.push_str(" corner-available");
|
||||
}
|
||||
}
|
||||
if is_rest_corner(field_num, !is_white) {
|
||||
cls.push_str(" corner");
|
||||
}
|
||||
if all_in_exit && exit_field_test(field_num) {
|
||||
cls.push_str(" exit-eligible");
|
||||
}
|
||||
|
|
@ -501,8 +505,10 @@ pub fn Board(
|
|||
let staged = staged_moves.get();
|
||||
let (u0, u1) = if bar_is_move {
|
||||
bar_matched_dice_used(&staged, dice_vals)
|
||||
} else {
|
||||
} else if is_my_turn {
|
||||
(true, true)
|
||||
} else {
|
||||
(false, false)
|
||||
};
|
||||
let used = if die_idx == 0 { u0 } else { u1 };
|
||||
view! { <Die value=die_val used=used is_double=bar_is_double /> }
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ pub fn GameScreen(state: GameUiState) -> impl IntoView {
|
|||
|
||||
let cmd_tx = use_context::<UnboundedSender<NetCommand>>()
|
||||
.expect("UnboundedSender<NetCommand> not found in context");
|
||||
let pending = use_context::<RwSignal<VecDeque<GameUiState>>>()
|
||||
.expect("pending not found in context");
|
||||
let pending =
|
||||
use_context::<RwSignal<VecDeque<GameUiState>>>().expect("pending not found in context");
|
||||
let cmd_tx_effect = cmd_tx.clone();
|
||||
Effect::new(move |_| {
|
||||
let moves = staged_moves.get();
|
||||
|
|
@ -68,7 +68,9 @@ pub fn GameScreen(state: GameUiState) -> impl IntoView {
|
|||
if show_roll && !waiting_for_confirm {
|
||||
let cmd_tx_auto = cmd_tx.clone();
|
||||
Effect::new(move |_| {
|
||||
cmd_tx_auto.unbounded_send(NetCommand::Action(PlayerAction::Roll)).ok();
|
||||
cmd_tx_auto
|
||||
.unbounded_send(NetCommand::Action(PlayerAction::Roll))
|
||||
.ok();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -92,13 +94,19 @@ pub fn GameScreen(state: GameUiState) -> impl IntoView {
|
|||
let mut store_board = StoreBoard::new();
|
||||
store_board.set_positions(&Color::White, vs.board);
|
||||
let store_dice = StoreDice { values: dice };
|
||||
let color = if player_id == 0 { Color::White } else { Color::Black };
|
||||
let color = if player_id == 0 {
|
||||
Color::White
|
||||
} else {
|
||||
Color::Black
|
||||
};
|
||||
let rules = MoveRules::new(&color, &store_board, store_dice);
|
||||
let raw = rules.get_possible_moves_sequences(true, vec![]);
|
||||
if player_id == 0 {
|
||||
raw
|
||||
} else {
|
||||
raw.into_iter().map(|(m1, m2)| (m1.mirror(), m2.mirror())).collect()
|
||||
raw.into_iter()
|
||||
.map(|(m1, m2)| (m1.mirror(), m2.mirror()))
|
||||
.collect()
|
||||
}
|
||||
} else {
|
||||
vec![]
|
||||
|
|
@ -113,7 +121,8 @@ pub fn GameScreen(state: GameUiState) -> impl IntoView {
|
|||
// ── Scoring notifications ──────────────────────────────────────────────────
|
||||
let my_scored_event = state.my_scored_event.clone();
|
||||
let opp_scored_event = state.opp_scored_event.clone();
|
||||
let hole_toast_info = my_scored_event.as_ref()
|
||||
let hole_toast_info = my_scored_event
|
||||
.as_ref()
|
||||
.filter(|e| e.holes_gained > 0)
|
||||
.map(|e| (e.holes_total, e.bredouille));
|
||||
|
||||
|
|
@ -123,14 +132,16 @@ pub fn GameScreen(state: GameUiState) -> impl IntoView {
|
|||
|
||||
// §6e — fields where a battue (hit) was scored; ripple animation shown there.
|
||||
let hit_fields: Vec<u8> = {
|
||||
let is_hit_jan = |jan: &Jan| matches!(
|
||||
jan,
|
||||
Jan::TrueHitSmallJan
|
||||
| Jan::TrueHitBigJan
|
||||
| Jan::TrueHitOpponentCorner
|
||||
| Jan::FalseHitSmallJan
|
||||
| Jan::FalseHitBigJan
|
||||
);
|
||||
let is_hit_jan = |jan: &Jan| {
|
||||
matches!(
|
||||
jan,
|
||||
Jan::TrueHitSmallJan
|
||||
| Jan::TrueHitBigJan
|
||||
| Jan::TrueHitOpponentCorner
|
||||
| Jan::FalseHitSmallJan
|
||||
| Jan::FalseHitBigJan
|
||||
)
|
||||
};
|
||||
let mut fields: Vec<u8> = vec![];
|
||||
for event_opt in [&my_scored_event, &opp_scored_event] {
|
||||
if let Some(event) = event_opt {
|
||||
|
|
@ -148,9 +159,6 @@ pub fn GameScreen(state: GameUiState) -> impl IntoView {
|
|||
}
|
||||
}
|
||||
}
|
||||
if !fields.is_empty() {
|
||||
leptos::logging::log!("[6e] hit_fields = {:?}", fields);
|
||||
}
|
||||
fields
|
||||
};
|
||||
|
||||
|
|
@ -248,6 +256,7 @@ pub fn GameScreen(state: GameUiState) -> impl IntoView {
|
|||
valid_sequences=valid_sequences
|
||||
bar_dice=show_dice.then_some(dice)
|
||||
bar_is_move=is_move_stage
|
||||
is_my_turn=is_my_turn
|
||||
bar_is_double=is_double_dice
|
||||
last_moves=last_moves
|
||||
hit_fields=hit_fields
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue