first commit

This commit is contained in:
2026-06-17 15:58:02 +03:00
commit 6b15d70955
45 changed files with 11598 additions and 0 deletions
+97
View File
@@ -0,0 +1,97 @@
'use client'
import { signOut } from 'next-auth/react'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { LayoutDashboard, Users, Settings, LogOut, Menu, X } from 'lucide-react'
import { useState } from 'react'
export default function AdminLayout({ children }: { children: React.ReactNode }) {
const pathname = usePathname()
const [sidebarOpen, setSidebarOpen] = useState(false)
const navigation = [
{ name: 'Dashboard', href: '/admin', icon: LayoutDashboard },
{ name: 'Kullanıcılar', href: '/admin/users', icon: Users },
{ name: 'Ayarlar', href: '/admin/settings', icon: Settings },
]
return (
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 flex">
{/* Mobile sidebar backdrop */}
{sidebarOpen && (
<div
className="fixed inset-0 z-40 bg-gray-900/80 lg:hidden"
onClick={() => setSidebarOpen(false)}
/>
)}
{/* Sidebar */}
<div className={`
fixed inset-y-0 left-0 z-50 w-64 bg-white dark:bg-gray-950 border-r border-gray-200 dark:border-gray-800
transform transition-transform duration-200 ease-in-out lg:translate-x-0 lg:static lg:inset-0
${sidebarOpen ? 'translate-x-0' : '-translate-x-full'}
`}>
<div className="h-full flex flex-col">
<div className="h-16 flex items-center px-6 border-b border-gray-200 dark:border-gray-800">
<h1 className="text-lg font-bold text-gray-900 dark:text-white">Admin Paneli</h1>
<button
className="ml-auto lg:hidden text-gray-500"
onClick={() => setSidebarOpen(false)}
>
<X className="h-5 w-5" />
</button>
</div>
<nav className="flex-1 px-4 py-6 space-y-1 overflow-y-auto">
{navigation.map((item) => {
const isActive = pathname.endsWith(item.href)
return (
<Link
key={item.name}
href={item.href}
className={`
flex items-center px-3 py-2.5 text-sm font-medium rounded-md transition-colors
${isActive
? 'bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-white'
: 'text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 hover:text-gray-900 dark:hover:text-white'}
`}
>
<item.icon className={`mr-3 flex-shrink-0 h-5 w-5 ${isActive ? 'text-gray-900 dark:text-white' : 'text-gray-400'}`} />
{item.name}
</Link>
)
})}
</nav>
<div className="p-4 border-t border-gray-200 dark:border-gray-800">
<button
onClick={() => signOut({ callbackUrl: '/' })}
className="flex w-full items-center px-3 py-2.5 text-sm font-medium text-red-600 dark:text-red-400 rounded-md hover:bg-red-50 dark:hover:bg-red-950/30 transition-colors"
>
<LogOut className="mr-3 h-5 w-5" />
Çıkış Yap
</button>
</div>
</div>
</div>
{/* Main content */}
<div className="flex-1 flex flex-col min-w-0 overflow-hidden">
<header className="h-16 flex items-center lg:hidden bg-white dark:bg-gray-950 border-b border-gray-200 dark:border-gray-800 px-4">
<button
onClick={() => setSidebarOpen(true)}
className="text-gray-500 hover:text-gray-900 dark:hover:text-white focus:outline-none"
>
<Menu className="h-6 w-6" />
</button>
<span className="ml-4 text-lg font-bold text-gray-900 dark:text-white">Admin Paneli</span>
</header>
<main className="flex-1 overflow-y-auto p-4 sm:p-6 lg:p-8">
{children}
</main>
</div>
</div>
)
}
+82
View File
@@ -0,0 +1,82 @@
import { auth } from '@/lib/auth'
export default async function AdminDashboardPage() {
const session = await auth()
return (
<div className="space-y-8 p-6 md:p-10 max-w-7xl mx-auto min-h-screen">
<div className="flex flex-col gap-2">
<h2 className="text-3xl font-bold tracking-tight text-foreground uppercase">Teras Yönetim Paneli</h2>
<p className="text-muted-foreground text-lg">
Hoş geldiniz, {session?.user?.name || session?.user?.email}. İşte restoranınızın genel görünümü.
</p>
</div>
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-4">
{/* Placeholder Stat Cards */}
{[
{ name: 'Bugünkü Rezervasyonlar', stat: '24', trend: '+4 dünden' },
{ name: 'Aktif Masalar', stat: '12 / 30', trend: '%40 Doluluk' },
{ name: 'Aylık Ziyaretçi', stat: '1,452', trend: '+%12 geçen aya göre' },
{ name: 'Stok: Dry Aged Et', stat: '45 porsiyon', trend: 'Kritik seviyeye yakın' },
].map((item) => (
<div
key={item.name}
className="rounded-lg bg-card border border-border/50 p-6 shadow-sm hover:border-primary/30 transition-colors"
>
<dt className="truncate text-sm font-medium text-muted-foreground uppercase tracking-wider">{item.name}</dt>
<dd className="mt-2 text-4xl font-bold tracking-tight text-primary">
{item.stat}
</dd>
<p className="mt-2 text-xs text-muted-foreground">{item.trend}</p>
</div>
))}
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
<div className="rounded-lg bg-card border border-border/50 shadow-sm">
<div className="p-6 border-b border-border/50">
<h3 className="text-lg font-bold text-foreground uppercase tracking-wider">Son Rezervasyon Talepleri</h3>
</div>
<div className="p-6">
<div className="space-y-4">
{[
{ name: 'Ahmet Yılmaz', time: 'Bu akşam 20:00', size: '4 Kişi', status: 'Onay Bekliyor' },
{ name: 'Ayşe Demir', time: 'Yarın 19:30', size: '2 Kişi', status: 'Onaylandı' },
{ name: 'Mehmet Kaya', time: '18 Haziran 21:00', size: '6 Kişi', status: 'Onaylandı' },
].map((req, i) => (
<div key={i} className="flex justify-between items-center p-4 bg-background rounded border border-border/30">
<div>
<p className="font-bold text-foreground">{req.name}</p>
<p className="text-sm text-muted-foreground">{req.time} {req.size}</p>
</div>
<span className={`text-xs px-2 py-1 rounded-full uppercase tracking-wider font-bold ${req.status === 'Onay Bekliyor' ? 'bg-secondary/20 text-secondary' : 'bg-green-500/20 text-green-500'}`}>
{req.status}
</span>
</div>
))}
</div>
</div>
</div>
<div className="rounded-lg bg-card border border-border/50 shadow-sm">
<div className="p-6 border-b border-border/50">
<h3 className="text-lg font-bold text-foreground uppercase tracking-wider">Sistem & İletişim Bildirimleri</h3>
</div>
<div className="p-6">
<div className="space-y-4">
<div className="p-4 bg-background rounded border border-border/30">
<p className="text-sm text-foreground"><strong>Yeni Mesaj:</strong> Müşteri memnuniyet anketi hakkında (Zeynep Ç.)</p>
<p className="text-xs text-muted-foreground mt-1">2 saat önce</p>
</div>
<div className="p-4 bg-background rounded border border-border/30">
<p className="text-sm text-foreground"><strong>Sistem Uyarı:</strong> Veritabanı yedeği başarıyla alındı.</p>
<p className="text-xs text-muted-foreground mt-1">Dün 03:00</p>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
+59
View File
@@ -0,0 +1,59 @@
'use client'
import { useTranslations } from 'next-intl'
import { motion } from 'framer-motion'
import Image from 'next/image'
const galleryImages = [
"https://images.unsplash.com/photo-1544025162-d76694265947?q=80&w=800&auto=format&fit=crop",
"https://images.unsplash.com/photo-1555939594-58d7cb561ad1?q=80&w=800&auto=format&fit=crop",
"https://images.unsplash.com/photo-1600891964092-4316c288032e?q=80&w=800&auto=format&fit=crop",
"https://images.unsplash.com/photo-1594041680534-e8c8cdebd659?q=80&w=800&auto=format&fit=crop",
"https://images.unsplash.com/photo-1603048297172-c92544798d5e?q=80&w=800&auto=format&fit=crop",
"https://images.unsplash.com/photo-1514933651103-005eec06c04b?q=80&w=800&auto=format&fit=crop"
]
export default function GalleryPage() {
const nav = useTranslations('nav')
return (
<div className="container mx-auto px-4 py-24 min-h-screen flex flex-col items-center">
<motion.div
className="text-center mb-16"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
>
<h1 className="text-4xl md:text-5xl font-bold text-primary mb-4 uppercase tracking-wider">
{nav('gallery')}
</h1>
<p className="text-lg text-muted-foreground">
Ateşin ve lezzetin sanata dönüştüğü anlar.
</p>
</motion.div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 max-w-7xl mx-auto">
{galleryImages.map((src, idx) => (
<motion.div
key={idx}
initial={{ opacity: 0, scale: 0.9 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true, margin: "-50px" }}
transition={{ duration: 0.5, delay: idx * 0.1 }}
className="aspect-square relative overflow-hidden rounded-lg group"
>
<Image
src={src}
alt={`Gallery Image ${idx + 1}`}
fill
className="object-cover transition-transform duration-700 group-hover:scale-110"
/>
<div className="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity duration-500 flex items-center justify-center">
<span className="text-white font-bold tracking-wider uppercase">Teras Steakhouse</span>
</div>
</motion.div>
))}
</div>
</div>
)
}
+99
View File
@@ -0,0 +1,99 @@
import { getTranslations, setRequestLocale } from 'next-intl/server'
import { MapPin, Phone, Mail, Send } from 'lucide-react'
export default async function ContactPage({ params }: { params: Promise<{ locale: string }> }) {
const { locale } = await params
setRequestLocale(locale)
const t = await getTranslations('contact')
return (
<div className="container mx-auto px-4 py-24">
<div className="max-w-5xl mx-auto">
<h1 className="text-4xl md:text-5xl font-bold text-primary mb-12 text-center uppercase tracking-wider">
{t('title')}
</h1>
<div className="grid grid-cols-1 md:grid-cols-2 gap-12">
{/* Contact Info */}
<div className="space-y-8 bg-card p-8 rounded-lg border border-border/50">
<h2 className="text-2xl font-bold text-foreground uppercase">Teras Steakhouse</h2>
<div className="space-y-6">
<div className="flex items-start gap-4">
<MapPin className="w-6 h-6 text-primary shrink-0" />
<div>
<h3 className="font-semibold text-foreground">Adres</h3>
<p className="text-muted-foreground mt-1">{t('address')}</p>
</div>
</div>
<div className="flex items-start gap-4">
<Phone className="w-6 h-6 text-primary shrink-0" />
<div>
<h3 className="font-semibold text-foreground">Telefon</h3>
<a href={`tel:${t('phone').replace(/\s/g, '')}`} className="text-muted-foreground hover:text-primary transition-colors mt-1 block">
{t('phone')}
</a>
</div>
</div>
<div className="flex items-start gap-4">
<Mail className="w-6 h-6 text-primary shrink-0" />
<div>
<h3 className="font-semibold text-foreground">E-posta</h3>
<a href={`mailto:${t('email')}`} className="text-muted-foreground hover:text-primary transition-colors mt-1 block">
{t('email')}
</a>
</div>
</div>
</div>
</div>
{/* Contact Form */}
<div className="bg-card p-8 rounded-lg border border-border/50">
<form className="space-y-6" action="#" method="POST">
<div className="space-y-2">
<label htmlFor="name" className="text-sm font-medium text-foreground">
{t('form_name')}
</label>
<input
id="name"
type="text"
required
className="w-full bg-background border border-border rounded-md px-4 py-3 focus:outline-none focus:ring-2 focus:ring-primary/50 text-foreground"
/>
</div>
<div className="space-y-2">
<label htmlFor="email" className="text-sm font-medium text-foreground">
{t('form_email')}
</label>
<input
id="email"
type="email"
required
className="w-full bg-background border border-border rounded-md px-4 py-3 focus:outline-none focus:ring-2 focus:ring-primary/50 text-foreground"
/>
</div>
<div className="space-y-2">
<label htmlFor="message" className="text-sm font-medium text-foreground">
{t('form_message')}
</label>
<textarea
id="message"
required
rows={5}
className="w-full bg-background border border-border rounded-md px-4 py-3 focus:outline-none focus:ring-2 focus:ring-primary/50 text-foreground resize-none"
/>
</div>
<button
type="submit"
className="w-full bg-primary text-white font-bold uppercase tracking-wider py-4 rounded-md hover:bg-primary/90 transition-colors flex items-center justify-center gap-2"
>
{t('form_submit')}
<Send className="w-4 h-4" />
</button>
</form>
</div>
</div>
</div>
</div>
)
}
+66
View File
@@ -0,0 +1,66 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import { NextIntlClientProvider } from 'next-intl';
import { getMessages, setRequestLocale } from 'next-intl/server';
import { notFound } from 'next/navigation';
import { routing } from '@/i18n/routing';
import { Header } from "@/components/layout/Header";
import { Footer } from "@/components/layout/Footer";
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: "Teras Steakhouse | Inspired by Open Fire",
description: "Premium steakhouse experience with dry aged meat, argentine grill and fine wines.",
};
export function generateStaticParams() {
return routing.locales.map((locale) => ({locale}));
}
export default async function RootLayout({
children,
params
}: Readonly<{
children: React.ReactNode;
params: Promise<{ locale: string }>;
}>) {
const { locale } = await params;
if (!routing.locales.includes(locale as any)) {
notFound();
}
setRequestLocale(locale);
const messages = await getMessages();
return (
<html
lang={locale}
className={`dark ${geistSans.variable} ${geistMono.variable} h-full antialiased`}
data-scroll-behavior="smooth"
>
<head>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400..900;1,400..900&family=Inter:wght@100..900&family=Montserrat:wght@100..900&family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" />
</head>
<body className="min-h-full flex flex-col bg-background text-foreground" suppressHydrationWarning>
<NextIntlClientProvider messages={messages}>
<Header />
<main className="flex-1">
{children}
</main>
<Footer />
</NextIntlClientProvider>
</body>
</html>
);
}
+96
View File
@@ -0,0 +1,96 @@
'use client'
import { useState } from 'react'
import { signIn } from 'next-auth/react'
import { useRouter } from 'next/navigation'
import { Flame } from 'lucide-react'
export default function LoginPage() {
const router = useRouter()
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState('')
const [loading, setLoading] = useState(false)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setLoading(true)
setError('')
const result = await signIn('credentials', {
redirect: false,
email,
password,
})
if (result?.error) {
setError('Geçersiz e-posta veya şifre')
setLoading(false)
} else {
router.push('/admin')
router.refresh()
}
}
return (
<div className="min-h-screen flex items-center justify-center px-4">
<div className="w-full max-w-md bg-card rounded-xl shadow-lg border border-border/50 overflow-hidden">
<div className="p-8">
<div className="text-center mb-8 flex flex-col items-center">
<Flame className="w-12 h-12 text-primary mb-4" />
<h1 className="text-2xl font-bold uppercase tracking-wider text-foreground">Teras Steakhouse</h1>
<p className="text-sm text-muted-foreground mt-2 uppercase tracking-wide">Yönetici Girişi</p>
</div>
{error && (
<div className="bg-destructive/10 text-destructive p-3 rounded-md text-sm mb-6 border border-destructive/20">
{error}
</div>
)}
<form onSubmit={handleSubmit} className="space-y-5">
<div>
<label className="block text-sm font-medium text-foreground mb-1 uppercase tracking-wide" htmlFor="email">
E-posta
</label>
<input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
className="w-full px-4 py-3 border border-border rounded-md focus:ring-2 focus:ring-primary/50 focus:border-primary/50 bg-background text-foreground transition-colors outline-none"
placeholder="admin@ayris.tech"
/>
</div>
<div>
<label className="block text-sm font-medium text-foreground mb-1 uppercase tracking-wide" htmlFor="password">
Şifre
</label>
<input
id="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
className="w-full px-4 py-3 border border-border rounded-md focus:ring-2 focus:ring-primary/50 focus:border-primary/50 bg-background text-foreground transition-colors outline-none"
placeholder="••••••••"
/>
</div>
<button
type="submit"
disabled={loading}
className="w-full bg-primary hover:bg-primary/90 text-primary-foreground font-bold py-3 px-4 rounded-md transition-colors uppercase tracking-wider disabled:opacity-70 disabled:cursor-not-allowed mt-2"
>
{loading ? 'Giriş yapılıyor...' : 'Giriş Yap'}
</button>
</form>
<div className="mt-8 pt-6 border-t border-border/50 text-center text-xs text-muted-foreground">
Demo: admin@ayris.tech / admin
</div>
</div>
</div>
</div>
)
}
+195
View File
@@ -0,0 +1,195 @@
'use client'
import { useTranslations } from 'next-intl'
import { useEffect } from 'react'
export default function MenuPage() {
const t = useTranslations('menu')
useEffect(() => {
// Intersection Observer to highlight current menu category
const sections = document.querySelectorAll('section[id]');
const navLinks = document.querySelectorAll('a[href^="#"]');
const observerOptions = {
root: null,
threshold: 0.5,
rootMargin: '0px'
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const id = entry.target.getAttribute('id');
navLinks.forEach(link => {
if (link.getAttribute('href') === `#${id}`) {
link.classList.add('text-tertiary', 'font-bold');
link.classList.remove('text-on-surface-variant');
} else {
link.classList.remove('text-tertiary', 'font-bold');
link.classList.add('text-on-surface-variant');
}
});
}
});
}, observerOptions);
sections.forEach(section => observer.observe(section));
// Subtle parallax effect on mouse move for cards
const handleMouseMove = (e: MouseEvent) => {
const cards = document.querySelectorAll('.copper-glow');
cards.forEach(card => {
const rect = card.getBoundingClientRect();
const cardX = rect.left + rect.width / 2;
const cardY = rect.top + rect.height / 2;
const angleX = (e.clientY - cardY) / 50;
const angleY = (cardX - e.clientX) / 50;
(card as HTMLElement).style.transform = `perspective(1000px) rotateX(${angleX}deg) rotateY(${angleY}deg)`;
});
};
document.addEventListener('mousemove', handleMouseMove);
return () => document.removeEventListener('mousemove', handleMouseMove);
}, [])
return (
<main className="relative">
{/* Hero Header */}
<section className="relative h-[614px] flex flex-col items-center justify-center text-center px-[var(--spacing-gutter)] overflow-hidden">
<div className="relative z-10 space-y-4">
<h1 className="font-display-lg text-display-lg-mobile md:text-display-lg italic">{t('title')}</h1>
<div className="w-32 h-px bg-tertiary mx-auto opacity-60"></div>
<p className="font-label-caps text-label-caps text-on-surface-variant tracking-[0.3em] uppercase">{t('subtitle')}</p>
</div>
</section>
{/* Category Navigation (Sticky) */}
<div className="sticky top-[72px] z-40 bg-surface/80 backdrop-blur-xl border-b border-outline-variant/10">
<div className="max-w-[var(--spacing-container-max)] mx-auto px-[var(--spacing-gutter)] overflow-x-auto no-scrollbar">
<div className="flex justify-center gap-8 md:gap-16 py-4 whitespace-nowrap">
<a className="font-label-caps text-[10px] md:text-label-caps text-tertiary font-bold hover:text-tertiary transition-colors uppercase" href="#starters">{t('nav_starters')}</a>
<a className="font-label-caps text-[10px] md:text-label-caps text-on-surface-variant hover:text-tertiary transition-colors uppercase" href="#prime-cuts">{t('nav_prime_cuts')}</a>
<a className="font-label-caps text-[10px] md:text-label-caps text-on-surface-variant hover:text-tertiary transition-colors uppercase" href="#sides">{t('nav_sides')}</a>
<a className="font-label-caps text-[10px] md:text-label-caps text-on-surface-variant hover:text-tertiary transition-colors uppercase" href="#dessert">{t('nav_dessert')}</a>
</div>
</div>
</div>
{/* Menu Sections */}
<div className="max-w-[var(--spacing-container-max)] mx-auto px-[var(--spacing-gutter)] space-y-[var(--spacing-section-padding)] py-[var(--spacing-section-padding)]">
{/* Starters Section */}
<section className="scroll-mt-32" id="starters">
<div className="grid grid-cols-1 md:grid-cols-12 gap-[var(--spacing-gutter)] items-start">
<div className="md:col-span-4 sticky top-48">
<h2 className="font-headline-md text-headline-md mb-4 text-tertiary">{t('starters_title')}</h2>
<p className="font-body-md text-on-surface-variant leading-relaxed">{t('starters_desc')}</p>
<div className="mt-8 h-24 w-px bg-gradient-to-b from-tertiary to-transparent opacity-30 hidden md:block"></div>
</div>
<div className="md:col-span-8 space-y-12">
<div className="group border-b border-outline-variant/10 pb-8 hover:border-tertiary/30 transition-colors duration-500">
<div className="flex justify-between items-baseline mb-2">
<h3 className="font-headline-sm text-headline-sm group-hover:text-tertiary transition-colors">{t('starter1_title')}</h3>
<span className="font-label-caps text-label-caps text-tertiary">22</span>
</div>
<p className="font-body-md text-on-surface-variant">{t('starter1_desc')}</p>
</div>
<div className="group border-b border-outline-variant/10 pb-8 hover:border-tertiary/30 transition-colors duration-500">
<div className="flex justify-between items-baseline mb-2">
<h3 className="font-headline-sm text-headline-sm group-hover:text-tertiary transition-colors">{t('starter2_title')}</h3>
<span className="font-label-caps text-label-caps text-tertiary">34</span>
</div>
<p className="font-body-md text-on-surface-variant">{t('starter2_desc')}</p>
</div>
</div>
</div>
</section>
{/* Featured Highlight - Prime Cuts */}
<section className="scroll-mt-32" id="prime-cuts">
<div className="relative overflow-hidden rounded-lg aspect-[16/9] mb-16">
<img className="w-full h-full object-cover" src="https://lh3.googleusercontent.com/aida-public/AB6AXuBZQFwOXiMm8B7hPOumV-GiiGFbt3Pl5c6NEOUSC3JFlzzahLgcckvjpa46Q5Ro6XsUyQhroFuxT9OFJEAUt5EpHxEi-C4NXILyPUk-HfKRP2ljE5UAYHdVTAa3q7FP_Tfp0a7ZDvugWHsIjKJBLDDTOC2czJwnC5CvJGL_WYAjtnO5DiNQdQGYe_vDmgTbKnr07TgIu6KUjFnxNr5_3MyOA35vKePtjK51nR_IDbAkZu5GrxfQByM-CE8f8-lPoksDABh3Z2NQD83x" alt="Tomahawk" />
<div className="vignette-overlay-linear absolute inset-0 flex flex-col justify-end p-[var(--spacing-gutter)] md:p-12">
<div className="max-w-xl">
<span className="font-label-caps text-label-caps text-tertiary mb-4 block tracking-widest uppercase">{t('prime_cuts_tag')}</span>
<h2 className="font-display-lg text-display-lg-mobile md:text-headline-md text-white mb-4">{t('prime_cuts_title')}</h2>
<p className="font-body-lg text-on-surface-variant mb-6">{t('prime_cuts_desc')}</p>
<span className="font-label-caps text-label-caps text-tertiary border border-tertiary/40 px-6 py-2 inline-block">{t('mkt_price')}</span>
</div>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-[var(--spacing-gutter)]">
<div className="bg-surface-container-low p-8 copper-glow border border-outline-variant/20 hover:border-tertiary/40 transition-all duration-300">
<h3 className="font-headline-sm text-headline-sm mb-2">{t('cut1_title')}</h3>
<p className="font-body-md text-on-surface-variant mb-4">{t('cut1_desc')}</p>
<span className="font-label-caps text-label-caps text-tertiary">58</span>
</div>
<div className="bg-surface-container-low p-8 copper-glow border border-outline-variant/20 hover:border-tertiary/40 transition-all duration-300">
<h3 className="font-headline-sm text-headline-sm mb-2">{t('cut2_title')}</h3>
<p className="font-body-md text-on-surface-variant mb-4">{t('cut2_desc')}</p>
<span className="font-label-caps text-label-caps text-tertiary">145</span>
</div>
<div className="bg-surface-container-low p-8 copper-glow border border-outline-variant/20 hover:border-tertiary/40 transition-all duration-300">
<h3 className="font-headline-sm text-headline-sm mb-2">{t('cut3_title')}</h3>
<p className="font-body-md text-on-surface-variant mb-4">{t('cut3_desc')}</p>
<span className="font-label-caps text-label-caps text-tertiary">74</span>
</div>
</div>
</section>
{/* Sides Section */}
<section className="scroll-mt-32" id="sides">
<div className="section-divider mb-16"></div>
<div className="text-center max-w-2xl mx-auto mb-16">
<h2 className="font-headline-md text-headline-md mb-4">{t('sides_title')}</h2>
<p className="font-body-md text-on-surface-variant">{t('sides_desc')}</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-16 gap-y-12">
<div className="flex justify-between items-start border-b border-outline-variant/10 pb-4">
<div>
<h4 className="font-label-caps text-label-caps uppercase tracking-wider mb-1">{t('side1_title')}</h4>
<p className="text-sm text-on-surface-variant">{t('side1_desc')}</p>
</div>
<span className="font-label-caps text-label-caps text-tertiary">18</span>
</div>
<div className="flex justify-between items-start border-b border-outline-variant/10 pb-4">
<div>
<h4 className="font-label-caps text-label-caps uppercase tracking-wider mb-1">{t('side2_title')}</h4>
<p className="text-sm text-on-surface-variant">{t('side2_desc')}</p>
</div>
<span className="font-label-caps text-label-caps text-tertiary">16</span>
</div>
</div>
</section>
{/* Dessert Section */}
<section className="scroll-mt-32" id="dessert">
<div className="grid grid-cols-1 md:grid-cols-12 gap-[var(--spacing-gutter)] items-center">
<div className="md:col-span-7 order-2 md:order-1 space-y-12">
<div className="group border-l-2 border-tertiary/20 pl-8 pb-4 hover:border-tertiary transition-colors duration-500">
<h3 className="font-headline-sm text-headline-sm mb-2 group-hover:text-tertiary transition-colors">{t('dessert1_title')}</h3>
<p className="font-body-md text-on-surface-variant mb-2">{t('dessert1_desc')}</p>
<span className="font-label-caps text-label-caps text-tertiary">18</span>
</div>
<div className="group border-l-2 border-tertiary/20 pl-8 pb-4 hover:border-tertiary transition-colors duration-500">
<h3 className="font-headline-sm text-headline-sm mb-2 group-hover:text-tertiary transition-colors">{t('dessert2_title')}</h3>
<p className="font-body-md text-on-surface-variant mb-2">{t('dessert2_desc')}</p>
<span className="font-label-caps text-label-caps text-tertiary">16</span>
</div>
</div>
<div className="md:col-span-5 order-1 md:order-2 mb-8 md:mb-0">
<div className="relative group">
<div className="absolute -inset-4 bg-tertiary/10 blur-xl group-hover:bg-tertiary/20 transition-all duration-700"></div>
<img className="relative z-10 w-full h-80 object-cover rounded-lg" src="https://lh3.googleusercontent.com/aida-public/AB6AXuBPy2xGbUE9MZqJC4F5ZVPD7fP5S1Eklhu3oZjiyREkC4_UyW4G5BxCOwOISwKzdsc3fVI-xIo_4DIV9frboEX0wEkj3mZvUKZBPXgB_I14udTZry1riWVcv1IrgaFtjN3GdtKy8SrIK03SCgZZ4kVzsBH-sxAsRpxBjgy8VU_w_-Ohc5n1x0yjyuNxrRWWM2PbFFA6mFv-4JV6qcV3cA9N-hd_TUVUsXGs9MGfQPNosGHEF_eiOd-Wecb6sNAUoiH_Rl0gl1l7IZLF" alt="Chocolate Fondant" />
<h2 className="font-headline-md text-headline-md mt-6 text-tertiary italic">{t('dessert_title')}</h2>
</div>
</div>
</div>
</section>
</div>
</main>
)
}
+193
View File
@@ -0,0 +1,193 @@
'use client'
import { useTranslations } from 'next-intl'
import { Link } from '@/i18n/routing'
import { useEffect } from 'react'
export default function HomePage() {
const t = useTranslations('home')
useEffect(() => {
// Micro-interaction for buttons
const buttons = document.querySelectorAll('button');
buttons.forEach(btn => {
btn.addEventListener('mousedown', () => btn.classList.add('scale-95'));
btn.addEventListener('mouseup', () => btn.classList.remove('scale-95'));
btn.addEventListener('mouseleave', () => btn.classList.remove('scale-95'));
});
// Simple Fade In on Scroll
const observerOptions = { threshold: 0.1 };
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('opacity-100');
entry.target.classList.remove('translate-y-10');
}
});
}, observerOptions);
const sections = document.querySelectorAll('section:not(:first-child)');
sections.forEach(section => {
section.classList.add('transition-all', 'duration-1000', 'translate-y-10', 'opacity-0');
observer.observe(section);
});
}, [])
return (
<main>
{/* Hero Section */}
<section className="relative h-screen flex items-center justify-center overflow-hidden transition-all duration-1000">
<div className="absolute inset-0 z-0">
<img className="w-full h-full object-cover" src="https://lh3.googleusercontent.com/aida-public/AB6AXuALRLjbZvJQRlnpOqK0FJXRpeoI4Q_PObykBtlxjxHFCLy_rpnzaUpvICS9bCJFLUNurkL6BnQYbkxPxHITsbreYTPJvVgybXvzTDIN37BpLrQBD34WDr81Es58HM112IRETzzryapmv-CURUfWMFTj5MblCZ9CUmI6LA5BaCnxiQFBgHkK6i09sV42FFOXuVMBMcyufKjkM2vStSHFYu4inukZsoPWxh8ydf9WnkTg0TYEkypsIK4T8LqZoGNav8jPB7R6aMdV6D01" alt="Hero Steak" />
<div className="absolute inset-0 chiaroscuro-gradient"></div>
<div className="absolute inset-0 vignette-overlay"></div>
</div>
<div className="relative z-10 text-center px-[var(--spacing-gutter)] max-w-4xl">
<p className="font-label-caps text-label-caps text-tertiary mb-4 tracking-[0.3em] uppercase">{t('hero.subtitle')}</p>
<h1 className="font-display-lg text-display-lg-mobile md:text-display-lg text-on-surface mb-6">{t('hero.title')}</h1>
<p className="font-body-lg text-body-lg text-on-surface-variant max-w-2xl mx-auto mb-10">
{t('hero.desc')}
</p>
<div className="flex flex-col md:flex-row gap-4 justify-center">
<Link href="/menu" className="bg-secondary-container text-white px-10 py-4 font-label-caps text-label-caps border border-transparent copper-glow transition-all uppercase inline-block">{t('hero.explore_menu')}</Link>
<Link href="#philosophy" className="bg-transparent text-secondary border border-secondary/50 px-10 py-4 font-label-caps text-label-caps hover:bg-secondary/10 transition-all uppercase inline-block">{t('hero.our_philosophy')}</Link>
</div>
</div>
<div className="absolute bottom-10 left-1/2 -translate-x-1/2 flex flex-col items-center gap-2">
<span className="font-label-caps text-[10px] text-outline tracking-widest uppercase">Scroll</span>
<div className="w-[1px] h-12 bg-gradient-to-b from-tertiary to-transparent"></div>
</div>
</section>
{/* The Ignis Philosophy */}
<section id="philosophy" className="py-[var(--spacing-section-padding)] bg-surface-container-lowest relative scroll-mt-20">
<div className="max-w-[var(--spacing-container-max)] mx-auto px-[var(--spacing-gutter)] grid grid-cols-1 md:grid-cols-12 gap-12 items-center">
<div className="md:col-span-5 relative group">
<div className="aspect-[4/5] overflow-hidden border border-outline-variant/20">
<img className="w-full h-full object-cover grayscale hover:grayscale-0 transition-all duration-700" src="https://static.wixstatic.com/media/19c276_8160f1c03e0343f1a2c4f456157a74e2~mv2.jpg/v1/fill/w_327,h_479,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/19c276_8160f1c03e0343f1a2c4f456157a74e2~mv2.jpg" alt="Aged Oak" />
</div>
<div className="absolute -bottom-6 -right-6 w-32 h-32 bg-surface-container border border-outline-variant/30 hidden md:flex items-center justify-center p-4">
<p className="font-label-caps text-[10px] text-tertiary text-center leading-relaxed">{t('philosophy.badge')}</p>
</div>
</div>
<div className="md:col-span-7 md:pl-12">
<span className="font-label-caps text-label-caps text-tertiary mb-6 block uppercase">{t('philosophy.tag')}</span>
<h2 className="font-headline-md text-headline-md text-on-surface mb-8 max-w-md">{t('philosophy.title')}</h2>
<div className="w-20 h-[1px] bg-tertiary mb-8"></div>
<p className="font-body-lg text-body-lg text-on-surface-variant mb-6">
{t('philosophy.desc1')}
</p>
<p className="font-body-md text-body-md text-outline">
{t('philosophy.desc2')}
</p>
</div>
</div>
</section>
{/* Signature Cuts */}
<section className="py-[var(--spacing-section-padding)] bg-surface">
<div className="max-w-[var(--spacing-container-max)] mx-auto px-[var(--spacing-gutter)]">
<div className="text-center mb-16">
<span className="font-label-caps text-label-caps text-secondary mb-4 block uppercase">{t('cuts.tag')}</span>
<h2 className="font-headline-md text-headline-md text-on-surface">{t('cuts.title')}</h2>
</div>
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
<div className="md:col-span-2 md:row-span-2 group relative overflow-hidden bg-surface-container-high aspect-square md:aspect-auto">
<img className="w-full h-full object-cover transition-transform duration-1000 group-hover:scale-105" src="https://static.wixstatic.com/media/19c276_ce72add7ebdb407597224e87e838bd70~mv2.jpg/v1/fill/w_327,h_479,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/19c276_ce72add7ebdb407597224e87e838bd70~mv2.jpg" alt="Tomahawk" />
<div className="absolute inset-0 bg-gradient-to-t from-background via-transparent to-transparent"></div>
<div className="absolute bottom-0 left-0 p-8">
<p className="font-label-caps text-[10px] text-secondary mb-2 uppercase">{t('cuts.dry_aged')}</p>
<h3 className="font-headline-sm text-headline-sm text-on-surface mb-2">{t('cuts.t_bone')}</h3>
<p className="font-body-md text-on-surface-variant opacity-0 group-hover:opacity-100 transition-opacity duration-500">{t('cuts.t_bone_desc')}</p>
</div>
</div>
<div className="group relative overflow-hidden aspect-square bg-surface-container">
<img className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110" src="https://lh3.googleusercontent.com/aida-public/AB6AXuBXylHVJVF2D1Ox5qiz8sQwSkUlOwci8kh62Sv8cdmxzU91j1ML3MymH-aTP2nIbmGZvn0W_AgmZKSfXQLI9YNSaYcaxoTh_VRv8NWU34xPwm3md4_ETDTR09cz2nTIfeBcrapG8PY-alnCnt3xFCrgeo0icFENiC5pSFfLxxvuRs0pnSYQgCNtf9AVc3s3PNJeOUW8hApoGrkjWai33iKnKA-JpBDZ6U-R0mW7AUS3sSZNBGfa98-KqVRswC-DiJI8DMHj1qoZan3C" alt="Tomahawk" />
<div className="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center p-4">
<div className="text-center">
<h4 className="font-headline-sm text-headline-sm text-on-surface">{t('cuts.tomahawk')}</h4>
<span className="font-label-caps text-label-caps text-tertiary">{t('cuts.tomahawk_desc')}</span>
</div>
</div>
</div>
<div className="group relative overflow-hidden aspect-square bg-surface-container">
<img className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110" src="https://lh3.googleusercontent.com/aida-public/AB6AXuDczwEijlcMbRMPQy8Dci6cx4PmffAeGbv0iOvph56bRTXI1t9Y1dReFXXp4whLg-EblfFEBNgDq0XrfPe2N1LGtQemcc5U9QHBJaEVgoGO2VlKW8OmFtK2L9KAuwBtUpGyQXcxm_tRD3PsjMOL3IhwPO2GqqTGD-2rnrZJ1GR0Y8awTQK8PhO114GuvBt9OVWAdz6iRSP4en5lNBJYCKcTGOL5Vj43_tM60tpBCAyfz2igf-RBo63GjkfoWMtGVul77nHFfCUw2rFi" alt="New York" />
<div className="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center p-4">
<div className="text-center">
<h4 className="font-headline-sm text-headline-sm text-on-surface">{t('cuts.new_york')}</h4>
<span className="font-label-caps text-label-caps text-tertiary">{t('cuts.new_york_desc')}</span>
</div>
</div>
</div>
<div className="md:col-span-2 group relative h-64 overflow-hidden bg-surface-container-high">
<div className="absolute inset-0 flex items-center justify-center px-12 z-10 pointer-events-none">
<div className="text-center">
<h3 className="font-headline-sm text-headline-sm text-on-surface mb-2">{t('cuts.dry_aged')}</h3>
<p className="font-body-md text-on-surface-variant">{t('cuts.dry_aged_desc')}</p>
</div>
</div>
<img className="w-full h-full object-cover opacity-40 grayscale group-hover:grayscale-0 group-hover:opacity-60 transition-all duration-700" src="https://static.wixstatic.com/media/19c276_3590e6b88f54446e93c31aeb65933107~mv2.jpg/v1/fill/w_326,h_479,al_b,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/19c276_3590e6b88f54446e93c31aeb65933107~mv2.jpg" alt="Porterhouse" />
</div>
</div>
</div>
</section>
{/* The Cellar */}
<section className="py-[var(--spacing-section-padding)] bg-surface-container-lowest relative overflow-hidden">
<div className="absolute left-1/2 top-0 bottom-0 w-[1px] bg-gradient-to-b from-transparent via-tertiary/20 to-transparent"></div>
<div className="max-w-[var(--spacing-container-max)] mx-auto px-[var(--spacing-gutter)] grid grid-cols-1 md:grid-cols-2 gap-20 items-center">
<div className="order-2 md:order-1">
<span className="font-label-caps text-label-caps text-secondary-container mb-6 block uppercase">{t('cellar.tag')}</span>
<h2 className="font-display-lg-mobile md:font-display-lg text-display-lg-mobile md:text-display-lg text-on-surface mb-8">{t('cellar.title')}</h2>
<p className="font-body-lg text-body-lg text-on-surface-variant mb-8">
{t('cellar.desc')}
</p>
<ul className="space-y-6 mb-10">
<li className="flex justify-between items-end border-b border-outline-variant/30 pb-2">
<div>
<h4 className="font-headline-sm text-[18px] text-on-surface">{t('cellar.wine1_name')}</h4>
<p className="font-body-md text-outline text-sm">{t('cellar.wine1_desc')}</p>
</div>
</li>
<li className="flex justify-between items-end border-b border-outline-variant/30 pb-2">
<div>
<h4 className="font-headline-sm text-[18px] text-on-surface">{t('cellar.wine2_name')}</h4>
<p className="font-body-md text-outline text-sm">{t('cellar.wine2_desc')}</p>
</div>
</li>
<li className="flex justify-between items-end border-b border-outline-variant/30 pb-2">
<div>
<h4 className="font-headline-sm text-[18px] text-on-surface">{t('cellar.wine3_name')}</h4>
<p className="font-body-md text-outline text-sm">{t('cellar.wine3_desc')}</p>
</div>
</li>
</ul>
<Link href="/menu" className="font-label-caps text-label-caps text-secondary flex items-center gap-2 group uppercase">
{t('cellar.view_list')}
<span className="material-symbols-outlined group-hover:translate-x-2 transition-transform">arrow_forward</span>
</Link>
</div>
<div className="order-1 md:order-2 relative">
<div className="aspect-[3/4] bg-surface-container relative">
<img className="w-full h-full object-cover" src="https://lh3.googleusercontent.com/aida-public/AB6AXuAjziyIdiB8l1fAyEZhCWldYGlClbeZAPQqY86so0hVbUW93mJpPvRcV1kmn2tAP0w8c2nm8MyBBoyJ-7GOU5WchtcLZCv33NWfNevgZqm0wX4nISlnjBN1RmdVBaUfhlyc84XquNYkm1jcA8247tT3HX0x0vkCS5rHzyGl3alUyHWFqIn0awR0s5tzCZ_PBX8X7XlUfY5umq4CGgIUY7_1ly9LIx3ZaYO6p9CgXGisNX3-rEJf0kQjBVPHRzpFsEDFjkatn8WvsoZP" alt="Wine Cellar" />
<div className="absolute -top-10 -left-10 w-40 h-40 border border-secondary/20 -z-10"></div>
<div className="absolute -bottom-10 -right-10 w-40 h-40 border border-secondary/20 -z-10"></div>
</div>
</div>
</div>
</section>
{/* CTA Section */}
<section className="py-24 bg-surface text-center">
<div className="max-w-2xl mx-auto px-[var(--spacing-gutter)]">
<h2 className="font-headline-md text-headline-md text-on-surface mb-8">{t('cta.title')}</h2>
<p className="font-body-md text-on-surface-variant mb-12">{t('cta.desc')}</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Link href="/rezervasyon" className="bg-secondary-container text-white px-8 py-3 font-label-caps text-label-caps hover:bg-secondary-container/80 transition-all uppercase">{t('cta.button')}</Link>
</div>
</div>
</section>
</main>
)
}
+185
View File
@@ -0,0 +1,185 @@
'use client'
import { useTranslations } from 'next-intl'
import { useState, useEffect } from 'react'
export default function ReservationPage() {
const t = useTranslations('reservation')
const [isSubmitted, setIsSubmitted] = useState(false)
const [formData, setFormData] = useState({
date: '',
time: '',
guests: '2',
occasion: '',
requests: ''
})
useEffect(() => {
// Parallax effect for hero
const handleScroll = () => {
const scrolled = window.pageYOffset;
const heroImage = document.querySelector('.hero-parallax') as HTMLElement;
if (heroImage) {
heroImage.style.transform = `scale(1.05) translateY(${scrolled * 0.3}px)`;
}
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
setIsSubmitted(true)
}
return (
<main>
{/* Hero Section */}
<section className="relative h-[1024px] flex items-center justify-center overflow-hidden">
<div className="absolute inset-0 z-0">
<img alt="Teras Dining Room" className="hero-parallax w-full h-full object-cover blur-[4px] brightness-[0.3] scale-105 transition-transform" src="https://lh3.googleusercontent.com/aida-public/AB6AXuAXZYL1k1MqQOOTVS2XFNUlHm_ujv_2XGjXeqDdqmW2cAzGhZ4YKMmCEyrzgsxhvecujJ71E-2WyhGynN2dOx7cTZN5kWr0OZHk1YS922FdQrqWKJqnyutqRVAiqO4lSs7jQM_4hVi9a2o4y6rFBXIlTFyHZlUWudF1sTQtjjBmk1Nbdr-YCx5t_lcmRArh0U9Q9y3J3wMuZS-Zl-rNtMzgXSyEnwtoLSPzaSFugpPM3nmzszmAAiAdhDXRJZzycQCK8oPbMuQ5JXqp" />
<div className="absolute inset-0 chiaroscuro-gradient"></div>
</div>
{/* Booking Widget */}
<div className="relative z-10 w-full max-w-2xl px-6" id="booking-container">
{!isSubmitted ? (
<div className="booking-card bg-surface-container/60 p-8 md:p-12 shadow-2xl transition-all duration-700 transform opacity-100 translate-y-0" id="reservation-form-wrapper">
<div className="text-center mb-10">
<span className="font-label-caps text-label-caps text-tertiary mb-4 block">{t('subtitle')}</span>
<h1 className="font-headline-md text-headline-md text-on-surface">{t('title')}</h1>
<div className="w-12 h-px bg-on-tertiary-container mx-auto mt-6"></div>
</div>
<form className="space-y-6" onSubmit={handleSubmit}>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* Date */}
<div className="space-y-2 copper-glow p-0.5 border-b border-outline-variant transition-all duration-300">
<label className="font-label-caps text-[10px] text-on-surface-variant">{t('date')}</label>
<input
type="date"
required
className="w-full bg-transparent border-none focus:ring-0 text-on-surface font-body-md p-0 pb-2"
value={formData.date}
onChange={e => setFormData({...formData, date: e.target.value})}
/>
</div>
{/* Time */}
<div className="space-y-2 copper-glow p-0.5 border-b border-outline-variant transition-all duration-300">
<label className="font-label-caps text-[10px] text-on-surface-variant">{t('time')}</label>
<input
type="time"
required
className="w-full bg-transparent border-none focus:ring-0 text-on-surface font-body-md p-0 pb-2"
value={formData.time}
onChange={e => setFormData({...formData, time: e.target.value})}
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* Guests */}
<div className="space-y-2 copper-glow p-0.5 border-b border-outline-variant transition-all duration-300">
<label className="font-label-caps text-[10px] text-on-surface-variant">{t('guests')}</label>
<select
required
className="w-full bg-transparent border-none focus:ring-0 text-on-surface font-body-md p-0 pb-2 appearance-none"
value={formData.guests}
onChange={e => setFormData({...formData, guests: e.target.value})}
>
<option className="bg-surface" value="1">1 {t('person')}</option>
<option className="bg-surface" value="2">2 {t('person')}</option>
<option className="bg-surface" value="3">3 {t('person')}</option>
<option className="bg-surface" value="4">4 {t('person')}</option>
<option className="bg-surface" value="5+">5+ {t('person')}</option>
</select>
</div>
{/* Occasion */}
<div className="space-y-2 copper-glow p-0.5 border-b border-outline-variant transition-all duration-300">
<label className="font-label-caps text-[10px] text-on-surface-variant">{t('occasion')}</label>
<select
className="w-full bg-transparent border-none focus:ring-0 text-on-surface font-body-md p-0 pb-2 appearance-none"
value={formData.occasion}
onChange={e => setFormData({...formData, occasion: e.target.value})}
>
<option className="bg-surface" value="">{t('occasion_none')}</option>
<option className="bg-surface" value="birthday">{t('occasion_birthday')}</option>
<option className="bg-surface" value="anniversary">{t('occasion_anniversary')}</option>
<option className="bg-surface" value="business">{t('occasion_business')}</option>
</select>
</div>
</div>
{/* Special Requests */}
<div className="space-y-2 copper-glow p-0.5 border-b border-outline-variant transition-all duration-300">
<label className="font-label-caps text-[10px] text-on-surface-variant">{t('requests')}</label>
<textarea
rows={2}
className="w-full bg-transparent border-none focus:ring-0 text-on-surface font-body-md p-0 pb-2 resize-none placeholder:text-outline-variant"
placeholder={t('requests_placeholder')}
value={formData.requests}
onChange={e => setFormData({...formData, requests: e.target.value})}
></textarea>
</div>
<button type="submit" className="w-full bg-secondary-container text-on-secondary-container py-4 font-label-caps text-label-caps tracking-[0.2em] hover:brightness-110 transition-all duration-300 shadow-lg mt-8 active:scale-[0.98]">
{t('submit')}
</button>
</form>
</div>
) : (
<div className="booking-card bg-surface-container/80 p-12 text-center shadow-2xl transition-all duration-700 opacity-100 transform translate-y-0" id="success-state">
<div className="mb-8">
<span className="material-symbols-outlined text-tertiary text-6xl" style={{ fontVariationSettings: "'wght' 200" }}>check_circle</span>
</div>
<h2 className="font-headline-md text-headline-md text-on-surface mb-4">{t('success_title')}</h2>
<p className="text-on-surface-variant font-body-md mb-10 max-w-sm mx-auto">
{t('success_desc')}
</p>
<div className="flex flex-col gap-4 max-w-xs mx-auto">
<div className="flex justify-between border-b border-outline-variant/30 pb-2">
<span className="font-label-caps text-[10px] text-on-surface-variant">{t('guests')}</span>
<span className="font-body-md text-tertiary">{formData.guests} {t('person')}</span>
</div>
<div className="flex justify-between border-b border-outline-variant/30 pb-2">
<span className="font-label-caps text-[10px] text-on-surface-variant">{t('time')}</span>
<span className="font-body-md text-tertiary">{formData.time || '19:30'}</span>
</div>
</div>
<button onClick={() => setIsSubmitted(false)} className="mt-12 text-secondary font-label-caps text-label-caps border-b border-secondary pb-1 hover:text-tertiary hover:border-tertiary transition-colors">
{t('book_another')}
</button>
</div>
)}
</div>
{/* Scroll Indicator */}
<div className="absolute bottom-12 left-1/2 -translate-x-1/2 flex flex-col items-center gap-4">
<div className="w-px h-16 bg-gradient-to-b from-transparent via-on-tertiary-container to-transparent"></div>
</div>
</section>
{/* Informational Section */}
<section className="bg-background py-[var(--spacing-section-padding)] px-[var(--spacing-gutter)]">
<div className="max-w-[var(--spacing-container-max)] mx-auto grid grid-cols-1 md:grid-cols-3 gap-12">
<div className="space-y-4">
<span className="material-symbols-outlined text-tertiary text-4xl">local_fire_department</span>
<h3 className="font-headline-sm text-headline-sm text-on-surface">{t('info_title1')}</h3>
<p className="text-on-surface-variant text-body-md">{t('info_desc1')}</p>
</div>
<div className="space-y-4">
<span className="material-symbols-outlined text-tertiary text-4xl">restaurant_menu</span>
<h3 className="font-headline-sm text-headline-sm text-on-surface">{t('info_title2')}</h3>
<p className="text-on-surface-variant text-body-md">{t('info_desc2')}</p>
</div>
<div className="space-y-4">
<span className="material-symbols-outlined text-tertiary text-4xl">wine_bar</span>
<h3 className="font-headline-sm text-headline-sm text-on-surface">{t('info_title3')}</h3>
<p className="text-on-surface-variant text-body-md">{t('info_desc3')}</p>
</div>
</div>
</section>
</main>
)
}
+3
View File
@@ -0,0 +1,3 @@
import { handlers } from "@/lib/auth"
export const { GET, POST } = handlers
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

