diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx index bde677a7..ceb7626a 100644 --- a/apps/web/src/app/layout.tsx +++ b/apps/web/src/app/layout.tsx @@ -10,7 +10,7 @@ import { authConfig } from "@/lib/auth/config"; import { SessionWrapper } from "./SessionWrapper"; import { TRPCProvider } from "@/providers/trpc-provider"; import { GeistSans } from "geist/font/sans"; - +import ScrollToTop from "@/components/ui/ScrollToTop"; // DM Mono - Used for code, terminal, and monospace text const dmMono = localFont({ src: [ @@ -100,6 +100,7 @@ export const metadata: Metadata = { }, }; + export default async function RootLayout({ children, }: Readonly<{ @@ -126,6 +127,7 @@ export default async function RootLayout({ + ); diff --git a/apps/web/src/components/ui/ScrollToTop.tsx b/apps/web/src/components/ui/ScrollToTop.tsx new file mode 100644 index 00000000..af97f95c --- /dev/null +++ b/apps/web/src/components/ui/ScrollToTop.tsx @@ -0,0 +1,63 @@ + +"use client"; + +import { useState, useEffect } from "react"; +import { ChevronUp } from "lucide-react"; +import { cn } from "@/lib/utils"; + +export default function ScrollToTop() { + const [isVisible, setIsVisible] = useState(false); + + useEffect(() => { + const toggleVisibility = () => { + if (window.scrollY > 300) { + setIsVisible(true); + } else { + setIsVisible(false); + } + }; + + window.addEventListener("scroll", toggleVisibility); + toggleVisibility(); + return () => { + window.removeEventListener("scroll", toggleVisibility); + }; + }, []); + + + const scrollToTop = () => { + window.scrollTo({ + top: 0, + behavior: "smooth", + }); + }; + + return ( + <> + {/* Button only renders when isVisible is true */} + {isVisible && ( + + )} + + ); +} \ No newline at end of file