- Replace flat mustard with softer champagne tones and gentler shadows - Hero eyebrow: Book direct · Shitaye Suite Hotel - Lighter pattern grid, chips, badges, card hover ring; meetings band ring toned down - Ignore .dev.vars and .wrangler for local secrets and cache Made-with: Cursor
154 lines
5.9 KiB
TypeScript
154 lines
5.9 KiB
TypeScript
import Image from "next/image";
|
|
import Link from "next/link";
|
|
import { notFound } from "next/navigation";
|
|
import { AmenityItem } from "@/components/AmenityItem";
|
|
import { MeetingHalfDayRate } from "@/components/MeetingHalfDayRate";
|
|
import { roomAmenities } from "@/lib/mocks/amenities";
|
|
import {
|
|
getAllMeetingSlugs,
|
|
getMeetingSpaceBySlug,
|
|
} from "@/lib/mocks/meetingSpaces";
|
|
import { siteConfig } from "@/lib/mocks/site";
|
|
import type { Metadata } from "next";
|
|
|
|
type Props = { params: Promise<{ slug: string }> };
|
|
|
|
export function generateStaticParams() {
|
|
return getAllMeetingSlugs().map((slug) => ({ slug }));
|
|
}
|
|
|
|
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
|
const { slug } = await params;
|
|
const m = getMeetingSpaceBySlug(slug);
|
|
if (!m) return { title: "Meeting space" };
|
|
return {
|
|
title: m.name,
|
|
description: m.shortDescription,
|
|
};
|
|
}
|
|
|
|
export default async function MeetingSpacePage({ params }: Props) {
|
|
const { slug } = await params;
|
|
const space = getMeetingSpaceBySlug(slug);
|
|
if (!space) notFound();
|
|
|
|
return (
|
|
<article className="bg-[var(--color-bg)]">
|
|
<div className="relative aspect-[21/9] min-h-[220px] w-full md:min-h-[320px]">
|
|
<Image
|
|
src={space.image}
|
|
alt={space.name}
|
|
fill
|
|
priority
|
|
className="object-cover"
|
|
sizes="100vw"
|
|
/>
|
|
<div className="absolute inset-0 bg-gradient-to-t from-black/75 to-transparent" />
|
|
<div className="absolute bottom-0 left-0 right-0 mx-auto max-w-7xl px-4 pb-8 md:px-8">
|
|
<Link
|
|
href="/#dining"
|
|
className="text-xs font-medium text-white/80 hover:text-white"
|
|
>
|
|
← Dining & venues
|
|
</Link>
|
|
<h1 className="mt-2 font-heading text-4xl text-white md:text-5xl">{space.name}</h1>
|
|
<p className="mt-2 max-w-2xl text-sm text-white/90">{space.shortDescription}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mx-auto max-w-7xl px-4 py-12 md:px-8 md:py-16">
|
|
<div className="grid gap-12 lg:grid-cols-[1fr_360px]">
|
|
<div>
|
|
<h2 className="font-heading text-2xl">Overview</h2>
|
|
<p className="mt-4 leading-relaxed text-[var(--color-muted)]">{space.longDescription}</p>
|
|
|
|
<div className="mt-10 grid gap-4 sm:grid-cols-2">
|
|
{space.gallery.slice(1).map((src) => (
|
|
<div key={src} className="relative aspect-[4/3] overflow-hidden rounded-2xl">
|
|
<Image
|
|
src={src}
|
|
alt={`${space.name} gallery`}
|
|
fill
|
|
className="object-cover"
|
|
sizes="(max-width:1024px) 100vw, 40vw"
|
|
/>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
<section className="mt-14">
|
|
<h2 className="font-heading text-2xl">Amenities & equipment</h2>
|
|
<ul className="mt-4 grid gap-2 sm:grid-cols-2">
|
|
{space.amenities.map((a) => (
|
|
<AmenityItem key={a.label} item={a} variant="card" />
|
|
))}
|
|
</ul>
|
|
</section>
|
|
|
|
<section className="mt-12">
|
|
<h2 className="font-heading text-2xl">Layouts</h2>
|
|
<ul className="mt-3 flex flex-wrap gap-2">
|
|
{space.layouts.map((l) => (
|
|
<li
|
|
key={l}
|
|
className="rounded-full border border-[var(--color-border)] bg-[var(--color-surface-muted)] px-4 py-1.5 text-sm"
|
|
>
|
|
{l}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</section>
|
|
|
|
<section className="mt-12">
|
|
<h2 className="font-heading text-2xl">Catering</h2>
|
|
<ul className="mt-3 space-y-2 text-sm text-[var(--color-muted)]">
|
|
{space.catering.map((c) => (
|
|
<li key={c}>· {c}</li>
|
|
))}
|
|
</ul>
|
|
</section>
|
|
</div>
|
|
|
|
<aside className="lg:sticky lg:top-28 lg:self-start">
|
|
<div className="rounded-2xl border border-[var(--color-border)] bg-[var(--color-surface)] p-6 shadow-sm">
|
|
<p className="text-xs font-semibold uppercase tracking-widest text-[var(--color-muted)]">
|
|
Capacity
|
|
</p>
|
|
<p className="mt-2 text-lg font-semibold text-[var(--color-text)]">{space.capacity}</p>
|
|
<p className="mt-4 text-xs font-semibold uppercase tracking-widest text-[var(--color-muted)]">
|
|
Floor
|
|
</p>
|
|
<p className="mt-1 font-medium">{space.floor}</p>
|
|
<MeetingHalfDayRate usdAmount={space.halfDayRateUsd} />
|
|
<a
|
|
href={`mailto:${siteConfig.email}?subject=${encodeURIComponent(`Event inquiry — ${space.name}`)}`}
|
|
className="btn-mustard mt-6 block w-full py-3 text-center text-sm"
|
|
>
|
|
Request a proposal
|
|
</a>
|
|
<a
|
|
href={`tel:${siteConfig.primaryPhone.replace(/\s/g, "")}`}
|
|
className="mt-3 block text-center text-sm font-semibold text-[var(--color-primary)] hover:underline"
|
|
>
|
|
Call {siteConfig.primaryPhone}
|
|
</a>
|
|
</div>
|
|
|
|
<div className="mt-6 rounded-2xl border border-[var(--color-border)] bg-[var(--color-surface-muted)] p-6">
|
|
<h3 className="text-sm font-semibold">Hotel guest amenities</h3>
|
|
<p className="mt-2 text-xs text-[var(--color-muted)]">
|
|
Delegates staying overnight enjoy the same in-room benefits:
|
|
</p>
|
|
<ul className="mt-3 grid gap-1">
|
|
{roomAmenities.slice(0, 6).map((a) => (
|
|
<AmenityItem key={a.label} item={a} variant="inline" />
|
|
))}
|
|
</ul>
|
|
</div>
|
|
</aside>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
);
|
|
}
|