migrate to leptos 0.7

This commit is contained in:
Adam 2024-09-07 01:17:51 -04:00
parent f22f1a00a9
commit 0de020ac39
19 changed files with 695 additions and 396 deletions

731
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -7,18 +7,19 @@ authors = ["Adam Doyle <adam@doordesk.net>"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
leptos = { version = "0.6", features = ["csr", "nightly"] }
leptos_meta = { version = "0.6", features = ["csr", "nightly"] }
leptos_router = { version = "0.6", features = ["csr", "nightly"] }
leptos = { version = "0.7.0-beta", features = ["csr", "nightly"] }
leptos_meta = { version = "0.7.0-beta" }
leptos_router = { version = "0.7.0-beta", features = ["nightly"] }
console_error_panic_hook = "0.1"
console_log = "1"
log = "0.4"
leptos-use = "0.13"
leptos-use = "0.14.0-beta"
codee = "0.2"
lib = { workspace = true }
serde_json = "1.0"
thaw = { version = "0.4.0-beta2", features = ["csr", "nightly"] }
[dev-dependencies]
wasm-bindgen = "0.2"

View file

@ -1,15 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<!-- Add a plain CSS file: see https://trunkrs.dev/assets/#css -->
<!-- If using Tailwind with Leptos CSR, see https://trunkrs.dev/assets/#tailwind instead-->
<link data-trunk rel="tailwind-css" href="public/styles.css" />
<!-- Include favicon in dist output: see https://trunkrs.dev/assets/#icon -->
<link data-trunk rel="icon" href="public/favicon.ico" />
<!-- include support for `wasm-bindgen --weak-refs` - see: https://rustwasm.github.io/docs/wasm-bindgen/reference/weak-references.html -->
<meta charset="utf-8" />
<link data-trunk rel="rust" data-target-path="client" data-wasm-opt="z" data-weak-refs />
<link data-trunk rel="icon" href="public/favicon.ico" />
<link data-trunk rel="tailwind-css" href="public/styles.css" />
<title>Cards for Humanity</title>
</head>
<body></body>
</html>

View file

@ -13,7 +13,7 @@
html,
body {
@apply text-neutral-200;
@apply text-neutral-200 bg-neutral-900;
font-family: "Inter", sans-serif;
font-optical-sizing: auto;
font-weight: 400;

View file

@ -1,6 +1,5 @@
use crate::components::websocket::WebSocketContext;
use html::Input;
use leptos::*;
use leptos::{html::Input, prelude::*};
use leptos_use::core::ConnectionReadyState;
use lib::*;
use serde_json::to_string;
@ -8,11 +7,11 @@ use serde_json::to_string;
#[component]
pub fn Auth() -> impl IntoView {
let websocket = expect_context::<WebSocketContext>();
let (username, set_username) = create_signal("".to_string());
let (username, set_username) = signal("".to_string());
let user_context = expect_context::<ReadSignal<Option<UserUpdate>>>();
let connected = move || websocket.ready_state.get() == ConnectionReadyState::Open;
create_effect(move |_| {
Effect::new(move |_| {
user_context.with(|new_user| {
if let Some(user) = new_user {
set_username(user.username.to_string());
@ -20,7 +19,7 @@ pub fn Auth() -> impl IntoView {
})
});
let username_input_ref = create_node_ref::<Input>();
let username_input_ref = NodeRef::<Input>::new();
let send_login = move |_| {
if let Some(input) = username_input_ref.get() {
if input.value() != String::from("") {
@ -37,7 +36,7 @@ pub fn Auth() -> impl IntoView {
};
// Clear user name on disconnect
create_effect(move |_| {
Effect::new(move |_| {
if !connected() {
set_username(String::from(""));
}

View file

@ -1,5 +1,5 @@
use crate::components::websocket::WebSocketContext;
use leptos::*;
use leptos::prelude::*;
use leptos_use::core::ConnectionReadyState;
use lib::*;
use serde_json::to_string;
@ -11,9 +11,9 @@ pub fn Browser() -> impl IntoView {
let connected = move || websocket.ready_state.get() == ConnectionReadyState::Open;
let tx = websocket.clone();
let (websocket_send, set_websocket_send) = create_signal("".to_string());
let (websocket_send, set_websocket_send) = signal("".to_string());
create_effect(move |_| {
Effect::new(move |_| {
if websocket_send() != "".to_string() {
tx.send(&websocket_send());
}
@ -21,14 +21,14 @@ pub fn Browser() -> impl IntoView {
// Browser stuff
let game_browser_context = expect_context::<ReadSignal<Vec<GameBrowserMeta>>>();
let (join_id, set_join_id) = create_signal("".to_string());
let (delete_id, set_delete_id) = create_signal("".to_string());
let (join_id, set_join_id) = signal("".to_string());
let (delete_id, set_delete_id) = signal("".to_string());
create_effect(move |_| {
Effect::new(move |_| {
set_websocket_send(to_string(&GameJoinRequest { id: join_id() }).unwrap());
});
create_effect(move |_| {
Effect::new(move |_| {
set_websocket_send(
to_string(&GameDeleteRequest {
delete_game_id: delete_id(),
@ -74,7 +74,7 @@ pub fn Browser() -> impl IntoView {
<td class="text-center border-b">
<button
type="button"
value=&game.uuid
value=game.uuid.clone()
on:click=move |e| {
set_join_id(event_target_value(&e));
}
@ -83,7 +83,7 @@ pub fn Browser() -> impl IntoView {
</button>
<button
type="button"
value=&game.uuid
value=game.uuid.clone()
on:click=move |e| {
set_delete_id(event_target_value(&e));
}

View file

@ -1,6 +1,8 @@
use crate::components::websocket::WebSocketContext;
use html::{Input, Textarea};
use leptos::*;
use leptos::{
html::{Input, Textarea},
prelude::*,
};
use leptos_use::core::ConnectionReadyState;
use lib::*;
use serde_json::to_string;
@ -13,18 +15,18 @@ pub fn Chat() -> impl IntoView {
let connected = move || websocket.ready_state.get() == ConnectionReadyState::Open;
// Chat stuff
let (chat_history, set_chat_history) = create_signal::<Vec<String>>(vec![]);
let (users, set_users) = create_signal::<Vec<String>>(vec![]);
let (chat_name, set_chat_name) = create_signal::<String>("".to_string());
let chat_history_ref = create_node_ref::<Textarea>();
let chat_input_ref = create_node_ref::<Input>();
let (chat_history, set_chat_history) = signal::<Vec<String>>(vec![]);
let (users, set_users) = signal::<Vec<String>>(vec![]);
let (chat_name, set_chat_name) = signal::<String>("".to_string());
let chat_history_ref = NodeRef::<Textarea>::new();
let chat_input_ref = NodeRef::<Input>::new();
fn update_chat_history(&history: &WriteSignal<Vec<String>>, message: String) {
let _ = &history.update(|history: &mut Vec<_>| history.push(message));
}
// Connection status updates in chat window
create_effect(move |_| {
Effect::new(move |_| {
websocket.ready_state.with(move |state| match *state {
ConnectionReadyState::Connecting => {
update_chat_history(
@ -45,7 +47,7 @@ pub fn Chat() -> impl IntoView {
});
// Handle incoming chat messages
create_effect(move |_| {
Effect::new(move |_| {
chat_context.with(move |chat_message| {
if let Some(message) = chat_message {
update_chat_history(&set_chat_history, format!("{}\n", message.text));
@ -54,7 +56,7 @@ pub fn Chat() -> impl IntoView {
});
// Handle users
create_effect(move |_| {
Effect::new(move |_| {
chat_update_context.with(move |chat_update| {
if let Some(update) = chat_update {
set_users(update.users.clone());
@ -64,7 +66,7 @@ pub fn Chat() -> impl IntoView {
});
// Clear user list on disconnect
create_effect(move |_| {
Effect::new(move |_| {
websocket.ready_state.with(move |status| {
if *status == ConnectionReadyState::Closed {
set_users(vec![]);
@ -88,7 +90,7 @@ pub fn Chat() -> impl IntoView {
};
// Keep chat scrolled to the bottom
create_effect(move |_| {
Effect::new(move |_| {
chat_history.with(move |_| {
// Scroll chat textarea to bottom
if let Some(hist) = chat_history_ref.get() {

View file

@ -1,6 +1,5 @@
use crate::components::websocket::WebSocketContext;
use leptos::html::Input;
use leptos::*;
use leptos::{html::Input, prelude::*};
use leptos_use::core::ConnectionReadyState;
use lib::*;
use serde_json::to_string;
@ -10,12 +9,12 @@ use std::collections::BTreeSet;
pub fn CreateGame() -> impl IntoView {
// Websocket stuff
let websocket = expect_context::<WebSocketContext>();
let (websocket_send, set_websocket_send) = create_signal("".to_string());
let (websocket_send, set_websocket_send) = signal("".to_string());
let connected = move || websocket.ready_state.get() == ConnectionReadyState::Open;
let tx = websocket.clone();
create_effect(move |_| {
Effect::new(move |_| {
if websocket_send() != "".to_string() {
tx.send(&websocket_send());
}
@ -24,29 +23,29 @@ pub fn CreateGame() -> impl IntoView {
// New game stuff
let card_packs = expect_context::<ReadSignal<CardPacksMeta>>();
let (show_packs, set_show_packs) = create_signal(false);
let (selected_packs, set_selected_packs) = create_signal::<BTreeSet<u8>>(BTreeSet::new());
let (show_packs, set_show_packs) = signal(false);
let (selected_packs, set_selected_packs) = signal::<BTreeSet<u8>>(BTreeSet::new());
create_effect(move |_| {
Effect::new(move |_| {
set_selected_packs
.update(|set| set.extend(card_packs().official_meta.iter().map(|pack| pack.pack)));
});
create_effect(move |_| {
Effect::new(move |_| {
set_selected_packs
.update(|set| set.extend(card_packs().unofficial_meta.iter().map(|pack| pack.pack)));
});
let new_game_name_ref = create_node_ref::<Input>();
let new_game_name_ref = NodeRef::<Input>::new();
let toggle_show_packs = move |_| set_show_packs(!show_packs());
let request_new_game = move |_| {
if let Some(input) = new_game_name_ref.get() {
if input.value() == *"" {
logging::error!("New game name is empty!");
println!("New game name is empty!");
} else if selected_packs().is_empty() {
logging::error!("New game selected packs is empty!");
println!("New game selected packs is empty!");
} else {
set_websocket_send(
to_string(&NewGameRequest {

View file

@ -1,5 +1,5 @@
use crate::components::websocket::WebSocketContext;
use leptos::*;
use leptos::prelude::*;
use leptos_use::core::ConnectionReadyState;
use lib::*;
@ -9,8 +9,8 @@ pub fn Debug() -> impl IntoView {
let state_summary = expect_context::<ReadSignal<Option<ServerStateSummary>>>();
// Signals
let (online_users, set_online_users) = create_signal(0);
let (active_games, set_active_games) = create_signal(0);
let (online_users, set_online_users) = signal(0);
let (active_games, set_active_games) = signal(0);
// Websocket stuff
let status = move || websocket.ready_state.get().to_string();
@ -26,7 +26,7 @@ pub fn Debug() -> impl IntoView {
};
// Update server info -> move this to a new component
create_effect(move |_| {
Effect::new(move |_| {
state_summary.with(move |state_summary| {
if let Some(state_summary) = state_summary {
set_online_users(state_summary.online_users);

View file

@ -2,7 +2,7 @@ use crate::components::game::header::*;
use crate::components::game::views::judging::*;
use crate::components::game::views::playing::*;
use crate::components::websocket::WebSocketContext;
use leptos::*;
use leptos::prelude::*;
use leptos_use::core::ConnectionReadyState;
use lib::*;
pub mod cards;
@ -20,10 +20,10 @@ pub fn Game() -> impl IntoView {
let user_update = expect_context::<ReadSignal<Option<UserUpdate>>>();
// Signals //
let (judging, set_judging) = create_signal(false);
let (judging, set_judging) = signal(false);
// Determine judging
create_effect(move |_| {
Effect::new(move |_| {
user_update.with(move |user_meta| {
if let Some(user_meta) = user_meta {
if let Some(game_meta) = game_meta() {

View file

@ -1,4 +1,4 @@
use leptos::*;
use leptos::prelude::*;
use lib::*;
#[component]

View file

@ -1,4 +1,4 @@
use leptos::*;
use leptos::prelude::*;
use lib::*;
#[component]

View file

@ -1,6 +1,6 @@
use crate::components::game::cards::*;
use crate::components::websocket::WebSocketContext;
use leptos::*;
use leptos::prelude::*;
use lib::*;
use serde_json::to_string;
@ -13,14 +13,14 @@ pub fn JudgingView() -> impl IntoView {
let set_judge_round = expect_context::<WriteSignal<Option<JudgeRound>>>();
// Signals
let (selected_cards, set_selected_cards) = create_signal::<Vec<WhiteCardMeta>>(vec![]);
let (card_clicked, set_card_clicked) = create_signal::<String>(String::new());
let (selected_cards, set_selected_cards) = signal::<Vec<WhiteCardMeta>>(vec![]);
let (card_clicked, set_card_clicked) = signal::<String>(String::new());
// Outoging
provide_context::<WriteSignal<String>>(set_card_clicked);
// On Incoming Judge
create_effect(move |_| {
Effect::new(move |_| {
// Clear selected cards
if judge_round().is_some() {
set_selected_cards.update(|list| {
@ -31,7 +31,7 @@ pub fn JudgingView() -> impl IntoView {
// Card selection //
// Toggle selected status of cards
create_effect(move |_| {
Effect::new(move |_| {
if card_clicked() != "".to_string() {
let identical_cards = selected_cards
.get_untracked()
@ -86,15 +86,15 @@ pub fn JudgingView() -> impl IntoView {
view! {
<div class="w-full ms-16 inline-flex flex-wrap">
<BlackCard />
// Selected cards
<For
each=move || selected_cards()
key=move |card| card.uuid.clone()
children=move |card| {
view! { <WhiteCard card_data=card /> }
}
/>
{move || {
selected_cards()
.into_iter()
.map(|card| {
view! { <WhiteCard card_data=card /> }
})
.collect_view()
}}
</div>
// Submit button
@ -114,18 +114,17 @@ pub fn JudgingView() -> impl IntoView {
}
}
>
<For
each=move || judge_round().unwrap().cards_to_judge
key=move |_| 69
children=move |group| {
{judge_round()
.unwrap()
.cards_to_judge
.into_iter()
.map(|group| {
view! {
<div class="m-2 inline-flex flex-wrap justify-center">
<For
each=move || group.clone()
key=move |card| card.uuid.clone()
children=move |card| {
{group
.into_iter()
.map(|card| {
view! {
// Hide cards from hand view when they exist as selected
<Show when={
let waste_of_memory = card.clone();
move || { !selected_cards().contains(&waste_of_memory) }
@ -133,12 +132,12 @@ pub fn JudgingView() -> impl IntoView {
<WhiteCard card_data=card.clone() />
</Show>
}
}
/>
})
.collect_view()}
</div>
}
}
/>
})
.collect_view()}
</Show>
}
}

View file

@ -1,6 +1,6 @@
use crate::components::game::cards::*;
use crate::components::websocket::WebSocketContext;
use leptos::*;
use leptos::prelude::*;
use lib::*;
use serde_json::to_string;
use std::collections::{HashMap, HashSet};
@ -13,13 +13,11 @@ pub fn PlayingView() -> impl IntoView {
let game_state = expect_context::<ReadSignal<Option<GameStateMeta>>>();
// Signals
let (selected_cards, set_selected_cards) = create_signal::<Vec<WhiteCardMeta>>(vec![]);
let (submitted_cards, set_submitted_cards) =
create_signal::<HashSet<WhiteCardMeta>>(HashSet::new());
let (card_clicked, set_card_clicked) = create_signal::<String>(String::new());
let (submitted, set_submitted) = create_signal(false);
let (player_hand, set_player_hand) =
create_signal::<HashMap<String, WhiteCardMeta>>(HashMap::new());
let (selected_cards, set_selected_cards) = signal::<Vec<WhiteCardMeta>>(vec![]);
let (submitted_cards, set_submitted_cards) = signal::<HashSet<WhiteCardMeta>>(HashSet::new());
let (card_clicked, set_card_clicked) = signal::<String>(String::new());
let (submitted, set_submitted) = signal(false);
let (player_hand, set_player_hand) = signal::<HashMap<String, WhiteCardMeta>>(HashMap::new());
// Outoging
provide_context::<WriteSignal<String>>(set_card_clicked);
@ -27,7 +25,7 @@ pub fn PlayingView() -> impl IntoView {
// On Incoming Meta //
// Put cards in a map for easier lookup
// The server sends a vec to preserve ordering
create_effect(move |_| {
Effect::new(move |_| {
if game_state().is_some() {
for card in game_state().unwrap().white {
set_player_hand.update(|map| {
@ -46,7 +44,7 @@ pub fn PlayingView() -> impl IntoView {
// Card selection
// Toggle selected status of cards
create_effect(move |_| {
Effect::new(move |_| {
if card_clicked() != "".to_string()
&& !submitted()
&& submitted_cards().len() < game_state().unwrap().black.1.into()
@ -102,15 +100,12 @@ pub fn PlayingView() -> impl IntoView {
<div class="w-full inline-flex flex-wrap">
<BlackCard />
// Selected cards
<For
each=move || selected_cards()
key=move |card| card.uuid.clone()
children=move |card| {
{move || selected_cards()
.into_iter()
.map(|card| {
view! { <WhiteCard card_data=card /> }
}
/>
})
.collect_view()}
</div>
// Submit button
@ -130,13 +125,15 @@ pub fn PlayingView() -> impl IntoView {
// Player hand
<div class="inline-flex flex-wrap justify-center">
<Show when=move || game_state().is_some()>
<For
each=move || game_state().unwrap().white
key=move |card| card.uuid.clone()
children=move |card| {
<Show when=move || {
game_state().is_some()
}>
{game_state()
.unwrap()
.white
.into_iter()
.map(|card| {
view! {
// Hide cards from hand view when they exist as selected or submitted
<Show when={
let id = card.uuid.clone();
move || {
@ -151,10 +148,9 @@ pub fn PlayingView() -> impl IntoView {
<WhiteCard card_data=card.clone() />
</Show>
}
}
/>
})
.collect_view()}
</Show>
</div>
}
}

View file

@ -1,26 +1,26 @@
use codee::string::FromToStringCodec;
use leptos::*;
use leptos::prelude::*;
use leptos_use::{core::ConnectionReadyState, use_websocket, UseWebSocketReturn};
use lib::*;
use serde_json::from_str;
use std::rc::Rc;
use std::sync::Arc;
#[derive(Clone)]
pub struct WebSocketContext {
pub ready_state: Signal<ConnectionReadyState>,
// pub message: Signal<Option<String>>,
send: Rc<dyn Fn(&String)>,
pub open: Rc<dyn Fn()>,
pub close: Rc<dyn Fn()>,
send: Arc<dyn Fn(&String) + Send + Sync + 'static>,
pub open: Arc<dyn Fn() + Send + Sync + 'static>,
pub close: Arc<dyn Fn() + Send + Sync + 'static>,
}
impl WebSocketContext {
pub fn new(
ready_state: Signal<ConnectionReadyState>,
// message: Signal<Option<String>>,
send: Rc<dyn Fn(&String)>,
open: Rc<dyn Fn()>,
close: Rc<dyn Fn()>,
send: Arc<dyn Fn(&String) + Send + Sync + 'static>,
open: Arc<dyn Fn() + Send + Sync + 'static>,
close: Arc<dyn Fn() + Send + Sync + 'static>,
) -> Self {
Self {
ready_state,
@ -59,38 +59,37 @@ pub fn Websocket() -> impl IntoView {
provide_context(WebSocketContext::new(
ready_state,
// message,
Rc::new(send.clone()),
Rc::new(open.clone()),
Rc::new(close.clone()),
Arc::new(send.clone()),
Arc::new(open.clone()),
Arc::new(close.clone()),
));
let connected = move || ready_state.get() == ConnectionReadyState::Open;
// Contexts for message handler
// TODO: This context stuff can probably be done better
let (state_summary, set_state_summary) =
create_signal::<Option<ServerStateSummary>>(Option::None);
let (active_games, set_active_games) = create_signal::<Vec<GameBrowserMeta>>(vec![]);
let (user_update, set_user_update) = create_signal::<Option<UserUpdate>>(Option::None);
let (chat_update, set_chat_update) = create_signal::<Option<ChatUpdate>>(Option::None);
let (judge_round, set_judge_round) = create_signal::<Option<JudgeRound>>(Option::None);
let (chat_message, set_chat_message) = create_signal::<Option<ChatMessage>>(Option::None);
let (game_meta, set_game_meta) = create_signal::<Option<GameMeta>>(Option::None);
let (game_state, set_game_state) = create_signal::<Option<GameStateMeta>>(Option::None);
let (card_packs_meta, set_card_packs_meta) = create_signal::<CardPacksMeta>(CardPacksMeta {
let (state_summary, set_state_summary) = signal::<Option<ServerStateSummary>>(Option::None);
let (active_games, set_active_games) = signal::<Vec<GameBrowserMeta>>(vec![]);
let (user_update, set_user_update) = signal::<Option<UserUpdate>>(Option::None);
let (chat_update, set_chat_update) = signal::<Option<ChatUpdate>>(Option::None);
let (judge_round, set_judge_round) = signal::<Option<JudgeRound>>(Option::None);
let (chat_message, set_chat_message) = signal::<Option<ChatMessage>>(Option::None);
let (game_meta, set_game_meta) = signal::<Option<GameMeta>>(Option::None);
let (game_state, set_game_state) = signal::<Option<GameStateMeta>>(Option::None);
let (card_packs_meta, set_card_packs_meta) = signal::<CardPacksMeta>(CardPacksMeta {
official_meta: vec![],
unofficial_meta: vec![],
});
create_effect(move |_| {
Effect::new(move |_| {
if !connected() {
set_active_games.set_untracked(vec![]);
set_user_update.set_untracked(None);
set_chat_update.set_untracked(None);
set_judge_round.set_untracked(None);
set_chat_message.set_untracked(None);
set_game_meta.set_untracked(None);
set_game_state.set_untracked(None);
set_active_games(vec![]);
set_user_update(None);
set_chat_update(None);
set_judge_round(None);
set_chat_message(None);
set_game_meta(None);
set_game_state(None);
}
});
@ -106,7 +105,7 @@ pub fn Websocket() -> impl IntoView {
provide_context::<ReadSignal<Option<ServerStateSummary>>>(state_summary);
// Message handler
create_effect(move |_| {
Effect::new(move |_| {
message.with(move |message_raw| {
if let Some(message) = message_raw {
if let Ok(state_summary) = from_str::<ServerStateSummary>(message) {
@ -128,7 +127,7 @@ pub fn Websocket() -> impl IntoView {
} else if let Ok(judge_update) = from_str::<JudgeRound>(message) {
set_judge_round(Some(judge_update));
} else {
logging::error!("Unhandled message: {:#?}", message);
println!("Unhandled message: {:#?}", message);
}
}
});

View file

@ -1,6 +1,8 @@
use leptos::*;
use leptos_meta::*;
use leptos_router::*;
use leptos::prelude::*;
use leptos_router::{
components::{Route, Router, Routes},
StaticSegment,
};
// Modules
mod components;
@ -8,28 +10,14 @@ mod pages;
// Top-Level pages
use crate::pages::home::Home;
use crate::pages::not_found::NotFound;
/// An app router which renders the homepage and handles 404's
#[component]
pub fn App() -> impl IntoView {
// Provides context that manages stylesheets, titles, meta tags, etc.
provide_meta_context();
view! {
<Html class="bg-neutral-900" lang="en" dir="ltr" attr:data-theme="dark" />
// sets the document title
<Title text="Cards for Humanity" />
// injects metadata in the <head> of the page
<Meta charset="UTF-8" />
<Meta name="viewport" content="width=device-width, initial-scale=1.0" />
<Router>
<Routes>
<Route path="/" view=Home />
<Route path="/*" view=NotFound />
<Routes fallback=|| "Not found.".into_view()>
<Route path=StaticSegment("") view=Home />
</Routes>
</Router>
}

View file

@ -1,12 +1,6 @@
use leptos::*;
use client::App;
fn main() {
// set up logging
_ = console_log::init_with_level(log::Level::Debug);
console_error_panic_hook::set_once();
mount_to_body(|| {
view! { <App /> }
})
leptos::mount::mount_to_body(App)
}

View file

@ -5,11 +5,15 @@ use crate::components::create_game::*;
use crate::components::debug::*;
use crate::components::game::*;
use crate::components::websocket::*;
use leptos::*;
use leptos::prelude::*;
use thaw::*;
/// Default Home Page
#[component]
pub fn Home() -> impl IntoView {
let open = RwSignal::new(true);
let theme = RwSignal::new(Theme::dark());
view! {
<ErrorBoundary fallback=|errors| {
view! {
@ -33,18 +37,35 @@ pub fn Home() -> impl IntoView {
<div class="container m-auto">
<h1 class="mx-4 text-6xl inter-med text-neutral-200">"Cards For Humanity"</h1>
<div class="p-5 bg-neutral-950 rounded-3xl shadow-black shadow-xl">
<h1 class="text-4xl">Hey!</h1>
<br />
<p>
{"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 "}
<a href="mailto:adam@doordesk.net">adam@doordesk.net</a>
{". 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>
<br />
<ConfigProvider theme>
<Dialog open>
<DialogSurface>
<DialogBody>
<DialogTitle>"Hey!"</DialogTitle>
<DialogContent>
<p>
{"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 "}
<a href="mailto:adam@doordesk.net">adam@doordesk.net</a>
{". 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 |_| open.set(!open())
appearance=ButtonAppearance::Primary
>
"Got it"
</Button>
</DialogActions>
</DialogBody>
</DialogSurface>
</Dialog>
</ConfigProvider>
<Websocket />
<hr />
<Auth />
<hr />
<Browser />

View file

@ -1,4 +1,4 @@
use leptos::*;
use leptos::prelude::*;
/// 404 Not Found Page
#[component]