feat: refactor TopLoader to use a hook for active state management and improve CSS for fixed positioning
This commit is contained in:
@@ -2,6 +2,7 @@ import { SidebarInset, SidebarProvider, SidebarTrigger } from '@/components/ui/s
|
||||
import { AppSidebar } from '@/components/layout/app-sidebar'
|
||||
import { BottomNav } from '@/components/layout/bottom-nav'
|
||||
import { ThemeToggle } from '@/components/layout/theme-toggle'
|
||||
import { TopLoader } from '@/components/shared/top-loader'
|
||||
|
||||
export default function DashboardLayout({
|
||||
children,
|
||||
@@ -10,6 +11,7 @@ export default function DashboardLayout({
|
||||
}) {
|
||||
return (
|
||||
<SidebarProvider>
|
||||
<TopLoader />
|
||||
<AppSidebar />
|
||||
<SidebarInset>
|
||||
<header className="flex h-14 shrink-0 items-center gap-2 border-b border-border px-4">
|
||||
|
||||
+4
-3
@@ -30,7 +30,7 @@ import { Input } from '@/components/ui/input'
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
|
||||
import { toast } from '@/components/ui/toast'
|
||||
import { TopLoader } from '@/components/shared/top-loader'
|
||||
import { useTopLoader } from '@/components/shared/top-loader'
|
||||
import { EmptyState } from '@/components/shared/empty-state'
|
||||
import { ReceiptDollarIcon } from '@hugeicons/core-free-icons'
|
||||
|
||||
@@ -70,11 +70,12 @@ export function SupplierPaymentsClient({ supplierId }: { supplierId: string }) {
|
||||
|
||||
useEffect(() => { loadPayments() }, [loadPayments])
|
||||
|
||||
useTopLoader(loading)
|
||||
|
||||
const pageCount = Math.max(1, Math.ceil(total / pageSize))
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<TopLoader active={loading} />
|
||||
<div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-semibold text-foreground">Supplier Payments</h1>
|
||||
|
||||
@@ -135,42 +135,44 @@
|
||||
border-bottom-color: var(--muted-foreground);
|
||||
}
|
||||
|
||||
/* Top loading strip: thin bar sliding across with a neon-red leading dot. */
|
||||
/* Top loading strip: fixed-at-top-of-viewport bar sliding across with a
|
||||
neon-red leading dot. Fixed positioning so no scroll container can clip it. */
|
||||
.top-loader {
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 2px;
|
||||
overflow: visible;
|
||||
z-index: 50;
|
||||
z-index: 100;
|
||||
}
|
||||
.top-loader__bar {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent 0%,
|
||||
rgba(255, 60, 90, 0.35) 55%,
|
||||
rgba(255, 90, 120, 0.9) 90%,
|
||||
rgba(255, 46, 99, 0.0) 0%,
|
||||
rgba(255, 46, 99, 0.85) 40%,
|
||||
rgba(255, 90, 120, 1) 80%,
|
||||
#ff2e63 100%
|
||||
);
|
||||
transform: translateX(-100%);
|
||||
animation: top-loader-slide 1.2s cubic-bezier(0.4, 0, 0.2, 1) infinite;
|
||||
animation: top-loader-slide 1.1s cubic-bezier(0.4, 0, 0.2, 1) infinite;
|
||||
box-shadow: 0 0 8px rgba(255, 46, 99, 0.45);
|
||||
}
|
||||
.top-loader__head {
|
||||
position: absolute;
|
||||
right: -4px;
|
||||
right: -2px;
|
||||
top: -2px;
|
||||
height: 6px;
|
||||
width: 10px;
|
||||
border-radius: 9999px;
|
||||
background: #ff6b8a;
|
||||
background: #ffd1dc;
|
||||
box-shadow:
|
||||
0 0 6px 1px #ff2e63,
|
||||
0 0 14px 2px rgba(255, 46, 99, 0.75),
|
||||
0 0 24px 4px rgba(255, 46, 99, 0.35);
|
||||
0 0 14px 3px rgba(255, 46, 99, 0.85),
|
||||
0 0 28px 6px rgba(255, 46, 99, 0.45);
|
||||
}
|
||||
@keyframes top-loader-slide {
|
||||
0% { transform: translateX(-100%); }
|
||||
|
||||
Reference in New Issue
Block a user