Files
yt-channel-scraper/docs/superpowers/specs/2026-08-22-videos-grid-view-design.md
T

105 lines
4.8 KiB
Markdown

# Diseño: vista de grid estilo YouTube para la sección Vídeos
Fecha: 2026-08-22
Estado: aprobado en conversación
## Problema
La sección Vídeos solo tiene visualización de tabla. Para navegar el catálogo
visualmente (miniaturas grandes, explorar por canal/tema) falta una vista tipo
YouTube: grid de tarjetas con miniatura 16:9, duración y metadatos compactos.
## Objetivo
Añadir un conmutador tabla ⇄ grid en la sección Vídeos. El grid replica el
look de YouTube (tarjetas 16:9) manteniendo toda la funcionalidad existente:
filtros, orden, selección masiva ("Download .md" / "Audio") y paginación.
## Decisiones tomadas en conversación
| Pregunta | Decisión |
|---|---|
| ¿Selección masiva en grid? | Sí, checkboxes como en la tabla; la barra masiva se comparte |
| ¿"Square" literal o estilo YouTube? | Miniatura 16:9 estilo YouTube (no recorte 1:1) |
| ¿Vista inicial y persistencia? | Tabla por defecto; la elección se recuerda en `localStorage` |
| ¿Estructura en index.html? | Dos bloques hermanos alternados con `x-if`; filtros/barra/paginación compartidos |
## Cambios
### 1. Estado y persistencia (`static/app.js`)
- Nuevo campo en el store de `videos`: `view`, valores `'table' | 'grid'`,
default `'table'`.
- En `init()`: leer `localStorage["videos-view"]` y aceptarlo solo si es
`'table'` o `'grid'` (mismo patrón defensivo que `videos-size`).
- Método `setVideoView(v)`: asigna y guarda en `localStorage`. No toca
`syncURL`/`hydrateURL`: es preferencia de UI como `videos-size`, no estado
navegable.
### 2. Conmutador de vista (`index.html`)
- Control segmentado de dos botones icono (lista / grid) alineado a la
derecha, en una fila fina inmediatamente encima del contenedor de
resultados.
- Una sola instancia visible en ambas vistas: fuera del `<thead>` de la
tabla a propósito, porque el grid no tiene cabecera donde colgarlo.
- Botón activo con `accent-grad btn-primary`, el mismo tratamiento que usa el
número de página activo en la paginación; aria-pressed en cada botón.
### 3. Tarjetas del grid (`index.html`)
- Contenedor: `grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 2xl:grid-cols-5 gap-4`.
- Tarjeta: bloque `glass` redondeado, cursor-pointer, hover con borde rose
(mismo lenguaje que las tarjetas de canales). Click → `openVideo(id)`;
clase `row-selected` si está seleccionada.
- Miniatura: `/api/thumbnails/{id}`, `aspect-video w-full object-cover`,
esquinas superiores redondeadas, mismo `onerror="this.style.visibility='hidden'"`
que la tabla.
- Badge de duración abajo-derecha sobre la miniatura: `ts(v.duration)`,
font-mono text-xs, fondo negro semitransparente.
- Checkbox de selección arriba-izquierda sobre la miniatura: aparece al
hover de la tarjeta o permanece visible si está seleccionada; click con
`.stop` → `toggleSelect(id)`.
- Cuerpo:
- Título con clamp a 2 líneas (`line-clamp-2`), text-zinc-100.
- Línea de metadatos: `chanName(channel_id)` · `fmtNum(view_count)` vistas ·
`videoDate(v)` (con `~` si estimada; tooltip `videoDateTitle(v)`).
- Pills de estado y candado de bloqueo idénticos a los de la tabla
(`statusClass`, `isBlocked`, `blockLabel`, `blockTitle`).
### 4. Comportamiento compartido (sin cambios)
- Filtros, barra masiva, paginación y select de orden: intactos, aplican a
ambas vistas.
- Estados loading/vacío duplicados dentro del bloque del grid con los mismos
mensajes ("loading…", "No videos match these filters.", "Clear filters").
- Las acciones por vídeo `.md`/`Process`/`Clip` **no** se duplican en las
tarjetas: quedan en la tabla y en la vista de detalle (look limpio tipo
YouTube; un click abre el detalle que las tiene todas).
## Errores cubiertos
| Caso | Comportamiento |
|---|---|
| Miniatura ausente | `onerror` oculta el `<img>`; la tarjeta conserva proporción por el contenedor aspect-video |
| Valor inválido/corrupto en localStorage | Se ignora y cae a `'table'` |
| Selección activa + cambio de vista | `videos.selected` no se toca; la barra masiva sigue funcionando en ambas |
## Fuera de alcance
- No se toca backend ni endpoints: `/api/videos` ya devuelve todos los campos
que la tarjeta necesita.
- Sin acciones por tarjeta, sin hover-preview de vídeo, sin infinite scroll.
- Sin tests automatizados nuevos: el repo no tiene infra de tests de frontend
(pytest es backend sin red). Verificación manual.
## Verificación manual
Con `start-server.bat`:
1. Alternar tabla ⇄ grid: ambas renderizan los mismos vídeos del filtro activo.
2. Marcar 3 tarjetas → barra masiva aparece → "Download .md" encola el job.
3. Paginar en grid: sin repeticiones ni saltos (mismo desempate que tabla).
4. Recargar la página: la vista elegida se conserva; primera visita → tabla.
5. La tabla existente funciona exactamente igual que antes del cambio.