// common.js — petits utilitaires partagés entre app.js (page globale) // et tenant.js (page détail tenant). const eurFormatter = new Intl.NumberFormat("fr-FR", { style: "currency", currency: "EUR", maximumFractionDigits: 2, }); function formatEUR(amount) { if (amount === null || amount === undefined) return "—"; return eurFormatter.format(amount); } function formatPct(value) { if (value === null || value === undefined) return null; const sign = value > 0 ? "+" : ""; return `${sign}${value.toFixed(1)} %`; } function deltaClass(value) { if (value === null || value === undefined) return "flat"; if (value > 0.5) return "up"; if (value < -0.5) return "down"; return "flat"; } function deltaArrow(value) { if (value === null || value === undefined) return ""; if (value > 0.5) return "↑"; if (value < -0.5) return "↓"; return "→"; } function monthLabel(monthKey) { const [y, m] = monthKey.split("-").map(Number); const d = new Date(Date.UTC(y, m - 1, 1)); return new Intl.DateTimeFormat("fr-FR", { month: "short", year: "2-digit", timeZone: "UTC" }).format(d); } function dayLabel(isoDate) { const d = new Date(`${isoDate}T00:00:00Z`); return new Intl.DateTimeFormat("fr-FR", { day: "2-digit", month: "short", timeZone: "UTC" }).format(d); } function providerLabel(provider) { return provider === "aws" ? "AWS" : provider === "azure" ? "Azure" : provider; } function escapeHtml(str) { return String(str) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } function cssVar(name) { return getComputedStyle(document.documentElement).getPropertyValue(name).trim(); } // Config partagée des axes/grilles Chart.js (gridlines discrètes, pas de // deuxième axe, tooltip alignée sur le design system). function chartBaseOptions() { return { responsive: true, maintainAspectRatio: false, interaction: { mode: "index", intersect: false }, plugins: { legend: { display: false }, tooltip: { backgroundColor: cssVar("--surface-1"), titleColor: cssVar("--text-primary"), bodyColor: cssVar("--text-secondary"), borderColor: cssVar("--border"), borderWidth: 1, padding: 10, displayColors: true, boxPadding: 4, }, }, scales: { x: { grid: { display: false }, border: { color: cssVar("--axis") }, ticks: { color: cssVar("--text-muted"), font: { size: 11 } }, }, y: { beginAtZero: true, grid: { color: cssVar("--gridline") }, border: { display: false }, ticks: { color: cssVar("--text-muted"), font: { size: 11 } }, }, }, }; }