From 0e6f61145513e17e5d65c09deeefb843559c64e6 Mon Sep 17 00:00:00 2001 From: joyzhao Date: Fri, 9 Jan 2026 09:55:52 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E2=80=9C=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E9=A1=B6=E9=83=A8=E2=80=9D=E7=BB=84=E4=BB=B6=EF=BC=8C?= =?UTF-8?q?=E6=8F=90=E5=8D=87=E7=94=A8=E6=88=B7=E5=AF=BC=E8=88=AA=E4=BD=93?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/back-to-top.tsx | 46 +++++++++++++++++++++++++++++++ src/layouts/Layout.astro | 2 ++ 2 files changed, 48 insertions(+) create mode 100644 src/components/ui/back-to-top.tsx diff --git a/src/components/ui/back-to-top.tsx b/src/components/ui/back-to-top.tsx new file mode 100644 index 0000000..b76f816 --- /dev/null +++ b/src/components/ui/back-to-top.tsx @@ -0,0 +1,46 @@ +import { ArrowUp } from "lucide-react"; +import { Button } from "./button"; +import { useEffect, useState } from "react"; + +export default function BackToTop() { + const [isVisible, setIsVisible] = useState(false); + + useEffect(() => { + const toggleVisibility = () => { + if (window.scrollY > 300) { + setIsVisible(true); + } else { + setIsVisible(false); + } + }; + + window.addEventListener("scroll", toggleVisibility); + return () => window.removeEventListener("scroll", toggleVisibility); + }, []); + + const scrollToTop = () => { + window.scrollTo({ + top: 0, + behavior: "smooth", + }); + }; + + return ( +
+ +
+ ); +} diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index a1b38c0..b932d77 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -1,4 +1,5 @@ --- +import BackToTop from "@/components/ui/back-to-top"; import { useTranslations } from "@/i18n/utils"; import type { Lang } from "@/types/i18n"; import { defaultLang } from "@/i18n/ui"; @@ -44,6 +45,7 @@ const t = useTranslations(lang); > +