feat: port SiteFooter (liên hệ Như Quỳnh) + BackToTopButton
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
"use client";
|
||||
|
||||
import { ArrowUp } from "lucide-react";
|
||||
import { CSSProperties, useEffect, useState } from "react";
|
||||
|
||||
export function BackToTopButton() {
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
const [scrollProgress, setScrollProgress] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
let frameId: number | null = null;
|
||||
|
||||
const updateScrollState = () => {
|
||||
const scrollTop = window.scrollY;
|
||||
const scrollableHeight = document.documentElement.scrollHeight - window.innerHeight;
|
||||
const nextProgress = scrollableHeight > 0 ? Math.min(100, Math.max(0, (scrollTop / scrollableHeight) * 100)) : 0;
|
||||
|
||||
setIsVisible(scrollTop > 120);
|
||||
setScrollProgress(nextProgress);
|
||||
frameId = null;
|
||||
};
|
||||
|
||||
const requestUpdate = () => {
|
||||
if (frameId === null) {
|
||||
frameId = window.requestAnimationFrame(updateScrollState);
|
||||
}
|
||||
};
|
||||
|
||||
requestUpdate();
|
||||
window.addEventListener("scroll", requestUpdate, { passive: true });
|
||||
window.addEventListener("resize", requestUpdate);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("scroll", requestUpdate);
|
||||
window.removeEventListener("resize", requestUpdate);
|
||||
if (frameId !== null) {
|
||||
window.cancelAnimationFrame(frameId);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleClick = () => {
|
||||
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
behavior: prefersReducedMotion ? "auto" : "smooth",
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Lên đầu trang"
|
||||
aria-hidden={!isVisible}
|
||||
onClick={handleClick}
|
||||
className="public-back-to-top"
|
||||
data-visible={isVisible ? "true" : "false"}
|
||||
tabIndex={isVisible ? 0 : -1}
|
||||
style={{ "--scroll-progress": `${scrollProgress}%` } as CSSProperties}
|
||||
>
|
||||
<span className="public-back-to-top-ring" aria-hidden="true" />
|
||||
<span className="public-back-to-top-core">
|
||||
<ArrowUp className="h-5 w-5" strokeWidth={2.2} />
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import Link from "next/link";
|
||||
import { Globe2, Mail, MapPin } from "lucide-react";
|
||||
import { navigation } from "@/app/content";
|
||||
|
||||
export function SiteFooter() {
|
||||
return (
|
||||
<footer id="contact" className="px-4 pb-8 sm:px-6">
|
||||
<div className="mx-auto grid max-w-7xl gap-8 border-t border-[var(--surface-border)] pt-8 lg:grid-cols-[1.1fr_0.72fr_0.82fr]">
|
||||
<div className="min-w-0">
|
||||
<p className="text-lg font-bold text-[var(--tour-ink)]">VR360 Như Quỳnh</p>
|
||||
<p className="mt-3 max-w-[62ch] text-sm leading-6 text-[var(--muted-foreground)]">
|
||||
Cổng số hóa di tích và không gian văn hóa Xã Như Quỳnh, tỉnh Hưng Yên bằng công nghệ VR360.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<nav className="grid gap-2 text-sm" aria-label="Liên kết nhanh">
|
||||
<p className="font-bold text-[var(--tour-ink)]">Liên kết nhanh</p>
|
||||
{navigation.map((item) => (
|
||||
<Link key={item.href} href={item.href} className="w-fit text-[var(--muted-foreground)] transition-colors hover:text-[var(--tour-ink)]">
|
||||
{item.label}
|
||||
</Link>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
<div className="grid gap-3 text-sm leading-6 text-[var(--muted-foreground)] lg:text-right">
|
||||
<p className="font-bold text-[var(--tour-ink)]">Thông tin liên hệ</p>
|
||||
<p className="inline-flex items-center gap-2 lg:justify-end">
|
||||
<MapPin className="h-4 w-4 text-[var(--primary)]" strokeWidth={1.8} />
|
||||
Xã Như Quỳnh, tỉnh Hưng Yên
|
||||
</p>
|
||||
<a
|
||||
href="#"
|
||||
className="inline-flex items-center gap-2 font-semibold text-[var(--tour-ink)] hover:text-[var(--primary)] lg:justify-end"
|
||||
>
|
||||
<Globe2 className="h-4 w-4 text-[var(--primary)]" strokeWidth={1.8} />
|
||||
Cổng thông tin Xã Như Quỳnh
|
||||
</a>
|
||||
<Link href="/lien-he" className="inline-flex items-center gap-2 font-semibold text-[var(--tour-ink)] hover:text-[var(--primary)] lg:justify-end">
|
||||
<Mail className="h-4 w-4 text-[var(--primary)]" strokeWidth={1.8} />
|
||||
Gửi góp ý hoặc tư liệu
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mx-auto mt-8 max-w-7xl border-t border-[var(--surface-border)] pt-5 text-center text-sm font-semibold text-[var(--muted-foreground)]">
|
||||
© 2026 VR360 Di sản Xã Như Quỳnh.
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user