JavaScript 56.7%
TypeScript 42.6%
1/**2 * Catégories de fichiers partagées (API stats + dataviz du tableau de bord).3 * Palette catégorielle validée (skill dataviz, ordre fixe, jamais cyclée) :4 * clair/sombre sélectionnés séparément, gris neutre réservé à « Autres ».5 */67export type CategoryKey =8 | "documents"9 | "images"10 | "videos"11 | "code"12 | "audio"13 | "spreadsheets"14 | "archives"15 | "other";1617export interface CategoryDef {18 key: CategoryKey;19 label: string;20 light: string;21 dark: string;22}2324/** Ordre = ordre des slots de la palette (fixe). */25export const CATEGORIES: CategoryDef[] = [26 { key: "documents", label: "Documents", light: "#2a78d6", dark: "#3987e5" },27 { key: "images", label: "Images", light: "#eb6834", dark: "#d95926" },28 { key: "videos", label: "Vidéos", light: "#1baf7a", dark: "#199e70" },29 { key: "code", label: "Code & texte", light: "#eda100", dark: "#c98500" },30 { key: "audio", label: "Audio", light: "#e87ba4", dark: "#d55181" },31 { key: "spreadsheets", label: "Tableurs", light: "#008300", dark: "#008300" },32 { key: "archives", label: "Archives", light: "#4a3aa7", dark: "#9085e9" },33 { key: "other", label: "Autres", light: "#9aa1ad", dark: "#6b7280" },34];3536export const CATEGORY_BY_KEY: Record<CategoryKey, CategoryDef> = Object.fromEntries(37 CATEGORIES.map((c) => [c.key, c])38) as Record<CategoryKey, CategoryDef>;3940export function categorize(mimeType: string): CategoryKey {41 const m = (mimeType || "").toLowerCase();42 if (m.startsWith("image/")) return "images";43 if (m.startsWith("video/")) return "videos";44 if (m.startsWith("audio/")) return "audio";45 if (46 m.includes("spreadsheet") ||47 m.includes("excel") ||48 m === "text/csv" ||49 m.includes("ms-excel") ||50 m.includes("numbers")51 )52 return "spreadsheets";53 if (54 m === "application/pdf" ||55 m.includes("word") ||56 m.includes("officedocument.wordprocessingml") ||57 m.includes("presentation") ||58 m.includes("powerpoint") ||59 m.includes("rtf") ||60 m.includes("opendocument") ||61 m.includes("pages") ||62 m.includes("epub") ||63 m.includes("keynote")64 )65 return "documents";66 if (67 m.includes("zip") ||68 m.includes("rar") ||69 m.includes("7z") ||70 m.includes("tar") ||71 m.includes("gzip") ||72 m.includes("compressed") ||73 m.includes("archive") ||74 m.includes("x-bzip") ||75 m.includes("x-xz")76 )77 return "archives";78 if (79 m.startsWith("text/") ||80 m.includes("json") ||81 m.includes("xml") ||82 m.includes("javascript") ||83 m.includes("typescript") ||84 m.includes("yaml") ||85 m.includes("toml") ||86 m.includes("x-sh") ||87 m.includes("x-python") ||88 m.includes("markdown") ||89 m.includes("html") ||90 m.includes("css") ||91 m.includes("sql")92 )93 return "code";94 return "other";95}9697export interface CategoryStat {98 key: CategoryKey;99 label: string;100 count: number;101 size: number;102}103104export function aggregateByCategory(rows: { type: string; count: number; size: number }[]): CategoryStat[] {105 const acc = new Map<CategoryKey, CategoryStat>();106 for (const c of CATEGORIES) acc.set(c.key, { key: c.key, label: c.label, count: 0, size: 0 });107 for (const r of rows) {108 const k = categorize(r.type);109 const s = acc.get(k)!;110 s.count += r.count;111 s.size += r.size;112 }113 // Ordre fixe (palette), on ne trie PAS par taille : la couleur suit l'entité.114 return Array.from(acc.values());115}116