player list styling
This commit is contained in:
parent
8c2791054a
commit
cbeee94113
|
|
@ -28,12 +28,12 @@ pub async fn handler(
|
|||
.map(|x| x.to_string())
|
||||
.unwrap_or_else(|| addr.to_string())
|
||||
.italic();
|
||||
log::info!(
|
||||
"{who}{} connected.",
|
||||
user_agent
|
||||
.map(|agent| format!(" (User-Agent: {})", agent.as_str()))
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
// log::debug!(
|
||||
// "{who}{} connected.",
|
||||
// user_agent
|
||||
// .map(|agent| format!(" (User-Agent: {})", agent.as_str()))
|
||||
// .unwrap_or_default(),
|
||||
// );
|
||||
let player_list = state.joined_players;
|
||||
|
||||
// finalize the upgrade process by returning upgrade callback.
|
||||
|
|
@ -46,7 +46,7 @@ pub async fn handler(
|
|||
return;
|
||||
}
|
||||
};
|
||||
log::info!("connected {who} as {ident}");
|
||||
// log::debug!("connected {who} as {ident}");
|
||||
let connection_id = ConnectionId::new(ident.player_id.clone());
|
||||
let recv = {
|
||||
let (send, recv) = tokio::sync::broadcast::channel(100);
|
||||
|
|
@ -76,7 +76,7 @@ pub async fn handler(
|
|||
.run()
|
||||
.await;
|
||||
|
||||
log::info!("ending connection with {who}");
|
||||
// log::debug!("ending connection with {who}");
|
||||
player_list.disconnect(&connection_id).await;
|
||||
})
|
||||
}
|
||||
|
|
@ -178,11 +178,11 @@ impl Client {
|
|||
}
|
||||
Message::Pong(_) => return Ok(()),
|
||||
Message::Close(Some(close_frame)) => {
|
||||
log::debug!("sent close frame: {close_frame:?}");
|
||||
// log::debug!("sent close frame: {close_frame:?}");
|
||||
return Ok(());
|
||||
}
|
||||
Message::Close(None) => {
|
||||
log::debug!("host closed connection");
|
||||
// log::debug!("host closed connection");
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use super::{HostComms, player::PlayerIdComms};
|
|||
|
||||
pub struct LobbyComms {
|
||||
comms: Comms,
|
||||
// TODO: move this to not use a receiver
|
||||
connect_recv: Receiver<(PlayerId, bool)>,
|
||||
}
|
||||
|
||||
|
|
@ -34,13 +35,17 @@ impl LobbyComms {
|
|||
pub async fn next_message(&mut self) -> Result<Message, GameError> {
|
||||
tokio::select! {
|
||||
r = self.comms.message() => {
|
||||
r
|
||||
match r {
|
||||
Ok(val) => Ok(val),
|
||||
Err(GameError::GenericError(err)) => Err(GameError::GenericError(format!("comms message: {err}"))),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
r = self.connect_recv.recv() => {
|
||||
match r {
|
||||
Ok((player_id, true)) => Ok(Message::Connect(player_id)),
|
||||
Ok((player_id, false)) => Ok(Message::Disconnect(player_id)),
|
||||
Err(err) => Err(GameError::GenericError(err.to_string())),
|
||||
Err(err) => Err(GameError::GenericError(format!("connect recv: {err}"))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
@use 'sass:color';
|
||||
|
||||
$wolves_color: rgba(255, 0, 0, 0.7);
|
||||
$village_color: rgba(0, 0, 255, 0.7);
|
||||
$connected_color: hsl(120, 68%, 50%);
|
||||
|
|
@ -94,6 +96,8 @@ nav.debug-nav {
|
|||
background-color: black;
|
||||
color: #cccccc;
|
||||
cursor: pointer;
|
||||
width: fit-content;
|
||||
text-align: center;
|
||||
|
||||
&:hover {
|
||||
background-color: white;
|
||||
|
|
@ -104,9 +108,6 @@ nav.debug-nav {
|
|||
|
||||
.player {
|
||||
margin: 0px;
|
||||
// padding-left: 5px;
|
||||
// padding-right: 5px;
|
||||
// padding-bottom: 5px;
|
||||
min-width: 10rem;
|
||||
max-width: 10vw;
|
||||
max-height: 4rem;
|
||||
|
|
@ -116,7 +117,6 @@ nav.debug-nav {
|
|||
font-family: 'Cute Font';
|
||||
|
||||
&.marked {
|
||||
// background-color: brighten($village_color, 100%);
|
||||
filter: hue-rotate(90deg);
|
||||
}
|
||||
|
||||
|
|
@ -219,18 +219,17 @@ button {
|
|||
background-color: #000;
|
||||
|
||||
&:disabled {
|
||||
filter: grayscale(80%);
|
||||
}
|
||||
|
||||
&:disabled:hover {
|
||||
filter: sepia(100%);
|
||||
background-color: rgba(128, 128, 128, 0.5);
|
||||
color: rgb(128, 128, 128);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&:disabled:hover::after {
|
||||
content: attr(reason);
|
||||
position: absolute;
|
||||
margin-top: 10px;
|
||||
top: 90%;
|
||||
// top: 90%;
|
||||
// left: 0;
|
||||
font: 'Cute Font';
|
||||
// color: #000;
|
||||
// background-color: #fff;
|
||||
|
|
@ -258,11 +257,21 @@ button {
|
|||
|
||||
}
|
||||
|
||||
.wolves-list {
|
||||
.wolves-intro {
|
||||
@extend .column-list;
|
||||
align-content: center;
|
||||
width: 100%;
|
||||
|
||||
.wolves-list {
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
justify-content: space-evenly;
|
||||
flex: 1 1 0;
|
||||
}
|
||||
|
||||
& button {
|
||||
align-self: center;
|
||||
}
|
||||
}
|
||||
|
||||
.character {
|
||||
|
|
@ -391,9 +400,12 @@ bool_role {
|
|||
}
|
||||
|
||||
.error-container {
|
||||
width: 70vw;
|
||||
margin-left: 10vw;
|
||||
margin-right: 10vw;
|
||||
position: fixed;
|
||||
top: 10vh;
|
||||
width: 100vw;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.error-container button {
|
||||
|
|
@ -412,14 +424,15 @@ bool_role {
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
width: 80%;
|
||||
margin: 30px;
|
||||
text-align: center;
|
||||
// gap: 20px;
|
||||
justify-content: center;
|
||||
gap: 30px;
|
||||
background-color: $error_color;
|
||||
filter: $error_filter;
|
||||
border: 1px solid color.change($error_color, $alpha: 1.0);
|
||||
backdrop-filter: grayscale(100%);
|
||||
|
||||
|
||||
padding-left: 5vw;
|
||||
|
|
@ -507,9 +520,17 @@ clients {
|
|||
}
|
||||
|
||||
.role-reveal-card {
|
||||
border: 3px solid rgba(0, 0, 0, 0.5);
|
||||
background-color: rgba(255, 0, 0, 0.7);
|
||||
min-width: 5cm;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid $wolves_color;
|
||||
background-color: color.change($wolves_color, $alpha: 0.1);
|
||||
min-width: 100px;
|
||||
color: white;
|
||||
|
||||
& p.number {
|
||||
font-size: 2rem;
|
||||
|
|
@ -519,12 +540,22 @@ clients {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
}
|
||||
&>button {
|
||||
border: 1px solid $wolves_color;
|
||||
$bg: color.change($wolves_color, $alpha: 0.2);
|
||||
background-color: $bg;
|
||||
|
||||
.role-reveal-card.ready {
|
||||
background-color: rgba(0, 255, 0, 0.7);
|
||||
}
|
||||
&:hover {
|
||||
background-color: white;
|
||||
color: color.change($wolves_color, $alpha: 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
&.ready {
|
||||
border: 1px solid $village_color;
|
||||
background-color: color.change($village_color, $alpha: 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.pronouns {
|
||||
font-size: 70%;
|
||||
|
|
@ -541,6 +572,8 @@ clients {
|
|||
font-size: 2rem;
|
||||
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
|
||||
&.margin-20 {
|
||||
margin-left: 20px;
|
||||
|
|
@ -562,6 +595,8 @@ clients {
|
|||
.column-list {
|
||||
list-style: none;
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
|
||||
font-family: 'Cute Font';
|
||||
|
||||
|
|
@ -607,6 +642,12 @@ clients {
|
|||
flex-direction: column;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
|
||||
& button {
|
||||
width: fit-content;
|
||||
text-align: center;
|
||||
align-self: center;
|
||||
}
|
||||
}
|
||||
|
||||
.small {
|
||||
|
|
@ -767,11 +808,6 @@ input {
|
|||
}
|
||||
}
|
||||
|
||||
.zoom {
|
||||
zoom: 200%;
|
||||
}
|
||||
|
||||
|
||||
.game-start-role {
|
||||
@extend .column-list;
|
||||
text-align: center;
|
||||
|
|
@ -826,3 +862,41 @@ input {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
.character-picker {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
color: white;
|
||||
$marked_bg: color.change($wolves_color, $alpha: 0.3);
|
||||
$marked_border: color.change($wolves_color, $alpha: 1.0);
|
||||
$village_bg: color.change($village_color, $alpha: 0.3);
|
||||
$village_border: color.change($village_color, $alpha: 1.0);
|
||||
|
||||
.character {
|
||||
padding: 0.5cm;
|
||||
|
||||
& * {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
&.marked {
|
||||
background-color: $marked_bg;
|
||||
border: 1px solid $marked_border;
|
||||
|
||||
&:hover {
|
||||
color: white;
|
||||
background-color: $marked_border;
|
||||
}
|
||||
}
|
||||
|
||||
background-color: $village_bg;
|
||||
border: 1px solid $village_border;
|
||||
|
||||
&:hover {
|
||||
color: white;
|
||||
background-color: $village_border;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -391,9 +391,8 @@ impl Component for Host {
|
|||
self.send.clone(),
|
||||
);
|
||||
html! {
|
||||
<>
|
||||
<h2>{format!("Day {}", day.get())}</h2>
|
||||
<DaytimePlayerList
|
||||
day={day}
|
||||
marked={marked_for_execution}
|
||||
big_screen={self.big_screen}
|
||||
characters={
|
||||
|
|
@ -402,7 +401,6 @@ impl Component for Host {
|
|||
on_execute={on_execute}
|
||||
on_mark={on_mark}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
}
|
||||
HostState::RoleReveal { ackd, waiting } => {
|
||||
|
|
@ -582,15 +580,16 @@ impl Component for Host {
|
|||
HostEvent::SetBigScreenState(state) => {
|
||||
self.big_screen = state;
|
||||
if self.big_screen
|
||||
&& let Ok(Some(root)) = gloo::utils::document().query_selector("app")
|
||||
&& let Err(err) = root.set_attribute("style", "zoom: 200%;")
|
||||
&& let Some(root) = gloo::utils::document().document_element()
|
||||
&& let Err(err) = root.set_attribute("style", "font-size: 3rem;")
|
||||
{
|
||||
log::error!("setting zoom: {err:?}");
|
||||
}
|
||||
|
||||
if state {
|
||||
let (discard_send, mut discard_recv) = futures::channel::mpsc::channel(10);
|
||||
self.send = discard_send;
|
||||
let (mut discard_send, mut discard_recv) = futures::channel::mpsc::channel(10);
|
||||
core::mem::swap(&mut discard_send, &mut self.send);
|
||||
Box::leak(Box::new(discard_send));
|
||||
yew::platform::spawn_local(async move {
|
||||
while discard_recv.next().await.is_some() {}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -290,26 +290,24 @@ impl Component for SingleTarget {
|
|||
.then(|| html!(<h2>{headline}</h2>));
|
||||
|
||||
let submit = target_selection.as_ref().map(|target_selection| {
|
||||
let disabled = self.selected.is_none();
|
||||
let disabled = self.selected.is_none().then_some("pick a target");
|
||||
let target_selection = target_selection.clone();
|
||||
let on_click = self
|
||||
.selected
|
||||
.clone()
|
||||
.map(|t| move |_| target_selection.emit(t.clone()));
|
||||
.map(|t| Callback::from(move |_| target_selection.emit(t.clone())))
|
||||
.unwrap_or_default();
|
||||
html! {
|
||||
<div class="button-container sp-ace">
|
||||
<button
|
||||
disabled={disabled}
|
||||
onclick={on_click}
|
||||
>
|
||||
<Button disabled_reason={disabled} on_click={on_click}>
|
||||
{"submit"}
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
});
|
||||
|
||||
html! {
|
||||
<div class="column-list">
|
||||
<div class="character-picker">
|
||||
{headline}
|
||||
{children.clone()}
|
||||
<div class="row-list">
|
||||
|
|
@ -344,81 +342,15 @@ pub struct TargetCardProps {
|
|||
|
||||
#[function_component]
|
||||
fn TargetCard(props: &TargetCardProps) -> Html {
|
||||
let submenu = {
|
||||
let button_text = if props.selected { "unpick" } else { "pick" };
|
||||
let character_id = props.target.character_id.clone();
|
||||
let on_select = props.on_select.clone();
|
||||
let on_click = Callback::from(move |_| on_select.emit(character_id.clone()));
|
||||
html! {
|
||||
<nav class="submenu">
|
||||
<Button on_click={on_click}>{button_text}</Button>
|
||||
</nav>
|
||||
}
|
||||
};
|
||||
|
||||
let marked = props.selected.then_some("marked");
|
||||
let ident: PublicIdentity = props.target.clone().into();
|
||||
html! {
|
||||
<div class={"row-list baseline margin-5"}>
|
||||
<div class={classes!("player", "ident", "column-list", marked)}>
|
||||
<Identity ident={Into::<PublicIdentity>::into(&props.target)} />
|
||||
{submenu}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Properties)]
|
||||
pub struct CustomTargetCardProps {
|
||||
pub target: CharacterIdentity,
|
||||
pub options: Arc<[String]>,
|
||||
pub on_select: Option<Callback<(CharacterId, String)>>,
|
||||
#[prop_or_default]
|
||||
pub class: String,
|
||||
#[prop_or(true)]
|
||||
pub hide_submenu: bool,
|
||||
}
|
||||
|
||||
#[function_component]
|
||||
pub fn CustomTargetCard(
|
||||
CustomTargetCardProps {
|
||||
target,
|
||||
options,
|
||||
on_select,
|
||||
class,
|
||||
hide_submenu,
|
||||
}: &CustomTargetCardProps,
|
||||
) -> Html {
|
||||
let submenu = options.is_empty().not().then(|| {
|
||||
let buttons = options
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|option| {
|
||||
let on_select = on_select.clone();
|
||||
let button_text = option.clone();
|
||||
let character_id = target.character_id.clone();
|
||||
let on_click = on_select
|
||||
.map(|on_select| {
|
||||
Callback::from(move |_| {
|
||||
on_select.emit((character_id.clone(), option.clone()))
|
||||
})
|
||||
})
|
||||
.unwrap_or_default();
|
||||
html! {
|
||||
<Button on_click={on_click}>{button_text}</Button>
|
||||
}
|
||||
})
|
||||
.collect::<Html>();
|
||||
html! {
|
||||
<nav class={classes!("submenu", hide_submenu.not().then_some("shown"))}>
|
||||
{buttons}
|
||||
</nav>
|
||||
}
|
||||
});
|
||||
html! {
|
||||
<div class={"row-list baseline"}>
|
||||
<div class={classes!("ident", "column-list", class)}>
|
||||
<Identity ident={Into::<PublicIdentity>::into(target)} />
|
||||
{submenu}
|
||||
</div>
|
||||
</div>
|
||||
<Button on_click={on_click} classes={classes!(marked, "character")}>
|
||||
<Identity ident={ident}/>
|
||||
</Button>
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ pub fn WolvesIntro(props: &WolvesIntroProps) -> Html {
|
|||
let on_complete = props.on_complete.clone();
|
||||
let on_complete = Callback::from(move |_| on_complete.emit(()));
|
||||
html! {
|
||||
<div class="column-list">
|
||||
<div class="wolves-intro">
|
||||
<h2>{"these are the wolves:"}</h2>
|
||||
<div class="row-list wolves-list">
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ pub struct ButtonProperties {
|
|||
pub disabled_reason: Option<String>,
|
||||
#[prop_or_default]
|
||||
pub children: Html,
|
||||
#[prop_or_default]
|
||||
pub classes: yew::Classes,
|
||||
}
|
||||
|
||||
#[function_component]
|
||||
|
|
@ -15,7 +17,7 @@ pub fn Button(props: &ButtonProperties) -> Html {
|
|||
let on_click = Callback::from(move |_| on_click.emit(()));
|
||||
html! {
|
||||
<button
|
||||
class="default-button"
|
||||
class={classes!("default-button", props.classes.clone())}
|
||||
disabled={props.disabled_reason.is_some()}
|
||||
reason={props.disabled_reason.clone()}
|
||||
onclick={on_click}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use core::ops::Not;
|
||||
use core::{num::NonZeroU8, ops::Not};
|
||||
|
||||
use werewolves_proto::{
|
||||
message::{CharacterState, PublicIdentity},
|
||||
|
|
@ -6,10 +6,11 @@ use werewolves_proto::{
|
|||
};
|
||||
use yew::prelude::*;
|
||||
|
||||
use crate::components::{Button, Identity};
|
||||
use crate::components::{Button, ClickableField, Identity};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Properties)]
|
||||
pub struct DaytimePlayerListProps {
|
||||
pub day: NonZeroU8,
|
||||
pub characters: Box<[CharacterState]>,
|
||||
pub marked: Box<[CharacterId]>,
|
||||
pub on_execute: Callback<()>,
|
||||
|
|
@ -20,6 +21,7 @@ pub struct DaytimePlayerListProps {
|
|||
#[function_component]
|
||||
pub fn DaytimePlayerList(
|
||||
DaytimePlayerListProps {
|
||||
day,
|
||||
characters,
|
||||
on_execute,
|
||||
on_mark,
|
||||
|
|
@ -42,22 +44,22 @@ pub fn DaytimePlayerList(
|
|||
}
|
||||
})
|
||||
.collect::<Html>();
|
||||
let button_text = if marked.is_empty() {
|
||||
"end day"
|
||||
} else {
|
||||
"execute"
|
||||
};
|
||||
let button = big_screen.not().then(|| {
|
||||
html! {
|
||||
<Button
|
||||
on_click={on_execute}
|
||||
disabled_reason={
|
||||
marked.is_empty()
|
||||
.then_some(String::from("no one is on the block"))
|
||||
}
|
||||
>
|
||||
{"execute"}
|
||||
<Button on_click={on_execute}>
|
||||
{button_text}
|
||||
</Button>
|
||||
}
|
||||
});
|
||||
html! {
|
||||
<div class="column-list">
|
||||
<div class="row-list small baseline player-list gap">
|
||||
<div class="character-picker">
|
||||
<h2>{"day "}{day.to_string()}</h2>
|
||||
<div class="player-list">
|
||||
{chars}
|
||||
</div>
|
||||
{button}
|
||||
|
|
@ -87,26 +89,16 @@ pub fn DaytimePlayer(
|
|||
}: &DaytimePlayerProps,
|
||||
) -> Html {
|
||||
let dead = died_to.is_some().then_some("dead");
|
||||
let button_text = if *on_the_block { "unmark" } else { "mark" };
|
||||
let on_the_block = on_the_block.then_some("marked");
|
||||
let submenu = died_to.is_none().then_some(()).and_then(|_| {
|
||||
on_select.as_ref().map(|on_select| {
|
||||
let marked = on_the_block.then_some("marked");
|
||||
let character_id = identity.character_id.clone();
|
||||
let on_select = on_select.clone();
|
||||
let on_click = Callback::from(move |_| on_select.emit(character_id.clone()));
|
||||
html! {
|
||||
<nav class="submenu">
|
||||
<Button on_click={on_click}>{button_text}</Button>
|
||||
</nav>
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
let on_click: Callback<_> = on_select
|
||||
.clone()
|
||||
.map(|on_select| Callback::from(move |_| on_select.emit(character_id.clone())))
|
||||
.unwrap_or_default();
|
||||
let identity: PublicIdentity = identity.into();
|
||||
html! {
|
||||
<div class={classes!("player", dead, on_the_block, "column-list", "ident")}>
|
||||
<Button on_click={on_click} classes={classes!(marked, dead, "character")}>
|
||||
<Identity ident={identity}/>
|
||||
{submenu}
|
||||
</div>
|
||||
</Button>
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@ pub fn LobbyPlayer(LobbyPlayerProps { player, on_action }: &LobbyPlayerProps) ->
|
|||
});
|
||||
|
||||
html! {
|
||||
// <div class={classes!("player", class, "column-list")}>
|
||||
<ClickableField
|
||||
state={open}
|
||||
options={submenu}
|
||||
|
|
@ -76,7 +75,5 @@ pub fn LobbyPlayer(LobbyPlayerProps { player, on_action }: &LobbyPlayerProps) ->
|
|||
>
|
||||
<Identity ident={player.identification.public.clone()}/>
|
||||
</ClickableField>
|
||||
// {submenu}
|
||||
// </div>
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use std::sync::Arc;
|
||||
use core::ops::Not;
|
||||
|
||||
use werewolves_proto::message::CharacterIdentity;
|
||||
use werewolves_proto::message::{CharacterIdentity, PublicIdentity};
|
||||
use yew::prelude::*;
|
||||
|
||||
use crate::components::{Button, action::CustomTargetCard};
|
||||
use crate::components::{Button, Identity};
|
||||
|
||||
#[derive(Debug, PartialEq, Properties)]
|
||||
pub struct RoleRevealProps {
|
||||
|
|
@ -65,12 +65,10 @@ impl Component for RoleReveal {
|
|||
}
|
||||
});
|
||||
html! {
|
||||
<div class="column-list gap">
|
||||
<div class="role-reveal-cards">
|
||||
{force_all}
|
||||
<div class={"role-reveal-cards"}>
|
||||
{cards}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -87,25 +85,20 @@ pub fn RoleRevealCard(props: &RoleRevealCardProps) -> Html {
|
|||
let class = props.is_ready.then_some("ready");
|
||||
let target = props.target.clone();
|
||||
let on_force_ready = props.on_force_ready.clone();
|
||||
let on_click = on_force_ready.map(|on_force_ready| {
|
||||
Callback::from(move |_| {
|
||||
let on_click = props.is_ready.not().then_some(()).and_then(|_| {
|
||||
on_force_ready.map(|on_force_ready| {
|
||||
let on_click = Callback::from(move |_| {
|
||||
on_force_ready.emit(target.clone());
|
||||
});
|
||||
html! {<Button on_click={on_click}>{"ready"}</Button>}
|
||||
})
|
||||
});
|
||||
let options: Arc<[String]> = if props.is_ready || props.on_force_ready.is_none() {
|
||||
Arc::new([])
|
||||
} else {
|
||||
Arc::new([String::from("ready")])
|
||||
};
|
||||
|
||||
let ident: PublicIdentity = props.target.clone().into();
|
||||
html! {
|
||||
<div class={classes!(class, "role-reveal-card")}>
|
||||
<CustomTargetCard
|
||||
target={props.target.clone()}
|
||||
options={options}
|
||||
class={if props.is_ready { String::from("ready") } else { String::new() }}
|
||||
on_select={on_click}
|
||||
hide_submenu=false
|
||||
/>
|
||||
<Identity ident={ident}/>
|
||||
{on_click}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ mod pages {
|
|||
}
|
||||
mod callback;
|
||||
|
||||
use core::num::NonZeroU8;
|
||||
|
||||
use pages::{ErrorComponent, WerewolfError};
|
||||
use web_sys::Url;
|
||||
use werewolves_proto::{
|
||||
|
|
@ -53,19 +55,14 @@ fn main() {
|
|||
}
|
||||
} else if path.starts_with("/many-client") {
|
||||
let clients = document.query_selector("clients").unwrap().unwrap();
|
||||
for (player_id, name, dupe) in [(
|
||||
PlayerId::from_u128(1),
|
||||
"player 1".to_string(),
|
||||
document.query_selector("app").unwrap().unwrap(),
|
||||
)]
|
||||
.into_iter()
|
||||
.chain((1..=2).map(|num| {
|
||||
for (player_id, name, num, dupe) in (1..=16).map(|num| {
|
||||
(
|
||||
PlayerId::from_u128(num as u128),
|
||||
format!("player {num}"),
|
||||
NonZeroU8::new(num).unwrap(),
|
||||
document.create_element("autoclient").unwrap(),
|
||||
)
|
||||
})) {
|
||||
}) {
|
||||
if dupe.tag_name() == "AUTOCLIENT" {
|
||||
clients.append_child(&dupe).unwrap();
|
||||
}
|
||||
|
|
@ -80,7 +77,7 @@ fn main() {
|
|||
public: PublicIdentity {
|
||||
name: name.to_string(),
|
||||
pronouns: Some(String::from("he/him")),
|
||||
number: None,
|
||||
number: Some(num),
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue