More macros?

This commit is contained in:
Daan Vanoverloop 2022-09-06 13:06:51 +02:00
parent 53cb2a22b1
commit d5fc504821
Signed by: Danacus
GPG Key ID: F2272B50E129FC5C
4 changed files with 71 additions and 106 deletions

1
Cargo.lock generated
View File

@ -1111,6 +1111,7 @@ dependencies = [
"anyhow", "anyhow",
"js-sys", "js-sys",
"lan_party_core", "lan_party_core",
"paste",
"serde", "serde",
"serde_json", "serde_json",
"thiserror", "thiserror",

View File

@ -18,3 +18,4 @@ thiserror = "1"
yew-hooks = "0.1" yew-hooks = "0.1"
anyhow = "1.0" anyhow = "1.0"
js-sys = "0.3" js-sys = "0.3"
paste = "1"

6
web/dist/index.html vendored
View File

@ -4,9 +4,9 @@
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css" rel="stylesheet">
<title>Yew App</title> <title>Yew App</title>
<link rel="preload" href="/index-eca47f078afaab22_bg.wasm" as="fetch" type="application/wasm" crossorigin=""> <link rel="preload" href="/index-f3d26bdebe032292_bg.wasm" as="fetch" type="application/wasm" crossorigin="">
<link rel="modulepreload" href="/index-eca47f078afaab22.js"></head> <link rel="modulepreload" href="/index-f3d26bdebe032292.js"></head>
<body class="base theme-dark bg-gray-900 text-gray-400"> <body class="base theme-dark bg-gray-900 text-gray-400">
<script type="module">import init from '/index-eca47f078afaab22.js';init('/index-eca47f078afaab22_bg.wasm');</script></body></html> <script type="module">import init from '/index-f3d26bdebe032292.js';init('/index-f3d26bdebe032292_bg.wasm');</script></body></html>

View File

@ -7,6 +7,7 @@ use lan_party_core::event::{
test::{Test, TestSpec}, test::{Test, TestSpec},
*, *,
}; };
use paste::paste;
use wasm_bindgen::JsValue; use wasm_bindgen::JsValue;
use yew::prelude::*; use yew::prelude::*;
@ -225,6 +226,61 @@ view_struct!(TeamGame as self =>
} }
); );
macro_rules! edit_fields {
($(($name:expr, $prop:expr)),* $(,)?) => {
html! {
<>
$(
<p>
{ $name }
{ $prop.edit() }
</p>
)*
</>
}
};
}
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! {
<Block title={stringify!($struct)}>
{ edit_fields!(("Name: ", name), ("Description: ", description)) }
</Block>
}
}
impl Editable for $struct {
type Edit = [<$struct Edit>];
}
}
};
}
#[derive(PartialEq, Properties)] #[derive(PartialEq, Properties)]
pub struct EditProps<T: PartialEq> { pub struct EditProps<T: PartialEq> {
pub state: UseStateHandle<T>, pub state: UseStateHandle<T>,
@ -234,43 +290,20 @@ pub trait Edit {
fn edit(&self) -> Html; fn edit(&self) -> Html;
} }
#[function_component(EventSpecEdit)] impl<Comp: Component<Properties = EditProps<Type>>, Type: Editable<Edit = Comp> + PartialEq> Edit
pub fn event_spec_edit(props: &EditProps<EventSpec>) -> Html { for UseStateHandle<Type>
let state = props.state.clone(); {
let name = use_state(|| state.name.clone());
let description = use_state(|| state.description.clone());
use_effect_with_deps(
clone!(name, description, state =>
move |_| {
web_sys::console::log_1(&JsValue::from("Update EventSpec"));
state.set(EventSpec {
name: (*name).clone(),
description: (*description).clone(),
..Default::default()
});
|| { drop(state); drop(name); drop(description) }
}
),
(name.clone(), description.clone()),
);
html! {
<>
{ "Name: " }
{ name.edit() }
{ "Description: " }
{ description.edit() }
</>
}
}
impl Edit for UseStateHandle<EventSpec> {
fn edit(&self) -> Html { fn edit(&self) -> Html {
html!(<EventSpecEdit state={self.clone()} />) html!(<Comp state={self.clone()} />)
} }
} }
pub trait Editable {
type Edit;
}
edit_struct!(EventSpec => ("Name: ", name), ("Description: ", description));
#[function_component(StringEdit)] #[function_component(StringEdit)]
pub fn string_edit(props: &EditProps<String>) -> Html { pub fn string_edit(props: &EditProps<String>) -> Html {
let string = props.state.clone(); let string = props.state.clone();
@ -288,73 +321,3 @@ impl Edit for UseStateHandle<String> {
html!(<StringEdit state={self.clone()} />) html!(<StringEdit state={self.clone()} />)
} }
} }
/*
pub trait Edit {
type Type;
fn to_edit(t: Self::Type) -> Self;
fn edit(&self) -> Html;
fn build(&self) -> Self::Type;
}
pub struct EventSpecEditHandle {
name: UseStateHandle<String>,
description: UseStateHandle<String>,
}
impl Edit for UseStateHandle<String> {
type Type = String;
fn to_edit(t: Self::Type) -> Self {
use_state(|| t)
}
fn edit(&self) -> Html {
let this = self.clone();
html! {
<TextInput
class={"mx-2 appearance-none block bg-gray-700 text-slate-400 border border-gray-600 rounded py-2 px-2 w-20 leading-tight focus:outline-none focus:ring-1 focus:ring-gray-500 focus:border-gray-500"}
bind={bind!(this)}
/>
}
}
fn build(&self) -> Self::Type {
(*self.clone()).clone()
}
}
impl Edit for EventSpecEditHandle {
type Type = EventSpec;
fn to_edit(t: Self::Type) -> Self {
Self {
name: use_state(|| t.name),
description: use_state(|| t.description),
}
}
fn edit(&self) -> Html {
html! {
<>
{ "Name: " }
{ self.name.edit() }
{ "Description: " }
{ self.description.edit() }
</>
}
}
fn build(&self) -> Self::Type {
let test_spec = TestSpec { num_players: 0 };
Self::Type {
name: self.name.build(),
description: self.description.build(),
event_type: EventTypeSpec::Test(test_spec),
}
}
}
*/