even more responsive
This commit is contained in:
parent
31cd79c543
commit
fb586bb362
11 changed files with 243 additions and 167 deletions
|
@ -14,7 +14,7 @@ console_error_panic_hook = "0.1"
|
|||
console_log = "1"
|
||||
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 = { git = "https://github.com/adoyle0/leptos-use.git", branch = "leptos-0.7" }
|
||||
codee = "0.2"
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body, html {
|
||||
background-color: #292929;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<meta charset="utf-8" />
|
||||
<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 />
|
||||
|
|
|
@ -12,7 +12,6 @@ pub fn Auth() -> impl IntoView {
|
|||
let user_context = expect_context::<ReadSignal<Option<UserUpdate>>>();
|
||||
let connected = move || websocket.ready_state.get() == ConnectionReadyState::Open;
|
||||
let new_username = RwSignal::new(String::new());
|
||||
let show_auth = RwSignal::new(false);
|
||||
|
||||
Effect::new(move |_| {
|
||||
user_context.with(|new_user| {
|
||||
|
@ -40,79 +39,71 @@ pub fn Auth() -> impl IntoView {
|
|||
});
|
||||
|
||||
view! {
|
||||
<div class="flex flex-wrap justify-between">
|
||||
<p class="my-2">"Welcome " {move || username()}"!"</p>
|
||||
<Button
|
||||
appearance=ButtonAppearance::Transparent
|
||||
size=ButtonSize::Small
|
||||
on_click=move |_| { show_auth.set(!show_auth()) }
|
||||
>
|
||||
<Avatar name=username />
|
||||
</Button>
|
||||
</div>
|
||||
<div class="overflow-hidden">
|
||||
<InlineDrawer open=show_auth position=DrawerPosition::Top size=DrawerSize::Small>
|
||||
<DrawerBody>
|
||||
<Show when=move || { connected() } fallback=|| view! { <p>"Disconnected."</p> }>
|
||||
<Popover
|
||||
trigger_type=PopoverTriggerType::Click
|
||||
position=PopoverPosition::BottomStart
|
||||
>
|
||||
<PopoverTrigger slot>
|
||||
<h2 class="text-2xl">
|
||||
"Sign In"
|
||||
<Button
|
||||
icon=icondata::TbHelp
|
||||
appearance=ButtonAppearance::Transparent
|
||||
size=ButtonSize::Small
|
||||
/>
|
||||
</h2>
|
||||
</PopoverTrigger>
|
||||
<p class="indent-1 text-pretty">
|
||||
"You were already given a random name but if you'd like to change it this is the place."
|
||||
</p>
|
||||
<p class="my-2 indent-1 text-pretty">
|
||||
"Identities are saved once created so if you leave or get disconnected just enter your old name here to \"log back in\"."
|
||||
</p>
|
||||
<p class="indent-1 text-pretty">
|
||||
"Please don't steal each other's identities (yes, you can)."
|
||||
</p>
|
||||
</Popover>
|
||||
<br />
|
||||
<Popover trigger_type=PopoverTriggerType::Click position=PopoverPosition::BottomEnd>
|
||||
<PopoverTrigger slot>
|
||||
<Button appearance=ButtonAppearance::Transparent size=ButtonSize::Small>
|
||||
// on_click=move |_| { show_auth.set(!show_auth()) }
|
||||
<Avatar class="drop-shadow-md" name=username />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<Show when=move || { connected() } fallback=|| view! { <p>"Disconnected."</p> }>
|
||||
<Popover
|
||||
trigger_type=PopoverTriggerType::Click
|
||||
position=PopoverPosition::BottomStart
|
||||
>
|
||||
<PopoverTrigger slot>
|
||||
<h2 class="text-2xl">
|
||||
"Sign In"
|
||||
<Button
|
||||
icon=icondata::TbHelp
|
||||
appearance=ButtonAppearance::Transparent
|
||||
size=ButtonSize::Small
|
||||
/>
|
||||
</h2>
|
||||
</PopoverTrigger>
|
||||
<p class="indent-1 text-pretty">
|
||||
"You were already given a random name but if you'd like to change it this is the place."
|
||||
</p>
|
||||
<p class="my-2 indent-1 text-pretty">
|
||||
"Identities are saved once created so if you leave or get disconnected just enter your old name here to \"log back in\"."
|
||||
</p>
|
||||
<p class="indent-1 text-pretty">
|
||||
"Please don't steal each other's identities (yes, you can)."
|
||||
</p>
|
||||
</Popover>
|
||||
<br />
|
||||
|
||||
<form onsubmit="return false" on:submit=send_login.clone() autocomplete="off">
|
||||
<FieldContextProvider>
|
||||
<Field label="Username" name="username">
|
||||
<Input
|
||||
placeholder=username
|
||||
value=new_username
|
||||
disabled=!connected()
|
||||
class="w-80"
|
||||
rules=vec![InputRule::required(true.into())]
|
||||
>
|
||||
<InputPrefix slot>
|
||||
<Icon icon=icondata::AiUserOutlined />
|
||||
</InputPrefix>
|
||||
</Input>
|
||||
</Field>
|
||||
<Button
|
||||
button_type=ButtonType::Submit
|
||||
on_click={
|
||||
let field_context = FieldContextInjection::expect_context();
|
||||
move |e: ev::MouseEvent| {
|
||||
if !field_context.validate() {
|
||||
e.prevent_default();
|
||||
}
|
||||
}
|
||||
<form onsubmit="return false" on:submit=send_login.clone() autocomplete="off">
|
||||
<FieldContextProvider>
|
||||
<Field label="Username" name="username">
|
||||
<Input
|
||||
placeholder=username
|
||||
value=new_username
|
||||
disabled=!connected()
|
||||
class="w-80"
|
||||
rules=vec![InputRule::required(true.into())]
|
||||
>
|
||||
<InputPrefix slot>
|
||||
<Icon icon=icondata::AiUserOutlined />
|
||||
</InputPrefix>
|
||||
</Input>
|
||||
</Field>
|
||||
<Button
|
||||
button_type=ButtonType::Submit
|
||||
on_click={
|
||||
let field_context = FieldContextInjection::expect_context();
|
||||
move |e: ev::MouseEvent| {
|
||||
if !field_context.validate() {
|
||||
e.prevent_default();
|
||||
}
|
||||
>
|
||||
"Submit"
|
||||
</Button>
|
||||
</FieldContextProvider>
|
||||
</form>
|
||||
</Show>
|
||||
</DrawerBody>
|
||||
</InlineDrawer>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
>
|
||||
"Submit"
|
||||
</Button>
|
||||
</FieldContextProvider>
|
||||
</form>
|
||||
</Show>
|
||||
</Popover>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,20 +24,29 @@ pub fn Browser() -> impl IntoView {
|
|||
|
||||
// Browser stuff
|
||||
let game_browser_context = expect_context::<ReadSignal<Vec<GameBrowserMeta>>>();
|
||||
let (join_id, set_join_id) = signal("".to_string());
|
||||
let (delete_id, set_delete_id) = signal("".to_string());
|
||||
let join_id = RwSignal::new("".to_string());
|
||||
let delete_id = RwSignal::new("".to_string());
|
||||
|
||||
let nav_context = expect_context::<RwSignal<String>>();
|
||||
|
||||
Effect::new(move |_| {
|
||||
set_websocket_send(to_string(&GameJoinRequest { id: join_id() }).unwrap());
|
||||
if join_id() != "" {
|
||||
set_websocket_send(to_string(&GameJoinRequest { id: join_id() }).unwrap());
|
||||
nav_context.set("game".to_string());
|
||||
join_id.set("".to_string());
|
||||
}
|
||||
});
|
||||
|
||||
Effect::new(move |_| {
|
||||
set_websocket_send(
|
||||
to_string(&GameDeleteRequest {
|
||||
delete_game_id: delete_id(),
|
||||
})
|
||||
.unwrap(),
|
||||
);
|
||||
if delete_id() != "" {
|
||||
set_websocket_send(
|
||||
to_string(&GameDeleteRequest {
|
||||
delete_game_id: delete_id(),
|
||||
})
|
||||
.unwrap(),
|
||||
);
|
||||
delete_id.set("".to_string());
|
||||
}
|
||||
});
|
||||
|
||||
let show_create_game = RwSignal::new(false);
|
||||
|
@ -51,14 +60,11 @@ pub fn Browser() -> impl IntoView {
|
|||
position=PopoverPosition::BottomStart
|
||||
>
|
||||
<PopoverTrigger slot>
|
||||
<h2 class="text-2xl">
|
||||
"Game Browser"
|
||||
<Button
|
||||
icon=icondata::TbHelp
|
||||
appearance=ButtonAppearance::Transparent
|
||||
size=ButtonSize::Small
|
||||
/>
|
||||
</h2>
|
||||
<Button
|
||||
icon=icondata::TbHelp
|
||||
appearance=ButtonAppearance::Transparent
|
||||
size=ButtonSize::Small
|
||||
/>
|
||||
</PopoverTrigger>
|
||||
<p>"Yes, the delete button works. Please don't abuse it."</p>
|
||||
</Popover>
|
||||
|
@ -135,7 +141,7 @@ pub fn Browser() -> impl IntoView {
|
|||
on_click={
|
||||
let game_id = game.uuid.clone();
|
||||
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
|
||||
icon=icondata::TiDeleteOutline
|
||||
on_click=move |_| {
|
||||
set_delete_id(game.uuid.clone());
|
||||
delete_id.set(game.uuid.clone());
|
||||
}
|
||||
>
|
||||
"Delete"
|
||||
|
|
|
@ -43,6 +43,8 @@ pub fn CreateGame() -> impl IntoView {
|
|||
let toggle_show_packs = move |_| show_packs.set(!show_packs());
|
||||
|
||||
let drawer_context = expect_context::<RwSignal<bool>>();
|
||||
|
||||
let nav_context = expect_context::<RwSignal<String>>();
|
||||
let request_new_game = move |_| {
|
||||
set_websocket_send(
|
||||
to_string(&NewGameRequest {
|
||||
|
@ -53,6 +55,7 @@ pub fn CreateGame() -> impl IntoView {
|
|||
);
|
||||
input_game_name.set(String::new());
|
||||
drawer_context.set(false);
|
||||
nav_context.set("game".to_string());
|
||||
};
|
||||
|
||||
view! {
|
||||
|
|
|
@ -79,7 +79,7 @@ pub fn Chat() -> impl IntoView {
|
|||
<span class="flex justify-between">
|
||||
<textarea
|
||||
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
|
||||
wrap="soft"
|
||||
>
|
||||
|
@ -95,14 +95,16 @@ pub fn Chat() -> impl IntoView {
|
|||
<form onsubmit="return false" on:submit=send_message autocomplete="off">
|
||||
<FieldContextProvider>
|
||||
<Field label="Message" name="message">
|
||||
<thaw::Input
|
||||
<Input
|
||||
rules=vec![InputRule::required(true.into())]
|
||||
class="drop-shadow-md"
|
||||
value=chat_input
|
||||
placeholder="talk shit..."
|
||||
/>
|
||||
</Field>
|
||||
<Button
|
||||
button_type=ButtonType::Submit
|
||||
class="drop-shadow-md"
|
||||
on_click={
|
||||
let field_context = FieldContextInjection::expect_context();
|
||||
move |e: ev::MouseEvent| {
|
||||
|
|
|
@ -39,7 +39,6 @@ pub fn Game() -> impl IntoView {
|
|||
|
||||
view! {
|
||||
<div class="my-2">
|
||||
<h2 class="text-2xl">Game</h2>
|
||||
<Show when=move || { connected() } fallback=|| view! { <p>"Disconnected."</p> }>
|
||||
<Show
|
||||
when=move || game_meta.get().is_some() && connected()
|
||||
|
|
|
@ -3,4 +3,5 @@ pub mod browser;
|
|||
pub mod chat;
|
||||
pub mod debug;
|
||||
pub mod game;
|
||||
pub mod theme_button;
|
||||
pub mod websocket;
|
||||
|
|
40
client/src/components/theme_button.rs
Normal file
40
client/src/components/theme_button.rs
Normal 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 /> }
|
||||
}
|
|
@ -4,6 +4,7 @@ use leptos_router::{
|
|||
components::{Route, Router, Routes},
|
||||
StaticSegment,
|
||||
};
|
||||
use leptos_use::use_media_query;
|
||||
use thaw::*;
|
||||
|
||||
// Modules
|
||||
|
@ -16,7 +17,16 @@ use crate::pages::home::Home;
|
|||
/// An app router which renders the homepage and handles 404's
|
||||
#[component]
|
||||
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_meta_context();
|
||||
|
|
|
@ -3,6 +3,7 @@ use crate::components::browser::*;
|
|||
use crate::components::chat::*;
|
||||
use crate::components::debug::*;
|
||||
use crate::components::game::*;
|
||||
use crate::components::theme_button::*;
|
||||
use crate::components::websocket::*;
|
||||
use leptos::prelude::*;
|
||||
use thaw::*;
|
||||
|
@ -17,29 +18,8 @@ pub fn Home() -> impl IntoView {
|
|||
modal.set(true);
|
||||
};
|
||||
|
||||
let theme = expect_context::<RwSignal<Theme>>();
|
||||
let icon = RwSignal::new(Some(icondata::BsMoon));
|
||||
|
||||
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();
|
||||
});
|
||||
};
|
||||
let selected_value = RwSignal::new("home".to_string());
|
||||
provide_context(selected_value);
|
||||
|
||||
view! {
|
||||
<ErrorBoundary fallback=|errors| {
|
||||
|
@ -60,64 +40,101 @@ pub fn Home() -> impl IntoView {
|
|||
</ul>
|
||||
}
|
||||
}>
|
||||
<Websocket />
|
||||
|
||||
<div class="container m-auto">
|
||||
<div class="container m-auto relative">
|
||||
<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);"
|
||||
>
|
||||
// Header
|
||||
<div class="flex flex-wrap justify-between">
|
||||
<h1 class="text-4xl sm:text-6xl md:text-7xl lg:text-8xl tracking-tighter">
|
||||
"Cards For Humanity"
|
||||
</h1>
|
||||
<Button icon on_click appearance=ButtonAppearance::Transparent />
|
||||
<ThemeButton />
|
||||
</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>
|
||||
<DialogSurface>
|
||||
<DialogBody>
|
||||
<DialogTitle>"Hey!"</DialogTitle>
|
||||
<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 "}
|
||||
<Link href="mailto:adam@doordesk.net">
|
||||
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."}
|
||||
</p>
|
||||
<br />
|
||||
<p>Have fun!</p>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
on_click=move |_| modal.set(false)
|
||||
appearance=ButtonAppearance::Primary
|
||||
>
|
||||
"Got it"
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</DialogBody>
|
||||
</DialogSurface>
|
||||
</Dialog>
|
||||
<Show when=move || selected_value() == "home".to_string()>
|
||||
<div class="p-4">
|
||||
<h2 class="text-2xl">"Hey!"</h2>
|
||||
<p class="indent-4 text-pretty my-3">
|
||||
{"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">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."}
|
||||
</p>
|
||||
<p>Have fun!</p>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
<Websocket />
|
||||
<Auth />
|
||||
<Divider />
|
||||
<Browser />
|
||||
<Divider />
|
||||
<Game />
|
||||
<Divider />
|
||||
<Chat />
|
||||
<Divider />
|
||||
<Debug />
|
||||
<Divider />
|
||||
<div class="m-2">
|
||||
<Link class="p-2" href="https://git.doordesk.net/adam/cards/">
|
||||
"Git"
|
||||
</Link>
|
||||
<Link class="p-2" href="mailto:adam@doordesk.net">
|
||||
"Email Me"
|
||||
</Link>
|
||||
<Show when=move || selected_value() == "browser".to_string()>
|
||||
<Browser />
|
||||
</Show>
|
||||
|
||||
<Show when=move || selected_value() == "game".to_string()>
|
||||
<Game />
|
||||
</Show>
|
||||
|
||||
<Show when=move || selected_value() == "chat".to_string()>
|
||||
<Chat />
|
||||
</Show>
|
||||
|
||||
<Show when=move || selected_value() == "debug".to_string()>
|
||||
<Debug />
|
||||
</Show>
|
||||
|
||||
// Footer
|
||||
<div
|
||||
class="fixed sm:static bottom-0 left-0 w-full sm:w-auto"
|
||||
style="background-color: var(--colorNeutralBackground4);"
|
||||
>
|
||||
<Divider />
|
||||
<div class="m-2">
|
||||
<Link class="p-2" href="https://git.doordesk.net/adam/cards/">
|
||||
"About"
|
||||
</Link>
|
||||
<Link class="p-2" href="mailto:adam@doordesk.net">
|
||||
"Contact"
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Add table
Reference in a new issue