Hero de paneles cromáticos
Hero de tres paneles que expanden su composición al seleccionar, enfocar y tocar; formas geométricas y paleta cálida.
Una buena idea cambia el paisaje.
Diseño que sale de la pantalla y mueve tu próximo proyecto.
Descubrir proyectosColor · composición interactiva de muestra
Código completo
Es exactamente el archivo que se descarga. Cópialo a tu proyecto y úsalo.
"use client";
import { useState, type CSSProperties } from "react";
/** Hero de paneles cromáticos. React + TypeScript, sin dependencias. Personaliza con variables --gcyp-*. */
export type HeroPanelesProps = {
title?: string;
description?: string;
label?: string;
href?: string;
className?: string;
style?: CSSProperties;
};
const CSS = `
.gcyp-root { box-sizing: border-box; min-width: 0; max-width: 100%; color: var(--gcyp-fg, #202421); font: 400 15px/1.5 ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
.gcyp-root *, .gcyp-root *::before, .gcyp-root *::after { box-sizing: border-box; }
.gcyp-root button, .gcyp-root input, .gcyp-root textarea, .gcyp-root select { font: inherit; }
.gcyp-root button, .gcyp-root a { -webkit-tap-highlight-color: transparent; }
.gcyp-root :focus-visible { outline: 2px solid var(--gcyp-accent, #25724b); outline-offset: 4px; }
.gcyp-root ::selection { background: var(--gcyp-accent, #25724b); color: #fff; }
.gcyp-root button:disabled { opacity: .5; cursor: not-allowed; }
.gcyp-root svg { flex-shrink: 0; }
@media (prefers-reduced-motion: reduce) { .gcyp-root *, .gcyp-root *::before, .gcyp-root *::after { animation: none !important; transition-duration: .01ms !important; scroll-behavior: auto !important; } }
.gcyp-root { container-type:inline-size; width:100%; background:var(--gcyp-bg,#f6f0e9); padding:48px clamp(24px,5vw,64px) 28px; }
.gcyp-copy { display:flex; align-items:flex-end; gap:30px; flex-wrap:wrap; margin-bottom:40px; }
.gcyp-copy h2 { font-size:clamp(36px,5vw,60px); letter-spacing:-.035em; line-height:1.08; font-weight:600; max-width:14ch; margin:0; text-wrap:balance; }
.gcyp-copy p { flex:1; min-width:180px; max-width:26ch; font-size:14px; color:#635347; margin:0; }
.gcyp-copy a { display:flex; align-items:center; gap:18px; min-height:44px; color:#302821; text-decoration:none; border-bottom:1px solid #928073; font-size:12px; font-weight:600; }
.gcyp-panels { display:flex; height:260px; gap:10px; }
.gcyp-panel { position:relative; overflow:hidden; flex:1; border:0; border-radius:10px; cursor:pointer; min-width:0; padding:0; transition:flex .6s cubic-bezier(.16,1,.3,1); }
.gcyp-panel[aria-pressed="true"] { flex:2.3; }
.gcyp-panel-0 { background:#bbd0ae; color:#27432b; }
.gcyp-panel-1 { background:#e7a27e; color:#65371f; }
.gcyp-panel-2 { background:#cac2e4; color:#44325f; }
.gcyp-shape { position:absolute; width:200px; height:200px; border:1px solid currentColor; top:30px; left:50%; transform:translateX(-50%) rotate(35deg); transition:transform .6s cubic-bezier(.16,1,.3,1); }
.gcyp-panel-1 .gcyp-shape { border-radius:50%; box-shadow:inset 0 0 0 32px #e7a27e,inset 0 0 0 33px currentColor; }
.gcyp-panel-2 .gcyp-shape { border-radius:100px 100px 0 0; }
.gcyp-panel[aria-pressed="true"] .gcyp-shape { transform:translateX(-50%) rotate(0); }
.gcyp-name { position:absolute; bottom:20px; left:20px; font-size:14px; font-weight:600; }
.gcyp-note { margin:18px 0 0; font-size:11px; color:#6f5b4b; }
@container(max-width:580px) { .gcyp-copy { align-items:flex-start; flex-direction:column; gap:20px; }
.gcyp-copy h2 { font-size:40px; }
.gcyp-panels { height:220px; gap:6px; }
.gcyp-name { left:10px; bottom:15px; font-size:11px; }
.gcyp-shape { width:150px; height:150px; } }`;
export function HeroPaneles({
title = "Una buena idea cambia el paisaje.",
description = "Diseño que sale de la pantalla y mueve tu próximo proyecto.",
label = "Descubrir proyectos",
href = "#proyectos",
className = "",
style,
}: HeroPanelesProps) {
const [selected, setSelected] = useState(1);
const names = ["Forma", "Color", "Movimiento"];
return (
<section className={`gcyp-root ${className}`} style={style}>
<style>{CSS}</style>
<div className="gcyp-copy">
<h2>{title}</h2>
<p>{description}</p>
<a href={href}>
{label}
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1.5"
aria-hidden="true"
>
<path d="M5 12h14m-6-6 6 6-6 6" />
</svg>
</a>
</div>
<div className="gcyp-panels" aria-label="Explorar composiciones">
{names.map((name, i) => (
<button
type="button"
key={name}
aria-pressed={i === selected}
aria-label={`Explorar ${name.toLowerCase()}`}
onClick={() => setSelected(i)}
onPointerEnter={(e) => {
if (e.pointerType === "mouse") setSelected(i);
}}
className={`gcyp-panel gcyp-panel-${i}`}
>
<span className="gcyp-shape" aria-hidden="true" />
<span className="gcyp-name">{name}</span>
</button>
))}
</div>
<p className="gcyp-note" role="status">
{names[selected]} · composición interactiva de muestra
</p>
</section>
);
}
Úsalo en tu proyecto
Instálalo con la CLI de shadcn.
npx shadcn@latest add https://www.gassierconsulting.com/r/hero-panelesEjemplo de uso de Hero de paneles cromáticos
Después de copiar hero-paneles.tsx a tu proyecto, impórtalo y colócalo donde lo necesites.
import { HeroPaneles } from "./hero-paneles";
export default function Ejemplo() {
return <HeroPaneles title="Ejemplo" />;
}Propiedades de HeroPaneles
HeroPaneles acepta 6 propiedades: todas son opcionales y tienen un valor por defecto, así que funciona sin configurar nada.
| Propiedad | Tipo | Descripción |
|---|---|---|
title? | string | Opcional. |
description? | string | Opcional. |
label? | string | Opcional. |
href? | string | Opcional. |
className? | string | Opcional. |
style? | CSSProperties | Opcional. |
Personaliza Hero de paneles cromáticos con variables CSS
Define estas variables en el contenedor o en tu hoja de estilos para cambiar los colores sin tocar el componente. Si no las defines, se usa el valor por defecto.
| Variable | Valor por defecto |
|---|---|
--gcyp-fg | #202421 |
--gcyp-accent | #25724b |
--gcyp-bg | #f6f0e9 |
Accesibilidad y rendimiento
El archivo tiene 103 líneas (5 KB) y no necesita @keyframes. Esto es lo que hace Hero de paneles cromáticos por quien lo usa:
- Detecta prefers-reduced-motion y baja o quita el movimiento cuando la persona lo pide.
- Muestra un anillo de foco visible al navegar con teclado (:focus-visible).
- Declara roles ARIA para lectores de pantalla: status.
- Es un componente de cliente de Next.js: incluye la directiva "use client".