fix(web client): reactive exit sign
This commit is contained in:
parent
7395d140cc
commit
a82169fbe5
1 changed files with 83 additions and 70 deletions
|
|
@ -312,13 +312,8 @@ pub fn Board(
|
||||||
exit_field_test = |f| matches!(f, 1..=6);
|
exit_field_test = |f| matches!(f, 1..=6);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show a clickable exit sign outside the board when bearing off is possible.
|
// Sequences clone for the reactive exit button (show/hide + class + click).
|
||||||
let has_exit_move = valid_sequences
|
let seqs_exit = valid_sequences.clone();
|
||||||
.iter()
|
|
||||||
.any(|(m1, m2)| m1.get_to() == 0 || m2.get_to() == 0);
|
|
||||||
let show_exit_btn = all_in_exit && is_move_stage && has_exit_move;
|
|
||||||
let seqs_exit_cls = valid_sequences.clone();
|
|
||||||
let seqs_exit_click = valid_sequences.clone();
|
|
||||||
|
|
||||||
// `valid_sequences` is cloned per field (the Vec is small; Send-safe unlike Rc).
|
// `valid_sequences` is cloned per field (the Vec is small; Send-safe unlike Rc).
|
||||||
let fields_from = |nums: &[u8], is_top_row: bool| -> Vec<AnyView> {
|
let fields_from = |nums: &[u8], is_top_row: bool| -> Vec<AnyView> {
|
||||||
|
|
@ -624,70 +619,88 @@ pub fn Board(
|
||||||
</svg>
|
</svg>
|
||||||
// Exit sign: circle+arrow outside the board, next to the last exit field.
|
// Exit sign: circle+arrow outside the board, next to the last exit field.
|
||||||
// White exits to the right (top-right quarter); Black exits to the left (top-left).
|
// White exits to the right (top-right quarter); Black exits to the left (top-left).
|
||||||
{show_exit_btn.then(|| {
|
{move || {
|
||||||
let (pos_style, line_x1, line_x2, head_pts): (&str, &str, &str, &str) =
|
// Recompute on every staged_moves change: the exit button must appear
|
||||||
if is_white {
|
// even when the initial board has a checker outside the exit zone,
|
||||||
(
|
// because the first move can bring all checkers in (e.g. 15→21, 19→exit).
|
||||||
"position:absolute;right:-60px;top:15px;width:50px;height:50px",
|
let staged = staged_moves.get();
|
||||||
"10", "31", "23,17 32,25 23,33",
|
let show = is_move_stage && match staged.len() {
|
||||||
)
|
0 => seqs_exit.iter().any(|(m1, m2)| m1.get_to() == 0 || m2.get_to() == 0),
|
||||||
} else {
|
1 => {
|
||||||
(
|
let (f0, t0) = staged[0];
|
||||||
"position:absolute;left:-60px;top:15px;width:50px;height:50px",
|
seqs_exit.iter()
|
||||||
"40", "19", "27,17 18,25 27,33",
|
.filter(|(m1, _)| m1.get_from() as u8 == f0 && m1.get_to() as u8 == t0)
|
||||||
)
|
.any(|(_, m2)| m2.get_to() == 0)
|
||||||
};
|
}
|
||||||
view! {
|
_ => false,
|
||||||
<div
|
};
|
||||||
title="Exit"
|
show.then(|| {
|
||||||
style=pos_style
|
let seqs_exit_cls = seqs_exit.clone();
|
||||||
class=move || {
|
let seqs_exit_click = seqs_exit.clone();
|
||||||
let staged = staged_moves.get();
|
let (pos_style, line_x1, line_x2, head_pts): (&str, &str, &str, &str) =
|
||||||
let sel = selected_origin.get();
|
if is_white {
|
||||||
let active = match sel {
|
(
|
||||||
Some(origin) => seqs_exit_cls.is_empty()
|
"position:absolute;right:-60px;top:15px;width:50px;height:50px",
|
||||||
|| valid_dests_for(&seqs_exit_cls, &staged, origin)
|
"10", "31", "23,17 32,25 23,33",
|
||||||
.iter()
|
)
|
||||||
.any(|&d| d == 0),
|
} else {
|
||||||
None => false,
|
(
|
||||||
};
|
"position:absolute;left:-60px;top:15px;width:50px;height:50px",
|
||||||
if active { "exit-btn exit-active" } else { "exit-btn" }
|
"40", "19", "27,17 18,25 27,33",
|
||||||
}
|
)
|
||||||
on:click=move |_| {
|
};
|
||||||
if !is_move_stage { return; }
|
view! {
|
||||||
let staged = staged_moves.get_untracked();
|
<div
|
||||||
if staged.len() >= 2 { return; }
|
title="Exit"
|
||||||
let Some(origin) = selected_origin.get_untracked() else {
|
style=pos_style
|
||||||
return;
|
class=move || {
|
||||||
};
|
let staged = staged_moves.get();
|
||||||
let valid = seqs_exit_click.is_empty()
|
let sel = selected_origin.get();
|
||||||
|| valid_dests_for(&seqs_exit_click, &staged, origin)
|
let active = match sel {
|
||||||
.iter()
|
Some(origin) => seqs_exit_cls.is_empty()
|
||||||
.any(|&d| d == 0);
|
|| valid_dests_for(&seqs_exit_cls, &staged, origin)
|
||||||
if valid {
|
.iter()
|
||||||
staged_moves.update(|v| v.push((origin, 0)));
|
.any(|&d| d == 0),
|
||||||
selected_origin.set(None);
|
None => false,
|
||||||
|
};
|
||||||
|
if active { "exit-btn exit-active" } else { "exit-btn" }
|
||||||
}
|
}
|
||||||
}
|
on:click=move |_| {
|
||||||
>
|
if !is_move_stage { return; }
|
||||||
<svg width="50" height="50" viewBox="0 0 50 50">
|
let staged = staged_moves.get_untracked();
|
||||||
<circle
|
if staged.len() >= 2 { return; }
|
||||||
cx="25" cy="25" r="20"
|
let Some(origin) = selected_origin.get_untracked() else {
|
||||||
style="fill:rgba(10,20,10,0.75);stroke:rgba(210,170,30,0.75);stroke-width:2.5"
|
return;
|
||||||
/>
|
};
|
||||||
<line
|
let valid = seqs_exit_click.is_empty()
|
||||||
x1=line_x1 y1="25" x2=line_x2 y2="25"
|
|| valid_dests_for(&seqs_exit_click, &staged, origin)
|
||||||
style="stroke:rgba(210,170,30,0.85);stroke-width:2.5;stroke-linecap:round"
|
.iter()
|
||||||
/>
|
.any(|&d| d == 0);
|
||||||
<polyline
|
if valid {
|
||||||
points=head_pts
|
staged_moves.update(|v| v.push((origin, 0)));
|
||||||
style="fill:none;stroke:rgba(210,170,30,0.85);stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round"
|
selected_origin.set(None);
|
||||||
/>
|
}
|
||||||
</svg>
|
}
|
||||||
</div>
|
>
|
||||||
}
|
<svg width="50" height="50" viewBox="0 0 50 50">
|
||||||
.into_any()
|
<circle
|
||||||
})}
|
cx="25" cy="25" r="20"
|
||||||
|
style="fill:rgba(10,20,10,0.75);stroke:rgba(210,170,30,0.75);stroke-width:2.5"
|
||||||
|
/>
|
||||||
|
<line
|
||||||
|
x1=line_x1 y1="25" x2=line_x2 y2="25"
|
||||||
|
style="stroke:rgba(210,170,30,0.85);stroke-width:2.5;stroke-linecap:round"
|
||||||
|
/>
|
||||||
|
<polyline
|
||||||
|
points=head_pts
|
||||||
|
style="fill:none;stroke:rgba(210,170,30,0.85);stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
.into_any()
|
||||||
|
})
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="zone-labels-row">
|
<div class="zone-labels-row">
|
||||||
<div class="zone-label zone-label-quarter">{label_bl}</div>
|
<div class="zone-label zone-label-quarter">{label_bl}</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue