inventschario/sketches/001-dashboard/index.html
pikaos ee849eb9a8 feat: roadmap y diseño inicial — iteración 1 antes de feedback del usuario
Inventario de dispositivos electrónicos no prestables para administración
pública. Esta primera iteración contiene el diseño y la planificación
antes de contactar con el usuario para su validación.

Contenido:
- especificaciones.md: requisitos detallados del programa
- docs/arquitectura.md: propuesta de arquitectura con alternativas
- docs/roadmap-iteracion-1.md: plan de desarrollo iteración 1
- docs/arquitectura-diagrama.html: diagrama visual de arquitectura
- sketches/: mockups de las 4 pantallas principales
  - 001-dashboard: vista resumen
  - 002-inventario: tabla de dispositivos
  - 003-formulario: alta/edición de dispositivos
  - 004-configuracion: ajustes generales

Stack propuesto: Python + Flask + SQLite + Alpine.js
Distribución: PyInstaller → un único .exe autocontenido
Entorno: Windows 11 Pro unida a dominio, sin privilegios de admin
2026-08-03 01:34:56 +01:00

526 lines
17 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Inventschario — Dashboard</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
color: #1a1a1a;
background: #f7f7f5;
line-height: 1.5;
display: flex;
min-height: 100vh;
}
/* Sidebar */
.sidebar {
width: 240px;
background: #ffffff;
border-right: 1px solid #e5e5e3;
padding: 20px 0;
flex-shrink: 0;
display: flex;
flex-direction: column;
}
.sidebar-logo {
padding: 0 20px 20px;
border-bottom: 1px solid #e5e5e3;
margin-bottom: 8px;
}
.sidebar-logo h1 {
font-size: 16px;
font-weight: 700;
color: #1a1a1a;
letter-spacing: -0.3px;
}
.sidebar-logo span {
font-size: 11px;
color: #999;
display: block;
margin-top: 2px;
}
.nav-section {
padding: 8px 12px;
}
.nav-label {
font-size: 11px;
font-weight: 600;
color: #999;
text-transform: uppercase;
letter-spacing: 0.5px;
padding: 8px 8px 4px;
}
.nav-item {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 12px;
border-radius: 6px;
font-size: 14px;
color: #666;
cursor: pointer;
text-decoration: none;
transition: background 0.15s, color 0.15s;
}
.nav-item:hover { background: #f0f0ee; color: #1a1a1a; }
.nav-item.active { background: #f0f0ee; color: #1a1a1a; font-weight: 500; }
.nav-item svg { width: 18px; height: 18px; flex-shrink: 0; }
.nav-spacer { flex: 1; }
.nav-footer {
padding: 12px 20px;
border-top: 1px solid #e5e5e3;
font-size: 12px;
color: #999;
}
/* Main content */
.main {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.topbar {
background: #ffffff;
border-bottom: 1px solid #e5e5e3;
padding: 16px 32px;
display: flex;
align-items: center;
justify-content: space-between;
}
.topbar h2 {
font-size: 18px;
font-weight: 600;
}
.topbar-actions { display: flex; gap: 10px; }
.btn {
padding: 8px 16px;
border-radius: 6px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
border: 1px solid #e5e5e3;
background: #fff;
color: #1a1a1a;
transition: background 0.15s;
font-family: inherit;
}
.btn:hover { background: #f0f0ee; }
.btn-primary {
background: #1a1a1a;
color: #fff;
border-color: #1a1a1a;
}
.btn-primary:hover { background: #333; }
.content {
padding: 32px;
overflow-y: auto;
flex: 1;
}
/* Stats grid */
.stats-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
margin-bottom: 32px;
}
.stat-card {
background: #ffffff;
border: 1px solid #e5e5e3;
border-radius: 8px;
padding: 20px;
}
.stat-label {
font-size: 12px;
color: #999;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.3px;
}
.stat-value {
font-size: 32px;
font-weight: 700;
color: #1a1a1a;
margin-top: 4px;
letter-spacing: -1px;
}
.stat-change {
font-size: 12px;
color: #666;
margin-top: 4px;
}
.stat-change .up { color: #16a34a; }
.stat-change .down { color: #dc2626; }
/* Two-column layout */
.two-col {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
}
/* Card */
.card {
background: #ffffff;
border: 1px solid #e5e5e3;
border-radius: 8px;
overflow: hidden;
}
.card-header {
padding: 16px 20px;
border-bottom: 1px solid #e5e5e3;
display: flex;
align-items: center;
justify-content: space-between;
}
.card-header h3 {
font-size: 14px;
font-weight: 600;
}
.card-body { padding: 0; }
.card-body.padded { padding: 20px; }
/* Table */
table {
width: 100%;
border-collapse: collapse;
}
th {
text-align: left;
padding: 10px 16px;
font-size: 11px;
font-weight: 600;
color: #999;
text-transform: uppercase;
letter-spacing: 0.3px;
border-bottom: 1px solid #e5e5e3;
background: #fafafa;
}
td {
padding: 12px 16px;
font-size: 13px;
border-bottom: 1px solid #f0f0ee;
}
tr:last-child td { border-bottom: none; }
tr:hover td { background: #fafaf8; }
/* Badges */
.badge {
display: inline-block;
padding: 2px 8px;
border-radius: 4px;
font-size: 11px;
font-weight: 500;
}
.badge-active { background: #dcfce7; color: #166534; }
.badge-available { background: #e0e7ff; color: #3730a3; }
.badge-maintenance { background: #fef3c7; color: #92400e; }
.badge-decommissioned { background: #f3f4f6; color: #6b7280; }
.badge-computer { background: #f0f0ee; color: #555; }
.badge-monitor { background: #eff6ff; color: #1d4ed8; }
.badge-laptop { background: #fdf4ff; color: #9333ea; }
/* Chart placeholder */
.chart-placeholder {
height: 160px;
display: flex;
align-items: flex-end;
gap: 8px;
padding: 20px;
}
.chart-bar {
flex: 1;
background: #e5e5e3;
border-radius: 4px 4px 0 0;
position: relative;
transition: background 0.2s;
}
.chart-bar:hover { background: #1a1a1a; }
.chart-bar-label {
position: absolute;
bottom: -24px;
left: 50%;
transform: translateX(-50%);
font-size: 10px;
color: #999;
white-space: nowrap;
}
/* Alert banner */
.alert {
background: #fffbeb;
border: 1px solid #fde68a;
border-radius: 8px;
padding: 14px 20px;
margin-bottom: 24px;
display: flex;
align-items: center;
gap: 12px;
font-size: 13px;
}
.alert-icon { font-size: 18px; }
.alert-text { flex: 1; color: #92400e; }
.alert-action {
padding: 6px 12px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
background: #fbbf24;
color: #92400e;
border: none;
cursor: pointer;
font-family: inherit;
}
.alert-action:hover { background: #f59e0b; }
/* Quick actions */
.quick-actions {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
}
.quick-action {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
padding: 20px 12px;
border: 1px solid #e5e5e3;
border-radius: 8px;
cursor: pointer;
transition: border-color 0.15s, background 0.15s;
text-decoration: none;
color: inherit;
}
.quick-action:hover { border-color: #ccc; background: #fafaf8; }
.quick-action-icon {
width: 40px;
height: 40px;
border-radius: 8px;
background: #f0f0ee;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
}
.quick-action-label {
font-size: 12px;
font-weight: 500;
color: #666;
text-align: center;
}
/* Focus styles for accessibility */
*:focus-visible {
outline: 2px solid #1a1a1a;
outline-offset: 2px;
}
</style>
</head>
<body>
<!-- Sidebar -->
<nav class="sidebar" role="navigation" aria-label="Menú principal">
<div class="sidebar-logo">
<h1>Inventschario</h1>
<span>Inventario Electrónico</span>
</div>
<div class="nav-section">
<div class="nav-label">Principal</div>
<a class="nav-item active" href="#dashboard" aria-current="page">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>
Dashboard
</a>
<a class="nav-item" href="#inventory">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2"/><rect x="9" y="3" width="6" height="4" rx="1"/></svg>
Inventario
</a>
<a class="nav-item" href="#add">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="16"/><line x1="8" y1="12" x2="16" y2="12"/></svg>
Agregar Dispositivo
</a>
</div>
<div class="nav-section">
<div class="nav-label">Herramientas</div>
<a class="nav-item" href="#import">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
Importar / Exportar
</a>
<a class="nav-item" href="#backups">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 21H5a2 2 0 01-2-2V5a2 2 0 012-2h11l5 5v11a2 2 0 01-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>
Copias de Seguridad
</a>
<a class="nav-item" href="#settings">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-2 2 2 2 0 01-2-2v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83 0 2 2 0 010-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 01-2-2 2 2 0 012-2h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 010-2.83 2 2 0 012.83 0l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 012-2 2 2 0 012 2v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 0 2 2 0 010 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9a1.65 1.65 0 001.51 1H21a2 2 0 012 2 2 2 0 01-2 2h-.09a1.65 1.65 0 00-1.51 1z"/></svg>
Configuración
</a>
</div>
<div class="nav-spacer"></div>
<div class="nav-footer">
v1.0.0 — 2026-08-03
</div>
</nav>
<!-- Main Content -->
<main class="main" role="main">
<header class="topbar">
<h2>Dashboard</h2>
<div class="topbar-actions">
<button class="btn" aria-label="Crear backup manual">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="vertical-align: middle; margin-right: 4px;"><path d="M19 21H5a2 2 0 01-2-2V5a2 2 0 012-2h11l5 5v11a2 2 0 01-2 2z"/></svg>
Backup
</button>
<button class="btn btn-primary" aria-label="Agregar nuevo dispositivo">+ Nuevo Dispositivo</button>
</div>
</header>
<div class="content">
<!-- Alert: old backups -->
<div class="alert" role="alert">
<span class="alert-icon" aria-hidden="true">⚠️</span>
<span class="alert-text">Hay <strong>3 copias de seguridad</strong> con más de 30 días. ¿Desea eliminar las antiguas?</span>
<button class="alert-action" aria-label="Eliminar backups antiguos">Revisar</button>
</div>
<!-- Stats -->
<div class="stats-grid">
<div class="stat-card">
<div class="stat-label">Total Dispositivos</div>
<div class="stat-value">247</div>
<div class="stat-change"><span class="up">↑ 12</span> este mes</div>
</div>
<div class="stat-card">
<div class="stat-label">En Uso</div>
<div class="stat-value">198</div>
<div class="stat-change">80% del total</div>
</div>
<div class="stat-card">
<div class="stat-label">Disponibles</div>
<div class="stat-value">31</div>
<div class="stat-change"><span class="up">↑ 5</span> desde el mes pasado</div>
</div>
<div class="stat-card">
<div class="stat-label">En Mantenimiento</div>
<div class="stat-value">8</div>
<div class="stat-change"><span class="down">↑ 3</span> esta semana</div>
</div>
</div>
<!-- Two column layout -->
<div class="two-col">
<!-- Recent devices -->
<div class="card">
<div class="card-header">
<h3>Últimos Dispositivos Registrados</h3>
<a href="#inventory" style="font-size: 12px; color: #666; text-decoration: none;">Ver todos →</a>
</div>
<div class="card-body">
<table>
<thead>
<tr>
<th>Catálogo</th>
<th>Nombre</th>
<th>Tipo</th>
<th>Estado</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>INV-2024-0247</strong></td>
<td>MacBook Pro 14"</td>
<td><span class="badge badge-laptop">Portátil</span></td>
<td><span class="badge badge-active">Activo</span></td>
</tr>
<tr>
<td><strong>INV-2024-0246</strong></td>
<td>Dell P2723QE</td>
<td><span class="badge badge-monitor">Monitor</span></td>
<td><span class="badge badge-available">Disponible</span></td>
</tr>
<tr>
<td><strong>INV-2024-0245</strong></td>
<td>Lenovo ThinkPad T14s</td>
<td><span class="badge badge-laptop">Portátil</span></td>
<td><span class="badge badge-active">Activo</span></td>
</tr>
<tr>
<td><strong>INV-2024-0244</strong></td>
<td>HP LaserJet Pro M404</td>
<td><span class="badge badge-computer">Impresora</span></td>
<td><span class="badge badge-maintenance">Mantenimiento</span></td>
</tr>
<tr>
<td><strong>INV-2024-0243</strong></td>
<td>Cisco Catalyst 2960</td>
<td><span class="badge badge-computer">Red</span></td>
<td><span class="badge badge-active">Activo</span></td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Distribution by type -->
<div class="card">
<div class="card-header">
<h3>Distribución por Tipo</h3>
</div>
<div class="card-body padded">
<div class="chart-placeholder" style="padding-bottom: 36px;">
<div class="chart-bar" style="height: 85%;">
<span class="chart-bar-label">Portátiles</span>
</div>
<div class="chart-bar" style="height: 60%;">
<span class="chart-bar-label">Monitores</span>
</div>
<div class="chart-bar" style="height: 45%;">
<span class="chart-bar-label">Sobremesa</span>
</div>
<div class="chart-bar" style="height: 25%;">
<span class="chart-bar-label">Impresoras</span>
</div>
<div class="chart-bar" style="height: 20%;">
<span class="chart-bar-label">Red</span>
</div>
<div class="chart-bar" style="height: 15%;">
<span class="chart-bar-label">Perif.</span>
</div>
<div class="chart-bar" style="height: 10%;">
<span class="chart-bar-label">Otros</span>
</div>
</div>
</div>
</div>
</div>
<!-- Quick actions -->
<div style="margin-top: 32px;">
<h3 style="font-size: 14px; font-weight: 600; margin-bottom: 16px;">Acciones Rápidas</h3>
<div class="quick-actions">
<a class="quick-action" href="#add">
<div class="quick-action-icon" aria-hidden="true"></div>
<div class="quick-action-label">Agregar<br>Dispositivo</div>
</a>
<a class="quick-action" href="#import">
<div class="quick-action-icon" aria-hidden="true"></div>
<div class="quick-action-label">Importar<br>desde CSV</div>
</a>
<a class="quick-action" href="#export">
<div class="quick-action-icon" aria-hidden="true"></div>
<div class="quick-action-label">Exportar<br>a CSV</div>
</a>
</div>
</div>
</div>
</main>
</body>
</html>