lan-party-backend/web/src/components/event.rs

93 lines
2.3 KiB
Rust

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<G> {
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<T>,
}
impl<'a, T> From<&'a Signal<T>> for EditProps<'a, T> {
fn from(state: &'a Signal<T>) -> Self {
EditProps { state }
}
}
pub trait IntoEdit<'a, G: Html> {
fn edit(self, cx: Scope<'a>) -> View<G>;
}
impl<'a, G: Html, T: Edit<'a, G>> IntoEdit<'a, G> for &'a Signal<T>
where
EditProps<'a, T>: From<&'a Signal<T>>,
{
fn edit(self, cx: Scope<'a>) -> View<G> {
T::edit(cx, self.into())
}
}
pub trait Edit<'a, G: Html>: Sized {
fn edit(cx: Scope<'a>, props: EditProps<'a, Self>) -> View<G>;
}
edit_struct!(EventSpec => ("Name", name));
/*
impl<'a, G: Html> Edit<'a, G> for EventSpec {
fn edit(cx: Scope<'a>, props: EditProps<'a, Self>) -> View<G> {
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<G> {
view! { cx,
input(bind:value=props.state)
}
}
}