// desidium-sections-b.jsx — Roster, Cases, Contact, Footer const { useState: useStateB } = React; /* ---------------- ROSTER (gallery) ---------------- */ function Roster({ lang, motion, columns, onOpen }) { const r = I18N.roster; const [filter, setFilter] = useStateB("all"); const filters = [["all",r.filters.all],["twin",r.filters.twin],["soul",r.filters.soul]]; const shown = MODELS.filter((m) => filter==="all" ? true : m.div===filter); return (
{L(r.label,lang)}

{L(r.title,lang)}

{filters.map(([k,lab]) => ( ))}
{shown.map((m, i) => ( ))}
); } /* ---------------- CASES ---------------- */ function Cases({ lang, motion, go }) { const c = I18N.cases; return (
{L(c.label,lang)}

{L(c.title,lang)}

{CASES.map((cs, i) => (
{cs.beforeVideo && cs.afterVideo && ( {cs.mediaNote && {L(cs.mediaNote,lang)}} {L(c.drag,lang)} )}
{cs.no} {L(cs.client,lang)}

{L(cs.title,lang)}

{L(cs.body,lang)}

{cs.metric && ( {cs.metric} {L(cs.metricLabel,lang)} )} {cs.dubbing && go && ( )}
))}
); } /* ---------------- CONTACT ---------------- */ function Contact({ lang, motion }) { const k = I18N.contact; const [form, setForm] = useStateB({ name:"", brand:"", email:"", interest:"twin", msg:"" }); const [hp, setHp] = useStateB(""); // honeypot — must stay empty const [errors, setErrors] = useStateB({}); const [state, setState] = useStateB("idle"); // idle | sending | sent | error const set = (f) => (e) => setForm({ ...form, [f]: e.target.value }); const submit = (e) => { e.preventDefault(); const er = {}; ["name","email","msg"].forEach((f) => { if (!form[f].trim()) er[f] = true; }); if (form.email && !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(form.email)) er.email = true; setErrors(er); if (Object.keys(er).length) return; const wp = window.desidiumWp || {}; if (!wp.contactUrl) { setState("error"); return; } setState("sending"); fetch(wp.contactUrl, { method: "POST", headers: { "Content-Type": "application/json", "X-WP-Nonce": wp.restNonce || "" }, body: JSON.stringify({ name: form.name, email: form.email, brand: form.brand, interest: form.interest, message: form.msg, lang, company: hp, }), }) .then((res) => res.json().catch(() => ({})).then((data) => ({ ok: res.ok && data && data.ok }))) .then(({ ok }) => setState(ok ? "sent" : "error")) .catch(() => setState("error")); }; const opts = [["twin",k.opt_twin],["soul",k.opt_soul],["b2b",k.opt_b2b],["other",k.opt_other]]; return (
{L(k.label,lang)}

{L(k.title1,lang)}
{L(k.title2,lang)}

{L(k.sub,lang)}

{L(k.studio,lang)}
Desidium LLC
30 N Gould St Ste R
Sheridan, WY 82801 · United States
hello@desidium.studio
{state==="sent" ? (

{L(k.sent_t,lang)}

{L(k.sent_d,lang)}

) : state==="error" ? (

{L(k.err_t,lang)}

{L(k.err_d,lang)}

) : (
{errors.name && {L(k.err,lang)}}
{errors.email && {L(k.err,lang)}}
{opts.map(([v,lab]) => ( ))}
{errors.msg && {L(k.err,lang)}}
)}
); } /* ---------------- FOOTER ---------------- */ function Footer({ lang, setLang, go }) { const f = I18N.footer; const n = I18N.nav; return ( ); } Object.assign(window, { Roster, Cases, Contact, Footer });