feat: redesign landing pages — bố cục giàu hơn, mượt & cao cấp hơn

- Trang chủ: thêm thẻ trải nghiệm Cổ vật 3D, khu "sắp ra mắt" dạng thẻ gọn
  (bỏ ảnh lặp), bo góc mềm, badge vuông có chấm trạng thái
- Giới thiệu: bố cục editorial bất đối xứng, dải thống kê, 4 trụ giá trị di sản,
  hành trình số hóa 4 bước, thẻ CTA tour nổi bật
- Liên hệ: 2 cột (hướng dẫn đóng góp + thẻ liên hệ), nhúng bản đồ
- CTA: sửa màu chữ tương phản trên nền xanh/nền sáng

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
tuyenio
2026-06-23 15:07:03 +07:00
parent f518c07763
commit 25772c9c25
4 changed files with 308 additions and 61 deletions
+144 -11
View File
@@ -1,9 +1,22 @@
import type { Metadata } from "next"; import type { Metadata } from "next";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link";
import {
ArrowRight,
BookOpenText,
Building2,
Compass,
FileText,
Landmark,
PlayCircle,
ScanLine,
Sparkles,
Users,
} from "lucide-react";
import { BackToTopButton } from "@/app/components/landing/BackToTopButton"; import { BackToTopButton } from "@/app/components/landing/BackToTopButton";
import { SiteFooter } from "@/app/components/landing/SiteFooter"; import { SiteFooter } from "@/app/components/landing/SiteFooter";
import { SiteHeader } from "@/app/components/landing/SiteHeader"; import { SiteHeader } from "@/app/components/landing/SiteHeader";
import { activeTour, heritageSites } from "@/app/content"; import { activeTour, antiquities, heritageSites, img } from "@/app/content";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Giới thiệu | VR360 Như Quỳnh", title: "Giới thiệu | VR360 Như Quỳnh",
@@ -15,9 +28,10 @@ const nationalCount = heritageSites.filter((s) => s.level === "Cấp quốc gia"
const provincialCount = heritageSites.filter((s) => s.level === "Cấp tỉnh").length; const provincialCount = heritageSites.filter((s) => s.level === "Cấp tỉnh").length;
const stats = [ const stats = [
{ value: String(nationalCount), label: "di tích xếp hạng cấp quốc gia" }, { value: String(nationalCount), label: "di tích cấp quốc gia" },
{ value: String(provincialCount), label: "di tích cấp tỉnh" }, { value: String(provincialCount), label: "di tích cấp tỉnh" },
{ value: activeTour.sceneCount, label: "điểm 360° trong tour đầu tiên" }, { value: activeTour.sceneCount, label: "điểm ảnh 360°" },
{ value: String(antiquities.length), label: "cổ vật số hóa 3D" },
]; ];
const paragraphs = [ const paragraphs = [
@@ -26,6 +40,20 @@ const paragraphs = [
"Mỗi không gian được giới thiệu bằng hình ảnh thật, điểm tương tác, chú thích tiếng Việt và cấu trúc nội dung dễ theo dõi, hướng tới mục tiêu chuyển đổi số di sản giai đoạn 20262030.", "Mỗi không gian được giới thiệu bằng hình ảnh thật, điểm tương tác, chú thích tiếng Việt và cấu trúc nội dung dễ theo dõi, hướng tới mục tiêu chuyển đổi số di sản giai đoạn 20262030.",
]; ];
const values = [
{ icon: Landmark, title: "Không gian tín ngưỡng", detail: "Đình, chùa, đền, văn miếu — nơi gìn giữ kiến trúc và đời sống tâm linh của cộng đồng làng quê." },
{ icon: BookOpenText, title: "Vùng đất khoa bảng", detail: "Truyền thống hiếu học được tôn vinh qua hệ thống văn miếu và các bậc danh nhân của quê hương." },
{ icon: Building2, title: "Kiến trúc nghệ thuật", detail: "Những mảng chạm khắc, đồ thờ tự và hiện vật mang giá trị mỹ thuật cổ tiêu biểu." },
{ icon: Users, title: "Ký ức cộng đồng", detail: "Lễ hội, phong tục và câu chuyện dân gian gắn liền với từng di tích qua nhiều thế hệ." },
];
const steps = [
{ icon: Compass, title: "Khảo sát", detail: "Xác định danh mục di tích, tuyến tham quan và đầu mối duyệt nội dung tại địa phương." },
{ icon: ScanLine, title: "Số hóa", detail: "Ghi nhận ảnh 360°, mô hình 3D cổ vật và dữ liệu không gian độ phân giải cao." },
{ icon: FileText, title: "Biên tập", detail: "Tổ chức nội dung thành trải nghiệm dễ hiểu cho người dân, học sinh và du khách." },
{ icon: Sparkles, title: "Vận hành", detail: "Đưa lên nền tảng trực tuyến, sẵn sàng mở rộng thêm các tuyến di sản mới." },
];
export default function AboutPage() { export default function AboutPage() {
return ( return (
<main className="public-page min-h-[100dvh] bg-[var(--background)] text-[var(--foreground)]"> <main className="public-page min-h-[100dvh] bg-[var(--background)] text-[var(--foreground)]">
@@ -34,34 +62,139 @@ export default function AboutPage() {
<section className="public-subpage-hero public-subpage-hero--compact relative isolate overflow-hidden border-b border-[var(--surface-border)]"> <section className="public-subpage-hero public-subpage-hero--compact relative isolate overflow-hidden border-b border-[var(--surface-border)]">
<Image src={activeTour.gateImage} alt="" fill priority sizes="100vw" className="public-subpage-hero-image object-cover" /> <Image src={activeTour.gateImage} alt="" fill priority sizes="100vw" className="public-subpage-hero-image object-cover" />
<div className="public-subpage-hero-content mx-auto max-w-7xl px-4 py-16 sm:px-6 lg:py-22"> <div className="public-subpage-hero-content mx-auto max-w-7xl px-4 py-16 sm:px-6 lg:py-22">
<div className="public-rise max-w-4xl"> <div className="public-rise public-hero-rule max-w-4xl">
<p className="public-kicker">Giới thiệu</p> <p className="public-kicker">Giới thiệu</p>
<h1 className="public-gradient-text public-heading-safe mt-4 text-[clamp(2.55rem,5.8vw,5rem)] font-extrabold"> <h1 className="public-gradient-text public-heading-safe mt-4 text-[clamp(2.55rem,5.8vw,5rem)] font-extrabold">
Di sản văn hóa Như Quỳnh Di sản văn hóa Như Quỳnh
</h1> </h1>
<p className="public-subpage-copy mt-6 max-w-[60ch] text-base leading-8 text-[var(--foreground)]/82 sm:text-lg">
Một vùng đt văn hiến với hệ thống di tích trải dài nhiều thế kỷ, nay đưc gìn giữ lan tỏa
bằng công nghệ số.
</p>
</div> </div>
</div> </div>
</section> </section>
<section className="mx-auto max-w-3xl px-4 py-14 sm:px-6 lg:py-20"> {/* Intro — bố cục bất đối xứng: nhãn dính bên trái, nội dung bên phải */}
<div className="grid gap-4 text-base leading-8 text-[var(--foreground)]/82"> <section className="mx-auto max-w-7xl px-4 py-16 sm:px-6 lg:grid lg:grid-cols-[0.42fr_0.58fr] lg:gap-12 lg:py-24">
<div className="lg:sticky lg:top-28 lg:self-start">
<p className="public-kicker">Về vùng đt</p>
<h2 className="public-display public-heading-safe mt-3 text-[clamp(1.9rem,3.2vw,2.8rem)] font-bold text-[var(--tour-ink)]">
Nơi lịch sử tín ngưỡng cùng hội tụ
</h2>
</div>
<div className="mt-6 grid max-w-[65ch] gap-5 text-base leading-8 text-[var(--foreground)]/82 lg:mt-0">
{paragraphs.map((text, i) => ( {paragraphs.map((text, i) => (
<p key={i}>{text}</p> <p key={i} className={i === 0 ? "text-lg leading-9 text-[var(--tour-ink)]" : undefined}>
{text}
</p>
))} ))}
</div> </div>
</section> </section>
{/* Stats */}
<section className="border-y border-[var(--surface-border)] bg-[var(--surface-band)]"> <section className="border-y border-[var(--surface-border)] bg-[var(--surface-band)]">
<div className="mx-auto grid max-w-7xl gap-4 px-4 py-14 sm:px-6 sm:grid-cols-3 lg:py-20"> <div className="mx-auto grid max-w-7xl gap-4 px-4 py-14 sm:px-6 sm:grid-cols-2 lg:grid-cols-4 lg:py-18">
{stats.map((s) => ( {stats.map((s) => (
<div key={s.label} className="public-panel rounded-[8px] p-6 text-center"> <div key={s.label} className="public-panel public-stagger-item rounded-[14px] p-6 text-center">
<p className="public-gradient-text text-4xl font-extrabold">{s.value}</p> <p className="public-gradient-text font-display-vn text-[2.6rem] font-extrabold leading-none [font-variant-numeric:tabular-nums]">
<p className="mt-2 text-sm leading-6 text-[var(--muted-foreground)]">{s.label}</p> {s.value}
</p>
<p className="mt-3 text-sm leading-6 text-[var(--muted-foreground)]">{s.label}</p>
</div> </div>
))} ))}
</div> </div>
</section> </section>
{/* Heritage values */}
<section className="mx-auto max-w-7xl px-4 py-16 sm:px-6 lg:py-24">
<div className="max-w-3xl">
<p className="public-kicker">Giá trị di sản</p>
<h2 className="public-display public-heading-safe mt-3 text-[clamp(1.9rem,3.4vw,3rem)] font-bold text-[var(--tour-ink)]">
Bốn lớp giá trị đưc gìn giữ
</h2>
</div>
<div className="mt-10 grid gap-4 md:grid-cols-2">
{values.map((value, index) => {
const Icon = value.icon;
return (
<article
key={value.title}
className={`public-panel public-stagger-item rounded-[16px] p-7 ${index % 2 === 1 ? "md:mt-8" : ""}`}
>
<span className="grid h-12 w-12 place-items-center rounded-[12px] bg-[rgb(200_164_106_/_0.14)]">
<Icon className="h-6 w-6 text-[var(--primary)]" strokeWidth={1.7} />
</span>
<h3 className="mt-5 text-xl font-bold text-[var(--tour-ink)]">{value.title}</h3>
<p className="mt-2.5 text-sm leading-7 text-[var(--muted-foreground)]">{value.detail}</p>
</article>
);
})}
</div>
</section>
{/* Digitization journey */}
<section className="border-y border-[var(--surface-border)] bg-[var(--surface-band)]">
<div className="mx-auto max-w-7xl px-4 py-16 sm:px-6 lg:py-24">
<div className="max-w-3xl">
<p className="public-kicker">Hành trình số hóa</p>
<h2 className="public-display public-heading-safe mt-3 text-[clamp(1.9rem,3.4vw,3rem)] font-bold text-[var(--tour-ink)]">
Từ liệu đến trải nghiệm số
</h2>
</div>
<ol className="mt-10 grid gap-4 md:grid-cols-2 xl:grid-cols-4">
{steps.map((step, index) => {
const Icon = step.icon;
return (
<li key={step.title} className="public-panel public-stagger-item relative rounded-[16px] p-6">
<span className="font-display-vn text-sm font-extrabold tracking-[0.2em] text-[var(--primary)]">
{String(index + 1).padStart(2, "0")}
</span>
<Icon className="mt-4 h-7 w-7 text-[var(--tour-jade)]" strokeWidth={1.7} />
<h3 className="mt-4 text-lg font-bold text-[var(--tour-ink)]">{step.title}</h3>
<p className="mt-2 text-sm leading-6 text-[var(--muted-foreground)]">{step.detail}</p>
</li>
);
})}
</ol>
</div>
</section>
{/* Featured tour CTA */}
<section className="mx-auto max-w-7xl px-4 py-16 sm:px-6 lg:py-20">
<div className="public-card group grid overflow-hidden rounded-[18px] lg:grid-cols-[1.05fr_0.95fr]">
<div className="relative min-h-[20rem]">
<Image
src={img("11.jpg")}
alt="Chùa Thái Lạc (Pháp Vân tự)"
fill
sizes="(max-width: 1024px) 100vw, 50vw"
className="object-cover transition-transform duration-700 group-hover:scale-[1.03]"
/>
</div>
<div className="flex flex-col justify-center p-7 sm:p-10">
<p className="public-kicker">Điểm đến tiêu biểu</p>
<h2 className="public-display public-heading-safe mt-3 text-[clamp(1.8rem,3vw,2.6rem)] font-bold text-[var(--tour-ink)]">
{activeTour.title}
</h2>
<p className="mt-4 max-w-[52ch] text-sm leading-7 text-[var(--foreground)]/80 sm:text-base">
Ngôi chùa cổ thờ Pháp Vân, nổi tiếng với mảng chạm khắc gỗ thời Trần di tích đu tiên
đưc số hóa thành tour VR360 hoàn chỉnh.
</p>
<div className="mt-7 flex flex-wrap gap-3">
<Link href={activeTour.href} className="public-cta">
<PlayCircle className="h-4 w-4" strokeWidth={1.8} />
Tham quan VR360
</Link>
<Link href="/co-vat" className="public-cta-secondary">
Xem cổ vật 3D
<ArrowRight className="h-4 w-4" strokeWidth={1.8} />
</Link>
</div>
</div>
</div>
</section>
<SiteFooter /> <SiteFooter />
<BackToTopButton /> <BackToTopButton />
</main> </main>
+5 -5
View File
@@ -890,7 +890,7 @@ a {
background: background:
linear-gradient(180deg, rgb(35 95 74), rgb(13 55 41)), linear-gradient(180deg, rgb(35 95 74), rgb(13 55 41)),
#123a2c; #123a2c;
color: var(--primary-foreground); color: #f7f0e0;
box-shadow: box-shadow:
0 18px 44px rgb(14 52 39 / 0.22), 0 18px 44px rgb(14 52 39 / 0.22),
inset 0 1px 0 rgb(255 255 255 / 0.2), inset 0 1px 0 rgb(255 255 255 / 0.2),
@@ -960,17 +960,17 @@ a {
.public-cta-secondary { .public-cta-secondary {
border: 1px solid rgb(14 52 39 / 0.18); border: 1px solid rgb(14 52 39 / 0.18);
background: rgb(255 255 255 / 0.78); background: rgb(255 255 255 / 0.82);
color: var(--tour-ink); color: var(--ink-on-light);
box-shadow: box-shadow:
0 14px 32px rgb(37 75 54 / 0.08), 0 14px 32px rgb(37 75 54 / 0.08),
inset 0 1px 0 rgb(255 255 255 / 0.82); inset 0 1px 0 rgb(255 255 255 / 0.82);
} }
.public-cta-secondary:hover { .public-cta-secondary:hover {
background: var(--surface-glass-strong); background: rgb(255 255 255 / 0.95);
transform: translateY(-2px); transform: translateY(-2px);
border-color: rgb(142 95 11 / 0.28); border-color: rgb(142 95 11 / 0.4);
box-shadow: box-shadow:
0 18px 40px rgb(37 75 54 / 0.12), 0 18px 40px rgb(37 75 54 / 0.12),
inset 0 1px 0 rgb(255 255 255 / 0.92); inset 0 1px 0 rgb(255 255 255 / 0.92);
+88 -26
View File
@@ -1,18 +1,25 @@
import type { Metadata } from "next"; import type { Metadata } from "next";
import { MapPin, Mail, Phone } from "lucide-react"; import { Clock, ImagePlus, Landmark, Mail, MapPin, MessageSquareText, Phone, Send } from "lucide-react";
import { BackToTopButton } from "@/app/components/landing/BackToTopButton"; import { BackToTopButton } from "@/app/components/landing/BackToTopButton";
import { SiteFooter } from "@/app/components/landing/SiteFooter"; import { SiteFooter } from "@/app/components/landing/SiteFooter";
import { SiteHeader } from "@/app/components/landing/SiteHeader"; import { SiteHeader } from "@/app/components/landing/SiteHeader";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Liên hệ | VR360 Như Quỳnh", title: "Liên hệ | VR360 Như Quỳnh",
description: "Thông tin liên hệ và đầu mối cung cấp tư liệu cho dự án số hóa di sản Xã Như Quỳnh.", description: "Thông tin liên hệ và đầu mối cung cấp tư liệu cho dự án số hóa di sản Xã Như Quỳnh, tỉnh Hưng Yên.",
}; };
const contacts = [ const contacts = [
{ icon: MapPin, label: "Địa chỉ", value: "Xã Như Quỳnh, tỉnh Hưng Yên" }, { icon: MapPin, label: "Địa chỉ", value: "Xã Như Quỳnh, tỉnh Hưng Yên" },
{ icon: Phone, label: "Điện thoại", value: "Đang cập nhật" }, { icon: Phone, label: "Điện thoại", value: "Đang cập nhật" },
{ icon: Mail, label: "Email", value: "Đang cập nhật" }, { icon: Mail, label: "Email", value: "Đang cập nhật" },
{ icon: Clock, label: "Thời gian tiếp nhận", value: "Trong giờ hành chính các ngày làm việc" },
];
const steps = [
{ icon: MessageSquareText, title: "Gửi thông tin", detail: "Mô tả ngắn về di tích, cổ vật hoặc câu chuyện bạn muốn đóng góp." },
{ icon: ImagePlus, title: "Kèm hình ảnh, tư liệu", detail: "Hình ảnh, tài liệu hoặc nguồn tham khảo giúp xác minh và biên tập nội dung." },
{ icon: Landmark, title: "Cùng hoàn thiện", detail: "Ban quản lý sẽ rà soát, đối chiếu và đưa nội dung phù hợp lên nền tảng số." },
]; ];
export default function ContactPage() { export default function ContactPage() {
@@ -20,31 +27,86 @@ export default function ContactPage() {
<main className="public-page min-h-[100dvh] bg-[var(--background)] text-[var(--foreground)]"> <main className="public-page min-h-[100dvh] bg-[var(--background)] text-[var(--foreground)]">
<SiteHeader /> <SiteHeader />
<section className="mx-auto max-w-3xl px-4 py-16 sm:px-6 lg:py-24"> <section className="mx-auto max-w-7xl px-4 pt-16 sm:px-6 lg:pt-24">
<p className="public-kicker">Liên hệ</p> <div className="public-rise max-w-3xl">
<h1 className="public-gradient-text public-heading-safe mt-3 text-[clamp(2.2rem,5vw,3.6rem)] font-extrabold"> <p className="public-kicker">Liên hệ</p>
Liên hệ & đóng góp liệu <h1 className="public-gradient-text public-heading-safe mt-3 text-[clamp(2.2rem,5vw,3.8rem)] font-extrabold">
</h1> Liên hệ & đóng góp liệu
<p className="mt-5 text-base leading-8 text-[var(--foreground)]/82"> </h1>
Người dân, tổ chức liệu, hình nh hoặc câu chuyện về các di tích của Như Quỳnh <p className="mt-5 text-base leading-8 text-[var(--foreground)]/82 sm:text-lg">
vui lòng liên hệ đ cùng hoàn thiện kho dữ liệu số di sản. Người dân, tổ chức liệu, hình nh hoặc câu chuyện về các di tích của Như Quỳnh
</p> vui lòng liên hệ đ cùng hoàn thiện kho dữ liệu số di sản.
</p>
</div>
</section>
<div className="mt-10 grid gap-4"> <section className="mx-auto max-w-7xl px-4 py-12 sm:px-6 lg:grid lg:grid-cols-[0.56fr_0.44fr] lg:gap-8 lg:py-16">
{contacts.map((c) => { {/* Contribution guidance */}
const Icon = c.icon; <div>
return ( <h2 className="public-display public-heading-safe text-2xl font-bold text-[var(--tour-ink)] sm:text-3xl">
<div key={c.label} className="public-panel flex items-center gap-4 rounded-[8px] p-5"> Cách đóng góp liệu
<span className="grid h-11 w-11 shrink-0 place-items-center rounded-full bg-[rgb(200_164_106_/_0.18)]"> </h2>
<Icon className="h-5 w-5 text-[var(--primary)]" strokeWidth={1.8} /> <ol className="mt-6 grid gap-4">
</span> {steps.map((step, index) => {
<span> const Icon = step.icon;
<span className="block text-sm font-bold text-[var(--muted-foreground)]">{c.label}</span> return (
<span className="block text-base font-bold text-[var(--tour-ink)]">{c.value}</span> <li key={step.title} className="public-panel public-stagger-item flex items-start gap-4 rounded-[14px] p-5">
</span> <span className="grid h-11 w-11 shrink-0 place-items-center rounded-[10px] bg-[rgb(200_164_106_/_0.14)]">
</div> <Icon className="h-5 w-5 text-[var(--primary)]" strokeWidth={1.8} />
); </span>
})} <span>
<span className="flex items-center gap-2">
<span className="font-display-vn text-xs font-extrabold tracking-[0.18em] text-[var(--primary)]">
{String(index + 1).padStart(2, "0")}
</span>
<span className="text-base font-bold text-[var(--tour-ink)]">{step.title}</span>
</span>
<span className="mt-1 block text-sm leading-6 text-[var(--muted-foreground)]">{step.detail}</span>
</span>
</li>
);
})}
</ol>
</div>
{/* Contact cards */}
<div className="mt-8 lg:mt-0">
<h2 className="public-display public-heading-safe text-2xl font-bold text-[var(--tour-ink)] sm:text-3xl">
Thông tin liên hệ
</h2>
<div className="mt-6 grid gap-3">
{contacts.map((c) => {
const Icon = c.icon;
return (
<div key={c.label} className="public-panel flex items-center gap-4 rounded-[14px] p-5">
<span className="grid h-11 w-11 shrink-0 place-items-center rounded-full bg-[rgb(200_164_106_/_0.18)]">
<Icon className="h-5 w-5 text-[var(--primary)]" strokeWidth={1.8} />
</span>
<span>
<span className="block text-xs font-bold uppercase tracking-[0.1em] text-[var(--muted-foreground)]">{c.label}</span>
<span className="block text-base font-semibold text-[var(--tour-ink)]">{c.value}</span>
</span>
</div>
);
})}
</div>
<p className="mt-4 inline-flex items-center gap-2 text-xs leading-5 text-[var(--muted-foreground)]">
<Send className="h-3.5 w-3.5 text-[var(--primary)]" strokeWidth={1.8} />
Thông tin số điện thoại email chính thức sẽ đưc cập nhật khi sẵn sàng.
</p>
</div>
</section>
{/* Map */}
<section className="mx-auto max-w-7xl px-4 pb-16 sm:px-6 lg:pb-24">
<div className="public-map-frame overflow-hidden rounded-[16px] border border-[var(--surface-border)]">
<iframe
title="Bản đồ Xã Như Quỳnh, tỉnh Hưng Yên"
src="https://www.google.com/maps?q=Nh%C6%B0%20Qu%E1%BB%B3nh%2C%20H%C6%B0ng%20Y%C3%AAn&output=embed"
loading="lazy"
referrerPolicy="no-referrer-when-downgrade"
className="h-[360px] w-full sm:h-[440px]"
/>
</div> </div>
</section> </section>
+71 -19
View File
@@ -1,12 +1,12 @@
import type { Metadata } from "next"; import type { Metadata } from "next";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import { ArrowRight, Box, Globe2, Landmark, PlayCircle, School, Sparkles } from "lucide-react"; import { ArrowRight, Box, Globe2, Landmark, PlayCircle, Rotate3d, School, Sparkles } from "lucide-react";
import { BackToTopButton } from "@/app/components/landing/BackToTopButton"; import { BackToTopButton } from "@/app/components/landing/BackToTopButton";
import { SiteFooter } from "@/app/components/landing/SiteFooter"; import { SiteFooter } from "@/app/components/landing/SiteFooter";
import { SiteHeader } from "@/app/components/landing/SiteHeader"; import { SiteHeader } from "@/app/components/landing/SiteHeader";
import { HeroShaderBackground } from "@/app/components/ui/hero-shader-background"; import { HeroShaderBackground } from "@/app/components/ui/hero-shader-background";
import { activeTour, heritageSites } from "@/app/content"; import { activeTour, heritageSites, img } from "@/app/content";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Trang chủ | VR360 Như Quỳnh", title: "Trang chủ | VR360 Như Quỳnh",
@@ -100,13 +100,13 @@ export default function Home() {
<div className="mx-auto max-w-7xl px-4 py-14 sm:px-6 lg:py-20"> <div className="mx-auto max-w-7xl px-4 py-14 sm:px-6 lg:py-20">
<div className="flex flex-col justify-between gap-4 lg:flex-row lg:items-end"> <div className="flex flex-col justify-between gap-4 lg:flex-row lg:items-end">
<div className="max-w-3xl"> <div className="max-w-3xl">
<p className="public-kicker">Di tích nổi bật</p> <p className="public-kicker">Trải nghiệm nổi bật</p>
<h2 className="public-heading-safe mt-3 text-[2rem] font-bold text-[var(--tour-ink)] sm:text-4xl"> <h2 className="public-display public-heading-safe mt-3 text-[2rem] font-bold text-[var(--tour-ink)] sm:text-4xl">
Không gian đang mở tour VR360. Đang mở đ khám phá.
</h2> </h2>
</div> </div>
<Link href="/di-tich" className="inline-flex items-center gap-2 text-sm font-extrabold text-[var(--tour-ink)] transition hover:text-[var(--primary)]"> <Link href="/di-tich" className="inline-flex items-center gap-2 text-sm font-extrabold text-[var(--tour-ink)] transition hover:text-[var(--primary)]">
Xem toàn bộ không gian Xem toàn bộ di tích
<ArrowRight className="h-4 w-4" strokeWidth={1.8} /> <ArrowRight className="h-4 w-4" strokeWidth={1.8} />
</Link> </Link>
</div> </div>
@@ -115,21 +115,72 @@ export default function Home() {
{availableSites.map((site) => ( {availableSites.map((site) => (
<HomeSiteCard key={site.id} site={site} /> <HomeSiteCard key={site.id} site={site} />
))} ))}
{/* Trải nghiệm cổ vật 3D */}
<article className="public-card public-stagger-item group grid overflow-hidden rounded-[16px] md:grid-cols-[0.92fr_1.08fr]">
<div className="relative min-h-[18rem]">
<Image
src={img("20.jpg")}
alt="Cổ vật số hóa 3D"
fill
sizes="(max-width: 768px) 100vw, 42vw"
className="object-cover transition-transform duration-700 group-hover:scale-[1.025]"
/>
<span className="absolute left-4 top-4 inline-flex items-center gap-1.5 rounded-md border border-[rgb(215_199_157_/_0.22)] bg-[rgb(18_21_16_/_0.55)] px-2.5 py-1 text-[0.7rem] font-bold uppercase tracking-[0.08em] text-[var(--tour-gold-light)] backdrop-blur-md">
<Rotate3d className="h-3.5 w-3.5" strokeWidth={1.8} />
hình 3D
</span>
</div>
<div className="flex min-h-[18rem] flex-col p-5 sm:p-6">
<p className="mt-1 text-sm font-bold text-[var(--primary)]">Phòng trưng bày số</p>
<h3 className="mt-2 text-2xl font-extrabold leading-tight text-[var(--tour-ink)]">Cổ vật & hiện vật 3D</h3>
<p className="mt-3 text-sm leading-6 text-[var(--muted-foreground)]">
Chiêm ngưỡng các cổ vật tiêu biểu đưc dựng thành hình ba chiều xoay, phóng to quan sát từng chi tiết.
</p>
<Link href="/co-vat" className="mt-auto inline-flex items-center gap-2 pt-5 text-sm font-extrabold text-[var(--tour-ink)] transition hover:text-[var(--primary)]">
Khám phá cổ vật 3D
<ArrowRight className="h-4 w-4" strokeWidth={1.8} />
</Link>
</div>
</article>
</div> </div>
</div> </div>
</section> </section>
<section className="mx-auto max-w-7xl px-4 py-14 sm:px-6 lg:py-20"> <section className="mx-auto max-w-7xl px-4 py-14 sm:px-6 lg:py-20">
<div className="max-w-3xl"> <div className="flex flex-col justify-between gap-4 lg:flex-row lg:items-end">
<p className="public-kicker">Sắp ra mắt</p> <div className="max-w-3xl">
<h2 className="public-heading-safe mt-3 text-[2rem] font-bold text-[var(--tour-ink)] sm:text-4xl"> <p className="public-kicker">Sắp ra mắt</p>
Các điểm đang bổ sung liệu. <h2 className="public-display public-heading-safe mt-3 text-[2rem] font-bold text-[var(--tour-ink)] sm:text-4xl">
</h2> Các di tích đang bổ sung liệu.
</h2>
</div>
<Link href="/di-tich" className="inline-flex items-center gap-2 text-sm font-extrabold text-[var(--tour-ink)] transition hover:text-[var(--primary)]">
Xem tất cả {heritageSites.length} di tích
<ArrowRight className="h-4 w-4" strokeWidth={1.8} />
</Link>
</div> </div>
<div className="mt-10 grid gap-4 md:grid-cols-2"> <div className="mt-10 grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
{upcomingSites.map((site) => ( {upcomingSites.map((site) => (
<HomeSiteCard key={site.id} site={site} /> <Link
key={site.id}
href={site.detailUrl}
className="public-panel public-stagger-item group flex flex-col rounded-[14px] p-5 transition hover:-translate-y-0.5"
>
<span className="flex items-center justify-between gap-3">
<span className="text-sm font-bold text-[var(--primary)]">{site.type}</span>
<span className="rounded-md border border-[rgb(200_164_106_/_0.24)] bg-[rgb(200_164_106_/_0.08)] px-2 py-0.5 text-[0.64rem] font-bold uppercase tracking-[0.06em] text-[var(--primary)]">
{site.level === "Cấp quốc gia" ? "Quốc gia" : "Cấp tỉnh"}
</span>
</span>
<span className="mt-2 text-lg font-bold leading-snug text-[var(--tour-ink)]">{site.name}</span>
<span className="mt-2 line-clamp-2 text-sm leading-6 text-[var(--muted-foreground)]">{site.shortDescription}</span>
<span className="mt-auto inline-flex items-center gap-1.5 pt-4 text-sm font-bold text-[var(--tour-ink)] transition group-hover:text-[var(--primary)]">
Xem thông tin
<ArrowRight className="h-4 w-4" strokeWidth={1.8} />
</span>
</Link>
))} ))}
</div> </div>
</section> </section>
@@ -147,7 +198,7 @@ export default function Home() {
const Icon = benefit.icon; const Icon = benefit.icon;
return ( return (
<article key={benefit.title} className="public-panel public-stagger-item rounded-[8px] p-5"> <article key={benefit.title} className="public-panel public-stagger-item rounded-[16px] p-6">
<Icon className="h-7 w-7 text-[var(--primary)]" strokeWidth={1.8} /> <Icon className="h-7 w-7 text-[var(--primary)]" strokeWidth={1.8} />
<h3 className="mt-5 text-xl font-bold text-[var(--tour-ink)]">{benefit.title}</h3> <h3 className="mt-5 text-xl font-bold text-[var(--tour-ink)]">{benefit.title}</h3>
<p className="mt-3 text-sm leading-6 text-[var(--muted-foreground)]">{benefit.detail}</p> <p className="mt-3 text-sm leading-6 text-[var(--muted-foreground)]">{benefit.detail}</p>
@@ -159,7 +210,7 @@ export default function Home() {
</section> </section>
<section className="px-4 py-14 sm:px-6 lg:py-20"> <section className="px-4 py-14 sm:px-6 lg:py-20">
<div className="public-panel public-glow mx-auto grid max-w-7xl gap-5 rounded-[8px] p-6 lg:grid-cols-[1fr_auto] lg:items-center lg:p-8"> <div className="public-panel public-glow mx-auto grid max-w-7xl gap-5 rounded-[18px] p-6 lg:grid-cols-[1fr_auto] lg:items-center lg:p-8">
<div> <div>
<p className="public-kicker">Bắt đu khám phá</p> <p className="public-kicker">Bắt đu khám phá</p>
<h2 className="public-heading-safe mt-2 text-3xl font-bold text-[var(--tour-ink)] sm:text-4xl"> <h2 className="public-heading-safe mt-2 text-3xl font-bold text-[var(--tour-ink)] sm:text-4xl">
@@ -184,7 +235,7 @@ export default function Home() {
function HomeSiteCard({ site }: { site: (typeof heritageSites)[number] }) { function HomeSiteCard({ site }: { site: (typeof heritageSites)[number] }) {
return ( return (
<article className="public-card public-stagger-item group grid overflow-hidden rounded-[8px] md:grid-cols-[0.92fr_1.08fr]"> <article className="public-card public-stagger-item group grid overflow-hidden rounded-[16px] md:grid-cols-[0.92fr_1.08fr]">
<div className="relative min-h-[18rem]"> <div className="relative min-h-[18rem]">
<Image <Image
src={site.image} src={site.image}
@@ -196,12 +247,13 @@ function HomeSiteCard({ site }: { site: (typeof heritageSites)[number] }) {
</div> </div>
<div className="flex min-h-[18rem] flex-col p-5 sm:p-6"> <div className="flex min-h-[18rem] flex-col p-5 sm:p-6">
<span <span
className={`w-fit rounded-full border px-3 py-1 text-xs font-extrabold ${ className={`inline-flex w-fit items-center gap-1.5 rounded-md border px-2.5 py-1 text-[0.7rem] font-bold uppercase tracking-[0.08em] ${
site.isAvailable site.isAvailable
? "border-[rgb(14_52_39_/_0.18)] bg-[rgb(14_92_62_/_0.12)] text-[var(--tour-ink)]" ? "border-[rgb(141_146_118_/_0.4)] bg-[rgb(141_146_118_/_0.16)] text-[var(--tour-gold-light)]"
: "border-[rgb(142_95_11_/_0.18)] bg-[rgb(142_95_11_/_0.1)] text-[var(--primary)]" : "border-[rgb(200_164_106_/_0.28)] bg-[rgb(200_164_106_/_0.1)] text-[var(--primary)]"
}`} }`}
> >
<span className={`h-1.5 w-1.5 rounded-full ${site.isAvailable ? "bg-[var(--tour-jade)]" : "bg-[var(--primary)]"}`} />
{site.status} {site.status}
</span> </span>
<p className="mt-4 text-sm font-bold text-[var(--primary)]">{site.type}</p> <p className="mt-4 text-sm font-bold text-[var(--primary)]">{site.type}</p>