// Shared UI components for the hi-fi site. const { useState, useEffect, useRef } = React; // ─── IMAGE SLOT — shows a real photo when `src` is set, else a placeholder ── function ImgSlot({ label, src, h, aspect, accent, span, position, style = {} }) { return (
{src ? ( {label ) : (
◇ IMG
{label}
)}
); } // ─── NAV ───────────────────────────────────────────────────── function Nav({ page, setPage, scrollTo }) { const [scrolled, setScrolled] = useState(false); useEffect(() => { const fn = () => setScrolled(window.scrollY > 40); window.addEventListener("scroll", fn); return () => window.removeEventListener("scroll", fn); }, []); const isStyle = page.type === "style"; const style = isStyle ? STYLES_DATA[page.artistId]?.find(s => s.id === page.styleId) : null; const NAV_IDS = ["hero", "artistas", "processo", "depoimentos", "faq", "contato"]; const active = useScrollSpy(NAV_IDS); return ( ); } // ─── SECTION HEAD ──────────────────────────────────────────── function SectionHead({ label, title, kicker }) { return (

{label}

{kicker &&

{kicker}

}

{title}

); } // ─── LIGHTBOX ──────────────────────────────────────────────── function Lightbox({ items, index, onClose, onNav }) { useEffect(() => { const onKey = (e) => { if (e.key === "Escape") onClose(); if (e.key === "ArrowRight") onNav(1); if (e.key === "ArrowLeft") onNav(-1); }; window.addEventListener("keydown", onKey); const prevOverflow = document.body.style.overflow; document.body.style.overflow = "hidden"; return () => { window.removeEventListener("keydown", onKey); document.body.style.overflow = prevOverflow; }; }, [onClose, onNav]); if (index == null) return null; const item = items[index]; const label = typeof item === "string" ? item : item.label; const src = typeof item === "string" ? null : item.src; const navBtn = (dir) => ({ background: "rgba(0,0,0,0.4)", border: `1px solid ${C.gray3}`, color: C.white, width: 52, height: 52, borderRadius: "50%", cursor: "pointer", fontSize: "1.4rem", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, transition: "background 0.15s, border-color 0.15s", }); return (
{/* Top bar */}
{label} · {index + 1} / {items.length}
{/* Stage */}
e.stopPropagation()} style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", gap: "1.5rem", padding: "0 1.6rem 2rem", minHeight: 0, }}>
{src ? ( {label} ) : (
{label}

FOTO EM BREVE
)}
); } // ─── GALLERY ───────────────────────────────────────────────── function Gallery({ labels, filter }) { const [hov, setHov] = useState(null); const [lbIndex, setLbIndex] = useState(null); const nav = (dir) => setLbIndex((i) => (i + dir + labels.length) % labels.length); return (
{labels.map((item, i) => { const wide = i === 0 || i === 5; const label = typeof item === "string" ? item : item.label; const src = typeof item === "string" ? null : item.src; const pos = typeof item === "string" ? undefined : item.position; return ( setHov(i)} onMouseLeave={() => setHov(null)} onClick={() => setLbIndex(i)} style={{ gridColumn: wide ? "span 2" : "span 1", aspectRatio: wide ? "2/1" : "1/1", position: "relative", cursor: "pointer", filter: hov === i ? "brightness(1.15)" : "brightness(1)", }}> {hov === i && (
VER
)}
); })}
{lbIndex != null && ( setLbIndex(null)} onNav={nav} /> )}
); } // ─── LEAD FORM (long) ──────────────────────────────────────── function LeadForm({ prefillArtist = "", prefillStyle = "" }) { const [form, setForm] = useState({ nome: "", whatsapp: "", artista: prefillArtist, estilo: prefillStyle, local: "", descricao: "", referencia: "", origem: "", }); const [errors, setErrors] = useState({}); const [sent, setSent] = useState(false); const [sending, setSending] = useState(false); const [waUrl, setWaUrl] = useState(""); const set = (k, v) => setForm(p => ({ ...p, [k]: v })); // Resolve which artist receives the lead: explicit choice wins; otherwise // infer from the selected style only when it belongs to a single artist; // otherwise default to Fabioness. const resolveArtist = () => { if (form.artista === "fabioness" || form.artista === "nanda") return form.artista; if (form.estilo) { const owners = Object.keys(STYLES_DATA).filter( aid => STYLES_DATA[aid].some(s => s.id === form.estilo) ); if (owners.length === 1) return owners[0]; } return "fabioness"; }; const styleLabel = (id) => { for (const aid of Object.keys(STYLES_DATA)) { const s = STYLES_DATA[aid].find(x => x.id === id); if (s) return s.label; } return ""; }; const REF_LABELS = { sim: "Sim, tenho referências prontas", parcial: "Tenho referências parciais", nao: "Não, preciso de ajuda", }; const ORIGEM_LABELS = { instagram: "Instagram", google: "Google", indicacao: "Indicação", tiktok: "TikTok", youtube: "YouTube", }; const buildWaUrl = (artistId) => { const a = ARTISTS[artistId]; const L = []; L.push("Olá! Vim pelo site do Estúdio Casa e gostaria de solicitar um orçamento."); L.push(""); L.push(`*Nome:* ${form.nome}`); L.push(`*WhatsApp:* ${form.whatsapp}`); L.push(`*Artista:* ${a.name}`); if (form.estilo) L.push(`*Estilo:* ${styleLabel(form.estilo)}`); if (form.local) L.push(`*Local no corpo:* ${form.local}`); if (form.referencia) L.push(`*Tem referência:* ${REF_LABELS[form.referencia] || form.referencia}`); if (form.origem) L.push(`*Como encontrou:* ${ORIGEM_LABELS[form.origem] || form.origem}`); L.push(""); L.push("*Projeto:*"); L.push(form.descricao); return `https://wa.me/${a.whatsapp}?text=${encodeURIComponent(L.join("\n"))}`; }; const submit = () => { const e = {}; if (!form.nome.trim()) e.nome = "Obrigatório"; if (!form.whatsapp.trim() || form.whatsapp.replace(/\D/g, "").length < 10) e.whatsapp = "WhatsApp inválido"; if (!form.descricao.trim()) e.descricao = "Obrigatório"; if (Object.keys(e).length) { setErrors(e); return; } setErrors({}); const url = buildWaUrl(resolveArtist()); setWaUrl(url); setSending(true); // Try to open directly off the click (kept inside the user-gesture so the // browser allows the popup). In sandboxed previews this may be blocked // (ERR_BLOCKED_BY_RESPONSE) — the confirmation screen always shows a real // anchor the user can tap, which works on the live site. try { window.open(url, "_blank", "noopener"); } catch (_) {} setTimeout(() => { setSending(false); setSent(true); }, 700); }; const inp = (err) => ({ width: "100%", background: C.bg, border: `1px solid ${err ? "#c0392b" : C.line}`, color: C.white, padding: "12px 16px", ...TY.body, outline: "none", marginTop: "0.5rem", fontFamily: F, }); const lbl = { ...TY.label, color: C.gray3, display: "block", marginTop: "1.5rem" }; const err = { ...TY.micro, color: "#c0392b", marginTop: "0.3rem", display: "block" }; if (sent) return (

QUASE LÁ

Seu projeto está pronto. Toque no botão abaixo para abrir a conversa
no WhatsApp com tudo já preenchido — é só apertar enviar.

ABRIR WHATSAPP →

RESPONDEMOS EM ATÉ 24H

); return (

FORMULÁRIO DE ORÇAMENTO

Solicitar Orçamento

set("nome", e.target.value)} style={inp(errors.nome)} placeholder="Seu nome" /> {errors.nome && {errors.nome}}
set("whatsapp", e.target.value)} style={inp(errors.whatsapp)} placeholder="(11) 9 0000-0000" /> {errors.whatsapp && {errors.whatsapp}}
set("local", e.target.value)} style={inp(false)} placeholder="Ex: antebraço esquerdo" />