Compare commits

...

11 Commits

Author SHA1 Message Date
spinline
8fc3571848 fix: restore missing BASE64 import
All checks were successful
Build MIPS Binary / build (push) Successful in 1m51s
2026-02-14 02:23:08 +03:00
spinline
792b6bc97b fix: resolve toolbar syntax error and unused imports
Some checks failed
Build MIPS Binary / build (push) Failing after 34s
2026-02-14 02:20:53 +03:00
spinline
6efa6cd2d9 fix: resolve unused variable warning
Some checks failed
Build MIPS Binary / build (push) Failing after 45s
2026-02-14 02:18:45 +03:00
spinline
89caa17b92 fix: correct malformed import in multi_select.rs
Some checks failed
Build MIPS Binary / build (push) Failing after 46s
2026-02-14 02:16:53 +03:00
spinline
47bb60d7d8 fix: explicit type fixes for toolbar and multi_select
Some checks failed
Build MIPS Binary / build (push) Failing after 45s
2026-02-14 02:14:40 +03:00
spinline
7730250b61 fix: resolve updated compilation errors
Some checks failed
Build MIPS Binary / build (push) Failing after 45s
2026-02-14 02:11:58 +03:00
spinline
73d111124a refactor: simplify toolbar toggle button structure
Some checks failed
Build MIPS Binary / build (push) Failing after 32s
2026-02-14 02:10:43 +03:00
spinline
670c5a653b fix: resolve type inference error in toolbar callback
Some checks failed
Build MIPS Binary / build (push) Failing after 40s
2026-02-14 02:09:12 +03:00
spinline
9394a56e7d fix: compile error in protected layout
Some checks failed
Build MIPS Binary / build (push) Failing after 45s
2026-02-14 02:07:43 +03:00
spinline
105388eec3 feat: refine responsive sidebar behavior with auto-collapse
Some checks failed
Build MIPS Binary / build (push) Failing after 30s
2026-02-14 02:06:20 +03:00
spinline
f5d9cb642c feat: implement collapsible sidebar
Some checks failed
Build MIPS Binary / build (push) Failing after 34s
2026-02-14 01:57:40 +03:00
11 changed files with 81 additions and 31 deletions

View File

