feat: add FestivalGallery component for showcasing festival moments with responsive grid layout
|
After Width: | Height: | Size: 289 KiB |
|
After Width: | Height: | Size: 257 KiB |
|
After Width: | Height: | Size: 262 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 428 KiB |
|
After Width: | Height: | Size: 332 KiB |
|
After Width: | Height: | Size: 235 KiB |
|
After Width: | Height: | Size: 309 KiB |
|
After Width: | Height: | Size: 473 KiB |
|
After Width: | Height: | Size: 432 KiB |
|
After Width: | Height: | Size: 480 KiB |
|
After Width: | Height: | Size: 565 KiB |
|
After Width: | Height: | Size: 650 KiB |
|
After Width: | Height: | Size: 561 KiB |
|
After Width: | Height: | Size: 339 KiB |
|
After Width: | Height: | Size: 480 KiB |
|
After Width: | Height: | Size: 527 KiB |
|
After Width: | Height: | Size: 382 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 431 KiB |
@@ -5,7 +5,7 @@ import AntiquityShowcaseClient from "./AntiquityShowcaseClient";
|
||||
import { BackToTopButton } from "@/app/components/landing/BackToTopButton";
|
||||
import { SiteFooter } from "@/app/components/landing/SiteFooter";
|
||||
import { SiteHeader } from "@/app/components/landing/SiteHeader";
|
||||
import { activeTour, antiquities } from "@/app/content";
|
||||
import { antiquities, subpageHero } from "@/app/content";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Cổ vật 3D | VR360 Như Quỳnh",
|
||||
@@ -25,7 +25,7 @@ export default function AntiquityPage() {
|
||||
<SiteHeader />
|
||||
|
||||
<section className="public-subpage-hero public-subpage-hero--compact relative isolate overflow-hidden border-b border-[var(--surface-border)]">
|
||||
<Image src={activeTour.shrineImage} alt="" fill priority sizes="100vw" className="public-subpage-hero-image public-parallax-bg object-cover" />
|
||||
<Image src={subpageHero.coVat} alt="" fill priority sizes="100vw" className="public-subpage-hero-image public-parallax-bg 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-rise public-hero-rule max-w-4xl">
|
||||
<p className="public-kicker">Phòng trưng bày số</p>
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import Image from "next/image";
|
||||
import { festivalGallery } from "@/app/content";
|
||||
|
||||
// Gallery "Khoảnh khắc lễ hội" — bố cục bento: dưới lg là lưới 2 cột đều, từ lg dùng
|
||||
// grid-auto-flow dense với vài ô lớn/cao để tạo nhịp điệu biên tập, tránh kiểu 3 thẻ đều.
|
||||
export function FestivalGallery() {
|
||||
return (
|
||||
<section className="mx-auto max-w-7xl px-4 py-14 sm:px-6 lg:py-20">
|
||||
<div className="public-split-reveal max-w-3xl rounded-[6px]">
|
||||
<p className="public-kicker">Khoảnh khắc lễ hội</p>
|
||||
<h2 className="public-display public-heading-safe mt-3 text-[2rem] font-bold text-[var(--tour-ink)] sm:text-4xl">
|
||||
Sắc màu hội làng bên ngôi chùa cổ
|
||||
</h2>
|
||||
<p className="mt-3 max-w-[64ch] text-sm leading-6 text-[var(--muted-foreground)] sm:text-base">
|
||||
Những khoảnh khắc thật của lễ hội truyền thống tại Chùa Pháp Vân (Thái Lạc) — đám rước, múa rồng,
|
||||
nghi thức tế lễ và đêm cầu an bên ngôi chùa cổ.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-9 grid auto-rows-[9.5rem] grid-cols-2 gap-3 sm:auto-rows-[12rem] sm:gap-4 lg:auto-rows-[12.5rem] lg:grid-cols-4 lg:[grid-auto-flow:dense]">
|
||||
{festivalGallery.map((photo) => (
|
||||
<figure
|
||||
key={photo.src}
|
||||
className={`public-stagger-item group relative overflow-hidden rounded-[14px] ring-1 ring-[var(--surface-border)] shadow-[0_18px_46px_rgb(37_75_54_/_0.14)] ${photo.span ?? ""}`}
|
||||
>
|
||||
<Image
|
||||
src={photo.src}
|
||||
alt={photo.alt}
|
||||
fill
|
||||
sizes="(max-width: 1024px) 50vw, 25vw"
|
||||
className="object-cover transition-transform duration-[900ms] ease-[cubic-bezier(.2,.9,.2,1)] group-hover:scale-[1.06]"
|
||||
/>
|
||||
<div
|
||||
aria-hidden
|
||||
className="absolute inset-0 bg-[linear-gradient(180deg,transparent_36%,rgb(8_31_23_/_0.82))] transition-opacity duration-500 group-hover:opacity-100"
|
||||
/>
|
||||
<figcaption className="absolute inset-x-0 bottom-0 p-4 sm:p-5">
|
||||
<p className="font-display-vn text-base font-extrabold leading-tight text-white drop-shadow-sm sm:text-lg">
|
||||
{photo.title}
|
||||
</p>
|
||||
<p className="mt-1 text-[0.78rem] leading-5 text-white/82 sm:text-sm">{photo.note}</p>
|
||||
</figcaption>
|
||||
</figure>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -21,7 +21,10 @@ export const activeTour = {
|
||||
title: "Chùa Thái Lạc (Pháp Vân tự)",
|
||||
subtitle: "Di tích quốc gia, chạm khắc gỗ thời Trần",
|
||||
href: "/tour/chua-thai-lac",
|
||||
heroImage: img("01.jpg"), // Chính diện cổng chùa
|
||||
// Ảnh nền hero (CSS background) — toàn cảnh lễ hội múa rồng, ảnh thật của di tích.
|
||||
heroImage: "/images/le-hoi/toan-canh-le-hoi.jpg",
|
||||
// Ảnh lớn bên phải hero — nghi lễ rước kiệu (qua next/image).
|
||||
heroFeatureImage: "/images/le-hoi/ruoc-kieu.jpg",
|
||||
coverImage: img("08.jpg"), // Chính sảnh
|
||||
gateImage: img("01.jpg"), // Chính diện cổng chùa
|
||||
shrineImage: img("11.jpg"), // Chính điện
|
||||
@@ -49,7 +52,7 @@ export const festivalVideo = {
|
||||
kicker: "Lễ hội & văn hóa",
|
||||
title: "Lễ hội cầu mưa Lạc Hồng – Văn Lâm",
|
||||
src: "/video/le-hoi-cau-mua-lac-hong-van-lam.mp4",
|
||||
poster: img("10.jpg"), // Đài lộ thiên giữa sân chùa — không gian nghi lễ ngoài trời
|
||||
poster: "/images/le-hoi/san-chua-tu-tren-cao.jpg", // Ảnh thật sân chùa ngày hội
|
||||
heading: "Lễ hội cầu mưa — nhịp sống tín ngưỡng Tứ Pháp",
|
||||
description: [
|
||||
"Lễ hội cầu mưa ở Lạc Hồng (Văn Lâm, Hưng Yên) là sinh hoạt tín ngưỡng lâu đời của cư dân nông nghiệp đồng bằng Bắc Bộ, gắn với hệ Tứ Pháp — Pháp Vân, Pháp Vũ, Pháp Lôi, Pháp Điện — cầu cho mưa thuận gió hòa, mùa màng tươi tốt.",
|
||||
@@ -59,6 +62,95 @@ export const festivalVideo = {
|
||||
ctaHref: "/tour/chua-thai-lac",
|
||||
} as const;
|
||||
|
||||
// Ảnh lễ hội thật của Chùa Pháp Vân (Thái Lạc) — Quang Trung, Lạc Hồng, Văn Lâm, Hưng Yên.
|
||||
// Đặt tại public/images/le-hoi/ với tên ASCII đã tối ưu (resize + nén) để an toàn khi triển khai.
|
||||
const leHoi = (file: string) => `/images/le-hoi/${file}`;
|
||||
|
||||
export type FestivalPhoto = {
|
||||
src: string;
|
||||
title: string;
|
||||
note: string;
|
||||
alt: string;
|
||||
// Lớp span Tailwind cho bố cục bento ở breakpoint lg (dưới lg là lưới 2 cột đều).
|
||||
span?: string;
|
||||
};
|
||||
|
||||
// Bộ ảnh "Khoảnh khắc lễ hội" — bố cục bento ở trang chủ. Ô đầu (đêm cầu an) làm ô chủ đạo.
|
||||
export const festivalGallery: FestivalPhoto[] = [
|
||||
{
|
||||
src: leHoi("le-cau-an-ban-dem.jpg"),
|
||||
title: "Lễ cầu an",
|
||||
note: "Phật tử dâng đèn hoa sen trong đêm hội",
|
||||
alt: "Phật tử áo tràng chắp tay bên đèn hoa sen trong lễ cầu an ban đêm tại Chùa Pháp Vân",
|
||||
span: "lg:col-span-2 lg:row-span-2",
|
||||
},
|
||||
{
|
||||
src: leHoi("toan-canh-le-hoi.jpg"),
|
||||
title: "Toàn cảnh đám rước",
|
||||
note: "Múa rồng và đoàn rước rợp sắc cờ",
|
||||
alt: "Toàn cảnh đám rước lễ hội với hai đoàn múa rồng vàng giữa hàng cây",
|
||||
span: "lg:col-span-2",
|
||||
},
|
||||
{
|
||||
src: leHoi("ruoc-kieu.jpg"),
|
||||
title: "Rước kiệu thánh",
|
||||
note: "Kiệu sơn son thếp vàng giữa sân lễ",
|
||||
alt: "Kiệu thánh sơn son thếp vàng được trai làng khiêng trong đám rước",
|
||||
},
|
||||
{
|
||||
src: leHoi("doan-khieng-kieu.jpg"),
|
||||
title: "Trai làng rước kiệu",
|
||||
note: "Khí thế đoàn rước qua đường làng",
|
||||
alt: "Đoàn trai làng cởi trần thắt đai đỏ vàng khiêng kiệu thánh qua đường làng",
|
||||
span: "lg:row-span-2",
|
||||
},
|
||||
{
|
||||
src: leHoi("mua-rong-cong-chua.jpg"),
|
||||
title: "Múa rồng trước Tam quan",
|
||||
note: "Sắc áo dài rực rỡ hai bên lối vào",
|
||||
alt: "Màn múa rồng trước Tam quan chùa với hàng người mặc áo dài cầm quạt hai bên",
|
||||
},
|
||||
{
|
||||
src: leHoi("nghi-thuc-san-chua.jpg"),
|
||||
title: "Nghi thức tế lễ",
|
||||
note: "Đội tế xếp hàng giữa sân chùa",
|
||||
alt: "Đội tế xếp hàng làm nghi thức giữa sân gạch chùa rợp cờ Phật giáo nhìn từ trên cao",
|
||||
span: "lg:col-span-2",
|
||||
},
|
||||
{
|
||||
src: leHoi("kieu-long-vang.jpg"),
|
||||
title: "Kiệu dưới tán lọng",
|
||||
note: "Lọng vàng che kiệu trong đám rước",
|
||||
alt: "Kiệu thánh dưới tán lọng vàng giữa dòng người trẩy hội",
|
||||
},
|
||||
{
|
||||
src: leHoi("san-chua-tu-tren-cao.jpg"),
|
||||
title: "Sân chùa ngày hội",
|
||||
note: "Rợp lọng vàng nhìn từ trên cao",
|
||||
alt: "Sân chùa ngày hội rợp lọng vàng và dòng người nhìn từ trên cao",
|
||||
},
|
||||
{
|
||||
src: leHoi("doan-ruoc-bo-lao.jpg"),
|
||||
title: "Đoàn rước bô lão",
|
||||
note: "Các cụ trong trang phục tế truyền thống",
|
||||
alt: "Đoàn các cụ bô lão mặc áo tế truyền thống cầm gậy đi trong đám rước",
|
||||
},
|
||||
{
|
||||
src: leHoi("tru-tri-le-hoi.jpg"),
|
||||
title: "Sư trụ trì chủ lễ",
|
||||
note: "Chủ lễ giữa đoàn rước long trọng",
|
||||
alt: "Sư trụ trì khoác áo cà sa vàng đi giữa hai hàng người cầm lọng và cờ lễ",
|
||||
},
|
||||
];
|
||||
|
||||
// Ảnh phần đầu (hero) của các trang con — dùng ảnh lễ hội thật thay cho ảnh panorama bị méo.
|
||||
export const subpageHero = {
|
||||
gioiThieu: leHoi("mua-rong-cong-chua.jpg"),
|
||||
diTich: leHoi("nghi-thuc-san-chua.jpg"),
|
||||
diTichFeature: leHoi("kieu-long-vang.jpg"),
|
||||
coVat: leHoi("tru-tri-le-hoi.jpg"),
|
||||
} as const;
|
||||
|
||||
export const navigation = [
|
||||
{ href: "/", label: "Trang chủ" },
|
||||
{ href: "/gioi-thieu", label: "Giới thiệu" },
|
||||
|
||||
@@ -6,7 +6,7 @@ import { BackToTopButton } from "@/app/components/landing/BackToTopButton";
|
||||
import { CulturalSpaceExplorer } from "@/app/components/landing/CulturalSpaceExplorer";
|
||||
import { SiteFooter } from "@/app/components/landing/SiteFooter";
|
||||
import { SiteHeader } from "@/app/components/landing/SiteHeader";
|
||||
import { activeTour, heritageSites } from "@/app/content";
|
||||
import { heritageSites, subpageHero } from "@/app/content";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Di tích | VR360 Như Quỳnh",
|
||||
@@ -21,7 +21,7 @@ export default function HeritageListPage() {
|
||||
|
||||
<section className="public-subpage-hero public-subpage-hero--compact relative isolate overflow-hidden border-b border-[var(--surface-border)]">
|
||||
<Image
|
||||
src={activeTour.gateImage}
|
||||
src={subpageHero.diTich}
|
||||
alt=""
|
||||
fill
|
||||
priority
|
||||
@@ -52,8 +52,8 @@ export default function HeritageListPage() {
|
||||
|
||||
<div className="public-image-stage public-hero-photo public-stagger-item hidden lg:block">
|
||||
<Image
|
||||
src={activeTour.coverImage}
|
||||
alt="Di sản văn hóa Xã Như Quỳnh"
|
||||
src={subpageHero.diTichFeature}
|
||||
alt="Kiệu rước dưới tán lọng vàng trong lễ hội Chùa Pháp Vân (Thái Lạc)"
|
||||
fill
|
||||
sizes="38vw"
|
||||
className="object-cover"
|
||||
|
||||
@@ -17,7 +17,7 @@ import { BackToTopButton } from "@/app/components/landing/BackToTopButton";
|
||||
import { CountUp } from "@/app/components/landing/CountUp";
|
||||
import { SiteFooter } from "@/app/components/landing/SiteFooter";
|
||||
import { SiteHeader } from "@/app/components/landing/SiteHeader";
|
||||
import { activeTour, antiquities, heritageSites, img } from "@/app/content";
|
||||
import { activeTour, antiquities, heritageSites, img, subpageHero } from "@/app/content";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Giới thiệu | VR360 Như Quỳnh",
|
||||
@@ -61,7 +61,7 @@ export default function AboutPage() {
|
||||
<SiteHeader />
|
||||
|
||||
<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 public-parallax-bg object-cover" />
|
||||
<Image src={subpageHero.gioiThieu} alt="" fill priority sizes="100vw" className="public-subpage-hero-image public-parallax-bg 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-rise public-hero-rule max-w-4xl">
|
||||
<p className="public-kicker">Giới thiệu</p>
|
||||
|
||||
@@ -3,6 +3,7 @@ import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { ArrowRight, Box, Globe2, Landmark, PlayCircle, Rotate3d, School, Sparkles } from "lucide-react";
|
||||
import { BackToTopButton } from "@/app/components/landing/BackToTopButton";
|
||||
import { FestivalGallery } from "@/app/components/landing/FestivalGallery";
|
||||
import { FestivalVideo } from "@/app/components/landing/FestivalVideo";
|
||||
import { HeritageMarquee } from "@/app/components/landing/HeritageMarquee";
|
||||
import { SiteFooter } from "@/app/components/landing/SiteFooter";
|
||||
@@ -84,8 +85,8 @@ export default function Home() {
|
||||
|
||||
<div className="public-image-stage public-stagger-item relative hidden min-h-[31rem] lg:block">
|
||||
<Image
|
||||
src={activeTour.coverImage}
|
||||
alt="Không gian di sản Xã Như Quỳnh được số hóa VR360"
|
||||
src={activeTour.heroFeatureImage}
|
||||
alt="Nghi lễ rước kiệu trong lễ hội Chùa Thái Lạc (Pháp Vân tự), Xã Như Quỳnh"
|
||||
fill
|
||||
priority
|
||||
sizes="42vw"
|
||||
@@ -162,6 +163,9 @@ export default function Home() {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Khoảnh khắc lễ hội — gallery bento ảnh thật, nối tiếp mạch "Lễ hội & văn hóa" */}
|
||||
<FestivalGallery />
|
||||
|
||||
<section className="mx-auto grid max-w-7xl gap-10 px-4 py-14 sm:px-6 lg:grid-cols-[0.8fr_1.2fr] lg:items-center lg:py-20">
|
||||
<div className="min-w-0">
|
||||
<p className="public-kicker">Giới thiệu nhanh</p>
|
||||
|
||||
@@ -158,7 +158,7 @@ const seeds: SceneSeed[] = [
|
||||
id: "video-le-hoi-cau-mua",
|
||||
title: "Lễ hội cầu mưa",
|
||||
eyebrow: EYEBROW,
|
||||
yaw: 119,
|
||||
yaw: 120,
|
||||
pitch: 2,
|
||||
iconType: "video",
|
||||
video: {
|
||||
|
||||