Skip to content

Dashboard de administración ​

Panel de administración completo hecho con HTML, CSS y JavaScript puro, sin librerías: sidebar colapsable, tarjetas de KPIs, gráfica de barras y gráfica de dona en SVG con tooltips y animación, tabla de pedidos con búsqueda, filtro, orden por columna y paginación, y modo oscuro persistente.

Sirve como base para el panel de cualquier sistema que construyas para un cliente: tienda, CRM, escuela, inventario, reservas...

Vista previa ​

Panel de administración

Prueba: cambia el periodo (7 días / 30 días / 12 meses), pasa el mouse sobre las barras, ordena la tabla haciendo clic en los encabezados, busca un cliente, colapsa el menú con ☰ y activa el modo oscuro.

Estructura del layout ​

txt
.app (grid: sidebar | principal)
├── aside.sidebar         ← menú lateral (fijo en escritorio, deslizable en móvil)
└── .principal
    ├── header.topbar     ← botón de menú, búsqueda, tema, notificaciones, usuario
    └── main.contenido
        ├── .cabecera     ← saludo + selector de periodo
        ├── .kpis         ← 4 tarjetas de indicadores
        ├── .fila-graficas← barras (2/3) + dona (1/3)
        └── tabla de pedidos

El sidebar colapsable se logra cambiando una sola variable CSS:

css
.app { display: grid; grid-template-columns: var(--ancho-sidebar) 1fr; transition: grid-template-columns .3s; }
.app.colapsado { --ancho-sidebar: 72px; }
.app.colapsado .texto-menu { opacity: 0; }  /* sólo se ven los iconos */

En pantallas pequeñas el sidebar sale de la pantalla (translateX(-100%)) y se abre encima del contenido con una capa oscura.

Gráficas sin librerías ​

Barras en SVG ​

pintarGrafica() calcula la escala a partir del valor máximo, dibuja la rejilla, las etiquetas de los ejes y dos barras por grupo (periodo actual y anterior). Las barras crecen con una transición CSS y muestran un tooltip con el valor exacto:

js
const max = Math.max(...actual, ...anterior) * 1.1;          // 10 % de aire arriba
const altoBarra = (valor / max) * h;                          // regla de tres
const rect = svgEl('rect', { x, y: m.arriba + h, width: anchoBarra, height: 0, rx: 4, class: 'barra' });
requestAnimationFrame(() => {                                 // anima de 0 a su altura
  rect.style.transition = 'y .6s ease, height .6s ease';
  rect.setAttribute('y', m.arriba + h - altoBarra);
  rect.setAttribute('height', altoBarra);
});

Los colores salen de variables CSS (fill: var(--primario)), así que la gráfica cambia sola con el modo oscuro.

Dona con stroke-dasharray ​

El truco: un círculo con radio 15.915 tiene una circunferencia de casi exactamente 100, así que cada porcentaje equivale a una unidad del trazo:

js
const r = 15.915;
svg.append(svgEl('circle', {
  cx: 21, cy: 21, r, fill: 'none', stroke: c.color, 'stroke-width': 6,
  'stroke-dasharray': `${pct} ${100 - pct}`,   // tramo visible y tramo vacío
  'stroke-dashoffset': 25 - acumulado,         // empieza donde terminó el anterior
}));

¿Cuándo usar una librería?

Para un panel con 2–3 gráficas simples, SVG a mano pesa 0 KB extra. Si el cliente pide gráficas de líneas con zoom, muchas series o exportar a imagen, usa Chart.js o ApexCharts desde un CDN.

Tabla con búsqueda, filtro, orden y paginación ​

Todo el comportamiento depende de un objeto de estado:

js
const estadoTabla = { texto: '', estado: '', orden: 'fecha', dir: -1, pagina: 1, porPagina: 8 };

pintarTabla() aplica en orden: filtrar → ordenar → paginar → pintar. Los encabezados con data-orden cambian la columna y alternan la dirección; la búsqueda usa un pequeño debounce de 200 ms. Para conectar datos reales, sustituye PEDIDOS por la respuesta de tu API:

js
const res = await fetch('/api/pedidos?limite=100');
const { data } = await res.json();
PEDIDOS.splice(0, PEDIDOS.length, ...data.map((p) => ({ ...p, fecha: new Date(p.fecha) })));
pintarTabla();

Con miles de registros, haz la búsqueda, el orden y la paginación en el servidor (paginación en Node o PHP) y envía ?q=&orden=&dir=&pagina= en cada cambio.

Conectar los KPIs a datos reales ​

Las consultas SQL que alimentan este tipo de panel están en Consultas útiles: ventas por día, ticket promedio, comparación contra el periodo anterior y ventas por categoría. Un endpoint típico devolvería:

json
{
  "kpis": { "ventas": 186400, "ventasAnterior": 171200, "pedidos": 412, "ticketPromedio": 452.4 },
  "serie": { "etiquetas": ["1 oct", "3 oct"], "actual": [6100, 7200], "anterior": [5400, 6800] },
  "categorias": [{ "nombre": "Café", "valor": 48200 }]
}

Personalización ​

css
:root {
  --primario: #4f46e5;   /* botones activos, barras, enlaces */
  --sidebar: #111827;    /* fondo del menú lateral */
  --fondo: #f4f6fb;
  --radio: 14px;         /* redondeo de tarjetas */
}
[data-tema="oscuro"] { /* mismas variables, versión oscura */ }
  • Menú: edita los enlaces del aside; el contador rojo es un span class="badge".
  • KPIs: cambia el arreglo datos dentro de pintarKpis() (etiqueta, valor, variación, icono y color de fondo).
  • Estados de pedidos: cada estado tiene una clase e-nombre con su color.

Protegerlo ​

Un dashboard nunca debe ser público. Ponlo detrás de un login:

Accesibilidad de las gráficas

Las gráficas SVG tienen role="img" y aria-label. Si los datos son críticos, ofrece también una tabla o un botón "Ver datos" para quienes usan lector de pantalla.

Academia Web — aprende, copia y construye.