// Maison Yeya — shared components
const { useState, useEffect, useRef, useMemo, useCallback, createContext, useContext } = React;
// ──────────────────────────────────────────────────────────
// Logo / mark
// ──────────────────────────────────────────────────────────
function YeyaMark({ size = 40, color = "currentColor", className = "" }) {
// Stylized "Y / bridge" abstraction inspired by the official wordmark, drawn
// from primitives (not a tracing of the brand logo).
return (
);
}
function Wordmark({ size = 18, color = "currentColor" }) {
return (
Maison Yeya
);
}
// ──────────────────────────────────────────────────────────
// Vertical tracked rail label
// ──────────────────────────────────────────────────────────
function VRail({ children, side = "left", top = 80, style = {} }) {
const tweaks = useContext(TweakCtx);
if (!tweaks?.showVerticals) return null;
const sideStyle = side === "left" ? { left: 24 } : { right: 24 };
return (
{children}
);
}
// ──────────────────────────────────────────────────────────
// Tweak context
// ──────────────────────────────────────────────────────────
const TweakCtx = createContext({});
const ACCENTS = {
champagne: { value: "oklch(0.78 0.035 75)", deep: "oklch(0.55 0.06 60)" },
blush: { value: "oklch(0.82 0.04 20)", deep: "oklch(0.55 0.06 20)" },
ink: { value: "oklch(0.42 0.02 60)", deep: "oklch(0.28 0.02 60)" },
rouge: { value: "oklch(0.45 0.12 25)", deep: "oklch(0.32 0.12 25)" }
};
// ──────────────────────────────────────────────────────────
// Persistent CTA cluster (used in nav)
// ──────────────────────────────────────────────────────────
function HeaderCTA({ onAppointment, onEnquiry, enquiryCount }) {
return (
Enquiry
{enquiryCount}
Request Appointment
);
}
// ──────────────────────────────────────────────────────────
// Site Header (sticky)
// ──────────────────────────────────────────────────────────
function SiteHeader({ route, setRoute, onAppointment, onEnquiry, enquiryCount }) {
const [scrolled, setScrolled] = useState(false);
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 16);
window.addEventListener("scroll", onScroll, { passive: true });
onScroll();
return () => window.removeEventListener("scroll", onScroll);
}, []);
const nav = [
{ id: "home", label: "Maison" },
{ id: "bridal", label: "Bridal" },
{ id: "couture", label: "Couture" },
{ id: "atelier", label: "L'Atelier" },
{ id: "press", label: "Press" },
{ id: "contact", label: "Contact" }
];
return (
);
}
function NavLink({ active, onClick, children }) {
return (
{children}
);
}
// ──────────────────────────────────────────────────────────
// Footer
// ──────────────────────────────────────────────────────────
function SiteFooter({ setRoute, onAppointment }) {
return (
{/* Brand block */}
Maison Yeya
Bridal and couture by Yasmine Yeya — by private appointment in Dubai Design District.
Request a VIP Appointment
setRoute("home")],
["La Maison", () => setRoute("atelier")],
["Press", () => setRoute("press")],
["Contact", () => setRoute("contact")],
]}/>
setRoute("bridal")],
["Gharami", () => setRoute("bridal")],
["Shades of White", () => setRoute("bridal")],
["Utopia", () => setRoute("bridal")],
]}/>
setRoute("couture")],
["Les Marionettes", () => setRoute("couture")],
["Les Nuits d'Aphrodite", () => setRoute("couture")],
["Harmony", () => setRoute("couture")],
]}/>
setRoute("contact")],
["Press enquiries", () => setRoute("contact")],
["Careers", () => setRoute("contact")],
["Appointments", onAppointment],
]}/>
© {new Date().getFullYear()} Maison Yeya · Office 203A, Building 4A, Dubai Design District
);
}
function FooterCol({ title, items }) {
return (
{title}
{items.map(([label, onClick], i) => (
{label}
))}
);
}
// ──────────────────────────────────────────────────────────
// Look card (used everywhere)
// ──────────────────────────────────────────────────────────
function LookCard({ look, onOpen, onSave, saved, large = false, lift = false, dark = false, aspect = "2/3" }) {
const [hover, setHover] = useState(false);
return (
setHover(true)}
onMouseLeave={() => setHover(false)}
style={{ display: "flex", flexDirection: "column", gap: 0, cursor: "pointer" }}
onClick={() => onOpen && onOpen(look)}>
{/* Hover overlay */}
View Look
{ e.stopPropagation(); onSave && onSave(look); }}
className="label"
style={{
display: "inline-flex", alignItems: "center", gap: 8,
padding: "8px 14px", border: "1px solid rgba(255,255,255,0.6)", color: "#fff",
background: saved ? "#fff" : "transparent",
color: saved ? "var(--ink)" : "#fff"
}}>
{saved ? "Saved" : "Save"}
{look.name}
{look.subtitle}
{String(look.looks).padStart(2, "0")} Looks
);
}
function Heart({ filled, size = 12 }) {
return (
);
}
// ──────────────────────────────────────────────────────────
// Marquee
// ──────────────────────────────────────────────────────────
function Marquee({ items, dark = false }) {
// Duplicate items so the keyframe wraps seamlessly
const tail = items.concat(items);
return (
{tail.map((t, i) => (
{t} ✦
))}
);
}
// ──────────────────────────────────────────────────────────
// Look detail drawer
// ──────────────────────────────────────────────────────────
function LookDrawer({ look, onClose, onSave, saved, onAppointment }) {
useEffect(() => {
if (!look) return;
const onKey = (e) => { if (e.key === "Escape") onClose(); };
document.body.style.overflow = "hidden";
window.addEventListener("keydown", onKey);
return () => {
document.body.style.overflow = "";
window.removeEventListener("keydown", onKey);
};
}, [look, onClose]);
if (!look) return null;
return (
{look.subtitle}
{look.name}
"{look.note}"
Pieces from this series are available by private appointment at the atelier in Dubai Design District.
Each gown is hand-made to measure; quotation provided after consultation.
Request Appointment
onSave(look)}>
{saved ? "✓ Saved to Enquiry" : "Save to Enquiry"}
);
}
function Spec({ label, value }) {
return (
);
}
// ──────────────────────────────────────────────────────────
// Enquiry Drawer
// ──────────────────────────────────────────────────────────
function EnquiryDrawer({ open, items, onClose, onRemove, onAppointment }) {
useEffect(() => {
if (!open) return;
const onKey = (e) => { if (e.key === "Escape") onClose(); };
document.body.style.overflow = "hidden";
window.addEventListener("keydown", onKey);
return () => {
document.body.style.overflow = "";
window.removeEventListener("keydown", onKey);
};
}, [open, onClose]);
if (!open) return null;
return (
{items.length === 0 ? (
⌖
No looks saved yet. Browse Bridal or Couture and tap "Save" on any look to begin an enquiry.
) : (
{items.map(it => (
))}
We will prepare a quotation and arrange a private fitting at the atelier in Dubai Design District. Lead times will be confirmed at consultation.
Send Enquiry & Request Appointment
)}
);
}
Object.assign(window, {
YeyaMark, Wordmark, VRail, TweakCtx, ACCENTS,
SiteHeader, SiteFooter, LookCard, Marquee, LookDrawer, EnquiryDrawer, Heart
});