use crate::components::*; use std::collections::{HashMap, HashSet}; use lan_party_core::event::{ free_for_all_game::FreeForAllGame, team_game::TeamGame, test::{Test, TestSpec}, *, }; use paste::paste; use wasm_bindgen::JsValue; use yew::prelude::*; use crate::{bind, bind_change, bind_value, clone, clone_cb}; macro_rules! view_fields { ($(($name:expr, $prop:expr)),* $(,)?) => { html! { <> $(

{ $name } { $prop.view() }

)* } }; } macro_rules! view_struct { ($struct:path: $title:expr => $(($name:expr, $prop:ident)),* $(,)?) => { impl View for $struct { fn view(&self) -> Html { html! { { view_fields!( $(($name, self.$prop),)* )} } } } }; ($struct:path as $self:ident => $body:expr) => { impl View for $struct { fn view(&$self) -> Html { $body } } }; } macro_rules! view_enum_simple { ($enum:path: $($variant:ident),* $(,)?) => { impl View for $enum { fn view(&self) -> Html { html! { {match self { $( Self::$variant(i) => html! { <> { i.view() } }, )* }} } } } }; } #[derive(Debug, Clone, Properties, PartialEq)] pub struct BlockProps { title: String, children: Children, } #[function_component(Block)] pub fn block(props: &BlockProps) -> Html { let open = use_state(|| false); let mut class = classes!("overflow-hidden"); if !*open { class.push("max-h-1"); } html! { <>

move |_| open.set(!*open))}>{ &props.title }


{for props.children.iter()}
} } pub trait View { fn view(&self) -> Html; } impl View for bool { fn view(&self) -> Html { html! { } } } macro_rules! view_html { ($t:ty) => { impl View for $t { fn view(&self) -> Html { html! { self } } } }; } view_html!(i64); view_html!(i32); view_html!(isize); view_html!(u64); view_html!(u32); view_html!(usize); view_html!(f64); view_html!(f32); view_html!(String); view_html!(&'static str); macro_rules! view_iter { ($t:ident => $type:ty) => { impl<$t: View> View for $type { fn view(&self) -> Html { html! { } } } }; } view_iter!(T => Vec); view_iter!(T => HashSet); view_iter!(T => &[T]); impl View for Option { fn view(&self) -> Html { match self { Some(content) => content.view(), None => html! { "None" }, } } } impl View for HashMap { fn view(&self) -> Html { html! { {self.iter().map(|(k, v)| { html! {

{k.view()}{ ": " }{v.view()}

} }).collect::()}
} } } view_struct!( lan_party_core::event::Event: "Event" => ("Name: ", name), ("Description: ", description), ("Concluded: ", concluded), ("Event type: ", event_type), ); view_enum_simple!( lan_party_core::event::EventType: Test, TeamGame, FreeForAllGame ); view_struct!( lan_party_core::event::test::Test: "Test" => ("Number of players: ", num_players) ); view_struct!(FreeForAllGame as self => html! { { view_fields!(("Ranking: ", self.ranking)) } { view_fields!( ("Participants: ", self.spec.participants), ("Win rewards: ", self.spec.win_rewards), ("Lose rewards: ", self.spec.lose_rewards), ) } } ); view_enum_simple!( lan_party_core::event::free_for_all_game::FreeForAllGameRanking: Ranking, Scores ); view_struct!(TeamGame as self => html! { { view_fields!(("Teams: ", self.teams)) } { view_fields!(("Ranking: ", self.ffa_game.ranking)) } { view_fields!( ("Participants: ", self.ffa_game.spec.participants), ("Win rewards: ", self.ffa_game.spec.win_rewards), ("Lose rewards: ", self.ffa_game.spec.lose_rewards), ) } } ); macro_rules! edit_fields { ($(($name:expr, $prop:expr)),* $(,)?) => { html! { <> $(

{ $name } { $prop.edit() }

)* } }; } macro_rules! link_fields { ($($field:ident),* $(,)? => $state:ident as $t:ident) => { $(let $field = use_state(|| $state.$field.clone());)* use_effect_with_deps( clone!($($field,)* $state => move |_| { $state.set($t { $($field: (*$field).clone(),)* ..Default::default() }); || { $(drop($field);)* drop($state); } } ), ($($field.clone(),)*), ); }; } macro_rules! edit_struct { ($struct:ident => $(($name:expr, $prop:ident)),* $(,)?) => { paste! { #[function_component([<$struct Edit>])] pub fn event_spec_edit(props: &EditProps<$struct>) -> Html { let state = props.state.clone(); link_fields!(name, description => state as $struct); html! { { edit_fields!(("Name: ", name), ("Description: ", description)) } } } impl Editable for $struct { type Edit = [<$struct Edit>]; } } }; } #[derive(PartialEq, Properties)] pub struct EditProps { pub state: UseStateHandle, } pub trait Edit { fn edit(&self) -> Html; } impl>, Type: Editable + PartialEq> Edit for UseStateHandle { fn edit(&self) -> Html { html!() } } pub trait Editable { type Edit; } edit_struct!(EventSpec => ("Name: ", name), ("Description: ", description)); #[function_component(StringEdit)] pub fn string_edit(props: &EditProps) -> Html { let string = props.state.clone(); html! { } } impl Edit for UseStateHandle { fn edit(&self) -> Html { html!() } }