lan-party-backend/web/src/'

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! {} })
}
}
}
}
}
}