Restyling light pastel: tema blanco/azul/verde + Inter self-hosted

- theme.css reescrito: paleta light (sky/emerald accents, slate neutrals),
  tokens de spacing/typography/radii/shadows, @font-face Inter +
  JetBrains Mono variable woff2 self-hosted.
- ops-shell: header blanco con nav active=accent-soft + status pill pastel.
- run-timeline: bubbles emerald-100 (user) / blue-100 (bot) sobre blanco.
- home-dashboard: helpers cssVar + withAlpha, 6 charts coordinados a
  paleta pastel (--chart-blue/green/purple/orange/pink/gray).
- 8 CRUDs (users, products, orders, conversations, aliases,
  recommendations, quantities, takeovers, settings, debug) migrados
  de hex hardcoded oscuros a var(--*).
- modal.js + toast.js refactor a vars con fallbacks; modal blanco
  con shadow-lg y soft icon backgrounds.
- test-panel: aliases :host apuntan a globals en vez de override dark.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lucas Tettamanti
2026-05-02 13:56:48 -03:00
parent 675a449ce8
commit 0bf26f8eb5
22 changed files with 2355 additions and 655 deletions

View File

@@ -10,6 +10,20 @@ function formatNumber(value) {
return new Intl.NumberFormat("es-AR", { maximumFractionDigits: 1 }).format(value);
}
/** Lee una CSS custom property del :root. Fallback al hex provisto. */
function cssVar(name, fallback = "") {
const v = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
return v || fallback;
}
/** rgba con alpha desde un hex (#RRGGBB) o sky/etc — para fills de charts. */
function withAlpha(hex, alpha) {
const m = /^#?([0-9a-f]{6})$/i.exec(hex || "");
if (!m) return hex;
const n = parseInt(m[1], 16);
return `rgba(${(n >> 16) & 255}, ${(n >> 8) & 255}, ${n & 255}, ${alpha})`;
}
class HomeDashboard extends HTMLElement {
constructor() {
super();
@@ -20,109 +34,86 @@ class HomeDashboard extends HTMLElement {
this.shadowRoot.innerHTML = `
<style>
:host {
/* Aliases locales que apuntan a los globals — los charts usan estos
nombres cortos. Cambiar el tema desde theme.css se propaga aquí. */
--line: var(--border);
--blue: var(--chart-blue);
--green: var(--chart-green);
--purple: var(--chart-purple);
--orange: var(--chart-orange);
--emerald: #10B981;
--pink: var(--chart-pink);
--gray: var(--chart-gray);
}
* { box-sizing: border-box; font-family: system-ui, Segoe UI, Roboto, Arial; }
:host { font-family: var(--font-sans); }
* { box-sizing: border-box; }
.container {
min-height: 100%;
background: var(--bg);
color: var(--text);
padding: 16px;
padding: var(--space-6);
overflow-y: auto;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
display: flex; justify-content: space-between; align-items: baseline;
margin-bottom: var(--space-6);
}
.header h1 {
font-size: 24px;
font-weight: 600;
font-size: var(--fs-xl);
font-weight: var(--fw-semibold);
letter-spacing: -0.02em;
margin: 0;
}
.sync-info {
font-size: 12px;
color: var(--muted);
}
.sync-info { font-size: var(--fs-sm); color: var(--text-muted); }
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
gap: 16px;
gap: var(--space-6);
}
.chart-card {
background: var(--panel);
border-radius: 8px;
padding: 16px;
}
.chart-card.full-width {
grid-column: 1 / -1;
border: 1px solid var(--border);
border-radius: var(--r-lg);
padding: var(--space-5);
box-shadow: var(--shadow-sm);
}
.chart-card.full-width { grid-column: 1 / -1; }
.chart-title {
font-size: 14px;
font-weight: 600;
color: var(--muted);
font-size: var(--fs-xs);
font-weight: var(--fw-semibold);
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 12px;
}
.chart-container {
position: relative;
height: 250px;
}
.chart-container.tall {
height: 300px;
}
.chart-container.short {
height: 200px;
letter-spacing: 0.06em;
margin-bottom: var(--space-4);
}
.chart-container { position: relative; height: 260px; }
.chart-container.tall { height: 320px; }
.chart-container.short { height: 200px; }
.loading {
display: flex;
align-items: center;
justify-content: center;
height: 200px;
color: var(--muted);
display: flex; align-items: center; justify-content: center;
height: 200px; color: var(--text-muted);
}
.kpi-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 16px;
margin-bottom: 20px;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: var(--space-4);
margin-bottom: var(--space-6);
}
.kpi-card {
background: var(--panel);
border-radius: 8px;
padding: 16px;
text-align: center;
border: 1px solid var(--border);
border-radius: var(--r-lg);
padding: var(--space-5);
box-shadow: var(--shadow-sm);
}
.kpi-value {
font-size: 24px;
font-weight: 700;
font-size: var(--fs-xl);
font-weight: var(--fw-bold);
letter-spacing: -0.02em;
margin-bottom: 4px;
}
.kpi-label {
font-size: 12px;
color: var(--muted);
font-size: var(--fs-xs);
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.06em;
font-weight: var(--fw-medium);
}
.donut-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
}
canvas {
max-width: 100%;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: var(--space-4);
}
canvas { max-width: 100%; }
</style>
<div class="container">
<div class="header">
@@ -236,7 +227,7 @@ class HomeDashboard extends HTMLElement {
const kpiRow = this.shadowRoot.querySelector(".kpi-row");
kpiRow.innerHTML = `
<div class="kpi-card">
<div class="kpi-value" style="color: var(--blue)">${formatCurrency(totals.total_revenue)}</div>
<div class="kpi-value" style="color: var(--chart-blue)">${formatCurrency(totals.total_revenue)}</div>
<div class="kpi-label">Total Facturado</div>
</div>
<div class="kpi-card">
@@ -244,11 +235,11 @@ class HomeDashboard extends HTMLElement {
<div class="kpi-label">Pedidos</div>
</div>
<div class="kpi-card">
<div class="kpi-value" style="color: var(--green)">${formatCurrency(totals.by_source?.whatsapp)}</div>
<div class="kpi-value" style="color: var(--chart-green)">${formatCurrency(totals.by_source?.whatsapp)}</div>
<div class="kpi-label">WhatsApp</div>
</div>
<div class="kpi-card">
<div class="kpi-value" style="color: var(--blue)">${formatCurrency(totals.by_source?.web)}</div>
<div class="kpi-value" style="color: var(--chart-blue)">${formatCurrency(totals.by_source?.web)}</div>
<div class="kpi-label">Web</div>
</div>
`;
@@ -273,8 +264,8 @@ class HomeDashboard extends HTMLElement {
datasets: [{
label: "Ventas",
data: totals,
backgroundColor: "rgba(59, 130, 246, 0.8)",
borderColor: "#3b82f6",
backgroundColor: withAlpha(cssVar("--chart-blue"), 0.7),
borderColor: cssVar("--chart-blue"),
borderWidth: 1,
}],
},
@@ -287,11 +278,11 @@ class HomeDashboard extends HTMLElement {
scales: {
y: {
beginAtZero: true,
ticks: { color: "#8aa0b5" },
grid: { color: "#1e2a3a" },
ticks: { color: cssVar("--text-muted") },
grid: { color: cssVar("--border") },
},
x: {
ticks: { color: "#8aa0b5" },
ticks: { color: cssVar("--text-muted") },
grid: { display: false },
},
},
@@ -320,12 +311,12 @@ class HomeDashboard extends HTMLElement {
{
label: "WhatsApp",
data: waData,
backgroundColor: "#25D366",
backgroundColor: cssVar("--chart-green"),
},
{
label: "Web",
data: webData,
backgroundColor: "#3b82f6",
backgroundColor: cssVar("--chart-blue"),
},
],
},
@@ -335,19 +326,19 @@ class HomeDashboard extends HTMLElement {
plugins: {
legend: {
position: "top",
labels: { color: "#8aa0b5" },
labels: { color: cssVar("--text-muted") },
},
},
scales: {
y: {
stacked: true,
beginAtZero: true,
ticks: { color: "#8aa0b5" },
grid: { color: "#1e2a3a" },
ticks: { color: cssVar("--text-muted") },
grid: { color: cssVar("--border") },
},
x: {
stacked: true,
ticks: { color: "#8aa0b5" },
ticks: { color: cssVar("--text-muted") },
grid: { display: false },
},
},
@@ -371,16 +362,16 @@ class HomeDashboard extends HTMLElement {
{
label: String(yoy.current_year || "Actual"),
data: yoy.current_year_data || [],
borderColor: "#3b82f6",
backgroundColor: "rgba(59, 130, 246, 0.1)",
borderColor: cssVar("--chart-blue"),
backgroundColor: withAlpha(cssVar("--chart-blue"), 0.15),
fill: true,
tension: 0.3,
},
{
label: String(yoy.last_year || "Anterior"),
data: yoy.last_year_data || [],
borderColor: "#9CA3AF",
backgroundColor: "rgba(156, 163, 175, 0.1)",
borderColor: cssVar("--chart-gray"),
backgroundColor: withAlpha(cssVar("--chart-gray"), 0.15),
fill: true,
tension: 0.3,
},
@@ -392,17 +383,17 @@ class HomeDashboard extends HTMLElement {
plugins: {
legend: {
position: "top",
labels: { color: "#8aa0b5" },
labels: { color: cssVar("--text-muted") },
},
},
scales: {
y: {
beginAtZero: true,
ticks: { color: "#8aa0b5" },
grid: { color: "#1e2a3a" },
ticks: { color: cssVar("--text-muted") },
grid: { color: cssVar("--border") },
},
x: {
ticks: { color: "#8aa0b5" },
ticks: { color: cssVar("--text-muted") },
grid: { display: false },
},
},
@@ -423,7 +414,7 @@ class HomeDashboard extends HTMLElement {
labels: ["WhatsApp", "Web"],
datasets: [{
data: [totals.by_source?.whatsapp || 0, totals.by_source?.web || 0],
backgroundColor: ["#25D366", "#3b82f6"],
backgroundColor: [cssVar("--chart-green"), cssVar("--chart-blue")],
}],
},
options: this.getDonutOptions(),
@@ -440,7 +431,7 @@ class HomeDashboard extends HTMLElement {
labels: ["Delivery", "Retiro"],
datasets: [{
data: [totals.by_shipping?.delivery || 0, totals.by_shipping?.pickup || 0],
backgroundColor: ["#8B5CF6", "#F59E0B"],
backgroundColor: [cssVar("--chart-purple"), cssVar("--chart-orange")],
}],
},
options: this.getDonutOptions(),
@@ -456,7 +447,7 @@ class HomeDashboard extends HTMLElement {
plugins: {
legend: {
position: "bottom",
labels: { color: "#8aa0b5" },
labels: { color: cssVar("--text-muted") },
},
},
};
@@ -479,8 +470,8 @@ class HomeDashboard extends HTMLElement {
datasets: [{
label: "Facturación",
data,
backgroundColor: "rgba(59, 130, 246, 0.8)",
borderColor: "#3b82f6",
backgroundColor: withAlpha(cssVar("--chart-blue"), 0.7),
borderColor: cssVar("--chart-blue"),
borderWidth: 1,
}],
},
@@ -494,11 +485,11 @@ class HomeDashboard extends HTMLElement {
scales: {
x: {
beginAtZero: true,
ticks: { color: "#8aa0b5" },
grid: { color: "#1e2a3a" },
ticks: { color: cssVar("--text-muted") },
grid: { color: cssVar("--border") },
},
y: {
ticks: { color: "#8aa0b5" },
ticks: { color: cssVar("--text-muted") },
grid: { display: false },
},
},
@@ -523,8 +514,8 @@ class HomeDashboard extends HTMLElement {
datasets: [{
label: "Kg",
data,
backgroundColor: "rgba(139, 92, 246, 0.8)",
borderColor: "#8B5CF6",
backgroundColor: withAlpha(cssVar("--chart-purple"), 0.7),
borderColor: cssVar("--chart-purple"),
borderWidth: 1,
}],
},
@@ -538,11 +529,11 @@ class HomeDashboard extends HTMLElement {
scales: {
x: {
beginAtZero: true,
ticks: { color: "#8aa0b5" },
grid: { color: "#1e2a3a" },
ticks: { color: cssVar("--text-muted") },
grid: { color: cssVar("--border") },
},
y: {
ticks: { color: "#8aa0b5", font: { size: 10 } },
ticks: { color: cssVar("--text-muted"), font: { size: 10 } },
grid: { display: false },
},
},
@@ -567,8 +558,8 @@ class HomeDashboard extends HTMLElement {
datasets: [{
label: "Unidades",
data,
backgroundColor: "rgba(245, 158, 11, 0.8)",
borderColor: "#F59E0B",
backgroundColor: withAlpha(cssVar("--chart-orange"), 0.7),
borderColor: cssVar("--chart-orange"),
borderWidth: 1,
}],
},
@@ -582,11 +573,11 @@ class HomeDashboard extends HTMLElement {
scales: {
x: {
beginAtZero: true,
ticks: { color: "#8aa0b5" },
grid: { color: "#1e2a3a" },
ticks: { color: cssVar("--text-muted") },
grid: { color: cssVar("--border") },
},
y: {
ticks: { color: "#8aa0b5", font: { size: 10 } },
ticks: { color: cssVar("--text-muted"), font: { size: 10 } },
grid: { display: false },
},
},