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
+9
View File
@@ -0,0 +1,9 @@
---
interface Props {
class?: string;
}
const { class: className = '', ...rest } = Astro.props;
---
<svg viewBox="0 0 24 24" class={className} fill="currentColor" fill-rule="evenodd" aria-hidden="true" {...rest}>
<path d="M2 12 L9 4 H16.5 A2.5 2.5 0 0 1 19 6.5 V17.5 A2.5 2.5 0 0 1 16.5 20 H9 Z M7.3 12 a1.3 1.3 0 1 0 -2.6 0 a1.3 1.3 0 1 0 2.6 0 Z" />
</svg>
@@ -53,11 +53,9 @@ export default function EliminarMaterial({ id, nombre, tienePrestamos }: Props)
<>
<button
type="button"
className="btn btn-ghost transition-colors duration-150 hover:!text-white"
className="btn btn-ghost hover:!bg-[color:var(--color-danger)] hover:!text-white"
style={{ minHeight: '36px', paddingBlock: '0.25rem' }}
onClick={open}
onMouseEnter={(e) => (e.currentTarget.style.background = 'var(--color-danger)')}
onMouseLeave={(e) => (e.currentTarget.style.background = 'transparent')}
>
Eliminar
</button>
@@ -143,9 +143,11 @@ export default function MaterialForm({ mode, material, categorias }: Props) {
type="button"
onClick={close}
aria-label="Cerrar"
className="rounded-lg p-1 hover:bg-black/5 transition-colors leading-none text-xl"
className="rounded-lg p-1.5 hover:bg-black/5 transition-colors"
>
<span aria-hidden="true">×</span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden="true">
<path d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
@@ -126,7 +126,9 @@ export function Autocomplete({ name, endpoint, label, placeholder, initialValue,
/>
{(text || value) && (
<button type="button" className="btn btn-ghost px-3" onClick={clear} aria-label="Limpiar">
<span aria-hidden="true">×</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden="true">
<path d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
)}
</div>
@@ -134,7 +136,7 @@ export function Autocomplete({ name, endpoint, label, placeholder, initialValue,
<ul
id={listId}
role="listbox"
className="absolute z-10 mt-1 w-full bg-white rounded-lg shadow-lg max-h-64 overflow-auto"
className="absolute z-10 mt-1 w-full bg-white rounded-lg max-h-64 overflow-auto"
style={{ border: '1px solid color-mix(in oklab, var(--color-ink) 15%, transparent)' }}
>
{loading && items.length === 0 && (
@@ -173,11 +173,8 @@ function RechazarDialog({ prestamo }: { prestamo: Prestamo }) {
<>
<button
type="button"
className="btn btn-ghost"
className="btn btn-ghost hover:!text-[color:var(--color-danger)]"
onClick={dlg.open}
style={{ ['--h' as any]: 'var(--color-danger)' }}
onMouseEnter={(e) => (e.currentTarget.style.color = 'var(--color-danger)')}
onMouseLeave={(e) => (e.currentTarget.style.color = '')}
>
Rechazar
</button>
@@ -55,7 +55,11 @@ export default function VerDetalles({ prestamoId }: { prestamoId: number }) {
<div className="p-6">
<div className="flex items-start justify-between gap-4">
<h2 className="text-lg font-semibold">Detalle del préstamo</h2>
<button type="button" className="btn btn-ghost" onClick={() => ref.current?.close()} aria-label="Cerrar">×</button>
<button type="button" className="rounded-lg p-1.5 hover:bg-black/5 transition-colors" onClick={() => ref.current?.close()} aria-label="Cerrar">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden="true">
<path d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
{loading && <p className="mt-4 text-sm opacity-70">Cargando</p>}
+4 -2
View File
@@ -106,9 +106,11 @@ export default function SolicitarModal({ material }: Props) {
type="button"
onClick={close}
aria-label="Cerrar"
className="rounded-lg p-1 hover:bg-black/5 transition-colors leading-none text-xl"
className="rounded-lg p-1.5 hover:bg-black/5 transition-colors"
>
<span aria-hidden="true">×</span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden="true">
<path d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>