//#![allow(unused_imports)] //#![allow(dead_code)] //#![allow(unused_variables)] // Suppress leptos_router warnings about reactive signal access outside tracking context #![allow(clippy::redundant_closure)] //#![allow(unused_assignments)] //use crate::defs::{NAV_LINK_CLASS, ROUTES}; use crate::auth::AuthProvider; use crate::components::NavMenu; use crate::i18n::{I18nProvider, ThemeProvider}; use crate::pages::{AboutPage, DaisyUIPage, FeaturesDemoPage, HomePage, UserPage}; use crate::state::*; use crate::utils::make_popstate_effect; use leptos::children::Children; use leptos::prelude::*; use leptos_meta::{MetaTags, Title, provide_meta_context}; // use regex::Regex; use shared::{get_bundle, t}; use std::collections::HashMap; //// Wrapper component for consistent layout. #[component] fn Wrapper(children: Children) -> impl IntoView { view! { <>{children()} } } /// NotFoundPage component for 404s. #[component] fn NotFoundPage() -> impl IntoView { view! {
"Page not found."
} } /// Main app component with SSR path awareness and SPA routing. #[component] pub fn App(#[prop(default = String::new())] _initial_path: String) -> impl IntoView { provide_meta_context(); // Always start with HOME during SSR, then route to correct page on client let (path, set_path) = signal("/".to_string()); make_popstate_effect(set_path); // Update path from URL after hydration (client-side redirect) #[cfg(target_arch = "wasm32")] { use wasm_bindgen_futures::spawn_local; spawn_local(async move { if let Some(win) = web_sys::window() { let current_path = win .location() .pathname() .unwrap_or_else(|_| "/".to_string()); // If URL path is different from home, redirect to it if current_path != "/" { web_sys::console::log_1( &format!("Client-side redirect to: {}", current_path).into(), ); set_path.set(current_path); } } }); } let (lang, _set_lang) = signal("en".to_string()); // --- Unit test placeholder for route matching --- // #[cfg(test)] // mod tests { // use super::*; // #[test] // fn test_user_route() { // let re = Regex::new(r"^/user/(\\d+)$").expect("Valid regex"); // assert!(re.is_match("/user/42")); // } // } view! { <header class="absolute inset-x-0 top-2 z-90 mx-2"> <Wrapper><NavMenu set_path=set_path /></Wrapper> </header> <div class="min-h-screen bg-gray-50 dark:bg-gray-900"> <main class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8"> { let lang = lang.clone(); let path = path.clone(); move || { let p = path.get(); let lang_val = lang.get(); let bundle = get_bundle(&lang_val).unwrap_or_else(|_| { // Fallback to a simple bundle if loading fails use fluent::FluentBundle; use unic_langid::LanguageIdentifier; let langid: LanguageIdentifier = "en".parse().unwrap_or_else(|e| { web_sys::console::error_1(&format!("Failed to parse default language 'en': {:?}", e).into()); // This should never happen, but create a minimal fallback LanguageIdentifier::from_parts( unic_langid::subtags::Language::from_bytes(b"en").unwrap_or_else(|e| { web_sys::console::error_1(&format!("Critical error: failed to create 'en' language: {:?}", e).into()); // Fallback to creating a new language identifier from scratch match "en".parse::<unic_langid::subtags::Language>() { Ok(lang) => lang, Err(_) => { // If even this fails, we'll use the default language web_sys::console::error_1(&"Using default language as final fallback".into()); unic_langid::subtags::Language::default() } } }), None, None, &[], ) }); FluentBundle::new(vec![langid]) }); let content = match p.as_str() { "/" => t(&bundle, "main-desc", None), "/about" => t(&bundle, "about-desc", None), "/user" => "User Dashboard".to_string(), "/daisyui" => "DaisyUI Components Demo".to_string(), "/features-demo" => "New Features Demo".to_string(), _ if p.starts_with("/user/") => { if let Some(id) = p.strip_prefix("/user/") { let mut args = HashMap::new(); args.insert("id", id); t(&bundle, "user-page", Some(&args)) } else { t(&bundle, "not-found", None) } }, _ => t(&bundle, "not-found", None), }; view! { <Wrapper> <div>{content}</div> {match p.as_str() { "/" => view! { <div><HomePage /></div> }.into_any(), "/about" => view! { <div><AboutPage /></div> }.into_any(), "/user" => view! { <div><UserPage /></div> }.into_any(), "/daisyui" => view! { <div><DaisyUIPage /></div> }.into_any(), "/features-demo" => view! { <div><FeaturesDemoPage /></div> }.into_any(), _ => view! { <div>Not found</div> }.into_any(), }} </Wrapper> } }} </main> </div> </AppStateProvider> </UserProvider> </AuthProvider> </ToastProvider> </I18nProvider> </ThemeProvider> </GlobalStateProvider> } } /// The SSR shell for Leptos/Axum integration. pub fn shell(options: LeptosOptions) -> impl IntoView { shell_with_path(options, None) } /// The SSR shell for Leptos/Axum integration with path support. pub fn shell_with_path(options: LeptosOptions, path: Option<String>) -> impl IntoView { view! { <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"/> <AutoReload options=options.clone() /> <HydrationScripts options/> <link rel="stylesheet" id="leptos" href="/public/website.css"/> <link rel="shortcut icon" type="image/ico" href="/favicon.ico"/> <MetaTags/> </head> <body> <App _initial_path=path.unwrap_or_default() /> </body> </html> } }