use crate::components::Block; use lan_party_core::event::EventSpec; use sycamore::prelude::*; macro_rules! edit_fields { ($cx:ident, $(($name:expr, $prop:expr)),* $(,)?) => { view! { $cx, $( p { ($name) ": " ($prop.edit($cx)) } )* } }; } macro_rules! link_fields { ($cx:ident, $($field:ident),* $(,)? => $state:ident as $t:ident) => { $(let $field = create_signal($cx, $state.get().$field.clone());)* create_effect($cx, || { $state.set(Self { $($field: $field.get().as_ref().clone(),)* ..Default::default() }); }); }; } macro_rules! edit_struct { ($struct:ident => $(($name:expr, $prop:ident)),* $(,)?) => { impl<'a, G: Html> Edit<'a, G> for $struct { fn edit(cx: Scope<'a>, props: EditProps<'a, Self>) -> View { let state = props.state; link_fields!(cx, $($prop,)* => state as Self); view! { cx, Block(title=stringify!($struct).into()) { (edit_fields!(cx, $(($name, $prop),)*)) } } } } }; } #[derive(Prop)] pub struct EditProps<'a, T> { pub state: &'a Signal, } impl<'a, T> From<&'a Signal> for EditProps<'a, T> { fn from(state: &'a Signal) -> Self { EditProps { state } } } pub trait IntoEdit<'a, G: Html> { fn edit(self, cx: Scope<'a>) -> View; } impl<'a, G: Html, T: Edit<'a, G>> IntoEdit<'a, G> for &'a Signal where EditProps<'a, T>: From<&'a Signal>, { fn edit(self, cx: Scope<'a>) -> View { T::edit(cx, self.into()) } } pub trait Edit<'a, G: Html>: Sized { fn edit(cx: Scope<'a>, props: EditProps<'a, Self>) -> View; } edit_struct!(EventSpec => ("Name", name)); /* impl<'a, G: Html> Edit<'a, G> for EventSpec { fn edit(cx: Scope<'a>, props: EditProps<'a, Self>) -> View { let state = props.state; link_fields!(cx, name => state as Self); edit_fields!(cx, ("Name", name)) } } */ impl<'a, G: Html> Edit<'a, G> for String { fn edit(cx: Scope<'a>, props: EditProps<'a, Self>) -> View { view! { cx, input(bind:value=props.state) } } }