fix: centralize sidenav state in store and resolve all component property issues
Some checks failed
Build MIPS Binary / build (push) Failing after 45s
Some checks failed
Build MIPS Binary / build (push) Failing after 45s
This commit is contained in:
@@ -1,23 +1,20 @@
|
|||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use crate::components::layout::sidebar::Sidebar;
|
use crate::components::layout::sidebar::Sidebar;
|
||||||
use crate::components::layout::toolbar::Toolbar;
|
use crate::components::layout::toolbar::Toolbar;
|
||||||
use crate::components::ui::sidenav::{SidenavWrapper, Sidenav, SidenavInset, SidenavState, SidenavCollapsible};
|
use crate::components::ui::sidenav::{SidenavWrapper, Sidenav, SidenavInset};
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn ProtectedLayout(children: Children) -> impl IntoView {
|
pub fn ProtectedLayout(children: Children) -> impl IntoView {
|
||||||
let sidenav_state = RwSignal::new(SidenavState::Expanded);
|
let store = use_context::<crate::store::TorrentStore>().expect("store not provided");
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<SidenavWrapper attr:style="--sidenav-width:16rem; --sidenav-width-icon:3.5rem;">
|
<SidenavWrapper attr:style="--sidenav-width:16rem; --sidenav-width-icon:4rem;">
|
||||||
<Sidenav
|
<Sidenav data_state=Signal::from(store.sidenav_state)>
|
||||||
data_state=Signal::from(sidenav_state)
|
|
||||||
data_collapsible=SidenavCollapsible::Icon
|
|
||||||
>
|
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
</Sidenav>
|
</Sidenav>
|
||||||
|
|
||||||
<SidenavInset class="flex flex-col h-screen overflow-hidden">
|
<SidenavInset class="flex flex-col h-screen overflow-hidden">
|
||||||
<Toolbar sidenav_state=sidenav_state />
|
<Toolbar sidenav_state=store.sidenav_state />
|
||||||
<main class="flex-1 overflow-auto bg-muted/30">
|
<main class="flex-1 overflow-auto bg-muted/30">
|
||||||
{children()}
|
{children()}
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -109,9 +109,48 @@ pub fn Sidebar() -> impl IntoView {
|
|||||||
icon="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
|
icon="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
|
||||||
label="Tümü"
|
label="Tümü"
|
||||||
count=Signal::derive(total_count)
|
count=Signal::derive(total_count)
|
||||||
is_collapsed=is_collapsed.into()
|
is_collapsed=is_collapsed
|
||||||
|
/>
|
||||||
|
<SidebarItem
|
||||||
|
active=Signal::derive(move || is_active(crate::store::FilterStatus::Downloading))
|
||||||
|
on_click=move |_| set_filter(crate::store::FilterStatus::Downloading)
|
||||||
|
icon="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3"
|
||||||
|
label="İndirilenler"
|
||||||
|
count=Signal::derive(downloading_count)
|
||||||
|
is_collapsed=is_collapsed
|
||||||
|
/>
|
||||||
|
<SidebarItem
|
||||||
|
active=Signal::derive(move || is_active(crate::store::FilterStatus::Seeding))
|
||||||
|
on_click=move |_| set_filter(crate::store::FilterStatus::Seeding)
|
||||||
|
icon="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5"
|
||||||
|
label="Gönderilenler"
|
||||||
|
count=Signal::derive(seeding_count)
|
||||||
|
is_collapsed=is_collapsed
|
||||||
|
/>
|
||||||
|
<SidebarItem
|
||||||
|
active=Signal::derive(move || is_active(crate::store::FilterStatus::Completed))
|
||||||
|
on_click=move |_| set_filter(crate::store::FilterStatus::Completed)
|
||||||
|
icon="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
|
label="Tamamlananlar"
|
||||||
|
count=Signal::derive(completed_count)
|
||||||
|
is_collapsed=is_collapsed
|
||||||
|
/>
|
||||||
|
<SidebarItem
|
||||||
|
active=Signal::derive(move || is_active(crate::store::FilterStatus::Paused))
|
||||||
|
on_click=move |_| set_filter(crate::store::FilterStatus::Paused)
|
||||||
|
icon="M15.75 5.25v13.5m-7.5-13.5v13.5"
|
||||||
|
label="Durdurulanlar"
|
||||||
|
count=Signal::derive(paused_count)
|
||||||
|
is_collapsed=is_collapsed
|
||||||
|
/>
|
||||||
|
<SidebarItem
|
||||||
|
active=Signal::derive(move || is_active(crate::store::FilterStatus::Inactive))
|
||||||
|
on_click=move |_| set_filter(crate::store::FilterStatus::Inactive)
|
||||||
|
icon="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636"
|
||||||
|
label="Pasif"
|
||||||
|
count=Signal::derive(inactive_count)
|
||||||
|
is_collapsed=is_collapsed
|
||||||
/>
|
/>
|
||||||
// ... (aynı mantık diğer itemler için de geçerli olacak)
|
|
||||||
</SidenavMenu>
|
</SidenavMenu>
|
||||||
</SidenavGroupContent>
|
</SidenavGroupContent>
|
||||||
</SidenavGroup>
|
</SidenavGroup>
|
||||||
@@ -119,7 +158,6 @@ pub fn Sidebar() -> impl IntoView {
|
|||||||
|
|
||||||
<SidenavFooter>
|
<SidenavFooter>
|
||||||
<div class="flex flex-col gap-4 p-2">
|
<div class="flex flex-col gap-4 p-2">
|
||||||
// Push Toggle - Hide text when collapsed
|
|
||||||
<div class="flex items-center justify-between px-2 py-1 bg-muted/20 rounded-md border border-border/50">
|
<div class="flex items-center justify-between px-2 py-1 bg-muted/20 rounded-md border border-border/50">
|
||||||
<div class="flex flex-col gap-0.5" class:hidden=is_collapsed>
|
<div class="flex flex-col gap-0.5" class:hidden=is_collapsed>
|
||||||
<span class="text-[10px] font-bold uppercase tracking-wider text-foreground/70">"Bildirimler"</span>
|
<span class="text-[10px] font-bold uppercase tracking-wider text-foreground/70">"Bildirimler"</span>
|
||||||
@@ -169,15 +207,18 @@ pub fn Sidebar() -> impl IntoView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn SidebarItem(
|
fn SidebarItem<F>(
|
||||||
active: Signal<bool>,
|
active: Signal<bool>,
|
||||||
on_click: impl Fn(web_sys::MouseEvent) + 'static + Send,
|
on_click: F,
|
||||||
#[prop(into)] icon: String,
|
#[prop(into)] icon: String,
|
||||||
#[prop(into)] label: &'static str,
|
#[prop(into)] label: &'static str,
|
||||||
count: Signal<usize>,
|
count: Signal<usize>,
|
||||||
) -> impl IntoView {
|
#[prop(into)] is_collapsed: Signal<bool>,
|
||||||
|
) -> impl IntoView
|
||||||
|
where F: Fn(web_sys::MouseEvent) + 'static + Send
|
||||||
|
{
|
||||||
let variant = move || if active.get() { SidenavMenuButtonVariant::Outline } else { SidenavMenuButtonVariant::Default };
|
let variant = move || if active.get() { SidenavMenuButtonVariant::Outline } else { SidenavMenuButtonVariant::Default };
|
||||||
let class = move || if active.get() { "bg-accent/50 border-accent text-foreground".to_string() } else { "text-muted-foreground hover:text-foreground".to_string() };
|
let class = move || if active.get() { "bg-accent/50 border-accent text-foreground font-bold".to_string() } else { "text-muted-foreground hover:text-foreground".to_string() };
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<SidenavMenuItem>
|
<SidenavMenuItem>
|
||||||
@@ -189,8 +230,8 @@ fn SidebarItem(
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4 shrink-0">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4 shrink-0">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d=icon.clone() />
|
<path stroke-linecap="round" stroke-linejoin="round" d=icon.clone() />
|
||||||
</svg>
|
</svg>
|
||||||
<span class="flex-1 truncate">{label}</span>
|
<span class="flex-1 truncate" class:hidden=is_collapsed>{label}</span>
|
||||||
<span class="text-[10px] font-mono opacity-50">{count}</span>
|
<span class="text-[10px] font-mono opacity-50" class:hidden=is_collapsed>{count}</span>
|
||||||
</SidenavMenuButton>
|
</SidenavMenuButton>
|
||||||
</SidenavMenuItem>
|
</SidenavMenuItem>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64};
|
|||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
|
|
||||||
use crate::components::ui::toast::{ToastType, toast};
|
use crate::components::ui::toast::{ToastType, toast};
|
||||||
|
use crate::components::ui::sidenav::SidenavState;
|
||||||
|
|
||||||
pub fn show_toast(level: NotificationLevel, message: impl Into<String>) {
|
pub fn show_toast(level: NotificationLevel, message: impl Into<String>) {
|
||||||
let msg = message.into();
|
let msg = message.into();
|
||||||
@@ -55,6 +56,7 @@ pub struct TorrentStore {
|
|||||||
pub user: RwSignal<Option<String>>,
|
pub user: RwSignal<Option<String>>,
|
||||||
pub selected_torrent: RwSignal<Option<String>>,
|
pub selected_torrent: RwSignal<Option<String>>,
|
||||||
pub push_enabled: RwSignal<bool>,
|
pub push_enabled: RwSignal<bool>,
|
||||||
|
pub sidenav_state: RwSignal<SidenavState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn provide_torrent_store() {
|
pub fn provide_torrent_store() {
|
||||||
@@ -65,10 +67,11 @@ pub fn provide_torrent_store() {
|
|||||||
let user = RwSignal::new(Option::<String>::None);
|
let user = RwSignal::new(Option::<String>::None);
|
||||||
let selected_torrent = RwSignal::new(Option::<String>::None);
|
let selected_torrent = RwSignal::new(Option::<String>::None);
|
||||||
let push_enabled = RwSignal::new(false);
|
let push_enabled = RwSignal::new(false);
|
||||||
|
let sidenav_state = RwSignal::new(SidenavState::Expanded);
|
||||||
|
|
||||||
let show_browser_notification = crate::utils::notification::use_app_notification();
|
let show_browser_notification = crate::utils::notification::use_app_notification();
|
||||||
|
|
||||||
let store = TorrentStore { torrents, filter, search_query, global_stats, user, selected_torrent, push_enabled };
|
let store = TorrentStore { torrents, filter, search_query, global_stats, user, selected_torrent, push_enabled, sidenav_state };
|
||||||
provide_context(store);
|
provide_context(store);
|
||||||
|
|
||||||
// Initial check for push status
|
// Initial check for push status
|
||||||
@@ -134,7 +137,7 @@ pub fn provide_torrent_store() {
|
|||||||
}
|
}
|
||||||
if was_connected && !disconnect_notified {
|
if was_connected && !disconnect_notified {
|
||||||
show_toast(NotificationLevel::Warning, "Sunucu bağlantısı kesildi, yeniden bağlanılıyor...");
|
show_toast(NotificationLevel::Warning, "Sunucu bağlantısı kesildi, yeniden bağlanılıyor...");
|
||||||
disconnect_notified = true;
|
disconnect_notified = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,8 +156,7 @@ pub fn provide_torrent_store() {
|
|||||||
|
|
||||||
pub async fn is_push_subscribed() -> Result<bool, String> {
|
pub async fn is_push_subscribed() -> Result<bool, String> {
|
||||||
let window = web_sys::window().ok_or("no window")?;
|
let window = web_sys::window().ok_or("no window")?;
|
||||||
let navigator = window.navigator();
|
let sw_container = window.navigator().service_worker();
|
||||||
let sw_container = navigator.service_worker();
|
|
||||||
|
|
||||||
let registration = wasm_bindgen_futures::JsFuture::from(sw_container.ready().map_err(|e| format!("{:?}", e))?)
|
let registration = wasm_bindgen_futures::JsFuture::from(sw_container.ready().map_err(|e| format!("{:?}", e))?)
|
||||||
.await
|
.await
|
||||||
@@ -172,8 +174,7 @@ pub async fn is_push_subscribed() -> Result<bool, String> {
|
|||||||
|
|
||||||
pub async fn subscribe_to_push_notifications() {
|
pub async fn subscribe_to_push_notifications() {
|
||||||
let window = web_sys::window().expect("no window");
|
let window = web_sys::window().expect("no window");
|
||||||
let navigator = window.navigator();
|
let sw_container = window.navigator().service_worker();
|
||||||
let sw_container = navigator.service_worker();
|
|
||||||
|
|
||||||
let registration = match wasm_bindgen_futures::JsFuture::from(sw_container.ready().expect("sw not ready")).await {
|
let registration = match wasm_bindgen_futures::JsFuture::from(sw_container.ready().expect("sw not ready")).await {
|
||||||
Ok(reg) => reg.dyn_into::<web_sys::ServiceWorkerRegistration>().expect("not a reg"),
|
Ok(reg) => reg.dyn_into::<web_sys::ServiceWorkerRegistration>().expect("not a reg"),
|
||||||
@@ -181,8 +182,7 @@ pub async fn subscribe_to_push_notifications() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 1. Get Public Key from Backend
|
// 1. Get Public Key from Backend
|
||||||
let public_key_res: Result<String, _> = shared::server_fns::push::get_public_key().await;
|
let public_key = match shared::server_fns::push::get_public_key().await {
|
||||||
let public_key = match public_key_res {
|
|
||||||
Ok(key) => key,
|
Ok(key) => key,
|
||||||
Err(e) => { log::error!("Failed to get public key: {:?}", e); return; }
|
Err(e) => { log::error!("Failed to get public key: {:?}", e); return; }
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user