// Shared UI components: Icon, Pill, Button, Modal, etc. function Icon({ name, size = 16, color = "currentColor", strokeWidth = 1.6, style, ...rest }) { const s = size; const stroke = { stroke: color, fill: "none", strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" }; const paths = { home: <>, calendar: <>, list: <>, sparkle: <>, bell: <>, plus: <>, check: <>, cross: <>, arrow: <>, back: <>, chev: <>, chevDown: <>, dot: <>, circle: <>, halfcircle: <>, repeat: <>, edit: <>, trash: <>, flag: <>, cake: <>, stethoscope: <>, users: <>, party: <>, filter: <>, search: <>, close: <>, moon: <>, sun: <>, sprout: <>, settings: <>, star: <>, }; return ( {paths[name] || null} ); } // Icon for kind function KindIcon({ kind, size = 14, color = "currentColor" }) { const map = { task: "check", birthday: "cake", appointment: "stethoscope", family: "users", event: "party" }; return ; } // Status pill function StatusPill({ status, compact }) { const s = STATES[status] || STATES.todo; return ( {s.label} ); } // Priority pill (small flag) function PriorityFlag({ p, withLabel }) { const pr = PRIORITIES[p] || PRIORITIES.mid; return ( {withLabel && pr.label} ); } // Kind chip function KindChip({ kind }) { const k = KINDS[kind] || KINDS.task; return ( {k.label} ); } // Button function Button({ variant = "ghost", size = "md", icon, children, style, ...rest }) { const padBy = { sm: "6px 10px", md: "8px 14px", lg: "10px 18px" }; const variants = { primary: { background: "var(--terracotta)", color: "#FFF8F0", border: "1px solid var(--terracotta-2)" }, ghost: { background: "transparent", color: "var(--ink)", border: "1px solid var(--line-2)" }, soft: { background: "var(--surface)", color: "var(--ink)", border: "1px solid var(--line)" }, quiet: { background: "transparent", color: "var(--ink-2)", border: "1px solid transparent" }, danger: { background: "transparent", color: "var(--prio-high)", border: "1px solid #E5C0BA" }, }; return ( ); } // IconButton function IconButton({ icon, onClick, label, active, size = 32, style }) { return ( ); } // Card function Card({ children, style, padding = 20, ...rest }) { return (
{children}
); } // Section heading function SectionHeading({ eyebrow, title, action, count }) { return (
{eyebrow &&
{eyebrow}
}
{title} {count != null && {count}}
{action}
); } // Modal function Modal({ open, onClose, children, width = 560 }) { if (!open) return null; return (
e.stopPropagation()} style={{ background: "var(--bg-2)", borderRadius: 18, border: "1px solid var(--line)", boxShadow: "var(--shadow-lg)", width: "100%", maxWidth: width, maxHeight: "90vh", overflow: "auto", }}> {children}
); } // Empty state function Empty({ icon = "sparkle", title, hint, action }) { return (
{title}
{hint &&
{hint}
}
{action}
); } // Status dot bar (multiple status colors stacked) function StatusDots({ items, date, max = 4 }) { const colors = items.slice(0, max).map(it => { if (it.kind !== "task") return KINDS[it.kind].color; const s = statusOn(it, date); return STATES[s].color; }); return (
{colors.map((c, i) => ( ))} {items.length > max && ( +{items.length - max} )}
); } Object.assign(window, { Icon, KindIcon, StatusPill, PriorityFlag, KindChip, Button, IconButton, Card, SectionHeading, Modal, Empty, StatusDots, });