diff --git a/web/dist/index.html b/web/dist/index.html index 42c435a..2e94d33 100644 --- a/web/dist/index.html +++ b/web/dist/index.html @@ -6,7 +6,7 @@ LAN Party - - + + - \ No newline at end of file + \ No newline at end of file diff --git a/web/src/components/event.rs b/web/src/components/event.rs index ee5c52f..d890cfb 100644 --- a/web/src/components/event.rs +++ b/web/src/components/event.rs @@ -1,4 +1,9 @@ -use std::{marker::PhantomData, str::FromStr}; +use std::{ + collections::{HashMap, HashSet}, + hash::Hash, + marker::PhantomData, + str::FromStr, +}; use crate::components::Block; use lan_party_core::event::{ @@ -7,7 +12,9 @@ use lan_party_core::event::{ }; use log::debug; use paste::paste; -use sycamore::prelude::*; +use sycamore::{builder::prelude::*, prelude::*}; + +use super::{BlockProps, Button, ButtonProps}; macro_rules! editable { ($type:ty => $editor:ty) => { @@ -174,8 +181,8 @@ edit_enum!(EventTypeSpec => selected => ); edit_struct!(TestSpec => ("Number of players", num_players)); -edit_struct!(TeamGameSpec => ("Win rewards", win_rewards)); -edit_struct!(FreeForAllGameSpec => ); +edit_struct!(TeamGameSpec => ("Teams", teams), ("Win rewards", win_rewards), ("Lose rewards", lose_rewards)); +edit_struct!(FreeForAllGameSpec => ("Participants", participants), ("Win rewards", win_rewards), ("Lose rewards", lose_rewards)); pub struct StringEdit; @@ -251,7 +258,7 @@ pub struct VecEdit; impl<'a, G, T, I> Editor<'a, G, I> for VecEdit where G: Html, - T: Editable<'a, G> + Clone + PartialEq + 'a, + T: Editable<'a, G> + Clone + PartialEq + Default + 'a, I: IntoIterator + FromIterator + Clone, { fn edit(cx: Scope<'a>, props: EditProps<'a, I>) -> View { @@ -266,9 +273,6 @@ where .map(|x| create_signal(cx, x)) .collect::>(), ); - //let signal = create_signal(cx, 0); - //let vec2 = vec.get().as_ref().clone(); - //let signal = create_ref(cx, vec.get(0).unwrap()); create_effect(cx, || { props.state.set( @@ -281,30 +285,107 @@ where ) }); - /* - view! { cx, - Indexed( - iterable=vec, - view=|cx: BoundedScope<'_, 'a>, x| { - let signal = create_ref(cx, x); - view! { cx, - (T::edit(cx, x.into())) - } - }, - ) - } - */ + let onadd = move |_| vec.modify().push(create_signal(cx, T::default())); + + Block( + cx, + BlockProps { + title: "List".into(), + children: Children::new(cx, move |_| { + div() + .dyn_c(move || { + View::new_fragment( + vec.get() + .as_ref() + .clone() + .into_iter() + .map(|x| div().c(x.edit(cx)).c(br()).view(cx)) + .collect(), + ) + }) + .c(Button( + cx, + ButtonProps { + onclick: onadd, + text: "Add new".into(), + icon: "mdi-plus".into(), + }, + )) + .view(cx) + }), + }, + ) } } impl<'a, G, T> Editable<'a, G> for Vec where G: Html, - T: Editable<'a, G> + Clone + PartialEq + 'a, + T: Editable<'a, G> + Clone + PartialEq + Default + 'a, { type Editor = VecEdit; } +impl<'a, G, T> Editable<'a, G> for HashSet +where + G: Html, + T: Editable<'a, G> + Clone + PartialEq + Default + Hash + Eq + 'a, +{ + type Editor = VecEdit; +} + +impl<'a, G, K, V> Editable<'a, G> for HashMap +where + G: Html, + K: Clone + Hash + Eq, + V: Clone, + (K, V): Editable<'a, G> + Clone + PartialEq + Default + Hash + Eq + 'a, +{ + type Editor = VecEdit; +} + +pub struct TupleEdit; + +impl<'a, 'b, G: Html, A: Editable<'a, G> + Clone, B: Editable<'a, G> + Clone> Editor<'a, G, (A, B)> + for TupleEdit +{ + fn edit(cx: Scope<'a>, props: EditProps<'a, (A, B)>) -> View { + let state = props.state; + let (a, b) = state.get_untracked().as_ref().clone(); + + let a = create_signal(cx, a.clone()); + let b = create_signal(cx, b.clone()); + + create_effect(cx, || { + props + .state + .set((a.get().as_ref().clone(), b.get().as_ref().clone())) + }); + + Block( + cx, + BlockProps { + title: "Tuple".into(), + children: Children::new(cx, move |_| { + div() + .dyn_c(move || a.edit(cx)) + .dyn_c(move || b.edit(cx)) + .view(cx) + }), + }, + ) + } +} + +impl<'a, G, A, B> Editable<'a, G> for (A, B) +where + G: Html, + A: Editable<'a, G> + Clone, + B: Editable<'a, G> + Clone, +{ + type Editor = TupleEdit; +} + #[derive(Default, Clone, Debug)] pub struct Test { inner: TestInner, diff --git a/web/src/components/mod.rs b/web/src/components/mod.rs index 559a396..a0d672f 100644 --- a/web/src/components/mod.rs +++ b/web/src/components/mod.rs @@ -6,7 +6,7 @@ use web_sys::Event; use yew::use_effect; #[derive(Prop)] -pub struct Props { +pub struct ButtonProps { pub onclick: F, #[builder(default)] pub text: String, @@ -15,7 +15,7 @@ pub struct Props { } #[component] -pub fn Button<'a, G: Html, F: 'a + FnMut(Event)>(cx: Scope<'a>, props: Props) -> View { +pub fn Button<'a, G: Html, F: 'a + FnMut(Event)>(cx: Scope<'a>, props: ButtonProps) -> View { let mut icon_class = String::from("mdi "); if !props.icon.is_empty() {