feat(themes): add Neon Street Fuze graffiti burger/taco menu design system
This commit is contained in:
@@ -156,6 +156,7 @@ export const restaurantsRoutes: FastifyPluginAsync = async (app) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const THEME_NAMES: Record<string, string> = {
|
const THEME_NAMES: Record<string, string> = {
|
||||||
|
neon: "Neon Street Fuze",
|
||||||
maison: "La Maison d'Élève",
|
maison: "La Maison d'Élève",
|
||||||
swiss: "Swiss Brutalist",
|
swiss: "Swiss Brutalist",
|
||||||
artisan: "Amber Artisan",
|
artisan: "Amber Artisan",
|
||||||
|
|||||||
@@ -31,6 +31,18 @@ export interface ThemeOption {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const THEME_OPTIONS: ThemeOption[] = [
|
export const THEME_OPTIONS: ThemeOption[] = [
|
||||||
|
{
|
||||||
|
key: "neon",
|
||||||
|
name: "Neon Street Fuze",
|
||||||
|
category: "Street Food & Burger / Neon",
|
||||||
|
color: "#FF2A85",
|
||||||
|
badgeBg: "#0070F3",
|
||||||
|
badgeText: "#FFFFFF",
|
||||||
|
bgPreview: "#0D1117",
|
||||||
|
accent: "Neon Pembe & Lime Yeşili",
|
||||||
|
desc: "Grafiti sokak sanatı, neon ışıltılar, krem rengi burger/taco kartları ve açılı fiyat etiketleri.",
|
||||||
|
suitableFor: "Smash burgerciler, taco barlar, sokak lezzetleri, Asya füzyon & kokteyl barlar",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: "maison",
|
key: "maison",
|
||||||
name: "La Maison d'Élève",
|
name: "La Maison d'Élève",
|
||||||
|
|||||||
@@ -315,7 +315,7 @@ export function PublicMenuClient({
|
|||||||
<div className="bg-stone-900 text-white px-5 py-4 border-b border-stone-800 animate-slide-up">
|
<div className="bg-stone-900 text-white px-5 py-4 border-b border-stone-800 animate-slide-up">
|
||||||
<div className="flex items-center justify-between mb-3">
|
<div className="flex items-center justify-between mb-3">
|
||||||
<p className="text-xs font-bold uppercase tracking-wider text-stone-400">
|
<p className="text-xs font-bold uppercase tracking-wider text-stone-400">
|
||||||
Canlı Tema Önizleme (8 Şablon)
|
Canlı Tema Önizleme (9 Şablon)
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -325,7 +325,7 @@ export function PublicMenuClient({
|
|||||||
Kapat ✕
|
Kapat ✕
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-4 sm:grid-cols-4 md:grid-cols-8 gap-2">
|
<div className="grid grid-cols-3 sm:grid-cols-5 md:grid-cols-9 gap-2">
|
||||||
{Object.values(THEME_PRESETS).map((preset) => {
|
{Object.values(THEME_PRESETS).map((preset) => {
|
||||||
const isSelected = selectedThemeKey === preset.key;
|
const isSelected = selectedThemeKey === preset.key;
|
||||||
return (
|
return (
|
||||||
@@ -426,12 +426,13 @@ export function PublicMenuClient({
|
|||||||
const chapterNum = String(catIndex + 1).padStart(2, "0");
|
const chapterNum = String(catIndex + 1).padStart(2, "0");
|
||||||
const isSwiss = theme.key === "swiss";
|
const isSwiss = theme.key === "swiss";
|
||||||
const isMaison = theme.key === "maison";
|
const isMaison = theme.key === "maison";
|
||||||
|
const isNeon = theme.key === "neon";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
key={category.id}
|
key={category.id}
|
||||||
id={`category-${category.id}`}
|
id={`category-${category.id}`}
|
||||||
className={isSwiss ? "scroll-mt-28 space-y-0" : isMaison ? "scroll-mt-28 space-y-4" : "scroll-mt-28 space-y-3.5"}
|
className={isSwiss ? "scroll-mt-28 space-y-0" : isMaison ? "scroll-mt-28 space-y-4" : isNeon ? "scroll-mt-28 space-y-3.5" : "scroll-mt-28 space-y-3.5"}
|
||||||
>
|
>
|
||||||
{/* Category Heading Banner */}
|
{/* Category Heading Banner */}
|
||||||
{isSwiss ? (
|
{isSwiss ? (
|
||||||
@@ -472,6 +473,20 @@ export function PublicMenuClient({
|
|||||||
<div className="absolute right-0 -top-[2px] w-1.5 h-1.5 bg-[#24463A] rounded-full"></div>
|
<div className="absolute right-0 -top-[2px] w-1.5 h-1.5 bg-[#24463A] rounded-full"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : isNeon ? (
|
||||||
|
<div className="sticky top-[58px] z-20 bg-[#0D1117]/95 backdrop-blur-xl border-b border-pink-500/30 py-3 px-3 flex items-center justify-between transition-all shadow-[0_4px_20px_rgba(255,42,133,0.15)]">
|
||||||
|
<div>
|
||||||
|
<span className="text-[10px] font-black uppercase tracking-wider text-[#00FF87] drop-shadow-[0_0_8px_rgba(0,255,135,0.6)] block">
|
||||||
|
⚡ DROPS // SECTION
|
||||||
|
</span>
|
||||||
|
<h2 className="text-xl sm:text-2xl font-black uppercase tracking-tight text-white drop-shadow-[0_2px_10px_rgba(255,42,133,0.4)]">
|
||||||
|
{category.name}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<span className="bg-[#FF2A85] text-white text-[10px] font-black uppercase px-3 py-1 rounded-full shadow-[0_0_12px_rgba(255,42,133,0.7)] -rotate-2">
|
||||||
|
{category.menu_items.length} DROPS
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
className="sticky top-[58px] z-20 flex items-center justify-between py-2.5 px-3 -mx-3 rounded-2xl backdrop-blur-xl border-b transition-all shadow-sm"
|
className="sticky top-[58px] z-20 flex items-center justify-between py-2.5 px-3 -mx-3 rounded-2xl backdrop-blur-xl border-b transition-all shadow-sm"
|
||||||
@@ -509,6 +524,8 @@ export function PublicMenuClient({
|
|||||||
? "divide-y-2 divide-black border-b-2 border-black"
|
? "divide-y-2 divide-black border-b-2 border-black"
|
||||||
: isMaison
|
: isMaison
|
||||||
? "grid grid-cols-1 gap-4"
|
? "grid grid-cols-1 gap-4"
|
||||||
|
: isNeon
|
||||||
|
? "grid grid-cols-1 gap-3.5"
|
||||||
: theme.key === "artisan"
|
: theme.key === "artisan"
|
||||||
? "grid grid-cols-2 gap-3 sm:gap-4"
|
? "grid grid-cols-2 gap-3 sm:gap-4"
|
||||||
: theme.config.productLayout === "list"
|
: theme.config.productLayout === "list"
|
||||||
@@ -517,6 +534,62 @@ export function PublicMenuClient({
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
{category.menu_items.map((item, itemIndex) => {
|
{category.menu_items.map((item, itemIndex) => {
|
||||||
|
if (isNeon) {
|
||||||
|
return (
|
||||||
|
<article
|
||||||
|
key={item.id}
|
||||||
|
onClick={() => setSelectedItem(item)}
|
||||||
|
className="group relative bg-[#FCF7EC] rounded-3xl p-4 overflow-hidden border border-white/20 shadow-2xl text-black cursor-pointer hover:scale-[1.02] active:scale-[0.98] transition-all duration-300 flex flex-col sm:flex-row gap-3.5 items-center justify-between"
|
||||||
|
>
|
||||||
|
{/* Floating Badges */}
|
||||||
|
<div className="absolute right-3 top-3 flex gap-1.5 z-20">
|
||||||
|
<span className="bg-[#FFD600] text-black text-[9px] font-black uppercase px-2 py-0.5 rounded-full shadow -rotate-2 border border-black/10">
|
||||||
|
POPULAR
|
||||||
|
</span>
|
||||||
|
<span className="bg-black text-[#FF3B30] text-[9px] font-black uppercase px-2 py-0.5 rounded-full flex items-center gap-1 shadow">
|
||||||
|
SPICY 🔥
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Details */}
|
||||||
|
<div className="flex-1 min-w-0 pr-2 z-10 w-full">
|
||||||
|
<h3 className="font-black text-xl sm:text-2xl uppercase tracking-tight text-[#101419] group-hover:text-[#FF2A85] transition-colors leading-tight">
|
||||||
|
{item.name}
|
||||||
|
</h3>
|
||||||
|
{item.description && (
|
||||||
|
<p className="text-xs font-semibold text-stone-700 mt-1 leading-snug line-clamp-2">
|
||||||
|
{item.description}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
<div className="flex flex-wrap gap-1.5 mt-3">
|
||||||
|
<span className="bg-[#00FF87]/25 text-emerald-950 text-[8px] font-extrabold uppercase px-2 py-0.5 rounded-md border border-emerald-500/30">
|
||||||
|
STREET SPECIAL
|
||||||
|
</span>
|
||||||
|
<span className="bg-blue-100 text-blue-950 text-[8px] font-extrabold uppercase px-2 py-0.5 rounded-md border border-blue-400/30">
|
||||||
|
CRISPY
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Image with Rotated Cloud Price Tag */}
|
||||||
|
{item.image_url && (
|
||||||
|
<div className="relative w-full sm:w-28 aspect-video sm:aspect-square flex-shrink-0 flex justify-end">
|
||||||
|
<img
|
||||||
|
src={item.image_url}
|
||||||
|
alt={item.name}
|
||||||
|
className="w-full h-full object-cover rounded-2xl shadow-md group-hover:scale-105 transition-transform duration-300"
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
{/* Angled Price Badge */}
|
||||||
|
<div className="absolute -bottom-2 -right-1 bg-[#00FF87] text-black font-black px-2.5 py-0.5 rounded-xl shadow-xl border-2 border-black -rotate-6 text-center leading-none">
|
||||||
|
<div className="text-[7px] uppercase font-black">PRICE</div>
|
||||||
|
<div className="text-base font-black">₺{item.price.toFixed(0)}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</article>
|
||||||
|
);
|
||||||
|
}
|
||||||
if (isMaison) {
|
if (isMaison) {
|
||||||
return (
|
return (
|
||||||
<article
|
<article
|
||||||
|
|||||||
@@ -16,6 +16,25 @@ export interface ThemePreset {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const THEME_PRESETS: Record<string, ThemePreset> = {
|
export const THEME_PRESETS: Record<string, ThemePreset> = {
|
||||||
|
neon: {
|
||||||
|
key: "neon",
|
||||||
|
name: "Neon Street Fuze",
|
||||||
|
fontFamily: "heading",
|
||||||
|
config: {
|
||||||
|
primaryColor: "#FF2A85",
|
||||||
|
background: "#0D1117",
|
||||||
|
productLayout: "card",
|
||||||
|
categoryLayout: "tabs",
|
||||||
|
},
|
||||||
|
cardBg: "#FCF7EC",
|
||||||
|
cardBorder: "rgba(255, 42, 133, 0.3)",
|
||||||
|
textPrimary: "#101419",
|
||||||
|
textSecondary: "#4B5563",
|
||||||
|
accentBg: "rgba(0, 255, 135, 0.15)",
|
||||||
|
headerGradient: "linear-gradient(180deg, #161B22 0%, #0D1117 100%)",
|
||||||
|
badgeBg: "#0070F3",
|
||||||
|
badgeText: "#FFFFFF",
|
||||||
|
},
|
||||||
maison: {
|
maison: {
|
||||||
key: "maison",
|
key: "maison",
|
||||||
name: "La Maison d'Élève",
|
name: "La Maison d'Élève",
|
||||||
|
|||||||
Reference in New Issue
Block a user