feat(themes): add La Maison d'Élève French luxury editorial restaurant design system

This commit is contained in:
AyrisAI
2026-08-20 03:41:07 +03:00
parent de8bd506b8
commit 809200550e
4 changed files with 111 additions and 3 deletions
+1
View File
@@ -156,6 +156,7 @@ export const restaurantsRoutes: FastifyPluginAsync = async (app) => {
}
const THEME_NAMES: Record<string, string> = {
maison: "La Maison d'Élève",
swiss: "Swiss Brutalist",
artisan: "Amber Artisan",
elegant: "Elegant Gold",
@@ -31,6 +31,18 @@ export interface ThemeOption {
}
export const THEME_OPTIONS: ThemeOption[] = [
{
key: "maison",
name: "La Maison d'Élève",
category: "Fransız Haute Cuisine & Lüks",
color: "#24463A",
badgeBg: "#E3DDD4",
badgeText: "#24463A",
bgPreview: "#EEEAE4",
accent: "Orman Yeşili & Fransız Krem",
desc: "Zarif serif tipografi, Fransız editoryal mizanpaj, pin çizgileri ve | ₺180 | özel fiyatlandırma stili.",
suitableFor: "Lüks otel restoranları, Fransız mutfağı, degustasyon menüleri, şarap salonları",
},
{
key: "swiss",
name: "Swiss Brutalist",
+79 -3
View File
@@ -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="flex items-center justify-between mb-3">
<p className="text-xs font-bold uppercase tracking-wider text-stone-400">
Canlı Tema Önizleme (7 Şablon)
Canlı Tema Önizleme (8 Şablon)
</p>
<button
type="button"
@@ -325,7 +325,7 @@ export function PublicMenuClient({
Kapat
</button>
</div>
<div className="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-7 gap-2">
<div className="grid grid-cols-4 sm:grid-cols-4 md:grid-cols-8 gap-2">
{Object.values(THEME_PRESETS).map((preset) => {
const isSelected = selectedThemeKey === preset.key;
return (
@@ -425,12 +425,13 @@ export function PublicMenuClient({
filteredCategories.map((category, catIndex) => {
const chapterNum = String(catIndex + 1).padStart(2, "0");
const isSwiss = theme.key === "swiss";
const isMaison = theme.key === "maison";
return (
<section
key={category.id}
id={`category-${category.id}`}
className={isSwiss ? "scroll-mt-28 space-y-0" : "scroll-mt-28 space-y-3.5"}
className={isSwiss ? "scroll-mt-28 space-y-0" : isMaison ? "scroll-mt-28 space-y-4" : "scroll-mt-28 space-y-3.5"}
>
{/* Category Heading Banner */}
{isSwiss ? (
@@ -452,6 +453,25 @@ export function PublicMenuClient({
Ø{catIndex + 1}
</div>
</div>
) : isMaison ? (
<div className="sticky top-[58px] z-20 bg-[#EEEAE4]/95 backdrop-blur-xl border-b border-[#24463A]/20 py-3.5 px-3 flex items-baseline justify-between transition-all">
<div className="flex items-baseline gap-3.5">
<span className="text-3xl sm:text-4xl font-serif font-light text-[#24463A]">
{chapterNum}
</span>
<div>
<h2 className="text-xl sm:text-2xl font-serif font-bold uppercase tracking-tight text-[#1A1A1A]">
{category.name}
</h2>
<p className="text-[10px] tracking-widest uppercase text-stone-500 font-sans mt-0.5">
{category.description || "Sélection Culinaire"}
</p>
</div>
</div>
<div className="w-20 sm:w-32 h-[1px] bg-[#24463A]/40 relative self-center">
<div className="absolute right-0 -top-[2px] w-1.5 h-1.5 bg-[#24463A] rounded-full"></div>
</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"
@@ -487,6 +507,8 @@ export function PublicMenuClient({
className={
isSwiss
? "divide-y-2 divide-black border-b-2 border-black"
: isMaison
? "grid grid-cols-1 gap-4"
: theme.key === "artisan"
? "grid grid-cols-2 gap-3 sm:gap-4"
: theme.config.productLayout === "list"
@@ -495,6 +517,60 @@ export function PublicMenuClient({
}
>
{category.menu_items.map((item, itemIndex) => {
if (isMaison) {
return (
<article
key={item.id}
onClick={() => setSelectedItem(item)}
className="group bg-[#F7F4EF] rounded-2xl p-4 sm:p-5 border border-[#24463A]/15 hover:border-[#24463A]/40 transition-all duration-300 cursor-pointer shadow-sm flex flex-col sm:flex-row gap-4 items-center justify-between"
>
{/* Image with subtle clay circle and forest green accent */}
{item.image_url && (
<div className="relative w-full sm:w-32 aspect-video sm:aspect-square flex-shrink-0">
<div className="absolute -top-2 -left-2 w-14 h-14 bg-[#C9C1B5]/40 rounded-full z-0 pointer-events-none"></div>
<div className="relative z-10 w-full h-full rounded-xl overflow-hidden shadow-sm">
<img
src={item.image_url}
alt={item.name}
className="w-full h-full object-cover grayscale-[0.2] group-hover:grayscale-0 group-hover:scale-105 transition-all duration-500"
loading="lazy"
/>
<div className="absolute -bottom-1 -right-1 w-3.5 h-3.5 bg-[#24463A]"></div>
</div>
</div>
)}
{/* Details */}
<div className="flex-1 min-w-0 w-full">
<div className="flex justify-between items-start gap-3">
<div>
<h3 className="text-lg sm:text-xl font-serif font-bold uppercase tracking-tight text-[#1A1A1A] group-hover:text-[#24463A] transition-colors leading-tight">
{item.name}
</h3>
{item.description && (
<p className="text-xs sm:text-sm font-serif text-[#5C5852] mt-1 leading-relaxed line-clamp-2">
{item.description}
</p>
)}
</div>
<div className="text-right flex-shrink-0">
<span className="text-[9px] uppercase tracking-wider text-stone-500 font-serif italic block">
Maison
</span>
<div className="w-5 h-[1px] bg-[#24463A]/40 ml-auto mt-1"></div>
</div>
</div>
<div className="mt-3 flex justify-end">
<span className="text-base sm:text-lg font-light font-sans border-x border-[#1A1A1A]/20 px-3 py-0.5 text-[#1A1A1A]">
| {item.price.toFixed(0)} |
</span>
</div>
</div>
</article>
);
}
if (isSwiss) {
const itemCode = `${String.fromCharCode(65 + catIndex)}${String(itemIndex + 1).padStart(2, "0")}`;
return (
+19
View File
@@ -16,6 +16,25 @@ export interface ThemePreset {
}
export const THEME_PRESETS: Record<string, ThemePreset> = {
maison: {
key: "maison",
name: "La Maison d'Élève",
fontFamily: "serif",
config: {
primaryColor: "#24463A",
background: "#EEEAE4",
productLayout: "card",
categoryLayout: "tabs",
},
cardBg: "#F7F4EF",
cardBorder: "rgba(36, 70, 58, 0.2)",
textPrimary: "#1A1A1A",
textSecondary: "#5C5852",
accentBg: "rgba(36, 70, 58, 0.08)",
headerGradient: "linear-gradient(180deg, #182C24 0%, #11201A 100%)",
badgeBg: "#E3DDD4",
badgeText: "#24463A",
},
swiss: {
key: "swiss",
name: "Swiss Brutalist",