feat: finalize shadcn integration with portal-based context menu and clean build
All checks were successful
Build MIPS Binary / build (push) Successful in 5m13s

This commit is contained in:
spinline
2026-02-10 23:16:13 +03:00
parent fddc81365b
commit 376615813b
15 changed files with 382 additions and 386 deletions

View File

@@ -5,28 +5,48 @@ use crate::components::layout::statusbar::StatusBar;
#[component]
pub fn Protected(children: Children) -> impl IntoView {
// Mobil menü durumu için bir sinyal oluşturuyoruz (RwSignal for easier passing)
let is_mobile_menu_open = RwSignal::new(false);
// Sinyali context olarak sağlıyoruz ki Toolbar ve Sidebar buna erişebilsin
provide_context(is_mobile_menu_open);
view! {
<div class="drawer lg:drawer-open h-full w-full">
<input id="my-drawer" type="checkbox" class="drawer-toggle" />
<div class="flex h-screen w-full overflow-hidden bg-background">
<div class="drawer-content flex flex-col h-full overflow-hidden bg-base-100">
// --- SIDEBAR (Desktop: Sabit, Mobil: Overlay) ---
<aside class=move || {
let base = "fixed inset-y-0 left-0 z-50 w-64 transform transition-transform duration-300 ease-in-out border-r border-border bg-card lg:relative lg:translate-x-0";
if is_mobile_menu_open.get() {
format!("{} translate-x-0", base)
} else {
format!("{} -translate-x-full", base)
}
}>
<Sidebar />
</aside>
// Mobil arka plan karartma (Overlay)
<Show when=move || is_mobile_menu_open.get()>
<div
class="fixed inset-0 z-40 bg-background/80 backdrop-blur-sm lg:hidden"
on:click=move |_| is_mobile_menu_open.set(false)
></div>
</Show>
// --- MAIN CONTENT AREA ---
<div class="flex flex-1 flex-col overflow-hidden">
// --- TOOLBAR (TOP) ---
<Toolbar />
// --- MAIN CONTENT ---
<main class="flex-1 overflow-hidden relative">
<main class="flex-1 overflow-hidden relative bg-background">
{children()}
</main>
// --- STATUS BAR (BOTTOM) ---
<StatusBar />
</div>
// --- SIDEBAR (DRAWER) ---
<div class="drawer-side z-[100]">
<label for="my-drawer" aria-label="close sidebar" class="drawer-overlay"></label>
<Sidebar />
</div>
</div>
}
}

View File

@@ -1,11 +1,10 @@
use leptos::prelude::*;
use leptos::wasm_bindgen::JsCast;
use leptos::task::spawn_local;
use crate::api;
#[component]
pub fn Sidebar() -> impl IntoView {
let store = use_context::<crate::store::TorrentStore>().expect("store not provided");
let is_mobile_menu_open = use_context::<RwSignal<bool>>().expect("mobile menu state not provided");
let total_count = move || store.torrents.with(|map| map.len());
let downloading_count = move || {
@@ -50,16 +49,9 @@ pub fn Sidebar() -> impl IntoView {
})
};
let close_drawer = move || {
// With Shadcn Sheet, this logic might change, but for now we keep DOM manipulation minimal or handled by parent
if let Some(element) = document().get_element_by_id("mobile-sheet-trigger") {
// Logic to close sheet if open (simulated click or state change)
}
};
let set_filter = move |f: crate::store::FilterStatus| {
store.filter.set(f);
close_drawer();
is_mobile_menu_open.set(false);
};
let filter_class = move |f: crate::store::FilterStatus| {
@@ -73,7 +65,7 @@ pub fn Sidebar() -> impl IntoView {
let handle_logout = move |_| {
spawn_local(async move {
if api::auth::logout().await.is_ok() {
if shared::server_fns::auth::logout().await.is_ok() {
let window = web_sys::window().expect("window should exist");
let _ = window.location().set_href("/login");
}
@@ -89,7 +81,7 @@ pub fn Sidebar() -> impl IntoView {
};
view! {
<div class="w-64 min-h-[100dvh] flex flex-col bg-card border-r border-border pb-8" style="padding-top: env(safe-area-inset-top);">
<div class="w-full h-full flex flex-col bg-card" style="padding-top: env(safe-area-inset-top);">
<div class="p-4 flex-1 overflow-y-auto">
<div class="mb-4 px-2 text-lg font-semibold tracking-tight text-foreground">
"VibeTorrent"
@@ -171,4 +163,4 @@ pub fn Sidebar() -> impl IntoView {
</div>
</div>
}
}
}

View File

@@ -5,12 +5,16 @@ use crate::components::torrent::add_torrent::AddTorrentDialog;
pub fn Toolbar() -> impl IntoView {
let show_add_modal = signal(false);
let store = use_context::<crate::store::TorrentStore>().expect("store not provided");
let is_mobile_menu_open = use_context::<RwSignal<bool>>().expect("mobile menu state not provided");
view! {
<div class="flex min-h-14 h-auto items-center border-b border-border bg-background px-4" style="padding-top: env(safe-area-inset-top);">
<div class="flex flex-1 items-center gap-4">
// Mobile Menu Trigger (Sheet Trigger in full impl)
<button id="mobile-sheet-trigger" class="lg:hidden inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground h-10 w-10">
// Mobile Menu Trigger
<button
on:click=move |_| is_mobile_menu_open.update(|v| *v = !*v)
class="lg:hidden inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground h-10 w-10"
>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="w-5 h-5 stroke-current"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path></svg>
</button>