140 lines
4.2 KiB
Plaintext
140 lines
4.2 KiB
Plaintext
use lan_party_core::user::User;
|
|
use log::debug;
|
|
use sycamore::{futures::spawn_local_scoped, prelude::*};
|
|
use web_sys::Event;
|
|
|
|
use crate::util::api_request;
|
|
|
|
#[component]
|
|
pub fn UsersPage<'a, G: Html>(cx: Scope<'a>) -> View<G> {
|
|
let users = create_signal(cx, Vec::<User>::new());
|
|
|
|
spawn_local_scoped(cx, async move {
|
|
users.set(
|
|
api_request::<_, Vec<User>>(reqwasm::http::Method::GET, "/user", Option::<()>::None)
|
|
.await
|
|
.map(|inner| inner.unwrap())
|
|
.unwrap(),
|
|
);
|
|
});
|
|
|
|
let handle_click = move |event: Event| {
|
|
debug!("{:#?}", event);
|
|
};
|
|
|
|
view! { cx,
|
|
Page {
|
|
ul {
|
|
Keyed(
|
|
iterable=users,
|
|
view=|cx, user| view! { cx,
|
|
li { (user.name) }
|
|
},
|
|
key=|user| user.name.clone(),
|
|
)
|
|
}
|
|
|
|
Button(onclick=handle_click,text="Click me".to_string())
|
|
}
|
|
}
|
|
}
|
|
|
|
// Temp
|
|
|
|
#[derive(Prop)]
|
|
pub struct PageProps<'a, G: Html> {
|
|
pub children: Children<'a, G>,
|
|
}
|
|
|
|
#[component]
|
|
pub fn Page<'a, G: Html>(cx: Scope<'a>, props: PageProps<'a, G>) -> View<G> {
|
|
let children = props.children.call(cx);
|
|
|
|
view! { cx,
|
|
div(class="max-w-7xl mx-auto") { (children) }
|
|
}
|
|
}
|
|
|
|
#[derive(Prop)]
|
|
pub struct Props<F: FnMut(Event)> {
|
|
pub onclick: F,
|
|
#[builder(default)]
|
|
pub text: String,
|
|
#[builder(default)]
|
|
pub icon: String,
|
|
}
|
|
|
|
#[component]
|
|
pub fn Button<'a, G: Html, F: 'a + FnMut(Event)>(cx: Scope<'a>, props: Props<F>) -> View<G> {
|
|
let mut icon_class = String::from("mdi text-lg ");
|
|
|
|
if !props.icon.is_empty() {
|
|
icon_class.push_str(&props.icon);
|
|
}
|
|
|
|
view! { cx,
|
|
button(class="bg-gray-700 hover:bg-gray-800 text-gray-400 font-bold py-2 px-2 rounded inline-flex items-center",on:click=props.onclick) {
|
|
span(class=icon_class)
|
|
span { (props.text) }
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Prop)]
|
|
pub struct TableProps<'a, G: Html> {
|
|
pub headers: Vec<String>,
|
|
pub rows: Vec<Vec<String>>,
|
|
pub loading: bool,
|
|
|
|
#[builder(default)]
|
|
pub children: Children<'a, G>,
|
|
}
|
|
|
|
#[component]
|
|
pub fn table<'a, G: Html>(props: TableProps<'a, G>) -> View<G> {
|
|
let children = props.children.call(cx);
|
|
|
|
view! { cx,
|
|
div(class="inline-block min-w-full py-2 align-middle") {
|
|
div(class="overflow-hidden shadow ring-1 ring-black ring-opacity-5 md:rounded-lg") {
|
|
table(class="min-w-full divide-y divide-gray-600") {
|
|
thead(class="bg-gray-800") {
|
|
tr {
|
|
(props.headers.iter().map(|header| view! { cx,
|
|
th(
|
|
scope="col",
|
|
class="px-3 py-3.5 text-left
|
|
text-sm font-semibold text-gray-400"
|
|
) {
|
|
(header)
|
|
}
|
|
}).collect())
|
|
}
|
|
}
|
|
tbody(class="divide-y divide-gray-600 bg-gray-700") {
|
|
(props.rows.iter().map(|row| view! { cx,
|
|
tr {
|
|
{row.iter().map(|value| html! {
|
|
td(class="whitespace-nowrap px-3 py-4 text-sm text-gray-400"){
|
|
(value)
|
|
}
|
|
}).collect()}
|
|
}
|
|
}).collect())
|
|
(children)
|
|
(if props.loading == true { view! {
|
|
tr {
|
|
td(colspan={(props.headers.len() + 1).to_string()} class="py-3") {
|
|
div(class="grid place-items-center") {
|
|
"Loading ..."
|
|
}
|
|
}
|
|
}
|
|
}} else { view! {} })
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|