diff --git a/.gitignore b/.gitignore index 5e10cc7..676841b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,14 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + # dependencies /node_modules /.pnp -.pnp.js -.yarn/install-state.gz +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions # testing /coverage @@ -22,13 +28,28 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +.pnpm-debug.log* -# local env files -.env*.local +# env files (can opt-in for committing if needed) +.env* # vercel .vercel # typescript *.tsbuildinfo -next-env.d.ts \ No newline at end of file +next-env.d.ts + +# Developer / deployment instructions +# Contains sensitive production credentials (Gitea admin password, DB password, secrets, SSH keys, etc.) +# This file MUST NEVER be committed or pushed. +developer_instructions.txt + +# Video optimization artifacts and temp files +# Generated by optimize-food-videos.sh, optimize-videos.sh, extract-video-posters.sh, ffmpeg passes etc. +# These should not pollute the working tree or be committed. +public/videos/*-optimized.* +public/videos/*-optimized.mp4 +public/videos/*-optimized.webm +error*.jpeg +ffmpeg2pass*.log diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..8bd0e39 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,5 @@ + +# This is NOT the Next.js you know + +This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices. + diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/README.md b/README.md index a1c21f2..187dad4 100644 --- a/README.md +++ b/README.md @@ -1,69 +1,100 @@ -# Kött Gård — Premium Halal Meat Delivery +# Shahikitchen — Animated Restaurant Website -A modern, premium e-commerce website for 100% Halal meat delivery. Built with Next.js, TypeScript, and Tailwind CSS. +This directory contains the official website for **Shahi Kitchen**, a popular Indian & Pakistani restaurant in Gothenburg (Göteborg), Sweden. -## Features +**Domain**: [shahikitchen.se](https://shahikitchen.se) -- **Premium Design** — Green, white, and gold color palette with luxurious typography -- **Multi-language** — Swedish (default), English, and Urdu with RTL support -- **Product Customization** - - Chicken: Choose quantity in pieces (4, 8, 10, 12, 14) - - Beef & Lamb: Choose cutting style (Nihari, Karahi, Qeema, Boneless, Steak) - - Fish: Standard professional cut -- **Full E-commerce Flow** — Shop, product details, cart, secure checkout -- **User Accounts** — Registration, login, order history -- **Wishlist** — Save favorite products -- **Responsive** — Mobile-first design -- **SEO Optimized** — Meta tags, semantic HTML, Open Graph +--- -## Getting Started +## About Shahi Kitchen -```bash -npm install -npm run dev -``` +Shahi Kitchen is an authentic Indian and Pakistani restaurant specializing in flavorful curries, tandoori dishes, biryanis, haleem, fresh naan, and traditional sweets. The restaurant is particularly well-known for its generous **lunch buffet**, which offers excellent value and is popular among locals in the Gothenburg area. -Open [http://localhost:3000](http://localhost:3000). +### Key Information -### Demo Account +| Detail | Information | +|---------------------|--------------------------------------------------| +| **Full Name** | Shahi Kitchen (Shahikitchen / Shahi Kitchen Sisjön) | +| **Cuisine** | Indian & Pakistani (Halal options available) | +| **Address** | Datavägen 10A, 436 32 Askim, Sweden | +| **Area** | Sisjön / Askim (suburb of Gothenburg) | +| **Phone** | 031-28 89 10 / 0739-381089 (Imran) | +| **Email** | hello@shahikitchen.se | +| **Opened** | Around 2016 | +| **Specialties** | Lunch buffet, Biryani, Lamb Karahi, Curries, Sweets (Shahi Sweets) | -- Email: `demo@kottgard.se` -- Password: `demo123` +### Current Online Presence -### Languages +- **Instagram**: [@shahikitchen](https://www.instagram.com/Shahikitchen/) +- **Facebook**: [facebook.com/shahikitchengbg](https://www.facebook.com/shahikitchengbg/) +- **Reviews**: ~4.1/5 on Google (600+ reviews) +- **Note**: As of 2026, the domain `shahikitchen.se` is parked. This project will give the restaurant a proper modern website. -Use the language bar or globe icon to switch between: -- **Svenska** (Swedish) — default -- **English** -- **اردو** (Urdu) — RTL -- **العربية** (Arabic) — RTL -- **فارسی** (Persian) — RTL -- **Türkçe** (Turkish) +--- ## Tech Stack -- **Framework:** Next.js 13 (App Router) -- **Language:** TypeScript -- **Styling:** Tailwind CSS -- **State:** Zustand (persisted cart, auth, wishlist, locale) -- **i18n:** Custom translation system with locale store -- **Icons:** Lucide React +- **Next.js 15** (App Router) + TypeScript +- **Tailwind CSS** +- **GSAP** — for advanced scroll and UI animations +- **React Three Fiber** — for 3D experiences (dishes) +- **Spline** (optional) — for high-quality hosted 3D scenes +- **Framer Motion** (optional alternative to GSAP for simpler animations) -## Project Structure (Clean Architecture) +--- + +## Project Structure (Planned) ``` -src/ -├── domain/ # Entities + business rules (no React/Next) -├── application/ # Use cases, ports, container.ts -├── infrastructure/ # Zustand, product data, i18n adapters -├── presentation/ # useCart, useAuth, useCatalog hooks -├── app/ # Next.js pages (thin UI) -├── components/ # React UI components -├── i18n/ # Translation dictionaries (en, sv, ur) -├── hooks/ # useTranslation -├── lib/ # Backward-compatible facades -├── store/ # Backward-compatible re-exports -└── types/ # Re-exports domain entities +shahikitchen/ +├── app/ +│ ├── layout.tsx +│ ├── page.tsx # Homepage (Hero + Menu + About + Contact) +│ └── globals.css +├── components/ +│ ├── MenuSection.tsx +│ ├── Dish3D.tsx # React Three Fiber or Spline component +│ ├── ReservationForm.tsx +│ └── ... +├── lib/ +│ └── menu-data.ts # Menu items +├── public/ +│ └── images/ +└── ... ``` -See **[docs/CLEAN-ARCHITECTURE.md](docs/CLEAN-ARCHITECTURE.md)** for the full step-by-step guide. \ No newline at end of file +--- + +## Development + +### Getting Started + +```bash +# Install dependencies +npm install + +# Run development server +npm run dev +``` + +Open [http://localhost:3000](http://localhost:3000) in your browser. + +### Planned Features (in order) + +1. ✅ Create Next.js project +2. ⏳ Build normal restaurant homepage (Hero, Navigation, About) +3. ⏳ Add menu items (name, description, price) +4. ⏳ Style with Tailwind CSS +5. ⏳ Add animations (GSAP / Framer Motion) +6. ⏳ Add 3D dishes (React Three Fiber + Spline) +7. ⏳ Reservation / Contact form +8. ⏳ Mobile responsive +9. ⏳ Deploy to Vercel + +--- + +## License + +This project is being built for Shahi Kitchen. All rights reserved. + + diff --git a/app/catering/page.tsx b/app/catering/page.tsx new file mode 100644 index 0000000..f9609bb --- /dev/null +++ b/app/catering/page.tsx @@ -0,0 +1,107 @@ +'use client'; + +import Navbar from '@/components/Navbar'; +import Footer from '@/components/Footer'; +import PageHeader from '@/components/PageHeader'; +import CateringPackageCard from '@/components/CateringPackageCard'; +import { + cateringPackages, + CATERING_DISH_CATALOG, + CATERING_CATEGORY_ORDER, +} from '@/lib/catering-data'; +import { useLanguage } from '@/lib/language-context'; +import { getTranslation } from '@/lib/translations'; +import { container } from '@/infrastructure/di/container'; +import { Sparkles } from 'lucide-react'; + +export default function CateringPage() { + const { language } = useLanguage(); + const t = getTranslation(language); + + const handleSendInquiry = () => { + container.messagingGateway.openWhatsApp(t.catering.inquiryMessage); + }; + + return ( +
+ + +
+ + + {/* Packages grid */} +
+
+ {cateringPackages.map((pkg, index) => ( + + ))} +
+
+ + {/* Full dish catalog reference */} +
+
+
+
+ + {t.catering.catalogBadge} +
+
+
+

