kite-menu-lang
This commit is contained in:
+34
-5
@@ -2,9 +2,11 @@
|
||||
|
||||
import { useEffect, useState, useRef } from "react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { useRouter, usePathname } from "next/navigation";
|
||||
import { MenuCategory, MenuItem as MenuItemType } from "@/data/menu";
|
||||
import { CategoryNav } from "@/components/CategoryNav";
|
||||
import { MenuItem } from "@/components/MenuItem";
|
||||
import { getDictionary } from "@/lib/dictionaries";
|
||||
|
||||
export const CATEGORY_ICONS: Record<string, string> = {
|
||||
"kahvaltiliklar": "🌅",
|
||||
@@ -35,12 +37,23 @@ type SiteSettings = {
|
||||
restaurantName: string
|
||||
}
|
||||
|
||||
export default function MenuClient({ initialCategories, siteSettings }: { initialCategories: MenuCategory[], siteSettings: SiteSettings }) {
|
||||
export default function MenuClient({ initialCategories, siteSettings, lang = "tr" }: { initialCategories: MenuCategory[], siteSettings: SiteSettings, lang?: string }) {
|
||||
const [activeCategoryId, setActiveCategoryId] = useState<string>(
|
||||
initialCategories[0]?.id || ""
|
||||
);
|
||||
const [selectedItem, setSelectedItem] = useState<MenuItemType | null>(null);
|
||||
const sectionRefs = useRef<(HTMLElement | null)[]>([]);
|
||||
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const t = getDictionary(lang);
|
||||
|
||||
const switchLanguage = (newLang: string) => {
|
||||
if (newLang === lang) return;
|
||||
// Replace the current locale in the pathname
|
||||
const newPath = pathname.replace(`/${lang}`, `/${newLang}`);
|
||||
router.push(newPath || `/${newLang}`);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const observer = new IntersectionObserver(
|
||||
@@ -81,6 +94,22 @@ export default function MenuClient({ initialCategories, siteSettings }: { initia
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Language Switcher */}
|
||||
<div className="absolute top-4 right-4 z-20 flex gap-2">
|
||||
<button
|
||||
onClick={() => switchLanguage('tr')}
|
||||
className={`px-3 py-1.5 rounded-full text-[11px] font-sans tracking-widest uppercase transition-colors ${lang === 'tr' ? 'bg-white text-stone-900 font-bold' : 'bg-black/40 text-white/90 backdrop-blur-sm border border-white/20'}`}
|
||||
>
|
||||
TR
|
||||
</button>
|
||||
<button
|
||||
onClick={() => switchLanguage('en')}
|
||||
className={`px-3 py-1.5 rounded-full text-[11px] font-sans tracking-widest uppercase transition-colors ${lang === 'en' ? 'bg-white text-stone-900 font-bold' : 'bg-black/40 text-white/90 backdrop-blur-sm border border-white/20'}`}
|
||||
>
|
||||
EN
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Dark overlay to make text readable */}
|
||||
<div className="absolute inset-0 z-0 bg-gradient-to-b from-black/60 via-black/40 to-black/80" />
|
||||
|
||||
@@ -96,7 +125,7 @@ export default function MenuClient({ initialCategories, siteSettings }: { initia
|
||||
className="text-[10px] tracking-[0.38em] uppercase mb-8 font-sans font-medium"
|
||||
style={{ color: "rgba(255,220,160,1)" }}
|
||||
>
|
||||
Akyaka · Muğla
|
||||
{siteSettings.location || t.hero.location}
|
||||
</p>
|
||||
|
||||
{/* Logo */}
|
||||
@@ -120,7 +149,7 @@ export default function MenuClient({ initialCategories, siteSettings }: { initia
|
||||
className="text-xs font-sans tracking-wide"
|
||||
style={{ color: "rgba(255,218,168,0.5)" }}
|
||||
>
|
||||
Akyaka'nın en keyifli menüsü
|
||||
{t.hero.subtitle}
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
@@ -203,7 +232,7 @@ export default function MenuClient({ initialCategories, siteSettings }: { initia
|
||||
className="text-[10px] font-sans tracking-[0.3em] uppercase mt-1"
|
||||
style={{ color: "rgba(255,200,130,0.35)" }}
|
||||
>
|
||||
Akyaka, Muğla
|
||||
{siteSettings.location || t.hero.location}
|
||||
</p>
|
||||
<div
|
||||
className="flex items-center gap-3 my-4"
|
||||
@@ -217,7 +246,7 @@ export default function MenuClient({ initialCategories, siteSettings }: { initia
|
||||
className="text-[11px] font-sans"
|
||||
style={{ color: "rgba(120,90,60,0.5)" }}
|
||||
>
|
||||
© 2026 KiteBeach Akyaka. Tüm hakları saklıdır.
|
||||
{t.footer.copyright}
|
||||
</p>
|
||||
<a
|
||||
href="https://ayris.tech"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Cormorant_Garamond, Plus_Jakarta_Sans } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import Script from "next/script";
|
||||
import "../globals.css";
|
||||
|
||||
const cormorant = Cormorant_Garamond({
|
||||
variable: "--font-cormorant",
|
||||
@@ -22,14 +23,26 @@ export const metadata: Metadata = {
|
||||
description: "Kite Beach Akyaka dijital menü.",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
export default async function RootLayout({
|
||||
children,
|
||||
params,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
params: Promise<{ lang: string }>;
|
||||
}>) {
|
||||
const { lang } = await params;
|
||||
|
||||
return (
|
||||
<html lang="tr" className={`${cormorant.variable} ${jakarta.variable} h-full`}>
|
||||
<body className="min-h-full flex flex-col antialiased" suppressHydrationWarning>{children}</body>
|
||||
<html lang={lang} className={`${cormorant.variable} ${jakarta.variable} h-full`}>
|
||||
<body className="min-h-full flex flex-col antialiased" suppressHydrationWarning>
|
||||
{children}
|
||||
{/* VPS Panel Analytics */}
|
||||
<Script
|
||||
src="https://panel.ayris.tech/api/analytics/script"
|
||||
data-domain="https://menu.kitebeachakyaka.com.tr/"
|
||||
strategy="afterInteractive"
|
||||
/>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import MenuClient from "./MenuClient";
|
||||
import MenuClient from "../MenuClient";
|
||||
import { MenuCategory } from "@/data/menu";
|
||||
|
||||
async function getMenuData(): Promise<MenuCategory[]> {
|
||||
async function getMenuData(lang: string): Promise<MenuCategory[]> {
|
||||
const dbCategories = await prisma.categories.findMany({
|
||||
where: { status: 1 },
|
||||
orderBy: { order_num: "asc" },
|
||||
@@ -17,12 +17,12 @@ async function getMenuData(): Promise<MenuCategory[]> {
|
||||
const categoryProducts = dbProducts.filter((p) => p.category_id === cat.id);
|
||||
return {
|
||||
id: cat.slug,
|
||||
title: cat.name_tr,
|
||||
title: lang === "tr" ? cat.name_tr : cat.name,
|
||||
items: categoryProducts.map((p) => ({
|
||||
id: p.id.toString(),
|
||||
name: p.name_tr,
|
||||
description: p.description_tr,
|
||||
price: p.price.toString() + " ₺",
|
||||
name: lang === "tr" ? p.name_tr : p.name,
|
||||
description: (lang === "tr" ? p.description_tr : p.description) || "",
|
||||
price: p.price.toString() + (lang === "tr" ? " ₺" : " ₺"), // Or maybe dynamic currency formatting
|
||||
image: p.image_url || '/default-product.png',
|
||||
})),
|
||||
};
|
||||
@@ -43,11 +43,17 @@ async function getSiteSettings() {
|
||||
}
|
||||
}
|
||||
|
||||
export default async function Page() {
|
||||
export default async function Page({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ lang: string }>;
|
||||
}) {
|
||||
const { lang } = await params;
|
||||
|
||||
const [menuData, siteSettings] = await Promise.all([
|
||||
getMenuData(),
|
||||
getMenuData(lang),
|
||||
getSiteSettings(),
|
||||
]);
|
||||
|
||||
return <MenuClient initialCategories={menuData} siteSettings={siteSettings} />;
|
||||
return <MenuClient initialCategories={menuData} siteSettings={siteSettings} lang={lang} />;
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Reference in New Issue
Block a user