Rediseño impeccable: brand mark, páginas 403/404, DESIGN.md + PRODUCT.md

Rediseño hecho en sesión aparte con el skill impeccable. Se registran
las especificaciones y ajustes visuales al sistema ya en producción.

Añade:
- BrandMark.astro con el escudo/logo del laboratorio.
- Favicon actualizado (svg + ico).
- Páginas propias 403 y 404 consistentes con el sistema visual.
- DESIGN.md y PRODUCT.md documentando decisiones.
- .impeccable/design.json con el design system tokenizado.

Ajusta componentes existentes (modales, autocomplete, layout, login,
solicitudes, mis-préstamos, middleware) para alinearse a los tokens
del design system.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-08-16 15:19:57 -07:00
parent 927d99c262
commit 57b07b9b82
20 changed files with 596 additions and 27 deletions
+18
View File
@@ -0,0 +1,18 @@
---
import Layout from '@/layouts/Layout.astro';
import BrandMark from '@/components/BrandMark.astro';
Astro.response.status = 403;
---
<Layout title="Acceso denegado — LabPréstamos">
<main id="main" class="min-h-screen grid place-items-center p-4">
<div class="w-full max-w-md text-center">
<div class="inline-grid place-items-center w-16 h-16 rounded-2xl mb-4 p-4" style="background: color-mix(in oklab, var(--color-danger) 12%, transparent);">
<BrandMark class="w-full h-full" style="color: var(--color-danger);" />
</div>
<h1 class="text-2xl font-semibold">Acceso denegado</h1>
<p class="text-sm opacity-70 mt-2">Esta sección es solo para administradores del laboratorio.</p>
<a href="/" class="btn btn-primary mt-6 inline-flex">Volver al inicio</a>
</div>
</main>
</Layout>
+18
View File
@@ -0,0 +1,18 @@
---
import Layout from '@/layouts/Layout.astro';
import BrandMark from '@/components/BrandMark.astro';
Astro.response.status = 404;
---
<Layout title="Página no encontrada — LabPréstamos">
<main id="main" class="min-h-screen grid place-items-center p-4">
<div class="w-full max-w-md text-center">
<div class="inline-grid place-items-center w-16 h-16 rounded-2xl bg-[color:var(--color-primary)] mb-4 p-4">
<BrandMark class="w-full h-full text-white" />
</div>
<h1 class="text-2xl font-semibold">Página no encontrada</h1>
<p class="text-sm opacity-70 mt-2">La dirección no existe o cambió de lugar.</p>
<a href="/" class="btn btn-primary mt-6 inline-flex">Volver al inicio</a>
</div>
</main>
</Layout>
+3 -1
View File
@@ -59,7 +59,9 @@ const tabs = [
{filas.length === 0 ? (
<div class="card text-center py-12">
<div class="text-4xl mb-3" aria-hidden="true">✓</div>
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="var(--color-primary)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="mx-auto mb-3" aria-hidden="true">
<path d="M4.5 12.75l6 6 9-13.5" />
</svg>
<p class="font-medium">No hay solicitudes por revisar.</p>
<p class="text-sm opacity-70 mt-1">Todo al día.</p>
</div>
+5 -4
View File
@@ -129,7 +129,9 @@ const badgeStyle = (e: Estado) =>
<section>
<details open={historial.length <= 5}>
<summary class="text-lg font-semibold cursor-pointer list-none flex items-center gap-2">
<span aria-hidden="true"></span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M9 6l6 6-6 6" />
</svg>
Historial <span class="text-sm opacity-60" style="font-variant-numeric: tabular-nums;">({historial.length})</span>
</summary>
{historial.length === 0 ? (
@@ -174,9 +176,8 @@ const badgeStyle = (e: Estado) =>
<style>
details > summary::-webkit-details-marker { display: none; }
details[open] > summary > span[aria-hidden] { transform: rotate(90deg); }
details > summary > span[aria-hidden] {
display: inline-block;
details[open] > summary > svg { transform: rotate(90deg); }
details > summary > svg {
transition: transform 150ms ease-out;
}
</style>
+4 -1
View File
@@ -1,5 +1,6 @@
---
import Layout from '@/layouts/Layout.astro';
import BrandMark from '@/components/BrandMark.astro';
const url = Astro.url;
const errorParam = url.searchParams.get('error');
@@ -15,7 +16,9 @@ const googleAuthUrl = '/api/auth/signin';
<main id="main" class="min-h-screen grid place-items-center p-4">
<div class="w-full max-w-md">
<div class="text-center mb-8">
<div class="inline-grid place-items-center w-16 h-16 rounded-2xl bg-[color:var(--color-primary)] text-white font-bold text-3xl mb-4 motion-safe:animate-[fadein_.4s_ease-out]">L</div>
<div class="inline-grid place-items-center w-16 h-16 rounded-2xl bg-[color:var(--color-primary)] p-4 mb-4 motion-safe:animate-[fadein_.4s_ease-out]">
<BrandMark class="w-full h-full text-white" />
</div>
<h1 class="text-2xl md:text-3xl font-semibold">Sistema de Préstamos</h1>
<p class="text-sm mt-2 opacity-70">Laboratorio de Sistemas Computacionales · UABC</p>
</div>