557 lines
26 KiB
TypeScript
557 lines
26 KiB
TypeScript
"use client";
|
||
|
||
import React, { useState } from "react";
|
||
import Link from "next/link";
|
||
import { THEME_PRESETS, ThemePreset } from "@/lib/theme";
|
||
import { DEMO_RESTAURANT, DEMO_CATEGORIES } from "@/lib/demo-data";
|
||
import { PublicMenuClient } from "@/components/PublicMenuClient";
|
||
|
||
export function MenuTemplatesAdminClient() {
|
||
const [themesMap, setThemesMap] = useState<Record<string, ThemePreset>>(THEME_PRESETS);
|
||
const [activeThemeKey, setActiveThemeKey] = useState<string>("coastal");
|
||
const [activeTab, setActiveTab] = useState<"gallery" | "customize">("gallery");
|
||
const [toastMsg, setToastMsg] = useState<string | null>(null);
|
||
const [jsonModalOpen, setJsonModalOpen] = useState(false);
|
||
const [importedJson, setImportedJson] = useState("");
|
||
|
||
const currentTheme = themesMap[activeThemeKey] || THEME_PRESETS.coastal!;
|
||
|
||
const showToast = (msg: string) => {
|
||
setToastMsg(msg);
|
||
setTimeout(() => setToastMsg(null), 3000);
|
||
};
|
||
|
||
const handleUpdateCurrentTheme = (updates: Partial<ThemePreset> | Partial<ThemePreset["config"]>) => {
|
||
setThemesMap((prev) => {
|
||
const existing = prev[activeThemeKey];
|
||
if (!existing) return prev;
|
||
|
||
let updatedConfig = { ...existing.config };
|
||
let updatedTopLevel = { ...existing };
|
||
|
||
if ("primaryColor" in updates || "productLayout" in updates || "categoryLayout" in updates || "headerLayout" in updates) {
|
||
updatedConfig = { ...updatedConfig, ...updates };
|
||
} else {
|
||
updatedTopLevel = { ...updatedTopLevel, ...updates };
|
||
}
|
||
|
||
return {
|
||
...prev,
|
||
[activeThemeKey]: {
|
||
...updatedTopLevel,
|
||
config: updatedConfig,
|
||
},
|
||
};
|
||
});
|
||
};
|
||
|
||
const handleSaveAll = () => {
|
||
showToast(`"${currentTheme.name}" şablon ayarları başarıyla kaydedildi!`);
|
||
};
|
||
|
||
const handleImportJsonSubmit = () => {
|
||
try {
|
||
const parsed = JSON.parse(importedJson);
|
||
if (!parsed.key || !parsed.name || !parsed.config) {
|
||
throw new Error("Geçersiz şablon JSON formatı. 'key', 'name' ve 'config' alanları zorunludur.");
|
||
}
|
||
setThemesMap((prev) => ({
|
||
...prev,
|
||
[parsed.key]: parsed,
|
||
}));
|
||
setActiveThemeKey(parsed.key);
|
||
setJsonModalOpen(false);
|
||
setImportedJson("");
|
||
showToast(`Yeni şablon "${parsed.name}" başarıyla içe aktarıldı!`);
|
||
} catch (err: any) {
|
||
alert("Hata: " + (err?.message || "Geçersiz JSON formatı"));
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className="max-w-7xl mx-auto space-y-6">
|
||
{/* Toast Bildirimi */}
|
||
{toastMsg && (
|
||
<div className="fixed top-20 right-6 z-50 bg-[#D4AF37] text-black font-extrabold px-5 py-3 rounded-2xl shadow-2xl shadow-[#D4AF37]/30 text-xs flex items-center gap-2 animate-bounce">
|
||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2.5" d="M5 13l4 4L19 7" />
|
||
</svg>
|
||
{toastMsg}
|
||
</div>
|
||
)}
|
||
|
||
{/* Üst Karşılama Barı */}
|
||
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4 bg-[#121215] border border-white/10 p-6 rounded-3xl">
|
||
<div>
|
||
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-[#D4AF37]/10 border border-[#D4AF37]/30 text-xs font-bold text-[#D4AF37] mb-2">
|
||
🎨 WEB DİNAMİK MENÜ TEMA STÜDYOSU
|
||
</div>
|
||
<h1 className="text-2xl md:text-3xl font-black text-white tracking-tight">
|
||
Web Menü Şablon Yöneticisi
|
||
</h1>
|
||
<p className="text-xs text-zinc-400 mt-1">
|
||
Restoran web menülerinin renk paletlerini, düzen yapılarını ve tipografisini canlı cihaz simülatöründe anında test edip yönetin.
|
||
</p>
|
||
</div>
|
||
|
||
<div className="flex items-center gap-3 flex-wrap">
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
setImportedJson(JSON.stringify(currentTheme, null, 2));
|
||
setJsonModalOpen(true);
|
||
}}
|
||
className="px-4 py-2.5 rounded-xl bg-white/5 border border-white/10 hover:bg-white/10 text-xs font-bold text-zinc-300 transition-all flex items-center gap-2 cursor-pointer"
|
||
>
|
||
<svg className="w-4 h-4 text-[#D4AF37]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
|
||
</svg>
|
||
JSON İçe/Dışa Aktar
|
||
</button>
|
||
|
||
<button
|
||
type="button"
|
||
onClick={handleSaveAll}
|
||
className="px-5 py-2.5 rounded-xl bg-gradient-to-r from-[#D4AF37] to-[#F59E0B] text-black font-extrabold text-xs shadow-lg shadow-[#D4AF37]/20 hover:opacity-95 transition-all flex items-center gap-2 cursor-pointer"
|
||
>
|
||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2.5" d="M5 13l4 4L19 7" />
|
||
</svg>
|
||
Değişiklikleri Yayınla & Kaydet
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Ana İçerik Çift Sütun Düzeni: Sol Kontrol / Sağ Canlı Simülatör */}
|
||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 items-start">
|
||
{/* SOL PANEL: Şablon Galerisi ve Özelleştirici */}
|
||
<div className="lg:col-span-7 space-y-6">
|
||
{/* Sekme Butonları */}
|
||
<div className="flex items-center gap-2 p-1.5 rounded-2xl bg-[#121215] border border-white/10">
|
||
<button
|
||
type="button"
|
||
onClick={() => setActiveTab("gallery")}
|
||
className={`flex-1 py-2.5 px-4 rounded-xl font-extrabold text-xs transition-all flex items-center justify-center gap-2 cursor-pointer ${
|
||
activeTab === "gallery"
|
||
? "bg-[#D4AF37] text-black shadow-lg shadow-[#D4AF37]/20"
|
||
: "text-zinc-400 hover:text-white"
|
||
}`}
|
||
>
|
||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" />
|
||
</svg>
|
||
Hazır Şablonlar ({Object.keys(themesMap).length})
|
||
</button>
|
||
|
||
<button
|
||
type="button"
|
||
onClick={() => setActiveTab("customize")}
|
||
className={`flex-1 py-2.5 px-4 rounded-xl font-extrabold text-xs transition-all flex items-center justify-center gap-2 cursor-pointer ${
|
||
activeTab === "customize"
|
||
? "bg-[#D4AF37] text-black shadow-lg shadow-[#D4AF37]/20"
|
||
: "text-zinc-400 hover:text-white"
|
||
}`}
|
||
>
|
||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4" />
|
||
</svg>
|
||
Seçili Temayı Özelleştir ({currentTheme.key})
|
||
</button>
|
||
</div>
|
||
|
||
{/* TAB 1: ŞABLON GALERİSİ KARTLARI */}
|
||
{activeTab === "gallery" && (
|
||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||
{Object.values(themesMap).map((theme) => {
|
||
const isSelected = theme.key === activeThemeKey;
|
||
return (
|
||
<div
|
||
key={theme.key}
|
||
onClick={() => setActiveThemeKey(theme.key)}
|
||
className={`p-5 rounded-2xl border transition-all cursor-pointer space-y-4 relative overflow-hidden group ${
|
||
isSelected
|
||
? "bg-[#16161A] border-[#D4AF37] ring-2 ring-[#D4AF37]/30 shadow-xl shadow-[#D4AF37]/10"
|
||
: "bg-[#121215] border-white/10 hover:border-white/20 hover:bg-white/[0.02]"
|
||
}`}
|
||
>
|
||
{/* Üst İkon & Seçim Rozeti */}
|
||
<div className="flex items-center justify-between">
|
||
<div className="flex items-center gap-2">
|
||
<span
|
||
className="w-4 h-4 rounded-full border border-black/20 shadow-sm"
|
||
style={{ backgroundColor: theme.config.primaryColor }}
|
||
/>
|
||
<span
|
||
className="w-4 h-4 rounded-full border border-black/20 shadow-sm"
|
||
style={{ backgroundColor: theme.cardBg }}
|
||
/>
|
||
</div>
|
||
{isSelected ? (
|
||
<span className="text-[10px] bg-[#D4AF37] text-black font-extrabold px-2 py-0.5 rounded-full flex items-center gap-1">
|
||
<svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="3" d="M5 13l4 4L19 7" />
|
||
</svg>
|
||
AKTİF
|
||
</span>
|
||
) : (
|
||
<span className="text-[10px] text-zinc-500 font-mono uppercase">
|
||
{theme.key}
|
||
</span>
|
||
)}
|
||
</div>
|
||
|
||
{/* Tema Adı & Açıklama */}
|
||
<div>
|
||
<h3 className="font-extrabold text-white text-base group-hover:text-[#D4AF37] transition-colors">
|
||
{theme.name}
|
||
</h3>
|
||
<div className="flex items-center gap-2 mt-2 text-[11px] text-zinc-400">
|
||
<span className="bg-white/5 border border-white/10 px-2 py-0.5 rounded-md capitalize font-mono">
|
||
{theme.fontFamily}
|
||
</span>
|
||
<span className="bg-white/5 border border-white/10 px-2 py-0.5 rounded-md capitalize font-mono">
|
||
{theme.config.productLayout}
|
||
</span>
|
||
<span className="bg-white/5 border border-white/10 px-2 py-0.5 rounded-md capitalize font-mono">
|
||
{theme.config.categoryLayout}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Alt Butonlar */}
|
||
<div className="pt-3 border-t border-white/5 flex items-center justify-between">
|
||
<button
|
||
type="button"
|
||
onClick={(e) => {
|
||
e.stopPropagation();
|
||
setActiveThemeKey(theme.key);
|
||
setActiveTab("customize");
|
||
}}
|
||
className="text-xs font-bold text-[#D4AF37] hover:underline flex items-center gap-1"
|
||
>
|
||
Renk & Düzen Özelleştir →
|
||
</button>
|
||
</div>
|
||
</div>
|
||
);
|
||
})}
|
||
</div>
|
||
)}
|
||
|
||
{/* TAB 2: SEÇİLİ TEMAYI ÖZELLEŞTİR */}
|
||
{activeTab === "customize" && (
|
||
<div className="p-6 rounded-2xl bg-[#121215] border border-white/10 space-y-6">
|
||
<div className="flex items-center justify-between border-b border-white/10 pb-4">
|
||
<div>
|
||
<h3 className="text-lg font-bold text-white flex items-center gap-2">
|
||
<span
|
||
className="w-3.5 h-3.5 rounded-full inline-block"
|
||
style={{ backgroundColor: currentTheme.config.primaryColor }}
|
||
/>
|
||
{currentTheme.name}
|
||
</h3>
|
||
<p className="text-xs text-zinc-400 mt-0.5">
|
||
Ana renkleri, arka plan tonlarını ve düzen tiplerini anında özelleştirin.
|
||
</p>
|
||
</div>
|
||
|
||
<button
|
||
type="button"
|
||
onClick={() => setActiveTab("gallery")}
|
||
className="text-xs font-bold text-zinc-400 hover:text-white"
|
||
>
|
||
← Galeriye Dön
|
||
</button>
|
||
</div>
|
||
|
||
{/* Renk Ayarları */}
|
||
<div className="space-y-4">
|
||
<h4 className="text-xs font-extrabold text-[#D4AF37] uppercase tracking-wider">
|
||
1. Renk Paleti & Tonlar
|
||
</h4>
|
||
|
||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||
{/* Primary Color */}
|
||
<div className="space-y-1.5 p-3 rounded-xl bg-white/[0.03] border border-white/5">
|
||
<label className="text-xs font-semibold text-zinc-300 block">
|
||
Ana Vurgu Rengi (Primary)
|
||
</label>
|
||
<div className="flex items-center gap-3">
|
||
<input
|
||
type="color"
|
||
value={currentTheme.config.primaryColor || "#D4AF37"}
|
||
onChange={(e) =>
|
||
handleUpdateCurrentTheme({ primaryColor: e.target.value })
|
||
}
|
||
className="w-10 h-10 rounded-lg cursor-pointer bg-transparent border-0"
|
||
/>
|
||
<input
|
||
type="text"
|
||
value={currentTheme.config.primaryColor || "#D4AF37"}
|
||
onChange={(e) =>
|
||
handleUpdateCurrentTheme({ primaryColor: e.target.value })
|
||
}
|
||
className="flex-1 bg-black/40 border border-white/10 rounded-lg px-3 py-1.5 text-xs text-white font-mono uppercase"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Background Color */}
|
||
<div className="space-y-1.5 p-3 rounded-xl bg-white/[0.03] border border-white/5">
|
||
<label className="text-xs font-semibold text-zinc-300 block">
|
||
Sayfa Arka Plan Rengi
|
||
</label>
|
||
<div className="flex items-center gap-3">
|
||
<input
|
||
type="color"
|
||
value={currentTheme.config.background || "#FAF8F5"}
|
||
onChange={(e) =>
|
||
handleUpdateCurrentTheme({ background: e.target.value })
|
||
}
|
||
className="w-10 h-10 rounded-lg cursor-pointer bg-transparent border-0"
|
||
/>
|
||
<input
|
||
type="text"
|
||
value={currentTheme.config.background || "#FAF8F5"}
|
||
onChange={(e) =>
|
||
handleUpdateCurrentTheme({ background: e.target.value })
|
||
}
|
||
className="flex-1 bg-black/40 border border-white/10 rounded-lg px-3 py-1.5 text-xs text-white font-mono uppercase"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Card Background */}
|
||
<div className="space-y-1.5 p-3 rounded-xl bg-white/[0.03] border border-white/5">
|
||
<label className="text-xs font-semibold text-zinc-300 block">
|
||
Ürün Kart Arka Planı
|
||
</label>
|
||
<div className="flex items-center gap-3">
|
||
<input
|
||
type="color"
|
||
value={currentTheme.cardBg.startsWith("#") ? currentTheme.cardBg : "#FFFFFF"}
|
||
onChange={(e) => handleUpdateCurrentTheme({ cardBg: e.target.value })}
|
||
className="w-10 h-10 rounded-lg cursor-pointer bg-transparent border-0"
|
||
/>
|
||
<input
|
||
type="text"
|
||
value={currentTheme.cardBg}
|
||
onChange={(e) => handleUpdateCurrentTheme({ cardBg: e.target.value })}
|
||
className="flex-1 bg-black/40 border border-white/10 rounded-lg px-3 py-1.5 text-xs text-white font-mono uppercase"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Text Primary */}
|
||
<div className="space-y-1.5 p-3 rounded-xl bg-white/[0.03] border border-white/5">
|
||
<label className="text-xs font-semibold text-zinc-300 block">
|
||
Ana Başlık & Fiyat Yazı Rengi
|
||
</label>
|
||
<div className="flex items-center gap-3">
|
||
<input
|
||
type="color"
|
||
value={currentTheme.textPrimary.startsWith("#") ? currentTheme.textPrimary : "#1C1917"}
|
||
onChange={(e) => handleUpdateCurrentTheme({ textPrimary: e.target.value })}
|
||
className="w-10 h-10 rounded-lg cursor-pointer bg-transparent border-0"
|
||
/>
|
||
<input
|
||
type="text"
|
||
value={currentTheme.textPrimary}
|
||
onChange={(e) => handleUpdateCurrentTheme({ textPrimary: e.target.value })}
|
||
className="flex-1 bg-black/40 border border-white/10 rounded-lg px-3 py-1.5 text-xs text-white font-mono uppercase"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Düzen & Yerleşim Ayarları */}
|
||
<div className="space-y-4 pt-4 border-t border-white/10">
|
||
<h4 className="text-xs font-extrabold text-[#D4AF37] uppercase tracking-wider">
|
||
2. Düzen & Yerleşim Mimarisi
|
||
</h4>
|
||
|
||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||
{/* Product Layout */}
|
||
<div className="space-y-2">
|
||
<label className="text-xs font-semibold text-zinc-300 block">
|
||
Ürün Görünüm Tipi
|
||
</label>
|
||
<select
|
||
value={currentTheme.config.productLayout || "card"}
|
||
onChange={(e) =>
|
||
handleUpdateCurrentTheme({ productLayout: e.target.value as any })
|
||
}
|
||
className="w-full bg-black/40 border border-white/10 rounded-xl px-3 py-2 text-xs text-white focus:border-[#D4AF37] focus:outline-none"
|
||
>
|
||
<option value="card">Card (Kutu / Kart)</option>
|
||
<option value="list">List (Satır / Liste)</option>
|
||
</select>
|
||
</div>
|
||
|
||
{/* Category Layout */}
|
||
<div className="space-y-2">
|
||
<label className="text-xs font-semibold text-zinc-300 block">
|
||
Kategori Gezinme Tipi
|
||
</label>
|
||
<select
|
||
value={currentTheme.config.categoryLayout || "tabs"}
|
||
onChange={(e) =>
|
||
handleUpdateCurrentTheme({ categoryLayout: e.target.value as any })
|
||
}
|
||
className="w-full bg-black/40 border border-white/10 rounded-xl px-3 py-2 text-xs text-white focus:border-[#D4AF37] focus:outline-none"
|
||
>
|
||
<option value="tabs">Tabs (Yatay Sekmeler)</option>
|
||
<option value="accordion">Accordion (Açılır Kapanır)</option>
|
||
<option value="flat">Flat (Düz Sıralı)</option>
|
||
</select>
|
||
</div>
|
||
|
||
{/* Header Layout */}
|
||
<div className="space-y-2">
|
||
<label className="text-xs font-semibold text-zinc-300 block">
|
||
Header Hizalaması
|
||
</label>
|
||
<select
|
||
value={currentTheme.config.headerLayout || "centered"}
|
||
onChange={(e) =>
|
||
handleUpdateCurrentTheme({ headerLayout: e.target.value as any })
|
||
}
|
||
className="w-full bg-black/40 border border-white/10 rounded-xl px-3 py-2 text-xs text-white focus:border-[#D4AF37] focus:outline-none"
|
||
>
|
||
<option value="centered">Centered (Ortalanmış)</option>
|
||
<option value="left">Left (Sola Hizalı)</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Tipografi */}
|
||
<div className="space-y-4 pt-4 border-t border-white/10">
|
||
<h4 className="text-xs font-extrabold text-[#D4AF37] uppercase tracking-wider">
|
||
3. Tipografi & Font Ailesi
|
||
</h4>
|
||
|
||
<div className="grid grid-cols-3 gap-3">
|
||
{[
|
||
{ id: "serif", label: "Zarif Serif", desc: "Playfair / Georgia" },
|
||
{ id: "sans", label: "Modern Sans", desc: "Inter / System" },
|
||
{ id: "heading", label: "Güçlü Display", desc: "Outfit / Montserrat" },
|
||
].map((font) => (
|
||
<button
|
||
key={font.id}
|
||
type="button"
|
||
onClick={() => handleUpdateCurrentTheme({ fontFamily: font.id as any })}
|
||
className={`p-3 rounded-xl border text-left transition-all cursor-pointer ${
|
||
currentTheme.fontFamily === font.id
|
||
? "bg-[#D4AF37]/15 border-[#D4AF37] text-white"
|
||
: "bg-white/[0.02] border-white/10 text-zinc-400 hover:text-white"
|
||
}`}
|
||
>
|
||
<div className="text-xs font-bold">{font.label}</div>
|
||
<div className="text-[10px] opacity-70 mt-0.5">{font.desc}</div>
|
||
</button>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* SAĞ PANEL: Canlı İnceleme Telefon Simülatörü */}
|
||
<div className="lg:col-span-5 sticky top-20">
|
||
<div className="bg-[#121215] border border-white/10 rounded-3xl p-5 space-y-4 shadow-2xl">
|
||
<div className="flex items-center justify-between border-b border-white/10 pb-3">
|
||
<div className="flex items-center gap-2">
|
||
<div className="w-2.5 h-2.5 rounded-full bg-emerald-400 animate-pulse" />
|
||
<span className="text-xs font-bold text-white">Canlı Telefon Simülatörü</span>
|
||
</div>
|
||
<span className="text-[10px] font-mono text-[#D4AF37] bg-[#D4AF37]/10 px-2 py-0.5 rounded-full font-bold">
|
||
{currentTheme.name}
|
||
</span>
|
||
</div>
|
||
|
||
{/* Mock iPhone Frame */}
|
||
<div className="w-full max-w-[340px] h-[640px] mx-auto rounded-[40px] border-[8px] border-zinc-800 bg-black shadow-2xl overflow-hidden relative flex flex-col">
|
||
{/* iPhone Notch Header */}
|
||
<div className="w-full h-6 bg-black shrink-0 flex items-center justify-center relative z-20">
|
||
<div className="w-24 h-4 bg-zinc-900 rounded-b-xl" />
|
||
</div>
|
||
|
||
{/* Dynamic Theme Render Component */}
|
||
<div className="flex-1 overflow-y-auto relative">
|
||
<PublicMenuClient
|
||
restaurant={DEMO_RESTAURANT}
|
||
categories={DEMO_CATEGORIES}
|
||
initialThemeKey={currentTheme.key}
|
||
customThemeConfig={currentTheme.config}
|
||
/>
|
||
</div>
|
||
|
||
{/* Home Bar Indicator */}
|
||
<div className="w-full h-4 bg-black shrink-0 flex items-center justify-center z-20">
|
||
<div className="w-28 h-1 bg-zinc-700 rounded-full" />
|
||
</div>
|
||
</div>
|
||
|
||
<div className="text-center text-[11px] text-zinc-500">
|
||
Sol taraftan yaptığınız renk ve düzen değişiklikleri anında burada simüle edilir.
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* JSON İÇE / DIŞA AKTARMA MODAL */}
|
||
{jsonModalOpen && (
|
||
<div className="fixed inset-0 z-50 bg-black/80 backdrop-blur-sm flex items-center justify-center p-4">
|
||
<div className="w-full max-w-xl bg-[#121215] border border-white/15 rounded-3xl p-6 space-y-4 shadow-2xl">
|
||
<div className="flex items-center justify-between border-b border-white/10 pb-3">
|
||
<h3 className="font-extrabold text-white text-base">
|
||
Tema JSON Spesifikasyonu
|
||
</h3>
|
||
<button
|
||
type="button"
|
||
onClick={() => setJsonModalOpen(false)}
|
||
className="text-zinc-400 hover:text-white"
|
||
>
|
||
✕
|
||
</button>
|
||
</div>
|
||
|
||
<p className="text-xs text-zinc-400">
|
||
Mevcut temanın JSON kodunu kopyalayabilir veya yeni bir tema JSON spesifikasyonunu buraya yapıştırıp içe aktarabilirsiniz:
|
||
</p>
|
||
|
||
<textarea
|
||
value={importedJson}
|
||
onChange={(e) => setImportedJson(e.target.value)}
|
||
rows={12}
|
||
className="w-full bg-black/60 border border-white/10 rounded-xl p-4 text-xs font-mono text-emerald-400 focus:outline-none focus:border-[#D4AF37]"
|
||
/>
|
||
|
||
<div className="flex items-center justify-end gap-3 pt-2">
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
navigator.clipboard.writeText(importedJson);
|
||
showToast("JSON panoya kopyalandı!");
|
||
}}
|
||
className="px-4 py-2 rounded-xl bg-white/5 border border-white/10 hover:bg-white/10 text-xs font-bold text-white cursor-pointer"
|
||
>
|
||
Panoya Kopyala
|
||
</button>
|
||
<button
|
||
type="button"
|
||
onClick={handleImportJsonSubmit}
|
||
className="px-4 py-2 rounded-xl bg-[#D4AF37] text-black font-extrabold text-xs cursor-pointer shadow-lg shadow-[#D4AF37]/20"
|
||
>
|
||
İçe Aktar & Uygula
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|