//! Combined application for lazy-loading admin interface.
//!
//! This module provides a unified app that serves both user and admin interfaces,
//! with the admin interface lazy-loaded to reduce initial WASM bundle size.
use leptos::prelude::*;
use leptos_meta::{MetaTags, Stylesheet, Title, provide_meta_context};
use leptos_router::{
ParamSegment, StaticSegment,
components::{Route, Router, Routes},
};
// Re-export user pages for inline route definitions
use chattyness_user_ui::pages::{HomePage, LoginPage, PasswordResetPage, ProfilePage, RealmPage, SignupPage, UserProfilePage};
// Lazy-load admin pages to split WASM bundle
// Each lazy function includes the admin CSS stylesheet for on-demand loading
#[lazy]
fn lazy_dashboard() -> AnyView {
view! {
}.into_any()
}
#[lazy]
fn lazy_login() -> AnyView {
view! {
}
.into_any()
}
#[lazy]
fn lazy_config() -> AnyView {
view! {
}.into_any()
}
#[lazy]
fn lazy_users() -> AnyView {
view! {
}.into_any()
}
#[lazy]
fn lazy_user_new() -> AnyView {
view! {
}.into_any()
}
#[lazy]
fn lazy_user_detail() -> AnyView {
view! {
}.into_any()
}
#[lazy]
fn lazy_staff() -> AnyView {
view! {
}.into_any()
}
#[lazy]
fn lazy_realms() -> AnyView {
view! {
}.into_any()
}
#[lazy]
fn lazy_realm_new() -> AnyView {
view! {
}.into_any()
}
#[lazy]
fn lazy_realm_detail() -> AnyView {
view! {
}.into_any()
}
#[lazy]
fn lazy_scenes() -> AnyView {
view! {
}.into_any()
}
#[lazy]
fn lazy_scene_new() -> AnyView {
view! {
}.into_any()
}
#[lazy]
fn lazy_scene_detail() -> AnyView {
view! {
}.into_any()
}
/// Admin loading fallback - shown on both server (SSR) and client until lazy content loads.
#[component]
fn AdminLoading() -> impl IntoView {
view! {
}
}
/// Macro to generate lazy admin route view functions.
/// Both SSR and client render the same Suspense structure initially.
/// On SSR: Suspense child is empty, so fallback always shows.
/// On client: Suspense child is the lazy content, which loads after hydration.
macro_rules! lazy_admin_view {
($name:ident, $lazy_fn:ident) => {
fn $name() -> impl IntoView {
view! {
{
// On server: empty content, Suspense shows fallback
// On client: lazy content loads after hydration
#[cfg(feature = "ssr")]
{ () }
#[cfg(feature = "hydrate")]
{ Suspend::new(async { $lazy_fn().await }) }
}
}
}
};
}
// Generate view functions for each admin route
lazy_admin_view!(admin_login_view, lazy_login);
lazy_admin_view!(admin_dashboard_view, lazy_dashboard);
lazy_admin_view!(admin_config_view, lazy_config);
lazy_admin_view!(admin_users_view, lazy_users);
lazy_admin_view!(admin_user_new_view, lazy_user_new);
lazy_admin_view!(admin_user_detail_view, lazy_user_detail);
lazy_admin_view!(admin_staff_view, lazy_staff);
lazy_admin_view!(admin_realms_view, lazy_realms);
lazy_admin_view!(admin_realm_new_view, lazy_realm_new);
lazy_admin_view!(admin_realm_detail_view, lazy_realm_detail);
lazy_admin_view!(admin_scenes_view, lazy_scenes);
lazy_admin_view!(admin_scene_new_view, lazy_scene_new);
lazy_admin_view!(admin_scene_detail_view, lazy_scene_detail);
/// Combined app state for unified SSR.
#[cfg(feature = "ssr")]
#[derive(Clone)]
pub struct CombinedAppState {
pub pool: sqlx::PgPool,
pub leptos_options: LeptosOptions,
}
#[cfg(feature = "ssr")]
impl axum::extract::FromRef for LeptosOptions {
fn from_ref(state: &CombinedAppState) -> Self {
state.leptos_options.clone()
}
}
#[cfg(feature = "ssr")]
impl axum::extract::FromRef for sqlx::PgPool {
fn from_ref(state: &CombinedAppState) -> Self {
state.pool.clone()
}
}
/// Combined shell for SSR.
pub fn combined_shell(options: LeptosOptions) -> impl IntoView {
view! {
}
}
/// Combined application component with lazy-loaded admin routes.
///
/// User routes are eagerly loaded, admin routes are lazy-loaded via LocalResource
/// to ensure consistent SSR/hydration (server renders fallback, client loads lazy content).
#[component]
pub fn CombinedApp() -> impl IntoView {
provide_meta_context();
view! {
// ==========================================
// User routes (eager loading)
// ==========================================
// ==========================================
// Admin routes (lazy loading)
// Server renders fallback, client loads lazy WASM after hydration.
// ==========================================
// Scene routes (must come before realm detail to match first)
// Realm detail (must come after more specific routes)
}
}