+154
View File
@@ -0,0 +1,154 @@
@import "tailwindcss";
@theme {
--color-surface-bright: #3a3939;
--color-on-tertiary-fixed: #2e1500;
--color-surface: #141313;
--color-primary-container: #121212;
--color-surface-variant: #353434;
--color-outline-variant: #444748;
--color-on-surface-variant: #c4c7c7;
--color-surface-container-highest: #353434;
--color-surface-container: #201f1f;
--color-on-error: #690005;
--color-on-primary-fixed: #1c1b1b;
--color-tertiary-container: #200d00;
--color-inverse-on-surface: #313030;
--color-on-tertiary-container: #b16d2e;
--color-error: #ffb4ab;
--color-on-primary-container: #7e7d7d;
--color-on-background: #e5e2e1;
--color-tertiary-fixed-dim: #ffb77b;
--color-surface-container-lowest: #0e0e0e;
--color-tertiary: #ffb77b;
--color-on-primary-fixed-variant: #474646;
--color-on-surface: #e5e2e1;
--color-secondary-container: #7a322f;
--color-primary-fixed-dim: #c8c6c5;
--color-outline: #8e9192;
--color-surface-container-high: #2b2a2a;
--color-on-secondary-fixed-variant: #77302d;
--color-on-tertiary-fixed-variant: #6d3a00;
--color-primary: #c8c6c5;
--color-secondary: #ffb3ad;
--color-on-tertiary: #4d2700;
--color-error-container: #93000a;
--color-tertiary-fixed: #ffdcc2;
--color-inverse-surface: #e5e2e1;
--color-secondary-fixed: #ffdad7;
--color-on-secondary-container: #ff9e97;
--color-on-secondary-fixed: #3d0506;
--color-surface-dim: #141313;
--color-primary-fixed: #e5e2e1;
--color-on-secondary: #5a1a19;
--color-inverse-primary: #5f5e5e;
--color-surface-container-low: #1c1b1b;
--color-on-error-container: #ffdad6;
--color-secondary-fixed-dim: #ffb3ad;
--color-surface-tint: #c8c6c5;
--color-background: #141313;
--color-on-primary: #313030;
--radius-DEFAULT: 0.125rem;
--radius-lg: 0.25rem;
--radius-xl: 0.5rem;
--radius-full: 0.75rem;
--spacing-gutter: 24px;
--spacing-unit: 8px;
--spacing-section-padding: 80px;
--spacing-container-max: 1200px;
--spacing-edge-margin-mobile: 20px;
--font-headline-md: "Playfair Display", serif;
--font-body-md: "Inter", sans-serif;
--font-display-lg-mobile: "Playfair Display", serif;
--font-headline-sm: "Playfair Display", serif;
--font-display-lg: "Playfair Display", serif;
--font-body-lg: "Inter", sans-serif;
--font-label-caps: "Montserrat", sans-serif;
}
@layer base {
:root {
--background: var(--color-background);
--foreground: var(--color-on-surface);
}
html {
scroll-behavior: smooth;
}
body {
background-color: var(--color-background);
color: var(--color-on-surface);
-webkit-font-smoothing: antialiased;
}
}
@layer utilities {
.font-headline-md { font-family: var(--font-headline-md); }
.font-body-md { font-family: var(--font-body-md); }
.font-display-lg-mobile { font-family: var(--font-display-lg-mobile); }
.font-headline-sm { font-family: var(--font-headline-sm); }
.font-display-lg { font-family: var(--font-display-lg); }
.font-body-lg { font-family: var(--font-body-lg); }
.font-label-caps { font-family: var(--font-label-caps); }
.text-headline-md { font-size: 32px; line-height: 1.3; font-weight: 600; }
.text-body-md { font-size: 16px; line-height: 1.6; font-weight: 400; }
.text-display-lg-mobile { font-size: 40px; line-height: 1.2; font-weight: 700; }
.text-headline-sm { font-size: 24px; line-height: 1.4; font-weight: 600; }
.text-display-lg { font-size: 64px; line-height: 1.1; letter-spacing: -0.02em; font-weight: 700; }
.text-body-lg { font-size: 18px; line-height: 1.6; font-weight: 400; }
.text-label-caps { font-size: 12px; line-height: 1.0; letter-spacing: 0.15em; font-weight: 600; }
.chiaroscuro-gradient {
background: linear-gradient(180deg, rgba(20,19,19,0) 0%, rgba(20,19,19,0.9) 80%, rgba(20,19,19,1) 100%);
}
.copper-glow {
box-shadow: inset 0 0 15px rgba(177, 109, 46, 0.1);
}
.copper-glow:hover {
box-shadow: 0 0 20px rgba(177, 109, 46, 0.3);
}
.copper-glow:focus-within {
box-shadow: 0 0 15px rgba(177, 109, 46, 0.3);
border-color: #b16d2e;
}
.vignette-overlay {
background: radial-gradient(circle, rgba(0,0,0,0) 0%, rgba(0,0,0,0.7) 100%);
}
.vignette-overlay-linear {
background: linear-gradient(to bottom, transparent 0%, rgba(20, 19, 19, 0.8) 70%, rgba(20, 19, 19, 1) 100%);
}
.section-divider {
height: 1px;
background: linear-gradient(90deg, transparent 0%, #ffb77b 50%, transparent 100%);
opacity: 0.3;
}
.booking-card {
backdrop-filter: blur(12px);
border: 0.5px solid rgba(177, 109, 46, 0.2);
}
.material-symbols-outlined {
font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 24;
}
}
/* Scrollbar Styles */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: #0e0e0e; }
::-webkit-scrollbar-thumb { background: #444748; border-radius: 10px; }
::-webkit-scrollbar-thumb:hover { background: #ffb77b; }
/* Date/Time pickers */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator {
filter: invert(0.8);
cursor: pointer;
}