use leptos::prelude::*; use leptos::task::spawn_local; #[component] pub fn Sidebar() -> impl IntoView { let store = use_context::().expect("store not provided"); let is_mobile_menu_open = use_context::>().expect("mobile menu state not provided"); let total_count = move || store.torrents.with(|map| map.len()); let downloading_count = move || { store.torrents.with(|map| { map.values() .filter(|t| t.status == shared::TorrentStatus::Downloading) .count() }) }; let seeding_count = move || { store.torrents.with(|map| { map.values() .filter(|t| t.status == shared::TorrentStatus::Seeding) .count() }) }; let completed_count = move || { store.torrents.with(|map| { map.values() .filter(|t| { t.status == shared::TorrentStatus::Seeding || (t.status == shared::TorrentStatus::Paused && t.percent_complete >= 100.0) }) .count() }) }; let paused_count = move || { store.torrents.with(|map| { map.values() .filter(|t| t.status == shared::TorrentStatus::Paused) .count() }) }; let inactive_count = move || { store.torrents.with(|map| { map.values() .filter(|t| { t.status == shared::TorrentStatus::Paused || t.status == shared::TorrentStatus::Error }) .count() }) }; let set_filter = move |f: crate::store::FilterStatus| { store.filter.set(f); is_mobile_menu_open.set(false); }; let is_active = move |f: crate::store::FilterStatus| store.filter.get() == f; let username = move || { store.user.get().unwrap_or_else(|| "User".to_string()) }; let first_letter = move || { username().chars().next().unwrap_or('?').to_uppercase().to_string() }; view! {
"VibeTorrent"

"Filters"

// Separator
// Avatar
{first_letter}
{username}
"Online"
// Theme toggle button
// Logout button
} } #[component] fn SidebarButton( active: Signal, on_click: impl Fn(web_sys::MouseEvent) + 'static, #[prop(into)] icon: String, #[prop(into)] label: &'static str, count: Signal, ) -> impl IntoView { view! { } }