Contenido del bloque. Stat compacto, KPI o badge.
BentoCard
Card individual del layout bento. Hija de BentoGrid (CSS Grid). Cierra el círculo con v0.8.0 consumiendo useIntersectionObserver para entry animation con semántica triggerOnce. Respeta prefers-reduced-motion vía CSS @media.
Demo
Contenido del bloque. Section secundaria.
Contenido del bloque. Project showcase, gallery.
Contenido del bloque. Hero, About largo, o feature destacada.
Pulsa Reset grid para volver a montar las cards y ver la entry animation desde cero. Activa el toggle keyboardHint para ver los badges Alt+N en cada esquina.
Uso
<script>
import { BentoGrid, BentoCard } from '@codigosinsiesta/theme/layout';
</script>
<BentoGrid cols={12} gap="20px" dense>
<BentoCard size="xl" ariaLabel="Hero" id="hero" keyboardHint="Alt+1">
<h1>Technical Leader Specialist</h1>
<p>Bio del autor...</p>
</BentoCard>
<BentoCard size="md" ariaLabel="Stats">
<span class="big-number">42</span>
</BentoCard>
</BentoGrid> Tamaños
Cada size mapea a un span de grid (asumiendo BentoGrid con 12 cols):
| size | grid-column | grid-row | Uso típico |
|---|---|---|---|
sm | span 3 | span 1 | Stat compacto, KPI, badge. |
md | span 4 | span 1 | Section secundaria, callout. |
lg | span 6 | span 2 | Project showcase, gallery. |
xl | span 8 | span 2 | Hero, feature destacada, about largo. |
Responsive cascade: a ≤ 768px las cards lg/xl bajan a span 4 × 1; sm/md a span 2. A ≤ 480px todas ocupan el ancho completo del grid colapsado (span 2). Coordinado con los breakpoints de BentoGrid (12 → 4 → 2 cols).
Entry animation
Con entryAnimation={true} (default), la card empieza con opacity: 0 + translateY(20px) y transiciona a opacity: 1 + none en 600ms cuando entra en viewport. La detección usa useIntersectionObserver con threshold: 0.2 y triggerOnce: true — tras la primera intersección, el observer se desconecta.
Reduced motion: si el usuario tiene prefers-reduced-motion: reduce activo, una @media rule del CSS fuerza opacity: 1 + transition: none. La card aparece sin animar. El composable sigue corriendo pero su efecto visual queda neutralizado — diseño deliberado para no requerir lógica JS extra.
Accesibilidad
ariaLabelobligatorio: cada card es un landmark<article>. El label da contexto a screen readers cuando navegan por landmarks.keyboardHintrenderiza un<kbd>visible. Es solo decorativo (aria-hidden); el atajo real lo registra el consumer conuseKeyboardNavapuntando alidde la card.- Entry animation: respeta
prefers-reduced-motionsin código extra (CSS-only).
API
| Prop | Tipo | Default | Descripción |
|---|---|---|---|
size | 'sm' | 'md' | 'lg' | 'xl' | 'md' | Mapea a grid-column/grid-row span. |
ariaLabel | string | — | Obligatorio. Label del landmark <article>. |
keyboardHint | string | '' | Texto del badge <kbd>. Si vacío, no se renderiza. |
entryAnimation | boolean | true | Activa la entry animation on-viewport. |
id | string | '' | id HTML para coordinar con useKeyboardNav (ej. scrollTo('#hero')). |
children | Snippet | — | Contenido de la card. |
Casos de uso
- Portfolio CsS: cada bloque del bento (Hero, About, Skills, Projects, Contact...) con sizes mixtos.
- Landings de talleres: feature cards en grid asimétrico.
- Dashboards: KPI cards individuales con entry animation al scroll.