SPB Git forge

spb/spb-cloud

Public
10commits 1branches 0releases
3.2 MBsize
maindefault branch
2 h agolast push
JavaScript 56.7% TypeScript 42.6%
1.6 KB · 55 lines tsx
Raw Blame History
1"use client";23import { useEffect, useState, useRef } from "react";4import { usePathname } from "next/navigation";56/** Barre de progression de navigation (2 px, dégradé d'accent + lueur). */7export default function TopLoader() {8  const pathname = usePathname();9  const [loading, setLoading] = useState(false);10  const [progress, setProgress] = useState(0);11  const [visible, setVisible] = useState(false);12  const prevPathname = useRef(pathname);13  const timers = useRef<ReturnType<typeof setTimeout>[]>([]);1415  useEffect(() => {16    if (pathname === prevPathname.current) return;17    prevPathname.current = pathname;1819    timers.current.forEach(clearTimeout);20    timers.current = [];21    const t = (fn: () => void, ms: number) => timers.current.push(setTimeout(fn, ms));2223    setLoading(true);24    setVisible(true);25    setProgress(0);26    t(() => setProgress(30), 40);27    t(() => setProgress(62), 180);28    t(() => setProgress(82), 380);29    t(() => {30      setProgress(100);31      t(() => {32        setLoading(false);33        t(() => { setVisible(false); setProgress(0); }, 220);34      }, 140);35    }, 520);3637    return () => { timers.current.forEach(clearTimeout); };38  }, [pathname]);3940  if (!visible) return null;4142  return (43    <div className="fixed top-0 left-0 right-0 z-[90] h-[2px] pointer-events-none" aria-hidden>44      <div45        className="h-full bg-accent-gradient transition-all ease-out shadow-[0_0_10px_rgb(var(--accent-500)/0.7),0_0_2px_rgb(var(--accent-400)/0.9)]"46        style={{47          width: `${progress}%`,48          transitionDuration: progress === 100 ? "140ms" : "480ms",49          opacity: loading ? 1 : 0,50        }}51      />52    </div>53  );54}55