first commit
This commit is contained in:
154
app/accommodation/[slug]/page.tsx
Normal file
154
app/accommodation/[slug]/page.tsx
Normal file
@@ -0,0 +1,154 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import { resortData } from "@/src/data/resort";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { notFound, useParams } from "next/navigation";
|
||||
|
||||
const getCloudinaryUrl = (publicId: string) => {
|
||||
return `https://res.cloudinary.com/du7xohbct/image/upload/q_auto,f_auto,w_2000/${publicId}`;
|
||||
};
|
||||
|
||||
export default function RoomDetailsPage() {
|
||||
const params = useParams();
|
||||
const slug = params.slug as string;
|
||||
const lang = "tr"; // Mocked locale
|
||||
|
||||
const room = resortData.rooms.find((r) => r.slug === slug);
|
||||
|
||||
if (!room) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="bg-[#FAF9F6] min-h-screen">
|
||||
{/* Hero Header */}
|
||||
<section className="relative h-[65vh] w-full overflow-hidden">
|
||||
<motion.div
|
||||
initial={{ scale: 1.1 }}
|
||||
animate={{ scale: 1 }}
|
||||
transition={{ duration: 1.5 }}
|
||||
className="absolute inset-0"
|
||||
>
|
||||
<Image
|
||||
src={getCloudinaryUrl(room.mainImageId)}
|
||||
alt={room.name[lang]}
|
||||
fill
|
||||
className="object-cover brightness-75"
|
||||
priority
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
<div className="absolute inset-0 flex flex-col items-center justify-center text-center z-10 px-6">
|
||||
<motion.span
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="text-white text-xs tracking-[0.5em] font-bold uppercase mb-4"
|
||||
>
|
||||
{room.size} — {room.capacity}
|
||||
</motion.span>
|
||||
<motion.h1
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.2 }}
|
||||
className="text-white text-5xl md:text-8xl font-serif"
|
||||
>
|
||||
{room.name[lang]}
|
||||
</motion.h1>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Content Section */}
|
||||
<section className="max-w-7xl mx-auto px-6 py-32">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-20">
|
||||
|
||||
{/* Left: Description & Details */}
|
||||
<div className="lg:col-span-2 space-y-16">
|
||||
<div className="space-y-6">
|
||||
<h2 className="text-sm font-bold tracking-[0.3em] text-gold uppercase">ODA HAKKINDA</h2>
|
||||
<p className="text-2xl md:text-3xl font-serif text-gray-900 leading-relaxed font-light italic">
|
||||
{room.description[lang]}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-8 pt-10 border-t border-black/5">
|
||||
{room.features.map((f) => {
|
||||
const feat = resortData.featureIcons[f];
|
||||
return feat ? (
|
||||
<div key={f} className="flex items-center gap-4 group">
|
||||
<div className="w-12 h-12 rounded-full border border-black/5 flex items-center justify-center text-xl bg-white transition-colors group-hover:border-gold group-hover:bg-gold/5">
|
||||
{feat.icon}
|
||||
</div>
|
||||
<span className="text-[10px] font-bold tracking-widest text-gray-400 uppercase">
|
||||
{feat.label[lang]}
|
||||
</span>
|
||||
</div>
|
||||
) : null;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right: Sticky Sidebar / Call to Action */}
|
||||
<div className="lg:col-span-1">
|
||||
<div className="sticky top-32 bg-white p-10 shadow-2xl shadow-black/5 border border-black/5">
|
||||
<div className="space-y-8">
|
||||
<div>
|
||||
<h4 className="text-[10px] font-bold tracking-widest text-gray-400 uppercase mb-2">KONAKLAMA TİPİ</h4>
|
||||
<p className="text-xl font-serif text-gray-900">{room.capacity}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 className="text-[10px] font-bold tracking-widest text-gray-400 uppercase mb-2">ODA BÜYÜKLÜĞÜ</h4>
|
||||
<p className="text-xl font-serif text-gray-900">{room.size}</p>
|
||||
</div>
|
||||
|
||||
<div className="pt-8">
|
||||
<Link
|
||||
href={resortData.bookingUrl}
|
||||
className="block w-full bg-[#5C6353] text-white text-center py-5 text-[10px] font-bold tracking-[0.3em] uppercase hover:bg-gold transition-all"
|
||||
>
|
||||
ŞİMDİ REZERVASYON YAP
|
||||
</Link>
|
||||
<p className="mt-4 text-[9px] text-gray-400 text-center tracking-tight leading-normal">
|
||||
* En iyi fiyat garantisi ve resmi web sitesi avantajları ile yerinizi ayırtın.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Gallery Highlight */}
|
||||
<section className="bg-white py-24 pb-48">
|
||||
<div className="max-w-7xl mx-auto px-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-1">
|
||||
{room.galleryImageIds.slice(0, 3).map((id, i) => (
|
||||
<div key={id} className="relative aspect-square overflow-hidden group">
|
||||
<Image
|
||||
src={getCloudinaryUrl(id)}
|
||||
alt={`${room.name[lang]} Gallery ${i + 1}`}
|
||||
fill
|
||||
className="object-cover grayscale hover:grayscale-0 transition-all duration-700"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-20 text-center">
|
||||
<Link
|
||||
href="/accommodation"
|
||||
className="text-[10px] font-bold tracking-[0.4em] text-gray-400 hover:text-gold transition-colors inline-flex items-center gap-4"
|
||||
>
|
||||
<span className="w-12 h-px bg-current" />
|
||||
GERİ DÖN
|
||||
<span className="w-12 h-px bg-current" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
90
app/accommodation/page.tsx
Normal file
90
app/accommodation/page.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import { resortData } from "@/src/data/resort";
|
||||
import { useState } from "react";
|
||||
import AccommodationCard from "../components/AccommodationCard";
|
||||
|
||||
export default function AccommodationPage() {
|
||||
const lang = "tr";
|
||||
const [filter, setFilter] = useState<"all" | "rooms" | "residence">("all");
|
||||
|
||||
const filteredRooms = resortData.rooms.filter(room => {
|
||||
if (filter === "all") return true;
|
||||
if (filter === "rooms") return !room.slug.includes("rezidans");
|
||||
if (filter === "residence") return room.slug.includes("rezidans");
|
||||
return true;
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="bg-[#ECE7E1] min-h-screen pt-72 md:pt-96 pb-48 flex flex-col items-center">
|
||||
<div className="max-w-[1600px] mx-auto px-6 ">
|
||||
|
||||
{/* Header Section */}
|
||||
<div className="space-y-12 mb-32 mt-40">
|
||||
<div className="space-y-6">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
className="flex items-center gap-4"
|
||||
>
|
||||
<div className="w-12 h-px bg-gold" />
|
||||
<span className="text-gold text-[10px] tracking-[0.5em] font-bold uppercase block">
|
||||
KONAKLAMA DENEYİMİ
|
||||
</span>
|
||||
</motion.div>
|
||||
|
||||
<motion.h1
|
||||
initial={{ y: 30, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ delay: 0.1, duration: 0.8 }}
|
||||
className="text-6xl md:text-8xl font-serif text-gray-900 leading-[0.85] tracking-tight"
|
||||
>
|
||||
Zarafet & <br /><span className="italic font-light">Ege Serüveni</span>
|
||||
</motion.h1>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.3 }}
|
||||
className="pt-10 border-t border-black/5"
|
||||
>
|
||||
<p className="text-gray-500 font-light text-2xl leading-relaxed italic border-l-4 border-gold/20 pl-8 max-w-2xl">
|
||||
“Bardakçı Koyu'nun büyüleyici manzarasında, lüksün ve huzurun buluştuğu noktada sizi ağırlıyoruz.”
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<div className="flex bg-white p-2 rounded-full shadow-sm border border-black/5 w-fit">
|
||||
{["all", "rooms", "residence"].map((id) => (
|
||||
<button
|
||||
key={id}
|
||||
onClick={() => setFilter(id as any)}
|
||||
className={`px-10 py-3 rounded-full text-[10px] font-bold tracking-[0.2em] transition-all duration-500 ${filter === id ? "bg-[#5C6353] text-white shadow-lg" : "text-gray-400 hover:text-gray-900"
|
||||
}`}
|
||||
>
|
||||
{id === "all" ? "HEPSİ" : id === "rooms" ? "ODALAR" : "REZİDANS"}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Accommodation Grid - Single Column for Wide Mode */}
|
||||
<div className="flex flex-col gap-y-16">
|
||||
{filteredRooms.map((room) => (
|
||||
<motion.div
|
||||
key={room.slug}
|
||||
layout
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
>
|
||||
<AccommodationCard room={room} lang={lang} />
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user