/* global React, ReactDOM */
const { useState, useEffect, useRef, useMemo } = React;
const D = window.XY_DATA;
const C = window.XY_COPY;
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
"lang": "en",
"heroVariant": "wide",
"yachtsLayout": "grid",
"photoTreatment": "natural",
"accentIntensity": "signature"
}/*EDITMODE-END*/;
/* ---------- Icons ---------- */
const I = {
arrow: (props) => (
),
whatsapp: (props) => (
),
phone: (props) => (
),
pin: (props) => (
),
ruler: (p) => ,
users: (p) => ,
bed: (p) => ,
anchor: (p) => ,
check: (p) => ,
close: (p) => ,
};
const SPEC_ICONS = { length: I.ruler, guests: I.users, cabins: I.bed, crew: I.anchor };
/* ---------- Nav ---------- */
function Nav({ t, lang, setLang, onEnquire }) {
const [scrolled, setScrolled] = useState(false);
useEffect(() => {
const fn = () => setScrolled(window.scrollY > 40);
window.addEventListener("scroll", fn, { passive: true });
return () => window.removeEventListener("scroll", fn);
}, []);
return (
);
}
/* ---------- Hero ---------- */
function Hero({ t, onEnquire, photoTreatment }) {
const [idx, setIdx] = useState(0);
useEffect(() => {
const id = setInterval(() => setIdx((i) => (i + 1) % D.heroSlides.length), 6000);
return () => clearInterval(id);
}, []);
const filter = photoTreatment === "noir" ? "saturate(0.7) contrast(1.05) brightness(0.92)" : "none";
return (
{D.heroSlides.map((s, i) => (
))}
{t.hero.eyebrow}
{t.hero.h1Pre}
{t.hero.h1Em}
{D.heroSlides.map((_, i) => (
{t.hero.scroll}
);
}
/* ---------- Trust ---------- */
function Trust({ t }) {
return (
{t.trust.map((it, i) => (
0{i+1}
{it.lab}
{it.val}
{it.sup}
))}
);
}
/* ---------- Fleet ---------- */
function Fleet({ t, onEnquire }) {
const [filter, setFilter] = useState(0);
return (
{t.fleet.eyebrow}
{t.fleet.h2Pre}{t.fleet.h2Em}
{t.fleet.intro}
{t.fleet.filters.map((f, i) => (
))}
{D.yachts.map((y) => (
= 140 ? "featured" : "small")} key={y.id} onClick={onEnquire}>
{y.tag}
From / hr
AED {y.from}
{y.name}{y.length}
{y.builder}
{y.guests}Guests
{y.cabins}Cabins
{y.crew}Crew
{y.sleeps}Sleeps
))}
);
}
/* ---------- Experiences ---------- */
function Experiences({ t, onEnquire }) {
return (
{t.experiences.eyebrow}
{t.experiences.h2Pre}{t.experiences.h2Em}
{t.experiences.intro}
{D.experiences.map((e, i) => {
const span = i % 4 === 0 ? "tall" : (i % 3 === 0 ? "wide" : "med");
return (
onEnquire({ name: e.name })}>
);
})}
);
}
/* ---------- Booking ---------- */
function Booking({ t, onSubmit }) {
const [form, setForm] = useState({ yacht: "", date: "", guests: "", name: "", phone: "" });
const upd = (k) => (e) => setForm({ ...form, [k]: e.target.value });
return (
{t.booking.eyebrow}
{t.booking.h2Pre}{t.booking.h2Em}
{t.booking.copy}
{t.booking.ticks.map((s, i) => - {s}
)}
);
}
/* ---------- Heritage ---------- */
function Heritage({ t }) {
return (
{t.heritage.badge.y}
{t.heritage.badge.t}
{t.heritage.eyebrow}
{t.heritage.h2Pre}{t.heritage.h2Em}
{t.heritage.p1}
{t.heritage.p2}
{D.reviews.slice(0, 2).map((r, i) => (
{r.q}
— {r.who}
))}
);
}
/* ---------- Marina / contact ---------- */
function Marina({ t }) {
return (
);
}
/* ---------- Footer ---------- */
function Footer() {
return (
);
}
/* ---------- WhatsApp FAB ---------- */
function Fab() {
return (
Concierge
Reply within the hour
);
}
/* ---------- Modal ---------- */
function EnquireModal({ open, onClose, prefill }) {
const [sent, setSent] = useState(false);
useEffect(() => { if (!open) setSent(false); }, [open]);
if (!open) return null;
return (
e.stopPropagation()}>
{!sent ? (
<>
Tell us about your day
{prefill?.name ? `Enquiring about ${prefill.name}. ` : ""}We respond inside the hour.
>
) : (
Enquiry received.
Our concierge will reply within the hour, 8:30am–10:30pm Gulf time. For anything urgent, message us on WhatsApp.
)}
);
}
/* ---------- App ---------- */
function App() {
const [tweaks, setTweak] = window.useTweaks(TWEAK_DEFAULTS);
const lang = tweaks.lang;
const setLang = (l) => setTweak("lang", l);
const dict = C[lang] || C.en;
useEffect(() => {
document.documentElement.dir = dict.dir;
document.documentElement.lang = lang;
}, [lang, dict.dir]);
const [modal, setModal] = useState({ open: false, prefill: null });
const openModal = (prefill) => setModal({ open: true, prefill: prefill && prefill.name ? prefill : null });
// Accent intensity tweak
useEffect(() => {
const root = document.documentElement;
if (tweaks.accentIntensity === "muted") {
root.style.setProperty("--brand", "#A0394A");
} else if (tweaks.accentIntensity === "bold") {
root.style.setProperty("--brand", "#E20E33");
} else {
root.style.setProperty("--brand", "#C8102E");
}
}, [tweaks.accentIntensity]);
return (
<>