diff --git a/apps/frontend/src/components/layout/Layout.tsx b/apps/frontend/src/components/layout/Layout.tsx index 7dfbb33..4a8a778 100644 --- a/apps/frontend/src/components/layout/Layout.tsx +++ b/apps/frontend/src/components/layout/Layout.tsx @@ -2,12 +2,14 @@ import { useState } from "react"; import { Outlet } from "@tanstack/react-router"; import { Header } from "./Header"; import { Sidebar } from "./Sidebar"; +import { LoadingBar } from "@/components/ui/loading-bar"; export function Layout() { const [sidebarOpen, setSidebarOpen] = useState(false); return (
+ setSidebarOpen(false)} />
setSidebarOpen(true)} /> diff --git a/apps/frontend/src/components/ui/loading-bar.tsx b/apps/frontend/src/components/ui/loading-bar.tsx new file mode 100644 index 0000000..dd135bf --- /dev/null +++ b/apps/frontend/src/components/ui/loading-bar.tsx @@ -0,0 +1,37 @@ +import { useState, useEffect, useRef } from "react"; +import { useRouterState } from "@tanstack/react-router"; +import { useIsFetching, useIsMutating } from "@tanstack/react-query"; +import { cn } from "@/lib/utils"; + +export function LoadingBar() { + const isNavigating = useRouterState({ select: (s) => s.status === "pending" }); + const isFetching = useIsFetching(); + const isMutating = useIsMutating(); + + const [visible, setVisible] = useState(false); + const timerRef = useRef>(undefined); + + const loading = isNavigating || isFetching > 0 || isMutating > 0; + + useEffect(() => { + if (loading) { + timerRef.current = setTimeout(() => setVisible(true), 200); + } else { + clearTimeout(timerRef.current); + setVisible(false); + } + return () => clearTimeout(timerRef.current); + }, [loading]); + + return ( +