// shared.jsx — shared UI primitives for Absensi MOTOART const STATUS_LABEL = { hadir: 'Hadir', telat: 'Telat', izin: 'Izin', absen: 'Tidak Hadir', belum: 'Belum Absen' }; function StatusChip({ status, sm }) { return ( {STATUS_LABEL[status] || status} ); } function Avatar({ init, size = 44, fs }) { return (
{init}
); } // animated donut ring function Ring({ value, size = 132, sw = 13, label, sub, color = 'var(--accent)' }) { const r = (size - sw) / 2; const circ = 2 * Math.PI * r; const off = circ * (1 - value / 100); return (
{label}
{sub &&
{sub}
}
); } function ProgressBar({ value, color = 'var(--accent)' }) { return
; } // stylized "map" with abstract streets + pulsing pin function MiniMap({ height = 132, pinLabel }) { return (
{pinLabel && (
{pinLabel}
)}
); } function BottomNav({ tabs, active, onChange }) { return (
{tabs.map(t => ( ))}
); } function AppHeader({ title, sub, right, avatar }) { return (
{avatar && }
{title}
{sub &&
{sub}
}
{right}
); } function IconBtn({ name, onClick, badge }) { return ( ); } function Logo({ h = 28, chip = true, pad = 6, radius = 11 }) { const img = MOTOART; if (!chip) return img; return (
{img}
); } function Toast({ children, icon = 'checkCircle' }) { return
{children}
; } function StatCard({ label, value, unit, icon, tone = 'accent', delta }) { const toneColor = { accent: 'var(--accent)', success: 'var(--success)', warn: 'var(--warn)', danger: 'var(--danger)' }[tone]; const toneWeak = { accent: 'var(--accent-weak)', success: 'var(--success-weak)', warn: 'var(--warn-weak)', danger: 'var(--danger-weak)' }[tone]; return (
{delta && {delta}}
{value}{unit && {unit}}
{label}
); } Object.assign(window, { STATUS_LABEL, StatusChip, Avatar, Ring, ProgressBar, MiniMap, BottomNav, AppHeader, IconBtn, Logo, Toast, StatCard });