Compare commits
2 Commits
c2ecce0324
...
99b4d9af1a
| Author | SHA1 | Date | |
|---|---|---|---|
| 99b4d9af1a | |||
| 462ca81a15 |
@@ -19,7 +19,6 @@ once_cell = "1.18.0"
|
|||||||
web-sys = "0.3.64"
|
web-sys = "0.3.64"
|
||||||
cfg-if = "1.0.0"
|
cfg-if = "1.0.0"
|
||||||
chrono = { version = "0.4.38", features = ["serde", "wasm-bindgen"] }
|
chrono = { version = "0.4.38", features = ["serde", "wasm-bindgen"] }
|
||||||
axum-login = "0.15.3"
|
|
||||||
password-auth = "1.0.0"
|
password-auth = "1.0.0"
|
||||||
lazy_static = "1.5"
|
lazy_static = "1.5"
|
||||||
|
|
||||||
|
|||||||
@@ -2,24 +2,51 @@ use lazy_static::lazy_static;
|
|||||||
use perseus::prelude::*;
|
use perseus::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sycamore::prelude::*;
|
use sycamore::prelude::*;
|
||||||
|
use web_sys::Event;
|
||||||
|
|
||||||
|
use crate::{state_enums::OpenState, templates::global_state::AppStateRx};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref LOGIN_FORM: Capsule<PerseusNodeType, LoginFormProps> = get_capsule();
|
pub static ref LOGIN_FORM: Capsule<PerseusNodeType, LoginFormProps> = get_capsule();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, ReactiveState)]
|
||||||
|
#[rx(alias = "LoginFormStateRx")]
|
||||||
|
struct LoginFormState {
|
||||||
|
username: String,
|
||||||
|
password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LoginFormProps {
|
||||||
|
pub remember_me: bool,
|
||||||
|
pub endpoint: String,
|
||||||
|
pub lost_password_url: Option<String>,
|
||||||
|
pub forgot_password_url: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[auto_scope]
|
#[auto_scope]
|
||||||
fn login_form_capsule<G: Html>(
|
fn login_form_capsule<G: Html>(
|
||||||
cx: Scope,
|
cx: Scope,
|
||||||
state: &LoginFormStateRx,
|
state: &LoginFormStateRx,
|
||||||
props: LoginFormProps,
|
props: LoginFormProps,
|
||||||
) -> View<G> {
|
) -> View<G> {
|
||||||
view! {
|
let close_modal = move |_event: Event| {
|
||||||
cx,
|
#[cfg(client)]
|
||||||
|
{
|
||||||
|
spawn_local_scoped(cx, async move {
|
||||||
|
let global_state = Reactor::<G>::from_cx(cx).get_global_state::<AppStateRx>(cx);
|
||||||
|
global_state.modals_open.login.set(OpenState::Closed)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
view! { cx,
|
||||||
div (class="overflow-x-hidden overflow-y-auto fixed h-modal md:h-full top-4 left-0 right-0 md:inset-0 z-50 justify-center items-center"){
|
div (class="overflow-x-hidden overflow-y-auto fixed h-modal md:h-full top-4 left-0 right-0 md:inset-0 z-50 justify-center items-center"){
|
||||||
div (class="relative w-full max-w-md px-4 h-full md:h-auto") {
|
div (class="relative md:mx-auto w-full md:w-1/2 lg:w-1/3 z-0 my-10") {
|
||||||
div (class="bg-white rounded-lg shadow relative dark:bg-gray-700"){
|
div (class="bg-white rounded-lg shadow relative dark:bg-gray-700"){
|
||||||
div (class="flex justify-end p-2"){
|
div (class="flex justify-end p-2"){
|
||||||
button (class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-800 dark:hover:text-white"){
|
button (on:click = close_modal, class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-800 dark:hover:text-white"){
|
||||||
"Back"
|
"Back"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,21 +82,6 @@ fn login_form_capsule<G: Html>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, ReactiveState)]
|
|
||||||
#[rx(alias = "LoginFormStateRx")]
|
|
||||||
struct LoginFormState {
|
|
||||||
username: String,
|
|
||||||
password: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct LoginFormProps {
|
|
||||||
pub remember_me: bool,
|
|
||||||
pub endpoint: String,
|
|
||||||
pub lost_password_url: Option<String>,
|
|
||||||
pub forgot_password_url: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_capsule<G: Html>() -> Capsule<G, LoginFormProps> {
|
pub fn get_capsule<G: Html>() -> Capsule<G, LoginFormProps> {
|
||||||
Capsule::build(Template::build("login_form").build_state_fn(get_build_state))
|
Capsule::build(Template::build("login_form").build_state_fn(get_build_state))
|
||||||
.empty_fallback()
|
.empty_fallback()
|
||||||
|
|||||||
97
src/components/header.rs
Normal file
97
src/components/header.rs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use perseus::prelude::*;
|
||||||
|
use sycamore::prelude::*;
|
||||||
|
use web_sys::Event;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
capsules::login_form::{LoginFormProps, LOGIN_FORM},
|
||||||
|
state_enums::{GameState, LoginState, OpenState},
|
||||||
|
templates::global_state::AppStateRx,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Prop)]
|
||||||
|
pub struct HeaderProps<'a> {
|
||||||
|
pub game: GameState,
|
||||||
|
pub title: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn Header<'a, G: Html>(cx: Scope<'a>, HeaderProps { game, title }: HeaderProps<'a>) -> View<G> {
|
||||||
|
// Get global state to get authentication info
|
||||||
|
let global_state = Reactor::<G>::from_cx(cx).get_global_state::<AppStateRx>(cx);
|
||||||
|
|
||||||
|
let handle_log_in = move |_event: Event| {
|
||||||
|
#[cfg(client)]
|
||||||
|
{
|
||||||
|
spawn_local_scoped(cx, async move {
|
||||||
|
let global_state = Reactor::<G>::from_cx(cx).get_global_state::<AppStateRx>(cx);
|
||||||
|
global_state.modals_open.login.set(OpenState::Open);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
view! { cx,
|
||||||
|
header {
|
||||||
|
div (class = "flex items-center justify-between w-full md:text-center h-20") {
|
||||||
|
div(class = "flex-1") {}
|
||||||
|
|
||||||
|
// Title
|
||||||
|
div(class = "text-gray-700 text-2xl font-semibold py-2") {
|
||||||
|
"Pool Elo - Season 1"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Login / register or user buttons
|
||||||
|
div(class = "flex-1 py-2") {(
|
||||||
|
match *global_state.auth.state.get() {
|
||||||
|
LoginState::NotAuthenticated => {
|
||||||
|
view! { cx,
|
||||||
|
button(class = "text-gray-900 bg-white border border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-100 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-gray-800 dark:text-white dark:border-gray-600 dark:hover:bg-gray-700 dark:hover:border-gray-600 dark:focus:ring-gray-700") {
|
||||||
|
"Register"
|
||||||
|
}
|
||||||
|
button(on:click = handle_log_in,class = "text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800") {
|
||||||
|
"Login"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LoginState::Authenticated => {
|
||||||
|
view! { cx,
|
||||||
|
div {
|
||||||
|
"Hello {username}!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Will only appear for a few seconds
|
||||||
|
LoginState::Unknown => {
|
||||||
|
view! { cx,
|
||||||
|
div (class = "px-5 py-2.5 me-2 mb-2"){
|
||||||
|
"Loading..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section(class = "flex-2") {
|
||||||
|
(match *global_state.modals_open.login.get() {
|
||||||
|
OpenState::Open => {
|
||||||
|
view! { cx,
|
||||||
|
(LOGIN_FORM.widget(cx, "",
|
||||||
|
LoginFormProps{
|
||||||
|
remember_me: true,
|
||||||
|
endpoint: "".to_string(),
|
||||||
|
lost_password_url: Some("".to_string()),
|
||||||
|
forgot_password_url: Some("".to_string()),
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OpenState::Closed => {
|
||||||
|
view!{ cx, }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
capsules::login_form::{LoginFormProps, LOGIN_FORM},
|
capsules::login_form::{LoginFormProps, LOGIN_FORM},
|
||||||
templates::global_state::{AppStateRx, LoginState},
|
components::header::{Header, HeaderProps},
|
||||||
|
state_enums::{GameState, LoginState},
|
||||||
|
templates::global_state::AppStateRx,
|
||||||
};
|
};
|
||||||
use perseus::prelude::*;
|
use perseus::prelude::*;
|
||||||
use sycamore::prelude::*;
|
use sycamore::prelude::*;
|
||||||
@@ -8,7 +10,8 @@ use web_sys::Event;
|
|||||||
|
|
||||||
#[derive(Prop)]
|
#[derive(Prop)]
|
||||||
pub struct LayoutProps<'a, G: Html> {
|
pub struct LayoutProps<'a, G: Html> {
|
||||||
pub _title: &'a str,
|
pub game: GameState,
|
||||||
|
pub title: &'a str,
|
||||||
pub children: Children<'a, G>,
|
pub children: Children<'a, G>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,86 +21,26 @@ pub struct LayoutProps<'a, G: Html> {
|
|||||||
pub fn Layout<'a, G: Html>(
|
pub fn Layout<'a, G: Html>(
|
||||||
cx: Scope<'a>,
|
cx: Scope<'a>,
|
||||||
LayoutProps {
|
LayoutProps {
|
||||||
_title: _,
|
game,
|
||||||
|
title,
|
||||||
children,
|
children,
|
||||||
}: LayoutProps<'a, G>,
|
}: LayoutProps<'a, G>,
|
||||||
) -> View<G> {
|
) -> View<G> {
|
||||||
let children = children.call(cx);
|
let children = children.call(cx);
|
||||||
|
|
||||||
// Get global state to get authentication info
|
// Get global state to get authentication info
|
||||||
|
#[cfg(client)]
|
||||||
let global_state = Reactor::<G>::from_cx(cx).get_global_state::<AppStateRx>(cx);
|
let global_state = Reactor::<G>::from_cx(cx).get_global_state::<AppStateRx>(cx);
|
||||||
|
|
||||||
// Check if the client is authenticated or not
|
// Check if the client is authenticated or not
|
||||||
#[cfg(client)]
|
#[cfg(client)]
|
||||||
global_state.auth.detect_state();
|
global_state.auth.detect_state();
|
||||||
|
|
||||||
// TODO -> move into function
|
|
||||||
let handle_log_in = move |_event: Event| {
|
|
||||||
#[cfg(client)]
|
|
||||||
{
|
|
||||||
spawn_local_scoped(cx, async move {
|
|
||||||
let global_state = Reactor::<G>::from_cx(cx).get_global_state::<AppStateRx>(cx);
|
|
||||||
global_state.auth.state.set(LoginState::Authenticated);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
view! { cx,
|
view! { cx,
|
||||||
// Main page header
|
// Main page header, including login functionality
|
||||||
header {
|
Header(game = game, title = title)
|
||||||
div (class = "flex items-center justify-between w-full md:text-center h-20") {
|
|
||||||
div(class = "flex-1") {}
|
|
||||||
div(class = "text-gray-700 text-2xl font-semibold py-2") {
|
|
||||||
"Pool Elo - Season 1"
|
|
||||||
}
|
|
||||||
|
|
||||||
div(class = "flex-1 py-2") {(
|
|
||||||
match *global_state.auth.state.get() {
|
|
||||||
LoginState::NotAuthenticated => {
|
|
||||||
view! { cx,
|
|
||||||
button(class = "text-gray-900 bg-white border border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-100 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-gray-800 dark:text-white dark:border-gray-600 dark:hover:bg-gray-700 dark:hover:border-gray-600 dark:focus:ring-gray-700") {
|
|
||||||
"Register"
|
|
||||||
}
|
|
||||||
button(on:click = handle_log_in,class = "text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800") {
|
|
||||||
"Login"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LoginState::Authenticated => {
|
|
||||||
view! { cx,
|
|
||||||
div {
|
|
||||||
"Hello {username}!"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Will only appear for a few seconds
|
|
||||||
LoginState::Unknown => {
|
|
||||||
view! { cx,
|
|
||||||
div (class = "px-5 py-2.5 me-2 mb-2"){
|
|
||||||
"Loading..."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
main(style = "my-8") {
|
main(style = "my-8") {
|
||||||
|
|
||||||
(
|
|
||||||
match *global_state.auth.state.get() {
|
|
||||||
LoginState::Authenticated => { view! { cx,
|
|
||||||
(LOGIN_FORM.widget(cx, "",
|
|
||||||
LoginFormProps{
|
|
||||||
remember_me: true,
|
|
||||||
endpoint: "".to_string(),
|
|
||||||
lost_password_url: Some("".to_string()),
|
|
||||||
forgot_password_url: Some("".to_string())
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}},
|
|
||||||
_ => { view! { cx, div {} } }})
|
|
||||||
|
|
||||||
// Body header
|
// Body header
|
||||||
div {
|
div {
|
||||||
div (class = "container mx-auto px-6 py-3") {
|
div (class = "container mx-auto px-6 py-3") {
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
mod header;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ mod entity;
|
|||||||
mod error_views;
|
mod error_views;
|
||||||
#[cfg(engine)]
|
#[cfg(engine)]
|
||||||
mod server;
|
mod server;
|
||||||
|
mod state_enums;
|
||||||
mod templates;
|
mod templates;
|
||||||
|
|
||||||
use perseus::prelude::*;
|
use perseus::prelude::*;
|
||||||
|
|||||||
22
src/state_enums.rs
Normal file
22
src/state_enums.rs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub enum LoginState {
|
||||||
|
Authenticated,
|
||||||
|
NotAuthenticated,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub enum GameState {
|
||||||
|
None,
|
||||||
|
Pool,
|
||||||
|
Pickleball,
|
||||||
|
TableTennis,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub enum OpenState {
|
||||||
|
Open,
|
||||||
|
Closed,
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::components::layout::Layout;
|
use crate::{components::layout::Layout, state_enums::GameState};
|
||||||
use perseus::prelude::*;
|
use perseus::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sycamore::prelude::*;
|
use sycamore::prelude::*;
|
||||||
@@ -40,7 +40,7 @@ fn add_game_form_page<'a, G: Html>(cx: BoundedScope<'_, 'a>, state: &'a PageStat
|
|||||||
};
|
};
|
||||||
|
|
||||||
view! { cx,
|
view! { cx,
|
||||||
Layout(_title = "Add Game Results") {
|
Layout(title = "Add Game Results", game = GameState::Pool) {
|
||||||
div (class = "flex flex-wrap") {
|
div (class = "flex flex-wrap") {
|
||||||
select {
|
select {
|
||||||
option (value="red")
|
option (value="red")
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
use perseus::{prelude::*, state::GlobalStateCreator};
|
use perseus::{prelude::*, state::GlobalStateCreator};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::state_enums::{LoginState, OpenState};
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(engine)] {
|
if #[cfg(engine)] {
|
||||||
|
|
||||||
@@ -14,13 +16,8 @@ cfg_if::cfg_if! {
|
|||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
#[rx(nested)]
|
#[rx(nested)]
|
||||||
pub auth: AuthData,
|
pub auth: AuthData,
|
||||||
}
|
#[rx(nested)]
|
||||||
|
pub modals_open: ModalOpenData,
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
|
||||||
pub enum LoginState {
|
|
||||||
Authenticated,
|
|
||||||
NotAuthenticated,
|
|
||||||
Unknown,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, ReactiveState, Clone)]
|
#[derive(Serialize, Deserialize, ReactiveState, Clone)]
|
||||||
@@ -31,6 +28,12 @@ pub struct AuthData {
|
|||||||
pub claims: Claims,
|
pub claims: Claims,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, ReactiveState, Clone)]
|
||||||
|
#[rx(alias = "ModalOpenDataRx")]
|
||||||
|
pub struct ModalOpenData {
|
||||||
|
pub login: OpenState,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, ReactiveState, Clone)]
|
#[derive(Serialize, Deserialize, ReactiveState, Clone)]
|
||||||
#[rx(alias = "ClaimsRx")]
|
#[rx(alias = "ClaimsRx")]
|
||||||
pub struct Claims {}
|
pub struct Claims {}
|
||||||
@@ -47,6 +50,9 @@ pub async fn get_build_state() -> AppState {
|
|||||||
username: None,
|
username: None,
|
||||||
claims: Claims {},
|
claims: Claims {},
|
||||||
},
|
},
|
||||||
|
modals_open: ModalOpenData {
|
||||||
|
login: OpenState::Closed,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::components::layout::Layout;
|
use crate::{components::layout::Layout, state_enums::GameState};
|
||||||
use perseus::prelude::*;
|
use perseus::prelude::*;
|
||||||
use sycamore::prelude::*;
|
use sycamore::prelude::*;
|
||||||
|
|
||||||
fn index_page<G: Html>(cx: Scope) -> View<G> {
|
fn index_page<G: Html>(cx: Scope) -> View<G> {
|
||||||
view! { cx,
|
view! { cx,
|
||||||
Layout(_title = "Index") {
|
Layout(title = "Index", game = GameState::Pool) {
|
||||||
// Anything we put in here will be rendered inside the `<main>` block of the layout
|
// Anything we put in here will be rendered inside the `<main>` block of the layout
|
||||||
p { "Hello World!" }
|
p { "Hello World!" }
|
||||||
br {}
|
br {}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::components::layout::Layout;
|
use crate::{components::layout::Layout, state_enums::GameState};
|
||||||
use perseus::prelude::*;
|
use perseus::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sycamore::prelude::*;
|
use sycamore::prelude::*;
|
||||||
@@ -9,7 +9,7 @@ struct PageState {}
|
|||||||
|
|
||||||
fn one_v_one_board_page<'a, G: Html>(cx: BoundedScope<'_, 'a>, _state: &'a PageStateRx) -> View<G> {
|
fn one_v_one_board_page<'a, G: Html>(cx: BoundedScope<'_, 'a>, _state: &'a PageStateRx) -> View<G> {
|
||||||
view! { cx,
|
view! { cx,
|
||||||
Layout(_title = "1v1 Leaderboard") {
|
Layout(title = "1v1 Leaderboard", game = GameState::Pool) {
|
||||||
p { "leaderboard" }
|
p { "leaderboard" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
use crate::{components::layout::Layout, templates::global_state::AppStateRx};
|
use crate::{
|
||||||
|
components::layout::Layout, state_enums::GameState, templates::global_state::AppStateRx,
|
||||||
|
};
|
||||||
|
|
||||||
use perseus::prelude::*;
|
use perseus::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -12,7 +14,7 @@ fn overall_board_page<'a, G: Html>(cx: BoundedScope<'_, 'a>, _state: &'a PageSta
|
|||||||
let _global_state = Reactor::<G>::from_cx(cx).get_global_state::<AppStateRx>(cx);
|
let _global_state = Reactor::<G>::from_cx(cx).get_global_state::<AppStateRx>(cx);
|
||||||
|
|
||||||
view! { cx,
|
view! { cx,
|
||||||
Layout(_title = "Overall Leaderboard") {
|
Layout(title = "Overall Leaderboard", game = GameState::Pool) {
|
||||||
ul {
|
ul {
|
||||||
(View::new_fragment(
|
(View::new_fragment(
|
||||||
vec![],
|
vec![],
|
||||||
|
|||||||
Reference in New Issue
Block a user