// Klyvio — Shared UI pieces (dark theme Klyvio)
const { useState, useEffect, useRef, useMemo, useCallback } = React;
/* ———————————————————— LOGO ———————————————————— */
function Logo({ size = 22 }) {
const h = Math.round(size * 2);
return (
);
}
/* ———————————————————— PAGE CHROME ———————————————————— */
function AppChrome({ current, onNav, children, hideNav = false }) {
const isMobile = typeof window !== "undefined" && window.innerWidth <= 960;
const items = [
{ id: "landing", label: "Accueil", icon: "home" },
{ id: "onboarding", label: "Démarrer l\'audit", icon: "sparkles" },
{ id: "audit", label: "Questionnaire", icon: "compass" },
{ id: "loading", label: "Analyse", icon: "bolt" },
{ id: "report", label: "Rapport", icon: "fileText" },
];
return (
{!hideNav && (
)}
{children}
);
}
/* ———————————————————— CIRCULAR SCORE ———————————————————— */
function ScoreDial({ value = 0, size = 220, stroke = 14, label = "Maturité IA", sub }) {
const r = (size - stroke) / 2;
const c = 2 * Math.PI * r;
const offset = c - (value / 100) * c;
const bandColor = value < 30 ? "var(--danger-500)"
: value < 55 ? "var(--warn-500)"
: value < 75 ? "var(--accent)"
: "var(--success-500)";
const gradId = `dial-grad-${size}-${Math.round(value)}`;
return (
{Math.round(value)}
{label}
{sub &&
{sub}
}
);
}
/* ———————————————————— RADAR ———————————————————— */
function RadarChart({ data, size = 320, max = 100 }) {
const cx = size / 2;
const cy = size / 2;
const r = size / 2 - 44;
const n = data.length;
const angle = (i) => (Math.PI * 2 * i) / n - Math.PI / 2;
const point = (i, v) => {
const a = angle(i);
const rr = (v / max) * r;
return [cx + Math.cos(a) * rr, cy + Math.sin(a) * rr];
};
const polyPoints = data.map((d, i) => point(i, d.value).join(",")).join(" ");
const gridLevels = [0.25, 0.5, 0.75, 1];
return (
);
}
/* ———————————————————— STAT CARD ———————————————————— */
function StatCard({ eyebrow, value, unit, sub, icon, tone = "default", trend, className = "" }) {
const tones = {
default: { bg: "var(--bg2)", accent: "var(--accent)", text: "var(--white)" },
accent: { bg: "linear-gradient(135deg, rgba(0,174,239,0.2), rgba(0,136,204,0.15))", accent: "var(--accent)", text: "var(--white)" },
dark: { bg: "var(--bg)", accent: "var(--accent)", text: "var(--white)" },
soft: { bg: "var(--accent-dim)", accent: "var(--accent)", text: "var(--white)" },
};
const t = tones[tone] || tones.default;
return (
{(sub || trend) && (
{trend && (
0 ? "var(--success-500)" : "var(--danger-500)" }}>
0 ? "trendUp" : "trendDown"} size={12} />
{trend > 0 ? "+" : ""}{trend}%
)}
{sub}
)}
);
}
/* ———————————————————— UTILS ———————————————————— */
function formatEur(n) {
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(n > 10_000_000 ? 0 : 1)}\u202fM€`;
if (n >= 1_000) return `${Math.round(n / 100) / 10}\u202fk€`;
return `${Math.round(n)}\u202f€`;
}
function formatHours(n) {
if (n >= 1000) return `${Math.round(n / 100) / 10}\u202fk\u202fh`;
return `${Math.round(n)}\u202fh`;
}
Object.assign(window, { Logo, AppChrome, ScoreDial, RadarChart, StatCard, formatEur, formatHours });