/** * Catégories de fichiers partagées (API stats + dataviz du tableau de bord). * Palette catégorielle validée (skill dataviz, ordre fixe, jamais cyclée) : * clair/sombre sélectionnés séparément, gris neutre réservé à « Autres ». */ export type CategoryKey = | "documents" | "images" | "videos" | "code" | "audio" | "spreadsheets" | "archives" | "other"; export interface CategoryDef { key: CategoryKey; label: string; light: string; dark: string; } /** Ordre = ordre des slots de la palette (fixe). */ export const CATEGORIES: CategoryDef[] = [ { key: "documents", label: "Documents", light: "#2a78d6", dark: "#3987e5" }, { key: "images", label: "Images", light: "#eb6834", dark: "#d95926" }, { key: "videos", label: "Vidéos", light: "#1baf7a", dark: "#199e70" }, { key: "code", label: "Code & texte", light: "#eda100", dark: "#c98500" }, { key: "audio", label: "Audio", light: "#e87ba4", dark: "#d55181" }, { key: "spreadsheets", label: "Tableurs", light: "#008300", dark: "#008300" }, { key: "archives", label: "Archives", light: "#4a3aa7", dark: "#9085e9" }, { key: "other", label: "Autres", light: "#9aa1ad", dark: "#6b7280" }, ]; export const CATEGORY_BY_KEY: Record = Object.fromEntries( CATEGORIES.map((c) => [c.key, c]) ) as Record; export function categorize(mimeType: string): CategoryKey { const m = (mimeType || "").toLowerCase(); if (m.startsWith("image/")) return "images"; if (m.startsWith("video/")) return "videos"; if (m.startsWith("audio/")) return "audio"; if ( m.includes("spreadsheet") || m.includes("excel") || m === "text/csv" || m.includes("ms-excel") || m.includes("numbers") ) return "spreadsheets"; if ( m === "application/pdf" || m.includes("word") || m.includes("officedocument.wordprocessingml") || m.includes("presentation") || m.includes("powerpoint") || m.includes("rtf") || m.includes("opendocument") || m.includes("pages") || m.includes("epub") || m.includes("keynote") ) return "documents"; if ( m.includes("zip") || m.includes("rar") || m.includes("7z") || m.includes("tar") || m.includes("gzip") || m.includes("compressed") || m.includes("archive") || m.includes("x-bzip") || m.includes("x-xz") ) return "archives"; if ( m.startsWith("text/") || m.includes("json") || m.includes("xml") || m.includes("javascript") || m.includes("typescript") || m.includes("yaml") || m.includes("toml") || m.includes("x-sh") || m.includes("x-python") || m.includes("markdown") || m.includes("html") || m.includes("css") || m.includes("sql") ) return "code"; return "other"; } export interface CategoryStat { key: CategoryKey; label: string; count: number; size: number; } export function aggregateByCategory(rows: { type: string; count: number; size: number }[]): CategoryStat[] { const acc = new Map(); for (const c of CATEGORIES) acc.set(c.key, { key: c.key, label: c.label, count: 0, size: 0 }); for (const r of rows) { const k = categorize(r.type); const s = acc.get(k)!; s.count += r.count; s.size += r.size; } // Ordre fixe (palette), on ne trie PAS par taille : la couleur suit l'entité. return Array.from(acc.values()); }