156 lines
5.6 KiB
TypeScript
156 lines
5.6 KiB
TypeScript
import { useState } from 'preact/hooks';
|
|
import { Dialog, DialogPanel, DialogTitle, Tab, TabGroup, TabList, TabPanel, TabPanels, Transition, TransitionChild } from '@headlessui/react';
|
|
|
|
export interface FacilityItem {
|
|
text: string;
|
|
}
|
|
|
|
export interface FacilityCategory {
|
|
title: string;
|
|
items: FacilityItem[];
|
|
}
|
|
|
|
interface FacilitiesCardProps {
|
|
title?: string;
|
|
left: FacilityCategory[];
|
|
middle: FacilityCategory[];
|
|
right: FacilityCategory[];
|
|
seeMoreShow?: boolean;
|
|
}
|
|
|
|
function CategorySection({ category }: { category: FacilityCategory }) {
|
|
return (
|
|
<div className="mb-6">
|
|
<h4 className="text-[#C74F28] underline font-semibold mb-3">{category.title}</h4>
|
|
<ol className="list-decimal list-outside pl-5 flex flex-col gap-2.5">
|
|
{category.items.map((item, i) => (
|
|
<li key={i} className="text-md">
|
|
{item.text}
|
|
</li>
|
|
))}
|
|
</ol>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function FacilitiesCard({ title = 'Facilities & Amenities', left, middle, right, seeMoreShow }: FacilitiesCardProps) {
|
|
const [dialogOpen, setDialogOpen] = useState(false);
|
|
|
|
// Flatten all categories from the 3 columns into a single ordered list for tabs
|
|
const allCategories = [...left, ...middle, ...right];
|
|
|
|
function handleSeeMore() {
|
|
setDialogOpen(true);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<div className="w-full mt-4 bg-black/[0.27] p-6 rounded-xl">
|
|
<h3 className="text-center font-bold text-2xl mb-6">{title}</h3>
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
<div className={'border-r-2 border-x-gray-700'}>
|
|
{left.map((cat, i) => <CategorySection key={i} category={cat} />)}
|
|
</div>
|
|
<div className={'border-r-2 border-x-gray-700'}>
|
|
{middle.map((cat, i) => <CategorySection key={i} category={cat} />)}
|
|
</div>
|
|
<div className={''}>
|
|
{right.map((cat, i) => <CategorySection key={i} category={cat} />)}
|
|
</div>
|
|
</div>
|
|
{seeMoreShow !== undefined && (
|
|
<div className="flex justify-end mt-4">
|
|
<button
|
|
onClick={handleSeeMore}
|
|
className="text-sm text-tertiary underline underline-offset-2 hover:text-white transition-colors"
|
|
>
|
|
See more
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Dialog */}
|
|
<Transition show={dialogOpen}>
|
|
<Dialog onClose={() => setDialogOpen(false)} className="relative z-50">
|
|
|
|
{/* Backdrop */}
|
|
<TransitionChild
|
|
enter="ease-out duration-200"
|
|
enterFrom="opacity-0"
|
|
enterTo="opacity-100"
|
|
leave="ease-in duration-150"
|
|
leaveFrom="opacity-100"
|
|
leaveTo="opacity-0"
|
|
>
|
|
<div className="fixed inset-0 bg-black/70" />
|
|
</TransitionChild>
|
|
|
|
{/* Panel container */}
|
|
<div className="fixed inset-0 flex items-center justify-center p-4">
|
|
<TransitionChild
|
|
enter="ease-out duration-200"
|
|
enterFrom="opacity-0 scale-95"
|
|
enterTo="opacity-100 scale-100"
|
|
leave="ease-in duration-150"
|
|
leaveFrom="opacity-100 scale-100"
|
|
leaveTo="opacity-0 scale-95"
|
|
>
|
|
<DialogPanel className="bg-[#1a1a1a] text-white rounded-2xl w-full max-w-3xl max-h-[85vh] flex flex-col overflow-hidden relative">
|
|
|
|
{/* Close button — top right */}
|
|
<button
|
|
onClick={() => setDialogOpen(false)}
|
|
className="absolute top-5 right-5 text-tertiary hover:text-white transition-colors text-2xl leading-none w-9 h-9 flex items-center justify-center rounded-full hover:bg-white/10 z-10"
|
|
>
|
|
×
|
|
</button>
|
|
|
|
{/* Header */}
|
|
<div className="px-8 pt-8 pb-0 flex-shrink-0">
|
|
<DialogTitle className="text-4xl font-bold mb-5">{title}</DialogTitle>
|
|
|
|
{/* Pill tabs */}
|
|
<TabGroup>
|
|
<TabList className="flex flex-row gap-1 bg-[#2a2a2a] rounded-xl p-1 w-fit overflow-x-auto [-webkit-overflow-scrolling:touch] [&::-webkit-scrollbar]:hidden">
|
|
{allCategories.map((cat, i) => (
|
|
<Tab
|
|
key={i}
|
|
className="whitespace-nowrap px-5 py-2 text-sm font-medium text-tertiary rounded-lg transition-colors outline-none
|
|
data-[selected]:bg-black data-[selected]:text-white
|
|
hover:text-white"
|
|
>
|
|
{cat.title}
|
|
</Tab>
|
|
))}
|
|
</TabList>
|
|
|
|
{/* Tab panels */}
|
|
<TabPanels className="overflow-y-auto py-6 flex-1">
|
|
{allCategories.map((cat, i) => (
|
|
<TabPanel key={i}>
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-x-12 gap-y-4">
|
|
{cat.items.map((item, j) => (
|
|
<div key={j} className="flex items-start gap-3">
|
|
<span className="text-sm leading-relaxed">{item.text}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</TabPanel>
|
|
))}
|
|
</TabPanels>
|
|
</TabGroup>
|
|
</div>
|
|
|
|
</DialogPanel>
|
|
</TransitionChild>
|
|
</div>
|
|
|
|
</Dialog>
|
|
</Transition>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default FacilitiesCard;
|