+ {t.catering.catalogTitle} +

+

+ {t.catering.catalogSubtitle} +

+
+ +
+
+ +
+ {CATERING_CATEGORY_ORDER.map((category) => { + const dishes = CATERING_DISH_CATALOG.filter((d) => d.category === category); + const categoryLabel = + (t.catering.categories as Record)?.[category] ?? category; + + return ( +
+

+ {categoryLabel} +

+
    + {dishes.map((dish) => ( +
  • + {dish.name} +
  • + ))} +
+
+ ); + })} +
+
+
+
+ +
+ ); +} \ No newline at end of file diff --git a/app/favicon.ico b/app/favicon.ico new file mode 100644 index 0000000..87d7dbb Binary files /dev/null and b/app/favicon.ico differ diff --git a/app/globals.css b/app/globals.css new file mode 100644 index 0000000..00e4b31 --- /dev/null +++ b/app/globals.css @@ -0,0 +1,482 @@ +/** + * ============================================================================= + * GLOBAL DESIGN SYSTEM — Shahi Kitchen + * ============================================================================= + * + * Shahi cream + gold visual identity for Shahi Kitchen. + * Bright, warm, appetizing, and luxurious without being dark. + */ + +@import "tailwindcss"; + +:root { + /* === Refined Shahi Light Palette - Warm Cream + Gold === */ + + /* Backgrounds */ + --bg: #F8F5F0; + --bg-elevated: #F5F1E9; + --surface: #FFFFFF; + --surface-subtle: #F2EDE4; + + /* Gold System */ + --gold: #B38B4D; + --gold-dark: #8C6B3A; + --gold-light: #C9A46B; + --gold-muted: #d4a73d; + + /* Emerald for contrast */ + --emerald: #0f5a4a; + --emerald-deep: #0a4a3d; + + /* Text */ + --text: #2C2520; + --text-muted: #6B665F; + --text-light: #8A8478; + + /* Borders */ + --border: #EDE6D9; + + /* Typography */ + --font-display: var(--font-playfair); + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); + --font-arabic: var(--font-arabic); + + /* Motion */ + --ease: cubic-bezier(0.25, 1, 0.5, 1); + + /* Layout — language banner (48px) + navbar (68px) */ + --header-height: 116px; + --page-top-gap: 1rem; +} + +/* Anchor links (/#menu, /#experience) land below the fixed header */ +.scroll-mt-header { + scroll-margin-top: var(--header-height); +} + +/* Base */ +body, +.shahi-body { + font-family: var(--font-sans); + background-color: var(--bg); + color: var(--text); + background-image: + radial-gradient(ellipse 80% 50% at 50% -20%, rgba(201, 154, 46, 0.08), transparent), + radial-gradient(ellipse 60% 40% at 100% 100%, rgba(15, 90, 74, 0.04), transparent); + background-attachment: fixed; +} + +/* RTL typography */ +html[dir="rtl"] body { + font-family: var(--font-arabic), var(--font-sans); +} + +html[dir="rtl"] h1, +html[dir="rtl"] h2, +html[dir="rtl"] h3, +html[dir="rtl"] h4 { + font-family: var(--font-arabic), var(--font-display); + letter-spacing: 0; +} + +h1, h2, h3, h4 { + font-family: var(--font-display); + font-weight: 600; + letter-spacing: -0.025em; + color: var(--text); +} + +/* Premium Buttons */ +.btn-primary { + background: linear-gradient(135deg, var(--gold), var(--gold-muted)); + color: #241806; + font-weight: 700; + transition: all 0.2s var(--ease); +} + +.btn-primary:hover { + transform: translateY(-1px); +} + +.btn-outline { + border: 1px solid var(--gold); + color: var(--gold-dark); + background: transparent; + font-weight: 600; + transition: all 0.2s var(--ease); +} + +.btn-outline:hover { + background: var(--gold); + color: #241806; +} + +/* Glass effect helper */ +.glass { + background: rgba(255, 253, 248, 0.72); + backdrop-filter: blur(20px); +} + +/* Luxury card style */ +.luxury-card { + border-radius: 2rem; + transition: transform 0.4s var(--ease), box-shadow 0.4s var(--ease); +} + +.luxury-card:hover { + transform: translateY(-4px); + box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.12); +} + +/* Signature dish cards */ +.signature-card { + box-shadow: 0 4px 24px -4px rgb(16 23 36 / 0.06); + transition: transform 0.35s var(--ease), box-shadow 0.35s var(--ease), border-color 0.35s var(--ease); +} + +.signature-card:hover { + box-shadow: 0 20px 40px -12px rgb(179 139 77 / 0.18); + border-color: rgba(201, 154, 46, 0.45); +} + +/* Section ornament */ +.section-ornament { + position: relative; +} + +.section-ornament::before { + content: ''; + position: absolute; + top: 0; + left: 50%; + transform: translateX(-50%); + width: 80px; + height: 3px; + background: linear-gradient(90deg, transparent, var(--gold-muted), transparent); + border-radius: 2px; +} + +/* Hero overlay text */ +.hero-glass { + background: linear-gradient( + 135deg, + rgba(255, 253, 248, 0.92) 0%, + rgba(255, 250, 240, 0.88) 50%, + rgba(248, 245, 240, 0.85) 100% + ); + backdrop-filter: blur(20px); + border: 1px solid rgba(201, 154, 46, 0.2); + box-shadow: + 0 25px 50px -12px rgba(16, 23, 36, 0.15), + inset 0 1px 0 rgba(255, 255, 255, 0.8); +} + +/* ============================================================================= + * FOOTER — Matches header cream + gold palette + * ============================================================================= */ +.shahi-footer { + background: linear-gradient( + 180deg, + #fffcf7 0%, + #fbf7ef 55%, + #f5f0e6 100% + ); + color: #101724; + border-top: 1px solid rgba(201, 154, 46, 0.25); + box-shadow: 0 -4px 24px -4px rgba(16, 23, 36, 0.06); +} + +.footer-top-rail { + height: 4px; + background: linear-gradient( + 90deg, + transparent 0%, + #8a6a25 15%, + #c99a2e 35%, + #f4d47f 50%, + #c99a2e 65%, + #8a6a25 85%, + transparent 100% + ); +} + +.footer-main { + position: relative; +} + +.footer-glow { + position: absolute; + border-radius: 50%; + pointer-events: none; + filter: blur(80px); +} + +.footer-glow--gold { + top: -40px; + right: 10%; + width: 280px; + height: 280px; + background: rgba(201, 154, 46, 0.08); +} + +.footer-glow--emerald { + bottom: 0; + left: -5%; + width: 320px; + height: 320px; + background: rgba(15, 90, 74, 0.05); +} + +.footer-heading-line { + display: inline-block; + width: 20px; + height: 2px; + background: linear-gradient(90deg, #c99a2e, #f4d47f); + border-radius: 1px; +} + +.footer-info-card { + border-radius: 1rem; + border: 1px solid rgba(201, 154, 46, 0.22); + background: rgba(255, 255, 255, 0.72); + padding: 1rem 1.125rem; + backdrop-filter: blur(8px); + transition: border-color 0.25s var(--ease), background 0.25s var(--ease), box-shadow 0.25s var(--ease); +} + +.footer-info-card:hover { + border-color: rgba(201, 154, 46, 0.45); + background: #ffffff; + box-shadow: 0 4px 16px -6px rgba(16, 23, 36, 0.08); +} + +.footer-link { + color: #3d4654; + transition: color 0.2s var(--ease), transform 0.2s var(--ease); +} + +.footer-link:hover { + color: #0f5a4a; +} + +html[dir="rtl"] .footer-link:hover { + transform: translateX(-2px); +} + +html[dir="ltr"] .footer-link:hover { + transform: translateX(2px); +} + +.footer-social-btn { + display: flex; + align-items: center; + justify-content: center; + width: 2.75rem; + height: 2.75rem; + border-radius: 0.875rem; + border: 1px solid rgba(201, 154, 46, 0.35); + background: rgba(255, 255, 255, 0.85); + color: #8a6a25; + transition: all 0.25s var(--ease); +} + +.footer-social-btn:hover { + background: linear-gradient(135deg, #c99a2e, #e8c56a); + color: #241806; + border-color: #c99a2e; + transform: translateY(-2px); + box-shadow: 0 8px 24px -4px rgba(201, 154, 46, 0.35); +} + +.footer-logo-ring { + border-color: rgba(201, 154, 46, 0.35); + background: #ffffff; + box-shadow: 0 4px 20px -6px rgba(16, 23, 36, 0.1); +} + +.footer-bottom { + background: rgba(255, 255, 255, 0.55); + border-top: 1px solid rgba(201, 154, 46, 0.2); +} + +.footer-cta { + backdrop-filter: blur(12px); + background: linear-gradient( + 135deg, + rgba(255, 255, 255, 0.92) 0%, + rgba(255, 252, 247, 0.88) 100% + ); + border-color: rgba(201, 154, 46, 0.35); +} + +/* Language banner subtle shine */ +.lang-banner { + position: relative; + overflow: hidden; +} + +.lang-banner::after { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient( + 90deg, + transparent 0%, + rgba(255, 255, 255, 0.06) 50%, + transparent 100% + ); + pointer-events: none; +} + +/* Mesmerizing shimmer animation for premium buttons (used in Navbar) */ +@keyframes shimmer { + 0% { transform: translateX(-100%); } + 100% { transform: translateX(200%); } +} + +/* Continuous menu reel marquee for 43" displays - items move LEFT (enter from right, exit left), seamless loop with 2x duplication */ +@keyframes menu-reel { + 0% { transform: translateX(0); } + 100% { transform: translateX(-50%); } +} + +.menu-reel-track { + will-change: transform; + animation: menu-reel linear infinite; + /* Force GPU layer for stable poster/video during transform */ + transform: translateZ(0); + backface-visibility: hidden; +} + +/* Homepage signature menu — dishes scroll left to right */ +@keyframes signature-menu-reel-ltr { + 0% { transform: translateX(-50%); } + 100% { transform: translateX(0); } +} + +.signature-menu-reel-track { + will-change: transform; + animation: signature-menu-reel-ltr linear infinite; + transform: translateZ(0); + backface-visibility: hidden; +} + +.signature-menu-reel:hover .signature-menu-reel-track { + animation-play-state: paused; +} + +@media (prefers-reduced-motion: reduce) { + .signature-menu-reel-track { + animation: none; + flex-wrap: wrap; + width: 100% !important; + justify-content: center; + } +} + +/* ============================================================================= + * KIOSK / FULLSCREEN DISPLAY PAGES (screen1 & screen2) + * Professional clean TV/window look: no scrollbars ever, even in browser + * fullscreen (F11) or kiosk mode. User zooms browser (in/out) to adjust + * visible reel density instead of scrolling. Content sized to fit 100vh. + * ============================================================================= */ +html.screen-kiosk, +body.screen-kiosk { + overflow: hidden !important; + overscroll-behavior: none; + /* Hide scrollbars cross-browser */ + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; /* IE/Edge */ +} + +html.screen-kiosk::-webkit-scrollbar, +body.screen-kiosk::-webkit-scrollbar { + display: none; /* Chrome/Safari/Opera */ +} + +.screen-root { + height: 100vh; + overflow: hidden; + display: flex; + flex-direction: column; + /* Extra insurance: hide any descendant scrollbars */ + scrollbar-width: none; + -ms-overflow-style: none; +} + +.screen-root::-webkit-scrollbar, +.screen-root *::-webkit-scrollbar { + display: none; +} + +/* Subtle polish for pure display (no accidental text selection or pointer) */ +.screen-root { + cursor: default; +} + +/* ============================================================================= + * VERTICAL REEL for screen3 order columns + * Orders move UP (from below to above) in a loop, like screen2 horizontal but vertical. + * Cards have fixed px height; viewport h-full of available column space (after header) => + * fills entire screen height with no white space (max top to bottom). + * Zoom in browser: fewer items visible per column (larger cards relative). + * Zoom out: more items visible per column (smaller cards relative). + * When > visible count, the track loops seamlessly (duplicated list + 50% translateY). + * ============================================================================= */ +@keyframes order-reel-up { + 0% { transform: translateY(0); } + 100% { transform: translateY(-50%); } +} + +.order-reel-track { + display: flex; + flex-direction: column; + will-change: transform; + animation: order-reel-up linear infinite; + /* Force GPU layer for stable animation */ + transform: translateZ(0); + backface-visibility: hidden; +} + +.reel-viewport { + overflow: hidden; + /* Height 100% of available (flex h-full after section header) to fill screen. + Fixed card heights + zoom changes visible count dynamically. */ +} + +/* Menu page — smooth category filter scrolling */ +.menu-category-scroll { + scroll-behavior: smooth; + scrollbar-width: none; + -ms-overflow-style: none; +} + +.menu-category-scroll::-webkit-scrollbar { + display: none; +} + +@media (min-width: 1024px) { + .menu-category-scroll { + scrollbar-width: thin; + scrollbar-color: #d4c9b8 transparent; + } + + .menu-category-scroll::-webkit-scrollbar { + display: block; + width: 5px; + } + + .menu-category-scroll::-webkit-scrollbar-track { + background: transparent; + } + + .menu-category-scroll::-webkit-scrollbar-thumb { + background: #d4c9b8; + border-radius: 999px; + } + + .menu-category-scroll::-webkit-scrollbar-thumb:hover { + background: #c99a2e; + } +} diff --git a/app/layout.tsx b/app/layout.tsx new file mode 100644 index 0000000..2fd67c1 --- /dev/null +++ b/app/layout.tsx @@ -0,0 +1,123 @@ +/** + * ROOT LAYOUT — Shahi Kitchen (shahikitchen.se) + * + * This is the single root layout for the entire Next.js App Router application. + * + * RESPONSIBILITIES: + * - Set up global metadata (title, description, favicon) for SEO and social sharing + * - Load the premium typography system: + * • Playfair Display (display/serif) → used for headings via --font-playfair + * • Geist Sans (system UI) → body text + * • Geist Mono → code / tabular data + * - Initialize the GLOBAL CART SYSTEM: + * • CartProvider wraps the whole tree so any page/component can use `useCart()` + * • CartDrawer is rendered once at the root (slide-in basket panel) + * • Sonner provides beautiful toast notifications used by the cart + * + * ARCHITECTURAL NOTES: + * - We deliberately render and at the root level instead of + * inside individual pages. This guarantees only ONE instance exists and prevents + * duplicate drawers/toasts when navigating. + * - The cream/gold Shahi theme tokens live in globals.css and are referenced via + * Tailwind arbitrary values (e.g. bg-[#F8F5F0]). + * + * FUTURE DEVELOPERS: + * - To add a new global provider (theme, analytics, etc.), wrap it here. + * - WhatsApp number for orders is currently hardcoded in CartDrawer.tsx (46739381089). + * - If you ever split the cart into a separate modal library, keep the provider here. + */ + +import type { Metadata } from "next"; +import { Playfair_Display, Geist, Geist_Mono, Noto_Sans_Arabic } from "next/font/google"; +import "./globals.css"; +import { Toaster } from "sonner"; +import CartDrawer from "@/components/CartDrawer"; +import WishlistDrawer from "@/components/WishlistDrawer"; +import { CartProvider } from "@/presentation/providers/cart-provider"; +import { WishlistProvider } from "@/presentation/providers/wishlist-provider"; +import { LanguageProvider } from "@/presentation/providers/language-provider"; + +const playfair = Playfair_Display({ + variable: "--font-playfair", + subsets: ["latin"], + weight: ["400", "500", "600", "700"], + style: ["normal", "italic"], +}); + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], + weight: ["400", "500", "600", "700"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], + weight: ["400", "500", "600"], +}); + +const notoArabic = Noto_Sans_Arabic({ + variable: "--font-arabic", + subsets: ["arabic"], + weight: ["400", "500", "600", "700"], +}); + +/** + * Next.js Metadata API (static) + * These values power: + * - Browser tab title + * - Search engine results + * - Social cards (Open Graph / Twitter) when shared + * + * For dynamic per-page metadata, use `generateMetadata()` in page files. + */ +export const metadata: Metadata = { + title: "Shahi Kitchen | Authentic Indian & Pakistani Restaurant in Gothenburg", + description: "Experience Shahi flavors at Shahi Kitchen in Askim, Gothenburg. Authentic Indian & Pakistani cuisine, famous lunch buffet, and traditional sweets since 2016.", + icons: { + icon: "/favicon.ico", + }, +}; + +/** + * RootLayout + * + * The ONLY place in the app where we initialize: + * 1. CartProvider → gives every descendant access to `useCart()` hook + * 2. CartDrawer → the actual slide-in basket UI (controlled via context) + * 3. Toaster → global toast surface used by cart (Sonner library) + * + * IMPORTANT: + * - Never wrap the entire app in another CartProvider — it will break the singleton. + * - The body uses the Shahi cream background (#F8F5F0) as the base canvas. + * - `antialiased` + font variables are applied once at the root for consistency. + */ +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + + + + {children} + + + + + + + + + ); +} diff --git a/app/locations/page.tsx b/app/locations/page.tsx new file mode 100644 index 0000000..edfd503 --- /dev/null +++ b/app/locations/page.tsx @@ -0,0 +1,144 @@ +/** + * LOCATIONS PAGE + * + * Dedicated page for the restaurant's two physical branches. + * + * ARCHITECTURE: + * - Two branches are modeled as distinct concepts: + * 1. Shahi Kitchen Askim (Sisjön) → Full restaurant + famous lunch buffet + * 2. Shahi Sweets Backaplan → Sweets, snacks, café, halwa puri etc. + * - Both are operated by the same team (explicitly stated at the bottom) + * - Google Maps embeds are intentionally simple (lazy loaded) + * + * FUTURE: + * - When real online ordering launches, this page could show "Order from Askim" + * vs "Order from Backaplan" with different delivery radii. + * - Both branches now have the same opening hours. + */ + +'use client'; + +import Navbar from "@/components/Navbar"; +import Footer from "@/components/Footer"; +import PageHeader from "@/components/PageHeader"; +import { useLanguage } from "@/lib/language-context"; +import { getTranslation } from "@/lib/translations"; + +export default function LocationsPage() { + const { language } = useLanguage(); + const t = getTranslation(language); + return ( +
+ + + + +
+ + + +
+ {/* Branch 1: Askim */} +
+
RESTAURANT & BUFFET
+

Shahi Kitchen – Askim (Sisjön)

+ +
+
+
ADDRESS
+
Datavägen 10A
436 32 Askim, Gothenburg
+
+ +
+
PHONE
+ 031-28 89 10 + 0739-381089 +
+ +
+
OPENING HOURS
+
Monday – Sunday • 11:00 – 21:00
+
+ +
+
WHAT TO EXPECT
+
Full restaurant experience with our popular lunch buffet, à la carte, and traditional Pakistani & Indian dishes.
+
+
+ +
+