Initial commit: Shahi Kitchen premium website
- Royal cream + gold theme - Playful animated hero with chef mascot - Advanced menu with sidebar + video hover - Multilingual support (EN, SV, HI, UR) - Cart system with WhatsApp ordering - Real restaurant photos integration - Responsive design with proper navbar
This commit is contained in:
+97
-16
@@ -1,26 +1,107 @@
|
||||
/**
|
||||
* =============================================================================
|
||||
* GLOBAL DESIGN SYSTEM — Shahi Kitchen
|
||||
* =============================================================================
|
||||
*
|
||||
* Royal cream + gold visual identity for Shahi Kitchen.
|
||||
* Bright, warm, appetizing, and luxurious without being dark.
|
||||
*/
|
||||
|
||||
@import "tailwindcss";
|
||||
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--foreground: #171717;
|
||||
}
|
||||
/* === Refined Royal Light Palette - Warm Cream + Gold === */
|
||||
|
||||
/* Backgrounds */
|
||||
--bg: #F8F5F0;
|
||||
--bg-elevated: #F5F1E9;
|
||||
--surface: #FFFFFF;
|
||||
--surface-subtle: #F2EDE4;
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
/* Gold System */
|
||||
--gold: #B38B4D;
|
||||
--gold-dark: #8C6B3A;
|
||||
--gold-light: #C9A46B;
|
||||
--gold-muted: #d4a73d;
|
||||
|
||||
/* Emerald for contrast (kept from recent improvements) */
|
||||
--emerald: #0f5a4a;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Motion */
|
||||
--ease: cubic-bezier(0.25, 1, 0.5, 1);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background: #0a0a0a;
|
||||
--foreground: #ededed;
|
||||
}
|
||||
}
|
||||
|
||||
/* Base */
|
||||
body {
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-family: var(--font-sans);
|
||||
background-color: var(--bg);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* Mesmerizing shimmer animation for premium buttons (used in Navbar) */
|
||||
@keyframes shimmer {
|
||||
0% { transform: translateX(-100%); }
|
||||
100% { transform: translateX(200%); }
|
||||
}
|
||||
|
||||
+80
-5
@@ -1,22 +1,89 @@
|
||||
/**
|
||||
* 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 <Toaster> provides beautiful toast notifications used by the cart
|
||||
*
|
||||
* ARCHITECTURAL NOTES:
|
||||
* - We deliberately render <CartDrawer /> and <Toaster /> 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 royal 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 (46709864995).
|
||||
* - If you ever split the cart into a separate modal library, keep the provider here.
|
||||
*/
|
||||
|
||||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import { Playfair_Display, Geist, Geist_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import { Toaster } from "sonner";
|
||||
import { CartProvider } from "@/components/CartContext";
|
||||
import CartDrawer from "@/components/CartDrawer";
|
||||
import { LanguageProvider } from "@/lib/language-context";
|
||||
|
||||
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"],
|
||||
});
|
||||
|
||||
/**
|
||||
* 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: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
title: "Shahi Kitchen | Authentic Indian & Pakistani Restaurant in Gothenburg",
|
||||
description: "Experience royal 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 royal cream background (#F8F5F0) as the base canvas.
|
||||
* - `antialiased` + font variables are applied once at the root for consistency.
|
||||
*/
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
@@ -25,9 +92,17 @@ export default function RootLayout({
|
||||
return (
|
||||
<html
|
||||
lang="en"
|
||||
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
|
||||
className={`${playfair.variable} ${geistSans.variable} ${geistMono.variable} h-full antialiased`}
|
||||
>
|
||||
<body className="min-h-full flex flex-col">{children}</body>
|
||||
<body className="min-h-full flex flex-col bg-[#F8F5F0] text-[#2C2A26]">
|
||||
<LanguageProvider>
|
||||
<CartProvider>
|
||||
{children}
|
||||
<CartDrawer />
|
||||
<Toaster position="top-center" richColors closeButton />
|
||||
</CartProvider>
|
||||
</LanguageProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* 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.
|
||||
* - Instagram handles for each location are mentioned where relevant.
|
||||
*/
|
||||
|
||||
import Navbar from "@/components/Navbar";
|
||||
import Footer from "@/components/Footer";
|
||||
|
||||
export default function LocationsPage() {
|
||||
return (
|
||||
<div className="min-h-screen bg-[#F8F5F0] text-[#2C2A26]">
|
||||
<Navbar />
|
||||
|
||||
<div className="max-w-5xl mx-auto px-6 pt-20 pb-16">
|
||||
<div className="text-center mb-12">
|
||||
<div className="text-[#B38B4D] text-xs tracking-[3px] mb-3">WHERE TO FIND US</div>
|
||||
<h1 className="text-6xl md:text-7xl tracking-[-2.5px] leading-none mb-4">Our Locations</h1>
|
||||
<p className="text-xl text-[#6B665F] max-w-md mx-auto">
|
||||
Two branches in Gothenburg — both serving authentic flavors with the same royal hospitality.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-center mb-8">
|
||||
<a href="/#contact" className="btn-primary px-8 py-3 rounded-full text-sm tracking-[0.5px]">
|
||||
Make a Reservation
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-8">
|
||||
{/* Branch 1: Askim */}
|
||||
<div className="bg-white border border-[#EDE6D9] rounded-2xl p-8">
|
||||
<div className="uppercase text-[#B38B4D] text-xs tracking-[2px] mb-2">RESTAURANT & BUFFET</div>
|
||||
<h2 className="text-4xl tracking-[-1.5px] mb-4">Shahi Kitchen – Askim (Sisjön)</h2>
|
||||
|
||||
<div className="space-y-5 text-[15px]">
|
||||
<div>
|
||||
<div className="text-[#B38B4D] text-xs tracking-widest mb-1">ADDRESS</div>
|
||||
<div>Datavägen 10A<br />436 32 Askim, Gothenburg</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="text-[#B38B4D] text-xs tracking-widest mb-1">PHONE</div>
|
||||
<a href="tel:031288910" className="block hover:text-[#B38B4D]">031-28 89 10</a>
|
||||
<a href="tel:0739381089" className="block hover:text-[#B38B4D]">0739-381089</a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="text-[#B38B4D] text-xs tracking-widest mb-1">OPENING HOURS</div>
|
||||
<div>Monday – Sunday • 11:00 – 21:00</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="text-[#B38B4D] text-xs tracking-widest mb-1">WHAT TO EXPECT</div>
|
||||
<div className="text-[#6B665F]">Full restaurant experience with our popular lunch buffet, à la carte, and traditional Pakistani & Indian dishes.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-8 aspect-video rounded-xl overflow-hidden border border-[#EDE6D9]">
|
||||
<iframe
|
||||
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2130.5!2d11.95!3d57.65!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x464ff3c8b8b8b8b8%3A0x1234567890abcdef!2sDatav%C3%A4gen%2010A%2C%20436%2032%20Askim!5e0!3m2!1sen!2sse!4v1700000000000"
|
||||
width="100%"
|
||||
height="100%"
|
||||
style={{ border: 0 }}
|
||||
allowFullScreen
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Branch 2: Backaplan */}
|
||||
<div className="bg-white border border-[#EDE6D9] rounded-2xl p-8">
|
||||
<div className="uppercase text-[#B38B4D] text-xs tracking-[2px] mb-2">SWEETS, SNACKS & CAFÉ</div>
|
||||
<h2 className="text-4xl tracking-[-1.5px] mb-4">Shahi Sweets – Backaplan</h2>
|
||||
|
||||
<div className="space-y-5 text-[15px]">
|
||||
<div>
|
||||
<div className="text-[#B38B4D] text-xs tracking-widest mb-1">ADDRESS</div>
|
||||
<div>Krokegårdsgatan 5<br />417 30 Göteborg (Backaplan)</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="text-[#B38B4D] text-xs tracking-widest mb-1">PHONE</div>
|
||||
<a href="tel:0739381089" className="block hover:text-[#B38B4D]">0739-381089</a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="text-[#B38B4D] text-xs tracking-widest mb-1">OPENING HOURS</div>
|
||||
<div>Varies — please check our Instagram <span className="text-[#B38B4D]">@shahisweets_bp</span> for current hours.</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="text-[#B38B4D] text-xs tracking-widest mb-1">WHAT TO EXPECT</div>
|
||||
<div className="text-[#6B665F]">Fresh mithai (sweets), savory snacks, halwa puri, biryani, nihari, and café-style seating.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-8 aspect-video rounded-xl overflow-hidden border border-[#EDE6D9]">
|
||||
<iframe
|
||||
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2130!2d11.92!3d57.72!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x464ff3c8b8b8b8b8%3A0x1234567890abcdef!2sKrokeg%C3%A5rdsgatan%205%2C%20417%2030%20G%C3%B6teborg!5e0!3m2!1sen!2sse!4v1700000000000"
|
||||
width="100%"
|
||||
height="100%"
|
||||
style={{ border: 0 }}
|
||||
allowFullScreen
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="mt-12 text-center text-sm text-[#6B665F]">
|
||||
Both branches are operated by the same team and share the same passion for authentic flavors.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
"use client";
|
||||
|
||||
/**
|
||||
* MENU PAGE — Premium Sidebar + Beautiful Loading Experience
|
||||
*/
|
||||
|
||||
import { useEffect, useState, useMemo } from "react";
|
||||
import { menuCategories } from "@/lib/menu-data";
|
||||
import { gsap } from "gsap";
|
||||
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||
import Navbar from "@/components/Navbar";
|
||||
import Footer from "@/components/Footer";
|
||||
import { useCart } from "@/components/CartContext";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
|
||||
export default function MenuPage() {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [activeCategory, setActiveCategory] = useState("All");
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [showVegetarianOnly, setShowVegetarianOnly] = useState(false);
|
||||
|
||||
const { addToCart } = useCart();
|
||||
|
||||
// Beautiful loading screen on initial load
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setIsLoading(false);
|
||||
}, 1350);
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
// Sidebar categories
|
||||
const sidebarCategories = [
|
||||
{ id: "All", name: "All Dishes" },
|
||||
...menuCategories.map((cat) => ({ id: cat.id, name: cat.name })),
|
||||
];
|
||||
|
||||
// Filtering logic
|
||||
const filteredCategories = useMemo(() => {
|
||||
return menuCategories
|
||||
.map((category) => {
|
||||
let items = category.items;
|
||||
|
||||
// Sidebar filter
|
||||
if (activeCategory !== "All" && category.id !== activeCategory) {
|
||||
items = [];
|
||||
}
|
||||
|
||||
// Search
|
||||
if (searchQuery.trim()) {
|
||||
const q = searchQuery.toLowerCase().trim();
|
||||
items = items.filter(
|
||||
(item) =>
|
||||
item.name.toLowerCase().includes(q) ||
|
||||
(item.description && item.description.toLowerCase().includes(q))
|
||||
);
|
||||
}
|
||||
|
||||
// Vegetarian
|
||||
if (showVegetarianOnly) {
|
||||
items = items.filter((item) => item.isVegetarian);
|
||||
}
|
||||
|
||||
return { ...category, items };
|
||||
})
|
||||
.filter((category) => category.items.length > 0);
|
||||
}, [searchQuery, showVegetarianOnly, activeCategory]);
|
||||
|
||||
const handleCategorySelect = (id: string) => {
|
||||
setActiveCategory(id);
|
||||
window.scrollTo({ top: 220, behavior: "smooth" });
|
||||
};
|
||||
|
||||
// === BEAUTIFUL LOADING SCREEN ===
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="min-h-screen bg-[#fbf7ef] flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<div className="relative mx-auto mb-8 w-20 h-20">
|
||||
<div className="absolute inset-0 rounded-full border-2 border-[#c99a2e]/30" />
|
||||
<motion.div
|
||||
className="absolute inset-0 rounded-full border-2 border-transparent border-t-[#c99a2e] border-r-[#d4a73d]"
|
||||
animate={{ rotate: 360 }}
|
||||
transition={{ duration: 1.3, repeat: Infinity, ease: "linear" }}
|
||||
/>
|
||||
<div className="absolute inset-[6px] rounded-full border border-[#0f5a4a]/20" />
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<h2 className="font-serif text-3xl tracking-tight text-[#101724]">
|
||||
Loading the Menu
|
||||
</h2>
|
||||
<p className="text-[#68717f] text-sm tracking-[1.5px]">Preparing the Royal Table...</p>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-center gap-2 mt-6">
|
||||
{[0, 1, 2].map((i) => (
|
||||
<motion.div
|
||||
key={i}
|
||||
className="w-1.5 h-1.5 rounded-full bg-[#c99a2e]"
|
||||
animate={{ opacity: [0.3, 1, 0.3] }}
|
||||
transition={{ duration: 1.1, repeat: Infinity, delay: i * 0.18 }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-[#F8F5F0] text-[#2C2A26]">
|
||||
<Navbar />
|
||||
|
||||
{/* Page Header */}
|
||||
<div className="max-w-7xl mx-auto px-6 pt-14 pb-10">
|
||||
<div className="max-w-3xl">
|
||||
<div className="text-[#B38B4D] text-xs tracking-[3.5px] mb-4 font-medium">AUTHENTIC • GENEROUS • ROYAL</div>
|
||||
<h1 className="text-6xl md:text-7xl tracking-[-2.8px] leading-none mb-5 text-[#101724]">Our Menu</h1>
|
||||
<p className="text-2xl text-[#4b5563] max-w-2xl">
|
||||
Traditional recipes. Generous portions. Made with heart.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main Layout */}
|
||||
<div className="max-w-7xl mx-auto px-6 pb-20">
|
||||
<div className="flex flex-col lg:flex-row gap-10">
|
||||
|
||||
{/* BEAUTIFUL SIDEBAR */}
|
||||
<div className="lg:w-72 flex-shrink-0">
|
||||
<div className="sticky top-24">
|
||||
<div className="mb-6">
|
||||
<div className="text-xs tracking-[3px] text-[#c99a2e] mb-2">EXPLORE OUR</div>
|
||||
<h3 className="font-serif text-3xl tracking-tight">Signature Categories</h3>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1 pr-4">
|
||||
{sidebarCategories.map((cat) => {
|
||||
const isActive = activeCategory === cat.id;
|
||||
const itemCount = cat.id === "All"
|
||||
? menuCategories.reduce((sum, c) => sum + c.items.length, 0)
|
||||
: menuCategories.find(c => c.id === cat.id)?.items.length || 0;
|
||||
|
||||
return (
|
||||
<button
|
||||
key={cat.id}
|
||||
onClick={() => handleCategorySelect(cat.id)}
|
||||
className={`w-full flex items-center justify-between px-5 py-3.5 rounded-2xl text-left transition-all group ${
|
||||
isActive
|
||||
? "bg-[#101724] text-white shadow-lg"
|
||||
: "hover:bg-white hover:shadow-sm text-[#101724] border border-transparent hover:border-[#e5e1d7]"
|
||||
}`}
|
||||
>
|
||||
<span className={`font-medium tracking-[-0.1px] ${isActive ? "" : "group-hover:text-[#0f5a4a]"}`}>
|
||||
{cat.name}
|
||||
</span>
|
||||
<span className={`text-xs px-2.5 py-0.5 rounded-full font-mono tabular-nums ${
|
||||
isActive ? "bg-white/20" : "bg-[#e5e1d7] text-[#68717f]"
|
||||
}`}>
|
||||
{itemCount}
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* MAIN CONTENT */}
|
||||
<div className="flex-1 min-w-0">
|
||||
{/* Search + Vegetarian Filter */}
|
||||
<div className="mb-8 flex flex-col md:flex-row gap-4 items-center">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search dishes..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="w-full md:w-80 rounded-2xl border border-[#e5e1d7] bg-white px-5 py-3 text-sm placeholder:text-[#8A8478] focus:border-[#c99a2e] focus:ring-2 focus:ring-[#c99a2e]/20 transition-all"
|
||||
/>
|
||||
|
||||
<button
|
||||
onClick={() => setShowVegetarianOnly(!showVegetarianOnly)}
|
||||
className={`px-6 py-3 rounded-2xl text-sm font-medium border transition-all ${
|
||||
showVegetarianOnly
|
||||
? "bg-[#0f5a4a] text-white border-[#0f5a4a]"
|
||||
: "border-[#e5e1d7] hover:border-[#c99a2e] text-[#101724] bg-white"
|
||||
}`}
|
||||
>
|
||||
{showVegetarianOnly ? "Vegetarian Only" : "Show Vegetarian"}
|
||||
</button>
|
||||
|
||||
{(searchQuery || showVegetarianOnly || activeCategory !== "All") && (
|
||||
<button
|
||||
onClick={() => {
|
||||
setSearchQuery("");
|
||||
setShowVegetarianOnly(false);
|
||||
setActiveCategory("All");
|
||||
}}
|
||||
className="text-sm font-medium text-[#c99a2e] hover:text-[#8f6b22]"
|
||||
>
|
||||
Clear filters
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Menu Items */}
|
||||
{filteredCategories.length === 0 ? (
|
||||
<div className="text-center py-16 text-[#6B665F]">
|
||||
No dishes found matching your filters.
|
||||
</div>
|
||||
) : (
|
||||
filteredCategories.map((category) => (
|
||||
<div key={category.id} className="mb-16">
|
||||
<div className="flex items-center gap-4 mb-7">
|
||||
<div className="text-3xl tracking-[-1px] text-[#101724]">{category.name}</div>
|
||||
<div className="flex-1 h-px bg-gradient-to-r from-[#e5e1d7] to-transparent" />
|
||||
<div className="text-sm font-medium text-[#68717f] tracking-widest">
|
||||
{category.items.length} dishes
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{category.items.map((item) => (
|
||||
<div
|
||||
key={item.id}
|
||||
className="menu-card group bg-white border border-[#EDE6D9] rounded-2xl overflow-hidden flex flex-col hover:border-[#c99a2e]/40 transition-all duration-300 cursor-pointer"
|
||||
onClick={() => addToCart({ id: item.id, name: item.name, price: item.price, image: item.image })}
|
||||
>
|
||||
{/* Media - Restored Premium Video Hover + Poster Logic */}
|
||||
{item.video ? (
|
||||
<div
|
||||
className="relative h-52 overflow-hidden bg-[#F2EDE4] cursor-pointer"
|
||||
onMouseEnter={(e) => {
|
||||
const video = e.currentTarget.querySelector("video");
|
||||
if (video) video.play().catch(() => {});
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
const video = e.currentTarget.querySelector("video");
|
||||
if (video) {
|
||||
video.pause();
|
||||
video.currentTime = 0;
|
||||
}
|
||||
}}
|
||||
onClick={() => addToCart({ id: item.id, name: item.name, price: item.price, image: item.image })}
|
||||
>
|
||||
{/* Static Poster (first frame) */}
|
||||
<img
|
||||
src={`/images/dishes/${item.video.replace(".mp4", "-poster.jpg")}`}
|
||||
alt={item.name}
|
||||
className="absolute inset-0 w-full h-full object-cover group-hover:opacity-0 transition-opacity duration-150"
|
||||
loading="lazy"
|
||||
onError={(e) => {
|
||||
// Fallback poster logic
|
||||
const base = (item.video || item.image || "").replace(".mp4", "").replace(/-optimized/g, "");
|
||||
const fallbacks = [
|
||||
`/images/dishes/${base}-poster.jpg`,
|
||||
`/images/dishes/${base}-optimized-poster.jpg`,
|
||||
`/images/dishes/${item.image}`,
|
||||
].filter(Boolean);
|
||||
let i = 0;
|
||||
const tryNext = () => {
|
||||
if (i < fallbacks.length) {
|
||||
(e.target as HTMLImageElement).src = fallbacks[i++];
|
||||
}
|
||||
};
|
||||
tryNext();
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Video on Hover */}
|
||||
<video
|
||||
muted
|
||||
loop
|
||||
playsInline
|
||||
preload="metadata"
|
||||
className="absolute inset-0 w-full h-full object-cover opacity-0 group-hover:opacity-100 transition-opacity duration-150"
|
||||
>
|
||||
<source src={`/videos/${item.video.replace(".mp4", ".webm")}`} type="video/webm" />
|
||||
<source src={`/videos/${item.video}`} type="video/mp4" />
|
||||
</video>
|
||||
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-black/5 via-black/10 to-black/25 group-hover:opacity-0 transition-opacity" />
|
||||
</div>
|
||||
) : (
|
||||
/* Static Image for items without video */
|
||||
<div
|
||||
className="relative h-52 overflow-hidden bg-[#F2EDE4] cursor-pointer"
|
||||
onClick={() => addToCart({ id: item.id, name: item.name, price: item.price, image: item.image })}
|
||||
>
|
||||
<img
|
||||
src={`/images/dishes/${item.image}`}
|
||||
alt={item.name}
|
||||
className="w-full h-full object-cover group-hover:scale-[1.03] transition-transform duration-700"
|
||||
loading="lazy"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-black/5 via-black/10 to-black/25" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="p-6 flex flex-col flex-1">
|
||||
<div className="flex justify-between items-start gap-4 mb-4">
|
||||
<h3 className="text-[22px] leading-tight tracking-[-0.4px] text-[#2C2A26]">
|
||||
{item.name}
|
||||
</h3>
|
||||
<div className="shrink-0 text-right">
|
||||
<div className="text-[#B38B4D] text-2xl font-medium tracking-[-0.5px] tabular-nums">
|
||||
{item.price}
|
||||
</div>
|
||||
<div className="text-[10px] text-[#8A8478] tracking-widest -mt-1">KR</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{item.description && (
|
||||
<p className="text-[#6B665F] text-[15px] leading-relaxed mb-5">
|
||||
{item.description}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<div className="mt-auto">
|
||||
{item.isVegetarian && (
|
||||
<span className="text-xs px-3 py-1 rounded-full bg-[#3F5C4A]/10 text-[#3F5C4A] tracking-wider">
|
||||
VEGETARIAN
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+304
-58
@@ -1,65 +1,311 @@
|
||||
import Image from "next/image";
|
||||
"use client";
|
||||
|
||||
/**
|
||||
* SHAHI KITCHEN HOMEPAGE
|
||||
* Version with advanced Signature Menu + elegant hero (pre full Sultan redesign)
|
||||
*/
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import Lenis from "lenis";
|
||||
import { gsap } from "gsap";
|
||||
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||
import { Crown, Clock, ArrowRight, UtensilsCrossed } from "lucide-react";
|
||||
import Navbar from "@/components/Navbar";
|
||||
import Footer from "@/components/Footer";
|
||||
import { useCart } from "@/components/CartContext";
|
||||
import { useLanguage } from "@/lib/language-context";
|
||||
import { getTranslation } from "@/lib/translations";
|
||||
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
|
||||
export default function ShahiKitchenHomepage() {
|
||||
const { addToCart } = useCart();
|
||||
const { language } = useLanguage();
|
||||
const t = getTranslation(language);
|
||||
|
||||
const [menuFilter, setMenuFilter] = useState<"All" | "Rice" | "Curry" | "Meat" | "Street" | "Roll" | "Sweet">("All");
|
||||
|
||||
// Lenis smooth scroll
|
||||
useEffect(() => {
|
||||
const lenis = new Lenis({
|
||||
duration: 1.1,
|
||||
easing: (t: number) => Math.min(1, 1.001 * (-Math.pow(2, -10 * t) + 1)),
|
||||
smoothWheel: true,
|
||||
});
|
||||
const raf = (time: number) => { lenis.raf(time); requestAnimationFrame(raf); };
|
||||
requestAnimationFrame(raf);
|
||||
return () => lenis.destroy();
|
||||
}, []);
|
||||
|
||||
const signatureDishes = [
|
||||
{
|
||||
id: "chicken-biryani",
|
||||
name: "Chicken Biryani",
|
||||
category: "Rice",
|
||||
price: 149,
|
||||
time: "32 min",
|
||||
desc: "Fragrant aged basmati layered with spiced chicken, saffron & caramelized onions",
|
||||
image: "chicken-biryani-poster.jpg"
|
||||
},
|
||||
{
|
||||
id: "bong-nihari",
|
||||
name: "Bong Nihari",
|
||||
category: "Curry",
|
||||
price: 199,
|
||||
time: "45 min",
|
||||
desc: "Slow-cooked beef shank in rich aromatic gravy with ginger, lemon & fresh naan",
|
||||
image: "bong-nihari-poster.jpg"
|
||||
},
|
||||
{
|
||||
id: "panipuri",
|
||||
name: "Golgappy / Panipuri",
|
||||
category: "Street",
|
||||
price: 69,
|
||||
time: "15 min",
|
||||
desc: "Crispy hollow puris filled with spiced chickpeas, potatoes & tangy tamarind water",
|
||||
image: "panipuri-poster.jpg"
|
||||
},
|
||||
{
|
||||
id: "lamm-palak",
|
||||
name: "Lamm Palak",
|
||||
category: "Meat",
|
||||
price: 179,
|
||||
time: "30 min",
|
||||
desc: "Tender lamb cooked with fresh spinach in a flavorful mild gravy",
|
||||
image: "lamm-palak-poster.jpg"
|
||||
},
|
||||
{
|
||||
id: "chicken-karahi",
|
||||
name: "Chicken Karahi",
|
||||
category: "Curry",
|
||||
price: 149,
|
||||
time: "28 min",
|
||||
desc: "Wok-tossed chicken in a robust tomato, chili & ginger gravy",
|
||||
image: "chicken-karahi-poster.jpg"
|
||||
},
|
||||
{
|
||||
id: "chicken-haleem",
|
||||
name: "Chicken Haleem",
|
||||
category: "Curry",
|
||||
price: 149,
|
||||
time: "35 min",
|
||||
desc: "Slow-cooked shredded chicken with lentils, wheat & aromatic spices",
|
||||
image: "chicken-haleem-poster.jpg"
|
||||
},
|
||||
{
|
||||
id: "tikka-boti-roll",
|
||||
name: "Tikka Boti Roll",
|
||||
category: "Roll",
|
||||
price: 99,
|
||||
time: "20 min",
|
||||
desc: "Juicy chicken tikka wrapped in soft naan with mint chutney & onions",
|
||||
image: "tikka-boti-roll-poster.jpg"
|
||||
},
|
||||
{
|
||||
id: "jalebi",
|
||||
name: "Jalebi",
|
||||
category: "Sweet",
|
||||
price: 119,
|
||||
time: "12 min",
|
||||
desc: "Crispy golden saffron spirals soaked in fragrant sugar syrup",
|
||||
image: "jalebi-poster.jpg"
|
||||
},
|
||||
{
|
||||
id: "kulfi",
|
||||
name: "Kulfi",
|
||||
category: "Sweet",
|
||||
price: 39,
|
||||
time: "10 min",
|
||||
desc: "Traditional frozen milk dessert with cardamom, pistachio & saffron",
|
||||
image: "kulfi-poster.jpg"
|
||||
},
|
||||
];
|
||||
|
||||
const filtered = menuFilter === "All" ? signatureDishes : signatureDishes.filter(d => d.category === menuFilter);
|
||||
|
||||
const addDish = (d: any) => {
|
||||
addToCart({ id: d.id, name: d.name, price: d.price, image: d.image });
|
||||
};
|
||||
|
||||
// Advanced GSAP effects for signature cards
|
||||
useEffect(() => {
|
||||
const cards = document.querySelectorAll<HTMLElement>(".signature-card");
|
||||
|
||||
gsap.fromTo(cards,
|
||||
{ opacity: 0, y: 45 },
|
||||
{
|
||||
opacity: 1, y: 0, duration: 0.9, ease: "power3.out", stagger: 0.06,
|
||||
scrollTrigger: { trigger: ".signature-menu-grid", start: "top 82%", once: true }
|
||||
}
|
||||
);
|
||||
|
||||
cards.forEach((card) => {
|
||||
const image = card.querySelector(".signature-image") as HTMLElement | null;
|
||||
let bounds: DOMRect;
|
||||
|
||||
const onMouseMove = (e: MouseEvent) => {
|
||||
if (!bounds) bounds = card.getBoundingClientRect();
|
||||
const x = ((e.clientX - bounds.left) / bounds.width - 0.5) * 2;
|
||||
const y = ((e.clientY - bounds.top) / bounds.height - 0.5) * 2;
|
||||
|
||||
gsap.to(card, {
|
||||
rotationY: x * 11, rotationX: -y * 8, transformPerspective: 1400, duration: 0.35, ease: "power2.out"
|
||||
});
|
||||
if (image) gsap.to(image, { x: x * 8, y: y * 6, duration: 0.45, ease: "power2.out" });
|
||||
};
|
||||
|
||||
const onMouseLeave = () => {
|
||||
gsap.to(card, { rotationY: 0, rotationX: 0, duration: 1.1, ease: "elastic.out(1, 0.45)" });
|
||||
if (image) gsap.to(image, { x: 0, y: 0, scale: 1, duration: 0.9, ease: "power2.out" });
|
||||
};
|
||||
|
||||
const onMouseEnter = () => {
|
||||
if (image) gsap.to(image, { scale: 1.12, duration: 1.1, ease: "power2.out" });
|
||||
};
|
||||
|
||||
card.addEventListener("mousemove", onMouseMove);
|
||||
card.addEventListener("mouseleave", onMouseLeave);
|
||||
card.addEventListener("mouseenter", onMouseEnter);
|
||||
|
||||
(card as any)._cleanup = () => {
|
||||
card.removeEventListener("mousemove", onMouseMove);
|
||||
card.removeEventListener("mouseleave", onMouseLeave);
|
||||
card.removeEventListener("mouseenter", onMouseEnter);
|
||||
};
|
||||
});
|
||||
|
||||
return () => {
|
||||
cards.forEach(card => (card as any)._cleanup?.());
|
||||
};
|
||||
}, [filtered]);
|
||||
|
||||
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 className="min-h-screen bg-[#F8F5F0] text-[#2C2A26]">
|
||||
<Navbar />
|
||||
|
||||
{/* HERO - Full Banner Video with responsive framing */}
|
||||
<section className="relative min-h-[70dvh] sm:min-h-[78dvh] md:min-h-[85dvh] lg:min-h-[92dvh] xl:min-h-[100dvh]
|
||||
flex items-center justify-center pt-20 lg:pt-[88px] overflow-hidden bg-[#fbf7ef]">
|
||||
|
||||
{/* Banner Video - Optimized positioning per device */}
|
||||
<video
|
||||
autoPlay
|
||||
muted
|
||||
loop
|
||||
playsInline
|
||||
className="absolute inset-0 z-10 w-full h-full object-cover
|
||||
object-[50%_22%] sm:object-[50%_26%] md:object-[50%_30%]
|
||||
lg:object-[50%_35%] xl:object-[50%_38%]"
|
||||
>
|
||||
<source src="/videos/banner.webm" type="video/webm" />
|
||||
<source src="/videos/banner.mp4" type="video/mp4" />
|
||||
</video>
|
||||
|
||||
{/* Subtle gradient to improve visibility of baked-in text */}
|
||||
<div className="absolute inset-0 z-20 bg-gradient-to-b from-black/5 via-transparent to-black/30" />
|
||||
</section>
|
||||
|
||||
{/* ADVANCED SIGNATURE MENU */}
|
||||
<section id="menu" className="bg-[#fffdf8] px-6 py-20 lg:px-8">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="flex flex-col md:flex-row md:items-end justify-between gap-6 mb-10">
|
||||
<div>
|
||||
<div className="mb-3 inline-flex items-center gap-2 rounded-full bg-[#fff6dc] px-4 py-1.5 text-sm font-semibold text-[#60420d]">
|
||||
<UtensilsCrossed className="h-4 w-4" /> {t.signatureMenu.title}
|
||||
</div>
|
||||
<h2 className="font-serif text-6xl leading-none tracking-[-0.055em] md:text-7xl">{t.signatureMenu.title}</h2>
|
||||
</div>
|
||||
<p className="max-w-md text-lg font-medium text-[#4b5563]">{t.signatureMenu.subtitle}</p>
|
||||
</div>
|
||||
|
||||
{/* Filters */}
|
||||
<div className="mb-8 flex flex-wrap gap-2">
|
||||
{["All", "Rice", "Curry", "Meat", "Street", "Roll", "Sweet"].map((cat) => (
|
||||
<button
|
||||
key={cat}
|
||||
onClick={() => setMenuFilter(cat as any)}
|
||||
className={`rounded-full px-6 py-3 text-sm font-bold transition-all ${menuFilter === cat ? "bg-[#101724] text-white" : "border border-[#e5e1d7] bg-white text-[#182235] hover:border-[#c99a2e] hover:bg-[#fff6dc]"}`}
|
||||
>
|
||||
{cat}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Menu Grid with Advanced Effects */}
|
||||
<div className="signature-menu-grid grid gap-5 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">
|
||||
<AnimatePresence>
|
||||
{filtered.map((dish, index) => (
|
||||
<motion.div
|
||||
key={dish.id}
|
||||
layout
|
||||
onClick={() => addDish(dish)}
|
||||
className="signature-card group flex cursor-pointer flex-col overflow-hidden rounded-[2rem] border border-[#EDE6D9] bg-white"
|
||||
>
|
||||
<div className="relative h-48 overflow-hidden bg-[#F2EDE4]">
|
||||
<img
|
||||
src={`/images/dishes/${dish.image}`}
|
||||
alt={dish.name}
|
||||
className="signature-image absolute inset-0 w-full h-full object-cover transition-transform duration-700"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-black/5 via-transparent to-black/25" />
|
||||
|
||||
<div className="absolute top-4 right-4 px-4 py-1 rounded-full bg-white/95 text-[#B38B4D] text-sm font-medium tracking-tight shadow-sm border border-[#EDE6D9]">
|
||||
{dish.price} kr
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-5 flex-1 flex flex-col">
|
||||
<h4 className="text-[21px] leading-tight tracking-[-0.5px] mb-2 group-hover:text-[#B38B4D] transition-colors">
|
||||
{dish.name}
|
||||
</h4>
|
||||
<p className="text-[#6B665F] text-[13.5px] leading-snug flex-1">{dish.desc}</p>
|
||||
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); addDish(dish); }}
|
||||
className="mt-5 w-full py-3 text-sm tracking-[0.6px] border border-[#B38B4D] text-[#B38B4D] rounded-full hover:bg-[#B38B4D] hover:text-white font-medium transition-all"
|
||||
>
|
||||
{t.signatureMenu.addToTable}
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
|
||||
<div className="mt-10 text-center">
|
||||
<a href="/menu" className="inline-flex items-center gap-2 text-sm font-bold tracking-wider text-[#B38B4D] hover:text-[#8C6B3A]">
|
||||
{t.signatureMenu.viewFullMenu} <ArrowRight className="h-4 w-4" />
|
||||
</a>
|
||||
</div>
|
||||
</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>
|
||||
</section>
|
||||
|
||||
{/* THE SHAHI EXPERIENCE */}
|
||||
<section id="experience" className="section bg-white border-y border-[#EDE6D9]">
|
||||
<div className="max-w-6xl mx-auto px-6">
|
||||
<div className="text-center mb-14">
|
||||
<div className="text-[#B38B4D] text-xs tracking-[3px] mb-3">THE SHAHI WAY</div>
|
||||
<h3 className="text-5xl md:text-6xl tracking-[-2px]">More than a meal.<br />A moment of royalty.</h3>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-3 gap-6">
|
||||
{[
|
||||
{ title: "The Legendary Buffet", desc: "Our famous lunch buffet features over 20 rotating dishes — curries, biryanis, fresh naan, and sweets." },
|
||||
{ title: "Shahi Sweets", desc: "Homemade mithai made daily. From fresh Jalebi to Rasmalai — the perfect sweet ending." },
|
||||
{ title: "Warm Hospitality", desc: "Whether you're here for a quick lunch or a family celebration, you will always be treated like royalty." },
|
||||
].map((item, index) => (
|
||||
<div key={index} className="experience-card group relative border border-[#EDE6D9] p-9 rounded-2xl bg-[#F8F5F0] overflow-hidden">
|
||||
<div className="text-[#B38B4D] text-6xl font-light mb-9 tracking-[-2px]">0{index + 1}</div>
|
||||
<h4 className="text-[29px] tracking-[-0.8px] mb-5 text-[#2C2A26] leading-tight">{item.title}</h4>
|
||||
<p className="text-[#6B665F] text-[15.5px] leading-relaxed">{item.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user