first commit
This commit is contained in:
@@ -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
|
## Getting Started
|
||||||
|
|
||||||
First, run the development server:
|
1. **Install dependencies:**
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
```bash
|
2. **Run the development server:**
|
||||||
npm run dev
|
```bash
|
||||||
# or
|
npm run dev
|
||||||
yarn dev
|
```
|
||||||
# or
|
|
||||||
pnpm dev
|
|
||||||
# or
|
|
||||||
bun 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:
|
*Created by [ayris.tech](https://ayris.tech)*
|
||||||
|
|
||||||
- [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.
|
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
<main className="min-h-screen bg-sand selection:bg-coral selection:text-white flex flex-col">
|
||||||
|
<Navbar locale={locale} />
|
||||||
|
{/* Spacer to push content below fixed navbar */}
|
||||||
|
<div className="flex-grow pt-24">
|
||||||
|
<Accommodation />
|
||||||
|
</div>
|
||||||
|
<Footer />
|
||||||
|
<WhatsAppButton />
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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 (
|
||||||
|
<html lang={locale} data-scroll-behavior="smooth" className={`${marcellus.variable}`}>
|
||||||
|
<body className="bg-sand text-midnight font-body antialiased relative">
|
||||||
|
<NextIntlClientProvider messages={messages}>
|
||||||
|
{children}
|
||||||
|
</NextIntlClientProvider>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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 (
|
||||||
|
<main className="min-h-screen bg-cream selection:bg-turquoise selection:text-white">
|
||||||
|
<Navbar locale={locale} />
|
||||||
|
<Hero />
|
||||||
|
<About />
|
||||||
|
<Accommodation />
|
||||||
|
<Beach />
|
||||||
|
<Dining />
|
||||||
|
<Events />
|
||||||
|
<Gallery />
|
||||||
|
<Contact />
|
||||||
|
<Footer />
|
||||||
|
<WhatsAppButton />
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
+148
-17
@@ -1,26 +1,157 @@
|
|||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
|
|
||||||
:root {
|
@theme {
|
||||||
--background: #ffffff;
|
--color-sand: #FFF8EE;
|
||||||
--foreground: #171717;
|
--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 {
|
@layer base {
|
||||||
--color-background: var(--background);
|
body {
|
||||||
--color-foreground: var(--foreground);
|
@apply bg-sand text-midnight font-body antialiased;
|
||||||
--font-sans: var(--font-geist-sans);
|
}
|
||||||
--font-mono: var(--font-geist-mono);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
h1, h2, h3, h4, h5, h6 {
|
||||||
:root {
|
@apply font-heading;
|
||||||
--background: #0a0a0a;
|
|
||||||
--foreground: #ededed;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
html {
|
||||||
background: var(--background);
|
scroll-behavior: smooth;
|
||||||
color: var(--foreground);
|
}
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
|
/* ── CSS custom property for animated border ──── */
|
||||||
|
@property --border-angle {
|
||||||
|
syntax: '<angle>';
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 (
|
|
||||||
<html
|
|
||||||
lang="en"
|
|
||||||
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
|
|
||||||
>
|
|
||||||
<body className="min-h-full flex flex-col">{children}</body>
|
|
||||||
</html>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -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',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
import Image from "next/image";
|
|
||||||
|
|
||||||
export default function Home() {
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col flex-1 items-center justify-center bg-zinc-50 font-sans dark:bg-black">
|
|
||||||
<main className="flex flex-1 w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
|
|
||||||
<Image
|
|
||||||
className="dark:invert"
|
|
||||||
src="/next.svg"
|
|
||||||
alt="Next.js logo"
|
|
||||||
width={100}
|
|
||||||
height={20}
|
|
||||||
priority
|
|
||||||
/>
|
|
||||||
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
|
|
||||||
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
|
|
||||||
To get started, edit the page.tsx file.
|
|
||||||
</h1>
|
|
||||||
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
|
|
||||||
Looking for a starting point or more instructions? Head over to{" "}
|
|
||||||
<a
|
|
||||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
className="font-medium text-zinc-950 dark:text-zinc-50"
|
|
||||||
>
|
|
||||||
Templates
|
|
||||||
</a>{" "}
|
|
||||||
or the{" "}
|
|
||||||
<a
|
|
||||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
className="font-medium text-zinc-950 dark:text-zinc-50"
|
|
||||||
>
|
|
||||||
Learning
|
|
||||||
</a>{" "}
|
|
||||||
center.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
|
|
||||||
<a
|
|
||||||
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
|
|
||||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
className="dark:invert"
|
|
||||||
src="/vercel.svg"
|
|
||||||
alt="Vercel logomark"
|
|
||||||
width={16}
|
|
||||||
height={16}
|
|
||||||
/>
|
|
||||||
Deploy Now
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
|
|
||||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
Documentation
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { MetadataRoute } from 'next';
|
||||||
|
|
||||||
|
export default function robots(): MetadataRoute.Robots {
|
||||||
|
return {
|
||||||
|
rules: {
|
||||||
|
userAgent: '*',
|
||||||
|
allow: '/',
|
||||||
|
},
|
||||||
|
sitemap: 'https://kozmosbeach.com/sitemap.xml',
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -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 (
|
||||||
|
<section id="about" className="py-28 bg-sand text-midnight relative">
|
||||||
|
<div className="container mx-auto px-6 lg:px-12">
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-20 items-center">
|
||||||
|
|
||||||
|
{/* Left content */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: -30 }}
|
||||||
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.8 }}
|
||||||
|
className="space-y-8"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<span className="text-xs tracking-[0.4em] uppercase font-black text-coral mb-4 block">
|
||||||
|
— Beach & More
|
||||||
|
</span>
|
||||||
|
<h2 className="font-heading text-5xl md:text-6xl font-black leading-tight text-midnight mb-6">
|
||||||
|
{t('title')}
|
||||||
|
</h2>
|
||||||
|
<p className="text-lg leading-relaxed text-midnight/60">{t('description')}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
{features.map(({ icon: Icon, titleKey, descKey, color, bg }, i) => (
|
||||||
|
<motion.div
|
||||||
|
key={titleKey}
|
||||||
|
initial={{ opacity: 0, x: -20 }}
|
||||||
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: i * 0.1 + 0.2 }}
|
||||||
|
className="flex items-start gap-4 p-4 rounded-2xl hover:bg-sandy/50 transition-colors"
|
||||||
|
>
|
||||||
|
<div className={`p-3 rounded-xl ${bg} ${color} flex-shrink-0`}>
|
||||||
|
<Icon size={20} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="font-heading text-lg font-bold mb-0.5">{t(titleKey)}</h3>
|
||||||
|
<p className="text-midnight/55 text-sm leading-relaxed">{t(descKey)}</p>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* Right image */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, scale: 0.95 }}
|
||||||
|
whileInView={{ opacity: 1, scale: 1 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.8 }}
|
||||||
|
className="relative"
|
||||||
|
>
|
||||||
|
{/* Glow ring */}
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 rounded-3xl opacity-30 blur-2xl scale-105"
|
||||||
|
style={{ background: 'linear-gradient(135deg, #FF5A36, #FFA827, #00BFA5)' }}
|
||||||
|
/>
|
||||||
|
<div className="relative h-[560px] w-full rounded-3xl overflow-hidden shadow-2xl">
|
||||||
|
<Image
|
||||||
|
src="https://picsum.photos/800/1100?random=2"
|
||||||
|
alt="Kozmos atmosferi"
|
||||||
|
fill
|
||||||
|
sizes="(max-width: 1024px) 100vw, 50vw"
|
||||||
|
className="object-cover"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="absolute inset-0"
|
||||||
|
style={{ background: 'linear-gradient(to top, rgba(8,13,24,0.35) 0%, transparent 55%)' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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 (
|
||||||
|
<section id="accommodation" className="py-28 bg-sandy/25 text-midnight">
|
||||||
|
<div className="container mx-auto px-6 lg:px-12">
|
||||||
|
|
||||||
|
<div className="text-center max-w-3xl mx-auto mb-16">
|
||||||
|
<motion.span
|
||||||
|
initial={{ opacity: 0, y: 10 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
className="text-xs tracking-[0.4em] uppercase font-black text-coral mb-4 block"
|
||||||
|
>
|
||||||
|
— Konaklama
|
||||||
|
</motion.span>
|
||||||
|
<motion.h2
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
className="font-heading text-5xl md:text-6xl font-black mb-6 text-midnight"
|
||||||
|
>
|
||||||
|
{t('title')}
|
||||||
|
</motion.h2>
|
||||||
|
<motion.p
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: 0.1 }}
|
||||||
|
className="text-lg text-midnight/60"
|
||||||
|
>
|
||||||
|
{t('description')}
|
||||||
|
</motion.p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
{rooms.map((room, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={room.id}
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: index * 0.1, duration: 0.6 }}
|
||||||
|
className={`relative rounded-3xl overflow-hidden bg-white shadow-lg hover:shadow-2xl transition-all duration-500 hover:-translate-y-1 ${
|
||||||
|
room.featured ? 'outline outline-2 outline-offset-2 outline-coral' : ''
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{/* Featured badge */}
|
||||||
|
{room.featured && (
|
||||||
|
<div
|
||||||
|
className="absolute top-4 right-4 z-10 flex items-center gap-1.5 px-3 py-1.5 rounded-full text-[11px] font-black text-white tracking-wider"
|
||||||
|
style={{ background: 'linear-gradient(135deg, #FF5A36, #FFA827)' }}
|
||||||
|
>
|
||||||
|
<Sparkles size={10} />
|
||||||
|
FEATURED
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Image */}
|
||||||
|
<div className="relative h-52 w-full overflow-hidden">
|
||||||
|
<Image
|
||||||
|
src={room.image}
|
||||||
|
alt={t(`rooms.${room.id}.name`)}
|
||||||
|
fill
|
||||||
|
sizes="(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 33vw"
|
||||||
|
className="object-cover transition-transform duration-700 hover:scale-110"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="absolute inset-0"
|
||||||
|
style={{ background: 'linear-gradient(to top, rgba(8,13,24,0.5), transparent)' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Content */}
|
||||||
|
<div className="p-7">
|
||||||
|
<h3 className="font-heading text-xl font-black mb-2 text-midnight">
|
||||||
|
{t(`rooms.${room.id}.name`)}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-2 text-midnight/45 mb-5 text-sm">
|
||||||
|
<Users size={14} />
|
||||||
|
<span>
|
||||||
|
{t('capacity')} {room.capacity} {t('person')}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul className="space-y-2 mb-7">
|
||||||
|
{room.features.map((feature, i) => (
|
||||||
|
<li key={i} className="flex items-center gap-2.5 text-sm text-midnight/65">
|
||||||
|
<Check size={13} className="text-aqua flex-shrink-0" />
|
||||||
|
<span>{feature}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={openWhatsApp}
|
||||||
|
className="w-full py-3.5 rounded-2xl font-black text-sm text-white transition-all duration-300 hover:opacity-90 hover:scale-[1.02]"
|
||||||
|
style={{ background: room.gradient }}
|
||||||
|
>
|
||||||
|
{t('book_whatsapp')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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 (
|
||||||
|
<section id="beach" className="pt-28 pb-36 bg-sand text-midnight relative overflow-hidden">
|
||||||
|
<div className="container mx-auto px-6 lg:px-12">
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 items-center">
|
||||||
|
|
||||||
|
{/* Left masonry photos */}
|
||||||
|
<div className="grid grid-cols-2 gap-3">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
className="space-y-3"
|
||||||
|
>
|
||||||
|
<div className="relative h-64 rounded-2xl overflow-hidden shadow-md">
|
||||||
|
<Image
|
||||||
|
src="https://picsum.photos/400/600?random=10"
|
||||||
|
alt="Plaj"
|
||||||
|
fill
|
||||||
|
sizes="(max-width: 1024px) 50vw, 25vw"
|
||||||
|
className="object-cover hover:scale-105 transition-transform duration-700"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="relative h-48 rounded-2xl overflow-hidden shadow-md">
|
||||||
|
<Image
|
||||||
|
src="https://picsum.photos/400/400?random=11"
|
||||||
|
alt="Şezlong"
|
||||||
|
fill
|
||||||
|
sizes="(max-width: 1024px) 50vw, 25vw"
|
||||||
|
className="object-cover hover:scale-105 transition-transform duration-700"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 40 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: 0.15 }}
|
||||||
|
className="space-y-3 pt-8"
|
||||||
|
>
|
||||||
|
<div className="relative h-48 rounded-2xl overflow-hidden shadow-md">
|
||||||
|
<Image
|
||||||
|
src="https://picsum.photos/400/400?random=12"
|
||||||
|
alt="Deniz"
|
||||||
|
fill
|
||||||
|
sizes="(max-width: 1024px) 50vw, 25vw"
|
||||||
|
className="object-cover hover:scale-105 transition-transform duration-700"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="relative h-64 rounded-2xl overflow-hidden shadow-md">
|
||||||
|
<Image
|
||||||
|
src="https://picsum.photos/400/600?random=13"
|
||||||
|
alt="Koy"
|
||||||
|
fill
|
||||||
|
sizes="(max-width: 1024px) 50vw, 25vw"
|
||||||
|
className="object-cover hover:scale-105 transition-transform duration-700"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Right content */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: 30 }}
|
||||||
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.7 }}
|
||||||
|
className="space-y-7"
|
||||||
|
>
|
||||||
|
<div className="inline-flex items-center gap-2 font-black text-amber tracking-wider uppercase text-sm">
|
||||||
|
<Sun size={18} />
|
||||||
|
Beach Club
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 className="font-heading text-5xl md:text-6xl font-black text-midnight leading-tight">
|
||||||
|
{t('title')}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<p className="text-lg text-midnight/60 leading-relaxed">{t('description')}</p>
|
||||||
|
|
||||||
|
{/* Stats */}
|
||||||
|
<div className="grid grid-cols-3 gap-4 py-6 border-y border-sandy">
|
||||||
|
{stats.map(({ value, label }) => (
|
||||||
|
<div key={label} className="text-center">
|
||||||
|
<div className="font-heading text-2xl font-black gradient-text-warm">{value}</div>
|
||||||
|
<div className="text-[11px] text-midnight/45 mt-1 uppercase tracking-wider">{label}</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Info & CTA */}
|
||||||
|
<div className="p-6 rounded-2xl bg-sandy/50 border border-sandy">
|
||||||
|
<p className="text-midnight/70 text-sm font-medium mb-5">{t('reservation_info')}</p>
|
||||||
|
<button
|
||||||
|
onClick={openWhatsApp}
|
||||||
|
className="px-8 py-3.5 rounded-full font-black text-sm text-midnight transition-all duration-300 hover:scale-105 hover:shadow-lg"
|
||||||
|
style={{ background: 'linear-gradient(135deg, #FFA827, #FFD166)' }}
|
||||||
|
>
|
||||||
|
{t('book_lounger')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Wave → midnight */}
|
||||||
|
<div className="absolute bottom-0 left-0 w-full leading-none pointer-events-none">
|
||||||
|
<svg viewBox="0 0 1440 64" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" className="w-full h-16">
|
||||||
|
<path d="M0,32 C240,64 480,0 720,32 C960,64 1200,0 1440,32 L1440,64 L0,64 Z" fill="#080D18" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||||
|
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 (
|
||||||
|
<section id="contact" className="py-28 bg-sandy/25 text-midnight">
|
||||||
|
<div className="container mx-auto px-6 lg:px-12">
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
className="text-center mb-16"
|
||||||
|
>
|
||||||
|
<span className="text-xs tracking-[0.4em] uppercase font-black text-coral mb-4 block">
|
||||||
|
— Bize Ulaşın
|
||||||
|
</span>
|
||||||
|
<h2 className="font-heading text-5xl md:text-6xl font-black text-midnight">
|
||||||
|
{t('title')}
|
||||||
|
</h2>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16">
|
||||||
|
|
||||||
|
{/* Left: info + form */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: -30 }}
|
||||||
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
className="space-y-8"
|
||||||
|
>
|
||||||
|
{/* Contact info */}
|
||||||
|
<div className="space-y-5">
|
||||||
|
{contactItems.map(({ Icon, label, value, href, color, bg }) => (
|
||||||
|
<div key={label} className="flex items-start gap-4">
|
||||||
|
<div className={`p-3 rounded-xl ${bg} ${color} flex-shrink-0`}>
|
||||||
|
<Icon size={19} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="font-bold text-sm text-midnight/50 mb-0.5">{label}</p>
|
||||||
|
{href ? (
|
||||||
|
<a
|
||||||
|
href={href}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className={`${color} font-medium hover:underline`}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<p className="text-midnight font-medium">{value}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Form */}
|
||||||
|
<form
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
className="bg-white p-8 rounded-3xl shadow-sm border border-sandy space-y-5"
|
||||||
|
>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<label className="text-[11px] font-black uppercase tracking-wider text-midnight/45">
|
||||||
|
{t('form.name')}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
required
|
||||||
|
type="text"
|
||||||
|
name="name"
|
||||||
|
value={formData.name}
|
||||||
|
onChange={handleChange}
|
||||||
|
className={inputClass}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<label className="text-[11px] font-black uppercase tracking-wider text-midnight/45">
|
||||||
|
{t('form.date')}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
required
|
||||||
|
type="date"
|
||||||
|
name="date"
|
||||||
|
value={formData.date}
|
||||||
|
onChange={handleChange}
|
||||||
|
className={inputClass}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<label className="text-[11px] font-black uppercase tracking-wider text-midnight/45">
|
||||||
|
{t('form.guests')}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
required
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
name="guests"
|
||||||
|
value={formData.guests}
|
||||||
|
onChange={handleChange}
|
||||||
|
className={inputClass}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<label className="text-[11px] font-black uppercase tracking-wider text-midnight/45">
|
||||||
|
{t('form.message')}
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
rows={3}
|
||||||
|
name="message"
|
||||||
|
value={formData.message}
|
||||||
|
onChange={handleChange}
|
||||||
|
className={inputClass + ' resize-none'}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="w-full py-4 rounded-2xl font-black text-sm text-white flex items-center justify-center gap-2 hover:opacity-90 hover:scale-[1.01] transition-all shadow-md"
|
||||||
|
style={{ background: 'linear-gradient(135deg, #FF5A36, #FFA827)' }}
|
||||||
|
>
|
||||||
|
<Send size={15} />
|
||||||
|
{t('form.submit')}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* Right: map */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: 30 }}
|
||||||
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
className="min-h-[420px] lg:min-h-[600px] w-full rounded-3xl overflow-hidden shadow-2xl"
|
||||||
|
>
|
||||||
|
<iframe
|
||||||
|
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d12754.717654763133!2d28.3144!3d36.9507!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x14bf76ccf312ba37%3A0xcdaaa97b102b4bb7!2sAkyaka%2C%20Ula%2FMu%C4%9Fla!5e0!3m2!1str!2str!4v1700000000000!5m2!1str!2str"
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
style={{ border: 0 }}
|
||||||
|
allowFullScreen
|
||||||
|
loading="lazy"
|
||||||
|
referrerPolicy="no-referrer-when-downgrade"
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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 (
|
||||||
|
<section
|
||||||
|
id="dining"
|
||||||
|
className="pt-20 pb-28 text-white relative overflow-hidden"
|
||||||
|
style={{ background: '#080D18' }}
|
||||||
|
>
|
||||||
|
{/* Background blobs */}
|
||||||
|
<div className="absolute inset-0 overflow-hidden pointer-events-none">
|
||||||
|
<div
|
||||||
|
className="absolute bottom-0 left-1/4 w-[500px] h-[500px] rounded-full opacity-20"
|
||||||
|
style={{ background: 'radial-gradient(circle, #FF5A36 0%, transparent 70%)' }}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="absolute top-0 right-1/4 w-[400px] h-[400px] rounded-full opacity-15"
|
||||||
|
style={{ background: 'radial-gradient(circle, #00BFA5 0%, transparent 70%)' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="container mx-auto px-6 lg:px-12 relative z-10">
|
||||||
|
<div className="text-center max-w-3xl mx-auto mb-16">
|
||||||
|
<motion.span
|
||||||
|
initial={{ opacity: 0, y: 10 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
className="text-xs tracking-[0.4em] uppercase font-black text-amber mb-4 block"
|
||||||
|
>
|
||||||
|
— Yeme & İçme
|
||||||
|
</motion.span>
|
||||||
|
|
||||||
|
<motion.h2
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
className="font-heading text-5xl md:text-6xl font-black mb-6"
|
||||||
|
>
|
||||||
|
<span className="gradient-text">{t('title')}</span>
|
||||||
|
</motion.h2>
|
||||||
|
|
||||||
|
<motion.p
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: 0.1 }}
|
||||||
|
className="text-lg text-white/50 mb-8"
|
||||||
|
>
|
||||||
|
{t('description')}
|
||||||
|
</motion.p>
|
||||||
|
|
||||||
|
<motion.a
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: 0.2 }}
|
||||||
|
href={menuUrl}
|
||||||
|
target={menuUrl !== '#' ? '_blank' : '_self'}
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="inline-flex items-center gap-2 px-8 py-3.5 rounded-full font-black text-sm text-midnight transition-all hover:scale-105"
|
||||||
|
style={{ background: 'linear-gradient(135deg, #FFA827, #FFD166)' }}
|
||||||
|
>
|
||||||
|
{t('view_menu')}
|
||||||
|
<ArrowRight size={15} />
|
||||||
|
</motion.a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||||
|
{CARDS.map(({ id, icon: Icon, accent }, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={id}
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: index * 0.1 + 0.2 }}
|
||||||
|
className="group relative p-8 rounded-3xl border border-white/10 hover:border-white/25 transition-all duration-300"
|
||||||
|
style={{ background: 'rgba(255,255,255,0.04)' }}
|
||||||
|
>
|
||||||
|
{/* Icon */}
|
||||||
|
<div
|
||||||
|
className="w-14 h-14 rounded-2xl mb-6 flex items-center justify-center"
|
||||||
|
style={{ background: `${accent}18`, color: accent }}
|
||||||
|
>
|
||||||
|
<Icon size={26} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 className="font-heading text-2xl font-black mb-3 text-white">
|
||||||
|
{t(`cards.${id}.title`)}
|
||||||
|
</h3>
|
||||||
|
<p className="text-white/45 text-sm leading-relaxed">{t(`cards.${id}.desc`)}</p>
|
||||||
|
|
||||||
|
{/* Bottom accent line on hover */}
|
||||||
|
<div
|
||||||
|
className="absolute bottom-0 left-8 right-8 h-[1px] opacity-0 group-hover:opacity-100 transition-opacity duration-300 rounded-full"
|
||||||
|
style={{ background: `linear-gradient(90deg, transparent, ${accent}, transparent)` }}
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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<number, string> = {
|
||||||
|
3: '#FF5A36',
|
||||||
|
4: '#00E5FF',
|
||||||
|
5: '#00E5FF',
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ── sub-components ────────────────────────────── */
|
||||||
|
|
||||||
|
function VinylDisc() {
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
animate={{ rotate: 360 }}
|
||||||
|
transition={{ duration: 4, repeat: Infinity, ease: 'linear' }}
|
||||||
|
className="w-36 h-36 md:w-44 md:h-44 rounded-full relative flex-shrink-0"
|
||||||
|
style={{
|
||||||
|
background:
|
||||||
|
'repeating-conic-gradient(#0a0f1e 0deg 18deg, #141e30 18deg 36deg)',
|
||||||
|
boxShadow: '0 0 48px rgba(0,229,255,0.35), 0 0 80px rgba(0,229,255,0.12)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Grooves */}
|
||||||
|
{[55, 45, 35].map((size) => (
|
||||||
|
<div
|
||||||
|
key={size}
|
||||||
|
className="absolute rounded-full border border-white/[0.04]"
|
||||||
|
style={{ inset: `${(100 - size) / 2}%` }}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{/* Label */}
|
||||||
|
<div
|
||||||
|
className="absolute inset-[35%] rounded-full flex items-center justify-center"
|
||||||
|
style={{ background: 'radial-gradient(circle, #00E5FF, #0084A8)' }}
|
||||||
|
>
|
||||||
|
<div className="w-2 h-2 rounded-full bg-white/80" />
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<div className="flex items-end gap-[3px] h-8">
|
||||||
|
{heights.map((h, i) => (
|
||||||
|
<motion.div
|
||||||
|
key={i}
|
||||||
|
className="w-1.5 rounded-full origin-bottom"
|
||||||
|
style={{ background: color, height: `${h * 100}%` }}
|
||||||
|
animate={{ scaleY: [h, h > 0.6 ? 0.2 : 1, h] }}
|
||||||
|
transition={{
|
||||||
|
duration: 0.5 + Math.random() * 0.4,
|
||||||
|
repeat: Infinity,
|
||||||
|
repeatType: 'mirror',
|
||||||
|
delay: i * 0.07,
|
||||||
|
ease: 'easeInOut',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function WineGlassIcon() {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="22"
|
||||||
|
height="22"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
>
|
||||||
|
<path d="M8 22h8" />
|
||||||
|
<path d="M12 15v7" />
|
||||||
|
<path d="M12 15a5 5 0 0 0 5-5c0-2-.5-4-2-8H9c-1.5 4-2 6-2 8a5 5 0 0 0 5 5Z" />
|
||||||
|
<path d="M7 10h10" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── main component ────────────────────────────── */
|
||||||
|
|
||||||
|
export default function Events() {
|
||||||
|
const t = useTranslations('Events');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
id="events"
|
||||||
|
className="pt-28 pb-36 text-white relative overflow-hidden"
|
||||||
|
style={{ background: '#080D18' }}
|
||||||
|
>
|
||||||
|
{/* Aurora background blobs */}
|
||||||
|
<div className="absolute inset-0 overflow-hidden pointer-events-none">
|
||||||
|
<div
|
||||||
|
className="absolute top-[-20%] left-[-10%] w-[600px] h-[600px] rounded-full opacity-[0.12]"
|
||||||
|
style={{ background: 'radial-gradient(circle, #00E5FF 0%, transparent 70%)' }}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="absolute bottom-[-10%] right-[-5%] w-[500px] h-[500px] rounded-full opacity-[0.1]"
|
||||||
|
style={{ background: 'radial-gradient(circle, #FF5A36 0%, transparent 70%)' }}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[700px] h-[700px] rounded-full opacity-[0.05]"
|
||||||
|
style={{ background: 'radial-gradient(circle, #FFA827 0%, transparent 70%)' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Fine dot grid */}
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 opacity-[0.035] pointer-events-none"
|
||||||
|
style={{
|
||||||
|
backgroundImage: 'radial-gradient(circle, rgba(255,255,255,0.9) 1px, transparent 1px)',
|
||||||
|
backgroundSize: '36px 36px',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="container mx-auto px-6 lg:px-12 relative z-10 space-y-10">
|
||||||
|
|
||||||
|
{/* ── Header ───────────────────────────────── */}
|
||||||
|
<div className="flex flex-col lg:flex-row lg:items-end justify-between gap-6">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2 mb-4">
|
||||||
|
<Zap size={13} className="text-coral" />
|
||||||
|
<span className="text-xs tracking-[0.4em] uppercase font-black text-coral">
|
||||||
|
Live Events
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<h2 className="font-heading text-5xl md:text-6xl font-black leading-tight">
|
||||||
|
{t('title')}
|
||||||
|
</h2>
|
||||||
|
<p className="text-white/45 mt-3 text-base max-w-md leading-relaxed">
|
||||||
|
{t('description')}
|
||||||
|
</p>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<motion.button
|
||||||
|
initial={{ opacity: 0, x: 20 }}
|
||||||
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
className="self-start lg:self-auto flex items-center gap-2 px-7 py-3.5 rounded-full font-black text-sm text-white flex-shrink-0 transition-all hover:scale-105"
|
||||||
|
style={{ background: 'linear-gradient(135deg, #FF5A36, #FFA827)' }}
|
||||||
|
>
|
||||||
|
<CalendarDays size={15} />
|
||||||
|
{t('view_calendar')}
|
||||||
|
</motion.button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ── Weekly schedule bar ───────────────────── */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 12 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
className="flex items-center gap-2 md:gap-4 bg-white/[0.04] rounded-2xl px-6 py-4 border border-white/[0.07]"
|
||||||
|
>
|
||||||
|
{WEEK_DAYS.map((day, i) => {
|
||||||
|
const accent = ACTIVE_DAYS[i];
|
||||||
|
const isActive = !!accent;
|
||||||
|
return (
|
||||||
|
<div key={day} className="flex-1 flex flex-col items-center gap-2">
|
||||||
|
<span
|
||||||
|
className={`text-[10px] font-black uppercase tracking-wider ${
|
||||||
|
isActive ? 'text-white' : 'text-white/25'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{day}
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
className={`w-1.5 h-1.5 rounded-full transition-all ${isActive ? 'scale-125' : ''}`}
|
||||||
|
style={{
|
||||||
|
background: isActive ? accent : 'rgba(255,255,255,0.12)',
|
||||||
|
boxShadow: isActive ? `0 0 8px ${accent}` : 'none',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* ── Featured Event: DJ Nights ────────────── */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 24 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.7 }}
|
||||||
|
className="border-spin-cyan rounded-3xl p-px overflow-hidden"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="rounded-3xl p-8 md:p-10 flex flex-col md:flex-row items-center gap-8 overflow-hidden relative"
|
||||||
|
style={{ background: '#0C1828' }}
|
||||||
|
>
|
||||||
|
{/* Glow center */}
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 pointer-events-none"
|
||||||
|
style={{
|
||||||
|
background:
|
||||||
|
'radial-gradient(ellipse at 80% 50%, rgba(0,229,255,0.08) 0%, transparent 60%)',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Left: text */}
|
||||||
|
<div className="flex-1 relative z-10">
|
||||||
|
<div className="flex items-center gap-3 mb-5">
|
||||||
|
<span
|
||||||
|
className="text-[10px] font-black uppercase tracking-[0.35em] px-3 py-1.5 rounded-full"
|
||||||
|
style={{ background: '#00E5FF1A', color: '#00E5FF' }}
|
||||||
|
>
|
||||||
|
EN POPÜLER
|
||||||
|
</span>
|
||||||
|
<div className="flex items-center gap-1.5 text-white/40 text-xs">
|
||||||
|
<Calendar size={11} />
|
||||||
|
<span>{t('cards.dj.time')}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 className="font-heading text-4xl md:text-5xl font-black mb-3 text-white leading-tight">
|
||||||
|
{t('cards.dj.title')}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-3 mb-7">
|
||||||
|
<Disc3 size={18} style={{ color: '#00E5FF' }} />
|
||||||
|
<span className="text-white/50 text-sm">Open-air · Beach Stage</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<EqBars color="#00E5FF" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Right: vinyl */}
|
||||||
|
<div className="relative z-10 flex-shrink-0">
|
||||||
|
<VinylDisc />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* ── Secondary events: 2-col grid ─────────── */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||||
|
|
||||||
|
{/* Rakı Geceleri */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: 0.1 }}
|
||||||
|
className="border-spin-coral rounded-3xl p-px group cursor-pointer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="rounded-3xl p-7 h-full flex flex-col gap-5 relative overflow-hidden transition-colors duration-300 group-hover:bg-[#110a0a]"
|
||||||
|
style={{ background: '#0C0808' }}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity duration-400 pointer-events-none"
|
||||||
|
style={{
|
||||||
|
background:
|
||||||
|
'radial-gradient(ellipse at 20% 50%, rgba(255,90,54,0.1) 0%, transparent 65%)',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="flex items-start justify-between">
|
||||||
|
<div
|
||||||
|
className="w-12 h-12 rounded-2xl flex items-center justify-center"
|
||||||
|
style={{ background: '#FF5A361A', color: '#FF5A36' }}
|
||||||
|
>
|
||||||
|
<WineGlassIcon />
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
className="text-[10px] font-black uppercase tracking-wider px-2.5 py-1 rounded-full"
|
||||||
|
style={{ background: '#FF5A361A', color: '#FF5A36' }}
|
||||||
|
>
|
||||||
|
PER
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 className="font-heading text-2xl font-black text-white mb-2">
|
||||||
|
{t('cards.raki.title')}
|
||||||
|
</h3>
|
||||||
|
<div className="flex items-center gap-1.5 text-sm text-white/40">
|
||||||
|
<Calendar size={12} />
|
||||||
|
<span>{t('cards.raki.time')}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-auto opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
||||||
|
<EqBars color="#FF5A36" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* Canlı Müzik */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: 0.2 }}
|
||||||
|
className="border-spin-amber rounded-3xl p-px group cursor-pointer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="rounded-3xl p-7 h-full flex flex-col gap-5 relative overflow-hidden transition-colors duration-300 group-hover:bg-[#110d04]"
|
||||||
|
style={{ background: '#0C0A04' }}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity duration-400 pointer-events-none"
|
||||||
|
style={{
|
||||||
|
background:
|
||||||
|
'radial-gradient(ellipse at 80% 50%, rgba(255,168,39,0.1) 0%, transparent 65%)',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="flex items-start justify-between">
|
||||||
|
<div
|
||||||
|
className="w-12 h-12 rounded-2xl flex items-center justify-center"
|
||||||
|
style={{ background: '#FFA8271A', color: '#FFA827' }}
|
||||||
|
>
|
||||||
|
<Music size={22} />
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
className="text-[10px] font-black uppercase tracking-wider px-2.5 py-1 rounded-full"
|
||||||
|
style={{ background: '#FFA8271A', color: '#FFA827' }}
|
||||||
|
>
|
||||||
|
★ ÖZEL
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 className="font-heading text-2xl font-black text-white mb-2">
|
||||||
|
{t('cards.live_music.title')}
|
||||||
|
</h3>
|
||||||
|
<div className="flex items-center gap-1.5 text-sm text-white/40">
|
||||||
|
<Calendar size={12} />
|
||||||
|
<span>{t('cards.live_music.time')}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-auto opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
||||||
|
<EqBars color="#FFA827" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Wave → sand */}
|
||||||
|
<div className="absolute bottom-0 left-0 w-full leading-none pointer-events-none">
|
||||||
|
<svg viewBox="0 0 1440 64" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" className="w-full h-16">
|
||||||
|
<path d="M0,20 C360,64 720,0 1080,40 C1260,56 1380,10 1440,20 L1440,64 L0,64 Z" fill="#FFF8EE" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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 (
|
||||||
|
<footer
|
||||||
|
className="text-white py-16 relative overflow-hidden"
|
||||||
|
style={{ background: '#080D18' }}
|
||||||
|
>
|
||||||
|
{/* Rainbow top border */}
|
||||||
|
<div
|
||||||
|
className="absolute top-0 left-0 right-0 h-[1px]"
|
||||||
|
style={{
|
||||||
|
background:
|
||||||
|
'linear-gradient(90deg, transparent 0%, #FF5A36 25%, #FFA827 50%, #00BFA5 75%, transparent 100%)',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="container mx-auto px-6 lg:px-12">
|
||||||
|
<div className="flex flex-col md:flex-row justify-between items-start gap-12 mb-12">
|
||||||
|
|
||||||
|
{/* Brand */}
|
||||||
|
<div>
|
||||||
|
<Link href="/" className="inline-flex flex-col mb-3">
|
||||||
|
<span className="font-heading text-5xl font-black uppercase tracking-tighter gradient-text-warm">
|
||||||
|
Kozmos
|
||||||
|
</span>
|
||||||
|
<span className="text-[10px] tracking-[0.5em] font-body uppercase text-white/30 mt-0.5">
|
||||||
|
Beach & More
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
<p className="text-white/35 text-sm mt-1">{t('tagline')}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Nav links */}
|
||||||
|
<div className="flex flex-wrap gap-x-7 gap-y-3">
|
||||||
|
{navLinks.map((link) => (
|
||||||
|
<Link
|
||||||
|
key={link.href}
|
||||||
|
href={link.href}
|
||||||
|
className="text-sm text-white/40 hover:text-white transition-colors"
|
||||||
|
>
|
||||||
|
{link.label}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Social */}
|
||||||
|
<a
|
||||||
|
href="https://www.instagram.com/kozmosbeach/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="w-12 h-12 rounded-2xl border border-white/10 flex items-center justify-center text-white/40 hover:border-coral hover:text-coral transition-all"
|
||||||
|
>
|
||||||
|
<Instagram size={19} />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="pt-8 border-t border-white/10 flex flex-col md:flex-row justify-between items-center gap-4 text-xs text-white/25">
|
||||||
|
<div>{t('rights')}</div>
|
||||||
|
<div>
|
||||||
|
Created by{' '}
|
||||||
|
<a
|
||||||
|
href="https://ayris.tech"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="text-white/40 hover:text-coral transition-colors"
|
||||||
|
>
|
||||||
|
ayris.tech
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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<number | null>(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 (
|
||||||
|
<section id="gallery" className="py-24 bg-white text-midnight">
|
||||||
|
<div className="container mx-auto px-6 lg:px-12">
|
||||||
|
|
||||||
|
{/* Header */}
|
||||||
|
<div className="flex flex-col md:flex-row justify-between items-end mb-10">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: -20 }}
|
||||||
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
>
|
||||||
|
<span className="text-xs tracking-[0.4em] uppercase font-black text-coral mb-3 block">
|
||||||
|
— Fotoğraflar
|
||||||
|
</span>
|
||||||
|
<h2 className="font-heading text-5xl md:text-6xl font-black text-midnight">
|
||||||
|
{t('title')}
|
||||||
|
</h2>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<motion.a
|
||||||
|
initial={{ opacity: 0, x: 20 }}
|
||||||
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
href="https://www.instagram.com/kozmosbeach/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="flex items-center gap-2 px-5 py-2.5 rounded-full border border-coral/30 text-coral font-bold text-sm hover:bg-coral hover:text-white transition-all"
|
||||||
|
>
|
||||||
|
<Instagram size={15} />
|
||||||
|
{t('follow_instagram')}
|
||||||
|
</motion.a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Masonry grid */}
|
||||||
|
<div className="columns-1 sm:columns-2 md:columns-3 lg:columns-4 gap-3 space-y-3">
|
||||||
|
{images.map((img, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={img.id}
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: (index % 4) * 0.07 }}
|
||||||
|
onClick={() => setSelectedIndex(index)}
|
||||||
|
className="relative rounded-2xl overflow-hidden group break-inside-avoid cursor-pointer"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={img.src}
|
||||||
|
alt={img.alt}
|
||||||
|
className="w-full h-auto object-cover transition-transform duration-700 group-hover:scale-105"
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
{/* Coral gradient overlay */}
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity duration-300"
|
||||||
|
style={{
|
||||||
|
background:
|
||||||
|
'linear-gradient(135deg, rgba(255,90,54,0.55), rgba(0,191,165,0.4))',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* Plus icon */}
|
||||||
|
<div className="absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
||||||
|
<span className="text-white text-4xl font-thin select-none">+</span>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Lightbox Overlay */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{selectedIndex !== null && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
exit={{ opacity: 0 }}
|
||||||
|
className="fixed inset-0 z-[100] flex items-center justify-center bg-midnight/95 backdrop-blur-md"
|
||||||
|
>
|
||||||
|
{/* Close Button */}
|
||||||
|
<button
|
||||||
|
onClick={() => setSelectedIndex(null)}
|
||||||
|
className="absolute top-6 right-6 z-[110] text-white/70 hover:text-white transition-colors"
|
||||||
|
>
|
||||||
|
<X size={36} />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Left/Right Navigation */}
|
||||||
|
<button
|
||||||
|
onClick={(e) => {
|
||||||
|
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"
|
||||||
|
>
|
||||||
|
<ChevronLeft size={30} />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={(e) => {
|
||||||
|
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"
|
||||||
|
>
|
||||||
|
<ChevronRight size={30} />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Image */}
|
||||||
|
<motion.div
|
||||||
|
key={selectedIndex}
|
||||||
|
initial={{ opacity: 0, scale: 0.9 }}
|
||||||
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
|
exit={{ opacity: 0, scale: 0.9 }}
|
||||||
|
transition={{ type: "spring", damping: 25, stiffness: 300 }}
|
||||||
|
className="relative max-w-5xl w-full h-[80vh] px-4 md:px-24"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={images[selectedIndex].src}
|
||||||
|
alt={images[selectedIndex].alt}
|
||||||
|
className="w-full h-full object-contain drop-shadow-2xl"
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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 (
|
||||||
|
<section
|
||||||
|
id="hero"
|
||||||
|
className="relative w-full h-screen flex items-center justify-center overflow-hidden"
|
||||||
|
style={{ background: '#080D18' }}
|
||||||
|
>
|
||||||
|
{/* ── Ambient gradient blobs ───────────────────── */}
|
||||||
|
<div className="absolute inset-0 overflow-hidden">
|
||||||
|
<motion.div
|
||||||
|
animate={{ x: [0, 60, -20, 0], y: [0, -50, 30, 0], scale: [1, 1.15, 0.95, 1] }}
|
||||||
|
transition={{ duration: 28, repeat: Infinity, ease: 'easeInOut' }}
|
||||||
|
className="absolute -top-56 -left-56 w-[700px] h-[700px] rounded-full"
|
||||||
|
style={{ background: 'radial-gradient(circle, rgba(255,90,54,0.28) 0%, transparent 65%)' }}
|
||||||
|
/>
|
||||||
|
<motion.div
|
||||||
|
animate={{ x: [0, -80, 50, 0], y: [0, 70, -30, 0], scale: [1, 0.85, 1.2, 1] }}
|
||||||
|
transition={{ duration: 32, repeat: Infinity, ease: 'easeInOut', delay: 6 }}
|
||||||
|
className="absolute -bottom-40 -right-40 w-[600px] h-[600px] rounded-full"
|
||||||
|
style={{ background: 'radial-gradient(circle, rgba(0,191,165,0.22) 0%, transparent 65%)' }}
|
||||||
|
/>
|
||||||
|
<motion.div
|
||||||
|
animate={{ x: [0, 100, -60, 0], y: [0, -80, 50, 0], scale: [1, 1.3, 0.85, 1] }}
|
||||||
|
transition={{ duration: 22, repeat: Infinity, ease: 'easeInOut', delay: 12 }}
|
||||||
|
className="absolute top-1/2 right-1/3 w-[400px] h-[400px] rounded-full"
|
||||||
|
style={{ background: 'radial-gradient(circle, rgba(255,168,39,0.18) 0%, transparent 65%)' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Grain overlay */}
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 z-[1] opacity-[0.035] pointer-events-none"
|
||||||
|
style={{
|
||||||
|
backgroundImage: `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")`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* ── Content ──────────────────────────────────── */}
|
||||||
|
<div className="relative z-10 container mx-auto px-6 flex flex-col items-center text-center">
|
||||||
|
|
||||||
|
{/* Location */}
|
||||||
|
<motion.p
|
||||||
|
initial={{ opacity: 0, y: 16 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.7 }}
|
||||||
|
className="text-[11px] tracking-[0.45em] uppercase text-coral font-bold mb-10"
|
||||||
|
>
|
||||||
|
Akyaka · Gökova Körfezi
|
||||||
|
</motion.p>
|
||||||
|
|
||||||
|
{/* Brand name — static gradient, no shimmer */}
|
||||||
|
<motion.h1
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.9, delay: 0.15 }}
|
||||||
|
className="font-heading font-black uppercase tracking-tight leading-none gradient-text-warm mb-4"
|
||||||
|
style={{ fontSize: 'clamp(3rem, 8vw, 6.5rem)' }}
|
||||||
|
>
|
||||||
|
KOZMOS
|
||||||
|
</motion.h1>
|
||||||
|
|
||||||
|
{/* Thin divider */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ scaleX: 0 }}
|
||||||
|
animate={{ scaleX: 1 }}
|
||||||
|
transition={{ duration: 0.8, delay: 0.35 }}
|
||||||
|
className="w-16 h-px mb-5"
|
||||||
|
style={{ background: 'linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent)' }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Subtitle */}
|
||||||
|
<motion.p
|
||||||
|
initial={{ opacity: 0, y: 12 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6, delay: 0.45 }}
|
||||||
|
className="text-sm md:text-base tracking-[0.55em] uppercase text-white/40 font-medium mb-6"
|
||||||
|
>
|
||||||
|
Beach & More
|
||||||
|
</motion.p>
|
||||||
|
|
||||||
|
{/* Tagline */}
|
||||||
|
<motion.p
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
transition={{ duration: 0.6, delay: 0.6 }}
|
||||||
|
className="text-white/55 text-sm md:text-base max-w-xs leading-relaxed mb-12"
|
||||||
|
>
|
||||||
|
{t('tagline')}
|
||||||
|
</motion.p>
|
||||||
|
|
||||||
|
{/* CTAs */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 16 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6, delay: 0.75 }}
|
||||||
|
className="flex flex-col sm:flex-row gap-3"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
onClick={openWhatsApp}
|
||||||
|
className="px-8 py-3.5 rounded-full font-bold text-sm tracking-wider text-white transition-all duration-300 hover:scale-105 hover:shadow-[0_0_32px_rgba(255,90,54,0.45)]"
|
||||||
|
style={{ background: 'linear-gradient(135deg, #FF5A36, #FFA827)' }}
|
||||||
|
>
|
||||||
|
{t('cta_reservation')}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="#contact"
|
||||||
|
className="flex items-center justify-center gap-2 px-7 py-3.5 rounded-full text-sm tracking-wider font-medium text-white/70 border border-white/15 hover:border-white/35 hover:text-white transition-all duration-300"
|
||||||
|
>
|
||||||
|
<MapPin size={14} />
|
||||||
|
{t('cta_location')}
|
||||||
|
</a>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ── Wave divider ─────────────────────────────── */}
|
||||||
|
<div className="absolute bottom-0 left-0 w-full z-10 leading-none">
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 1440 72"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
className="w-full h-[72px]"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M0,36 C240,72 480,0 720,36 C960,72 1200,0 1440,36 L1440,72 L0,72 Z"
|
||||||
|
fill="#FFF8EE"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Scroll cue */}
|
||||||
|
<motion.div
|
||||||
|
className="absolute bottom-10 left-1/2 -translate-x-1/2 z-20 text-white/35"
|
||||||
|
animate={{ y: [0, 7, 0] }}
|
||||||
|
transition={{ repeat: Infinity, duration: 1.8 }}
|
||||||
|
>
|
||||||
|
<a href="#about" aria-label="Scroll down">
|
||||||
|
<ChevronDown size={24} />
|
||||||
|
</a>
|
||||||
|
</motion.div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export function Instagram({ size = 24, className = "" }: { size?: number, className?: string }) {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
<rect width="20" height="20" x="2" y="2" rx="5" ry="5" />
|
||||||
|
<path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z" />
|
||||||
|
<line x1="17.5" x2="17.51" y1="6.5" y2="6.5" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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 (
|
||||||
|
<nav
|
||||||
|
className={`fixed top-0 left-0 w-full z-50 transition-all duration-300 ${
|
||||||
|
isScrolled
|
||||||
|
? 'bg-white/90 backdrop-blur-lg shadow-sm py-4 border-b border-sandy/40'
|
||||||
|
: 'bg-transparent py-6'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="container mx-auto px-6 lg:px-12 flex justify-between items-center">
|
||||||
|
|
||||||
|
{/* Logo */}
|
||||||
|
<Link href="/" className="flex flex-col items-start">
|
||||||
|
<span
|
||||||
|
className={`font-heading text-2xl font-black uppercase tracking-tighter ${
|
||||||
|
isScrolled ? 'text-midnight' : 'gradient-text-warm'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
Kozmos
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className={`text-[10px] tracking-[0.4em] font-body uppercase ${
|
||||||
|
isScrolled ? 'text-coral' : 'text-white/40'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
Beach & More
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Desktop Nav */}
|
||||||
|
<div className="hidden lg:flex items-center gap-8">
|
||||||
|
<div className="flex gap-6">
|
||||||
|
{navLinks.map((link) => (
|
||||||
|
<Link
|
||||||
|
key={link.href}
|
||||||
|
href={link.href}
|
||||||
|
className={`text-sm font-medium tracking-wide transition-colors hover:text-coral ${
|
||||||
|
isScrolled ? 'text-midnight/70' : 'text-white/80'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{link.label}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={`flex items-center gap-3 border-l pl-5 ${
|
||||||
|
isScrolled ? 'border-sandy' : 'border-white/20'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{(['tr', 'en'] as const).map((l) => (
|
||||||
|
<button
|
||||||
|
key={l}
|
||||||
|
onClick={() => switchLocale(l)}
|
||||||
|
className={`text-[11px] font-black uppercase tracking-wider transition-colors ${
|
||||||
|
locale === l
|
||||||
|
? 'text-coral'
|
||||||
|
: isScrolled
|
||||||
|
? 'text-midnight/40'
|
||||||
|
: 'text-white/40'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{l}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="#contact"
|
||||||
|
className="px-5 py-2.5 rounded-full text-xs font-black text-white tracking-wider transition-all hover:scale-105 hover:shadow-[0_0_24px_rgba(255,90,54,0.45)]"
|
||||||
|
style={{ background: 'linear-gradient(135deg, #FF5A36, #FFA827)' }}
|
||||||
|
>
|
||||||
|
{t('reservation')}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Mobile toggle */}
|
||||||
|
<button
|
||||||
|
className="lg:hidden"
|
||||||
|
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
||||||
|
aria-label="Toggle menu"
|
||||||
|
>
|
||||||
|
{isMobileMenuOpen ? (
|
||||||
|
<X className={isScrolled ? 'text-midnight' : 'text-white'} size={26} />
|
||||||
|
) : (
|
||||||
|
<Menu className={isScrolled ? 'text-midnight' : 'text-white'} size={26} />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Mobile menu */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{isMobileMenuOpen && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: -10 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, y: -10 }}
|
||||||
|
className="lg:hidden absolute top-full left-0 w-full bg-white/96 backdrop-blur-lg shadow-xl border-t border-sandy/30"
|
||||||
|
>
|
||||||
|
<div className="flex flex-col py-6 px-8 gap-3">
|
||||||
|
{navLinks.map((link) => (
|
||||||
|
<Link
|
||||||
|
key={link.href}
|
||||||
|
href={link.href}
|
||||||
|
className="text-midnight text-base font-heading font-semibold py-2 border-b border-sandy/20 hover:text-coral transition-colors"
|
||||||
|
onClick={() => setIsMobileMenuOpen(false)}
|
||||||
|
>
|
||||||
|
{link.label}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<div className="flex gap-4 pt-3">
|
||||||
|
{(['tr', 'en'] as const).map((l) => (
|
||||||
|
<button
|
||||||
|
key={l}
|
||||||
|
onClick={() => switchLocale(l)}
|
||||||
|
className={`text-sm font-black uppercase ${locale === l ? 'text-coral' : 'text-midnight/40'}`}
|
||||||
|
>
|
||||||
|
{l}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="#contact"
|
||||||
|
className="mt-2 text-center py-3.5 rounded-full text-sm font-black text-white"
|
||||||
|
style={{ background: 'linear-gradient(135deg, #FF5A36, #FFA827)' }}
|
||||||
|
onClick={() => setIsMobileMenuOpen(false)}
|
||||||
|
>
|
||||||
|
{t('reservation')}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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 (
|
||||||
|
<button
|
||||||
|
onClick={openWhatsApp}
|
||||||
|
className="fixed bottom-6 right-6 z-50 bg-[#25D366] text-white p-4 rounded-full shadow-[0_4px_14px_0_rgba(37,211,102,0.39)] hover:shadow-[0_6px_20px_rgba(37,211,102,0.23)] hover:scale-105 transition-all duration-300 flex items-center justify-center group"
|
||||||
|
aria-label="WhatsApp ile iletişime geçin"
|
||||||
|
>
|
||||||
|
<div className="absolute inset-0 rounded-full bg-[#25D366] animate-ping opacity-20"></div>
|
||||||
|
<MessageCircle size={28} className="relative z-10" />
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -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);
|
||||||
@@ -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."
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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."
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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|.*\\..*).*)']
|
||||||
|
};
|
||||||
+12
-2
@@ -1,7 +1,17 @@
|
|||||||
import type { NextConfig } from "next";
|
import type { NextConfig } from "next";
|
||||||
|
import createNextIntlPlugin from "next-intl/plugin";
|
||||||
|
|
||||||
|
const withNextIntl = createNextIntlPlugin();
|
||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
/* config options here */
|
images: {
|
||||||
|
remotePatterns: [
|
||||||
|
{
|
||||||
|
protocol: 'https',
|
||||||
|
hostname: 'picsum.photos',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
export default withNextIntl(nextConfig);
|
||||||
|
|||||||
Generated
+806
-4
@@ -8,9 +8,14 @@
|
|||||||
"name": "kozmosweb",
|
"name": "kozmosweb",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"framer-motion": "^12.40.0",
|
||||||
|
"lucide-react": "^1.17.0",
|
||||||
"next": "16.2.7",
|
"next": "16.2.7",
|
||||||
|
"next-intl": "^4.13.0",
|
||||||
"react": "19.2.4",
|
"react": "19.2.4",
|
||||||
"react-dom": "19.2.4"
|
"react-dom": "19.2.4",
|
||||||
|
"tailwind-merge": "^3.6.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/postcss": "^4",
|
"@tailwindcss/postcss": "^4",
|
||||||
@@ -453,6 +458,36 @@
|
|||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"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": {
|
"node_modules/@humanfs/core": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.2",
|
||||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
|
||||||
@@ -1306,6 +1341,331 @@
|
|||||||
"node": ">=12.4.0"
|
"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": {
|
"node_modules/@rtsao/scc": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
|
||||||
@@ -1313,6 +1673,228 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/@swc/helpers": {
|
||||||
"version": "0.5.15",
|
"version": "0.5.15",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
|
||||||
@@ -1322,6 +1904,15 @@
|
|||||||
"tslib": "^2.8.0"
|
"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": {
|
"node_modules/@tailwindcss/node": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz",
|
||||||
@@ -2771,6 +3362,15 @@
|
|||||||
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
|
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/color-convert": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
@@ -2953,7 +3553,6 @@
|
|||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||||
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
||||||
"devOptional": true,
|
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
@@ -3762,6 +4361,33 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"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": {
|
"node_modules/function-bind": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
@@ -4067,6 +4693,21 @@
|
|||||||
"hermes-estree": "0.25.1"
|
"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": {
|
"node_modules/ignore": {
|
||||||
"version": "5.3.2",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||||
@@ -4119,6 +4760,16 @@
|
|||||||
"node": ">= 0.4"
|
"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": {
|
"node_modules/is-array-buffer": {
|
||||||
"version": "3.0.5",
|
"version": "3.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
|
||||||
@@ -4281,7 +4932,6 @@
|
|||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
@@ -4327,7 +4977,6 @@
|
|||||||
"version": "4.0.3",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-extglob": "^2.1.1"
|
"is-extglob": "^2.1.1"
|
||||||
@@ -5032,6 +5681,15 @@
|
|||||||
"yallist": "^3.0.2"
|
"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": {
|
"node_modules/magic-string": {
|
||||||
"version": "0.30.21",
|
"version": "0.30.21",
|
||||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
||||||
@@ -5099,6 +5757,21 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"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": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
@@ -5147,6 +5820,15 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/next": {
|
||||||
"version": "16.2.7",
|
"version": "16.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/next/-/next-16.2.7.tgz",
|
"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": {
|
"node_modules/next/node_modules/postcss": {
|
||||||
"version": "8.4.31",
|
"version": "8.4.31",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
||||||
@@ -5228,6 +5987,12 @@
|
|||||||
"node": "^10 || ^12 || >=14"
|
"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": {
|
"node_modules/node-exports-info": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz",
|
"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"
|
"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": {
|
"node_modules/possible-typed-array-names": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
|
"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"
|
"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": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz",
|
||||||
@@ -6603,6 +7384,27 @@
|
|||||||
"punycode": "^2.1.0"
|
"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": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|||||||
+6
-1
@@ -9,9 +9,14 @@
|
|||||||
"lint": "eslint"
|
"lint": "eslint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"framer-motion": "^12.40.0",
|
||||||
|
"lucide-react": "^1.17.0",
|
||||||
"next": "16.2.7",
|
"next": "16.2.7",
|
||||||
|
"next-intl": "^4.13.0",
|
||||||
"react": "19.2.4",
|
"react": "19.2.4",
|
||||||
"react-dom": "19.2.4"
|
"react-dom": "19.2.4",
|
||||||
|
"tailwind-merge": "^3.6.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/postcss": "^4",
|
"@tailwindcss/postcss": "^4",
|
||||||
|
|||||||
Reference in New Issue
Block a user