diff --git a/Frontend/src/App.tsx b/Frontend/src/App.tsx index 60f7ecd..11411b0 100644 --- a/Frontend/src/App.tsx +++ b/Frontend/src/App.tsx @@ -20,6 +20,7 @@ import PublicRoute from "./components/PublicRoute"; import Dashboard from "./pages/Brand/Dashboard"; import BasicDetails from "./pages/BasicDetails"; import Onboarding from "./components/Onboarding"; +import ScrollToTop from "./components/ui/scroll-to-top"; function App() { const [isLoading, setIsLoading] = useState(true); @@ -45,6 +46,7 @@ function App() { return ( + {/* Public Routes */} } /> diff --git a/Frontend/src/components/ui/scroll-to-top.tsx b/Frontend/src/components/ui/scroll-to-top.tsx new file mode 100644 index 0000000..1296906 --- /dev/null +++ b/Frontend/src/components/ui/scroll-to-top.tsx @@ -0,0 +1,134 @@ +import { useState, useEffect, useRef } from "react"; +import { ArrowUp } from "lucide-react"; + +export default function ScrollToTop() { + const [isVisible, setIsVisible] = useState(false); + const [scrollProgress, setScrollProgress] = useState(0); + const [circleRadius, setCircleRadius] = useState(20); + const rafIdRef = useRef(null); + const svgRef = useRef(null); + + useEffect(() => { + const updateScrollState = () => { + const scrolled = window.scrollY; + const documentHeight = document.documentElement.scrollHeight; + const clientHeight = document.documentElement.clientHeight; + const scrollableHeight = documentHeight - clientHeight; + + const progress = scrollableHeight > 0 + ? Math.min(100, Math.max(0, (scrolled / scrollableHeight) * 100)) + : 0; + + setScrollProgress(progress); + setIsVisible(scrolled > 300); + rafIdRef.current = null; + }; + + const handleScroll = () => { + if (rafIdRef.current === null) { + rafIdRef.current = requestAnimationFrame(updateScrollState); + } + }; + + window.addEventListener("scroll", handleScroll, { passive: true }); + updateScrollState(); + + return () => { + window.removeEventListener("scroll", handleScroll); + if (rafIdRef.current !== null) { + cancelAnimationFrame(rafIdRef.current); + } + }; + }, []); + + useEffect(() => { + const updateCircleRadius = () => { + if (svgRef.current) { + const svgRect = svgRef.current.getBoundingClientRect(); + const computedRadius = (Math.min(svgRect.width, svgRect.height) / 2) * 0.45; + setCircleRadius(Math.max(computedRadius, 1)); + } + }; + + updateCircleRadius(); + window.addEventListener("resize", updateCircleRadius, { passive: true }); + + return () => { + window.removeEventListener("resize", updateCircleRadius); + }; + }, []); + + const scrollToTop = () => { + window.scrollTo({ + top: 0, + behavior: "smooth", + }); + }; + + const circumference = 2 * Math.PI * circleRadius; + const offset = circumference * (1 - scrollProgress / 100); + + return ( +
+
+ + + +
+ ); +}