// components.jsx — shared UI building blocks
// Map a Portuguese color name to an approximate hue/lightness for placeholder gradients
const COR_HUE = {
branco: { h: 95, l: 0.78, c: 0.01 }, prata: { h: 250, l: 0.66, c: 0.01 },
cinza: { h: 250, l: 0.52, c: 0.008 }, "cinza platinum": { h: 250, l: 0.58, c: 0.01 },
preto: { h: 250, l: 0.28, c: 0.006 }, vermelho: { h: 25, l: 0.52, c: 0.16 },
azul: { h: 250, l: 0.52, c: 0.13 }, verde: { h: 150, l: 0.55, c: 0.12 },
amarelo: { h: 95, l: 0.78, c: 0.15 }, laranja: { h: 55, l: 0.62, c: 0.15 },
};
function corStyle(cor) {
const key = (cor || "").toLowerCase();
const m = COR_HUE[key] || { h: 250, l: 0.5, c: 0.01 };
return m;
}
// Vehicle photo: real image if URL provided, otherwise a designed placeholder
function VehiclePhoto({ vehicle, className, style, rounded = true, label = true }) {
const foto = vehicle.fotos && vehicle.fotos[0];
const m = corStyle(vehicle.cor);
const Icon = IconBike;
if (foto) {
return (
);
}
const c1 = `oklch(${m.l} ${m.c} ${m.h})`;
const c2 = `oklch(${Math.max(0.2, m.l - 0.22)} ${m.c} ${m.h})`;
return (
{label && (
foto da moto
)}
);
}
function StatusBadge({ status }) {
const meta = STATUS_META[status];
if (!meta || !meta.badge) return null;
return {meta.label} ;
}
function SpecPill({ icon: Icon, label, value }) {
return (
);
}
// Vehicle card for catalog grid
function VehicleCard({ vehicle, onOpen }) {
const sold = vehicle.status === "vendido";
const meta = STATUS_META[vehicle.status];
return (
onOpen(vehicle)} className="card fade-in" style={{
textAlign: "left", padding: 0, overflow: "hidden", cursor: "pointer",
transition: "transform .16s ease, border-color .16s, box-shadow .16s",
display: "flex", flexDirection: "column",
}}
onMouseEnter={(e) => { e.currentTarget.style.transform = "translateY(-4px)"; e.currentTarget.style.borderColor = "var(--faint)"; e.currentTarget.style.boxShadow = "var(--shadow)"; }}
onMouseLeave={(e) => { e.currentTarget.style.transform = ""; e.currentTarget.style.borderColor = "var(--border-soft)"; e.currentTarget.style.boxShadow = "none"; }}>
{meta && meta.badge && }
{sold && (
)}
{vehicle.ano}
{vehicle.marca}
{vehicle.modelo}
{formatKM(vehicle.km)}
{vehicle.cambio}
{vehicle.combustivel}
{vehicle.status === "oferta" && vehicle.precoAntigo > vehicle.preco && (
{formatBRL(vehicle.precoAntigo)}
)}
{formatBRL(vehicle.preco)}
Ver detalhes
);
}
// Generic modal
function Modal({ open, onClose, children, maxWidth = 560, label }) {
React.useEffect(() => {
if (!open) return;
const onKey = (e) => { if (e.key === "Escape") onClose(); };
document.addEventListener("keydown", onKey);
document.body.style.overflow = "hidden";
return () => { document.removeEventListener("keydown", onKey); document.body.style.overflow = ""; };
}, [open]);
if (!open) return null;
return (
e.stopPropagation()} className="card" style={{
maxWidth, width: "100%", boxShadow: "0 30px 80px -20px rgba(0,0,0,.7)", animation: "fadeIn .25s ease",
}}>{children}
);
}
function ModalHeader({ title, subtitle, onClose }) {
return (
{title}
{subtitle &&
{subtitle}
}
);
}
// Store location placeholder map
function StoreMap({ height = 150 }) {
return (
);
}
Object.assign(window, {
VehiclePhoto, StatusBadge, SpecPill, VehicleCard, Modal, ModalHeader, StoreMap, corStyle,
});