# Kozmos Beach & More — QR Menü Sitesi Tasarım Dokümanı **Tarih:** 2026-06-03 **Proje:** kozmosqr **Stack:** Next.js 16.2.7 · React 19.2 · Tailwind CSS v4 · TypeScript --- ## Amaç Masa başında QR okutulunca açılan, uygulama gerektirmeyen, sadece görüntüleme amaçlı dijital menü. TR/EN dil desteği, mobil-first, PWA-ready. --- ## Tasarım Kararları (Brainstorming Özeti) | Karar | Seçim | Gerekçe | |---|---|---| | Ürün kartı stili | Minimal liste (emoji + isim + açıklama + fiyat) | Hızlı taranır, fotoğraf zorunluluğu yok | | Kategori navigasyon | Sticky alt tab bar | Başparmakla kolay erişim, native his | | i18n yaklaşımı | URL tabanlı (`/tr`, `/en`) | Next.js native `[lang]` dynamic segment | | Günün Önerisi / Rakı Gecesi | Sonraki sprint'e bırakıldı | Şimdilik kapsam dışı | --- ## Tasarım Dili - **Renkler:** krem `#F5F0E8` · bej `#E8DCC8` · turkuaz `#4AAFA8` · yeşil `#5C8A5C` · koyu kahve `#3D2B1F` - **Font:** Playfair Display (başlıklar, italic vurgu) + Inter (gövde, fiyat, etiketler) - **His:** Bohem, Ege, hasır doku — Magic UI animasyon kalitesi ile desteklenmiş - **Animasyon:** Minimal — scroll geçişleri, tab değiştirme fade --- ## Sayfa Yapısı ``` ┌─────────────────────┐ │ KOZMOS Beach&More │ sticky header — bg: #3D2B1F │ TR EN│ dil seçici sağ üst ├─────────────────────┤ │ │ │ [Aktif kategori │ scroll area — bg: #F5F0E8 │ içeriği] │ │ │ │ 🥗 Akdeniz Salatası│ minimal liste satırı │ Taze sebzeler ₺120 │ │ ─ ─ ─ ─ ─ ─ ─ ─ ─ │ │ │ │ [WA btn] │ fixed, sağ alt, bg: #25D366 ├─────────────────────┤ │ 🥗 🍽️ 🍕 🍹 🍮│ sticky bottom tab bar — bg: #3D2B1F └─────────────────────┘ ``` --- ## Dosya Yapısı ``` app/ [lang]/ layout.tsx — font yükleme, html lang attr, meta tags page.tsx — menü sayfası (Server Component) manifest.ts — PWA web app manifest proxy.ts — / → /tr yönlendirmesi (Next.js 16 proxy) data/ menu.ts — tüm menü verisi (TR+EN, tip tanımlı) dictionaries/ tr.json — UI string'leri Türkçe en.json — UI string'leri İngilizce public/ icons/ — PWA icon'ları (192x192, 512x512) ``` --- ## Veri Modeli ```ts // data/menu.ts type LocalizedString = { tr: string; en: string } type MenuItem = { id: string emoji: string name: LocalizedString description: LocalizedString price: number // TL highlight?: boolean // Günün Önerisi — sonraya hazır alan } type Category = { id: string emoji: string label: LocalizedString items: MenuItem[] } export const categories: Category[] = [ ... ] ``` **Kategoriler (6):** Başlangıçlar · Ana Yemekler · Pizzalar · Mezeler · İçecekler · Tatlılar **Her kategoride:** 4–5 ürün, TR+EN isim ve açıklama --- ## i18n Mimarisi **Routing:** `app/[lang]/page.tsx` — `/tr` ve `/en` URL'leri **proxy.ts:** - `/` → `/tr` yönlendirir (varsayılan locale) - Desteklenmeyen locale → 404 **dictionaries/tr.json + en.json:** ```json { "nav": { "starters": "Başlangıçlar", "mains": "Ana Yemekler", ... }, "whatsapp": "Rezervasyon için yazın", "currency": "₺" } ``` **getDictionary (server-only):** `app/[lang]/dictionaries.ts` - `import 'server-only'` ile client bundle'dan korunur - `hasLocale()` ile geçersiz locale → `notFound()` **Params:** Next.js 16 gereği `await params` — senkron erişim yok. --- ## Bileşen Mimarisi Bileşenler varsayılan olarak Server Component'tir. `'use client'` yalnızca aktif tab detection için gereklidir. ``` app/[lang]/page.tsx └─ — Server Component ├─
— Server Component, dil linkleri ├─ — Server Component, her kategori için │ └─ — Server Component ├─ — Server Component (statik link) └─ — CLIENT Component ⚠️ ``` **BottomTabBar neden client?** Sayfa tek scroll alanı, tüm kategoriler alt alta sıralı. Tab'lar `href="#category-id"` anchor linkleri. Aktif tab'ı belirlemek için Intersection Observer kullanılır — bu `useEffect` + `useState` gerektirir. **Sayfada sadece bu bir bileşen `'use client'` alır.** --- ## PWA `app/manifest.ts`: ```ts { name: 'Kozmos Beach & More', short_name: 'Kozmos', start_url: '/tr', display: 'standalone', background_color: '#F5F0E8', theme_color: '#3D2B1F' } ``` `app/[lang]/layout.tsx` meta tags: - `viewport` + `theme-color` - `apple-mobile-web-app-capable` --- ## Tailwind v4 Yapılandırması `app/globals.css` içinde `@theme inline` ile özel renkler: ```css @import "tailwindcss"; @theme inline { --color-cream: #F5F0E8; --color-beige: #E8DCC8; --color-teal: #4AAFA8; --color-green: #5C8A5C; --color-coffee: #3D2B1F; --font-display: 'Playfair Display', serif; --font-body: 'Inter', sans-serif; } ``` --- ## WhatsApp Butonu Fixed, sağ alt köşe. `href="https://wa.me/90XXXXXXXXXX"` — telefon numarası `data/menu.ts`'ten gelir, hardcode edilmez. --- ## Kapsam Dışı (Sonraki Sprint) - Günün Önerisi özel kartı - Perşembe Rakı Gecesi banner'ı - Gerçek ürün fotoğrafları (Next.js Image optimizasyonu) - Admin paneli / menü düzenleme arayüzü