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
This commit is contained in:
pikaos 2026-08-03 01:34:56 +01:00
commit ee849eb9a8
14 changed files with 3761 additions and 0 deletions

View file

@ -0,0 +1,18 @@
# Variant: Dashboard — Monitor Surface
## Design stance
Data-first density: the user is watching state change. Stats cards at the top,
recent items table, and distribution chart — no hero, no marketing.
## Key choices
- **Layout:** Sidebar + main content, 4-column stats grid, 2-column lower section
- **Typography:** Inter, 32px stat values, 13px body
- **Color:** Neutral (#1a1a1a accent, #f7f7f5 background), status badges with semantic colors
- **Interaction:** Hover on table rows, clickable chart bars, alert dismiss
## Trade-offs
- Strong at: At-a-glance status, quick navigation, density without clutter
- Weak at: On first use with 0 devices (needs empty state design)
## Best for
Administrators who check the dashboard daily to monitor inventory status.

View file

@ -0,0 +1,526 @@
<!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>

View file

@ -0,0 +1,18 @@
# Variant: Inventario — Operate Surface
## Design stance
Action-oriented data table: the user is working with devices, not just viewing them.
Every row has inline actions, the toolbar has filters, and bulk selection is available.
## Key choices
- **Layout:** Full-width table with persistent toolbar, checkbox selection, pagination
- **Typography:** Monospace for catalog numbers, Inter for everything else
- **Color:** Status badges with semantic colors, row hover highlight
- **Interaction:** Sortable columns, filter dropdowns, row-level actions (view, edit, delete)
## Trade-offs
- Strong at: Scanning large lists, quick actions per device, bulk operations
- Weak at: Needs mobile responsive design for tablet use
## Best for
Daily inventory management — searching, filtering, and acting on specific devices.

View file

@ -0,0 +1,403 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Inventschario — Inventario</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 — same as dashboard */
.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; }
.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 { 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; }
.btn-danger { background: #fff; color: #dc2626; border-color: #fca5a5; }
.btn-danger:hover { background: #fef2f2; }
.content { padding: 32px; overflow-y: auto; flex: 1; }
/* Toolbar */
.toolbar {
display: flex; align-items: center; gap: 12px; margin-bottom: 16px; flex-wrap: wrap;
}
.search-box {
flex: 1; min-width: 240px; position: relative;
}
.search-box input {
width: 100%; padding: 8px 12px 8px 36px; border: 1px solid #e5e5e3;
border-radius: 6px; font-size: 13px; font-family: inherit; background: #fff;
}
.search-box input:focus { outline: 2px solid #1a1a1a; outline-offset: -1px; }
.search-box svg {
position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
width: 16px; height: 16px; color: #999;
}
.filter-group { display: flex; gap: 8px; }
.filter-select {
padding: 8px 12px; border: 1px solid #e5e5e3; border-radius: 6px;
font-size: 13px; font-family: inherit; background: #fff; color: #1a1a1a;
cursor: pointer;
}
.filter-select:focus { outline: 2px solid #1a1a1a; outline-offset: -1px; }
/* Selection bar */
.selection-bar {
background: #1a1a1a; color: #fff; padding: 10px 20px; border-radius: 8px;
margin-bottom: 16px; display: flex; align-items: center; gap: 16px;
font-size: 13px;
}
.selection-bar .btn {
background: transparent; color: #fff; border-color: rgba(255,255,255,0.2);
padding: 4px 12px; font-size: 12px;
}
.selection-bar .btn:hover { background: rgba(255,255,255,0.1); }
/* Table */
.table-card {
background: #ffffff; border: 1px solid #e5e5e3; border-radius: 8px; overflow: hidden;
}
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; cursor: pointer;
user-select: none; white-space: nowrap;
}
th:hover { color: #1a1a1a; }
th .sort-icon { margin-left: 4px; opacity: 0.4; }
th.sorted .sort-icon { opacity: 1; color: #1a1a1a; }
td {
padding: 12px 16px; font-size: 13px; border-bottom: 1px solid #f0f0ee;
vertical-align: middle;
}
tr:last-child td { border-bottom: none; }
tr:hover td { background: #fafaf8; }
tr.selected td { background: #f0f0ee; }
/* Checkbox */
.checkbox { width: 16px; height: 16px; cursor: pointer; accent-color: #1a1a1a; }
/* 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-disposed { background: #fee2e2; color: #991b1b; }
.badge-computer { background: #f0f0ee; color: #555; }
.badge-monitor { background: #eff6ff; color: #1d4ed8; }
.badge-laptop { background: #fdf4ff; color: #9333ea; }
.badge-printer { background: #fef3c7; color: #92400e; }
.badge-network { background: #ecfdf5; color: #065f46; }
/* Row actions */
.row-actions { display: flex; gap: 4px; }
.row-action {
width: 28px; height: 28px; border-radius: 4px; border: none;
background: transparent; cursor: pointer; display: flex;
align-items: center; justify-content: center; color: #999;
transition: background 0.15s, color 0.15s;
}
.row-action:hover { background: #f0f0ee; color: #1a1a1a; }
.row-action svg { width: 14px; height: 14px; }
/* Pagination */
.pagination {
display: flex; align-items: center; justify-content: space-between;
padding: 12px 16px; border-top: 1px solid #e5e5e3; font-size: 13px; color: #666;
}
.pagination-info { font-size: 12px; }
.pagination-controls { display: flex; gap: 4px; }
.page-btn {
padding: 4px 10px; border-radius: 4px; border: 1px solid #e5e5e3;
background: #fff; cursor: pointer; font-size: 12px; font-family: inherit;
}
.page-btn:hover { background: #f0f0ee; }
.page-btn.active { background: #1a1a1a; color: #fff; border-color: #1a1a1a; }
/* Focus styles */
*: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" href="#dashboard">
<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 active" href="#inventory" aria-current="page">
<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-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9c.26.604.852.997 1.51 1H21a2 2 0 010 4h-.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>Inventario <span style="font-weight: 400; color: #999; font-size: 14px;">(247 dispositivos)</span></h2>
<div class="topbar-actions">
<button class="btn" aria-label="Exportar selección a CSV">⬇ Exportar</button>
<button class="btn btn-primary" aria-label="Agregar nuevo dispositivo">+ Nuevo</button>
</div>
</header>
<div class="content">
<!-- Toolbar -->
<div class="toolbar" role="search">
<div class="search-box">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="search" placeholder="Buscar por nombre, número de serie, catálogo..." aria-label="Buscar dispositivos">
</div>
<div class="filter-group">
<select class="filter-select" aria-label="Filtrar por tipo">
<option value="">Todos los tipos</option>
<option>Portátil</option>
<option>Sobremesa</option>
<option>Monitor</option>
<option>Impresora</option>
<option>Red</option>
<option>Periférico</option>
</select>
<select class="filter-select" aria-label="Filtrar por estado">
<option value="">Todos los estados</option>
<option>Activo</option>
<option>Disponible</option>
<option>Mantenimiento</option>
<option>Baja</option>
</select>
<select class="filter-select" aria-label="Filtrar por departamento">
<option value="">Todos los departamentos</option>
<option>Informática</option>
<option>Administración</option>
<option>Recursos Humanos</option>
<option>Contabilidad</option>
</select>
</div>
</div>
<!-- Selection bar (hidden by default, shown when items selected) -->
<div class="selection-bar" role="status" aria-live="polite" style="display: none;">
<span>3 seleccionados</span>
<button class="btn">Exportar selección</button>
<button class="btn">Cambiar estado</button>
<button class="btn btn-danger">Eliminar</button>
<button class="btn" style="margin-left: auto;">Cancelar selección</button>
</div>
<!-- Table -->
<div class="table-card">
<table role="grid" aria-label="Lista de dispositivos">
<thead>
<tr>
<th style="width: 40px;"><input type="checkbox" class="checkbox" aria-label="Seleccionar todos"></th>
<th class="sorted">Catálogo <span class="sort-icon"></span></th>
<th>Nombre / Descripción</th>
<th>Tipo</th>
<th>Marca / Modelo</th>
<th>Ubicación</th>
<th>Estado</th>
<th style="width: 100px;">Acciones</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="checkbox" class="checkbox" aria-label="Seleccionar INV-2024-0247"></td>
<td><strong>INV-2024-0247</strong></td>
<td>MacBook Pro 14" — Oficina Dirección</td>
<td><span class="badge badge-laptop">Portátil</span></td>
<td>Apple / MacBook Pro M3</td>
<td>Planta 2, Desp. 201</td>
<td><span class="badge badge-active">Activo</span></td>
<td>
<div class="row-actions">
<button class="row-action" title="Ver detalle" aria-label="Ver detalle de INV-2024-0247">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
</button>
<button class="row-action" title="Editar" aria-label="Editar INV-2024-0247">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
</button>
<button class="row-action" title="Dar de baja" aria-label="Dar de baja INV-2024-0247" style="color: #dc2626;">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
</button>
</div>
</td>
</tr>
<tr>
<td><input type="checkbox" class="checkbox" aria-label="Seleccionar INV-2024-0246"></td>
<td><strong>INV-2024-0246</strong></td>
<td>Dell P2723QE — Monitor 4K</td>
<td><span class="badge badge-monitor">Monitor</span></td>
<td>Dell / P2723QE</td>
<td>Almacén</td>
<td><span class="badge badge-available">Disponible</span></td>
<td>
<div class="row-actions">
<button class="row-action" title="Ver detalle"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg></button>
<button class="row-action" title="Editar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg></button>
<button class="row-action" title="Dar de baja" style="color: #dc2626;"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg></button>
</div>
</td>
</tr>
<tr>
<td><input type="checkbox" class="checkbox" aria-label="Seleccionar INV-2024-0245"></td>
<td><strong>INV-2024-0245</strong></td>
<td>Lenovo ThinkPad T14s — Desarrollo</td>
<td><span class="badge badge-laptop">Portátil</span></td>
<td>Lenovo / ThinkPad T14s Gen 4</td>
<td>Planta 1, Open Space</td>
<td><span class="badge badge-active">Activo</span></td>
<td>
<div class="row-actions">
<button class="row-action" title="Ver detalle"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg></button>
<button class="row-action" title="Editar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg></button>
<button class="row-action" title="Dar de baja" style="color: #dc2626;"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg></button>
</div>
</td>
</tr>
<tr>
<td><input type="checkbox" class="checkbox" aria-label="Seleccionar INV-2024-0244"></td>
<td><strong>INV-2024-0244</strong></td>
<td>HP LaserJet Pro M404dn</td>
<td><span class="badge badge-printer">Impresora</span></td>
<td>HP / LaserJet Pro M404dn</td>
<td>Planta 1, Reprografía</td>
<td><span class="badge badge-maintenance">Mantenimiento</span></td>
<td>
<div class="row-actions">
<button class="row-action" title="Ver detalle"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg></button>
<button class="row-action" title="Editar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg></button>
<button class="row-action" title="Dar de baja" style="color: #dc2626;"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg></button>
</div>
</td>
</tr>
<tr>
<td><input type="checkbox" class="checkbox" aria-label="Seleccionar INV-2024-0243"></td>
<td><strong>INV-2024-0243</strong></td>
<td>Cisco Catalyst 2960 — Switch Planta 1</td>
<td><span class="badge badge-network">Red</span></td>
<td>Cisco / Catalyst 2960-24TC-L</td>
<td>Planta 1, Cuarto Redes</td>
<td><span class="badge badge-active">Activo</span></td>
<td>
<div class="row-actions">
<button class="row-action" title="Ver detalle"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg></button>
<button class="row-action" title="Editar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg></button>
<button class="row-action" title="Dar de baja" style="color: #dc2626;"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg></button>
</div>
</td>
</tr>
<tr>
<td><input type="checkbox" class="checkbox" aria-label="Seleccionar INV-2024-0242"></td>
<td><strong>INV-2024-0242</strong></td>
<td>Dell OptiPlex 7090 — Recepción</td>
<td><span class="badge badge-computer">Sobremesa</span></td>
<td>Dell / OptiPlex 7090</td>
<td>Planta 0, Recepción</td>
<td><span class="badge badge-active">Activo</span></td>
<td>
<div class="row-actions">
<button class="row-action" title="Ver detalle"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg></button>
<button class="row-action" title="Editar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg></button>
<button class="row-action" title="Dar de baja" style="color: #dc2626;"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg></button>
</div>
</td>
</tr>
</tbody>
</table>
<!-- Pagination -->
<div class="pagination">
<div class="pagination-info">Mostrando 1-20 de 247 dispositivos</div>
<div class="pagination-controls">
<button class="page-btn" aria-label="Página anterior"></button>
<button class="page-btn active" aria-current="page">1</button>
<button class="page-btn">2</button>
<button class="page-btn">3</button>
<button class="page-btn"></button>
<button class="page-btn">13</button>
<button class="page-btn" aria-label="Página siguiente"></button>
</div>
</div>
</div>
</div>
</main>
</body>
</html>

View file

@ -0,0 +1,19 @@
# Variant: Formulario — Configure Surface
## Design stance
Progressive disclosure through logical sections: identification, device info,
purchase, assignment, notes. Required fields marked clearly, inline validation.
## Key choices
- **Layout:** Single-column form card, 2-column grid within sections
- **Typography:** Clear section headers, field labels with required markers
- **Color:** Minimal — white card on light gray background, red for required/errors
- **Interaction:** Real-time validation, "Save and Add Another" for batch entry
## Trade-offs
- Strong at: Clear data entry flow, reduced errors, batch-friendly
- Weak at: Long form on small screens (needs responsive stacking)
## Best for
Staff entering new devices — the form guides them through required fields
and offers shortcuts for batch entry.

View file

@ -0,0 +1,351 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Inventschario — Agregar Dispositivo</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 {
width: 240px; background: #fff; 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; }
.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 { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
.topbar {
background: #fff; 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; }
.btn-ghost { border: none; background: transparent; color: #666; }
.btn-ghost:hover { color: #1a1a1a; background: #f0f0ee; }
.content { padding: 32px; overflow-y: auto; flex: 1; max-width: 800px; }
/* Form */
.form-card {
background: #fff; border: 1px solid #e5e5e3; border-radius: 8px;
overflow: hidden;
}
.form-header {
padding: 20px 24px; border-bottom: 1px solid #e5e5e3;
}
.form-header h3 { font-size: 15px; font-weight: 600; }
.form-header p { font-size: 13px; color: #666; margin-top: 4px; }
.form-body { padding: 24px; }
.form-section {
margin-bottom: 28px;
}
.form-section:last-child { margin-bottom: 0; }
.form-section-title {
font-size: 12px; font-weight: 600; color: #999; text-transform: uppercase;
letter-spacing: 0.5px; margin-bottom: 16px; padding-bottom: 8px;
border-bottom: 1px solid #f0f0ee;
}
.form-grid {
display: grid; grid-template-columns: 1fr 1fr; gap: 16px;
}
.form-grid .full-width { grid-column: 1 / -1; }
.form-group { display: flex; flex-direction: column; gap: 4px; }
.form-label {
font-size: 13px; font-weight: 500; color: #1a1a1a;
}
.form-label .required { color: #dc2626; margin-left: 2px; }
.form-hint { font-size: 11px; color: #999; }
.form-input, .form-select, .form-textarea {
padding: 8px 12px; border: 1px solid #e5e5e3; border-radius: 6px;
font-size: 13px; font-family: inherit; background: #fff; color: #1a1a1a;
transition: border-color 0.15s;
}
.form-input:focus, .form-select:focus, .form-textarea:focus {
outline: none; border-color: #1a1a1a; box-shadow: 0 0 0 1px #1a1a1a;
}
.form-input.error { border-color: #dc2626; }
.form-error { font-size: 11px; color: #dc2626; margin-top: 2px; }
.form-textarea { resize: vertical; min-height: 80px; }
.form-select { cursor: pointer; }
/* Required fields note */
.required-note {
font-size: 12px; color: #999; margin-bottom: 20px;
}
.required-note .required { color: #dc2626; }
/* Form footer */
.form-footer {
padding: 16px 24px; border-top: 1px solid #e5e5e3;
display: flex; justify-content: space-between; align-items: center;
background: #fafafa;
}
.form-footer-info { font-size: 12px; color: #999; }
.form-footer-actions { display: flex; gap: 8px; }
/* Success toast */
.toast {
position: fixed; bottom: 24px; right: 24px; background: #166534;
color: #fff; padding: 12px 20px; border-radius: 8px; font-size: 13px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15); display: flex; align-items: center;
gap: 8px; z-index: 100;
}
.toast-icon { font-size: 16px; }
*: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" href="#dashboard">
<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 active" href="#add" aria-current="page">
<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-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9c.26.604.852.997 1.51 1H21a2 2 0 010 4h-.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">
<div style="display: flex; align-items: center; gap: 12px;">
<a href="#inventory" class="btn-ghost" style="padding: 4px; border: none; background: none; cursor: pointer; color: #666; text-decoration: none;" aria-label="Volver al inventario">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg>
</a>
<h2>Agregar Dispositivo</h2>
</div>
<div class="topbar-actions">
<button class="btn">Cancelar</button>
<button class="btn btn-primary">Guardar Dispositivo</button>
</div>
</header>
<div class="content">
<p class="required-note">Los campos marcados con <span class="required">*</span> son obligatorios.</p>
<form class="form-card" aria-label="Formulario de nuevo dispositivo">
<!-- Identification -->
<div class="form-section" style="padding: 24px; padding-bottom: 0;">
<div class="form-section-title">Identificación</div>
<div class="form-grid">
<div class="form-group">
<label class="form-label" for="catalog_number">Número de Catálogo Interno <span class="required">*</span></label>
<input class="form-input" type="text" id="catalog_number" placeholder="INV-2024-0248" required aria-required="true">
<span class="form-hint">Se genera automáticamente si se deja vacío</span>
</div>
<div class="form-group">
<label class="form-label" for="serial_number">Número de Serie <span class="required">*</span></label>
<input class="form-input" type="text" id="serial_number" placeholder="C02X1234JHD5" required aria-required="true">
</div>
<div class="form-group">
<label class="form-label" for="service_tag">Service Tag</label>
<input class="form-input" type="text" id="service_tag" placeholder="ABC1234">
<span class="form-hint">Número de servicio del fabricante</span>
</div>
<div class="form-group">
<label class="form-label" for="additional_reg">Registro Adicional</label>
<input class="form-input" type="text" id="additional_reg" placeholder="Cualquier otro número de registro">
</div>
</div>
</div>
<!-- Device info -->
<div class="form-section" style="padding: 24px; padding-bottom: 0;">
<div class="form-section-title">Información del Dispositivo</div>
<div class="form-grid">
<div class="form-group full-width">
<label class="form-label" for="device_name">Nombre / Descripción <span class="required">*</span></label>
<input class="form-input" type="text" id="device_name" placeholder="MacBook Pro 14" Oficina Dirección" required aria-required="true">
</div>
<div class="form-group">
<label class="form-label" for="device_type">Tipo de Dispositivo <span class="required">*</span></label>
<select class="form-select" id="device_type" required aria-required="true">
<option value="">Seleccionar tipo...</option>
<option>Ordenador de sobremesa</option>
<option selected>Portátil</option>
<option>Monitor / Pantalla</option>
<option>Impresora</option>
<option>Escáner</option>
<option>Dispositivo de red</option>
<option>Periférico</option>
<option>Servidor</option>
<option>SAI / Regulador</option>
<option>Almacenamiento externo</option>
<option>Otro</option>
</select>
</div>
<div class="form-group">
<label class="form-label" for="brand">Marca</label>
<input class="form-input" type="text" id="brand" placeholder="Apple">
</div>
<div class="form-group">
<label class="form-label" for="model">Modelo</label>
<input class="form-input" type="text" id="model" placeholder="MacBook Pro M3">
</div>
<div class="form-group">
<label class="form-label" for="serial_internal">N.º Serie Interno</label>
<input class="form-input" type="text" id="serial_internal" placeholder="Número interno de control">
</div>
<div class="form-group">
<label class="form-label" for="condition">Estado Físico</label>
<select class="form-select" id="condition">
<option value="excellent">Excelente</option>
<option value="good" selected>Bueno</option>
<option value="fair">Regular</option>
<option value="poor">Malo</option>
<option value="damaged">Dañado</option>
</select>
</div>
<div class="form-group">
<label class="form-label" for="status">Estado</label>
<select class="form-select" id="status">
<option value="active" selected>Activo</option>
<option value="available">Disponible</option>
<option value="reserved">Reservado</option>
</select>
</div>
</div>
</div>
<!-- Purchase info -->
<div class="form-section" style="padding: 24px; padding-bottom: 0;">
<div class="form-section-title">Compra y Garantía</div>
<div class="form-grid">
<div class="form-group">
<label class="form-label" for="purchase_date">Fecha de Compra</label>
<input class="form-input" type="date" id="purchase_date">
</div>
<div class="form-group">
<label class="form-label" for="warranty_expiry">Fin de Garantía</label>
<input class="form-input" type="date" id="warranty_expiry">
</div>
<div class="form-group">
<label class="form-label" for="purchase_price">Precio de Compra (€)</label>
<input class="form-input" type="number" id="purchase_price" placeholder="0.00" step="0.01" min="0">
</div>
</div>
</div>
<!-- Assignment -->
<div class="form-section" style="padding: 24px; padding-bottom: 0;">
<div class="form-section-title">Asignación</div>
<div class="form-grid">
<div class="form-group">
<label class="form-label" for="location">Ubicación Asignada</label>
<select class="form-select" id="location">
<option value="">Seleccionar ubicación...</option>
<option>Planta 0 — Recepción</option>
<option>Planta 1 — Open Space</option>
<option>Planta 1 — Reprografía</option>
<option>Planta 1 — Cuarto Redes</option>
<option>Planta 2 — Desp. Dirección</option>
<option>Almacén</option>
</select>
</div>
<div class="form-group">
<label class="form-label" for="assigned_user">Usuario Asignado</label>
<input class="form-input" type="text" id="assigned_user" placeholder="Nombre del usuario">
</div>
<div class="form-group">
<label class="form-label" for="department">Departamento</label>
<select class="form-select" id="department">
<option value="">Seleccionar departamento...</option>
<option>Informática</option>
<option>Administración</option>
<option>Recursos Humanos</option>
<option>Contabilidad</option>
<option>Dirección</option>
</select>
</div>
</div>
</div>
<!-- Notes -->
<div class="form-section" style="padding: 24px;">
<div class="form-section-title">Notas</div>
<div class="form-grid">
<div class="form-group full-width">
<label class="form-label" for="notes">Observaciones</label>
<textarea class="form-textarea" id="notes" placeholder="Notas adicionales sobre el dispositivo..." rows="3"></textarea>
</div>
</div>
</div>
<!-- Footer -->
<div class="form-footer">
<span class="form-footer-info">Los cambios se guardan localmente</span>
<div class="form-footer-actions">
<button type="button" class="btn">Cancelar</button>
<button type="button" class="btn" style="border-color: #e5e5e3;">Guardar y Agregar Otro</button>
<button type="submit" class="btn btn-primary">Guardar Dispositivo</button>
</div>
</div>
</form>
</div>
</main>
<!-- Toast demo -->
<div class="toast" role="alert" aria-live="polite">
<span class="toast-icon" aria-hidden="true"></span>
Dispositivo INV-2024-0247 guardado correctamente
</div>
</body>
</html>

View file

@ -0,0 +1,20 @@
# Variant: Configuración — Configure Surface
## Design stance
Tabbed settings with inline editing: each section is self-contained, changes
are saved explicitly, and the field label editor shows the internal key alongside
the user-facing label.
## Key choices
- **Layout:** Tabbed navigation, settings sections as cards, inline list editors
- **Typography:** Monospace for field keys, Inter for labels and values
- **Color:** Minimal — toggle switches for boolean settings, danger color for delete
- **Interaction:** Toggle switches, inline add/remove for locations/departments
## Trade-offs
- Strong at: Organized settings, clear field mapping, backup management
- Weak at: Many settings could overwhelm on first visit
## Best for
Initial setup and ongoing configuration — the admin sets up the system once
and revisits occasionally for adjustments.

View file

@ -0,0 +1,496 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Inventschario — Configuración</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 {
width: 240px; background: #fff; 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; }
.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 { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
.topbar {
background: #fff; 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; }
.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; }
.btn-danger { color: #dc2626; border-color: #fca5a5; }
.btn-danger:hover { background: #fef2f2; }
.btn-sm { padding: 4px 10px; font-size: 12px; }
.content { padding: 32px; overflow-y: auto; flex: 1; max-width: 800px; }
/* Settings sections */
.settings-section {
background: #fff; border: 1px solid #e5e5e3; border-radius: 8px;
margin-bottom: 24px; overflow: hidden;
}
.settings-header {
padding: 16px 20px; border-bottom: 1px solid #e5e5e3;
display: flex; align-items: center; justify-content: space-between;
}
.settings-header h3 { font-size: 14px; font-weight: 600; }
.settings-header p { font-size: 12px; color: #999; }
.settings-body { padding: 20px; }
.setting-row {
display: flex; align-items: center; justify-content: space-between;
padding: 12px 0; border-bottom: 1px solid #f0f0ee;
}
.setting-row:last-child { border-bottom: none; }
.setting-info { flex: 1; }
.setting-label { font-size: 13px; font-weight: 500; }
.setting-desc { font-size: 12px; color: #999; margin-top: 2px; }
.setting-control { margin-left: 20px; }
.form-input, .form-select {
padding: 6px 10px; border: 1px solid #e5e5e3; border-radius: 4px;
font-size: 13px; font-family: inherit; background: #fff;
}
.form-input:focus, .form-select:focus {
outline: none; border-color: #1a1a1a; box-shadow: 0 0 0 1px #1a1a1a;
}
/* Toggle switch */
.toggle {
width: 40px; height: 22px; background: #e5e5e3; border-radius: 11px;
position: relative; cursor: pointer; transition: background 0.2s;
border: none; padding: 0;
}
.toggle.active { background: #166534; }
.toggle::after {
content: ''; width: 18px; height: 18px; background: #fff;
border-radius: 50%; position: absolute; top: 2px; left: 2px;
transition: transform 0.2s; box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.toggle.active::after { transform: translateX(18px); }
/* Field labels editor */
.label-editor { margin-top: 8px; }
.label-row {
display: flex; align-items: center; gap: 12px; padding: 8px 0;
border-bottom: 1px solid #f0f0ee;
}
.label-row:last-child { border-bottom: none; }
.label-key {
font-size: 12px; color: #999; font-family: monospace;
min-width: 160px;
}
.label-input {
flex: 1; padding: 6px 10px; border: 1px solid #e5e5e3; border-radius: 4px;
font-size: 13px; font-family: inherit;
}
.label-input:focus { outline: none; border-color: #1a1a1a; box-shadow: 0 0 0 1px #1a1a1a; }
/* Backup list */
.backup-list { margin-top: 12px; }
.backup-item {
display: flex; align-items: center; justify-content: space-between;
padding: 10px 12px; border: 1px solid #f0f0ee; border-radius: 6px;
margin-bottom: 8px; font-size: 13px;
}
.backup-info { display: flex; align-items: center; gap: 12px; }
.backup-icon { font-size: 16px; }
.backup-name { font-weight: 500; }
.backup-meta { font-size: 11px; color: #999; }
.backup-actions { display: flex; gap: 4px; }
/* Tabs */
.tabs {
display: flex; gap: 0; border-bottom: 1px solid #e5e5e3; margin-bottom: 20px;
}
.tab {
padding: 10px 16px; font-size: 13px; font-weight: 500; color: #666;
cursor: pointer; border-bottom: 2px solid transparent; transition: all 0.15s;
background: none; border-top: none; border-left: none; border-right: none;
font-family: inherit;
}
.tab:hover { color: #1a1a1a; }
.tab.active { color: #1a1a1a; border-bottom-color: #1a1a1a; }
*: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" href="#dashboard">
<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 active" href="#settings" aria-current="page">
<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-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9c.26.604.852.997 1.51 1H21a2 2 0 010 4h-.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>Configuración</h2>
<div class="topbar-actions">
<button class="btn btn-primary">Guardar Cambios</button>
</div>
</header>
<div class="content">
<!-- Tabs -->
<div class="tabs" role="tablist">
<button class="tab active" role="tab" aria-selected="true">General</button>
<button class="tab" role="tab">Campos</button>
<button class="tab" role="tab">Copias de Seguridad</button>
<button class="tab" role="tab">Importar / Exportar</button>
</div>
<!-- General Settings -->
<div class="settings-section">
<div class="settings-header">
<div>
<h3>Información General</h3>
<p>Datos de la institución y configuración básica</p>
</div>
</div>
<div class="settings-body">
<div class="setting-row">
<div class="setting-info">
<div class="setting-label">Nombre de la Institución</div>
<div class="setting-desc">Aparece en el encabezado de exportaciones e informes</div>
</div>
<div class="setting-control">
<input class="form-input" type="text" value="Ayuntamiento de Ejemplo" style="width: 280px;">
</div>
</div>
<div class="setting-row">
<div class="setting-info">
<div class="setting-label">Prefijo de Número de Catálogo</div>
<div class="setting-desc">Prefijo para la generación automática de números de inventario</div>
</div>
<div class="setting-control">
<input class="form-input" type="text" value="INV-" style="width: 120px;">
</div>
</div>
<div class="setting-row">
<div class="setting-info">
<div class="setting-label">Separador CSV por Defecto</div>
<div class="setting-desc">Separador utilizado al exportar e importar archivos CSV</div>
</div>
<div class="setting-control">
<select class="form-select">
<option value=";">Punto y coma (;)</option>
<option value=",">Coma (,)</option>
<option value="\t">Tabulador</option>
</select>
</div>
</div>
</div>
</div>
<!-- Field Labels -->
<div class="settings-section">
<div class="settings-header">
<div>
<h3>Etiquetas de Campos</h3>
<p>Personaliza los nombres que aparecen en la interfaz. El nombre interno en la base de datos no cambia.</p>
</div>
</div>
<div class="settings-body">
<div class="label-editor">
<div class="label-row">
<span class="label-key">serial_number</span>
<input class="label-input" type="text" value="Número de Serie">
</div>
<div class="label-row">
<span class="label-key">service_tag</span>
<input class="label-input" type="text" value="Service Tag">
</div>
<div class="label-row">
<span class="label-key">catalog_number</span>
<input class="label-input" type="text" value="Número de Catálogo Interno">
</div>
<div class="label-row">
<span class="label-key">additional_registry</span>
<input class="label-input" type="text" value="Registro Adicional">
</div>
<div class="label-row">
<span class="label-key">device_name</span>
<input class="label-input" type="text" value="Nombre / Descripción">
</div>
<div class="label-row">
<span class="label-key">device_type</span>
<input class="label-input" type="text" value="Tipo de Dispositivo">
</div>
<div class="label-row">
<span class="label-key">brand</span>
<input class="label-input" type="text" value="Marca">
</div>
<div class="label-row">
<span class="label-key">model</span>
<input class="label-input" type="text" value="Modelo">
</div>
<div class="label-row">
<span class="label-key">purchase_date</span>
<input class="label-input" type="text" value="Fecha de Compra">
</div>
<div class="label-row">
<span class="label-key">warranty_expiry</span>
<input class="label-input" type="text" value="Fin de Garantía">
</div>
<div class="label-row">
<span class="label-key">purchase_price</span>
<input class="label-input" type="text" value="Precio de Compra (€)">
</div>
<div class="label-row">
<span class="label-key">assigned_location</span>
<input class="label-input" type="text" value="Ubicación Asignada">
</div>
<div class="label-row">
<span class="label-key">assigned_user</span>
<input class="label-input" type="text" value="Usuario Asignado">
</div>
<div class="label-row">
<span class="label-key">department</span>
<input class="label-input" type="text" value="Departamento">
</div>
<div class="label-row">
<span class="label-key">status</span>
<input class="label-input" type="text" value="Estado">
</div>
<div class="label-row">
<span class="label-key">condition</span>
<input class="label-input" type="text" value="Estado Físico">
</div>
</div>
</div>
</div>
<!-- Backup Settings -->
<div class="settings-section">
<div class="settings-header">
<div>
<h3>Copias de Seguridad</h3>
<p>Configuración del backup automático y gestión de copias</p>
</div>
</div>
<div class="settings-body">
<div class="setting-row">
<div class="setting-info">
<div class="setting-label">Backup Automático</div>
<div class="setting-desc">Crear una copia de seguridad de la base de datos cada día</div>
</div>
<div class="setting-control">
<button class="toggle active" role="switch" aria-checked="true" aria-label="Activar backup automático"></button>
</div>
</div>
<div class="setting-row">
<div class="setting-info">
<div class="setting-label">Hora del Backup</div>
<div class="setting-desc">Hora a la que se ejecuta el backup diario</div>
</div>
<div class="setting-control">
<input class="form-input" type="time" value="02:00">
</div>
</div>
<div class="setting-row">
<div class="setting-info">
<div class="setting-label">Días de Retención</div>
<div class="setting-desc">Número de días antes de sugerir la eliminación de backups antiguos</div>
</div>
<div class="setting-control">
<input class="form-input" type="number" value="30" min="7" max="365" style="width: 80px;">
<span style="font-size: 12px; color: #999; margin-left: 4px;">días</span>
</div>
</div>
<div class="setting-row">
<div class="setting-info">
<div class="setting-label">Máximo de Backups</div>
<div class="setting-desc">Número máximo de copias de seguridad a conservar</div>
</div>
<div class="setting-control">
<input class="form-input" type="number" value="90" min="10" max="365" style="width: 80px;">
</div>
</div>
<!-- Recent backups -->
<div style="margin-top: 20px; padding-top: 16px; border-top: 1px solid #e5e5e3;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;">
<span style="font-size: 13px; font-weight: 500;">Copias Recientes</span>
<button class="btn btn-sm">Crear Backup Manual</button>
</div>
<div class="backup-list">
<div class="backup-item">
<div class="backup-info">
<span class="backup-icon" aria-hidden="true">💾</span>
<div>
<div class="backup-name">inventschario_20260803_020000.db.gz</div>
<div class="backup-meta">3 de agosto 2026, 02:00 — 2.4 MB — Automático</div>
</div>
</div>
<div class="backup-actions">
<button class="btn btn-sm" aria-label="Restaurar este backup">Restaurar</button>
<button class="btn btn-sm btn-danger" aria-label="Eliminar este backup">Eliminar</button>
</div>
</div>
<div class="backup-item">
<div class="backup-info">
<span class="backup-icon" aria-hidden="true">💾</span>
<div>
<div class="backup-name">inventschario_20260802_020000.db.gz</div>
<div class="backup-meta">2 de agosto 2026, 02:00 — 2.3 MB — Automático</div>
</div>
</div>
<div class="backup-actions">
<button class="btn btn-sm">Restaurar</button>
<button class="btn btn-sm btn-danger">Eliminar</button>
</div>
</div>
<div class="backup-item">
<div class="backup-info">
<span class="backup-icon" aria-hidden="true">💾</span>
<div>
<div class="backup-name">inventschario_20260801_143022.db.gz</div>
<div class="backup-meta">1 de agosto 2026, 14:30 — 2.3 MB — <strong style="color: #92400e;">Manual</strong></div>
</div>
</div>
<div class="backup-actions">
<button class="btn btn-sm">Restaurar</button>
<button class="btn btn-sm btn-danger">Eliminar</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Locations & Departments -->
<div class="settings-section">
<div class="settings-header">
<div>
<h3>Ubicaciones y Departamentos</h3>
<p>Gestiona las ubicaciones físicas y departamentos de la institución</p>
</div>
</div>
<div class="settings-body">
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 24px;">
<!-- Locations -->
<div>
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;">
<span style="font-size: 13px; font-weight: 500;">Ubicaciones</span>
<button class="btn btn-sm">+ Añadir</button>
</div>
<div style="border: 1px solid #e5e5e3; border-radius: 6px; overflow: hidden;">
<div style="padding: 8px 12px; border-bottom: 1px solid #f0f0ee; font-size: 13px; display: flex; justify-content: space-between;">
<span>Planta 0 — Recepción</span>
<button class="btn btn-sm btn-danger" style="padding: 2px 6px; font-size: 11px;">×</button>
</div>
<div style="padding: 8px 12px; border-bottom: 1px solid #f0f0ee; font-size: 13px; display: flex; justify-content: space-between;">
<span>Planta 1 — Open Space</span>
<button class="btn btn-sm btn-danger" style="padding: 2px 6px; font-size: 11px;">×</button>
</div>
<div style="padding: 8px 12px; border-bottom: 1px solid #f0f0ee; font-size: 13px; display: flex; justify-content: space-between;">
<span>Planta 1 — Reprografía</span>
<button class="btn btn-sm btn-danger" style="padding: 2px 6px; font-size: 11px;">×</button>
</div>
<div style="padding: 8px 12px; border-bottom: 1px solid #f0f0ee; font-size: 13px; display: flex; justify-content: space-between;">
<span>Planta 2 — Desp. Dirección</span>
<button class="btn btn-sm btn-danger" style="padding: 2px 6px; font-size: 11px;">×</button>
</div>
<div style="padding: 8px 12px; font-size: 13px; display: flex; justify-content: space-between;">
<span>Almacén</span>
<button class="btn btn-sm btn-danger" style="padding: 2px 6px; font-size: 11px;">×</button>
</div>
</div>
</div>
<!-- Departments -->
<div>
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;">
<span style="font-size: 13px; font-weight: 500;">Departamentos</span>
<button class="btn btn-sm">+ Añadir</button>
</div>
<div style="border: 1px solid #e5e5e3; border-radius: 6px; overflow: hidden;">
<div style="padding: 8px 12px; border-bottom: 1px solid #f0f0ee; font-size: 13px; display: flex; justify-content: space-between;">
<span>Informática</span>
<button class="btn btn-sm btn-danger" style="padding: 2px 6px; font-size: 11px;">×</button>
</div>
<div style="padding: 8px 12px; border-bottom: 1px solid #f0f0ee; font-size: 13px; display: flex; justify-content: space-between;">
<span>Administración</span>
<button class="btn btn-sm btn-danger" style="padding: 2px 6px; font-size: 11px;">×</button>
</div>
<div style="padding: 8px 12px; border-bottom: 1px solid #f0f0ee; font-size: 13px; display: flex; justify-content: space-between;">
<span>Recursos Humanos</span>
<button class="btn btn-sm btn-danger" style="padding: 2px 6px; font-size: 11px;">×</button>
</div>
<div style="padding: 8px 12px; border-bottom: 1px solid #f0f0ee; font-size: 13px; display: flex; justify-content: space-between;">
<span>Contabilidad</span>
<button class="btn btn-sm btn-danger" style="padding: 2px 6px; font-size: 11px;">×</button>
</div>
<div style="padding: 8px 12px; font-size: 13px; display: flex; justify-content: space-between;">
<span>Dirección</span>
<button class="btn btn-sm btn-danger" style="padding: 2px 6px; font-size: 11px;">×</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</body>
</html>