/* Core UI primitives for Kisongi Farm Tracker. Styled with Tailwind utility classes. Original implementation inspired by the calm, neutral feel of headless component libraries. */ const { useState, useEffect, useRef, useMemo, useCallback } = React; /* ---------------- Utilities ---------------- */ function formatUGX(n, opts = {}) { if (n === null || n === undefined || isNaN(n)) return "—"; const sign = n < 0 ? "−" : ""; const abs = Math.abs(n); const s = abs.toLocaleString("en-US"); return opts.bare ? `${sign}${s}` : `${sign}${s} UGX`; } function formatDate(iso) { if (!iso) return "—"; const d = new Date(iso + "T00:00:00"); return d.toLocaleDateString("en-GB", { day: "2-digit", month: "short", year: "numeric" }); } function todayISO() { return new Date().toISOString().slice(0, 10); } function cls(...xs) { return xs.filter(Boolean).join(" "); } /* ---------------- Icon set (lucide-style inline SVGs) ---------------- */ const Icon = { Plus: (p) => , Search: (p) => , X: (p) => , Edit: (p) => , Trash: (p) => , Eye: (p) => , Calendar:(p) => , Filter: (p) => , Check: (p) => , Chevron: (p) => , ArrowUp: (p) => , ArrowDown:(p)=> , Coffee: (p) => , User: (p) => , TrendDown:(p)=> , TrendUp: (p) => , Wallet: (p) => , Home: (p) => , Pie: (p) => , Book: (p) => , Mail: (p) => , Sparkle: (p) => , Inbox: (p) => , Leaf: (p) => , }; /* ---------------- Button ---------------- */ function Button({ variant = "primary", size = "md", children, className = "", ...rest }) { const base = "inline-flex items-center justify-center gap-2 font-medium rounded-lg transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-emerald-600/40 disabled:opacity-50 disabled:cursor-not-allowed select-none"; const sizes = { sm: "h-8 px-3 text-[13px]", md: "h-10 px-4 text-sm", lg: "h-12 px-5 text-[15px]" }; const variants = { primary: "bg-[#2E7D32] text-white shadow-sm hover:bg-[#256A29] active:bg-[#1F5A23]", secondary: "bg-white text-stone-800 border border-stone-200 hover:bg-stone-50 active:bg-stone-100", ghost: "text-stone-700 hover:bg-stone-100 active:bg-stone-200", danger: "bg-rose-600 text-white hover:bg-rose-700 active:bg-rose-800", gold: "bg-[#FBC02D] text-stone-900 hover:bg-[#F2B619] active:bg-[#E0A700]", }; return ; } /* ---------------- Badge ---------------- */ function Badge({ tone = "neutral", outlined = false, children, className = "" }) { const tones = { green: outlined ? "border-[#2E7D32] text-[#2E7D32]" : "bg-[#2E7D32] text-white", gold: outlined ? "border-[#FBC02D] text-[#8a6500]" : "bg-[#FBC02D] text-stone-900", neutral: outlined ? "border-stone-300 text-stone-700" : "bg-stone-100 text-stone-700", red: outlined ? "border-rose-500 text-rose-700" : "bg-rose-100 text-rose-700", surface: outlined ? "border-emerald-200 text-emerald-800" : "bg-[#f1f8e9] text-emerald-800", }; return ( {children} ); } /* ---------------- Input / Select / Textarea ---------------- */ function Input({ className = "", icon, ...rest }) { if (icon) { return (
{icon}
); } return ; } function Select({ value, onChange, options, placeholder = "Select…", className = "" }) { return (
); } function Textarea({ className = "", ...rest }) { return