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:
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
Reference in New Issue
Block a user