app.rs
⎇
Raw
1use leptos::prelude::*;
2use wasm_bindgen_futures::spawn_local;
3
4use crate::api::{self, Me};
5use crate::router::{Location, parse_location};
6
7#[derive(Clone, Copy, PartialEq, Debug)]
8pub enum AuthPhase {
9 Loading,
10 Setup,
11 Login,
12 Authed,
13}
14
15#[component]
16pub fn App() -> impl IntoView {
17 let (phase, set_phase) = signal(AuthPhase::Loading);
18 let (me, set_me) = signal(Option::<Me>::None);
19 let (loc, set_loc) = signal(Location::root());
20
21 // Tri-state theme (auto/light/dark): restore the persisted choice and
22 // apply it before first paint of the app UI.
23 let initial_theme = crate::theme::Theme::load();
24 initial_theme.apply();
25 let (theme, set_theme) = signal(initial_theme);
26
27 // The URL hash is the source of truth for the location.
28 {
29 set_loc.set(parse_location());
30 crate::util::owned_window_listener(leptos::ev::hashchange, move |_| {
31 set_loc.set(parse_location());
32 });
33 }
34
35 // Initial /me probe: first boot, signed in, or needs login.
36 spawn_local(async move {
37 match api::me().await {
38 Ok(m) => {
39 let first_boot = m.first_boot;
40 set_me.set(Some(m));
41 set_phase.set(if first_boot {
42 AuthPhase::Setup
43 } else {
44 AuthPhase::Authed
45 });
46 }
47 Err(_) => set_phase.set(AuthPhase::Login),
48 }
49 });
50
51 view! {
52 {move || {
53 // Public share links (`#/shares/{token}/...`) bypass the auth flow.
54 let loc_now = loc.get();
55 if let Some(token) = loc_now.share_token.clone() {
56 return view! {
57 <crate::views::share_page::ShareView token=token loc=loc/>
58 }
59 .into_view()
60 .into_any();
61 }
62 match phase.get() {
63 AuthPhase::Loading => view! {
64 <div class="center-screen">
65 <p class="muted">"Loading…"</p>
66 </div>
67 }
68 .into_view()
69 .into_any(),
70 AuthPhase::Setup => view! {
71 <crate::views::setup::SetupView set_me=set_me set_phase=set_phase/>
72 }
73 .into_view()
74 .into_any(),
75 AuthPhase::Login => view! {
76 <crate::views::login::LoginView set_me=set_me set_phase=set_phase/>
77 }
78 .into_view()
79 .into_any(),
80 AuthPhase::Authed => view! {
81 <crate::views::shell::ShellView
82 me=me
83 set_me=set_me
84 set_phase=set_phase
85 loc=loc
86 theme=theme
87 set_theme=set_theme
88 />
89 }
90 .into_view()
91 .into_any(),
92 }
93 }}
94 }
95}
96