5.8 KiB
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
// 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:
/→/tryönlendirir (varsayılan locale)- Desteklenmeyen locale → 404
dictionaries/tr.json + en.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 korunurhasLocale()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
└─ <MenuPage lang dict categories /> — Server Component
├─ <Header lang /> — Server Component, dil linkleri
├─ <CategorySection id="starters" ...> — Server Component, her kategori için
│ └─ <MenuItemRow> — Server Component
├─ <WhatsAppButton phone /> — Server Component (statik link)
└─ <BottomTabBar categories /> — 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:
{ 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-colorapple-mobile-web-app-capable
Tailwind v4 Yapılandırması
app/globals.css içinde @theme inline ile özel renkler:
@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ü