@@ -1,4 +1,4 @@
use leptos::prelude::*;
// use leptos::prelude::*;
pub fn use_random_id_for(prefix: &str) -> String {
format!("{}_{}", prefix, js_sys::Math::random().to_string().replace(".", ""))

View File

@@ -3,20 +3,53 @@ use crate::components::layout::sidebar::Sidebar;
use crate::components::layout::toolbar::Toolbar;
use crate::components::layout::footer::Footer;
use crate::components::ui::sidenav::{SidenavWrapper, Sidenav, SidenavInset};
use wasm_bindgen::JsCast;
#[component]
pub fn Protected(children: Children) -> impl IntoView {
let (collapsed, set_collapsed) = signal(false);
// Responsive Sidebar Logic
Effect::new(move |_| {
let window = web_sys::window().expect("window missing");
// Initial check
let width = window.inner_width().unwrap().as_f64().unwrap_or(1920.0);
if width < 1280.0 {
set_collapsed.set(true);
} else {
set_collapsed.set(false);
}
// Listener
let closure = wasm_bindgen::closure::Closure::<dyn FnMut(_)>::new(move |_: web_sys::Event| {
let window = web_sys::window().expect("window missing");
let width = window.inner_width().unwrap().as_f64().unwrap_or(1920.0);
if width < 1280.0 {
set_collapsed.set(true);
} else {
set_collapsed.set(false);
}
});
let _ = window.add_event_listener_with_callback("resize", closure.as_ref().unchecked_ref());
closure.forget(); // Leak memory intentionally for global listener (or store in a cleanup handle if needed, but for layout component it's fine)
});
view! {
<SidenavWrapper attr:style="--sidenav-width:16rem; --sidenav-width-icon:3rem;">
// Masaüstü Sidenav
<Sidenav>
<Sidenav
data_collapsible=crate::components::ui::sidenav::SidenavCollapsible::Icon
data_state=if collapsed.get() { crate::components::ui::sidenav::SidenavState::Collapsed } else { crate::components::ui::sidenav::SidenavState::Expanded }
>
<Sidebar />
</Sidenav>
// İçerik Alanı
<SidenavInset class="flex flex-col h-screen overflow-hidden">
// Toolbar (Üst Bar)
<Toolbar />
<Toolbar on_toggle_sidebar=Callback::new(move |_| set_collapsed.update(|c| *c = !*c)) />
// Ana İçerik
<main class="flex-1 overflow-y-auto relative bg-background flex flex-col">

View File

@@ -87,7 +87,7 @@ pub fn Sidebar() -> impl IntoView {
<path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0112 21 8.25 8.25 0 016.038 7.048 8.287 8.287 0 009 9.6a8.983 8.983 0 013.361-6.867 8.21 8.25 0 003 2.48z" />
</svg>
</div>
<div class="grid flex-1 text-left text-sm leading-tight overflow-hidden">
<div class="grid flex-1 text-left text-sm leading-tight overflow-hidden group-data-[state=Collapsed]:hidden">
<span class="truncate font-semibold text-foreground text-base">"VibeTorrent"</span>
<span class="truncate text-[10px] text-muted-foreground opacity-70">"v3.0.0"</span>
</div>
@@ -150,26 +150,28 @@ pub fn Sidebar() -> impl IntoView {
<div class="flex flex-col gap-4 p-4">
// Push Notification Toggle
<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">
<div class="flex flex-col gap-0.5 group-data-[state=Collapsed]:hidden">
<span class="text-[10px] font-bold uppercase tracking-wider text-foreground/70">"Bildirimler"</span>
<span class="text-[9px] text-muted-foreground">"Web Push"</span>
</div>
<Switch
checked=Signal::from(store.push_enabled)
on_checked_change=Callback::new(on_push_toggle)
/>
<div class="group-data-[state=Collapsed]:hidden">
<Switch
checked=Signal::from(store.push_enabled)
on_checked_change=Callback::new(on_push_toggle)
/>
</div>
</div>
<div class="flex items-center gap-3 p-2 rounded-lg border bg-muted/30 shadow-xs overflow-hidden">
<div class="flex items-center gap-3 p-2 rounded-lg border bg-muted/30 shadow-xs overflow-hidden group-data-[state=Collapsed]:gap-0 group-data-[state=Collapsed]:justify-center group-data-[state=Collapsed]:p-0 group-data-[state=Collapsed]:border-none group-data-[state=Collapsed]:bg-transparent group-data-[state=Collapsed]:shadow-none">
<div class="h-8 w-8 rounded-full bg-primary text-primary-foreground flex items-center justify-center text-xs font-medium shrink-0 border border-primary-foreground/10">
{first_letter}
</div>
<div class="flex-1 overflow-hidden">
<div class="flex-1 overflow-hidden group-data-[state=Collapsed]:hidden">
<div class="font-medium text-[11px] truncate text-foreground leading-tight">{username}</div>
<div class="text-[9px] text-muted-foreground truncate opacity-70">"Yönetici"</div>
</div>
<div class="flex items-center gap-1">
<div class="flex items-center gap-1 group-data-[state=Collapsed]:hidden">
<ThemeToggle />
<Button
@@ -217,8 +219,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">
<path stroke-linecap="round" stroke-linejoin="round" d=icon.clone() />
</svg>
<span class="flex-1 truncate">{label}</span>
<span class="text-[10px] font-mono opacity-50">{count}</span>
<span class="flex-1 truncate group-data-[state=Collapsed]:hidden">{label}</span>
<span class="text-[10px] font-mono opacity-50 group-data-[state=Collapsed]:hidden">{count}</span>
</SidenavMenuButton>
</SidenavMenuItem>
}

View File

@@ -1,24 +1,38 @@
use leptos::prelude::*;
use icons::{PanelLeft, Plus};
use crate::components::torrent::add_torrent::AddTorrentDialogContent;
use crate::components::ui::button::{ButtonVariant, ButtonSize};
use crate::components::ui::button::{Button, ButtonVariant, ButtonSize};
use crate::components::ui::sheet::{Sheet, SheetContent, SheetTrigger, SheetDirection};
use crate::components::ui::dialog::{Dialog, DialogContent, DialogTrigger};
use crate::components::layout::sidebar::Sidebar;
#[component]
pub fn Toolbar() -> impl IntoView {
pub fn Toolbar(
on_toggle_sidebar: Callback<()>,
) -> impl IntoView {
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);">
// Sol kısım: Menü butonu (Mobil) + Add Torrent
<div class="flex items-center gap-3">
// Desktop Toggle
<div class="hidden lg:block">
<Button
variant=ButtonVariant::Ghost
size=ButtonSize::Icon
class="size-9"
on:click=move |_| { on_toggle_sidebar.run(()); }
>
<PanelLeft class="size-5" />
<span class="hidden">"Toggle Sidebar"</span>
</Button>
</div>
// --- MOBILE SHEET (SIDEBAR) ---
// Mobile Toggle (Sheet)
<div class="lg:hidden">
<Sheet>
<SheetTrigger variant=ButtonVariant::Ghost size=ButtonSize::Icon class="size-9">
<PanelLeft class="size-5" />
<span class="hidden">"Menüyü Aç"</span>
<span class="hidden">"Open Menu"</span>
</SheetTrigger>
<SheetContent
direction=SheetDirection::Left

View File

@@ -139,7 +139,7 @@ pub fn ContextMenuTrigger(
class=trigger_class
data-name="ContextMenuTrigger"
data-context-trigger=ctx.target_id
on:contextmenu=move |e: web_sys::MouseEvent| {
on:contextmenu=move |_e: web_sys::MouseEvent| {
if let Some(cb) = on_open {
cb.run(());
}

View File

@@ -1,6 +1,6 @@
// * Reuse @table.rs
pub use crate::components::ui::table::{
Table as DataTable, TableBody as DataTableBody, TableCaption as DataTableCaption, TableCell as DataTableCell,
TableFooter as DataTableFooter, TableHead as DataTableHead, TableHeader as DataTableHeader,
Table as DataTable, TableBody as DataTableBody, TableCell as DataTableCell,
TableHead as DataTableHead, TableHeader as DataTableHeader,
TableRow as DataTableRow, TableWrapper as DataTableWrapper,
};

View File

@@ -5,7 +5,7 @@ use leptos_ui::clx;
use tw_merge::*;
use crate::components::hooks::use_random::use_random_id_for;
pub use crate::components::ui::separator::Separator as DropdownMenuSeparator;
// pub use crate::components::ui::separator::Separator as DropdownMenuSeparator;
mod components {
use super::*;

View File

@@ -9,7 +9,7 @@ use crate::components::hooks::use_can_scroll_vertical::use_can_scroll_vertical;
use crate::components::hooks::use_random::use_random_id_for;
// * Reuse @select.rs
pub use crate::components::ui::select::{
SelectGroup as MultiSelectGroup, SelectItem as MultiSelectItem, SelectLabel as MultiSelectLabel,
SelectGroup as MultiSelectGroup, SelectItem as MultiSelectItem,
};
#[derive(Clone, Copy, PartialEq, Eq, Default)]

View File

@@ -16,7 +16,7 @@ mod components {
clx! {SheetFooter, footer, "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end"}
}
pub use components::*;
// pub use components::*;
/* ========================================================== */
/* ✨ CONTEXT ✨ */

View File

@@ -145,7 +145,8 @@ pub fn Sidenav(
data-name="Sidenav"
data-sidenav=data_state.to_string()
data-side=data_side.to_string()
class="hidden md:block group peer text-sidenav-foreground data-[state=Collapsed]:hidden"
data-collapsible=data_collapsible.to_string()
class="hidden md:block group peer text-sidenav-foreground group-data-[collapsible=Offcanvas]:data-[state=Collapsed]:hidden"
>
// * SidenavGap: This is what handles the sidenav gap on desktop
<div
@@ -155,9 +156,9 @@ pub fn Sidenav(
"group-data-[collapsible=Offcanvas]:w-0",
"group-data-[side=Right]:rotate-180",
match variant {
SidenavVariant::Sidenav => "group-data-[collapsible=Icon]:w-(--sidenav-width-icon)",
SidenavVariant::Sidenav => "group-data-[collapsible=Icon]:group-data-[state=Collapsed]:w-(--sidenav-width-icon)",
SidenavVariant::Floating | SidenavVariant::Inset =>
"group-data-[collapsible=Icon]:w-[calc(var(--sidenav-width-icon)+(--spacing(4)))]",
"group-data-[collapsible=Icon]:group-data-[state=Collapsed]:w-[calc(var(--sidenav-width-icon)+(--spacing(4)))]",
}
)
/>
@@ -171,9 +172,9 @@ pub fn Sidenav(
SidenavSide::Right => "right-0 group-data-[collapsible=Offcanvas]:right-[calc(var(--sidenav-width)*-1)]"
},
match variant {
SidenavVariant::Sidenav => "group-data-[collapsible=Icon]:w-(--sidenav-width-icon) group-data-[side=Left]:border-r group-data-[side=Right]:border-l",
SidenavVariant::Sidenav => "group-data-[collapsible=Icon]:group-data-[state=Collapsed]:w-(--sidenav-width-icon) group-data-[side=Left]:border-r group-data-[side=Right]:border-l",
SidenavVariant::Floating | SidenavVariant::Inset =>
"p-2 group-data-[collapsible=Icon]:w-[calc(var(--sidenav-width-icon)+(--spacing(4))+2px)]",
"p-2 group-data-[collapsible=Icon]:group-data-[state=Collapsed]:w-[calc(var(--sidenav-width-icon)+(--spacing(4))+2px)]",
},
)
>

View File

@@ -192,7 +192,7 @@ pub async fn subscribe_to_push_notifications() {
let key_array = js_sys::Uint8Array::from(&decoded_key[..]);
// 3. Prepare Options
let mut options = web_sys::PushSubscriptionOptionsInit::new();
let options = web_sys::PushSubscriptionOptionsInit::new();
options.set_user_visible_only(true);
options.set_application_server_key(&key_array.into());