diff --git a/README.md b/README.md
index e215bc4..1ff4eca 100644
--- a/README.md
+++ b/README.md
@@ -1,36 +1,65 @@
-This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
+# Kozmos Beach & More
+
+**"Denizin Ormana Kıyısında" / "Where the Sea Meets the Forest"**
+
+Kozmos Beach & More is a modern, responsive, and bilingual (Turkish & English) corporate website built with Next.js 16 (App Router). It features a mobile-first design, a seamless single-page scrolling experience, and dedicated pages like Accommodation, all wrapped in a boho-chic, Aegean-inspired aesthetic.
+
+## Features
+
+- **Next.js 16 (App Router):** Fast, SEO-friendly, and modern architecture.
+- **i18n Support:** Fully bilingual (TR/EN) using `next-intl`.
+- **Styling:** Tailwind CSS v4 with custom gradients, colors, and an elegant typography system (Marcellus).
+- **Animations:** Smooth micro-interactions and scroll animations powered by `framer-motion`.
+- **Responsive Design:** Mobile-first approach, ensuring a flawless experience across all devices.
+- **Lightbox Gallery:** Custom-built image gallery with a full-screen lightbox feature.
+- **PWA & SEO Ready:** Pre-configured `manifest.ts`, `robots.ts`, `sitemap.ts`, and metadata.
+
+## Tech Stack
+
+- **Framework:** [Next.js](https://nextjs.org/)
+- **Language:** [TypeScript](https://www.typescriptlang.org/)
+- **Styling:** [Tailwind CSS v4](https://tailwindcss.com/)
+- **Animations:** [Framer Motion](https://www.framer.com/motion/)
+- **Icons:** [Lucide React](https://lucide.dev/)
+- **Internationalization:** [next-intl](https://next-intl-docs.vercel.app/)
+
+## Environment Variables
+
+To run the project locally, create a `.env.local` file with the following variables:
+
+```env
+# Contact number for WhatsApp reservation buttons
+NEXT_PUBLIC_WHATSAPP_NUMBER="905000000000"
+
+# URL for the QR menu (if applicable)
+NEXT_PUBLIC_MENU_URL="https://qr.kozmosbeach.com"
+```
## Getting Started
-First, run the development server:
+1. **Install dependencies:**
+ ```bash
+ npm install
+ ```
-```bash
-npm run dev
-# or
-yarn dev
-# or
-pnpm dev
-# or
-bun dev
-```
+2. **Run the development server:**
+ ```bash
+ npm run dev
+ ```
-Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+3. **Build for production:**
+ ```bash
+ npm run build
+ npm run start
+ ```
-You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
+## Development Commands
-This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
+- `npm run dev`: Starts the development server.
+- `npm run build`: Builds the app for production.
+- `npm run start`: Runs the built app in production mode.
+- `npm run lint`: Runs ESLint.
-## Learn More
+---
-To learn more about Next.js, take a look at the following resources:
-
-- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
-- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
-
-You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
-
-## Deploy on Vercel
-
-The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
-
-Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
+*Created by [ayris.tech](https://ayris.tech)*
diff --git a/app/[locale]/accommodation/page.tsx b/app/[locale]/accommodation/page.tsx
new file mode 100644
index 0000000..742e4bf
--- /dev/null
+++ b/app/[locale]/accommodation/page.tsx
@@ -0,0 +1,24 @@
+import Navbar from '@/components/Navbar';
+import Accommodation from '@/components/Accommodation';
+import Footer from '@/components/Footer';
+import WhatsAppButton from '@/components/WhatsAppButton';
+
+export default async function AccommodationPage({
+ params
+}: {
+ params: Promise<{ locale: string }>
+}) {
+ const { locale } = await params;
+
+ return (
+
+
+ {/* Spacer to push content below fixed navbar */}
+
+
+
+
+ );
+}
diff --git a/app/[locale]/layout.tsx b/app/[locale]/layout.tsx
new file mode 100644
index 0000000..bed88d9
--- /dev/null
+++ b/app/[locale]/layout.tsx
@@ -0,0 +1,47 @@
+import { NextIntlClientProvider } from 'next-intl';
+import { getMessages } from 'next-intl/server';
+import { notFound } from 'next/navigation';
+import { routing } from '@/i18n/routing';
+import { Marcellus } from 'next/font/google';
+import '../globals.css';
+
+const marcellus = Marcellus({
+ subsets: ['latin'],
+ variable: '--font-marcellus',
+ weight: ['400'],
+});
+
+export const metadata = {
+ title: 'Kozmos Beach & More',
+ description: 'Denizin Ormana Kıyısında — Akyaka, Gökova',
+};
+
+export function generateStaticParams() {
+ return routing.locales.map((locale) => ({ locale }));
+}
+
+export default async function LocaleLayout({
+ children,
+ params,
+}: {
+ children: React.ReactNode;
+ params: Promise<{ locale: string }>;
+}) {
+ const { locale } = await params;
+
+ if (!routing.locales.includes(locale as any)) {
+ notFound();
+ }
+
+ const messages = await getMessages();
+
+ return (
+
+
+
+ {children}
+
+
+
+ );
+}
diff --git a/app/[locale]/page.tsx b/app/[locale]/page.tsx
new file mode 100644
index 0000000..93ab098
--- /dev/null
+++ b/app/[locale]/page.tsx
@@ -0,0 +1,35 @@
+import Navbar from '@/components/Navbar';
+import Hero from '@/components/Hero';
+import About from '@/components/About';
+import Accommodation from '@/components/Accommodation';
+import Beach from '@/components/Beach';
+import Dining from '@/components/Dining';
+import Events from '@/components/Events';
+import Gallery from '@/components/Gallery';
+import Contact from '@/components/Contact';
+import Footer from '@/components/Footer';
+import WhatsAppButton from '@/components/WhatsAppButton';
+
+export default async function Page({
+ params
+}: {
+ params: Promise<{ locale: string }>
+}) {
+ const { locale } = await params;
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/globals.css b/app/globals.css
index a2dc41e..545e0db 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -1,26 +1,157 @@
@import "tailwindcss";
-:root {
- --background: #ffffff;
- --foreground: #171717;
+@theme {
+ --color-sand: #FFF8EE;
+ --color-sandy: #F5E6CC;
+ --color-coral: #FF5A36;
+ --color-coral-light: #FF7A5A;
+ --color-amber: #FFA827;
+ --color-gold: #FFD166;
+ --color-aqua: #00BFA5;
+ --color-cyan: #00E5FF;
+ --color-midnight: #080D18;
+ --color-deep: #0E1B30;
+ --color-navy: #1A2F4A;
+
+ /* backward compat */
+ --color-cream: #FFF8EE;
+ --color-beige: #F5E6CC;
+ --color-turquoise: #00BFA5;
+ --color-forest: #0E1B30;
+ --color-dark-brown: #080D18;
+
+ --font-heading: var(--font-marcellus);
+ --font-body: var(--font-marcellus);
}
-@theme inline {
- --color-background: var(--background);
- --color-foreground: var(--foreground);
- --font-sans: var(--font-geist-sans);
- --font-mono: var(--font-geist-mono);
-}
+@layer base {
+ body {
+ @apply bg-sand text-midnight font-body antialiased;
+ }
-@media (prefers-color-scheme: dark) {
- :root {
- --background: #0a0a0a;
- --foreground: #ededed;
+ h1, h2, h3, h4, h5, h6 {
+ @apply font-heading;
}
}
-body {
- background: var(--background);
- color: var(--foreground);
- font-family: Arial, Helvetica, sans-serif;
+html {
+ scroll-behavior: smooth;
+}
+
+/* ── CSS custom property for animated border ──── */
+@property --border-angle {
+ syntax: '';
+ initial-value: 0deg;
+ inherits: false;
+}
+
+/* ── Animated conic border classes ─────────────── */
+.border-spin-cyan {
+ background:
+ linear-gradient(#0E1B30, #0E1B30) padding-box,
+ conic-gradient(from var(--border-angle), #00E5FF 0deg, transparent 70deg, transparent 290deg, #00E5FF 360deg) border-box;
+ border: 1px solid transparent;
+ animation: border-rotate 3s linear infinite;
+}
+
+.border-spin-coral {
+ background:
+ linear-gradient(#0E1B30, #0E1B30) padding-box,
+ conic-gradient(from var(--border-angle), #FF5A36 0deg, transparent 70deg, transparent 290deg, #FF5A36 360deg) border-box;
+ border: 1px solid transparent;
+ animation: border-rotate 4s linear infinite;
+}
+
+.border-spin-amber {
+ background:
+ linear-gradient(#0E1B30, #0E1B30) padding-box,
+ conic-gradient(from var(--border-angle), #FFA827 0deg, transparent 70deg, transparent 290deg, #FFA827 360deg) border-box;
+ border: 1px solid transparent;
+ animation: border-rotate 5s linear infinite;
+}
+
+/* ── Keyframes ─────────────────────────────────── */
+
+@keyframes shimmer {
+ 0% { background-position: -400% center; }
+ 100% { background-position: 400% center; }
+}
+
+@keyframes float {
+ 0%, 100% { transform: translateY(0px); }
+ 50% { transform: translateY(-16px); }
+}
+
+@keyframes border-rotate {
+ to { --border-angle: 360deg; }
+}
+
+@keyframes eq-bar {
+ 0%, 100% { transform: scaleY(0.3); }
+ 50% { transform: scaleY(1); }
+}
+
+@keyframes grain {
+ 0%, 100% { transform: translate(0, 0 ); }
+ 10% { transform: translate(-5%, -5% ); }
+ 20% { transform: translate(-10%, 5% ); }
+ 30% { transform: translate(5%, -10%); }
+ 40% { transform: translate(-5%, 15%); }
+ 50% { transform: translate(-10%, 5%); }
+ 60% { transform: translate(15%, 0% ); }
+ 70% { transform: translate(0%, 10%); }
+ 80% { transform: translate(-15%, 0% ); }
+ 90% { transform: translate(10%, 5%); }
+}
+
+/* ── Utility classes ───────────────────────────── */
+
+.shimmer-text {
+ background: linear-gradient(
+ 90deg,
+ #ffffff 0%,
+ #ffffff 35%,
+ #FFD166 45%,
+ #FF5A36 50%,
+ #FFD166 55%,
+ #ffffff 65%,
+ #ffffff 100%
+ );
+ background-size: 400% auto;
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ animation: shimmer 4s linear infinite;
+}
+
+.gradient-text {
+ background: linear-gradient(135deg, #FF5A36, #FFA827, #00BFA5);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+.gradient-text-warm {
+ background: linear-gradient(135deg, #FF5A36, #FFA827);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+.gradient-text-cool {
+ background: linear-gradient(135deg, #00E5FF, #00BFA5);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+.grain-overlay::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+ z-index: 1;
+ opacity: 0.045;
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
+ animation: grain 8s steps(10) infinite;
}
diff --git a/app/layout.tsx b/app/layout.tsx
deleted file mode 100644
index 976eb90..0000000
--- a/app/layout.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import type { Metadata } from "next";
-import { Geist, Geist_Mono } from "next/font/google";
-import "./globals.css";
-
-const geistSans = Geist({
- variable: "--font-geist-sans",
- subsets: ["latin"],
-});
-
-const geistMono = Geist_Mono({
- variable: "--font-geist-mono",
- subsets: ["latin"],
-});
-
-export const metadata: Metadata = {
- title: "Create Next App",
- description: "Generated by create next app",
-};
-
-export default function RootLayout({
- children,
-}: Readonly<{
- children: React.ReactNode;
-}>) {
- return (
-
- {children}
-
- );
-}
diff --git a/app/manifest.ts b/app/manifest.ts
new file mode 100644
index 0000000..ebd47e7
--- /dev/null
+++ b/app/manifest.ts
@@ -0,0 +1,25 @@
+import { MetadataRoute } from 'next';
+
+export default function manifest(): MetadataRoute.Manifest {
+ return {
+ name: 'Kozmos Beach & More',
+ short_name: 'Kozmos',
+ description: 'Where the Sea Meets the Forest',
+ start_url: '/',
+ display: 'standalone',
+ background_color: '#F5F0E8',
+ theme_color: '#4AAFA8',
+ icons: [
+ {
+ src: '/icon-192x192.png',
+ sizes: '192x192',
+ type: 'image/png',
+ },
+ {
+ src: '/icon-512x512.png',
+ sizes: '512x512',
+ type: 'image/png',
+ },
+ ],
+ };
+}
diff --git a/app/page.tsx b/app/page.tsx
deleted file mode 100644
index 3f36f7c..0000000
--- a/app/page.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import Image from "next/image";
-
-export default function Home() {
- return (
-
-
-
-
-
- To get started, edit the page.tsx file.
-
-
- Looking for a starting point or more instructions? Head over to{" "}
-
- Templates
- {" "}
- or the{" "}
-
- Learning
- {" "}
- center.
-
-
-
-
-
- );
-}
diff --git a/app/robots.ts b/app/robots.ts
new file mode 100644
index 0000000..765f1ff
--- /dev/null
+++ b/app/robots.ts
@@ -0,0 +1,11 @@
+import { MetadataRoute } from 'next';
+
+export default function robots(): MetadataRoute.Robots {
+ return {
+ rules: {
+ userAgent: '*',
+ allow: '/',
+ },
+ sitemap: 'https://kozmosbeach.com/sitemap.xml',
+ };
+}
diff --git a/app/sitemap.ts b/app/sitemap.ts
new file mode 100644
index 0000000..25d1083
--- /dev/null
+++ b/app/sitemap.ts
@@ -0,0 +1,20 @@
+import { MetadataRoute } from 'next';
+
+export default function sitemap(): MetadataRoute.Sitemap {
+ const baseUrl = 'https://kozmosbeach.com';
+
+ return [
+ {
+ url: `${baseUrl}/tr`,
+ lastModified: new Date(),
+ changeFrequency: 'monthly',
+ priority: 1,
+ },
+ {
+ url: `${baseUrl}/en`,
+ lastModified: new Date(),
+ changeFrequency: 'monthly',
+ priority: 1,
+ },
+ ];
+}
diff --git a/components/About.tsx b/components/About.tsx
new file mode 100644
index 0000000..714652e
--- /dev/null
+++ b/components/About.tsx
@@ -0,0 +1,94 @@
+"use client";
+
+import { useTranslations } from 'next-intl';
+import { motion } from 'framer-motion';
+import { Waves, Leaf, Music } from 'lucide-react';
+import Image from 'next/image';
+
+const features = [
+ { icon: Waves, titleKey: 'card1_title', descKey: 'card1_desc', color: 'text-aqua', bg: 'bg-aqua/10' },
+ { icon: Leaf, titleKey: 'card2_title', descKey: 'card2_desc', color: 'text-amber', bg: 'bg-amber/10' },
+ { icon: Music, titleKey: 'card3_title', descKey: 'card3_desc', color: 'text-coral', bg: 'bg-coral/10' },
+];
+
+export default function About() {
+ const t = useTranslations('About');
+
+ return (
+
+
+
+
+ {/* Left content */}
+
+
+
+ — Beach & More
+
+
+ {t('title')}
+
+
{t('description')}
+
+
+
+ {features.map(({ icon: Icon, titleKey, descKey, color, bg }, i) => (
+
+
+
+
+
+
{t(titleKey)}
+
{t(descKey)}
+
+
+ ))}
+
+
+
+ {/* Right image */}
+
+ {/* Glow ring */}
+
+
+
+
+
+
+
+ );
+}
diff --git a/components/Accommodation.tsx b/components/Accommodation.tsx
new file mode 100644
index 0000000..db8c927
--- /dev/null
+++ b/components/Accommodation.tsx
@@ -0,0 +1,149 @@
+"use client";
+
+import { useTranslations } from 'next-intl';
+import { motion } from 'framer-motion';
+import Image from 'next/image';
+import { Users, Check, Sparkles } from 'lucide-react';
+
+export default function Accommodation() {
+ const t = useTranslations('Accommodation');
+
+ const openWhatsApp = () => {
+ const phone = process.env.NEXT_PUBLIC_WHATSAPP_NUMBER || '905000000000';
+ window.open(`https://wa.me/${phone}`, '_blank');
+ };
+
+ const rooms = [
+ {
+ id: 'standard',
+ image: 'https://picsum.photos/600/400?random=3',
+ capacity: 2,
+ features: t.raw('rooms.standard.features') as string[],
+ featured: false,
+ gradient: 'linear-gradient(135deg, #00BFA5, #00E5FF)',
+ },
+ {
+ id: 'sea_view',
+ image: 'https://picsum.photos/600/400?random=4',
+ capacity: 2,
+ features: t.raw('rooms.sea_view.features') as string[],
+ featured: true,
+ gradient: 'linear-gradient(135deg, #FF5A36, #FFA827)',
+ },
+ {
+ id: 'garden_suite',
+ image: 'https://picsum.photos/600/400?random=5',
+ capacity: 4,
+ features: t.raw('rooms.garden_suite.features') as string[],
+ featured: false,
+ gradient: 'linear-gradient(135deg, #00BFA5, #00E5FF)',
+ },
+ ];
+
+ return (
+
+
+
+
+
+ — Konaklama
+
+
+ {t('title')}
+
+
+ {t('description')}
+
+
+
+
+ {rooms.map((room, index) => (
+
+ {/* Featured badge */}
+ {room.featured && (
+
+
+ FEATURED
+
+ )}
+
+ {/* Image */}
+
+
+ {/* Content */}
+
+
+ {t(`rooms.${room.id}.name`)}
+
+
+
+
+
+ {t('capacity')} {room.capacity} {t('person')}
+
+
+
+
+ {room.features.map((feature, i) => (
+
+
+ {feature}
+
+ ))}
+
+
+
+ {t('book_whatsapp')}
+
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/components/Beach.tsx b/components/Beach.tsx
new file mode 100644
index 0000000..bd6a1ee
--- /dev/null
+++ b/components/Beach.tsx
@@ -0,0 +1,139 @@
+"use client";
+
+import { useTranslations } from 'next-intl';
+import { motion } from 'framer-motion';
+import Image from 'next/image';
+import { Sun } from 'lucide-react';
+
+export default function Beach() {
+ const t = useTranslations('Beach');
+
+ const openWhatsApp = () => {
+ const phone = process.env.NEXT_PUBLIC_WHATSAPP_NUMBER || '905000000000';
+ window.open(
+ `https://wa.me/${phone}?text=Merhaba,%20şezlong%20rezervasyonu%20yaptırmak%20istiyorum.`,
+ '_blank',
+ );
+ };
+
+ const stats = [
+ { value: '∞', label: 'Şezlong' },
+ { value: '7/7', label: 'Açık' },
+ { value: 'VIP', label: 'Cabana' },
+ ];
+
+ return (
+
+
+
+
+ {/* Left masonry photos */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Right content */}
+
+
+
+ Beach Club
+
+
+
+ {t('title')}
+
+
+ {t('description')}
+
+ {/* Stats */}
+
+ {stats.map(({ value, label }) => (
+
+ ))}
+
+
+ {/* Info & CTA */}
+
+
{t('reservation_info')}
+
+ {t('book_lounger')}
+
+
+
+
+
+
+
+ {/* Wave → midnight */}
+
+
+ );
+}
diff --git a/components/Contact.tsx b/components/Contact.tsx
new file mode 100644
index 0000000..bc616ec
--- /dev/null
+++ b/components/Contact.tsx
@@ -0,0 +1,200 @@
+"use client";
+
+import { useTranslations } from 'next-intl';
+import { motion } from 'framer-motion';
+import { MapPin, Phone, Send } from 'lucide-react';
+import { Instagram } from '@/components/InstagramIcon';
+import { useState } from 'react';
+
+export default function Contact() {
+ const t = useTranslations('Contact');
+ const [formData, setFormData] = useState({ name: '', date: '', guests: '', message: '' });
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault();
+ const phone = process.env.NEXT_PUBLIC_WHATSAPP_NUMBER || '905000000000';
+ const text = `*Yeni Rezervasyon Talebi*%0A%0A*Ad Soyad:* ${formData.name}%0A*Tarih:* ${formData.date}%0A*Kişi Sayısı:* ${formData.guests}%0A*Mesaj:* ${formData.message}`;
+ window.open(`https://wa.me/${phone}?text=${text}`, '_blank');
+ };
+
+ const handleChange = (e: React.ChangeEvent) => {
+ setFormData({ ...formData, [e.target.name]: e.target.value });
+ };
+
+ const contactItems = [
+ {
+ Icon: MapPin,
+ label: 'Adres',
+ value: t('address'),
+ color: 'text-coral',
+ bg: 'bg-coral/10',
+ },
+ {
+ Icon: Phone,
+ label: 'Telefon / WhatsApp',
+ value: `+${process.env.NEXT_PUBLIC_WHATSAPP_NUMBER || '90 500 000 00 00'}`,
+ color: 'text-aqua',
+ bg: 'bg-aqua/10',
+ },
+ {
+ Icon: Instagram,
+ label: 'Instagram',
+ value: '@kozmosbeach',
+ href: 'https://www.instagram.com/kozmosbeach/',
+ color: 'text-amber',
+ bg: 'bg-amber/10',
+ },
+ ];
+
+ const inputClass =
+ 'w-full bg-sand border border-sandy rounded-xl px-4 py-3 text-sm focus:outline-none focus:border-coral focus:ring-1 focus:ring-coral transition-all placeholder:text-midnight/30';
+
+ return (
+
+ );
+}
diff --git a/components/Dining.tsx b/components/Dining.tsx
new file mode 100644
index 0000000..fafe2ed
--- /dev/null
+++ b/components/Dining.tsx
@@ -0,0 +1,116 @@
+"use client";
+
+import { useTranslations } from 'next-intl';
+import { motion } from 'framer-motion';
+import { Utensils, Wine, Coffee, ArrowRight } from 'lucide-react';
+
+const CARDS = [
+ { id: 'seafood', icon: Utensils, accent: '#FF5A36' },
+ { id: 'cocktails', icon: Wine, accent: '#00BFA5' },
+ { id: 'breakfast', icon: Coffee, accent: '#FFA827' },
+];
+
+export default function Dining() {
+ const t = useTranslations('Dining');
+ const menuUrl = process.env.NEXT_PUBLIC_MENU_URL || '#';
+
+ return (
+
+ {/* Background blobs */}
+
+
+
+
+
+ — Yeme & İçme
+
+
+
+ {t('title')}
+
+
+
+ {t('description')}
+
+
+
+ {t('view_menu')}
+
+
+
+
+
+ {CARDS.map(({ id, icon: Icon, accent }, index) => (
+
+ {/* Icon */}
+
+
+
+
+
+ {t(`cards.${id}.title`)}
+
+ {t(`cards.${id}.desc`)}
+
+ {/* Bottom accent line on hover */}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/components/Events.tsx b/components/Events.tsx
new file mode 100644
index 0000000..de68de7
--- /dev/null
+++ b/components/Events.tsx
@@ -0,0 +1,366 @@
+"use client";
+
+import { useTranslations } from 'next-intl';
+import { motion } from 'framer-motion';
+import { Calendar, Music, Disc3, CalendarDays, Zap } from 'lucide-react';
+
+/* ── static data ───────────────────────────────── */
+
+const WEEK_DAYS = ['Pzt', 'Sal', 'Çar', 'Per', 'Cum', 'Cmt', 'Paz'];
+const ACTIVE_DAYS: Record = {
+ 3: '#FF5A36',
+ 4: '#00E5FF',
+ 5: '#00E5FF',
+};
+
+/* ── sub-components ────────────────────────────── */
+
+function VinylDisc() {
+ return (
+
+ {/* Grooves */}
+ {[55, 45, 35].map((size) => (
+
+ ))}
+ {/* Label */}
+
+
+ );
+}
+
+function EqBars({ color }: { color: string }) {
+ const heights = [0.4, 0.8, 0.5, 1, 0.65, 0.9, 0.45, 0.75, 0.55, 0.85];
+ return (
+
+ {heights.map((h, i) => (
+ 0.6 ? 0.2 : 1, h] }}
+ transition={{
+ duration: 0.5 + Math.random() * 0.4,
+ repeat: Infinity,
+ repeatType: 'mirror',
+ delay: i * 0.07,
+ ease: 'easeInOut',
+ }}
+ />
+ ))}
+
+ );
+}
+
+function WineGlassIcon() {
+ return (
+
+
+
+
+
+
+ );
+}
+
+/* ── main component ────────────────────────────── */
+
+export default function Events() {
+ const t = useTranslations('Events');
+
+ return (
+
+ {/* Aurora background blobs */}
+
+
+ {/* Fine dot grid */}
+
+
+
+
+ {/* ── Header ───────────────────────────────── */}
+
+
+
+
+
+ Live Events
+
+
+
+ {t('title')}
+
+
+ {t('description')}
+
+
+
+
+
+ {t('view_calendar')}
+
+
+
+ {/* ── Weekly schedule bar ───────────────────── */}
+
+ {WEEK_DAYS.map((day, i) => {
+ const accent = ACTIVE_DAYS[i];
+ const isActive = !!accent;
+ return (
+
+ );
+ })}
+
+
+ {/* ── Featured Event: DJ Nights ────────────── */}
+
+
+ {/* Glow center */}
+
+
+ {/* Left: text */}
+
+
+
+ EN POPÜLER
+
+
+
+ {t('cards.dj.time')}
+
+
+
+
+ {t('cards.dj.title')}
+
+
+
+
+ Open-air · Beach Stage
+
+
+
+
+
+ {/* Right: vinyl */}
+
+
+
+
+
+
+ {/* ── Secondary events: 2-col grid ─────────── */}
+
+
+ {/* Rakı Geceleri */}
+
+
+
+
+
+
+
+
+ {t('cards.raki.title')}
+
+
+
+ {t('cards.raki.time')}
+
+
+
+
+
+
+
+
+
+ {/* Canlı Müzik */}
+
+
+
+
+
+
+
+
+ {t('cards.live_music.title')}
+
+
+
+ {t('cards.live_music.time')}
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Wave → sand */}
+
+
+ );
+}
diff --git a/components/Footer.tsx b/components/Footer.tsx
new file mode 100644
index 0000000..c0e3c50
--- /dev/null
+++ b/components/Footer.tsx
@@ -0,0 +1,94 @@
+"use client";
+
+import { useTranslations } from 'next-intl';
+import { Instagram } from '@/components/InstagramIcon';
+import { Link, usePathname } from '@/i18n/routing';
+
+export default function Footer() {
+ const t = useTranslations('Footer');
+ const tNav = useTranslations('Navbar');
+
+ const pathname = usePathname();
+
+ const navLinks = [
+ { href: pathname === '/' ? '#about' : '/#about', label: tNav('about') },
+ { href: '/accommodation', label: tNav('accommodation') },
+ { href: pathname === '/' ? '#beach' : '/#beach', label: tNav('beach') },
+ { href: pathname === '/' ? '#dining' : '/#dining', label: tNav('dining') },
+ { href: pathname === '/' ? '#events' : '/#events', label: tNav('events') },
+ { href: pathname === '/' ? '#gallery' : '/#gallery', label: tNav('gallery') },
+ { href: pathname === '/' ? '#contact' : '/#contact', label: tNav('contact') },
+ ];
+
+ return (
+
+ {/* Rainbow top border */}
+
+
+
+
+
+ {/* Brand */}
+
+
+
+ Kozmos
+
+
+ Beach & More
+
+
+
{t('tagline')}
+
+
+ {/* Nav links */}
+
+ {navLinks.map((link) => (
+
+ {link.label}
+
+ ))}
+
+
+ {/* Social */}
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/components/Gallery.tsx b/components/Gallery.tsx
new file mode 100644
index 0000000..0a5a214
--- /dev/null
+++ b/components/Gallery.tsx
@@ -0,0 +1,162 @@
+"use client";
+
+import { useTranslations } from 'next-intl';
+import { motion, AnimatePresence } from 'framer-motion';
+import { Instagram } from '@/components/InstagramIcon';
+import { useState, useEffect } from 'react';
+import { X, ChevronLeft, ChevronRight } from 'lucide-react';
+
+export default function Gallery() {
+ const t = useTranslations('Gallery');
+
+ const images = Array.from({ length: 12 }).map((_, i) => ({
+ id: i,
+ src: `https://picsum.photos/600/${400 + (i % 5) * 50}?random=${30 + i}`,
+ alt: `Gallery ${i + 1}`,
+ }));
+
+ const [selectedIndex, setSelectedIndex] = useState(null);
+
+ // Close lightbox on escape key
+ useEffect(() => {
+ const handleKeyDown = (e: KeyboardEvent) => {
+ if (e.key === 'Escape') setSelectedIndex(null);
+ if (e.key === 'ArrowRight' && selectedIndex !== null) {
+ setSelectedIndex((prev) => (prev !== null ? (prev + 1) % images.length : null));
+ }
+ if (e.key === 'ArrowLeft' && selectedIndex !== null) {
+ setSelectedIndex((prev) => (prev !== null ? (prev - 1 + images.length) % images.length : null));
+ }
+ };
+ window.addEventListener('keydown', handleKeyDown);
+ return () => window.removeEventListener('keydown', handleKeyDown);
+ }, [selectedIndex, images.length]);
+
+ return (
+
+
+
+ {/* Header */}
+
+
+
+ — Fotoğraflar
+
+
+ {t('title')}
+
+
+
+
+
+ {t('follow_instagram')}
+
+
+
+ {/* Masonry grid */}
+
+ {images.map((img, index) => (
+
setSelectedIndex(index)}
+ className="relative rounded-2xl overflow-hidden group break-inside-avoid cursor-pointer"
+ >
+
+ {/* Coral gradient overlay */}
+
+ {/* Plus icon */}
+
+ +
+
+
+ ))}
+
+
+
+ {/* Lightbox Overlay */}
+
+ {selectedIndex !== null && (
+
+ {/* Close Button */}
+ setSelectedIndex(null)}
+ className="absolute top-6 right-6 z-[110] text-white/70 hover:text-white transition-colors"
+ >
+
+
+
+ {/* Left/Right Navigation */}
+ {
+ e.stopPropagation();
+ setSelectedIndex((selectedIndex - 1 + images.length) % images.length);
+ }}
+ className="absolute left-4 md:left-10 z-[110] p-3 rounded-full bg-white/10 text-white hover:bg-white/20 transition-all"
+ >
+
+
+
+ {
+ e.stopPropagation();
+ setSelectedIndex((selectedIndex + 1) % images.length);
+ }}
+ className="absolute right-4 md:right-10 z-[110] p-3 rounded-full bg-white/10 text-white hover:bg-white/20 transition-all"
+ >
+
+
+
+ {/* Image */}
+ e.stopPropagation()}
+ >
+
+
+
+ )}
+
+
+ );
+}
diff --git a/components/Hero.tsx b/components/Hero.tsx
new file mode 100644
index 0000000..ffdddb5
--- /dev/null
+++ b/components/Hero.tsx
@@ -0,0 +1,156 @@
+"use client";
+
+import { useTranslations } from 'next-intl';
+import { motion } from 'framer-motion';
+import { ChevronDown, MapPin } from 'lucide-react';
+
+export default function Hero() {
+ const t = useTranslations('Hero');
+
+ const openWhatsApp = () => {
+ const phone = process.env.NEXT_PUBLIC_WHATSAPP_NUMBER || '905000000000';
+ window.open(`https://wa.me/${phone}`, '_blank');
+ };
+
+ return (
+
+ {/* ── Ambient gradient blobs ───────────────────── */}
+
+
+
+
+
+
+ {/* Grain overlay */}
+
+
+ {/* ── Content ──────────────────────────────────── */}
+
+
+ {/* Location */}
+
+ Akyaka · Gökova Körfezi
+
+
+ {/* Brand name — static gradient, no shimmer */}
+
+ KOZMOS
+
+
+ {/* Thin divider */}
+
+
+ {/* Subtitle */}
+
+ Beach & More
+
+
+ {/* Tagline */}
+
+ {t('tagline')}
+
+
+ {/* CTAs */}
+
+
+ {t('cta_reservation')}
+
+
+
+
+ {t('cta_location')}
+
+
+
+
+ {/* ── Wave divider ─────────────────────────────── */}
+
+
+ {/* Scroll cue */}
+
+
+
+
+
+
+ );
+}
diff --git a/components/InstagramIcon.tsx b/components/InstagramIcon.tsx
new file mode 100644
index 0000000..5cf3cc0
--- /dev/null
+++ b/components/InstagramIcon.tsx
@@ -0,0 +1,22 @@
+import React from 'react';
+
+export function Instagram({ size = 24, className = "" }: { size?: number, className?: string }) {
+ return (
+
+
+
+
+
+ );
+}
diff --git a/components/Navbar.tsx b/components/Navbar.tsx
new file mode 100644
index 0000000..89979aa
--- /dev/null
+++ b/components/Navbar.tsx
@@ -0,0 +1,173 @@
+"use client";
+
+import { useTranslations } from 'next-intl';
+import { Link, usePathname, useRouter } from '@/i18n/routing';
+import { useState, useEffect } from 'react';
+import { Menu, X } from 'lucide-react';
+import { motion, AnimatePresence } from 'framer-motion';
+
+export default function Navbar({ locale }: { locale: string }) {
+ const t = useTranslations('Navbar');
+ const pathname = usePathname();
+ const router = useRouter();
+
+ const [isScrolled, setIsScrolled] = useState(false);
+ const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
+
+ useEffect(() => {
+ const handleScroll = () => setIsScrolled(window.scrollY > 50);
+ window.addEventListener('scroll', handleScroll);
+ return () => window.removeEventListener('scroll', handleScroll);
+ }, []);
+
+ const switchLocale = (newLocale: string) => {
+ router.replace(pathname, { locale: newLocale });
+ };
+
+ const navLinks = [
+ { href: pathname === '/' ? '#about' : '/#about', label: t('about') },
+ { href: '/accommodation', label: t('accommodation') },
+ { href: pathname === '/' ? '#beach' : '/#beach', label: t('beach') },
+ { href: pathname === '/' ? '#dining' : '/#dining', label: t('dining') },
+ { href: pathname === '/' ? '#events' : '/#events', label: t('events') },
+ { href: pathname === '/' ? '#gallery' : '/#gallery', label: t('gallery') },
+ { href: pathname === '/' ? '#contact' : '/#contact', label: t('contact') },
+ ];
+
+ return (
+
+
+
+ {/* Logo */}
+
+
+ Kozmos
+
+
+ Beach & More
+
+
+
+ {/* Desktop Nav */}
+
+
+ {navLinks.map((link) => (
+
+ {link.label}
+
+ ))}
+
+
+
+ {(['tr', 'en'] as const).map((l) => (
+ switchLocale(l)}
+ className={`text-[11px] font-black uppercase tracking-wider transition-colors ${
+ locale === l
+ ? 'text-coral'
+ : isScrolled
+ ? 'text-midnight/40'
+ : 'text-white/40'
+ }`}
+ >
+ {l}
+
+ ))}
+
+
+
+ {t('reservation')}
+
+
+
+ {/* Mobile toggle */}
+
setIsMobileMenuOpen(!isMobileMenuOpen)}
+ aria-label="Toggle menu"
+ >
+ {isMobileMenuOpen ? (
+
+ ) : (
+
+ )}
+
+
+
+ {/* Mobile menu */}
+
+ {isMobileMenuOpen && (
+
+
+ {navLinks.map((link) => (
+
setIsMobileMenuOpen(false)}
+ >
+ {link.label}
+
+ ))}
+
+
+ {(['tr', 'en'] as const).map((l) => (
+ switchLocale(l)}
+ className={`text-sm font-black uppercase ${locale === l ? 'text-coral' : 'text-midnight/40'}`}
+ >
+ {l}
+
+ ))}
+
+
+
setIsMobileMenuOpen(false)}
+ >
+ {t('reservation')}
+
+
+
+ )}
+
+
+ );
+}
diff --git a/components/WhatsAppButton.tsx b/components/WhatsAppButton.tsx
new file mode 100644
index 0000000..67bc261
--- /dev/null
+++ b/components/WhatsAppButton.tsx
@@ -0,0 +1,21 @@
+"use client";
+
+import { MessageCircle } from 'lucide-react';
+
+export default function WhatsAppButton() {
+ const openWhatsApp = () => {
+ const phone = process.env.NEXT_PUBLIC_WHATSAPP_NUMBER || '905000000000';
+ window.open(`https://wa.me/${phone}`, '_blank');
+ };
+
+ return (
+
+
+
+
+ );
+}
diff --git a/i18n/request.ts b/i18n/request.ts
new file mode 100644
index 0000000..2437de2
--- /dev/null
+++ b/i18n/request.ts
@@ -0,0 +1,16 @@
+import { getRequestConfig } from 'next-intl/server';
+import { notFound } from 'next/navigation';
+import { routing } from './routing';
+
+export default getRequestConfig(async ({ requestLocale }) => {
+ let locale = await requestLocale;
+
+ if (!locale || !routing.locales.includes(locale as any)) {
+ locale = routing.defaultLocale;
+ }
+
+ return {
+ locale,
+ messages: (await import(`../messages/${locale}.json`)).default
+ };
+});
diff --git a/i18n/routing.ts b/i18n/routing.ts
new file mode 100644
index 0000000..12696ed
--- /dev/null
+++ b/i18n/routing.ts
@@ -0,0 +1,10 @@
+import { defineRouting } from 'next-intl/routing';
+import { createNavigation } from 'next-intl/navigation';
+
+export const routing = defineRouting({
+ locales: ['tr', 'en'],
+ defaultLocale: 'tr',
+ localePrefix: 'as-needed'
+});
+
+export const { Link, redirect, usePathname, useRouter } = createNavigation(routing);
diff --git a/messages/en.json b/messages/en.json
new file mode 100644
index 0000000..7468b05
--- /dev/null
+++ b/messages/en.json
@@ -0,0 +1,114 @@
+{
+ "Navbar": {
+ "about": "What is Kozmos?",
+ "accommodation": "Accommodation",
+ "beach": "Beach",
+ "dining": "Dining",
+ "events": "Events",
+ "gallery": "Gallery",
+ "contact": "Contact",
+ "reservation": "Reservation"
+ },
+ "Hero": {
+ "tagline": "Where the Sea Meets the Forest",
+ "cta_reservation": "Make a Reservation",
+ "cta_location": "View Location"
+ },
+ "About": {
+ "title": "What is Kozmos?",
+ "description": "A unique experience in the heart of nature, where the forest meets the sea in a quiet bay of the Gulf of Gökova. Kozmos is a special living space where you can enjoy the sea and sun on the beach during the day, and satisfy your soul with music and entertainment at night.",
+ "card1_title": "Beach & Sea",
+ "card1_desc": "A peaceful day in the cool waters of the Aegean.",
+ "card2_title": "Nature & Serenity",
+ "card2_desc": "The meeting point of the green of the forest and the blue of the sea.",
+ "card3_title": "Music & Nightlife",
+ "card3_desc": "Rhythm and entertainment starting as the sun sets."
+ },
+ "Accommodation": {
+ "title": "Accommodation",
+ "description": "Wake up in our bungalows designed without compromising your comfort, surrounded by nature.",
+ "capacity": "Capacity:",
+ "person": "Person",
+ "price_per_night": "Price per night:",
+ "book_whatsapp": "Book via WhatsApp",
+ "rooms": {
+ "standard": {
+ "name": "Standard Bungalow",
+ "features": ["Nature View", "Air Conditioning", "Mini Bar", "Private Bathroom"]
+ },
+ "sea_view": {
+ "name": "Sea View Bungalow",
+ "features": ["Sea View", "Spacious Patio", "Air Conditioning", "Mini Bar", "Private Bathroom"]
+ },
+ "garden_suite": {
+ "name": "Garden Suite",
+ "features": ["Private Garden", "Spacious Living Area", "Air Conditioning", "Mini Bar", "Private Bathroom"]
+ }
+ }
+ },
+ "Beach": {
+ "title": "Beach & Loungers",
+ "description": "Relax under the shades, facing the turquoise waters. Comfortable loungers and cabanas are available for our daily guests.",
+ "hours": "Working Hours:",
+ "price": "Lounger Fee:",
+ "reservation_info": "Reservations are recommended for daily entry.",
+ "book_lounger": "Book a Lounger"
+ },
+ "Dining": {
+ "title": "Dining",
+ "description": "Crown the freshest flavors of Aegean and Mediterranean cuisine with our signature cocktails on our thatched roof terrace.",
+ "view_menu": "View Menu",
+ "cards": {
+ "seafood": {
+ "title": "Fresh Seafood",
+ "desc": "Daily and local seafood."
+ },
+ "cocktails": {
+ "title": "Signature Cocktails",
+ "desc": "Signature flavors from our award-winning mixologists."
+ },
+ "breakfast": {
+ "title": "Mixed Breakfast",
+ "desc": "A fresh start to the day with natural products."
+ }
+ }
+ },
+ "Events": {
+ "title": "Events",
+ "description": "Entertainment never ends at Kozmos. Catch the rhythm with our weekly events.",
+ "view_calendar": "Event Calendar",
+ "cards": {
+ "raki": {
+ "title": "Thursday Rakı Nights",
+ "time": "Every Thursday, 20:00"
+ },
+ "dj": {
+ "title": "DJ Nights",
+ "time": "Friday & Saturday, 22:00"
+ },
+ "live_music": {
+ "title": "Live Music",
+ "time": "Special Days & Events"
+ }
+ }
+ },
+ "Gallery": {
+ "title": "Gallery",
+ "follow_instagram": "Follow on Instagram"
+ },
+ "Contact": {
+ "title": "Contact & Location",
+ "address": "Akyaka, Gulf of Gökova, Muğla",
+ "form": {
+ "name": "Full Name",
+ "date": "Date",
+ "guests": "Number of Guests",
+ "message": "Message",
+ "submit": "Send via WhatsApp"
+ }
+ },
+ "Footer": {
+ "tagline": "Where the Sea Meets the Forest",
+ "rights": "© 2025 Kozmos Beach & More. All rights reserved."
+ }
+}
diff --git a/messages/tr.json b/messages/tr.json
new file mode 100644
index 0000000..059d353
--- /dev/null
+++ b/messages/tr.json
@@ -0,0 +1,114 @@
+{
+ "Navbar": {
+ "about": "Kozmos Nedir?",
+ "accommodation": "Konaklama",
+ "beach": "Plaj",
+ "dining": "Yeme & İçme",
+ "events": "Etkinlikler",
+ "gallery": "Galeri",
+ "contact": "İletişim",
+ "reservation": "Rezervasyon"
+ },
+ "Hero": {
+ "tagline": "Denizin Ormana Kıyısında",
+ "cta_reservation": "Rezervasyon Yap",
+ "cta_location": "Konumu Gör"
+ },
+ "About": {
+ "title": "Kozmos Nedir?",
+ "description": "Gökova Körfezi'nin sakin bir koyunda, ormanın denizle buluştuğu noktada, doğanın kalbinde eşsiz bir deneyim. Kozmos; gündüz plajda denizin ve güneşin tadını çıkarabileceğiniz, gece ise müzik ve eğlenceyle ruhunuzu doyurabileceğiniz özel bir yaşam alanıdır.",
+ "card1_title": "Plaj & Deniz",
+ "card1_desc": "Ege'nin serin sularında huzurlu bir gün.",
+ "card2_title": "Doğa & Huzur",
+ "card2_desc": "Ormanın yeşiliyle denizin mavisinin buluştuğu nokta.",
+ "card3_title": "Müzik & Gece",
+ "card3_desc": "Güneş batarken başlayan ritim ve eğlence."
+ },
+ "Accommodation": {
+ "title": "Konaklama",
+ "description": "Doğanın içinde, konforunuzdan ödün vermeden tasarlanmış bungalowlarımızda uyanın.",
+ "capacity": "Kapasite:",
+ "person": "Kişi",
+ "price_per_night": "Gecelik Fiyat:",
+ "book_whatsapp": "WhatsApp ile Rezervasyon",
+ "rooms": {
+ "standard": {
+ "name": "Standart Bungalow",
+ "features": ["Doğa Manzaralı", "Klima", "Mini Bar", "Özel Banyo"]
+ },
+ "sea_view": {
+ "name": "Deniz Manzaralı Bungalow",
+ "features": ["Deniz Manzaralı", "Geniş Veranda", "Klima", "Mini Bar", "Özel Banyo"]
+ },
+ "garden_suite": {
+ "name": "Bahçe Suit",
+ "features": ["Özel Bahçe", "Geniş Yaşam Alanı", "Klima", "Mini Bar", "Özel Banyo"]
+ }
+ }
+ },
+ "Beach": {
+ "title": "Plaj & Şezlong",
+ "description": "Turkuaz sulara karşı, gölgeliklerin altında dinlenin. Günübirlik misafirlerimiz için konforlu şezlong ve cabanalarımız mevcuttur.",
+ "hours": "Çalışma Saatleri:",
+ "price": "Şezlong Ücreti:",
+ "reservation_info": "Günübirlik girişler için rezervasyon önerilir.",
+ "book_lounger": "Şezlong Rezervasyonu"
+ },
+ "Dining": {
+ "title": "Yeme & İçme",
+ "description": "Hasır çatılı terasımızda, Ege ve Akdeniz mutfağının en taze lezzetlerini imza kokteyllerimizle taçlandırın.",
+ "view_menu": "Menüyü Gör",
+ "cards": {
+ "seafood": {
+ "title": "Taze Deniz Ürünleri",
+ "desc": "Günlük ve yöresel deniz mahsulleri."
+ },
+ "cocktails": {
+ "title": "Özel Kokteyller",
+ "desc": "Ödüllü miksologlarımızdan imza lezzetler."
+ },
+ "breakfast": {
+ "title": "Serpme Kahvaltı",
+ "desc": "Doğal ürünlerle güne taze bir başlangıç."
+ }
+ }
+ },
+ "Events": {
+ "title": "Etkinlikler",
+ "description": "Kozmos'ta eğlence hiç bitmez. Haftalık etkinliklerimizle ritmi yakalayın.",
+ "view_calendar": "Etkinlik Takvimi",
+ "cards": {
+ "raki": {
+ "title": "Perşembe Rakı Geceleri",
+ "time": "Her Perşembe, 20:00"
+ },
+ "dj": {
+ "title": "DJ Geceleri",
+ "time": "Cuma & Cumartesi, 22:00"
+ },
+ "live_music": {
+ "title": "Canlı Müzik",
+ "time": "Özel Günler & Etkinlikler"
+ }
+ }
+ },
+ "Gallery": {
+ "title": "Galeri",
+ "follow_instagram": "Instagram'da Takip Et"
+ },
+ "Contact": {
+ "title": "İletişim & Konum",
+ "address": "Akyaka, Gökova Körfezi, Muğla",
+ "form": {
+ "name": "Ad Soyad",
+ "date": "Tarih",
+ "guests": "Kişi Sayısı",
+ "message": "Mesaj",
+ "submit": "WhatsApp ile Gönder"
+ }
+ },
+ "Footer": {
+ "tagline": "Denizin Ormana Kıyısında",
+ "rights": "© 2025 Kozmos Beach & More. Tüm hakları saklıdır."
+ }
+}
diff --git a/middleware.ts b/middleware.ts
new file mode 100644
index 0000000..80d7cec
--- /dev/null
+++ b/middleware.ts
@@ -0,0 +1,17 @@
+import createMiddleware from 'next-intl/middleware';
+
+export default createMiddleware({
+ // A list of all locales that are supported
+ locales: ['tr', 'en'],
+
+ // Used when no locale matches
+ defaultLocale: 'tr',
+ localePrefix: 'as-needed'
+});
+
+export const config = {
+ // Match all pathnames except for
+ // - … if they start with `/api`, `/_next` or `/_vercel`
+ // - … the ones containing a dot (e.g. `favicon.ico`)
+ matcher: ['/((?!api|_next|_vercel|.*\\..*).*)']
+};
diff --git a/next.config.ts b/next.config.ts
index e9ffa30..e0f3746 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -1,7 +1,17 @@
import type { NextConfig } from "next";
+import createNextIntlPlugin from "next-intl/plugin";
+
+const withNextIntl = createNextIntlPlugin();
const nextConfig: NextConfig = {
- /* config options here */
+ images: {
+ remotePatterns: [
+ {
+ protocol: 'https',
+ hostname: 'picsum.photos',
+ },
+ ],
+ },
};
-export default nextConfig;
+export default withNextIntl(nextConfig);
diff --git a/package-lock.json b/package-lock.json
index 259609d..53c3fda 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,9 +8,14 @@
"name": "kozmosweb",
"version": "0.1.0",
"dependencies": {
+ "clsx": "^2.1.1",
+ "framer-motion": "^12.40.0",
+ "lucide-react": "^1.17.0",
"next": "16.2.7",
+ "next-intl": "^4.13.0",
"react": "19.2.4",
- "react-dom": "19.2.4"
+ "react-dom": "19.2.4",
+ "tailwind-merge": "^3.6.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
@@ -453,6 +458,36 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
+ "node_modules/@formatjs/fast-memoize": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-3.1.5.tgz",
+ "integrity": "sha512-KLi3fan6WnCHmigd9pmEEN8Hid0v4wiFBW576M/d07KMWYecf1CvyMI3n34vCmHT4AoVqG2n702kiHbXjzZX2A==",
+ "license": "MIT"
+ },
+ "node_modules/@formatjs/icu-messageformat-parser": {
+ "version": "3.5.10",
+ "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-3.5.10.tgz",
+ "integrity": "sha512-XeJihYLy1lCe19xfK1KWKG/betBOK2rB0luL8lSkjfvJj0zP+LTJvkC+RKd0jsFI8mWxN71LrarHSrEXE8xxOQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@formatjs/icu-skeleton-parser": "2.1.9"
+ }
+ },
+ "node_modules/@formatjs/icu-skeleton-parser": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-2.1.9.tgz",
+ "integrity": "sha512-rsxswgHMfU1zUgB2byc08fesf83wLGjFnzLCEtuf00mx2doiqc6pYrf67raI37XqdRcGUviQepk2UKGqpng74Q==",
+ "license": "MIT"
+ },
+ "node_modules/@formatjs/intl-localematcher": {
+ "version": "0.8.9",
+ "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.8.9.tgz",
+ "integrity": "sha512-GmB0F/gYh4Hdl4rLWjgDsgT+x4pB54fkJeRh8kAZ4XFzKeCK8dGs+SBJWXO42QZtOUni+IDWKNuCw6wiL4lTvw==",
+ "license": "MIT",
+ "dependencies": {
+ "@formatjs/fast-memoize": "3.1.5"
+ }
+ },
"node_modules/@humanfs/core": {
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
@@ -1306,6 +1341,331 @@
"node": ">=12.4.0"
}
},
+ "node_modules/@parcel/watcher": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz",
+ "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "detect-libc": "^2.0.3",
+ "is-glob": "^4.0.3",
+ "node-addon-api": "^7.0.0",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "@parcel/watcher-android-arm64": "2.5.6",
+ "@parcel/watcher-darwin-arm64": "2.5.6",
+ "@parcel/watcher-darwin-x64": "2.5.6",
+ "@parcel/watcher-freebsd-x64": "2.5.6",
+ "@parcel/watcher-linux-arm-glibc": "2.5.6",
+ "@parcel/watcher-linux-arm-musl": "2.5.6",
+ "@parcel/watcher-linux-arm64-glibc": "2.5.6",
+ "@parcel/watcher-linux-arm64-musl": "2.5.6",
+ "@parcel/watcher-linux-x64-glibc": "2.5.6",
+ "@parcel/watcher-linux-x64-musl": "2.5.6",
+ "@parcel/watcher-win32-arm64": "2.5.6",
+ "@parcel/watcher-win32-ia32": "2.5.6",
+ "@parcel/watcher-win32-x64": "2.5.6"
+ }
+ },
+ "node_modules/@parcel/watcher-android-arm64": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz",
+ "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-darwin-arm64": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz",
+ "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-darwin-x64": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz",
+ "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-freebsd-x64": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz",
+ "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm-glibc": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz",
+ "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==",
+ "cpu": [
+ "arm"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm-musl": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz",
+ "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==",
+ "cpu": [
+ "arm"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm64-glibc": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz",
+ "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm64-musl": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz",
+ "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-x64-glibc": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz",
+ "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-x64-musl": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz",
+ "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-arm64": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz",
+ "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-ia32": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz",
+ "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-x64": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz",
+ "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher/node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
"node_modules/@rtsao/scc": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
@@ -1313,6 +1673,228 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@schummar/icu-type-parser": {
+ "version": "1.21.5",
+ "resolved": "https://registry.npmjs.org/@schummar/icu-type-parser/-/icu-type-parser-1.21.5.tgz",
+ "integrity": "sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw==",
+ "license": "MIT"
+ },
+ "node_modules/@swc/core-darwin-arm64": {
+ "version": "1.15.40",
+ "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.40.tgz",
+ "integrity": "sha512-PaYyclfmQ++77D8ityYvmmVzHv9aG8ROwt2GfG6/ccloy4Hgf80qtOnzb9VYvPsUT7Ty1uhuDRhv3XYpf62qhQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-darwin-x64": {
+ "version": "1.15.40",
+ "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.40.tgz",
+ "integrity": "sha512-HbbPzvfLBUXjIB1Ezks+//lNUjmLjfyd63XSwprJgrZaXYdm70kohXPJUWdqKZozolFxbPaO+xtBaiUp6BoueA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-arm-gnueabihf": {
+ "version": "1.15.40",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.40.tgz",
+ "integrity": "sha512-SlRZsCjOCPR2LvFs0Ri/Xrx/5o5TCt8vl4gW6mX1hEZOG0a625RxzRHpHdAQNGykmAN/7IeaFAJG+QnNmxlHcA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-arm64-gnu": {
+ "version": "1.15.40",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.40.tgz",
+ "integrity": "sha512-Q8byxJt2fh8CR3EUX6snBpy47AoBVm+In/+Z3rjDHMjC38ZvR9/gtUUNCT0tfrn4EdVsO8/QPi59nxrxvqxvBQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-arm64-musl": {
+ "version": "1.15.40",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.40.tgz",
+ "integrity": "sha512-4z0MgHU+7M0pZDqBN1El7mFXDI1SBwinfcUkAyA4v8QrhOIUOZltySt2aStQLZGrdXVXM4Y4ylfiTC04ED+MoQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-ppc64-gnu": {
+ "version": "1.15.40",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.40.tgz",
+ "integrity": "sha512-fLI4iUgeSZu0eRWUXwe6YzPFx9gHbFiPkl8Rp3mJfP8OpNR3nTQCGPvHdDh9xniW7mVvgMY4ni7A4VzqI1KrpA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-s390x-gnu": {
+ "version": "1.15.40",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.40.tgz",
+ "integrity": "sha512-YqeKMAb7d4nQSGMJQ454IlaCENpzcDqhvBE9+CPfdnYpnUXxd+BSrB6Xk0YjW8UyoEhUj4p6quATCxbsp6J3jg==",
+ "cpu": [
+ "s390x"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-x64-gnu": {
+ "version": "1.15.40",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.40.tgz",
+ "integrity": "sha512-7HOuS1iGcme/j/TuL1TfmmLGiMQrjv/GmjyZeydl00FKPtpGXEldwqfI56xgd1YzrzoB2svWjxbGGyQ0TEASxg==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-x64-musl": {
+ "version": "1.15.40",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.40.tgz",
+ "integrity": "sha512-h4kZYHc7dpc9P9u4brRJaS8Pl7tPVHAeiLSzw7T5RfIJgAoSdaCMKzI/2Uay9gFhaw8uyCDl0L5q37r0EpAfIA==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-win32-arm64-msvc": {
+ "version": "1.15.40",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.40.tgz",
+ "integrity": "sha512-+mQgKZXSj6mV38Zh05QaxSjUDmGP/R2JWlXZTDLSPkDzHU6p3GxN9eeSf5dfyDVU86946fmCvSzyl/ucImx8+A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-win32-ia32-msvc": {
+ "version": "1.15.40",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.40.tgz",
+ "integrity": "sha512-yvwdPLGd25mcj/mNatjNQ0lZujtQD6psH3v9PNmMb+fSzjbNG8KIDxjFWrcV+fsFVLOkyOmdJsFmX7NAFjVyPw==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-win32-x64-msvc": {
+ "version": "1.15.40",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.40.tgz",
+ "integrity": "sha512-OXtKsLU1bVtInzzDEAY2sYiF/rl4tvAnLLLpuMp3HzAOQZ5A+i69AKDhA1YLQTaMAqO3vzyYNVAYVRMPtSYD4w==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/counter": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
+ "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
+ "license": "Apache-2.0"
+ },
"node_modules/@swc/helpers": {
"version": "0.5.15",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
@@ -1322,6 +1904,15 @@
"tslib": "^2.8.0"
}
},
+ "node_modules/@swc/types": {
+ "version": "0.1.26",
+ "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.26.tgz",
+ "integrity": "sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@swc/counter": "^0.1.3"
+ }
+ },
"node_modules/@tailwindcss/node": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz",
@@ -2771,6 +3362,15 @@
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
"license": "MIT"
},
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -2953,7 +3553,6 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
- "devOptional": true,
"license": "Apache-2.0",
"engines": {
"node": ">=8"
@@ -3762,6 +4361,33 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/framer-motion": {
+ "version": "12.40.0",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.40.0.tgz",
+ "integrity": "sha512-uaBd3qC1v3KQqBEjwTUd183K6PbS+j0yR9w9VmEOLWA/tnUcSn8Xa3uck7t4dgpDoUss8xQTcj8W2L07lrnLFg==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-dom": "^12.40.0",
+ "motion-utils": "^12.39.0",
+ "tslib": "^2.4.0"
+ },
+ "peerDependencies": {
+ "@emotion/is-prop-valid": "*",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/is-prop-valid": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -4067,6 +4693,21 @@
"hermes-estree": "0.25.1"
}
},
+ "node_modules/icu-minify": {
+ "version": "4.13.0",
+ "resolved": "https://registry.npmjs.org/icu-minify/-/icu-minify-4.13.0.tgz",
+ "integrity": "sha512-SIFMeUHZJjzS5RvIGvybKvWoHjDm9cGVEs2EpJ8PmywOdJLWyblPm7TdPLLoUtkJtwQD7iGhl2WMptZ+N0on+w==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/amannn"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@formatjs/icu-messageformat-parser": "^3.4.0"
+ }
+ },
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -4119,6 +4760,16 @@
"node": ">= 0.4"
}
},
+ "node_modules/intl-messageformat": {
+ "version": "11.2.7",
+ "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-11.2.7.tgz",
+ "integrity": "sha512-+q6Ktg119nULZEpZ8YTuGOst9MyEzFtjD63FTGBlN1mLz0Z/MOUYDIvnpVKwq17eezIEh+cfJIebfJoCetpiNw==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@formatjs/fast-memoize": "3.1.5",
+ "@formatjs/icu-messageformat-parser": "3.5.10"
+ }
+ },
"node_modules/is-array-buffer": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
@@ -4281,7 +4932,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -4327,7 +4977,6 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
@@ -5032,6 +5681,15 @@
"yallist": "^3.0.2"
}
},
+ "node_modules/lucide-react": {
+ "version": "1.17.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.17.0.tgz",
+ "integrity": "sha512-9FA9evdox/JQL5PT57fdA1x/yg8T7knJ98+zjTL3UfKza6pflQUUh3XtaQIHKvnsJw1lmsEyHVlt5jchYxOQ5w==",
+ "license": "ISC",
+ "peerDependencies": {
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
@@ -5099,6 +5757,21 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/motion-dom": {
+ "version": "12.40.0",
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.40.0.tgz",
+ "integrity": "sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-utils": "^12.39.0"
+ }
+ },
+ "node_modules/motion-utils": {
+ "version": "12.39.0",
+ "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.39.0.tgz",
+ "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==",
+ "license": "MIT"
+ },
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -5147,6 +5820,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/negotiator": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
+ "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/next": {
"version": "16.2.7",
"resolved": "https://registry.npmjs.org/next/-/next-16.2.7.tgz",
@@ -5200,6 +5882,83 @@
}
}
},
+ "node_modules/next-intl": {
+ "version": "4.13.0",
+ "resolved": "https://registry.npmjs.org/next-intl/-/next-intl-4.13.0.tgz",
+ "integrity": "sha512-OvNq2v5XLx4EkQOsAhVE9g+6zdb83XHusADCXXtIW4LILYnjEVaeINdr1lkVWKSjzwNUiMSlH5N4K0OQTRiv6A==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/amannn"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@formatjs/intl-localematcher": "^0.8.1",
+ "@parcel/watcher": "^2.4.1",
+ "@swc/core": "^1.15.2",
+ "icu-minify": "^4.13.0",
+ "negotiator": "^1.0.0",
+ "next-intl-swc-plugin-extractor": "^4.13.0",
+ "po-parser": "^2.1.1",
+ "use-intl": "^4.13.0"
+ },
+ "peerDependencies": {
+ "next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/next-intl-swc-plugin-extractor": {
+ "version": "4.13.0",
+ "resolved": "https://registry.npmjs.org/next-intl-swc-plugin-extractor/-/next-intl-swc-plugin-extractor-4.13.0.tgz",
+ "integrity": "sha512-6S/fJI0KXvLCL8nhBo9P8eGaJPzmwJBTCzX0NaUIj0VyU8U89d//T+vjMLdNIXl5MlLaYH7B9MbAjb8Mvu+tqQ==",
+ "license": "MIT"
+ },
+ "node_modules/next-intl/node_modules/@swc/core": {
+ "version": "1.15.40",
+ "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.40.tgz",
+ "integrity": "sha512-2kwzJikRvgtNAG7MwVZY2vEzZjTxKIq5jXOihuSV/8U+Hej8Va22t65aKnJZs3P+NwojZvR8Mf8kyM7O+V8sQg==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@swc/counter": "^0.1.3",
+ "@swc/types": "^0.1.26"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/swc"
+ },
+ "optionalDependencies": {
+ "@swc/core-darwin-arm64": "1.15.40",
+ "@swc/core-darwin-x64": "1.15.40",
+ "@swc/core-linux-arm-gnueabihf": "1.15.40",
+ "@swc/core-linux-arm64-gnu": "1.15.40",
+ "@swc/core-linux-arm64-musl": "1.15.40",
+ "@swc/core-linux-ppc64-gnu": "1.15.40",
+ "@swc/core-linux-s390x-gnu": "1.15.40",
+ "@swc/core-linux-x64-gnu": "1.15.40",
+ "@swc/core-linux-x64-musl": "1.15.40",
+ "@swc/core-win32-arm64-msvc": "1.15.40",
+ "@swc/core-win32-ia32-msvc": "1.15.40",
+ "@swc/core-win32-x64-msvc": "1.15.40"
+ },
+ "peerDependencies": {
+ "@swc/helpers": ">=0.5.17"
+ },
+ "peerDependenciesMeta": {
+ "@swc/helpers": {
+ "optional": true
+ }
+ }
+ },
"node_modules/next/node_modules/postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
@@ -5228,6 +5987,12 @@
"node": "^10 || ^12 || >=14"
}
},
+ "node_modules/node-addon-api": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
+ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+ "license": "MIT"
+ },
"node_modules/node-exports-info": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz",
@@ -5507,6 +6272,12 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/po-parser": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/po-parser/-/po-parser-2.1.1.tgz",
+ "integrity": "sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==",
+ "license": "MIT"
+ },
"node_modules/possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
@@ -6242,6 +7013,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/tailwind-merge": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz",
+ "integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/dcastil"
+ }
+ },
"node_modules/tailwindcss": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz",
@@ -6603,6 +7384,27 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/use-intl": {
+ "version": "4.13.0",
+ "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-4.13.0.tgz",
+ "integrity": "sha512-fAFDrWaASxlhXOipcOyb5VDD+YONqj6+8O8EcG/J7RBoOUF3A8YahRWLN+mBxYMrlMQB8N6Voqk5X+YC+HSL0A==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/amannn"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@formatjs/fast-memoize": "^3.1.0",
+ "@schummar/icu-type-parser": "1.21.5",
+ "icu-minify": "^4.13.0",
+ "intl-messageformat": "^11.1.0"
+ },
+ "peerDependencies": {
+ "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
diff --git a/package.json b/package.json
index 38b4b9f..433107d 100644
--- a/package.json
+++ b/package.json
@@ -9,9 +9,14 @@
"lint": "eslint"
},
"dependencies": {
+ "clsx": "^2.1.1",
+ "framer-motion": "^12.40.0",
+ "lucide-react": "^1.17.0",
"next": "16.2.7",
+ "next-intl": "^4.13.0",
"react": "19.2.4",
- "react-dom": "19.2.4"
+ "react-dom": "19.2.4",
+ "tailwind-merge": "^3.6.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",