fix: fixed statusbar at bottom, fix dropdown toggle race, fix theme buttons on iOS

- StatusBar now uses fixed positioning at viewport bottom (z-[99])
- Dropdown toggle uses skip_next_close guard to prevent close-then-reopen
- Global close listener uses click instead of pointerdown (fires after toggle)
- Theme/limit buttons use on:pointerdown instead of on:click for iOS compat
- Main content has pb-8 to prevent overlap with fixed statusbar
- Rebuilt tailwind.css
This commit is contained in:
spinline
2026-02-06 17:17:07 +03:00
parent 2c25d3bdf1
commit 2a919211d9
3 changed files with 36 additions and 22 deletions

View File

@@ -1366,6 +1366,9 @@
.right-0 { .right-0 {
right: calc(var(--spacing) * 0); right: calc(var(--spacing) * 0);
} }
.bottom-0 {
bottom: calc(var(--spacing) * 0);
}
.bottom-full { .bottom-full {
bottom: 100%; bottom: 100%;
} }
@@ -2172,6 +2175,9 @@
.pt-1 { .pt-1 {
padding-top: calc(var(--spacing) * 1); padding-top: calc(var(--spacing) * 1);
} }
.pb-8 {
padding-bottom: calc(var(--spacing) * 8);
}
.pb-20 { .pb-20 {
padding-bottom: calc(var(--spacing) * 20); padding-bottom: calc(var(--spacing) * 20);
} }

View File

@@ -64,22 +64,19 @@ pub fn App() -> impl IntoView {
<div class="drawer lg:drawer-open h-full w-full"> <div class="drawer lg:drawer-open h-full w-full">
<input id="my-drawer" type="checkbox" class="drawer-toggle" /> <input id="my-drawer" type="checkbox" class="drawer-toggle" />
<div class="drawer-content flex flex-col h-full bg-base-100 text-base-content text-sm select-none"> <div class="drawer-content flex flex-col h-full overflow-hidden bg-base-100 text-base-content text-sm select-none">
// Toolbar + main wrapped so overflow-hidden doesn't clip StatusBar dropdowns <Toolbar />
<div class="flex-1 flex flex-col overflow-hidden">
<Toolbar />
<main class="flex-1 flex flex-col min-w-0 bg-base-100 overflow-hidden"> <main class="flex-1 flex flex-col min-w-0 bg-base-100 overflow-hidden pb-8">
<Router> <Router>
<Routes> <Routes>
<Route path="/" view=move || view! { <TorrentTable /> } /> <Route path="/" view=move || view! { <TorrentTable /> } />
<Route path="/settings" view=move || view! { <div class="p-4">"Settings Page (Coming Soon)"</div> } /> <Route path="/settings" view=move || view! { <div class="p-4">"Settings Page (Coming Soon)"</div> } />
</Routes> </Routes>
</Router> </Router>
</main> </main>
</div>
// Status Bar at the bottom - outside overflow-hidden so dropdowns can open upward // StatusBar is rendered via fixed positioning, just mount it here
<StatusBar /> <StatusBar />
</div> </div>

View File

@@ -111,13 +111,18 @@ pub fn StatusBar() -> impl IntoView {
// Signal-based dropdown state: 0=none, 1=download, 2=upload, 3=theme // Signal-based dropdown state: 0=none, 1=download, 2=upload, 3=theme
let (active_dropdown, set_active_dropdown) = create_signal(0u8); let (active_dropdown, set_active_dropdown) = create_signal(0u8);
// Guard to prevent global close from firing right after toggle opens
let skip_next_close = store_value(false);
// Toggle a specific dropdown // Toggle a specific dropdown
let toggle = move |id: u8| { let toggle = move |id: u8| {
if active_dropdown.get_untracked() == id { let current = active_dropdown.get_untracked();
if current == id {
set_active_dropdown.set(0); set_active_dropdown.set(0);
} else { } else {
set_active_dropdown.set(id); set_active_dropdown.set(id);
// Mark that the next global close should be skipped
skip_next_close.set_value(true);
} }
}; };
@@ -126,14 +131,17 @@ pub fn StatusBar() -> impl IntoView {
set_active_dropdown.set(0); set_active_dropdown.set(0);
}; };
// Close dropdowns when tapping outside // Close dropdowns when tapping outside — uses click (fires after pointerdown)
let _ = window_event_listener(ev::pointerdown, move |_| { let _ = window_event_listener(ev::click, move |_| {
// This fires first; dropdown buttons call stop_propagation to prevent closing if skip_next_close.get_value() {
skip_next_close.set_value(false);
return;
}
set_active_dropdown.set(0); set_active_dropdown.set(0);
}); });
view! { view! {
<div class="h-8 min-h-8 bg-base-200 border-t border-base-300 flex items-center px-4 text-xs gap-4 text-base-content/70"> <div class="fixed bottom-0 left-0 right-0 h-8 min-h-8 bg-base-200 border-t border-base-300 flex items-center px-4 text-xs gap-4 text-base-content/70 z-[99]">
// --- DOWNLOAD SPEED DROPDOWN --- // --- DOWNLOAD SPEED DROPDOWN ---
<div class="relative"> <div class="relative">
@@ -171,7 +179,8 @@ pub fn StatusBar() -> impl IntoView {
<li> <li>
<button <button
class=move || if is_active() { "bg-primary/10 text-primary font-bold text-xs flex justify-between" } else { "text-xs flex justify-between" } class=move || if is_active() { "bg-primary/10 text-primary font-bold text-xs flex justify-between" } else { "text-xs flex justify-between" }
on:click=move |_| { on:pointerdown=move |e| {
e.stop_propagation();
set_limit("down", val); set_limit("down", val);
close_all(); close_all();
} }
@@ -224,7 +233,8 @@ pub fn StatusBar() -> impl IntoView {
<li> <li>
<button <button
class=move || if is_active() { "bg-primary/10 text-primary font-bold text-xs flex justify-between" } else { "text-xs flex justify-between" } class=move || if is_active() { "bg-primary/10 text-primary font-bold text-xs flex justify-between" } else { "text-xs flex justify-between" }
on:click=move |_| { on:pointerdown=move |e| {
e.stop_propagation();
set_limit("up", val); set_limit("up", val);
close_all(); close_all();
} }
@@ -270,7 +280,8 @@ pub fn StatusBar() -> impl IntoView {
<li> <li>
<button <button
class=move || if current_theme.get() == theme { "bg-primary/10 text-primary font-bold text-xs capitalize" } else { "text-xs capitalize" } class=move || if current_theme.get() == theme { "bg-primary/10 text-primary font-bold text-xs capitalize" } else { "text-xs capitalize" }
on:click=move |_| { on:pointerdown=move |e| {
e.stop_propagation();
set_current_theme.set(theme.to_string()); set_current_theme.set(theme.to_string());
if let Some(win) = web_sys::window() { if let Some(win) = web_sys::window() {
if let Some(doc) = win.document() { if let Some(doc) = win.document() {