/* O Tal Picolé — shared components */ const { useState, useEffect, useMemo, useRef, useCallback } = React; /* ============ LOGO ============ */ function Logo({ size = 30, mark = false }) { // Popsicle mark in brand red — simple, geometric, recognizable return ( {/* Second popsicle behind for depth */} ); } /* ============ ICON SET (line, 18px) ============ */ const Icons = {}; const _icon = (paths, vb = "0 0 20 20") => function Icon({ size = 18, color = "currentColor", strokeWidth = 1.6, className = "ic" }) { return ( {paths} ); }; Icons.Dashboard = _icon(<>); Icons.Factory = _icon(<>); Icons.Store = _icon(<>); Icons.Sun = _icon(<>); Icons.Users = _icon(<>); Icons.Box = _icon(<>); Icons.Wallet = _icon(<>); Icons.Chart = _icon(<>); Icons.Settings = _icon(<>); Icons.Search = _icon(<>); Icons.Bell = _icon(<>); Icons.Plus = _icon(<>); Icons.Minus = _icon(<>); Icons.Check = _icon(<>); Icons.X = _icon(<>); Icons.ArrowUp = _icon(<>); Icons.ArrowDown = _icon(<>); Icons.ArrowRight = _icon(<>); Icons.ChevDown = _icon(<>); Icons.Filter = _icon(<>); Icons.Calendar = _icon(<>); Icons.Receipt = _icon(<>); Icons.Beach = _icon(<>); Icons.Truck = _icon(<>); Icons.Edit = _icon(<>); Icons.Trash = _icon(<>); Icons.More = _icon(<>); Icons.Eye = _icon(<>); Icons.Print = _icon(<>); Icons.Download = _icon(<>); Icons.Send = _icon(<>); Icons.AlertTriangle = _icon(<>); Icons.Snowflake = _icon(<>); Icons.History = _icon(<>); Icons.PieChart = _icon(<>); Icons.MapPin = _icon(<>); Icons.Coffee = _icon(<>); Icons.Star = _icon(<>); Icons.User = _icon(<>); Icons.QrCode = _icon(<>); /* ============ Helper components ============ */ function Card({ title, subtitle, action, children, flush, className = "", style }) { return (
{(title || action) && (
{title &&

{title}

} {subtitle &&

{subtitle}

}
{action &&
{action}
}
)}
{children}
); } function KPI({ label, value, trend, trendDir, sub, icon, medal, tone, sparkline }) { const cls = "kpi" + (tone ? " kpi--" + tone : ""); return (
{icon} {label}
{medal &&
{medal}
}
{value}
{trend && ( {trendDir === "up" && } {trendDir === "down" && } {trend} )} {sub && {sub}}
{sparkline}
); } function Chip({ children, tone, dot }) { const cls = "chip" + (tone ? " chip--" + tone : ""); return {dot && }{children}; } function FlavorTag({ productId }) { const p = PRODUCTS.find(x => x.id === productId); if (!p) return null; return ( {p.flavor} ); } function Button({ children, variant = "secondary", size, icon, onClick, type = "button", disabled, style }) { const cls = "btn btn--" + variant + (size ? " btn--" + size : ""); return ( ); } function Field({ label, required, hint, error, children, style }) { return (
{label && } {children} {hint && !error && {hint}} {error && {error}}
); } function Segmented({ options, value, onChange }) { return (
{options.map(opt => ( ))}
); } function Tabs({ items, value, onChange }) { return (
{items.map(it => ( ))}
); } function Modal({ title, subtitle, size, onClose, children, footer }) { useEffect(() => { const onKey = (e) => { if (e.key === "Escape") onClose && onClose(); }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [onClose]); return (
{ if (e.target === e.currentTarget) onClose && onClose(); }}>

{title}

{subtitle &&

{subtitle}

}
{children}
{footer &&
{footer}
}
); } function Toast({ message, onDone, kind = "success" }) { useEffect(() => { if (!message) return; const t = setTimeout(() => onDone && onDone(), 2400); return () => clearTimeout(t); }, [message, onDone]); if (!message) return null; return (
{kind === "success" ? : } {message}
); } function Sparkline({ data, color = "#D4310B", height = 38 }) { if (!data || !data.length) return null; const w = 120, h = height; const min = Math.min(...data), max = Math.max(...data); const range = max - min || 1; const step = w / (data.length - 1 || 1); const pts = data.map((v, i) => `${i*step},${h - ((v - min) / range) * (h - 6) - 3}`).join(" "); const area = `M0,${h} L${pts.split(' ').join(' L')} L${w},${h} Z`; return ( ); } function BarChart({ data, max, color = "var(--brand-600)", alt = "var(--ink-200)", showLabels = true, height = 180 }) { const m = max || Math.max(...data.map(d => d.value)); return (
{data.map((d, i) => { const pct = (d.value / m) * 100; return (
{showLabels &&
{d.label}
}
); })}
); } function ProgressBar({ value, max, tone }) { const pct = Math.min(100, Math.max(0, (value / max) * 100)); const cls = "bar" + (tone ? " bar--" + tone : ""); return
; } /* Numeric stepper */ function Stepper({ value, onChange, min = 0, max = 9999, step = 1 }) { return (
{ const v = parseInt(e.target.value || "0", 10); if (!isNaN(v)) onChange(Math.max(min, Math.min(max, v))); }} style={{ width:48, textAlign:"center", border:"none", borderLeft:"1px solid var(--line)", borderRight:"1px solid var(--line)", padding:"6px 4px", outline:"none", background:"white", fontWeight:600 }} />
); } function Steps({ items, current }) { return (
{items.map((it, i) => (
{i < current ? : i + 1}
{it}
{i < items.length - 1 &&
} ))}
); } /* Donut chart */ function Donut({ segments, size = 140, thickness = 18, total }) { const r = (size - thickness) / 2; const c = 2 * Math.PI * r; const sum = total || segments.reduce((s, x) => s + x.value, 0); let offset = 0; return ( {segments.map((s, i) => { const len = (s.value / sum) * c; const dasharray = `${len} ${c - len}`; const dashoffset = -offset; offset += len; return ( ); })} ); } /* Section header inside a page */ function SectionHead({ title, subtitle, action }) { return (

{title}

{subtitle &&

{subtitle}

}
{action}
); } Object.assign(window, { Logo, Icons, Card, KPI, Chip, FlavorTag, Button, Field, Segmented, Tabs, Modal, Toast, Sparkline, BarChart, ProgressBar, Stepper, Steps, Donut, SectionHead, });