Next.js 14 website with standalone output configured for Docker deployment. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
125 lines
4.7 KiB
TypeScript
125 lines
4.7 KiB
TypeScript
import { Metadata } from "next";
|
|
import { experiences } from "@/lib/constants";
|
|
import { generatePageMetadata } from "@/lib/metadata";
|
|
import { generateTouristTripSchema, generateBreadcrumbSchema } from "@/lib/structured-data";
|
|
import { ExperienceHero } from "@/components/experiences/ExperienceHero";
|
|
import { Itinerary } from "@/components/experiences/Itinerary";
|
|
import { BookingWidget } from "@/components/experiences/BookingWidget";
|
|
import { PhotoGallery } from "@/components/experiences/PhotoGallery";
|
|
import { Testimonials } from "@/components/home/Testimonials";
|
|
import { FinalCTA } from "@/components/home/FinalCTA";
|
|
|
|
const experience = experiences.find((e) => e.slug === "the-other-side")!;
|
|
|
|
export const metadata: Metadata = generatePageMetadata({
|
|
title: "The Other Side — Signature Asian Side Experience",
|
|
description: experience.hook,
|
|
path: "/experiences/the-other-side",
|
|
});
|
|
|
|
export default function TheOtherSidePage() {
|
|
return (
|
|
<>
|
|
<script
|
|
type="application/ld+json"
|
|
dangerouslySetInnerHTML={{
|
|
__html: JSON.stringify(generateTouristTripSchema(experience)),
|
|
}}
|
|
/>
|
|
<script
|
|
type="application/ld+json"
|
|
dangerouslySetInnerHTML={{
|
|
__html: JSON.stringify(
|
|
generateBreadcrumbSchema([
|
|
{ name: "Home", url: "https://theanatolianedit.com" },
|
|
{ name: "Experiences", url: "https://theanatolianedit.com/experiences" },
|
|
{ name: "The Other Side", url: "https://theanatolianedit.com/experiences/the-other-side" },
|
|
])
|
|
),
|
|
}}
|
|
/>
|
|
|
|
<ExperienceHero experience={experience} />
|
|
|
|
{/* Highlights */}
|
|
<section className="py-12 section-padding">
|
|
<div className="max-w-4xl mx-auto">
|
|
<div className="flex flex-wrap justify-center gap-4">
|
|
{experience.highlights.map((h, i) => (
|
|
<div
|
|
key={i}
|
|
className="inline-flex items-center gap-2 bg-warm-sand rounded-full px-5 py-3 text-sm text-deep-nazar font-medium"
|
|
>
|
|
<span className="text-lg">{h.icon}</span>
|
|
{h.text}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* What's Included */}
|
|
<section className="py-12 section-padding bg-warm-sand">
|
|
<div className="max-w-3xl mx-auto">
|
|
<h2 className="font-display text-2xl md:text-3xl font-bold text-deep-nazar mb-8 text-center">
|
|
What's Included
|
|
</h2>
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
{experience.includes.map((item, i) => (
|
|
<div key={i} className="flex items-start gap-3 bg-white rounded-2xl p-4">
|
|
<span className="text-bosphorus mt-0.5">
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
|
</svg>
|
|
</span>
|
|
<span className="text-deep-nazar/80 text-sm">{item}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{experience.itinerary && <Itinerary stops={experience.itinerary} />}
|
|
|
|
<PhotoGallery />
|
|
|
|
<BookingWidget experience={experience} />
|
|
|
|
<Testimonials />
|
|
|
|
{/* You Might Also Like */}
|
|
<section className="py-16 section-padding bg-warm-sand">
|
|
<div className="max-w-7xl mx-auto text-center">
|
|
<h2 className="font-display text-2xl md:text-3xl font-bold text-deep-nazar mb-8">
|
|
You Might Also Like
|
|
</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
{experiences
|
|
.filter((e) => e.slug !== "the-other-side")
|
|
.slice(0, 3)
|
|
.map((exp) => (
|
|
<a
|
|
key={exp.slug}
|
|
href={`/experiences/${exp.slug}`}
|
|
className="bg-white rounded-2xl p-6 shadow-sm hover:shadow-md transition-shadow text-left"
|
|
>
|
|
<p className="text-bosphorus font-semibold text-xs tracking-widest uppercase mb-1">
|
|
{exp.tagline}
|
|
</p>
|
|
<h3 className="font-display text-lg font-bold text-deep-nazar mb-2">
|
|
{exp.name}
|
|
</h3>
|
|
<p className="text-deep-nazar/60 text-sm mb-3">{exp.hook}</p>
|
|
<span className="text-coral-spritz font-semibold text-sm">
|
|
From €{exp.price} →
|
|
</span>
|
|
</a>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<FinalCTA />
|
|
</>
|
|
);
|
|
}
|