Rebuild the web UI on Bootstrap 5 with the dark felt theme
CI / Build and push docker image (push) Failing after 39s

The lobby was hand-rolled CSS and looked plain. Vendor Bootstrap 5.3
(MIT) under web/vendor so builds stay offline, load it in dark mode and
bridge the felt/gold palette onto Bootstrap's CSS variables in a new
theme.css; style.css now only owns the game table, cards and scoring
summary.

Rebuild the lobby, waiting room and shared chrome with Bootstrap
components: a shared navbar, creation form as cards with schema-driven
controls, roster as a list group with seat/team badges, a seats progress
bar and a copy-to-clipboard button on the join code. History,
leaderboard, connection/error states and the 404 page use cards, tables
and buttons too; the play table itself is unchanged.

The copy feedback timer is cancelled when the waiting room is rebuilt by
another player joining, fixing a disposed-signal panic that froze the
page mid-match.
This commit is contained in:
2026-09-21 23:40:44 +08:00
parent ed8a004ec8
commit 12fa3f5aae
15 changed files with 774 additions and 486 deletions
+3 -3
View File
@@ -246,7 +246,7 @@ pub fn hand_summary_modal(
// whole modal (which would swap DOM nodes under the user's cursor).
let deadline_ms = js_sys::Date::parse(deadline);
view! {
p(class="hint") {
p(class="text-secondary small") {
"Auto-continuing in "
(move || {
((deadline_ms - now.get_clone()) / 1000.0).ceil().max(0.0) as i32
@@ -263,11 +263,11 @@ pub fn hand_summary_modal(
let action = if already_acked {
let waiting_text = format!("Waiting for {}…", waiting.join(", "));
view! {
button(class="button primary", disabled=true) { (waiting_text) }
button(class="btn btn-warning", disabled=true) { (waiting_text) }
}
} else {
view! {
button(class="button primary", on:click=move |_| {
button(class="btn btn-warning", on:click=move |_| {
if let Some(s) = socket.get_clone() {
s.ack();
}