Auto-play a random legal card when the turn timeout expires

This commit is contained in:
2026-09-16 21:46:06 +08:00
parent d9cdba33a1
commit 89cf0a4c96
14 changed files with 285 additions and 8 deletions
+4
View File
@@ -132,6 +132,10 @@ pub struct GameView {
/// ISO-8601 instant at which the next hand is dealt automatically.
#[serde(default)]
pub hand_end_deadline: Option<String>,
/// ISO-8601 instant at which the server plays a random legal card for
/// the player on turn.
#[serde(default)]
pub turn_deadline: Option<String>,
#[serde(default)]
pub your_turn: Option<bool>,
/// Legal captures per hand card; present only for the player on turn.
+16 -1
View File
@@ -139,7 +139,7 @@ pub fn GamePage(id: String) -> View {
}
}
Some(g) if g.phase == "lobby" => lobby_view(g),
Some(g) => table_view(g, on_hand_card, selected),
Some(g) => table_view(g, on_hand_card, selected, now),
})
(move || capture_choice.get_clone().map(|(card, options)| {
capture_picker(card, options, socket, capture_choice)
@@ -193,6 +193,7 @@ fn table_view(
game: GameView,
on_hand_card: impl Fn(String) + Copy + 'static,
selected: Signal<Option<String>>,
now: Signal<f64>,
) -> View {
// Own seat: the only player entry carrying a hand.
let viewer_seat = game
@@ -218,6 +219,19 @@ fn table_view(
format!("{name}'s turn")
};
let turn_cls = if my_turn { "turn-note you" } else { "turn-note" };
let countdown = game.turn_deadline.as_ref().map(|deadline| {
// A dynamic closure so only the ticking number re-renders.
let deadline_ms = js_sys::Date::parse(deadline);
view! {
span(class="turn-timer") {
"Auto-play in "
(move || {
((deadline_ms - now.get_clone()) / 1000.0).ceil().max(0.0) as i32
})
"s"
}
}
});
let scores = game.scores.unwrap_or(Scores { a: 0, b: 0 });
let table_cards = game
@@ -272,6 +286,7 @@ fn table_view(
(target_score) ")"
}
span(class=turn_cls) { (turn_note) }
(countdown)
}
div(class="table-grid") {
(top)