feat: admin auth, web menu template studio, live text editing & Ayris Tech footer backlink
This commit is contained in:
@@ -0,0 +1,556 @@
|
||||
"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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user