diff --git a/client_web/assets/style.css b/client_web/assets/style.css index fceeea4..5ca31e5 100644 --- a/client_web/assets/style.css +++ b/client_web/assets/style.css @@ -54,7 +54,6 @@ input[type="text"] { align-items: center; gap: 0.75rem; width: 100%; - max-width: 900px; } /* ── Language switcher ──────────────────────────────────────────────── */ @@ -108,7 +107,6 @@ input[type="text"] { font-size: 0.9rem; box-shadow: 0 1px 4px rgba(0,0,0,0.2); width: 100%; - max-width: 900px; } .player-score-header { @@ -180,6 +178,28 @@ input[type="text"] { padding-top: 0.25rem; } +/* ── Board + side panel ─────────────────────────────────────────────── */ +.board-and-panel { + display: flex; + flex-direction: row; + align-items: flex-start; + gap: 1rem; +} + +.side-panel { + display: flex; + flex-direction: column; + gap: 0.75rem; + min-width: 160px; + padding-top: 0.25rem; +} + +.action-buttons { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + /* ── Status bar ─────────────────────────────────────────────────────── */ .status-bar { display: flex; @@ -189,7 +209,7 @@ input[type="text"] { font-weight: 500; } -/* ── Dice bars ──────────────────────────────────────────────────────── */ +/* ── Dice bar ───────────────────────────────────────────────────────── */ .dice-bar { display: flex; align-items: center; diff --git a/client_web/src/components/game_screen.rs b/client_web/src/components/game_screen.rs index 6c3edec..730e6be 100644 --- a/client_web/src/components/game_screen.rs +++ b/client_web/src/components/game_screen.rs @@ -157,77 +157,78 @@ pub fn GameScreen(state: GameUiState) -> impl IntoView { // ── Opponent score (above board) ───────────────────────────────── - // ── Status ─────────────────────────────────────────────────────── -
- {move || { - let n = staged_moves.get().len(); - if is_move_stage { - t_string!(i18n, select_move, n = n + 1) - } else { - String::from(match (&stage, is_my_turn, &turn_stage) { - (SerStage::Ended, _, _) => t_string!(i18n, game_over), - (SerStage::PreGame, _, _) => t_string!(i18n, waiting_for_opponent), - (SerStage::InGame, true, SerTurnStage::RollDice) => t_string!(i18n, your_turn_roll), - (SerStage::InGame, true, SerTurnStage::HoldOrGoChoice) => t_string!(i18n, hold_or_go), - (SerStage::InGame, true, _) => t_string!(i18n, your_turn), - (SerStage::InGame, false, _) => t_string!(i18n, opponent_turn), - }) - } - }} -
+ // ── Board + side panel ─────────────────────────────────────────── +
+ - // ── Opponent dice (top) ────────────────────────────────────────── - {(!is_my_turn && show_dice).then(|| view! { -
- - -
- })} - - // ── Board ──────────────────────────────────────────────────────── - - - // ── Player action bar (bottom) ─────────────────────────────────── - {is_my_turn.then(|| view! { -
- {move || { - let (d0, d1) = if is_move_stage { - matched_dice_used(&staged_moves.get(), dice) - } else { - (false, false) - }; - view! { - - - } - }} - {show_roll.then(|| view! { - - })} - {show_hold_go.then(|| view! { - - })} - {is_move_stage.then(|| view! { - + }} +
+ + // Dice (always shown when rolled, used state depends on whose turn) + {show_dice.then(|| view! { +
+ {move || { + let (d0, d1) = if is_move_stage { + matched_dice_used(&staged_moves.get(), dice) + } else { + (true, true) + }; + view! { + + + } + }} +
})} + + // Action buttons +
+ {show_roll.then(|| view! { + + })} + {show_hold_go.then(|| view! { + + })} + {is_move_stage.then(|| view! { + + })} +
- })} + // ── Player score (below board) ────────────────────────────────────