even more responsive

This commit is contained in:
Adam 2024-09-10 01:59:35 -04:00
parent 31cd79c543
commit fb586bb362
11 changed files with 243 additions and 167 deletions

View file

@ -14,7 +14,7 @@ console_error_panic_hook = "0.1"
console_log = "1" console_log = "1"
log = "0.4" log = "0.4"
leptos-use = "0.14.0-beta" leptos-use = { version = "0.14.0-beta", features = ["use_media_query"] }
# leptos-use = { path = "../../leptos-use" } # leptos-use = { path = "../../leptos-use" }
# leptos-use = { git = "https://github.com/adoyle0/leptos-use.git", branch = "leptos-0.7" } # leptos-use = { git = "https://github.com/adoyle0/leptos-use.git", branch = "leptos-0.7" }
codee = "0.2" codee = "0.2"

View file

@ -1,6 +1,13 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<style>
@media (prefers-color-scheme: dark) {
body, html {
background-color: #292929;
}
}
</style>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link data-trunk rel="rust" data-target-path="client" data-wasm-opt="z" data-weak-refs /> <link data-trunk rel="rust" data-target-path="client" data-wasm-opt="z" data-weak-refs />

View file

@ -12,7 +12,6 @@ pub fn Auth() -> impl IntoView {
let user_context = expect_context::<ReadSignal<Option<UserUpdate>>>(); let user_context = expect_context::<ReadSignal<Option<UserUpdate>>>();
let connected = move || websocket.ready_state.get() == ConnectionReadyState::Open; let connected = move || websocket.ready_state.get() == ConnectionReadyState::Open;
let new_username = RwSignal::new(String::new()); let new_username = RwSignal::new(String::new());
let show_auth = RwSignal::new(false);
Effect::new(move |_| { Effect::new(move |_| {
user_context.with(|new_user| { user_context.with(|new_user| {
@ -40,19 +39,13 @@ pub fn Auth() -> impl IntoView {
}); });
view! { view! {
<div class="flex flex-wrap justify-between"> <Popover trigger_type=PopoverTriggerType::Click position=PopoverPosition::BottomEnd>
<p class="my-2">"Welcome " {move || username()}"!"</p> <PopoverTrigger slot>
<Button <Button appearance=ButtonAppearance::Transparent size=ButtonSize::Small>
appearance=ButtonAppearance::Transparent // on_click=move |_| { show_auth.set(!show_auth()) }
size=ButtonSize::Small <Avatar class="drop-shadow-md" name=username />
on_click=move |_| { show_auth.set(!show_auth()) }
>
<Avatar name=username />
</Button> </Button>
</div> </PopoverTrigger>
<div class="overflow-hidden">
<InlineDrawer open=show_auth position=DrawerPosition::Top size=DrawerSize::Small>
<DrawerBody>
<Show when=move || { connected() } fallback=|| view! { <p>"Disconnected."</p> }> <Show when=move || { connected() } fallback=|| view! { <p>"Disconnected."</p> }>
<Popover <Popover
trigger_type=PopoverTriggerType::Click trigger_type=PopoverTriggerType::Click
@ -111,8 +104,6 @@ pub fn Auth() -> impl IntoView {
</FieldContextProvider> </FieldContextProvider>
</form> </form>
</Show> </Show>
</DrawerBody> </Popover>
</InlineDrawer>
</div>
} }
} }

View file

@ -24,20 +24,29 @@ pub fn Browser() -> impl IntoView {
// Browser stuff // Browser stuff
let game_browser_context = expect_context::<ReadSignal<Vec<GameBrowserMeta>>>(); let game_browser_context = expect_context::<ReadSignal<Vec<GameBrowserMeta>>>();
let (join_id, set_join_id) = signal("".to_string()); let join_id = RwSignal::new("".to_string());
let (delete_id, set_delete_id) = signal("".to_string()); let delete_id = RwSignal::new("".to_string());
let nav_context = expect_context::<RwSignal<String>>();
Effect::new(move |_| { Effect::new(move |_| {
if join_id() != "" {
set_websocket_send(to_string(&GameJoinRequest { id: join_id() }).unwrap()); set_websocket_send(to_string(&GameJoinRequest { id: join_id() }).unwrap());
nav_context.set("game".to_string());
join_id.set("".to_string());
}
}); });
Effect::new(move |_| { Effect::new(move |_| {
if delete_id() != "" {
set_websocket_send( set_websocket_send(
to_string(&GameDeleteRequest { to_string(&GameDeleteRequest {
delete_game_id: delete_id(), delete_game_id: delete_id(),
}) })
.unwrap(), .unwrap(),
); );
delete_id.set("".to_string());
}
}); });
let show_create_game = RwSignal::new(false); let show_create_game = RwSignal::new(false);
@ -51,14 +60,11 @@ pub fn Browser() -> impl IntoView {
position=PopoverPosition::BottomStart position=PopoverPosition::BottomStart
> >
<PopoverTrigger slot> <PopoverTrigger slot>
<h2 class="text-2xl">
"Game Browser"
<Button <Button
icon=icondata::TbHelp icon=icondata::TbHelp
appearance=ButtonAppearance::Transparent appearance=ButtonAppearance::Transparent
size=ButtonSize::Small size=ButtonSize::Small
/> />
</h2>
</PopoverTrigger> </PopoverTrigger>
<p>"Yes, the delete button works. Please don't abuse it."</p> <p>"Yes, the delete button works. Please don't abuse it."</p>
</Popover> </Popover>
@ -135,7 +141,7 @@ pub fn Browser() -> impl IntoView {
on_click={ on_click={
let game_id = game.uuid.clone(); let game_id = game.uuid.clone();
move |_| { move |_| {
set_join_id(game_id.clone()); join_id.set(game_id.clone());
} }
} }
> >
@ -146,7 +152,7 @@ pub fn Browser() -> impl IntoView {
size=ButtonSize::Small size=ButtonSize::Small
icon=icondata::TiDeleteOutline icon=icondata::TiDeleteOutline
on_click=move |_| { on_click=move |_| {
set_delete_id(game.uuid.clone()); delete_id.set(game.uuid.clone());
} }
> >
"Delete" "Delete"

View file

@ -43,6 +43,8 @@ pub fn CreateGame() -> impl IntoView {
let toggle_show_packs = move |_| show_packs.set(!show_packs()); let toggle_show_packs = move |_| show_packs.set(!show_packs());
let drawer_context = expect_context::<RwSignal<bool>>(); let drawer_context = expect_context::<RwSignal<bool>>();
let nav_context = expect_context::<RwSignal<String>>();
let request_new_game = move |_| { let request_new_game = move |_| {
set_websocket_send( set_websocket_send(
to_string(&NewGameRequest { to_string(&NewGameRequest {
@ -53,6 +55,7 @@ pub fn CreateGame() -> impl IntoView {
); );
input_game_name.set(String::new()); input_game_name.set(String::new());
drawer_context.set(false); drawer_context.set(false);
nav_context.set("game".to_string());
}; };
view! { view! {

View file

@ -79,7 +79,7 @@ pub fn Chat() -> impl IntoView {
<span class="flex justify-between"> <span class="flex justify-between">
<textarea <textarea
node_ref=chat_history_ref node_ref=chat_history_ref
class="w-full h-60 p-1 font-mono rounded-md resize-none bg-neutral-900 text-neutral-200" class="opacity-80 w-full h-60 p-1 font-mono rounded-md resize-none bg-neutral-900 text-neutral-200 drop-shadow-md"
readonly=true readonly=true
wrap="soft" wrap="soft"
> >
@ -95,14 +95,16 @@ pub fn Chat() -> impl IntoView {
<form onsubmit="return false" on:submit=send_message autocomplete="off"> <form onsubmit="return false" on:submit=send_message autocomplete="off">
<FieldContextProvider> <FieldContextProvider>
<Field label="Message" name="message"> <Field label="Message" name="message">
<thaw::Input <Input
rules=vec![InputRule::required(true.into())] rules=vec![InputRule::required(true.into())]
class="drop-shadow-md"
value=chat_input value=chat_input
placeholder="talk shit..." placeholder="talk shit..."
/> />
</Field> </Field>
<Button <Button
button_type=ButtonType::Submit button_type=ButtonType::Submit
class="drop-shadow-md"
on_click={ on_click={
let field_context = FieldContextInjection::expect_context(); let field_context = FieldContextInjection::expect_context();
move |e: ev::MouseEvent| { move |e: ev::MouseEvent| {

View file

@ -39,7 +39,6 @@ pub fn Game() -> impl IntoView {
view! { view! {
<div class="my-2"> <div class="my-2">
<h2 class="text-2xl">Game</h2>
<Show when=move || { connected() } fallback=|| view! { <p>"Disconnected."</p> }> <Show when=move || { connected() } fallback=|| view! { <p>"Disconnected."</p> }>
<Show <Show
when=move || game_meta.get().is_some() && connected() when=move || game_meta.get().is_some() && connected()

View file

@ -3,4 +3,5 @@ pub mod browser;
pub mod chat; pub mod chat;
pub mod debug; pub mod debug;
pub mod game; pub mod game;
pub mod theme_button;
pub mod websocket; pub mod websocket;

View file

@ -0,0 +1,40 @@
use leptos::prelude::*;
use thaw::*;
/// In charge of light/dark modes
#[component]
pub fn ThemeButton() -> impl IntoView {
let theme = expect_context::<RwSignal<Theme>>();
let icon = RwSignal::new(None);
Effect::new(move |_| {
if theme().name == "dark" {
icon.set(Some(icondata::BsMoon));
} else {
icon.set(Some(icondata::BsSun));
}
});
let on_click = move |_| {
icon.update(|icon| {
*icon = match icon {
Some(data) => {
if *data == icondata::BsMoon {
theme.set(Theme::light());
icondata::BsSun
} else {
theme.set(Theme::dark());
icondata::BsMoon
}
}
None => {
theme.set(Theme::dark());
icondata::BsMoon
}
}
.into();
});
};
view! { <Button class="drop-shadow-md" icon on_click appearance=ButtonAppearance::Transparent /> }
}

View file

@ -4,6 +4,7 @@ use leptos_router::{
components::{Route, Router, Routes}, components::{Route, Router, Routes},
StaticSegment, StaticSegment,
}; };
use leptos_use::use_media_query;
use thaw::*; use thaw::*;
// Modules // Modules
@ -16,7 +17,16 @@ use crate::pages::home::Home;
/// An app router which renders the homepage and handles 404's /// An app router which renders the homepage and handles 404's
#[component] #[component]
pub fn App() -> impl IntoView { pub fn App() -> impl IntoView {
let theme = RwSignal::new(Theme::dark()); let theme = RwSignal::new(Theme::light());
let prefers_dark = use_media_query("(prefers-color-scheme: dark)");
Effect::new(move |_| {
if prefers_dark() {
theme.set(Theme::dark());
} else {
theme.set(Theme::light());
}
});
provide_context(theme); provide_context(theme);
provide_meta_context(); provide_meta_context();

View file

@ -3,6 +3,7 @@ use crate::components::browser::*;
use crate::components::chat::*; use crate::components::chat::*;
use crate::components::debug::*; use crate::components::debug::*;
use crate::components::game::*; use crate::components::game::*;
use crate::components::theme_button::*;
use crate::components::websocket::*; use crate::components::websocket::*;
use leptos::prelude::*; use leptos::prelude::*;
use thaw::*; use thaw::*;
@ -17,29 +18,8 @@ pub fn Home() -> impl IntoView {
modal.set(true); modal.set(true);
}; };
let theme = expect_context::<RwSignal<Theme>>(); let selected_value = RwSignal::new("home".to_string());
let icon = RwSignal::new(Some(icondata::BsMoon)); provide_context(selected_value);
let on_click = move |_| {
icon.update(|icon| {
*icon = match icon {
Some(data) => {
if *data == icondata::BsMoon {
theme.set(Theme::light());
icondata::BsSun
} else {
theme.set(Theme::dark());
icondata::BsMoon
}
}
None => {
theme.set(Theme::dark());
icondata::BsMoon
}
}
.into();
});
};
view! { view! {
<ErrorBoundary fallback=|errors| { <ErrorBoundary fallback=|errors| {
@ -60,67 +40,104 @@ pub fn Home() -> impl IntoView {
</ul> </ul>
} }
}> }>
<Websocket />
<div class="container m-auto"> <div class="container m-auto relative">
<div <div
class="p-1 sm:p-5 sm:rounded-2xl sm:shadow-black sm:shadow-lg" class="p-1 sm:p-5 sm:rounded-2xl sm:shadow-black sm:shadow-lg min-h-screen sm:min-h-0"
style="background-color: var(--colorNeutralBackground4);" style="background-color: var(--colorNeutralBackground4);"
> >
// Header
<div class="flex flex-wrap justify-between"> <div class="flex flex-wrap justify-between">
<h1 class="text-4xl sm:text-6xl md:text-7xl lg:text-8xl tracking-tighter"> <h1 class="text-4xl sm:text-6xl md:text-7xl lg:text-8xl tracking-tighter">
"Cards For Humanity" "Cards For Humanity"
</h1> </h1>
<Button icon on_click appearance=ButtonAppearance::Transparent /> <ThemeButton />
</div> </div>
<div class="flex justify-between">
<TabList selected_value>
<Tab value="home">
<Button
appearance=ButtonAppearance::Transparent
icon=icondata::BiHomeAlt2Regular
/>
</Tab>
<Tab value="browser">
<Button
appearance=ButtonAppearance::Transparent
icon=icondata::RiMenuSearchSystemLine
/>
</Tab>
<Tab value="game">
<Button
appearance=ButtonAppearance::Transparent
icon=icondata::LuGamepad
/>
</Tab>
<Tab value="chat">
<Button
appearance=ButtonAppearance::Transparent
icon=icondata::BsChatLeftText
/>
</Tab>
<Tab value="debug">
<Button
appearance=ButtonAppearance::Transparent
icon=icondata::AiBugOutlined
/>
</Tab>
</TabList>
<div class="mt-2">
<Auth />
</div>
</div>
<Divider />
<Dialog open=modal> <Show when=move || selected_value() == "home".to_string()>
<DialogSurface> <div class="p-4">
<DialogBody> <h2 class="text-2xl">"Hey!"</h2>
<DialogTitle>"Hey!"</DialogTitle> <p class="indent-4 text-pretty my-3">
<DialogContent>
<p class="indent-2 text-pretty">
{"Welcome! Thank you for helping me test this. Please let me know about any issues you may come across. Chances are you already know how to contact me but in case you don't you can email me at "} {"Welcome! Thank you for helping me test this. Please let me know about any issues you may come across. Chances are you already know how to contact me but in case you don't you can email me at "}
<Link href="mailto:adam@doordesk.net"> <Link href="mailto:adam@doordesk.net">adam@doordesk.net</Link>
adam@doordesk.net
</Link>
{". The server may go down from time to time as bugs are found and as I add updates. If you manage to crash the server or notice it down for a long time please tell me about it."} {". The server may go down from time to time as bugs are found and as I add updates. If you manage to crash the server or notice it down for a long time please tell me about it."}
</p> </p>
<br />
<p>Have fun!</p> <p>Have fun!</p>
</DialogContent> </div>
<DialogActions> </Show>
<Button
on_click=move |_| modal.set(false)
appearance=ButtonAppearance::Primary
>
"Got it"
</Button>
</DialogActions>
</DialogBody>
</DialogSurface>
</Dialog>
<Websocket /> <Show when=move || selected_value() == "browser".to_string()>
<Auth />
<Divider />
<Browser /> <Browser />
<Divider /> </Show>
<Show when=move || selected_value() == "game".to_string()>
<Game /> <Game />
<Divider /> </Show>
<Show when=move || selected_value() == "chat".to_string()>
<Chat /> <Chat />
<Divider /> </Show>
<Show when=move || selected_value() == "debug".to_string()>
<Debug /> <Debug />
</Show>
// Footer
<div
class="fixed sm:static bottom-0 left-0 w-full sm:w-auto"
style="background-color: var(--colorNeutralBackground4);"
>
<Divider /> <Divider />
<div class="m-2"> <div class="m-2">
<Link class="p-2" href="https://git.doordesk.net/adam/cards/"> <Link class="p-2" href="https://git.doordesk.net/adam/cards/">
"Git" "About"
</Link> </Link>
<Link class="p-2" href="mailto:adam@doordesk.net"> <Link class="p-2" href="mailto:adam@doordesk.net">
"Email Me" "Contact"
</Link> </Link>
</div> </div>
</div> </div>
</div> </div>
</div>
</ErrorBoundary> </ErrorBoundary>
} }
} }