diff --git a/ui-kit.jsx b/ui-kit.jsx
deleted file mode 100644
index 92f9e76..0000000
--- a/ui-kit.jsx
+++ /dev/null
@@ -1,656 +0,0 @@
-/* ============================================================
- ui-kit.jsx
- Composants haute-fid Gruvbox Seventies.
- Tout est purement décoratif/interactif côté composant.
- Effets : transparence (glass), hover glow, click 3D, tooltips.
- ============================================================ */
-
-const { useState, useRef, useEffect } = React;
-
-/* ============================================================
- Icônes — Font Awesome 6 Free.
- Mapping nom logique → classe FA. Le CSS de FA est chargé en CDN
- dans le
. Le composant garde la MÊME API qu'avant (name,
- size, style) pour ne rien casser ailleurs.
- ============================================================ */
-const ICON_MAP = {
- cpu: 'microchip',
- memory: 'memory',
- disk: 'hard-drive',
- network: 'network-wired',
- clock: 'clock',
- grid: 'table-cells',
- list: 'list',
- cog: 'gear',
- alert: 'triangle-exclamation',
- bell: 'bell',
- server: 'server',
- chart: 'chart-line',
- bars: 'chart-simple',
- terminal: 'terminal',
- refresh: 'arrows-rotate',
- play: 'play',
- pause: 'pause',
- power: 'power-off',
- sun: 'sun',
- moon: 'moon',
- search: 'magnifying-glass',
- close: 'xmark',
- chevR: 'chevron-right',
- chevL: 'chevron-left',
- chevD: 'chevron-down',
- chevU: 'chevron-up',
- plus: 'plus',
- filter: 'filter',
- download: 'download',
- folder: 'folder',
- node: 'circle-nodes',
- user: 'user',
-};
-
-const Icon = ({ name, size = 16, style }) => {
- const fa = ICON_MAP[name] || 'circle-question';
- return (
-
- );
-};
-
-/* ============================================================
- Tooltip — apparaît au hover après 300ms, position auto.
- ============================================================ */
-function Tooltip({ children, label, side = 'top' }) {
- const [show, setShow] = useState(false);
- const t = useRef();
- const onEnter = () => { t.current = setTimeout(() => setShow(true), 280); };
- const onLeave = () => { clearTimeout(t.current); setShow(false); };
- const sides = {
- top: { bottom: 'calc(100% + 8px)', left: '50%', transform: 'translateX(-50%)' },
- bottom: { top: 'calc(100% + 8px)', left: '50%', transform: 'translateX(-50%)' },
- left: { right: 'calc(100% + 8px)', top: '50%', transform: 'translateY(-50%)' },
- right: { left: 'calc(100% + 8px)', top: '50%', transform: 'translateY(-50%)' },
- };
- return (
-
- {children}
- {show && (
- {label}
- )}
-
- );
-}
-
-/* ============================================================
- IconButton — bouton icône seul + tooltip obligatoire.
- ============================================================ */
-function IconButton({ icon, label, onClick, active, danger, size = 34, primary }) {
- const bg = active ? 'var(--accent-tint)'
- : primary ? 'var(--accent)'
- : 'var(--bg-3)';
- const fg = active ? 'var(--accent)'
- : primary ? 'var(--bg-1)'
- : danger ? 'var(--err)'
- : 'var(--ink-2)';
- const bd = active ? 'var(--accent-soft)' : 'var(--border-2)';
- return (
-
-
-
- );
-}
-
-/* ============================================================
- Toggle on/off — switch tactile avec glow accent quand ON
- ============================================================ */
-function Toggle({ on, onChange, label, icon }) {
- return (
-
- {icon && }
- {label && {label}}
-
-
- );
-}
-
-/* ============================================================
- Status LED — pastille pulsante (effet halo si critique)
- ============================================================ */
-function StatusLed({ status = 'ok', size = 10, pulse }) {
- const map = {
- ok: { c: 'var(--ok)', g: 'var(--ok-glow)' },
- warn: { c: 'var(--warn)', g: 'var(--warn-glow)' },
- err: { c: 'var(--err)', g: 'var(--err-glow)' },
- off: { c: 'var(--ink-4)', g: 'transparent' },
- info: { c: 'var(--info)', g: 'var(--info-glow)' },
- };
- const { c, g } = map[status];
- const id = `pulse-${status}-${size}`;
- return (
- <>
- {pulse && (
-
- )}
-
- >
- );
-}
-
-/* ============================================================
- BatteryGauge — jauge horizontale style batterie
- - Pas de bandes (couleur unie + léger gloss interne)
- - Pas de graduations verticales
- - Hover : glow lumineux dans la couleur de la jauge
- - Mode compact : label [bar] valeur sur une seule ligne
- ============================================================ */
-function BatteryGauge({ value = 60, label, max = 100, unit = '%', warnAt = 70, errAt = 90, height = 22, compact = false, color: colorOverride, icon }) {
- const pct = Math.max(0, Math.min(100, (value / max) * 100));
- const color = colorOverride
- || (pct >= errAt ? 'var(--err)' : pct >= warnAt ? 'var(--warn)' : 'var(--ok)');
- const glowVar = pct >= errAt ? 'var(--err-glow)'
- : pct >= warnAt ? 'var(--warn-glow)'
- : 'var(--ok-glow)';
-
- // Variante compacte : label [bar] valeur sur une seule ligne
- if (compact) {
- return (
-
- {(icon || label) && (
-
- {icon && }
- {label && {label}}
-
- )}
-
-
- {value}{unit}
-
-
- );
- }
-
- return (
-
- {label && (
-
- {label}
-
- {value}{unit}
-
-
- )}
-
-
- {/* Gloss interne très léger (un seul highlight haut, pas de bande inférieure) */}
-
-
-
- );
-}
-
-/* ============================================================
- RadialGauge — jauge ronde, version épurée
- ============================================================ */
-function RadialGauge({ value = 64, label, size = 120, warnAt = 70, errAt = 90 }) {
- const pct = Math.max(0, Math.min(100, value));
- const color = pct >= errAt ? 'var(--err)' : pct >= warnAt ? 'var(--warn)' : 'var(--ok)';
- const glow = pct >= errAt ? 'var(--err-glow)' : pct >= warnAt ? 'var(--warn-glow)' : 'var(--ok-glow)';
- const r = size / 2 - 10;
- const cx = size / 2;
- const cy = size / 2 + 6;
- const circ = Math.PI * r;
- const offset = circ - (pct / 100) * circ;
- return (
-
-
-
-
- {value}%
-
- {label &&
{label}
}
-
-
- );
-}
-
-/* ============================================================
- BigRadialGauge — la grande jauge cockpit "santé système"
- ============================================================ */
-function BigRadialGauge({ value = 87, label = 'score santé · stable' }) {
- const size = 320;
- const r = 130;
- const cx = size / 2;
- const cy = size / 2 + 30;
- const circ = Math.PI * r;
- const offset = circ - (value / 100) * circ;
- const color = value >= 80 ? 'var(--ok)' : value >= 50 ? 'var(--warn)' : 'var(--err)';
- return (
-
-
-
-
- );
-}
-
-/* ============================================================
- Popup — modale glassmorphism centrée + bouton fermer
- ============================================================ */
-function Popup({ open, onClose, title, children, footer, width = 460 }) {
- if (!open) return null;
- return (
-
-
-
e.stopPropagation()} style={{
- width, maxWidth: '90%',
- borderRadius: 12,
- boxShadow: 'var(--shadow-3)',
- animation: 'popin .25s cubic-bezier(.3,.7,.3,1.2)',
- overflow: 'hidden',
- }}>
-
-
{children}
- {footer && (
-
{footer}
- )}
-
-
- );
-}
-
-/* ============================================================
- Button — bouton classique avec variantes
- ============================================================ */
-function Button({ children, icon, onClick, variant = 'default', size = 'md' }) {
- const sizes = {
- sm: { padding: '5px 10px', fontSize: 12, h: 28 },
- md: { padding: '7px 14px', fontSize: 13, h: 34 },
- lg: { padding: '10px 18px', fontSize: 14, h: 40 },
- }[size];
- const variants = {
- default: { bg: 'var(--bg-3)', fg: 'var(--ink-1)', bd: 'var(--border-2)' },
- primary: { bg: 'var(--accent)', fg: 'var(--bg-1)', bd: 'var(--accent-soft)' },
- ghost: { bg: 'transparent', fg: 'var(--ink-2)', bd: 'var(--border-2)' },
- danger: { bg: 'var(--bg-3)', fg: 'var(--err)', bd: 'var(--err)' },
- }[variant];
- return (
-
- );
-}
-
-/* ============================================================
- TreeNav — arbre dépliable avec icône en tête (style B)
- ============================================================ */
-function TreeNav({ groups, activeId, onSelect }) {
- const [open, setOpen] = useState(() =>
- Object.fromEntries(groups.map(g => [g.id, g.open !== false]))
- );
- return (
-
- {groups.map(g => (
-
-
setOpen({ ...open, [g.id]: !open[g.id] })}
- style={{
- display: 'flex', alignItems: 'center', gap: 8,
- padding: '7px 8px', borderRadius: 6,
- color: 'var(--ink-2)',
- background: 'transparent',
- border: '1px solid transparent',
- cursor: 'pointer',
- }}>
-
-
- {g.label}
- {g.count != null && (
-
- {g.count}
-
- )}
-
- {open[g.id] && (
-
- {g.children.map(c => {
- const active = c.id === activeId;
- return (
-
onSelect && onSelect(c.id)}
- style={{
- display: 'flex', alignItems: 'center', gap: 8,
- padding: '6px 10px', borderRadius: 6,
- background: active ? 'var(--accent-tint)' : 'transparent',
- color: active ? 'var(--ink-1)' : 'var(--ink-2)',
- borderLeft: active ? '2px solid var(--accent)' : '2px solid transparent',
- marginLeft: active ? 0 : 2,
- fontSize: 12.5,
- }}>
-
- {c.label}
- {c.meta && {c.meta}}
-
- );
- })}
-
- )}
-
- ))}
-
- );
-}
-
-/* ============================================================
- Sparkline pour les KPI
- ============================================================ */
-function Sparkline({ points = [], color = 'var(--accent)', h = 28 }) {
- const w = 100;
- const max = Math.max(...points);
- const min = Math.min(...points);
- const range = max - min || 1;
- const step = w / (points.length - 1);
- const path = points.map((p, i) =>
- `${i === 0 ? 'M' : 'L'} ${(i * step).toFixed(1)} ${(h - 2 - ((p - min) / range) * (h - 4)).toFixed(1)}`
- ).join(' ');
- const area = path + ` L ${w} ${h} L 0 ${h} Z`;
- return (
-
- );
-}
-
-/* ============================================================
- LineChart — grand graph multi-séries
- ============================================================ */
-function LineChart({ series, h = 200, labels }) {
- const w = 600;
- const padding = { l: 36, r: 12, t: 12, b: 24 };
- const innerW = w - padding.l - padding.r;
- const innerH = h - padding.t - padding.b;
- const all = series.flatMap(s => s.points);
- const max = Math.max(...all) * 1.1;
- const min = 0;
- const range = max - min;
- const ptsCount = series[0].points.length;
- const step = innerW / (ptsCount - 1);
- return (
-
- );
-}
-
-/* Expose */
-Object.assign(window, {
- Icon, Tooltip, IconButton, Toggle, StatusLed,
- BatteryGauge, RadialGauge, BigRadialGauge,
- Popup, Button, TreeNav, Sparkline, LineChart,
-});
-
-/* Effets hover sur les jauges (sans effet au clic) */
-(function injectGaugeHoverStyles() {
- if (document.getElementById('gauge-hover-styles')) return;
- const s = document.createElement('style');
- s.id = 'gauge-hover-styles';
- s.textContent = `
- .bg-hover:hover .bg-bar {
- border-color: color-mix(in oklch, var(--accent) 60%, var(--border-3));
- }
- .bg-hover:hover .bg-fill {
- box-shadow: 0 0 14px var(--bg-glow, var(--accent-glow));
- filter: brightness(1.15);
- }
- .gauge-hover { transition: filter .2s; }
- .gauge-hover:hover { filter: drop-shadow(0 0 8px var(--accent-glow)) brightness(1.08); }
- `;
- document.head.appendChild(s);
-})();