Update gallery to bento grid, add real reviews, update phone numbers and locations
@@ -13,10 +13,10 @@ export async function generateMetadata({ params }: { params: Promise<{ lang: str
|
|||||||
const { lang } = await params;
|
const { lang } = await params;
|
||||||
return buildMeta(lang, "/aktiviteler", {
|
return buildMeta(lang, "/aktiviteler", {
|
||||||
title: "Aktiviteler | Kite Beach Akyaka",
|
title: "Aktiviteler | Kite Beach Akyaka",
|
||||||
description: "Kitesurf, yoga, SUP ve bisiklet kiralama. Akyaka'nın doğasında IKO sertifikalı eğitmenlerle unutulmaz deneyimler.",
|
description: "Kitesurf, yoga, SUP ve bisiklet kiralama. Akyaka'nın doğasında profesyonel eğitmenlerle unutulmaz deneyimler.",
|
||||||
}, {
|
}, {
|
||||||
title: "Activities | Kite Beach Akyaka",
|
title: "Activities | Kite Beach Akyaka",
|
||||||
description: "Kitesurf, yoga, SUP and bicycle rental. Unforgettable experiences in Akyaka with IKO certified instructors.",
|
description: "Kitesurf, yoga, SUP and bicycle rental. Unforgettable experiences in Akyaka with professional instructors.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ export default async function AktivitelerPage({ params }: { params: Promise<{ la
|
|||||||
|
|
||||||
{/* Activities */}
|
{/* Activities */}
|
||||||
<section className="py-20 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<section className="py-20 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
{activities.length > 0 ? activities.map((act, i) => (
|
{activities.length > 0 ? activities.map((act, i) => (
|
||||||
<ScrollReveal key={act.id} delay={i * 80}>
|
<ScrollReveal key={act.id} delay={i * 80}>
|
||||||
<div className="card-lift group bg-white rounded-3xl overflow-hidden border border-sand flex flex-col h-full">
|
<div className="card-lift group bg-white rounded-3xl overflow-hidden border border-sand flex flex-col h-full">
|
||||||
|
|||||||
@@ -23,13 +23,13 @@ const getAltText = (alt: string, isEn: boolean) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const gallery: { src: string; alt: string; category: "Odalar" | "Aktiviteler" | "Restoran" | "Doğa" }[] = [
|
const gallery: { src: string; alt: string; category: "Odalar" | "Aktiviteler" | "Restoran" | "Doğa" }[] = [
|
||||||
// { src: "https://images.unsplash.com/photo-1618773928121-c32242e63f39?q=80&w=2940&auto=format&fit=crop", alt: "Standart Oda", category: "Odalar" },
|
{ src: "https://images.unsplash.com/photo-1618773928121-c32242e63f39?q=80&w=2940&auto=format&fit=crop", alt: "Standart Oda", category: "Odalar" },
|
||||||
{ src: "https://images.unsplash.com/photo-1526367790999-0150786686a2?q=80&w=2940&auto=format&fit=crop", alt: "Kitesurf", category: "Aktiviteler" },
|
{ src: "https://images.unsplash.com/photo-1526367790999-0150786686a2?q=80&w=2940&auto=format&fit=crop", alt: "Kitesurf", category: "Aktiviteler" },
|
||||||
{ src: "https://images.unsplash.com/photo-1544551763-46a013bb70d5?q=80&w=2940&auto=format&fit=crop", alt: "Nehir Doğa", category: "Doğa" },
|
{ src: "https://images.unsplash.com/photo-1544551763-46a013bb70d5?q=80&w=2940&auto=format&fit=crop", alt: "Nehir Doğa", category: "Doğa" },
|
||||||
// { src: "https://images.unsplash.com/photo-1566665797739-1674de7a421a?q=80&w=2874&auto=format&fit=crop", alt: "Nehir Manzaralı Oda",category: "Odalar" },
|
{ src: "https://images.unsplash.com/photo-1566665797739-1674de7a421a?q=80&w=2874&auto=format&fit=crop", alt: "Nehir Manzaralı Oda",category: "Odalar" },
|
||||||
{ src: "https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?q=80&w=2940&auto=format&fit=crop", alt: "Restoran", category: "Restoran" },
|
{ src: "https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?q=80&w=2940&auto=format&fit=crop", alt: "Restoran", category: "Restoran" },
|
||||||
{ src: "https://images.unsplash.com/photo-1544367567-0f2fcb009e0b?q=80&w=2940&auto=format&fit=crop", alt: "Yoga", category: "Aktiviteler" },
|
{ src: "https://images.unsplash.com/photo-1544367567-0f2fcb009e0b?q=80&w=2940&auto=format&fit=crop", alt: "Yoga", category: "Aktiviteler" },
|
||||||
// { src: "https://images.unsplash.com/photo-1499955085172-a104c9463ece?q=80&w=2940&auto=format&fit=crop", alt: "Bungalow", category: "Odalar" },
|
{ src: "https://images.unsplash.com/photo-1499955085172-a104c9463ece?q=80&w=2940&auto=format&fit=crop", alt: "Bungalow", category: "Odalar" },
|
||||||
{ src: "https://images.unsplash.com/photo-1507525428034-b723cf961d3e?q=80&w=2940&auto=format&fit=crop", alt: "SUP", category: "Aktiviteler" },
|
{ src: "https://images.unsplash.com/photo-1507525428034-b723cf961d3e?q=80&w=2940&auto=format&fit=crop", alt: "SUP", category: "Aktiviteler" },
|
||||||
{ src: "https://images.unsplash.com/photo-1551504734-5ee1c4a1479b?q=80&w=2940&auto=format&fit=crop", alt: "Kahvaltı", category: "Restoran" },
|
{ src: "https://images.unsplash.com/photo-1551504734-5ee1c4a1479b?q=80&w=2940&auto=format&fit=crop", alt: "Kahvaltı", category: "Restoran" },
|
||||||
{ src: "https://images.unsplash.com/photo-1511994298241-608e28f14fde?q=80&w=2940&auto=format&fit=crop", alt: "Bisiklet", category: "Aktiviteler" },
|
{ src: "https://images.unsplash.com/photo-1511994298241-608e28f14fde?q=80&w=2940&auto=format&fit=crop", alt: "Bisiklet", category: "Aktiviteler" },
|
||||||
@@ -42,15 +42,15 @@ export default function GaleriPage({ params }: { params: Promise<{ lang: string
|
|||||||
const isEn = lang === "en";
|
const isEn = lang === "en";
|
||||||
|
|
||||||
const filters = isEn
|
const filters = isEn
|
||||||
? ["All", "Activities", "Restaurant", "Nature"]
|
? ["All", "Rooms", "Activities", "Restaurant", "Nature"]
|
||||||
: ["Tümü", "Aktiviteler", "Restoran", "Doğa"];
|
: ["Tümü", "Odalar", "Aktiviteler", "Restoran", "Doğa"];
|
||||||
|
|
||||||
const [active, setActive] = useState<string>(isEn ? "All" : "Tümü");
|
const [active, setActive] = useState<string>(isEn ? "All" : "Tümü");
|
||||||
const [lightbox, setLightbox] = useState<string | null>(null);
|
const [lightbox, setLightbox] = useState<string | null>(null);
|
||||||
|
|
||||||
const getInternalCategory = (filterName: string) => {
|
const getInternalCategory = (filterName: string) => {
|
||||||
if (filterName === "All" || filterName === "Tümü") return "Tümü";
|
if (filterName === "All" || filterName === "Tümü") return "Tümü";
|
||||||
// if (filterName === "Rooms") return "Odalar";
|
if (filterName === "Rooms") return "Odalar";
|
||||||
if (filterName === "Activities") return "Aktiviteler";
|
if (filterName === "Activities") return "Aktiviteler";
|
||||||
if (filterName === "Restaurant") return "Restoran";
|
if (filterName === "Restaurant") return "Restoran";
|
||||||
if (filterName === "Nature") return "Doğa";
|
if (filterName === "Nature") return "Doğa";
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ const valuesTr = [
|
|||||||
{
|
{
|
||||||
icon: Award,
|
icon: Award,
|
||||||
title: "Premium Deneyim",
|
title: "Premium Deneyim",
|
||||||
desc: "IKO sertifikalı kitesurf okulumuzdan restoranımıza kadar her noktada en yüksek kalite standartlarını sunuyoruz.",
|
desc: "Kitesurf okulumuzdan restoranımıza kadar her noktada en yüksek kalite standartlarını sunuyoruz.",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -49,21 +49,21 @@ const valuesEn = [
|
|||||||
{
|
{
|
||||||
icon: Award,
|
icon: Award,
|
||||||
title: "Premium Experience",
|
title: "Premium Experience",
|
||||||
desc: "From our IKO certified kitesurf school to our restaurant, we offer the highest quality standards at every point.",
|
desc: "From our kitesurf school to our restaurant, we offer the highest quality standards at every point.",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const statsTr = [
|
const statsTr = [
|
||||||
{ value: "10+", label: "Yıllık Deneyim" },
|
{ value: "10+", label: "Yıllık Deneyim" },
|
||||||
{ value: "500+", label: "Mutlu Misafir" },
|
{ value: "500+", label: "Mutlu Misafir" },
|
||||||
{ value: "3", label: "IKO Sertifikalı Eğitmen" },
|
{ value: "3", label: "Profesyonel Eğitmen" },
|
||||||
{ value: "4", label: "Benzersiz Aktivite" },
|
{ value: "4", label: "Benzersiz Aktivite" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const statsEn = [
|
const statsEn = [
|
||||||
{ value: "10+", label: "Years Experience" },
|
{ value: "10+", label: "Years Experience" },
|
||||||
{ value: "500+", label: "Happy Guests" },
|
{ value: "500+", label: "Happy Guests" },
|
||||||
{ value: "3", label: "IKO Certified Instructor" },
|
{ value: "3", label: "Professional Instructor" },
|
||||||
{ value: "4", label: "Unique Activity" },
|
{ value: "4", label: "Unique Activity" },
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -123,9 +123,9 @@ export default async function HakkimizdaPage({ params }: { params: Promise<{ lan
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{isEn ? (
|
{isEn ? (
|
||||||
"With our nature-friendly architecture, our kitchen supporting local producers, and our training center in IKO standards, we aim to be the face of sustainable tourism in Akyaka."
|
"With our nature-friendly architecture, our kitchen supporting local producers, and our professional training center, we aim to be the face of sustainable tourism in Akyaka."
|
||||||
) : (
|
) : (
|
||||||
"Doğaya saygılı mimarimiz, lokal üreticileri destekleyen mutfağımız ve IKO standartlarındaki eğitim merkezimizle, Akyaka'nın sürdürülebilir turizm yüzü olmayı hedefliyoruz."
|
"Doğaya saygılı mimarimiz, lokal üreticileri destekleyen mutfağımız ve profesyonel eğitim merkezimizle, Akyaka'nın sürdürülebilir turizm yüzü olmayı hedefliyoruz."
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ export default async function IletisimPage({ params }: { params: Promise<{ lang:
|
|||||||
{
|
{
|
||||||
icon: Phone,
|
icon: Phone,
|
||||||
label: "Phone / WhatsApp",
|
label: "Phone / WhatsApp",
|
||||||
value: "+90 533 081 6181",
|
value: "+90 544 504 03 10",
|
||||||
href: "tel:+905330816181",
|
href: "tel:+905445040310",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: Mail,
|
icon: Mail,
|
||||||
@@ -55,8 +55,8 @@ export default async function IletisimPage({ params }: { params: Promise<{ lang:
|
|||||||
{
|
{
|
||||||
icon: Phone,
|
icon: Phone,
|
||||||
label: "Telefon / WhatsApp",
|
label: "Telefon / WhatsApp",
|
||||||
value: "+90 533 081 6181",
|
value: "+90 544 504 03 10",
|
||||||
href: "tel:+905330816181",
|
href: "tel:+905445040310",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: Mail,
|
icon: Mail,
|
||||||
@@ -211,13 +211,13 @@ export default async function IletisimPage({ params }: { params: Promise<{ lang:
|
|||||||
{/* Map */}
|
{/* Map */}
|
||||||
<div className="rounded-3xl overflow-hidden border border-sand flex-grow min-h-[220px] relative">
|
<div className="rounded-3xl overflow-hidden border border-sand flex-grow min-h-[220px] relative">
|
||||||
<iframe
|
<iframe
|
||||||
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d12759.395175968393!2d28.3245!3d37.0564!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x14bf76cd1f1f1d1f%3A0x1d1f1f1f1f1f1f1f!2sAkyaka%2C%20Ula%2FMuğla!5e0!3m2!1str!2str!4v1650000000000!5m2!1str!2str"
|
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d1570.4884121408588!2d28.328470723755615!3d37.03786201891436!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x14bf9f4829fe7243%3A0xe3747440b7bf7a8f!2sKite%20Beach%20Akyaka!5e0!3m2!1str!2str!4v1784112071594!5m2!1str!2str"
|
||||||
width="100%"
|
width="100%"
|
||||||
height="100%"
|
height="100%"
|
||||||
style={{ border: 0 }}
|
style={{ border: 0 }}
|
||||||
allowFullScreen
|
allowFullScreen
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
referrerPolicy="no-referrer-when-downgrade"
|
referrerPolicy="strict-origin-when-cross-origin"
|
||||||
className="absolute inset-0"
|
className="absolute inset-0"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ function buildJsonLd(lang: string) {
|
|||||||
description: isEn
|
description: isEn
|
||||||
? "Boutique hotel and kitesurf center on the banks of Azmak River in Akyaka, Muğla."
|
? "Boutique hotel and kitesurf center on the banks of Azmak River in Akyaka, Muğla."
|
||||||
: "Akyaka, Muğla'da Azmak Nehri kıyısında butik otel ve kitesurf merkezi.",
|
: "Akyaka, Muğla'da Azmak Nehri kıyısında butik otel ve kitesurf merkezi.",
|
||||||
telephone: "+905330816181",
|
telephone: "+905445040310",
|
||||||
email: "info@kitebeachakyaka.com.tr",
|
email: "info@kitebeachakyaka.com.tr",
|
||||||
address: {
|
address: {
|
||||||
"@type": "PostalAddress",
|
"@type": "PostalAddress",
|
||||||
|
|||||||
@@ -1,111 +1,25 @@
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { Check, Wifi, Wind, Coffee, Eye, Trees } from "lucide-react";
|
import { Check, Info } from "lucide-react";
|
||||||
import ScrollReveal from "@/components/ScrollReveal";
|
import ScrollReveal from "@/components/ScrollReveal";
|
||||||
|
import BentoGallery from "@/components/BentoGallery";
|
||||||
|
|
||||||
const roomsTr = [
|
const galleryImages = [
|
||||||
{
|
"https://media.ayris.tech/t/kitebeachakyaka/rooms/WhatsApp%20Image%202026-07-13%20at%2017.02.15.jpeg",
|
||||||
img: "https://images.unsplash.com/photo-1618773928121-c32242e63f39?q=80&w=2940&auto=format&fit=crop",
|
"https://media.ayris.tech/t/kitebeachakyaka/rooms/WhatsApp%20Image%202026-07-13%20at%2017.02.18.jpeg",
|
||||||
tag: "Standart",
|
"https://media.ayris.tech/t/kitebeachakyaka/rooms/WhatsApp%20Image%202026-07-13%20at%2017.02.19.jpeg",
|
||||||
name: "Standart Oda",
|
"https://media.ayris.tech/t/kitebeachakyaka/rooms/WhatsApp%20Image%202026-07-13%20at%2017.02.20%20(1).jpeg",
|
||||||
desc: "Konforlu ve modern tasarımlı standart odalarımızda rahatlığın tadını çıkarın. Çift kişilik yatak ve şık dekorasyon ile dinlendirici bir atmosfer.",
|
"https://media.ayris.tech/t/kitebeachakyaka/rooms/WhatsApp%20Image%202026-07-13%20at%2017.02.20.jpeg",
|
||||||
sqm: "20 m²",
|
"https://media.ayris.tech/t/kitebeachakyaka/rooms/WhatsApp%20Image%202026-07-13%20at%2017.02.21.jpeg",
|
||||||
price: "₺4.500",
|
|
||||||
features: [
|
|
||||||
{ icon: Wifi, label: "Ücretsiz Wi-Fi" },
|
|
||||||
{ icon: Wind, label: "Klima" },
|
|
||||||
{ icon: Coffee, label: "Minibar" },
|
|
||||||
{ icon: Eye, label: "Bahçe Manzarası" },
|
|
||||||
],
|
|
||||||
reversed: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
img: "https://images.unsplash.com/photo-1566665797739-1674de7a421a?q=80&w=2874&auto=format&fit=crop",
|
|
||||||
tag: "Popüler",
|
|
||||||
name: "Nehir Manzaralı Oda",
|
|
||||||
desc: "Güne Azmak nehrinin eşsiz manzarası eşliğinde uyanacağınız ferah odalar. Balkonunuzda sabah kahvenizi yudumlarken doğanın sesini dinleyin.",
|
|
||||||
sqm: "25 m²",
|
|
||||||
price: "₺5.500",
|
|
||||||
features: [
|
|
||||||
{ icon: Eye, label: "Nehir Manzarası" },
|
|
||||||
{ icon: Trees, label: "Özel Balkon" },
|
|
||||||
{ icon: Coffee, label: "Nespresso Makinesi" },
|
|
||||||
{ icon: Wifi, label: "Ücretsiz Wi-Fi" },
|
|
||||||
],
|
|
||||||
reversed: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
img: "https://images.unsplash.com/photo-1499955085172-a104c9463ece?q=80&w=2940&auto=format&fit=crop",
|
|
||||||
tag: "Premium",
|
|
||||||
name: "Ahşap Bungalow",
|
|
||||||
desc: "Doğayla tamamen iç içe, bağımsız girişli ve teraslı ahşap tasarımlı yaşam alanı. Gizlilik ve huzur arayan çiftler için ideal.",
|
|
||||||
sqm: "35 m²",
|
|
||||||
price: "₺7.000",
|
|
||||||
features: [
|
|
||||||
{ icon: Trees, label: "Özel Teras" },
|
|
||||||
{ icon: Eye, label: "Doğa Manzarası" },
|
|
||||||
{ icon: Coffee, label: "Premium İkramlar" },
|
|
||||||
{ icon: Wind, label: "Klima" },
|
|
||||||
],
|
|
||||||
reversed: false,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const roomsEn = [
|
|
||||||
{
|
|
||||||
img: "https://images.unsplash.com/photo-1618773928121-c32242e63f39?q=80&w=2940&auto=format&fit=crop",
|
|
||||||
tag: "Standard",
|
|
||||||
name: "Standard Room",
|
|
||||||
desc: "Enjoy comfort in our modern standard rooms. Relaxing atmosphere with a double bed and stylish decoration.",
|
|
||||||
sqm: "20 m²",
|
|
||||||
price: "₺4.500",
|
|
||||||
features: [
|
|
||||||
{ icon: Wifi, label: "Free Wi-Fi" },
|
|
||||||
{ icon: Wind, label: "Air Conditioning" },
|
|
||||||
{ icon: Coffee, label: "Minibar" },
|
|
||||||
{ icon: Eye, label: "Garden View" },
|
|
||||||
],
|
|
||||||
reversed: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
img: "https://images.unsplash.com/photo-1566665797739-1674de7a421a?q=80&w=2874&auto=format&fit=crop",
|
|
||||||
tag: "Popular",
|
|
||||||
name: "River View Room",
|
|
||||||
desc: "Spacious rooms where you wake up to the unique view of the Azmak river. Listen to the sound of nature while sipping morning coffee on your private balcony.",
|
|
||||||
sqm: "25 m²",
|
|
||||||
price: "₺5.500",
|
|
||||||
features: [
|
|
||||||
{ icon: Eye, label: "River View" },
|
|
||||||
{ icon: Trees, label: "Private Balcony" },
|
|
||||||
{ icon: Coffee, label: "Nespresso Machine" },
|
|
||||||
{ icon: Wifi, label: "Free Wi-Fi" },
|
|
||||||
],
|
|
||||||
reversed: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
img: "https://images.unsplash.com/photo-1499955085172-a104c9463ece?q=80&w=2940&auto=format&fit=crop",
|
|
||||||
tag: "Premium",
|
|
||||||
name: "Wooden Bungalow",
|
|
||||||
desc: "Wooden living area with private entrance and terrace, fully integrated with nature. Ideal for couples seeking privacy and serenity.",
|
|
||||||
sqm: "35 m²",
|
|
||||||
price: "₺7.000",
|
|
||||||
features: [
|
|
||||||
{ icon: Trees, label: "Private Terrace" },
|
|
||||||
{ icon: Eye, label: "Nature View" },
|
|
||||||
{ icon: Coffee, label: "Premium Amenities" },
|
|
||||||
{ icon: Wind, label: "Air Conditioning" },
|
|
||||||
],
|
|
||||||
reversed: false,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export default async function OdalarPage({ params }: { params: Promise<{ lang: string }> }) {
|
export default async function OdalarPage({ params }: { params: Promise<{ lang: string }> }) {
|
||||||
const { lang } = await params;
|
const { lang } = await params;
|
||||||
const isEn = lang === "en";
|
const isEn = lang === "en";
|
||||||
const displayRooms = isEn ? roomsEn : roomsTr;
|
|
||||||
const displayAmenities = isEn
|
const displayAmenities = isEn
|
||||||
? ["Organic Breakfast Spread", "Free Parking", "Beach & River Access", "Sunbed & Towel", "Wi-Fi", "24/7 Reception"]
|
? ["Organic Breakfast Spread", "Free Parking", "Beach & River Access", "Sunbed & Towel", "Wi-Fi", "24/7 Reception", "Air Conditioning", "Minibar"]
|
||||||
: ["Organik Serpme Kahvaltı", "Ücretsiz Otopark", "Plaj & Nehir Erişimi", "Şezlong & Havlu", "Wi-Fi", "24/7 Resepsiyon"];
|
: ["Organik Serpme Kahvaltı", "Ücretsiz Otopark", "Plaj & Nehir Erişimi", "Şezlong & Havlu", "Wi-Fi", "24/7 Resepsiyon", "Klima", "Minibar"];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-background">
|
<div className="min-h-screen bg-background">
|
||||||
@@ -135,83 +49,65 @@ export default async function OdalarPage({ params }: { params: Promise<{ lang: s
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Room Listings */}
|
{/* Intro & Price */}
|
||||||
<section className="py-20 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<section className="py-20 max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div className="space-y-16">
|
<ScrollReveal className="text-center mb-12">
|
||||||
{displayRooms.map((room, i) => (
|
<h2 className="font-serif text-4xl font-bold text-dark mb-6">
|
||||||
<ScrollReveal key={i}>
|
{isEn ? "Comfort & Serenity" : "Konfor & Huzur"}
|
||||||
<div
|
</h2>
|
||||||
className="grid grid-cols-1 md:grid-cols-2 gap-0 bg-white rounded-3xl overflow-hidden shadow-sm border border-sand"
|
<p className="text-muted text-[15px] leading-relaxed mb-10 max-w-2xl mx-auto">
|
||||||
>
|
{isEn
|
||||||
{/* Image */}
|
? "All our rooms are carefully designed to offer you the ultimate relaxation, harmonizing with the natural beauty surrounding Akyaka. Enjoy modern amenities with a touch of Aegean warmth."
|
||||||
<div className={`relative h-80 md:h-auto ${room.reversed ? "md:order-2" : ""}`}>
|
: "Tüm odalarımız, Akyaka'yı çevreleyen doğal güzelliklerle uyum içinde, size en üst düzeyde rahatlama sunmak için özenle tasarlandı. Ege sıcaklığının dokunuşuyla modern olanakların keyfini çıkarın."}
|
||||||
<Image
|
</p>
|
||||||
src={room.img}
|
|
||||||
alt={room.name}
|
|
||||||
fill
|
|
||||||
sizes="(max-width: 768px) 100vw, 50vw"
|
|
||||||
className="object-cover"
|
|
||||||
/>
|
|
||||||
{/* Tag */}
|
|
||||||
<span className="absolute top-5 left-5 bg-dark/80 backdrop-blur-sm text-white text-[10px] font-bold px-3 py-1.5 rounded-full tracking-widest uppercase">
|
|
||||||
{room.tag}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Content */}
|
<div className="inline-flex items-center justify-center gap-4 bg-primary/10 border-2 border-primary/20 text-primary px-8 py-5 rounded-3xl shadow-sm">
|
||||||
<div className={`p-10 md:p-14 flex flex-col justify-center ${room.reversed ? "md:order-1" : ""}`}>
|
<Info size={24} className="text-accent" />
|
||||||
<span className="text-muted text-xs tracking-[0.2em] uppercase mb-3 block">{room.sqm}</span>
|
<div className="text-left">
|
||||||
<h2 className="font-serif text-3xl font-bold text-dark mb-4">{room.name}</h2>
|
<span className="block text-xs uppercase tracking-widest text-primary/70 mb-1">
|
||||||
<p className="text-gray-500 mb-8 leading-relaxed text-[15px]">{room.desc}</p>
|
{isEn ? "Standard Rate" : "Standart Fiyat"}
|
||||||
|
</span>
|
||||||
|
<span className="block font-bold text-xl md:text-2xl tracking-wide">
|
||||||
|
{isEn ? "8000 TL / Night (Breakfast Included)" : "8000 TL / Gecelik (Kahvaltı Dahil)"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ScrollReveal>
|
||||||
|
</section>
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-3 mb-10">
|
{/* Bento Grid Gallery */}
|
||||||
{room.features.map(({ icon: Icon, label }, j) => (
|
<section className="pb-24 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div key={j} className="flex items-center gap-2.5">
|
<ScrollReveal>
|
||||||
<div className="w-7 h-7 rounded-full bg-primary/8 flex items-center justify-center flex-shrink-0">
|
<BentoGallery images={galleryImages} />
|
||||||
<Icon size={13} className="text-primary" />
|
</ScrollReveal>
|
||||||
</div>
|
|
||||||
<span className="text-[13px] text-foreground/70">{label}</span>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex justify-between items-center pt-8 border-t border-sand">
|
<div className="text-center mt-16">
|
||||||
<div>
|
<Link
|
||||||
<span className="text-muted text-xs block mb-1 uppercase tracking-wider">
|
href={`/${lang}/iletisim`}
|
||||||
{isEn ? "Per Night" : "Gecelik"}
|
className="btn-shimmer bg-accent text-white px-10 py-4 rounded-full text-sm font-bold tracking-[0.15em] uppercase hover:bg-accent/90 transition-colors shadow-xl"
|
||||||
</span>
|
>
|
||||||
<span className="font-serif text-3xl font-bold text-dark">{room.price}</span>
|
{isEn ? "Contact For Reservation" : "Rezervasyon İçin İletişime Geçin"}
|
||||||
</div>
|
</Link>
|
||||||
<Link
|
|
||||||
href={`/${lang}/iletisim`}
|
|
||||||
className="btn-shimmer bg-accent text-white px-7 py-3.5 rounded-full text-[11px] font-bold tracking-[0.12em] uppercase hover:bg-accent/90 transition-colors shadow-lg"
|
|
||||||
>
|
|
||||||
{isEn ? "Contact Us" : "Bize Ulaşın"}
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ScrollReveal>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Info strip */}
|
{/* Info strip (Disabled)
|
||||||
<section className="py-16 bg-primary">
|
<section className="py-20 bg-primary">
|
||||||
<div className="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
||||||
<h3 className="font-serif text-3xl text-white font-bold mb-4">
|
<h3 className="font-serif text-3xl text-white font-bold mb-6">
|
||||||
{isEn ? "What's included in all rooms" : "Tüm odalarda dahil olanlar"}
|
{isEn ? "Included in your stay" : "Konaklamanıza dahil olanlar"}
|
||||||
</h3>
|
</h3>
|
||||||
<div className="flex flex-wrap justify-center gap-4 mt-8">
|
<div className="flex flex-wrap justify-center gap-5 mt-8">
|
||||||
{displayAmenities.map((item) => (
|
{displayAmenities.map((item) => (
|
||||||
<span key={item} className="inline-flex items-center gap-2 bg-white/10 text-white text-[13px] px-4 py-2 rounded-full border border-white/15">
|
<span key={item} className="inline-flex items-center gap-2.5 bg-white/10 text-white text-[14px] px-5 py-3 rounded-full border border-white/15 backdrop-blur-sm">
|
||||||
<Check size={13} className="text-accent" />
|
<Check size={16} className="text-accent" />
|
||||||
{item}
|
{item}
|
||||||
</span>
|
</span>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
*/}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,102 +1,64 @@
|
|||||||
import Image from "next/image";
|
import { getDictionary, Locale } from "./dictionaries";
|
||||||
import Link from "next/link";
|
import prisma from "@/lib/prisma";
|
||||||
import {
|
import { buildMeta } from "@/lib/metadata";
|
||||||
ArrowRight, Star, Wind, Anchor, Utensils, BedDouble, Sun,
|
import type { Metadata } from "next";
|
||||||
Waves, Bike, Coffee, Music, MapPin, Camera, Heart, Compass,
|
|
||||||
Fish, Mountain, Dumbbell, Leaf, Shield, Umbrella, Flame,
|
import HeroSection from "@/components/home/HeroSection";
|
||||||
type LucideIcon,
|
import FeaturesStrip from "@/components/home/FeaturesStrip";
|
||||||
} from "lucide-react";
|
import AboutSection from "@/components/home/AboutSection";
|
||||||
import ScrollReveal from "@/components/ScrollReveal";
|
import ActivitiesGrid from "@/components/home/ActivitiesGrid";
|
||||||
|
import EventsPreview from "@/components/home/EventsPreview";
|
||||||
|
import InstagramFeed from "@/components/home/InstagramFeed";
|
||||||
|
import TestimonialsSection from "@/components/home/TestimonialsSection";
|
||||||
|
import CtaBand from "@/components/home/CtaBand";
|
||||||
|
import RoomsSection from "@/components/home/RoomsSection";
|
||||||
|
|
||||||
export const revalidate = 3600;
|
export const revalidate = 3600;
|
||||||
|
|
||||||
const ICON_MAP: Record<string, LucideIcon> = {
|
|
||||||
Wind, Anchor, Utensils, BedDouble, Sun, Star, Waves, Bike,
|
|
||||||
Coffee, Music, MapPin, Camera, Heart, Compass, Fish, Mountain,
|
|
||||||
Dumbbell, Leaf, Shield, Umbrella, Flame,
|
|
||||||
};
|
|
||||||
|
|
||||||
import HeroVideo from "@/components/HeroVideo";
|
|
||||||
|
|
||||||
const defaultFeatures = [
|
const defaultFeatures = [
|
||||||
{ icon: "Wind", label: "Kitesurf Okulu", sub: "IKO Sertifikalı" },
|
{ icon: "Wind", label: "Kitesurf", sub: "Eğitimleri" },
|
||||||
{ icon: "Anchor", label: "Yoga Platformu", sub: "Nehir Kenarı" },
|
{ icon: "Anchor", label: "Yoga Wellness", sub: "Platform" },
|
||||||
{ icon: "Utensils", label: "Restoran & Bar", sub: "Ege Mutfağı" },
|
{ icon: "Utensils", label: "Restoran & Bar", sub: "Ege Mutfağı" },
|
||||||
// { icon: "BedDouble", label: "Butik Odalar", sub: "3 Tip Konaklama" },
|
{ icon: "BedDouble", label: "Butik Odalar", sub: "3 Tip Konaklama" },
|
||||||
{ icon: "Sun", label: "Gün Batımı Terası", sub: "Gökova Manzarası" },
|
{ icon: "Sun", label: "Sunset DJ Party", sub: "Etkinlikler" },
|
||||||
];
|
|
||||||
|
|
||||||
const rooms = [
|
|
||||||
{
|
|
||||||
img: "https://images.unsplash.com/photo-1618773928121-c32242e63f39?q=80&w=2940&auto=format&fit=crop",
|
|
||||||
badge: "Standart",
|
|
||||||
badgeStyle: "bg-white/90 text-dark",
|
|
||||||
name: "Standart Oda",
|
|
||||||
desc: "Konforlu ve modern tasarımlı odamızda huzurlu bir konaklama.",
|
|
||||||
price: "₺4.500",
|
|
||||||
cta: "primary" as const,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
img: "https://images.unsplash.com/photo-1566665797739-1674de7a421a?q=80&w=2874&auto=format&fit=crop",
|
|
||||||
badge: "Popüler",
|
|
||||||
badgeStyle: "bg-accent text-white",
|
|
||||||
name: "Nehir Manzaralı Oda",
|
|
||||||
desc: "Azmak nehrinin eşsiz manzarası eşliğinde güne uyanın.",
|
|
||||||
price: "₺5.500",
|
|
||||||
cta: "accent" as const,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
img: "https://images.unsplash.com/photo-1499955085172-a104c9463ece?q=80&w=2940&auto=format&fit=crop",
|
|
||||||
badge: "Premium",
|
|
||||||
badgeStyle: "bg-white/90 text-dark",
|
|
||||||
name: "Ahşap Bungalow",
|
|
||||||
desc: "Doğayla tamamen iç içe, teraslı ve bağımsız girişli.",
|
|
||||||
price: "₺7.000",
|
|
||||||
cta: "primary" as const,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const testimonials = [
|
const testimonials = [
|
||||||
{
|
{
|
||||||
text: "Akyaka'da pek çok yerde kaldım ama Kite Beach bambaşka bir deneyimdi. Nehrin sesi, kitesurf dersleri ve muhteşem kahvaltı — her şey mükemmeldi.",
|
text: "Çok atmosferik bir yer. Harika ortam, uçurtma ve rüzgar. Kahve fena değil ama biraz pahalı.",
|
||||||
name: "Ayşe K.",
|
name: "Elena Gerasimova",
|
||||||
from: "İstanbul",
|
from: "Google Yorumları",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: "Yoga seansları ahşap platformda, sabah erken saatte, nehir manzarası eşliğinde. Kelimelerle anlatmak zor — mutlaka yaşanmalı.",
|
text: "Ortama, plaja ve kitesurf yapanları izlemeye bayıldım. Takılacak bir sürü harika yer, iyi yemek ve iyi müzik var. Kitesurf'e uğramadan Akyaka'ya gelmiş sayılmazsınız.",
|
||||||
name: "Marco B.",
|
name: "Dhyani Love",
|
||||||
from: "İtalya",
|
from: "Google Yorumları",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: "Eğitmenler son derece ilgili. Kitesurf derslerimden sonra bağımlısı oldum. Önümüzdeki yaz mutlaka döneceğim.",
|
text: "Harika bir kitesurf plajı. Öğleden sonraları istikrarlı termal rüzgarlar ve yumuşak kum. Çoğu sörfçü (Eylül-Ekim) dalış kıyafeti giyiyor ama ben şortla bile rahattım. Sadece plaja girmek için ödeme yapmanıza gerek yok, yalnızca sörf yapacaksanız ödüyorsunuz.",
|
||||||
name: "Mehmet Ö.",
|
name: "Shebastian Reyes",
|
||||||
from: "Ankara",
|
from: "Google Yorumları",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const testimonialsEn = [
|
const testimonialsEn = [
|
||||||
{
|
{
|
||||||
text: "I've stayed in many places in Akyaka, but Kite Beach was a completely different experience. The sound of the river, kitesurf lessons, and the amazing breakfast — everything was perfect.",
|
text: "Very atmospheric place. Cool man, kite and wind. Coffee not bad, but expensive.",
|
||||||
name: "Ayse K.",
|
name: "Elena Gerasimova",
|
||||||
from: "Istanbul",
|
from: "Google Reviews",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: "Yoga sessions on the wooden platform, early in the morning with a river view. Hard to put into words — a must-try.",
|
text: "Loved the vibes love the beach and watching kite surfers. Lots of cool places to hang out, good food and good music. You cannot come to Akyaka without coming to kite surfing.",
|
||||||
name: "Marco B.",
|
name: "Dhyani Love",
|
||||||
from: "Italy",
|
from: "Google Reviews",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: "The instructors are very caring. After my kitesurf lessons, I became addicted. I will definitely return next summer.",
|
text: "Great kite beach. Steady thermal afternoon winds and soft sand. Most kiters wear a wetsuit (Sep - Oct) but I was fine with just board shorts. You don't have to pay just to go to the beach, only if you plan to kite.",
|
||||||
name: "Mehmet O.",
|
name: "Shebastian Reyes",
|
||||||
from: "Ankara",
|
from: "Google Reviews",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
import { getDictionary, Locale } from "./dictionaries";
|
|
||||||
import prisma from "@/lib/prisma";
|
|
||||||
import { buildMeta } from "@/lib/metadata";
|
|
||||||
import type { Metadata } from "next";
|
|
||||||
|
|
||||||
export async function generateMetadata(
|
export async function generateMetadata(
|
||||||
{ params }: { params: Promise<{ lang: string }> }
|
{ params }: { params: Promise<{ lang: string }> }
|
||||||
): Promise<Metadata> {
|
): Promise<Metadata> {
|
||||||
@@ -185,519 +147,23 @@ export default async function Home({ params }: { params: Promise<{ lang: string
|
|||||||
statsGuestLabel: lang === "en" ? "Happy Guests" : "Mutlu Misafir",
|
statsGuestLabel: lang === "en" ? "Happy Guests" : "Mutlu Misafir",
|
||||||
statsYearCount: "10+",
|
statsYearCount: "10+",
|
||||||
statsYearLabel: lang === "en" ? "Years Experience" : "Yıl Deneyim",
|
statsYearLabel: lang === "en" ? "Years Experience" : "Yıl Deneyim",
|
||||||
badgeIkoTitle: "IKO",
|
badgeIkoTitle: "Kitesurf",
|
||||||
badgeIkoLabel: lang === "en" ? "Certified" : "Sertifikalı"
|
badgeIkoLabel: lang === "en" ? "School" : "Okulu"
|
||||||
};
|
};
|
||||||
|
|
||||||
const displayFeatures = dbFeatures.length > 0 ? dbFeatures : defaultFeatures;
|
const displayFeatures = dbFeatures.length > 0 ? dbFeatures : defaultFeatures;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col min-h-screen">
|
<div className="flex flex-col min-h-screen">
|
||||||
|
<HeroSection heroData={heroData} lang={lang} />
|
||||||
{/* ──────────────────────────────────────────
|
<FeaturesStrip features={displayFeatures} />
|
||||||
HERO
|
<AboutSection aboutData={aboutData} lang={lang} />
|
||||||
────────────────────────────────────────── */}
|
<RoomsSection lang={lang} />
|
||||||
<section className="relative h-screen w-full flex items-center justify-center overflow-hidden">
|
<ActivitiesGrid activities={activities} lang={lang} />
|
||||||
<HeroVideo />
|
<EventsPreview events={events} lang={lang} />
|
||||||
|
<InstagramFeed instagramPosts={instagramPosts} lang={lang} />
|
||||||
{/* Floating season badge
|
<TestimonialsSection testimonials={displayTestimonials} lang={lang} />
|
||||||
<div className="absolute top-32 right-6 md:right-16 z-20 animate-float hidden sm:block">
|
<CtaBand lang={lang} />
|
||||||
<div className="bg-white/10 backdrop-blur-md border border-white/20 rounded-2xl px-5 py-4 text-white">
|
|
||||||
<span className="block text-accent font-bold text-[10px] tracking-[0.25em] uppercase mb-1">Sezon</span>
|
|
||||||
<span className="font-serif text-xl font-medium">Nisan — Ekim</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
*/}
|
|
||||||
<div className="relative z-10 text-center px-4 max-w-5xl mx-auto">
|
|
||||||
<div className="animate-fade-up delay-100">
|
|
||||||
<span className="inline-block text-white/60 text-xs tracking-[0.35em] uppercase mb-8 font-light">
|
|
||||||
{heroData.location}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-center justify-center gap-4 md:gap-6 mb-6 animate-fade-up delay-200">
|
|
||||||
<span
|
|
||||||
className="text-xs md:text-sm tracking-[0.4em] font-bold uppercase whitespace-nowrap text-white/90"
|
|
||||||
style={{ writingMode: 'vertical-rl', transform: 'rotate(180deg)' }}
|
|
||||||
>
|
|
||||||
{heroData.welcome}
|
|
||||||
</span>
|
|
||||||
<h1 className="font-sans font-black text-white leading-none tracking-tighter text-[clamp(4rem,10vw,10rem)] uppercase">
|
|
||||||
{heroData.title}
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p className="animate-fade-up delay-500 text-white/75 text-base md:text-xl mb-10 font-light italic tracking-wide">
|
|
||||||
{heroData.subtitle}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="animate-fade-up delay-600 flex flex-col sm:flex-row items-center justify-center gap-4">
|
|
||||||
|
|
||||||
<Link
|
|
||||||
href={`/${lang}/aktiviteler`}
|
|
||||||
className="bg-white/10 backdrop-blur-sm border border-white/30 text-white px-10 py-4 rounded-full text-xs font-bold tracking-[0.15em] uppercase hover:bg-white/20 transition-colors w-full sm:w-auto text-center"
|
|
||||||
>
|
|
||||||
{heroData.exploreActivities}
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Scroll indicator */}
|
|
||||||
<div className="absolute bottom-10 left-1/2 -translate-x-1/2 z-20 flex flex-col items-center gap-3">
|
|
||||||
<span className="text-white/40 text-[10px] tracking-[0.3em] uppercase">{heroData.scroll}</span>
|
|
||||||
<div className="w-px h-12 bg-gradient-to-b from-white/40 to-transparent animate-scroll-bounce" />
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* ──────────────────────────────────────────
|
|
||||||
FEATURES STRIP
|
|
||||||
────────────────────────────────────────── */}
|
|
||||||
<section className="bg-dark text-white py-8">
|
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
||||||
<div className="grid grid-cols-2 md:grid-cols-5 divide-x divide-white/8">
|
|
||||||
{displayFeatures.map(({ icon, label, sub }, i) => {
|
|
||||||
const IconComponent = ICON_MAP[icon as string] || Star;
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={i}
|
|
||||||
className={`flex flex-col items-center justify-center gap-2 py-6 px-4 group ${i >= 2 ? "hidden md:flex" : ""}`}
|
|
||||||
>
|
|
||||||
<IconComponent className="w-5 h-5 text-accent group-hover:scale-110 transition-transform duration-300" />
|
|
||||||
<span className="text-[13px] font-semibold text-center">{label}</span>
|
|
||||||
<span className="text-[11px] text-white/40 text-center">{sub}</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* ──────────────────────────────────────────
|
|
||||||
ABOUT
|
|
||||||
────────────────────────────────────────── */}
|
|
||||||
<section className="py-28 bg-background overflow-hidden">
|
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 lg:gap-24 items-center">
|
|
||||||
|
|
||||||
<ScrollReveal className="relative">
|
|
||||||
<div className="relative h-[540px] lg:h-[660px] rounded-3xl overflow-hidden shadow-2xl">
|
|
||||||
<Image
|
|
||||||
src={aboutData.image}
|
|
||||||
alt={aboutData.badge}
|
|
||||||
fill
|
|
||||||
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
|
||||||
className="object-cover"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{/* Stats card */}
|
|
||||||
<div className="absolute -bottom-5 -right-4 md:-right-8 bg-white rounded-2xl p-6 shadow-xl border border-sand">
|
|
||||||
<div className="grid grid-cols-2 gap-6 divide-x divide-sand">
|
|
||||||
<div className="text-center">
|
|
||||||
<span className="block font-serif text-3xl font-bold text-primary">{aboutData.statsGuestCount}</span>
|
|
||||||
<span className="block text-[10px] text-muted uppercase tracking-wider mt-1">{aboutData.statsGuestLabel}</span>
|
|
||||||
</div>
|
|
||||||
<div className="text-center pl-6">
|
|
||||||
<span className="block font-serif text-3xl font-bold text-primary">{aboutData.statsYearCount}</span>
|
|
||||||
<span className="block text-[10px] text-muted uppercase tracking-wider mt-1">{aboutData.statsYearLabel}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* IKO badge */}
|
|
||||||
<div className="absolute -top-4 -left-4 bg-accent text-white rounded-2xl p-4 shadow-lg">
|
|
||||||
<Star className="w-4 h-4 mb-1" fill="white" />
|
|
||||||
<span className="block text-xs font-bold leading-none">{aboutData.badgeIkoTitle}</span>
|
|
||||||
<span className="block text-[10px] opacity-80 mt-0.5">{aboutData.badgeIkoLabel}</span>
|
|
||||||
</div>
|
|
||||||
</ScrollReveal>
|
|
||||||
|
|
||||||
<ScrollReveal delay={200}>
|
|
||||||
<span className="inline-block text-accent text-xs tracking-[0.25em] uppercase font-semibold mb-5">
|
|
||||||
{aboutData.badge}
|
|
||||||
</span>
|
|
||||||
<h2 className="font-serif text-4xl md:text-5xl lg:text-6xl font-bold text-dark leading-[1.05] mb-8">
|
|
||||||
{aboutData.titleLine1}<br />{aboutData.titleLine2}<br />
|
|
||||||
<span className="text-primary italic">{aboutData.titleHighlight}</span>
|
|
||||||
</h2>
|
|
||||||
<p className="text-gray-600 leading-relaxed mb-5">
|
|
||||||
{aboutData.description1}
|
|
||||||
</p>
|
|
||||||
<p className="text-gray-600 leading-relaxed mb-10">
|
|
||||||
{aboutData.description2}
|
|
||||||
</p>
|
|
||||||
<div className="section-line mb-8" />
|
|
||||||
<Link
|
|
||||||
href={`/${lang}/hakkimizda`}
|
|
||||||
className="inline-flex items-center gap-2 text-dark font-bold text-sm tracking-wide group"
|
|
||||||
>
|
|
||||||
<span className="border-b-2 border-accent pb-0.5">
|
|
||||||
{lang === "en" ? "Read Our Story" : "Hikayemizi Okuyun"}
|
|
||||||
</span>
|
|
||||||
<ArrowRight className="w-4 h-4 group-hover:translate-x-1.5 transition-transform" />
|
|
||||||
</Link>
|
|
||||||
</ScrollReveal>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* ──────────────────────────────────────────
|
|
||||||
ROOMS
|
|
||||||
────────────────────────────────────────── */}
|
|
||||||
{/*
|
|
||||||
<section className="py-28 bg-white">
|
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
||||||
<ScrollReveal className="text-center mb-16">
|
|
||||||
<span className="inline-block text-accent text-xs tracking-[0.25em] uppercase font-semibold mb-4">
|
|
||||||
Konaklama
|
|
||||||
</span>
|
|
||||||
<h2 className="font-serif text-4xl md:text-5xl font-bold text-dark mb-6">Kite Beach Akyaka Otel</h2>
|
|
||||||
<p className="text-muted max-w-3xl mx-auto text-sm leading-relaxed">
|
|
||||||
Akyaka’nın en güzel köşesinde, nehrin dinginliği ile denizin sonsuz maviliğinin kucaklaştığı o özel noktadayız. Kapınızı açtığınız anda sizi karşılayan nehir kıyısının sessizliği, güne başlamak için en huzurlu davetiniz olacak. Doğanın kalbinde, nehir manzarasına karşı yaptığınız bir yoga seansıyla ruhunuzu dengelerken; hemen ardından Akyaka’nın meşhur rüzgarlarında Kite Surf ile adrenalini zirveye taşıyabilirsiniz. Günün yorgunluğunu ise, restoranımızın mutfağından çıkan lezzetlerle, Ege’nin kendine has o büyüleyici gün batımını izleyerek geride bırakın. Burada zaman, sadece sizin istediğiniz hızda akıyor.
|
|
||||||
</p>
|
|
||||||
</ScrollReveal>
|
|
||||||
|
|
||||||
<ScrollReveal stagger className="grid grid-cols-1 md:grid-cols-3 gap-6 md:gap-8">
|
|
||||||
{rooms.map((room, i) => (
|
|
||||||
<div
|
|
||||||
key={i}
|
|
||||||
className={`card-lift group rounded-2xl overflow-hidden bg-sand border border-sand ${i === 1 ? "md:-mt-4 md:shadow-xl" : ""
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div className="relative h-64 overflow-hidden">
|
|
||||||
<Image
|
|
||||||
src={room.img}
|
|
||||||
alt={room.name}
|
|
||||||
fill
|
|
||||||
sizes="(max-width: 768px) 100vw, 33vw"
|
|
||||||
className="object-cover group-hover:scale-105 transition-transform duration-700"
|
|
||||||
/>
|
|
||||||
<span className={`absolute top-4 left-4 text-[10px] font-bold px-3 py-1.5 rounded-full tracking-wider uppercase ${room.badgeStyle} backdrop-blur-sm`}>
|
|
||||||
{room.badge}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="p-7">
|
|
||||||
<h3 className="font-serif text-xl font-bold text-dark mb-2">{room.name}</h3>
|
|
||||||
<p className="text-muted mb-6 text-[13px] leading-relaxed">{room.desc}</p>
|
|
||||||
<div className="flex justify-between items-center pt-5 border-t border-sand">
|
|
||||||
<div>
|
|
||||||
<span className="text-2xl font-bold text-dark">{room.price}</span>
|
|
||||||
<span className="text-muted text-xs ml-1">/gece</span>
|
|
||||||
</div>
|
|
||||||
<Link
|
|
||||||
href="/odalar"
|
|
||||||
className={`text-[11px] px-5 py-2.5 rounded-full font-bold tracking-wider uppercase transition-colors ${room.cta === "accent"
|
|
||||||
? "bg-accent text-white hover:bg-accent/90"
|
|
||||||
: "bg-primary text-white hover:bg-primary/90"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
İncele
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</ScrollReveal>
|
|
||||||
|
|
||||||
<div className="text-center mt-12">
|
|
||||||
<Link
|
|
||||||
href="/odalar"
|
|
||||||
className="inline-flex items-center gap-2 border-2 border-dark text-dark text-xs px-8 py-3.5 rounded-full font-bold uppercase tracking-widest hover:bg-dark hover:text-white transition-colors"
|
|
||||||
>
|
|
||||||
Tüm Odaları Gör
|
|
||||||
<ArrowRight className="w-3.5 h-3.5" />
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
*/}
|
|
||||||
|
|
||||||
{/* ──────────────────────────────────────────
|
|
||||||
ACTIVITIES — BENTO GRID
|
|
||||||
────────────────────────────────────────── */}
|
|
||||||
<section className="py-28 bg-background">
|
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
||||||
<ScrollReveal className="flex flex-col md:flex-row md:items-end md:justify-between gap-6 mb-10">
|
|
||||||
<div>
|
|
||||||
<span className="inline-block text-accent text-xs tracking-[0.25em] uppercase font-semibold mb-4">
|
|
||||||
{lang === "en" ? "What Will You Do?" : "Ne Yapacaksınız?"}
|
|
||||||
</span>
|
|
||||||
<h2 className="font-serif text-5xl font-bold text-dark">
|
|
||||||
{lang === "en" ? "Activities" : "Aktiviteler"}
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
<Link
|
|
||||||
href={`/${lang}/aktiviteler`}
|
|
||||||
className="inline-flex items-center gap-2 text-sm font-semibold text-primary hover:text-accent transition-colors"
|
|
||||||
>
|
|
||||||
{lang === "en" ? "See All" : "Tümünü Gör"} <ArrowRight className="w-4 h-4" />
|
|
||||||
</Link>
|
|
||||||
</ScrollReveal>
|
|
||||||
|
|
||||||
{/* Bento rows */}
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
||||||
{activities.length > 0 ? (
|
|
||||||
activities.map((act, i) => (
|
|
||||||
<ScrollReveal
|
|
||||||
key={act.id}
|
|
||||||
className={i === 0 || i === 3 ? "md:col-span-2" : ""}
|
|
||||||
delay={i * 50}
|
|
||||||
>
|
|
||||||
<Link href={`/${lang}/aktiviteler`} className={`group relative block rounded-3xl overflow-hidden ${activities.length === 1 ? "aspect-[4/3] md:aspect-video" : i < 2 ? "h-[400px]" : "h-[280px]"}`}>
|
|
||||||
<Image
|
|
||||||
src={act.image}
|
|
||||||
alt={act.title}
|
|
||||||
fill
|
|
||||||
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
|
||||||
className="object-cover group-hover:scale-105 transition-transform duration-700"
|
|
||||||
/>
|
|
||||||
<div className={`absolute inset-0 bg-gradient-to-t ${i === 0 ? "from-dark/90 via-dark/20" : "from-dark/80"} to-transparent`} />
|
|
||||||
<div className={`absolute bottom-0 ${i === 0 || i === 3 ? "p-8" : "p-7"}`}>
|
|
||||||
{act.badge && (
|
|
||||||
<span className="block text-accent text-[10px] tracking-[0.25em] uppercase font-bold mb-2">{act.badge}</span>
|
|
||||||
)}
|
|
||||||
<h3 className={`font-serif text-white font-bold mb-1 ${i === 0 ? "text-4xl mb-2" : i === 1 || i === 3 ? "text-3xl" : "text-2xl"}`}>{act.title}</h3>
|
|
||||||
{i === 0 && (
|
|
||||||
<p className="text-white/60 text-sm mb-4 max-w-xs opacity-0 translate-y-2 group-hover:opacity-100 group-hover:translate-y-0 transition-all duration-400">
|
|
||||||
{act.description}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
{i === 0 && (
|
|
||||||
<span className="inline-flex items-center gap-2 text-white text-sm font-semibold hover:text-accent transition-colors">
|
|
||||||
<ArrowRight className="w-3.5 h-3.5" />
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
</ScrollReveal>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<div className="md:col-span-3 py-10 text-center text-gray-500">
|
|
||||||
{lang === "en" ? "No activities added yet." : "Henüz aktivite eklenmedi."}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* ──────────────────────────────────────────
|
|
||||||
EVENTS (PREVIEW)
|
|
||||||
────────────────────────────────────────── */}
|
|
||||||
<section className="py-28 bg-dark text-white relative overflow-hidden">
|
|
||||||
{/* Background glow */}
|
|
||||||
<div className="absolute top-0 right-0 w-96 h-96 bg-accent/20 rounded-full blur-[120px] pointer-events-none" />
|
|
||||||
<div className="absolute bottom-0 left-0 w-[500px] h-[500px] bg-primary/20 rounded-full blur-[150px] pointer-events-none" />
|
|
||||||
|
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
|
|
||||||
<ScrollReveal className="flex flex-col md:flex-row md:items-end md:justify-between gap-6 mb-16">
|
|
||||||
<div>
|
|
||||||
<span className="inline-block text-accent text-xs tracking-[0.25em] uppercase font-semibold mb-4">
|
|
||||||
{lang === "en" ? "Calendar" : "Takvim"}
|
|
||||||
</span>
|
|
||||||
<h2 className="font-serif text-5xl font-bold">
|
|
||||||
{lang === "en" ? "Events" : "Etkinlikler"}
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
<Link
|
|
||||||
href={`/${lang}/etkinlikler`}
|
|
||||||
className="inline-flex items-center gap-2 text-sm font-semibold text-white/70 hover:text-white transition-colors border border-white/20 hover:border-white px-6 py-2.5 rounded-full"
|
|
||||||
>
|
|
||||||
{lang === "en" ? "All Events" : "Tüm Etkinlikler"} <ArrowRight className="w-4 h-4" />
|
|
||||||
</Link>
|
|
||||||
</ScrollReveal>
|
|
||||||
|
|
||||||
<ScrollReveal delay={100}>
|
|
||||||
{events.length > 0 ? (
|
|
||||||
events.map((ev) => (
|
|
||||||
<div key={ev.id} className="group relative flex flex-col md:flex-row gap-8 bg-white/5 border border-white/10 rounded-3xl p-6 md:p-10 hover:bg-white/10 transition-colors backdrop-blur-sm mb-6">
|
|
||||||
<div className="relative w-full md:w-1/3 h-[250px] md:h-auto rounded-2xl overflow-hidden shrink-0">
|
|
||||||
<Image
|
|
||||||
src={ev.image}
|
|
||||||
alt={ev.title}
|
|
||||||
fill
|
|
||||||
sizes="(max-width: 768px) 100vw, 33vw"
|
|
||||||
className="object-cover group-hover:scale-105 transition-transform duration-700"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-col justify-center w-full md:w-2/3">
|
|
||||||
{ev.badge && (
|
|
||||||
<div className="inline-block bg-accent/20 text-accent text-[10px] font-bold px-3 py-1.5 rounded-full tracking-widest uppercase mb-4 w-max">
|
|
||||||
{ev.badge}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<h3 className="font-serif text-3xl md:text-4xl font-bold mb-4">{ev.title}</h3>
|
|
||||||
<p className="text-white/60 leading-relaxed mb-6 max-w-xl">
|
|
||||||
{ev.description}
|
|
||||||
</p>
|
|
||||||
<div className="flex flex-wrap items-center gap-6 mb-8 text-sm text-white/80">
|
|
||||||
<span className="flex items-center gap-2">
|
|
||||||
<span className="w-2 h-2 rounded-full bg-accent" /> {ev.date}
|
|
||||||
</span>
|
|
||||||
<span className="flex items-center gap-2">
|
|
||||||
<span className="w-2 h-2 rounded-full bg-accent" /> {ev.time}
|
|
||||||
</span>
|
|
||||||
<span className="flex items-center gap-2">
|
|
||||||
<span className="w-2 h-2 rounded-full bg-accent" /> {ev.location}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<Link
|
|
||||||
href={`/${lang}/etkinlikler`}
|
|
||||||
className="inline-flex items-center gap-2 text-xs font-bold tracking-widest uppercase text-accent hover:text-white transition-colors w-max"
|
|
||||||
>
|
|
||||||
{lang === "en" ? "View Details" : "Detayları İncele"} <ArrowRight className="w-4 h-4" />
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<div className="py-10 text-center text-white/50">
|
|
||||||
{lang === "en" ? "No events added yet." : "Henüz etkinlik eklenmedi."}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</ScrollReveal>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* ──────────────────────────────────────────
|
|
||||||
INSTAGRAM FEED
|
|
||||||
────────────────────────────────────────── */}
|
|
||||||
{instagramPosts.length > 0 && (
|
|
||||||
<section className="py-28 bg-background">
|
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
||||||
<ScrollReveal className="text-center mb-16">
|
|
||||||
<span className="inline-block text-accent text-xs tracking-[0.25em] uppercase font-semibold mb-4">
|
|
||||||
@kitebeachakyaka
|
|
||||||
</span>
|
|
||||||
<h2 className="font-serif text-5xl font-bold text-dark">Instagram</h2>
|
|
||||||
</ScrollReveal>
|
|
||||||
|
|
||||||
<ScrollReveal stagger className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-6">
|
|
||||||
{instagramPosts.map((post: any) => (
|
|
||||||
<a
|
|
||||||
key={post.id}
|
|
||||||
href={`https://instagram.com/p/${post.code}`}
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
className="group block relative rounded-2xl overflow-hidden aspect-[4/5] border border-sand"
|
|
||||||
>
|
|
||||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
||||||
<img
|
|
||||||
src={post.image_versions2?.candidates[0]?.url}
|
|
||||||
alt={post.caption?.text?.substring(0, 100) || "Instagram post"}
|
|
||||||
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-700"
|
|
||||||
/>
|
|
||||||
<div className="absolute inset-0 bg-dark/60 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex flex-col items-center justify-center text-white p-6 text-center">
|
|
||||||
<Camera className="w-8 h-8 mb-3" />
|
|
||||||
<p className="text-xs line-clamp-3">
|
|
||||||
{post.caption?.text}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
))}
|
|
||||||
</ScrollReveal>
|
|
||||||
|
|
||||||
<div className="text-center mt-12">
|
|
||||||
<a
|
|
||||||
href="https://instagram.com/kitebeachakyaka"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
className="inline-flex items-center gap-2 border-2 border-dark text-dark text-xs px-8 py-3.5 rounded-full font-bold uppercase tracking-widest hover:bg-dark hover:text-white transition-colors"
|
|
||||||
>
|
|
||||||
{lang === "en" ? "Follow Us" : "Bizi Takip Edin"}
|
|
||||||
<ArrowRight className="w-3.5 h-3.5" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* ──────────────────────────────────────────
|
|
||||||
TESTIMONIALS
|
|
||||||
────────────────────────────────────────── */}
|
|
||||||
<section className="py-28 bg-white">
|
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
||||||
<ScrollReveal className="text-center mb-16">
|
|
||||||
<span className="inline-block text-accent text-xs tracking-[0.25em] uppercase font-semibold mb-4">
|
|
||||||
{lang === "en" ? "Guest Reviews" : "Misafir Yorumları"}
|
|
||||||
</span>
|
|
||||||
<h2 className="font-serif text-5xl font-bold text-dark">
|
|
||||||
{lang === "en" ? "Experiences" : "Deneyimler"}
|
|
||||||
</h2>
|
|
||||||
</ScrollReveal>
|
|
||||||
|
|
||||||
<ScrollReveal stagger className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
||||||
{displayTestimonials.map((t, i) => (
|
|
||||||
<div key={i} className="relative bg-sand rounded-2xl p-8 border border-sand overflow-hidden">
|
|
||||||
{/* Large decorative quote */}
|
|
||||||
<span className="absolute top-3 right-5 font-serif text-[8rem] leading-none text-primary/8 select-none">
|
|
||||||
"
|
|
||||||
</span>
|
|
||||||
{/* Stars */}
|
|
||||||
<div className="flex gap-1 mb-5 relative z-10">
|
|
||||||
{Array.from({ length: 5 }).map((_, j) => (
|
|
||||||
<Star key={j} className="w-3.5 h-3.5 text-accent" fill="#E87040" />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<p className="text-foreground/75 text-[13px] leading-relaxed mb-6 relative z-10 italic">
|
|
||||||
"{t.text}"
|
|
||||||
</p>
|
|
||||||
<div className="flex items-center gap-3 relative z-10">
|
|
||||||
<div className="w-9 h-9 bg-primary/10 rounded-full flex items-center justify-center flex-shrink-0">
|
|
||||||
<span className="text-primary font-bold text-sm">{t.name[0]}</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span className="block font-semibold text-dark text-sm">{t.name}</span>
|
|
||||||
<span className="text-muted text-xs">{t.from}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</ScrollReveal>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* ──────────────────────────────────────────
|
|
||||||
CTA BAND
|
|
||||||
────────────────────────────────────────── */}
|
|
||||||
<section className="relative py-28 overflow-hidden">
|
|
||||||
<div
|
|
||||||
className="absolute inset-0 animate-gradient-pan"
|
|
||||||
style={{
|
|
||||||
background:
|
|
||||||
"linear-gradient(135deg, #0D3D50 0%, #1A6B8A 35%, #0E1A24 60%, #1A4A60 100%)",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div className="absolute inset-0 opacity-[0.04]">
|
|
||||||
<Image
|
|
||||||
src="https://images.unsplash.com/photo-1498623116890-37e912163d5d?q=80&w=2940&auto=format&fit=crop"
|
|
||||||
alt=""
|
|
||||||
fill
|
|
||||||
sizes="100vw"
|
|
||||||
className="object-cover"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="relative z-10 max-w-3xl mx-auto px-4 text-center">
|
|
||||||
<ScrollReveal>
|
|
||||||
<span className="inline-block text-accent text-xs tracking-[0.3em] uppercase font-semibold mb-6">
|
|
||||||
{lang === "en" ? "Get Started" : "Hemen Başlayın"}
|
|
||||||
</span>
|
|
||||||
<h2 className="font-serif text-5xl md:text-6xl font-bold text-white leading-tight mb-6">
|
|
||||||
{lang === "en" ? (
|
|
||||||
<>Are you ready to plan<br />your dream vacation?</>
|
|
||||||
) : (
|
|
||||||
<>Hayalindeki tatili<br />planlamaya hazır mısın?</>
|
|
||||||
)}
|
|
||||||
</h2>
|
|
||||||
<p className="text-white/50 mb-10 text-base leading-relaxed">
|
|
||||||
{lang === "en"
|
|
||||||
? "The wind is calling you. Book your spot now and become a part of this unique experience."
|
|
||||||
: "Rüzgar seni çağırıyor. Hemen yerini ayırt ve bu eşsiz deneyimin bir parçası ol."}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</ScrollReveal>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export function GET() {
|
|||||||
|
|
||||||
- **Location**: Akyaka Mahallesi, Akçapınar Mevkii, Akyaka, Muğla, Turkey
|
- **Location**: Akyaka Mahallesi, Akçapınar Mevkii, Akyaka, Muğla, Turkey
|
||||||
- **Coordinates**: 37.0543° N, 28.3286° E
|
- **Coordinates**: 37.0543° N, 28.3286° E
|
||||||
- **Phone / WhatsApp**: +90 533 081 6181
|
- **Phone / WhatsApp**: +90 544 504 03 10
|
||||||
- **Email**: info@kitebeachakyaka.com.tr
|
- **Email**: info@kitebeachakyaka.com.tr
|
||||||
- **Reception hours**: 08:00 – 22:00 daily
|
- **Reception hours**: 08:00 – 22:00 daily
|
||||||
- **Type**: Boutique hotel, kitesurf school, beach club, restaurant & bar
|
- **Type**: Boutique hotel, kitesurf school, beach club, restaurant & bar
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const baseUrl = 'https://kitebeachakyaka.com.tr';
|
|||||||
const langs = ['tr', 'en'];
|
const langs = ['tr', 'en'];
|
||||||
const routes = [
|
const routes = [
|
||||||
{ path: '', changeFrequency: 'daily' as const, priority: 1.0 },
|
{ path: '', changeFrequency: 'daily' as const, priority: 1.0 },
|
||||||
// { path: '/odalar', changeFrequency: 'weekly' as const, priority: 0.9 },
|
{ path: '/odalar', changeFrequency: 'weekly' as const, priority: 0.9 },
|
||||||
{ path: '/aktiviteler', changeFrequency: 'weekly' as const, priority: 0.9 },
|
{ path: '/aktiviteler', changeFrequency: 'weekly' as const, priority: 0.9 },
|
||||||
{ path: '/etkinlikler', changeFrequency: 'weekly' as const, priority: 0.9 },
|
{ path: '/etkinlikler', changeFrequency: 'weekly' as const, priority: 0.9 },
|
||||||
{ path: '/restoran', changeFrequency: 'weekly' as const, priority: 0.8 },
|
{ path: '/restoran', changeFrequency: 'weekly' as const, priority: 0.8 },
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import 'dotenv/config';
|
||||||
|
import prisma from './lib/prisma';
|
||||||
|
import bcrypt from 'bcryptjs';
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const users = await prisma.user.findMany();
|
||||||
|
console.log("Users in DB:", users.length);
|
||||||
|
for (const u of users) {
|
||||||
|
console.log(`- ID: ${u.id}, Username: ${u.username}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (users.length > 0) {
|
||||||
|
// Force reset the password of the first user to what's in .env just in case
|
||||||
|
const username = process.env.ADMIN_USERNAME || "admin";
|
||||||
|
const password = process.env.ADMIN_PASSWORD || "secretpassword";
|
||||||
|
console.log(`Updating password for user ${username} to ${password}...`);
|
||||||
|
const hashedPassword = await bcrypt.hash(password, 10);
|
||||||
|
|
||||||
|
// Check if the exact user exists
|
||||||
|
const exactUser = await prisma.user.findUnique({ where: { username } });
|
||||||
|
if (exactUser) {
|
||||||
|
await prisma.user.update({
|
||||||
|
where: { username },
|
||||||
|
data: { password: hashedPassword }
|
||||||
|
});
|
||||||
|
console.log(`Password reset successfully for ${username}.`);
|
||||||
|
} else {
|
||||||
|
console.log(`No exact user found with username ${username}. Updating first user.`);
|
||||||
|
await prisma.user.update({
|
||||||
|
where: { id: users[0].id },
|
||||||
|
data: { username: username, password: hashedPassword }
|
||||||
|
});
|
||||||
|
console.log(`Updated first user to be ${username} with new password.`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("No users exist in DB. The auth code will create one automatically.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
||||||
|
.catch(e => console.error(e))
|
||||||
|
.finally(() => prisma.$disconnect());
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { X } from "lucide-react";
|
||||||
|
|
||||||
|
interface BentoGalleryProps {
|
||||||
|
images: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function BentoGallery({ images }: BentoGalleryProps) {
|
||||||
|
const [lightboxIndex, setLightboxIndex] = useState<number | null>(null);
|
||||||
|
|
||||||
|
const openLightbox = (index: number) => {
|
||||||
|
setLightboxIndex(index);
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeLightbox = () => {
|
||||||
|
setLightboxIndex(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 auto-rows-[200px] md:auto-rows-[250px]">
|
||||||
|
{/* Big Feature Image */}
|
||||||
|
{images.length > 0 && (
|
||||||
|
<div
|
||||||
|
className="relative rounded-3xl overflow-hidden group col-span-2 row-span-2 cursor-pointer h-full"
|
||||||
|
onClick={() => openLightbox(0)}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src={images[0]}
|
||||||
|
alt="Gallery Image 1"
|
||||||
|
fill
|
||||||
|
sizes="(max-width: 768px) 100vw, 50vw"
|
||||||
|
className="object-cover group-hover:scale-105 transition-transform duration-700"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* Top Right */}
|
||||||
|
{images.length > 1 && (
|
||||||
|
<div
|
||||||
|
className="relative rounded-3xl overflow-hidden group col-span-2 row-span-1 cursor-pointer h-full"
|
||||||
|
onClick={() => openLightbox(1)}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src={images[1]}
|
||||||
|
alt="Gallery Image 2"
|
||||||
|
fill
|
||||||
|
sizes="(max-width: 768px) 100vw, 50vw"
|
||||||
|
className="object-cover group-hover:scale-105 transition-transform duration-700"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* Middle Right 1 */}
|
||||||
|
{images.length > 2 && (
|
||||||
|
<div
|
||||||
|
className="relative rounded-3xl overflow-hidden group col-span-1 row-span-1 cursor-pointer h-full"
|
||||||
|
onClick={() => openLightbox(2)}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src={images[2]}
|
||||||
|
alt="Gallery Image 3"
|
||||||
|
fill
|
||||||
|
sizes="(max-width: 768px) 50vw, 25vw"
|
||||||
|
className="object-cover group-hover:scale-105 transition-transform duration-700"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* Middle Right 2 */}
|
||||||
|
{images.length > 3 && (
|
||||||
|
<div
|
||||||
|
className="relative rounded-3xl overflow-hidden group col-span-1 row-span-1 cursor-pointer h-full"
|
||||||
|
onClick={() => openLightbox(3)}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src={images[3]}
|
||||||
|
alt="Gallery Image 4"
|
||||||
|
fill
|
||||||
|
sizes="(max-width: 768px) 50vw, 25vw"
|
||||||
|
className="object-cover group-hover:scale-105 transition-transform duration-700"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* Bottom Row 1 */}
|
||||||
|
{images.length > 4 && (
|
||||||
|
<div
|
||||||
|
className="relative rounded-3xl overflow-hidden group col-span-2 md:col-span-3 row-span-1 cursor-pointer h-full"
|
||||||
|
onClick={() => openLightbox(4)}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src={images[4]}
|
||||||
|
alt="Gallery Image 5"
|
||||||
|
fill
|
||||||
|
sizes="(max-width: 768px) 100vw, 75vw"
|
||||||
|
className="object-cover group-hover:scale-105 transition-transform duration-700"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* Bottom Row 2 */}
|
||||||
|
{images.length > 5 && (
|
||||||
|
<div
|
||||||
|
className="relative rounded-3xl overflow-hidden group col-span-2 md:col-span-1 row-span-1 cursor-pointer h-full"
|
||||||
|
onClick={() => openLightbox(5)}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src={images[5]}
|
||||||
|
alt="Gallery Image 6"
|
||||||
|
fill
|
||||||
|
sizes="(max-width: 768px) 100vw, 25vw"
|
||||||
|
className="object-cover group-hover:scale-105 transition-transform duration-700"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Lightbox */}
|
||||||
|
{lightboxIndex !== null && (
|
||||||
|
<div
|
||||||
|
className="fixed inset-0 z-[100] bg-dark/95 backdrop-blur-sm flex items-center justify-center p-4 cursor-zoom-out opacity-0 animate-fade-in"
|
||||||
|
style={{ animationFillMode: "forwards" }}
|
||||||
|
onClick={closeLightbox}
|
||||||
|
>
|
||||||
|
<div className="relative max-w-6xl w-full h-[85vh] aspect-auto" onClick={(e) => e.stopPropagation()}>
|
||||||
|
<Image
|
||||||
|
src={images[lightboxIndex]}
|
||||||
|
alt="Lightbox Image"
|
||||||
|
fill
|
||||||
|
sizes="100vw"
|
||||||
|
className="object-contain rounded-xl shadow-2xl"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="absolute top-6 right-6 text-white/60 hover:text-white transition-colors bg-white/10 hover:bg-white/20 p-2 rounded-full"
|
||||||
|
onClick={closeLightbox}
|
||||||
|
>
|
||||||
|
<X size={28} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -33,7 +33,7 @@ export default function Footer({ lang = "tr" }: { lang?: string }) {
|
|||||||
const isEn = lang === "en";
|
const isEn = lang === "en";
|
||||||
const quickLinks = isEn ? [
|
const quickLinks = isEn ? [
|
||||||
{ name: "Home", href: "/en" },
|
{ name: "Home", href: "/en" },
|
||||||
// { name: "Rooms", href: "/en/odalar" },
|
{ name: "Rooms", href: "/en/odalar" },
|
||||||
{ name: "Activities", href: "/en/aktiviteler"},
|
{ name: "Activities", href: "/en/aktiviteler"},
|
||||||
{ name: "Restaurant", href: "/en/restoran" },
|
{ name: "Restaurant", href: "/en/restoran" },
|
||||||
{ name: "Events", href: "/en/etkinlikler"},
|
{ name: "Events", href: "/en/etkinlikler"},
|
||||||
@@ -41,7 +41,7 @@ export default function Footer({ lang = "tr" }: { lang?: string }) {
|
|||||||
{ name: "About Us", href: "/en/hakkimizda" },
|
{ name: "About Us", href: "/en/hakkimizda" },
|
||||||
] : [
|
] : [
|
||||||
{ name: "Ana Sayfa", href: "/tr" },
|
{ name: "Ana Sayfa", href: "/tr" },
|
||||||
// { name: "Odalar", href: "/tr/odalar" },
|
{ name: "Odalar", href: "/tr/odalar" },
|
||||||
{ name: "Aktiviteler", href: "/tr/aktiviteler"},
|
{ name: "Aktiviteler", href: "/tr/aktiviteler"},
|
||||||
{ name: "Restoran", href: "/tr/restoran" },
|
{ name: "Restoran", href: "/tr/restoran" },
|
||||||
{ name: "Etkinlikler", href: "/tr/etkinlikler"},
|
{ name: "Etkinlikler", href: "/tr/etkinlikler"},
|
||||||
@@ -134,10 +134,10 @@ export default function Footer({ lang = "tr" }: { lang?: string }) {
|
|||||||
<Phone size={13} className="text-accent" />
|
<Phone size={13} className="text-accent" />
|
||||||
</div>
|
</div>
|
||||||
<a
|
<a
|
||||||
href="tel:+905330816181"
|
href="tel:+905445040310"
|
||||||
className="text-white/50 hover:text-white transition-colors text-[13px]"
|
className="text-white/50 hover:text-white transition-colors text-[13px]"
|
||||||
>
|
>
|
||||||
+90 533 081 6181
|
+90 544 504 03 10
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li className="flex items-center gap-3">
|
<li className="flex items-center gap-3">
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { motion, AnimatePresence } from "framer-motion";
|
|||||||
import { Menu, X, Globe } from "lucide-react";
|
import { Menu, X, Globe } from "lucide-react";
|
||||||
|
|
||||||
const navLinksEn = [
|
const navLinksEn = [
|
||||||
// { name: "Rooms", href: "/en/odalar" },
|
{ name: "Rooms", href: "/en/odalar" },
|
||||||
{ name: "Activities", href: "/en/aktiviteler" },
|
{ name: "Activities", href: "/en/aktiviteler" },
|
||||||
{ name: "Restaurant", href: "/en/restoran" },
|
{ name: "Restaurant", href: "/en/restoran" },
|
||||||
{ name: "Events", href: "/en/etkinlikler" },
|
{ name: "Events", href: "/en/etkinlikler" },
|
||||||
@@ -17,7 +17,7 @@ const navLinksEn = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const navLinksTr = [
|
const navLinksTr = [
|
||||||
// { name: "Odalar", href: "/tr/odalar" },
|
{ name: "Odalar", href: "/tr/odalar" },
|
||||||
{ name: "Aktiviteler", href: "/tr/aktiviteler" },
|
{ name: "Aktiviteler", href: "/tr/aktiviteler" },
|
||||||
{ name: "Restoran", href: "/tr/restoran" },
|
{ name: "Restoran", href: "/tr/restoran" },
|
||||||
{ name: "Etkinlikler", href: "/tr/etkinlikler" },
|
{ name: "Etkinlikler", href: "/tr/etkinlikler" },
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { motion } from "framer-motion";
|
|||||||
export default function WhatsAppButton() {
|
export default function WhatsAppButton() {
|
||||||
return (
|
return (
|
||||||
<motion.a
|
<motion.a
|
||||||
href="https://wa.me/905330816181"
|
href="https://wa.me/905445040310"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="fixed bottom-6 right-6 z-50 flex items-center justify-center w-14 h-14 bg-green-500 text-white rounded-full shadow-lg hover:shadow-2xl hover:bg-green-600 transition-all focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500"
|
className="fixed bottom-6 right-6 z-50 flex items-center justify-center w-14 h-14 bg-green-500 text-white rounded-full shadow-lg hover:shadow-2xl hover:bg-green-600 transition-all focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500"
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { Star, ArrowRight } from "lucide-react";
|
||||||
|
import ScrollReveal from "@/components/ScrollReveal";
|
||||||
|
|
||||||
|
interface AboutSectionProps {
|
||||||
|
aboutData: {
|
||||||
|
image: string;
|
||||||
|
badge: string;
|
||||||
|
statsGuestCount: string;
|
||||||
|
statsGuestLabel: string;
|
||||||
|
statsYearCount: string;
|
||||||
|
statsYearLabel: string;
|
||||||
|
badgeIkoTitle: string;
|
||||||
|
badgeIkoLabel: string;
|
||||||
|
titleLine1: string;
|
||||||
|
titleLine2: string;
|
||||||
|
titleHighlight: string;
|
||||||
|
description1: string;
|
||||||
|
description2: string;
|
||||||
|
};
|
||||||
|
lang: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AboutSection({ aboutData, lang }: AboutSectionProps) {
|
||||||
|
return (
|
||||||
|
<section className="py-28 bg-background overflow-hidden">
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 lg:gap-24 items-center">
|
||||||
|
<ScrollReveal className="relative">
|
||||||
|
<div className="relative h-[540px] lg:h-[660px] rounded-3xl overflow-hidden shadow-2xl">
|
||||||
|
<Image
|
||||||
|
src={aboutData.image}
|
||||||
|
alt={aboutData.badge}
|
||||||
|
fill
|
||||||
|
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
||||||
|
className="object-cover"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/* Stats card */}
|
||||||
|
<div className="absolute -bottom-5 -right-4 md:-right-8 bg-white rounded-2xl p-6 shadow-xl border border-sand">
|
||||||
|
<div className="grid grid-cols-2 gap-6 divide-x divide-sand">
|
||||||
|
<div className="text-center">
|
||||||
|
<span className="block font-serif text-3xl font-bold text-primary">{aboutData.statsGuestCount}</span>
|
||||||
|
<span className="block text-[10px] text-muted uppercase tracking-wider mt-1">{aboutData.statsGuestLabel}</span>
|
||||||
|
</div>
|
||||||
|
<div className="text-center pl-6">
|
||||||
|
<span className="block font-serif text-3xl font-bold text-primary">{aboutData.statsYearCount}</span>
|
||||||
|
<span className="block text-[10px] text-muted uppercase tracking-wider mt-1">{aboutData.statsYearLabel}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* IKO badge */}
|
||||||
|
<div className="absolute -top-4 -left-4 bg-accent text-white rounded-2xl p-4 shadow-lg">
|
||||||
|
<Star className="w-4 h-4 mb-1" fill="white" />
|
||||||
|
<span className="block text-xs font-bold leading-none">{aboutData.badgeIkoTitle}</span>
|
||||||
|
<span className="block text-[10px] opacity-80 mt-0.5">{aboutData.badgeIkoLabel}</span>
|
||||||
|
</div>
|
||||||
|
</ScrollReveal>
|
||||||
|
|
||||||
|
<ScrollReveal delay={200}>
|
||||||
|
<span className="inline-block text-accent text-xs tracking-[0.25em] uppercase font-semibold mb-5">
|
||||||
|
{aboutData.badge}
|
||||||
|
</span>
|
||||||
|
<h2 className="font-serif text-4xl md:text-5xl lg:text-6xl font-bold text-dark leading-[1.05] mb-8">
|
||||||
|
{aboutData.titleLine1}<br />{aboutData.titleLine2}<br />
|
||||||
|
<span className="text-primary italic">{aboutData.titleHighlight}</span>
|
||||||
|
</h2>
|
||||||
|
<p className="text-gray-600 leading-relaxed mb-5">
|
||||||
|
{aboutData.description1}
|
||||||
|
</p>
|
||||||
|
<p className="text-gray-600 leading-relaxed mb-10">
|
||||||
|
{aboutData.description2}
|
||||||
|
</p>
|
||||||
|
<div className="section-line mb-8" />
|
||||||
|
<Link
|
||||||
|
href={`/${lang}/hakkimizda`}
|
||||||
|
className="inline-flex items-center gap-2 text-dark font-bold text-sm tracking-wide group"
|
||||||
|
>
|
||||||
|
<span className="border-b-2 border-accent pb-0.5">
|
||||||
|
{lang === "en" ? "Read Our Story" : "Hikayemizi Okuyun"}
|
||||||
|
</span>
|
||||||
|
<ArrowRight className="w-4 h-4 group-hover:translate-x-1.5 transition-transform" />
|
||||||
|
</Link>
|
||||||
|
</ScrollReveal>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { ArrowRight } from "lucide-react";
|
||||||
|
import ScrollReveal from "@/components/ScrollReveal";
|
||||||
|
|
||||||
|
interface Activity {
|
||||||
|
id: number | string;
|
||||||
|
image: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
badge?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ActivitiesGridProps {
|
||||||
|
activities: Activity[];
|
||||||
|
lang: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ActivitiesGrid({ activities, lang }: ActivitiesGridProps) {
|
||||||
|
return (
|
||||||
|
<section className="py-28 bg-background">
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<ScrollReveal className="flex flex-col md:flex-row md:items-end md:justify-between gap-6 mb-10">
|
||||||
|
<div>
|
||||||
|
<span className="inline-block text-accent text-xs tracking-[0.25em] uppercase font-semibold mb-4">
|
||||||
|
{lang === "en" ? "What Will You Do?" : "Ne Yapacaksınız?"}
|
||||||
|
</span>
|
||||||
|
<h2 className="font-serif text-5xl font-bold text-dark">
|
||||||
|
{lang === "en" ? "Activities" : "Aktiviteler"}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<Link
|
||||||
|
href={`/${lang}/aktiviteler`}
|
||||||
|
className="inline-flex items-center gap-2 text-sm font-semibold text-primary hover:text-accent transition-colors"
|
||||||
|
>
|
||||||
|
{lang === "en" ? "See All" : "Tümünü Gör"} <ArrowRight className="w-4 h-4" />
|
||||||
|
</Link>
|
||||||
|
</ScrollReveal>
|
||||||
|
|
||||||
|
{/* Single Row 3 Cards */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||||
|
{activities.length > 0 ? (
|
||||||
|
activities.map((act, i) => (
|
||||||
|
<ScrollReveal
|
||||||
|
key={act.id}
|
||||||
|
delay={i * 50}
|
||||||
|
>
|
||||||
|
<Link href={`/${lang}/aktiviteler`} className={`group relative block rounded-3xl overflow-hidden h-[400px]`}>
|
||||||
|
<Image
|
||||||
|
src={act.image}
|
||||||
|
alt={act.title}
|
||||||
|
fill
|
||||||
|
sizes="(max-width: 768px) 100vw, 33vw"
|
||||||
|
className="object-cover group-hover:scale-105 transition-transform duration-700"
|
||||||
|
/>
|
||||||
|
<div className={`absolute inset-0 bg-gradient-to-t from-dark/90 via-dark/30 to-transparent`} />
|
||||||
|
<div className={`absolute bottom-0 p-8 flex flex-col justify-end h-full`}>
|
||||||
|
{act.badge && (
|
||||||
|
<span className="block text-accent text-[10px] tracking-[0.25em] uppercase font-bold mb-3">{act.badge}</span>
|
||||||
|
)}
|
||||||
|
<h3 className={`font-serif text-white font-bold mb-3 text-3xl`}>{act.title}</h3>
|
||||||
|
<p className="text-white/70 text-sm mb-4 max-w-xs line-clamp-3">
|
||||||
|
{act.description}
|
||||||
|
</p>
|
||||||
|
<span className="inline-flex items-center gap-2 text-white text-sm font-semibold hover:text-accent transition-colors mt-auto opacity-0 translate-y-2 group-hover:opacity-100 group-hover:translate-y-0 duration-400">
|
||||||
|
<ArrowRight className="w-4 h-4" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
</ScrollReveal>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className="md:col-span-3 py-10 text-center text-gray-500">
|
||||||
|
{lang === "en" ? "No activities added yet." : "Henüz aktivite eklenmedi."}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import Image from "next/image";
|
||||||
|
import ScrollReveal from "@/components/ScrollReveal";
|
||||||
|
|
||||||
|
interface CtaBandProps {
|
||||||
|
lang: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function CtaBand({ lang }: CtaBandProps) {
|
||||||
|
return (
|
||||||
|
<section className="relative py-28 overflow-hidden">
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 animate-gradient-pan"
|
||||||
|
style={{
|
||||||
|
background:
|
||||||
|
"linear-gradient(135deg, #0D3D50 0%, #1A6B8A 35%, #0E1A24 60%, #1A4A60 100%)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 opacity-[0.04]">
|
||||||
|
<Image
|
||||||
|
src="https://images.unsplash.com/photo-1498623116890-37e912163d5d?q=80&w=2940&auto=format&fit=crop"
|
||||||
|
alt=""
|
||||||
|
fill
|
||||||
|
sizes="100vw"
|
||||||
|
className="object-cover"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="relative z-10 max-w-3xl mx-auto px-4 text-center">
|
||||||
|
<ScrollReveal>
|
||||||
|
<span className="inline-block text-accent text-xs tracking-[0.3em] uppercase font-semibold mb-6">
|
||||||
|
{lang === "en" ? "Get Started" : "Hemen Başlayın"}
|
||||||
|
</span>
|
||||||
|
<h2 className="font-serif text-5xl md:text-6xl font-bold text-white leading-tight mb-6">
|
||||||
|
{lang === "en" ? (
|
||||||
|
<>Are you ready to plan<br />your dream vacation?</>
|
||||||
|
) : (
|
||||||
|
<>Hayalindeki tatili<br />planlamaya hazır mısın?</>
|
||||||
|
)}
|
||||||
|
</h2>
|
||||||
|
<p className="text-white/50 mb-10 text-base leading-relaxed">
|
||||||
|
{lang === "en"
|
||||||
|
? "The wind is calling you. Book your spot now and become a part of this unique experience."
|
||||||
|
: "Rüzgar seni çağırıyor. Hemen yerini ayırt ve bu eşsiz deneyimin bir parçası ol."}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</ScrollReveal>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { ArrowRight } from "lucide-react";
|
||||||
|
import ScrollReveal from "@/components/ScrollReveal";
|
||||||
|
|
||||||
|
interface Event {
|
||||||
|
id: number | string;
|
||||||
|
image: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
badge?: string | null;
|
||||||
|
date: string;
|
||||||
|
time: string;
|
||||||
|
location: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EventsPreviewProps {
|
||||||
|
events: Event[];
|
||||||
|
lang: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function EventsPreview({ events, lang }: EventsPreviewProps) {
|
||||||
|
return (
|
||||||
|
<section className="py-28 bg-dark text-white relative overflow-hidden">
|
||||||
|
{/* Background glow */}
|
||||||
|
<div className="absolute top-0 right-0 w-96 h-96 bg-accent/20 rounded-full blur-[120px] pointer-events-none" />
|
||||||
|
<div className="absolute bottom-0 left-0 w-[500px] h-[500px] bg-primary/20 rounded-full blur-[150px] pointer-events-none" />
|
||||||
|
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
|
||||||
|
<ScrollReveal className="flex flex-col md:flex-row md:items-end md:justify-between gap-6 mb-16">
|
||||||
|
<div>
|
||||||
|
<span className="inline-block text-accent text-xs tracking-[0.25em] uppercase font-semibold mb-4">
|
||||||
|
{lang === "en" ? "Calendar" : "Takvim"}
|
||||||
|
</span>
|
||||||
|
<h2 className="font-serif text-5xl font-bold">
|
||||||
|
{lang === "en" ? "Events" : "Etkinlikler"}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<Link
|
||||||
|
href={`/${lang}/etkinlikler`}
|
||||||
|
className="inline-flex items-center gap-2 text-sm font-semibold text-white/70 hover:text-white transition-colors border border-white/20 hover:border-white px-6 py-2.5 rounded-full"
|
||||||
|
>
|
||||||
|
{lang === "en" ? "All Events" : "Tüm Etkinlikler"} <ArrowRight className="w-4 h-4" />
|
||||||
|
</Link>
|
||||||
|
</ScrollReveal>
|
||||||
|
|
||||||
|
<ScrollReveal delay={100}>
|
||||||
|
{events.length > 0 ? (
|
||||||
|
events.map((ev) => (
|
||||||
|
<div key={ev.id} className="group relative flex flex-col md:flex-row gap-8 bg-white/5 border border-white/10 rounded-3xl p-6 md:p-10 hover:bg-white/10 transition-colors backdrop-blur-sm mb-6">
|
||||||
|
<div className="relative w-full md:w-1/3 h-[250px] md:h-auto rounded-2xl overflow-hidden shrink-0">
|
||||||
|
<Image
|
||||||
|
src={ev.image}
|
||||||
|
alt={ev.title}
|
||||||
|
fill
|
||||||
|
sizes="(max-width: 768px) 100vw, 33vw"
|
||||||
|
className="object-cover group-hover:scale-105 transition-transform duration-700"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col justify-center w-full md:w-2/3">
|
||||||
|
{ev.badge && (
|
||||||
|
<div className="inline-block bg-accent/20 text-accent text-[10px] font-bold px-3 py-1.5 rounded-full tracking-widest uppercase mb-4 w-max">
|
||||||
|
{ev.badge}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<h3 className="font-serif text-3xl md:text-4xl font-bold mb-4">{ev.title}</h3>
|
||||||
|
<p className="text-white/60 leading-relaxed mb-6 max-w-xl">
|
||||||
|
{ev.description}
|
||||||
|
</p>
|
||||||
|
<div className="flex flex-wrap items-center gap-6 mb-8 text-sm text-white/80">
|
||||||
|
<span className="flex items-center gap-2">
|
||||||
|
<span className="w-2 h-2 rounded-full bg-accent" /> {ev.date}
|
||||||
|
</span>
|
||||||
|
<span className="flex items-center gap-2">
|
||||||
|
<span className="w-2 h-2 rounded-full bg-accent" /> {ev.time}
|
||||||
|
</span>
|
||||||
|
<span className="flex items-center gap-2">
|
||||||
|
<span className="w-2 h-2 rounded-full bg-accent" /> {ev.location}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<Link
|
||||||
|
href={`/${lang}/etkinlikler`}
|
||||||
|
className="inline-flex items-center gap-2 text-xs font-bold tracking-widest uppercase text-accent hover:text-white transition-colors w-max"
|
||||||
|
>
|
||||||
|
{lang === "en" ? "View Details" : "Detayları İncele"} <ArrowRight className="w-4 h-4" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className="py-10 text-center text-white/50">
|
||||||
|
{lang === "en" ? "No events added yet." : "Henüz etkinlik eklenmedi."}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</ScrollReveal>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import {
|
||||||
|
Star, Wind, Anchor, Utensils, BedDouble, Sun,
|
||||||
|
Waves, Bike, Coffee, Music, MapPin, Camera, Heart, Compass,
|
||||||
|
Fish, Mountain, Dumbbell, Leaf, Shield, Umbrella, Flame,
|
||||||
|
type LucideIcon,
|
||||||
|
} from "lucide-react";
|
||||||
|
|
||||||
|
const ICON_MAP: Record<string, LucideIcon> = {
|
||||||
|
Wind, Anchor, Utensils, BedDouble, Sun, Star, Waves, Bike,
|
||||||
|
Coffee, Music, MapPin, Camera, Heart, Compass, Fish, Mountain,
|
||||||
|
Dumbbell, Leaf, Shield, Umbrella, Flame,
|
||||||
|
};
|
||||||
|
|
||||||
|
interface Feature {
|
||||||
|
icon: string | null;
|
||||||
|
label: string;
|
||||||
|
sub: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FeaturesStripProps {
|
||||||
|
features: Feature[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function FeaturesStrip({ features }: FeaturesStripProps) {
|
||||||
|
return (
|
||||||
|
<section className="bg-dark text-white py-8">
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-5 divide-x divide-white/8">
|
||||||
|
{features.map(({ icon, label, sub }, i) => {
|
||||||
|
const IconComponent = ICON_MAP[icon as string] || Star;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className={`flex flex-col items-center justify-center gap-2 py-6 px-4 group ${i >= 2 ? "hidden md:flex" : ""}`}
|
||||||
|
>
|
||||||
|
<IconComponent className="w-5 h-5 text-accent group-hover:scale-110 transition-transform duration-300" />
|
||||||
|
<span className="text-[13px] font-semibold text-center">{label}</span>
|
||||||
|
<span className="text-[11px] text-white/40 text-center">{sub}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
import HeroVideo from "@/components/HeroVideo";
|
||||||
|
|
||||||
|
interface HeroSectionProps {
|
||||||
|
heroData: {
|
||||||
|
location: string;
|
||||||
|
welcome: string;
|
||||||
|
title: string;
|
||||||
|
subtitle: string;
|
||||||
|
exploreActivities: string;
|
||||||
|
scroll: string;
|
||||||
|
};
|
||||||
|
lang: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function HeroSection({ heroData, lang }: HeroSectionProps) {
|
||||||
|
return (
|
||||||
|
<section className="relative h-screen w-full flex items-center justify-center overflow-hidden">
|
||||||
|
<HeroVideo />
|
||||||
|
|
||||||
|
<div className="relative z-10 text-center px-4 max-w-5xl mx-auto">
|
||||||
|
<div className="animate-fade-up delay-100">
|
||||||
|
<span className="inline-block text-white/60 text-xs tracking-[0.35em] uppercase mb-8 font-light">
|
||||||
|
{heroData.location}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-center gap-4 md:gap-6 mb-6 animate-fade-up delay-200">
|
||||||
|
<span
|
||||||
|
className="text-xs md:text-sm tracking-[0.4em] font-bold uppercase whitespace-nowrap text-white/90"
|
||||||
|
style={{ writingMode: 'vertical-rl', transform: 'rotate(180deg)' }}
|
||||||
|
>
|
||||||
|
{heroData.welcome}
|
||||||
|
</span>
|
||||||
|
<h1 className="font-sans font-black text-white leading-none tracking-tighter text-[clamp(4rem,10vw,10rem)] uppercase">
|
||||||
|
{heroData.title}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="animate-fade-up delay-500 text-white/75 text-base md:text-xl mb-10 font-light italic tracking-wide">
|
||||||
|
{heroData.subtitle}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="animate-fade-up delay-600 flex flex-col sm:flex-row items-center justify-center gap-4">
|
||||||
|
<Link
|
||||||
|
href={`/${lang}/aktiviteler`}
|
||||||
|
className="bg-white/10 backdrop-blur-sm border border-white/30 text-white px-10 py-4 rounded-full text-xs font-bold tracking-[0.15em] uppercase hover:bg-white/20 transition-colors w-full sm:w-auto text-center"
|
||||||
|
>
|
||||||
|
{heroData.exploreActivities}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Scroll indicator */}
|
||||||
|
<div className="absolute bottom-10 left-1/2 -translate-x-1/2 z-20 flex flex-col items-center gap-3">
|
||||||
|
<span className="text-white/40 text-[10px] tracking-[0.3em] uppercase">{heroData.scroll}</span>
|
||||||
|
<div className="w-px h-12 bg-gradient-to-b from-white/40 to-transparent animate-scroll-bounce" />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import { ArrowRight, Camera } from "lucide-react";
|
||||||
|
import ScrollReveal from "@/components/ScrollReveal";
|
||||||
|
|
||||||
|
interface InstagramFeedProps {
|
||||||
|
instagramPosts: any[];
|
||||||
|
lang: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function InstagramFeed({ instagramPosts, lang }: InstagramFeedProps) {
|
||||||
|
if (!instagramPosts || instagramPosts.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="py-28 bg-background">
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<ScrollReveal className="text-center mb-16">
|
||||||
|
<span className="inline-block text-accent text-xs tracking-[0.25em] uppercase font-semibold mb-4">
|
||||||
|
@kitebeachakyaka
|
||||||
|
</span>
|
||||||
|
<h2 className="font-serif text-5xl font-bold text-dark">Instagram</h2>
|
||||||
|
</ScrollReveal>
|
||||||
|
|
||||||
|
<ScrollReveal stagger className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-6">
|
||||||
|
{instagramPosts.map((post: any) => (
|
||||||
|
<a
|
||||||
|
key={post.id}
|
||||||
|
href={`https://instagram.com/p/${post.code}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="group block relative rounded-2xl overflow-hidden aspect-[4/5] border border-sand"
|
||||||
|
>
|
||||||
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
|
<img
|
||||||
|
src={post.image_versions2?.candidates[0]?.url}
|
||||||
|
alt={post.caption?.text?.substring(0, 100) || "Instagram post"}
|
||||||
|
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-700"
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 bg-dark/60 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex flex-col items-center justify-center text-white p-6 text-center">
|
||||||
|
<Camera className="w-8 h-8 mb-3" />
|
||||||
|
<p className="text-xs line-clamp-3">
|
||||||
|
{post.caption?.text}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</ScrollReveal>
|
||||||
|
|
||||||
|
<div className="text-center mt-12">
|
||||||
|
<a
|
||||||
|
href="https://instagram.com/kitebeachakyaka"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="inline-flex items-center gap-2 border-2 border-dark text-dark text-xs px-8 py-3.5 rounded-full font-bold uppercase tracking-widest hover:bg-dark hover:text-white transition-colors"
|
||||||
|
>
|
||||||
|
{lang === "en" ? "Follow Us" : "Bizi Takip Edin"}
|
||||||
|
<ArrowRight className="w-3.5 h-3.5" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { ArrowRight, Info } from "lucide-react";
|
||||||
|
import ScrollReveal from "@/components/ScrollReveal";
|
||||||
|
import BentoGallery from "@/components/BentoGallery";
|
||||||
|
|
||||||
|
export default function RoomsSection({ lang }: { lang: string }) {
|
||||||
|
const isEn = lang === "en";
|
||||||
|
|
||||||
|
const galleryImages = [
|
||||||
|
"https://media.ayris.tech/t/kitebeachakyaka/rooms/WhatsApp%20Image%202026-07-13%20at%2017.02.15.jpeg",
|
||||||
|
"https://media.ayris.tech/t/kitebeachakyaka/rooms/WhatsApp%20Image%202026-07-13%20at%2017.02.18.jpeg",
|
||||||
|
"https://media.ayris.tech/t/kitebeachakyaka/rooms/WhatsApp%20Image%202026-07-13%20at%2017.02.19.jpeg",
|
||||||
|
"https://media.ayris.tech/t/kitebeachakyaka/rooms/WhatsApp%20Image%202026-07-13%20at%2017.02.20%20(1).jpeg",
|
||||||
|
"https://media.ayris.tech/t/kitebeachakyaka/rooms/WhatsApp%20Image%202026-07-13%20at%2017.02.20.jpeg",
|
||||||
|
"https://media.ayris.tech/t/kitebeachakyaka/rooms/WhatsApp%20Image%202026-07-13%20at%2017.02.21.jpeg",
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="py-28 bg-white">
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<ScrollReveal className="text-center mb-16">
|
||||||
|
<span className="inline-block text-accent text-xs tracking-[0.25em] uppercase font-semibold mb-4">
|
||||||
|
{isEn ? "Accommodation" : "Konaklama"}
|
||||||
|
</span>
|
||||||
|
<h2 className="font-serif text-4xl md:text-5xl font-bold text-dark mb-6">Kite Beach Akyaka Otel</h2>
|
||||||
|
<p className="text-muted max-w-3xl mx-auto text-sm leading-relaxed mb-8">
|
||||||
|
{isEn
|
||||||
|
? "We are at that special point in Akyaka's most beautiful corner, where the tranquility of the river embraces the endless blue of the sea. The silence of the riverbank that greets you as soon as you open your door will be your most peaceful invitation to start the day. You can balance your soul with a yoga session against the river view in the heart of nature, and then push the adrenaline to the top with Kite Surfing in Akyaka's famous winds. Leave the tiredness of the day behind by tasting the delicacies from our restaurant's kitchen and watching the enchanting sunset of the Aegean. Here, time flows only at the pace you desire."
|
||||||
|
: "Akyaka’nın en güzel köşesinde, nehrin dinginliği ile denizin sonsuz maviliğinin kucaklaştığı o özel noktadayız. Kapınızı açtığınız anda sizi karşılayan nehir kıyısının sessizliği, güne başlamak için en huzurlu davetiniz olacak. Doğanın kalbinde, nehir manzarasına karşı yaptığınız bir yoga seansıyla ruhunuzu dengelerken; hemen ardından Akyaka’nın meşhur rüzgarlarında Kite Surf ile adrenalini zirveye taşıyabilirsiniz. Günün yorgunluğunu ise, restoranımızın mutfağından çıkan lezzetlerle, Ege’nin kendine has o büyüleyici gün batımını izleyerek geride bırakın. Burada zaman, sadece sizin istediğiniz hızda akıyor."}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="inline-flex items-center gap-3 bg-primary/10 text-primary border border-primary/20 px-6 py-3 rounded-2xl shadow-sm">
|
||||||
|
<Info size={18} />
|
||||||
|
<span className="font-bold text-[15px] tracking-wide">
|
||||||
|
{isEn ? "Price: 8000 TL / Night (Breakfast Included)" : "Fiyat Bilgisi: 8000 TL / Gecelik (Kahvaltı Dahil)"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</ScrollReveal>
|
||||||
|
|
||||||
|
<ScrollReveal>
|
||||||
|
<BentoGallery images={galleryImages} />
|
||||||
|
</ScrollReveal>
|
||||||
|
|
||||||
|
<div className="text-center mt-12">
|
||||||
|
<Link
|
||||||
|
href={isEn ? "/en/odalar" : "/tr/odalar"}
|
||||||
|
className="inline-flex items-center gap-2 border-2 border-dark text-dark text-xs px-8 py-3.5 rounded-full font-bold uppercase tracking-widest hover:bg-dark hover:text-white transition-colors"
|
||||||
|
>
|
||||||
|
{isEn ? "View Details" : "Detayları Gör"}
|
||||||
|
<ArrowRight className="w-3.5 h-3.5" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { Star } from "lucide-react";
|
||||||
|
import ScrollReveal from "@/components/ScrollReveal";
|
||||||
|
|
||||||
|
interface Testimonial {
|
||||||
|
text: string;
|
||||||
|
name: string;
|
||||||
|
from: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TestimonialsSectionProps {
|
||||||
|
testimonials: Testimonial[];
|
||||||
|
lang: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function TestimonialsSection({ testimonials, lang }: TestimonialsSectionProps) {
|
||||||
|
return (
|
||||||
|
<section className="py-28 bg-white">
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<ScrollReveal className="text-center mb-16">
|
||||||
|
<span className="inline-block text-accent text-xs tracking-[0.25em] uppercase font-semibold mb-4">
|
||||||
|
{lang === "en" ? "Guest Reviews" : "Misafir Yorumları"}
|
||||||
|
</span>
|
||||||
|
<h2 className="font-serif text-5xl font-bold text-dark">
|
||||||
|
{lang === "en" ? "Experiences" : "Deneyimler"}
|
||||||
|
</h2>
|
||||||
|
</ScrollReveal>
|
||||||
|
|
||||||
|
<ScrollReveal stagger className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||||
|
{testimonials.map((t, i) => (
|
||||||
|
<div key={i} className="relative bg-sand rounded-2xl p-8 border border-sand overflow-hidden">
|
||||||
|
{/* Large decorative quote */}
|
||||||
|
<span className="absolute top-3 right-5 font-serif text-[8rem] leading-none text-primary/8 select-none">
|
||||||
|
"
|
||||||
|
</span>
|
||||||
|
{/* Stars */}
|
||||||
|
<div className="flex gap-1 mb-5 relative z-10">
|
||||||
|
{Array.from({ length: 5 }).map((_, j) => (
|
||||||
|
<Star key={j} className="w-3.5 h-3.5 text-accent" fill="#E87040" />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<p className="text-foreground/75 text-[13px] leading-relaxed mb-6 relative z-10 italic">
|
||||||
|
"{t.text}"
|
||||||
|
</p>
|
||||||
|
<div className="flex items-center gap-3 relative z-10">
|
||||||
|
<div className="w-9 h-9 bg-primary/10 rounded-full flex items-center justify-center flex-shrink-0">
|
||||||
|
<span className="text-primary font-bold text-sm">{t.name[0]}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span className="block font-semibold text-dark text-sm">{t.name}</span>
|
||||||
|
<span className="text-muted text-xs">{t.from}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</ScrollReveal>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
export default function openinaryLoader({ src, width, quality }: { src: string, width: number, quality?: number }) {
|
||||||
|
// Handle already absolute openinary URLs
|
||||||
|
let path = src;
|
||||||
|
if (src.startsWith('https://media.ayris.tech/t/')) {
|
||||||
|
// format: https://media.ayris.tech/t/w_800,h_800/moyqr/img.jpg
|
||||||
|
const parts = src.split('/');
|
||||||
|
path = parts.slice(5).join('/');
|
||||||
|
} else if (src.startsWith('https://media.ayris.tech/upload/')) {
|
||||||
|
// format: https://media.ayris.tech/upload/moyqr/img.jpg
|
||||||
|
const parts = src.split('/');
|
||||||
|
path = parts.slice(4).join('/');
|
||||||
|
} else if (src.includes('res.cloudinary.com')) {
|
||||||
|
// Correctly apply width & quality for unmigrated Cloudinary URLs
|
||||||
|
// e.g. https://res.cloudinary.com/domain/image/upload/v1234/path.jpg
|
||||||
|
// becomes: https://res.cloudinary.com/domain/image/upload/w_800,f_webp,q_75/v1234/path.jpg
|
||||||
|
const parts = src.split('/upload/');
|
||||||
|
if (parts.length === 2) {
|
||||||
|
return `${parts[0]}/upload/w_${width},f_webp,q_${quality || 75}/${parts[1]}`;
|
||||||
|
}
|
||||||
|
return src;
|
||||||
|
} else if (src.startsWith('http')) {
|
||||||
|
// For other external URLs, we append the width as a query parameter to satisfy Next.js.
|
||||||
|
const url = new URL(src);
|
||||||
|
url.searchParams.set('w', width.toString());
|
||||||
|
if (quality) {
|
||||||
|
url.searchParams.set('q', quality.toString());
|
||||||
|
}
|
||||||
|
return url.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up any leading slash
|
||||||
|
if (path.startsWith('/')) {
|
||||||
|
path = path.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return `https://media.ayris.tech/t/w_${width},f_webp,q_${quality || 75}/${path}`
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
const BASE = process.env.NEXT_PUBLIC_OPENINARY_URL;
|
||||||
|
|
||||||
|
export function optimizedImage(path: string, params: string) {
|
||||||
|
return `${BASE}/t/${params}/${path}`;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
export async function uploadToOpeninary(file: File, folder: string) {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("files", file);
|
||||||
|
formData.append("folder", folder);
|
||||||
|
|
||||||
|
const res = await fetch(`${process.env.OPENINARY_API_URL}/api/upload`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { Authorization: `Bearer ${process.env.OPENINARY_API_KEY}` },
|
||||||
|
body: formData,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
const errorText = await res.text();
|
||||||
|
console.error("Openinary upload error:", errorText);
|
||||||
|
throw new Error("Upload başarısız: " + errorText);
|
||||||
|
}
|
||||||
|
const data = await res.json();
|
||||||
|
return data.files[0]; // { path, url, size, ... }
|
||||||
|
}
|
||||||
@@ -7,6 +7,12 @@ const nextConfig: NextConfig = {
|
|||||||
formats: ["image/avif", "image/webp"],
|
formats: ["image/avif", "image/webp"],
|
||||||
minimumCacheTTL: 2592000,
|
minimumCacheTTL: 2592000,
|
||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
|
{
|
||||||
|
protocol: 'https',
|
||||||
|
hostname: 'media.ayris.tech',
|
||||||
|
port: '',
|
||||||
|
pathname: '/**',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
protocol: 'https',
|
protocol: 'https',
|
||||||
hostname: 'images.unsplash.com',
|
hostname: 'images.unsplash.com',
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ model SiteSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model HeroSection {
|
model HeroSection {
|
||||||
lang String @id // "tr" or "en"
|
lang String @id
|
||||||
location String
|
location String
|
||||||
welcome String
|
welcome String
|
||||||
title String
|
title String
|
||||||
@@ -30,12 +30,12 @@ model HeroSection {
|
|||||||
|
|
||||||
model Activity {
|
model Activity {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
lang String // "tr" or "en"
|
lang String
|
||||||
title String
|
title String
|
||||||
description String
|
description String
|
||||||
price String
|
price String
|
||||||
image String
|
image String
|
||||||
badge String? // e.g. "IKO Sertifikalı"
|
badge String?
|
||||||
order Int @default(0)
|
order Int @default(0)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
@@ -43,31 +43,31 @@ model Activity {
|
|||||||
|
|
||||||
model Event {
|
model Event {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
lang String // "tr" or "en"
|
lang String
|
||||||
title String
|
title String
|
||||||
description String
|
description String
|
||||||
date String
|
date String
|
||||||
time String
|
time String
|
||||||
location String
|
location String
|
||||||
image String
|
image String
|
||||||
badge String? // e.g. "Yaklaşan Etkinlik"
|
badge String?
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
model Feature {
|
model Feature {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
lang String // "tr" or "en"
|
lang String
|
||||||
icon String
|
icon String
|
||||||
label String
|
label String
|
||||||
sub String
|
sub String
|
||||||
order Int @default(0)
|
order Int @default(0)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
model AboutSection {
|
model AboutSection {
|
||||||
lang String @id // "tr" or "en"
|
lang String @id
|
||||||
badge String
|
badge String
|
||||||
titleLine1 String
|
titleLine1 String
|
||||||
titleLine2 String
|
titleLine2 String
|
||||||
@@ -91,4 +91,3 @@ model User {
|
|||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 616 KiB |
|
After Width: | Height: | Size: 803 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
@@ -0,0 +1,16 @@
|
|||||||
|
import 'dotenv/config';
|
||||||
|
import prisma from './lib/prisma';
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const imageUrl = "https://media.ayris.tech/t/kitebeachakyaka/kitesurf.png";
|
||||||
|
|
||||||
|
await prisma.aboutSection.updateMany({
|
||||||
|
data: {
|
||||||
|
image: imageUrl
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("About section image updated to the kitesurf one successfully!");
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch(console.error).finally(() => prisma.$disconnect());
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import 'dotenv/config';
|
||||||
|
import prisma from './lib/prisma';
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
await prisma.aboutSection.updateMany({
|
||||||
|
where: { lang: 'tr' },
|
||||||
|
data: {
|
||||||
|
badgeIkoTitle: 'Kitesurf',
|
||||||
|
badgeIkoLabel: 'Okulu'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await prisma.aboutSection.updateMany({
|
||||||
|
where: { lang: 'en' },
|
||||||
|
data: {
|
||||||
|
badgeIkoTitle: 'Kitesurf',
|
||||||
|
badgeIkoLabel: 'School'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('AboutSection DB updated successfully');
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch(console.error).finally(() => prisma.$disconnect());
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import 'dotenv/config';
|
||||||
|
import prisma from './lib/prisma';
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
await prisma.activity.deleteMany({});
|
||||||
|
|
||||||
|
await prisma.activity.createMany({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
lang: 'tr',
|
||||||
|
title: 'Kitesurf',
|
||||||
|
description: 'Akyaka\'nın muhteşem rüzgarında profesyonel eğitmenlerle kitesurf deneyimi yaşayın.',
|
||||||
|
price: 'Fiyat bilgisi için ulaşın',
|
||||||
|
image: 'https://images.unsplash.com/photo-1526367790999-0150786686a2?q=80&w=2940&auto=format&fit=crop',
|
||||||
|
badge: 'Popüler',
|
||||||
|
order: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'tr',
|
||||||
|
title: 'Yoga Wellness',
|
||||||
|
description: 'Nehir kenarında güne taze bir başlangıç veya gün batımında ruhunuzu dinlendiren yoga seansları.',
|
||||||
|
price: 'Fiyat bilgisi için ulaşın',
|
||||||
|
image: 'https://images.unsplash.com/photo-1545205597-3d9d02c29597?q=80&w=2940&auto=format&fit=crop',
|
||||||
|
badge: 'Rahatlatıcı',
|
||||||
|
order: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'tr',
|
||||||
|
title: 'Sunset DJ Party',
|
||||||
|
description: 'Gün batımını Ege\'nin muhteşem manzarası ve harika müzikler eşliğinde kutlayın.',
|
||||||
|
price: 'Ücretsiz Katılım',
|
||||||
|
image: 'https://images.unsplash.com/photo-1514525253161-7a46d19cd819?q=80&w=2874&auto=format&fit=crop',
|
||||||
|
badge: 'Eğlence',
|
||||||
|
order: 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'en',
|
||||||
|
title: 'Kitesurf',
|
||||||
|
description: 'Experience kitesurfing with professional instructors in Akyaka\'s amazing wind.',
|
||||||
|
price: 'Contact for price',
|
||||||
|
image: 'https://images.unsplash.com/photo-1526367790999-0150786686a2?q=80&w=2940&auto=format&fit=crop',
|
||||||
|
badge: 'Popular',
|
||||||
|
order: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'en',
|
||||||
|
title: 'Yoga Wellness',
|
||||||
|
description: 'A fresh start to the day by the river or relaxing yoga sessions at sunset.',
|
||||||
|
price: 'Contact for price',
|
||||||
|
image: 'https://images.unsplash.com/photo-1545205597-3d9d02c29597?q=80&w=2940&auto=format&fit=crop',
|
||||||
|
badge: 'Relaxing',
|
||||||
|
order: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'en',
|
||||||
|
title: 'Sunset DJ Party',
|
||||||
|
description: 'Celebrate the sunset with the amazing view of the Aegean and great music.',
|
||||||
|
price: 'Free Entry',
|
||||||
|
image: 'https://images.unsplash.com/photo-1514525253161-7a46d19cd819?q=80&w=2874&auto=format&fit=crop',
|
||||||
|
badge: 'Entertainment',
|
||||||
|
order: 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Activities updated successfully');
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch(console.error).finally(() => prisma.$disconnect());
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import 'dotenv/config';
|
||||||
|
import prisma from './lib/prisma';
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const imageUrl = "https://media.ayris.tech/t/kitebeachakyaka/kitesurf.png";
|
||||||
|
|
||||||
|
await prisma.activity.updateMany({
|
||||||
|
where: {
|
||||||
|
title: "Kitesurf"
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
image: imageUrl
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("Kitesurf activity image updated to the local one successfully!");
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch(console.error).finally(() => prisma.$disconnect());
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import 'dotenv/config';
|
||||||
|
|
||||||
|
async function uploadFile(filePath, folder) {
|
||||||
|
const fileName = path.basename(filePath);
|
||||||
|
const fileBuffer = fs.readFileSync(filePath);
|
||||||
|
|
||||||
|
const blob = new Blob([fileBuffer], { type: 'image/png' });
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('files', blob, fileName);
|
||||||
|
formData.append('folder', folder);
|
||||||
|
|
||||||
|
const res = await fetch(`${process.env.OPENINARY_API_URL}/api/upload`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { Authorization: `Bearer ${process.env.OPENINARY_API_KEY}` },
|
||||||
|
body: formData,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
const text = await res.text();
|
||||||
|
throw new Error(`Upload failed for ${fileName}: ${text}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
return data.files[0].url;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const filePath = './public/kitesurf.png';
|
||||||
|
console.log(`Uploading ${filePath}...`);
|
||||||
|
try {
|
||||||
|
const url = await uploadFile(filePath, 'kitebeachakyaka');
|
||||||
|
console.log(`Uploaded! URL: ${url}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch(console.error);
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import 'dotenv/config';
|
||||||
|
|
||||||
|
async function uploadFile(filePath, folder) {
|
||||||
|
const fileName = path.basename(filePath);
|
||||||
|
const fileBuffer = fs.readFileSync(filePath);
|
||||||
|
|
||||||
|
const blob = new Blob([fileBuffer], { type: 'image/jpeg' });
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
// We can pass a file name to the formData in Node by passing an object with name or using File (if available)
|
||||||
|
// But FormData append takes (name, value, filename)
|
||||||
|
formData.append('files', blob, fileName);
|
||||||
|
formData.append('folder', folder);
|
||||||
|
|
||||||
|
const res = await fetch(`${process.env.OPENINARY_API_URL}/api/upload`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { Authorization: `Bearer ${process.env.OPENINARY_API_KEY}` },
|
||||||
|
body: formData,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
const text = await res.text();
|
||||||
|
throw new Error(`Upload failed for ${fileName}: ${text}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
return data.files[0].url;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const dirPath = './public/rooms';
|
||||||
|
const files = fs.readdirSync(dirPath).filter(f => f.endsWith('.jpeg') || f.endsWith('.jpg'));
|
||||||
|
|
||||||
|
const uploadedUrls = [];
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
console.log(`Uploading ${file}...`);
|
||||||
|
try {
|
||||||
|
const url = await uploadFile(path.join(dirPath, file), 'kitebeachakyaka/rooms');
|
||||||
|
console.log(`Uploaded! URL: ${url}`);
|
||||||
|
uploadedUrls.push(url);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n--- UPLOADED URLS ---');
|
||||||
|
console.log(JSON.stringify(uploadedUrls, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch(console.error);
|
||||||