From fbf058c45fbdd6ba31a928d0f6b052fa6e510711 Mon Sep 17 00:00:00 2001 From: tuyenio Date: Tue, 23 Jun 2026 11:11:50 +0700 Subject: [PATCH] =?UTF-8?q?feat:=20CulturalSpaceExplorer=20l=E1=BB=8Dc=20t?= =?UTF-8?q?heo=20c=E1=BA=A5p=20x=E1=BA=BFp=20h=E1=BA=A1ng=20+=20lo?= =?UTF-8?q?=E1=BA=A1i=20di=20t=C3=ADch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../landing/CulturalSpaceExplorer.tsx | 180 ++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 src/app/components/landing/CulturalSpaceExplorer.tsx diff --git a/src/app/components/landing/CulturalSpaceExplorer.tsx b/src/app/components/landing/CulturalSpaceExplorer.tsx new file mode 100644 index 0000000..acdc9dd --- /dev/null +++ b/src/app/components/landing/CulturalSpaceExplorer.tsx @@ -0,0 +1,180 @@ +"use client"; + +import Image from "next/image"; +import Link from "next/link"; +import { ArrowRight, Search, SlidersHorizontal } from "lucide-react"; +import { useMemo, useState } from "react"; +import type { HeritageSite } from "@/app/content"; + +const statusFilters = ["Tất cả", "Đang mở tour", "Đang bổ sung tư liệu"] as const; +const levelFilters = ["Tất cả", "Cấp quốc gia", "Cấp tỉnh"] as const; +const typeFilters = ["Tất cả", "Đình", "Chùa", "Đền", "Văn miếu", "Di tích khác"] as const; + +type StatusFilter = (typeof statusFilters)[number]; +type LevelFilter = (typeof levelFilters)[number]; +type TypeFilter = (typeof typeFilters)[number]; + +export function CulturalSpaceExplorer({ sites }: { sites: HeritageSite[] }) { + const [query, setQuery] = useState(""); + const [status, setStatus] = useState("Tất cả"); + const [level, setLevel] = useState("Tất cả"); + const [type, setType] = useState("Tất cả"); + + const filteredSites = useMemo(() => { + const normalizedQuery = query.trim().toLocaleLowerCase("vi-VN"); + + return sites.filter((site) => { + const matchesQuery = + normalizedQuery.length === 0 || + site.name.toLocaleLowerCase("vi-VN").includes(normalizedQuery) || + site.type.toLocaleLowerCase("vi-VN").includes(normalizedQuery) || + site.shortDescription.toLocaleLowerCase("vi-VN").includes(normalizedQuery); + + const matchesStatus = status === "Tất cả" || site.status === status; + const matchesLevel = level === "Tất cả" || site.level === level; + const matchesType = type === "Tất cả" || site.type === type; + + return matchesQuery && matchesStatus && matchesLevel && matchesType; + }); + }, [query, sites, status, level, type]); + + return ( +
+
+
+ + + + + + + +
+
+ +
+

+ Hiển thị {filteredSites.length} / {sites.length} địa điểm +

+ +
+ + {filteredSites.length > 0 ? ( +
+ {filteredSites.map((site) => ( +
+
+ {site.name} +
+
+ + {site.status} + +

{site.type}

+

+ {site.name} +

+

+ {site.shortDescription} +

+ + {site.isAvailable ? "Khám phá VR360" : "Xem thông tin"} + + +
+
+ ))} +
+ ) : ( +
+ +

+ Không tìm thấy di tích phù hợp. Vui lòng thử lại với từ khóa khác. +

+
+ )} +
+ ); +} + +function FilterGroup({ + label, + options, + value, + onChange, +}: { + label: string; + options: T; + value: T[number]; + onChange: (value: T[number]) => void; +}) { + return ( +
+ {label} +
+ {options.map((option) => ( + + ))} +
+
+ ); +}