//! The signed-in shell: left sidebar (folders + manage tabs) and the topbar. use leptos::prelude::*; use wasm_bindgen_futures::spawn_local; use crate::api::{self, Me}; use crate::components::icon::Icon; use crate::components::logo::Logo; use crate::components::toast::{ToastView, provide_toast}; use crate::icons::IconName; use crate::router::{Location, Section, navigate}; use crate::views::admin::{SettingsView, UsersView}; use crate::views::browser::{Browser, effective_root}; use crate::views::shares::SharesView; /// Whether the signed-in user has admin rights. fn is_admin_of(me: &Option) -> bool { me.as_ref() .and_then(|m| m.user.as_ref()) .is_some_and(|u| u.is_admin) } #[component] pub fn ShellView( me: ReadSignal>, set_me: WriteSignal>, set_phase: WriteSignal, loc: ReadSignal, theme: ReadSignal, set_theme: WriteSignal, ) -> impl IntoView { let toast = provide_toast(); // True while the off-canvas sidebar is open (narrow screens only). let (nav_open, set_nav_open) = signal(false); // A non-admin cannot open the admin sections. If the URL points at one // (deep link, hand-typed, or left over from a demotion), redirect to the // files view so the URL, the content fallback, and the sidebar highlight // all agree. { let me2 = me; let loc2 = loc; Effect::new(move |_| { let Some(m) = me2.get() else { return; }; let admin = m.user.as_ref().is_some_and(|u| u.is_admin); if admin { return; } let section = loc2.get().section; if section == Section::Users || section == Section::Settings { navigate(&Location::root()); } }); } let on_logout = move |_| { spawn_local(async move { let _ = api::logout().await; set_me.set(None); set_phase.set(crate::app::AuthPhase::Login); }); }; // Navigate to a manage section (each has its own URL) and, on narrow // screens, close the off-canvas sidebar. let open_section = move |section: Section| { set_nav_open.set(false); navigate(&Location { root_id: None, path: Vec::new(), share_token: None, section, }); }; view! {
"filebrowser-ng"
{move || { if nav_open.get() { view! { } .into_view() .into_any() } else { view! {}.into_any() } }}
{move || { let admin = is_admin_of(&me.get()); match loc.get().section { Section::Files => view! { } .into_view() .into_any(), Section::Shares => view! { } .into_view() .into_any(), Section::Users if admin => { view! { }.into_view().into_any() } Section::Settings if admin => { view! { }.into_view().into_any() } // Not an admin anymore (e.g. permissions changed): // fall back to the files view. _ => view! { } .into_view() .into_any(), } }}
} }