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:
@@ -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 },
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user