feat(client_web): add right panel for status messages and dice
This commit is contained in:
parent
c6031b0ace
commit
9fe79ffc7a
2 changed files with 91 additions and 70 deletions
|
|
@ -54,7 +54,6 @@ input[type="text"] {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 900px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Language switcher ──────────────────────────────────────────────── */
|
/* ── Language switcher ──────────────────────────────────────────────── */
|
||||||
|
|
@ -108,7 +107,6 @@ input[type="text"] {
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
box-shadow: 0 1px 4px rgba(0,0,0,0.2);
|
box-shadow: 0 1px 4px rgba(0,0,0,0.2);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 900px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.player-score-header {
|
.player-score-header {
|
||||||
|
|
@ -180,6 +178,28 @@ input[type="text"] {
|
||||||
padding-top: 0.25rem;
|
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 ─────────────────────────────────────────────────────── */
|
||||||
.status-bar {
|
.status-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -189,7 +209,7 @@ input[type="text"] {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Dice bars ──────────────────────────────────────────────────────── */
|
/* ── Dice bar ───────────────────────────────────────────────────────── */
|
||||||
.dice-bar {
|
.dice-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
||||||
|
|
@ -157,77 +157,78 @@ pub fn GameScreen(state: GameUiState) -> impl IntoView {
|
||||||
// ── Opponent score (above board) ─────────────────────────────────
|
// ── Opponent score (above board) ─────────────────────────────────
|
||||||
<PlayerScorePanel score=opp_score jans=opp_jans is_you=false />
|
<PlayerScorePanel score=opp_score jans=opp_jans is_you=false />
|
||||||
|
|
||||||
// ── Status ───────────────────────────────────────────────────────
|
// ── Board + side panel ───────────────────────────────────────────
|
||||||
<div class="status-bar">
|
<div class="board-and-panel">
|
||||||
<span>{move || {
|
<Board
|
||||||
let n = staged_moves.get().len();
|
view_state=vs
|
||||||
if is_move_stage {
|
player_id=player_id
|
||||||
t_string!(i18n, select_move, n = n + 1)
|
selected_origin=selected_origin
|
||||||
} else {
|
staged_moves=staged_moves
|
||||||
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),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
// ── Opponent dice (top) ──────────────────────────────────────────
|
// ── Side panel ───────────────────────────────────────────────
|
||||||
{(!is_my_turn && show_dice).then(|| view! {
|
<div class="side-panel">
|
||||||
<div class="dice-bar dice-bar-opponent">
|
// Status message
|
||||||
<Die value=dice.0 used=true />
|
<div class="status-bar">
|
||||||
<Die value=dice.1 used=true />
|
<span>{move || {
|
||||||
</div>
|
let n = staged_moves.get().len();
|
||||||
})}
|
if is_move_stage {
|
||||||
|
t_string!(i18n, select_move, n = n + 1)
|
||||||
// ── Board ────────────────────────────────────────────────────────
|
} else {
|
||||||
<Board
|
String::from(match (&stage, is_my_turn, &turn_stage) {
|
||||||
view_state=vs
|
(SerStage::Ended, _, _) => t_string!(i18n, game_over),
|
||||||
player_id=player_id
|
(SerStage::PreGame, _, _) => t_string!(i18n, waiting_for_opponent),
|
||||||
selected_origin=selected_origin
|
(SerStage::InGame, true, SerTurnStage::RollDice) => t_string!(i18n, your_turn_roll),
|
||||||
staged_moves=staged_moves
|
(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),
|
||||||
// ── Player action bar (bottom) ───────────────────────────────────
|
})
|
||||||
{is_my_turn.then(|| view! {
|
|
||||||
<div class="dice-bar dice-bar-player">
|
|
||||||
{move || {
|
|
||||||
let (d0, d1) = if is_move_stage {
|
|
||||||
matched_dice_used(&staged_moves.get(), dice)
|
|
||||||
} else {
|
|
||||||
(false, false)
|
|
||||||
};
|
|
||||||
view! {
|
|
||||||
<Die value=dice.0 used=d0 />
|
|
||||||
<Die value=dice.1 used=d1 />
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
{show_roll.then(|| view! {
|
|
||||||
<button class="btn btn-primary" on:click=move |_| {
|
|
||||||
cmd_tx_roll.unbounded_send(NetCommand::Action(PlayerAction::Roll)).ok();
|
|
||||||
}>{t!(i18n, roll_dice)}</button>
|
|
||||||
})}
|
|
||||||
{show_hold_go.then(|| view! {
|
|
||||||
<button class="btn btn-primary" on:click=move |_| {
|
|
||||||
cmd_tx_go.unbounded_send(NetCommand::Action(PlayerAction::Go)).ok();
|
|
||||||
}>{t!(i18n, go)}</button>
|
|
||||||
})}
|
|
||||||
{is_move_stage.then(|| view! {
|
|
||||||
<button
|
|
||||||
class="btn btn-secondary"
|
|
||||||
disabled=move || 2 <= staged_moves.get().len()
|
|
||||||
on:click=move |_| {
|
|
||||||
selected_origin.set(None);
|
|
||||||
staged_moves.update(|v| v.push((0, 0)));
|
|
||||||
}
|
}
|
||||||
>{t!(i18n, empty_move)}</button>
|
}}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
// Dice (always shown when rolled, used state depends on whose turn)
|
||||||
|
{show_dice.then(|| view! {
|
||||||
|
<div class="dice-bar">
|
||||||
|
{move || {
|
||||||
|
let (d0, d1) = if is_move_stage {
|
||||||
|
matched_dice_used(&staged_moves.get(), dice)
|
||||||
|
} else {
|
||||||
|
(true, true)
|
||||||
|
};
|
||||||
|
view! {
|
||||||
|
<Die value=dice.0 used=d0 />
|
||||||
|
<Die value=dice.1 used=d1 />
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
})}
|
})}
|
||||||
|
|
||||||
|
// Action buttons
|
||||||
|
<div class="action-buttons">
|
||||||
|
{show_roll.then(|| view! {
|
||||||
|
<button class="btn btn-primary" on:click=move |_| {
|
||||||
|
cmd_tx_roll.unbounded_send(NetCommand::Action(PlayerAction::Roll)).ok();
|
||||||
|
}>{t!(i18n, roll_dice)}</button>
|
||||||
|
})}
|
||||||
|
{show_hold_go.then(|| view! {
|
||||||
|
<button class="btn btn-primary" on:click=move |_| {
|
||||||
|
cmd_tx_go.unbounded_send(NetCommand::Action(PlayerAction::Go)).ok();
|
||||||
|
}>{t!(i18n, go)}</button>
|
||||||
|
})}
|
||||||
|
{is_move_stage.then(|| view! {
|
||||||
|
<button
|
||||||
|
class="btn btn-secondary"
|
||||||
|
disabled=move || 2 <= staged_moves.get().len()
|
||||||
|
on:click=move |_| {
|
||||||
|
selected_origin.set(None);
|
||||||
|
staged_moves.update(|v| v.push((0, 0)));
|
||||||
|
}
|
||||||
|
>{t!(i18n, empty_move)}</button>
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
})}
|
</div>
|
||||||
|
|
||||||
// ── Player score (below board) ────────────────────────────────────
|
// ── Player score (below board) ────────────────────────────────────
|
||||||
<PlayerScorePanel score=my_score jans=my_jans is_you=true />
|
<PlayerScorePanel score=my_score jans=my_jans is_you=true />
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue