// Shared UI primitives — Apple-inspired light system const { useState, useEffect, useRef, useMemo } = React; // ───────── Icons (line, 1.6 stroke, rounded) ───────── function Icon({ name, size = 18, stroke = 1.6, color = "currentColor" }) { const props = { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: stroke, strokeLinecap: "round", strokeLinejoin: "round" }; switch (name) { case "server": return (); case "users": return (); case "settings": return (); case "link": return (); case "lock": return (); case "tools": return (); case "gauge": return (); case "check": return (); case "plus": return (); case "chevron-down": return (); case "chevron-right": return (); case "back": return (); case "trash": return (); case "config": return (); case "stop": return (); case "play": return (); case "qr": return (); case "calendar": return (); case "clock": return (); case "download": return (); case "upload": return (); case "cpu": return (); case "ram": return (); case "disk": return (); case "globe": return (); case "refresh": return (); case "logout": return (); case "sun": return (); case "moon": return (); case "key": return (); case "sparkles": return (); case "satellite":return (); case "bolt": return (); case "plane": return (); case "shield": return (); case "wand": return (); case "brain": return (); case "star": return (); case "github": return (); case "doc": return (); case "edit": return (); case "more": return (); case "search": return (); case "heart": return (); case "qr-scan": return (); case "clipboard":return (); default: return null; } } // ───────── Buttons ───────── function Button({ children, variant = "primary", size = "md", icon, iconRight, onClick, type, disabled, style, full }) { const sizes = { sm: { h: 30, px: 12, fs: 13, gap: 6, r: 10 }, md: { h: 38, px: 16, fs: 14, gap: 8, r: 12 }, lg: { h: 46, px: 22, fs: 15, gap: 10, r: 14 }, }[size]; const variants = { primary: { bg: "var(--accent)", color: "#fff", border: "transparent", shadow:"0 1px 0 rgba(255,255,255,.18) inset, 0 6px 16px rgba(124,92,255,.35)" }, primaryGrad: { bg: "linear-gradient(180deg, #8a6cff, #6a44f5)", color:"#fff", border:"transparent", shadow:"0 1px 0 rgba(255,255,255,.22) inset, 0 8px 22px rgba(106,68,245,.35)" }, secondary: { bg: "#fff", color:"var(--ink)", border: "var(--line)", shadow:"0 1px 0 rgba(255,255,255,.6) inset, 0 1px 1px rgba(16,24,40,.04), 0 3px 8px rgba(16,24,40,.05)" }, ghost: { bg: "transparent", color:"var(--ink-2)", border:"transparent", shadow:"none" }, danger: { bg: "#fff", color:"var(--red)", border:"rgba(255,59,48,.22)", shadow:"0 1px 1px rgba(16,24,40,.03)" }, dangerSolid:{ bg:"var(--red)", color:"#fff", border:"transparent", shadow:"0 1px 0 rgba(255,255,255,.18) inset, 0 6px 14px rgba(255,59,48,.3)" }, success: { bg:"#fff", color:"var(--green)", border:"rgba(52,199,89,.25)" , shadow:"0 1px 1px rgba(16,24,40,.03)"}, }; const v = variants[variant] || variants.primary; return ( ); } // ───────── Card ───────── function Card({ children, padding = 22, radius, hover, style, onClick }) { const [h, setH] = useState(false); return (
setH(true)} onMouseLeave={()=>setH(false)} style={{ background:"var(--bg-elev)", borderRadius: radius || "var(--radius-card)", border:"1px solid var(--line)", boxShadow:"var(--shadow-card)", padding, transition:"transform .2s ease, box-shadow .25s ease", transform: hover && h ? "translateY(-2px)" : "translateY(0)", boxShadow: hover && h ? "var(--shadow-pop)" : "var(--shadow-card)", cursor: onClick ? "pointer" : "default", ...style, }}> {children}
); } // ───────── Badge ───────── function Badge({ children, tone = "neutral", dot, size="md", style }) { const tones = { neutral:{ bg:"#f1f2f6", color:"#3a3a3c", dot:"#8e8e93"}, green: { bg:"var(--green-soft)", color:"#1f7a3a", dot:"var(--green)" }, blue: { bg:"var(--blue-soft)", color:"#0a4ea3", dot:"var(--blue)" }, purple: { bg:"var(--accent-soft)", color:"#4a2fcc", dot:"var(--accent)" }, orange: { bg:"var(--orange-soft)", color:"#a05a00", dot:"var(--orange)" }, red: { bg:"var(--red-soft)", color:"#a8261d", dot:"var(--red)" }, }; const t = tones[tone] || tones.neutral; const sizes = { sm:{h:20, fs:10.5, px:7}, md:{h:24, fs:11.5, px:9}, lg:{h:28, fs:12.5, px:11}}; const s = sizes[size] || sizes.md; return ( {dot && } {children} ); } // ───────── Glyph tile (app-icon style with gradient) ───────── function GlyphTile({ icon, size = 44, gradient, radius = 12, glyph }) { return (
{glyph ? {glyph} : }
); } // ───────── Stat chip (used in server header) ───────── function Stat({ icon, label, value, tone="neutral" }) { const tones = { neutral:{c:"#3a3a3c", bg:"#f4f5f7"}, green:{c:"#1f7a3a", bg:"var(--green-soft)"}, orange:{c:"#a05a00", bg:"var(--orange-soft)"}, blue:{c:"#0a4ea3", bg:"var(--blue-soft)"}, }; const t = tones[tone] || tones.neutral; return (
{label} {value}
); } // ───────── Avatar (initial) ───────── function Avatar({ name, color = "var(--accent)", size = 36 }) { const letter = (name || "?").trim().charAt(0).toUpperCase(); return (
{letter}
); } // ───────── Toggle ───────── function Toggle({ on, onChange }) { return ( ); } // ───────── Input ───────── function Input({ label, value, onChange, placeholder, mono, type="text", suffix, hint }) { return ( ); } // ───────── Checkbox ───────── function Checkbox({ checked, onChange, label }) { return ( ); } // ───────── Section header ───────── function SectionHeader({ title, subtitle, right }) { return (

{title}

{subtitle &&

{subtitle}

}
{right}
); } // expose globally Object.assign(window, { Icon, Button, Card, Badge, GlyphTile, Stat, Avatar, Toggle, Input, Checkbox, SectionHeader, });