/* ============================================================
UVD CLUB — componentes compartilhados
============================================================ */
const { useState, useEffect, useRef } = React;
/* ---- helpers ---- */
const fmtBRL = (n) =>
"R$ " + n.toFixed(2).replace(".", ",").replace(/\B(?=(\d{3})+(?!\d))/g, ".");
/* ---- responsivo ---- */
function useIsMobile(bp = 760) {
const [m, setM] = useState(typeof window !== "undefined" && window.innerWidth <= bp);
useEffect(() => {
const on = () => setM(window.innerWidth <= bp);
window.addEventListener("resize", on);
on();
return () => window.removeEventListener("resize", on);
}, [bp]);
return m;
}
/* ---- placeholder de imagem ---- */
function Placeholder({ label, ratio, rounded, style, className }) {
const st = { ...style };
if (ratio) st.aspectRatio = ratio.replace("/", " / ");
if (rounded) st.borderRadius = rounded;
return (
{label}
);
}
/* ---- imagem real OU placeholder (decide pelo campo .src) ---- */
function Img({ src, label, ratio, rounded, pos, fit, bg, style, className }) {
if (!src) return ;
const st = { ...style };
if (ratio) st.aspectRatio = ratio.replace("/", " / ");
if (rounded) st.borderRadius = rounded;
st.overflow = "hidden";
if (bg) st.background = bg;
return (
);
}
/* ---- logo ---- */
function Logo({ height = 46, variant = "image" }) {
if (variant === "text") {
return (
UVD
Club
);
}
const white = variant === "white";
return
;
}
/* ---- color dot ---- */
function ColorDot({ hex, active, onClick, size = 26, title }) {
return (
);
}
/* ---- announcement bar (marquee fininho) ---- */
function AnnouncementBar() {
const items = ["Frete grátis acima de R$ 199", "✶", "Novidades toda semana", "✶", "Parcele em até 6x", "✶", "Reading is sexy", "✶"];
const row = [...items, ...items];
return (
{row.map((t, i) => (
{t}
))}
);
}
/* ---- header ---- */
function Header({ cartCount, onCart, onHome, onNav, transparent, menuVariant = "standard" }) {
const [scrolled, setScrolled] = useState(false);
const isMobile = useIsMobile();
useEffect(() => {
const root = document.querySelector("#scrollroot") || window;
const onScroll = () => {
const y = root === window ? window.scrollY : root.scrollTop;
setScrolled(y > 24);
};
root.addEventListener("scroll", onScroll);
return () => root.removeEventListener("scroll", onScroll);
}, []);
const cats = ["Moletons & Roupas", "Acessórios", "Papelaria", "Sobre"];
const navLink = (c, extra) => (
onNav && onNav(c)} className="ui-label"
style={{ fontSize: 12, color: "var(--ink)", cursor: "pointer", paddingBottom: 2, borderBottom: "1px solid transparent", transition: "border-color .2s", ...extra }}
onMouseEnter={(e) => (e.currentTarget.style.borderColor = "var(--wine)")}
onMouseLeave={(e) => (e.currentTarget.style.borderColor = "transparent")}>
{c}
);
const actions = (
{!isMobile && Buscar}
{!isMobile && Conta}
);
const headerBase = {
position: "sticky", top: 0, zIndex: 40,
background: scrolled ? "rgba(250,245,236,0.92)" : "var(--cream)",
backdropFilter: scrolled ? "saturate(140%) blur(8px)" : "none",
borderBottom: "1px solid var(--line)",
transition: "background .3s",
};
/* ---- OPÇÃO 01 — cabeçalho editorial: logo à esquerda + nav ao lado ---- */
if (menuVariant === "editorial" && !isMobile) {
return (
{actions}
);
}
/* ---- OPÇÕES 02 & 03 / mobile — cabeçalho padrão em 3 colunas ---- */
return (
);
}
/* ---- product card ---- */
function ProductCard({ p, onOpen, onAdd, variant = "editorial" }) {
const [hover, setHover] = useState(false);
const club = variant === "club";
return (
setHover(true)}
onMouseLeave={() => setHover(false)}
style={{ cursor: "pointer", display: "flex", flexDirection: "column" }}
onClick={() => onOpen(p.id)}
>

{p.tag && (
{p.tag}
)}
{/* quick add */}
{p.cat}
{p.name}
{fmtBRL(p.price)}
{p.compareAt && {fmtBRL(p.compareAt)}}
{p.colors.map((c) => (
))}
);
}
/* ---- mini cart ---- */
function MiniCart({ open, items, onClose, onRemove, onOpenProduct }) {
const subtotal = items.reduce((s, it) => s + it.price * it.qty, 0);
return (
<>
>
);
}
/* ---- footer ---- */
function Footer() {
const isMobile = useIsMobile();
const cols = [
{ h: "Loja", items: ["Moletons & Roupas", "Acessórios", "Papelaria", "Novidades", "Promoções"] },
{ h: "Ajuda", items: ["Trocas e devoluções", "Tabela de medidas", "Envio e prazos", "Fale conosco"] },
{ h: "UVD Club", items: ["Sobre a marca", "Programa de embaixadoras", "Instagram", "Termos"] },
];
return (
);
}
Object.assign(window, { fmtBRL, useIsMobile, Placeholder, Img, Logo, ColorDot, AnnouncementBar, Header, ProductCard, MiniCart, Footer });