Asymmetric bento with flagship motion cell — click to expand labels on peer cells, blur-dim on inactive (logo-cloud-7 expand-focus DNA).
@nusaiba
registry/blocks/features/11/features-bento-section.tsx
"use client";
import Image from "next/image";
import { useRef, useState } from "react";
import type { LucideIcon } from "lucide-react";
import {
ClipboardCopyIcon,
EyeIcon,
KeyRoundIcon,
SparklesIcon,
SquareTerminalIcon,
} from "lucide-react";
import { motion, useInView, useReducedMotion } from "motion/react";
import { DecorIcon } from "@/components/decor-icon";
import { GridPattern } from "@/components/ui/grid-pattern";
import { defaultSpring, motionStagger, motionViewport } from "@/lib/motion-tokens";
import { cn } from "@/lib/utils";
import { SectionShell, ContentRail } from "@/components/layout-contract";
type CapabilityCell = {
id: string;
title: string;
detail: string;
icon: LucideIcon;
span: string;
featured?: boolean;
stat?: string;
statLabel?: string;
description?: string;
preview?: {
src: string;
alt: string;
tall?: boolean;
};
};
const capabilities: CapabilityCell[] = [
{
id: "motion",
title: "Motion docs",
detail: "patterns · demos · tokens",
icon: SparklesIcon,
span: "col-span-2 row-span-2 md:col-start-1 md:row-start-1",
featured: true,
stat: "40",
statLabel: "live patterns",
description:
"Every block links to spring tokens, triggers, and isolated demos — motion is documented, not guessed.",
},
{
id: "cli",
title: "CLI install",
detail: "npx shadcn add @nusaiba/*",
icon: SquareTerminalIcon,
span: "md:col-start-3 md:row-start-1",
preview: {
src: "/images/visuals/pixel-blast.png",
alt: "Dark stippled field suggesting terminal output",
},
},
{
id: "token",
title: "Registry token",
detail: "Pro auth · private installs",
icon: KeyRoundIcon,
span: "md:col-start-3 md:row-start-2",
preview: {
src: "/images/visuals/dark-veil.png",
alt: "Purple light veil on black",
},
},
{
id: "preview",
title: "Preview live",
detail: "inspect before install",
icon: EyeIcon,
span: "md:col-start-1 md:row-start-3",
preview: {
src: "/images/visuals/light-rays.png",
alt: "Spotlight rays on dark field",
},
},
{
id: "prompt",
title: "Copy prompt",
detail: "AI handoff per block",
icon: ClipboardCopyIcon,
span: "md:col-span-2 md:col-start-2 md:row-start-3",
preview: {
src: "/images/visuals/threads.png",
alt: "Flowing white threads on black",
tall: true,
},
},
];
function CellPreview({
preview,
isFocused,
reduceMotion,
}: {
preview: NonNullable<CapabilityCell["preview"]>;
isFocused: boolean;
reduceMotion: boolean;
}) {
return (
<motion.div
animate={
reduceMotion
? undefined
: { opacity: isFocused ? 1 : 0.88 }
}
className="absolute inset-y-0 right-0 left-16 overflow-hidden rounded-tl-[calc(var(--radius-md)+4px)] border-t border-l border-border/80 md:left-[4.25rem]"
transition={{ type: "spring", duration: 0.3, bounce: 0 }}
>
<Image
alt={preview.alt}
className="object-cover object-top"
fill
sizes={preview.tall ? "320px" : "200px"}
src={preview.src}
/>
</motion.div>
);
}
function BentoCapabilityCell({
cell,
isFocused,
hasFocus,
onFocus,
onClear,
reduceMotion,
cellVariants,
}: {
cell: CapabilityCell;
isFocused: boolean;
hasFocus: boolean;
onFocus: () => void;
onClear: () => void;
reduceMotion: boolean;
cellVariants: {
hidden: { opacity: number; scale?: number; filter?: string };
visible: { opacity: number; scale?: number; filter?: string };
};
}) {
const Icon = cell.icon;
const featured = cell.featured;
const dimmed = hasFocus && !isFocused && !featured;
if (featured) {
return (
<motion.div
className={cn(
"relative flex min-h-[12rem] flex-col justify-between overflow-hidden bg-background p-6 md:min-h-0 md:p-8",
cell.span,
)}
variants={cellVariants}
>
<GridPattern
aria-hidden
className="absolute inset-0 stroke-foreground/[0.05]"
height={32}
width={32}
/>
<div className="absolute inset-0 bg-gradient-to-br from-primary/[0.06] via-transparent to-transparent" />
<div className="relative z-10">
<div className="inline-flex size-10 items-center justify-center rounded-[var(--radius-md)] border border-foreground/10 bg-background/80 text-primary">
<Icon className="size-5" strokeWidth={2} />
</div>
<p className="mt-4 font-medium text-primary text-xs uppercase tracking-[0.2em]">
Flagship
</p>
<h3 className="mt-2 text-balance font-medium text-xl tracking-tight md:text-2xl">
{cell.title}
</h3>
<p className="mt-3 max-w-md text-pretty text-muted-foreground text-sm leading-relaxed">
{cell.description}
</p>
</div>
<div className="relative z-10 mt-6 flex items-baseline gap-2">
<span className="font-medium text-4xl tabular-nums tracking-tight md:text-5xl">
{cell.stat}
</span>
<span className="text-muted-foreground text-sm">{cell.statLabel}</span>
</div>
</motion.div>
);
}
return (
<motion.button
animate={
reduceMotion
? undefined
: dimmed
? { opacity: 0.42, filter: "blur(1.5px)" }
: { opacity: 1, filter: "blur(0px)" }
}
aria-label={cell.title}
aria-pressed={isFocused}
className={cn(
"group relative flex h-full min-h-[10.5rem] w-full flex-col overflow-hidden bg-background text-left transition-[background-color,transform,box-shadow] active:scale-[0.96]",
cell.preview ? "min-h-[11.5rem] md:min-h-0" : "p-4 md:p-5",
"after:absolute after:top-1/2 after:left-1/2 after:size-10 after:-translate-1/2",
isFocused &&
"bg-muted/30 shadow-[inset_0_0_0_1px_rgba(0,0,0,0.06)] dark:shadow-[inset_0_0_0_1px_rgba(255,255,255,0.08)]",
cell.span,
)}
onBlur={onClear}
onClick={onFocus}
onFocus={onFocus}
transition={{ type: "spring", duration: 0.3, bounce: 0 }}
type="button"
variants={cellVariants}
>
<div
className={cn(
"flex min-w-0 items-start gap-3",
cell.preview ? "shrink-0 px-4 pt-4 md:px-5 md:pt-5" : undefined,
)}
>
<motion.span
animate={
reduceMotion
? undefined
: {
opacity: isFocused ? 1 : 0.85,
scale: isFocused ? 1 : 0.96,
}
}
className={cn(
"inline-flex shrink-0 items-center justify-center rounded-[var(--radius-sm)] border border-border bg-muted/30 text-primary",
isFocused ? "size-10" : "size-9",
)}
transition={{ type: "spring", duration: 0.3, bounce: 0 }}
>
<Icon className="size-4" strokeWidth={2} />
</motion.span>
<div className="min-w-0 flex-1">
<p
className={cn(
"font-medium text-sm leading-snug",
isFocused ? "text-foreground" : "text-foreground/85",
)}
>
{cell.title}
</p>
<motion.p
animate={
reduceMotion
? undefined
: {
opacity: isFocused ? 1 : 0.55,
filter: isFocused ? "blur(0px)" : "blur(0px)",
}
}
className="mt-1 text-pretty font-mono text-[10px] text-muted-foreground leading-relaxed tracking-[0.08em] md:text-[11px]"
transition={{ type: "spring", duration: 0.3, bounce: 0 }}
>
{cell.detail}
</motion.p>
</div>
</div>
{cell.preview ? (
<div
className={cn(
"relative mt-3 min-h-[4.25rem] flex-1",
cell.preview.tall && "min-h-[5rem]",
)}
>
<CellPreview
isFocused={isFocused}
preview={cell.preview}
reduceMotion={!!reduceMotion}
/>
</div>
) : null}
</motion.button>
);
}
export function FeaturesExpandBentoSection() {
const reduceMotion = useReducedMotion();
const gridRef = useRef<HTMLDivElement>(null);
const gridInView = useInView(gridRef, motionViewport);
const [focusedId, setFocusedId] = useState<string | null>(null);
const cellVariants = reduceMotion
? { hidden: { opacity: 1 }, visible: { opacity: 1 } }
: {
hidden: { opacity: 0, scale: 0.97, filter: "blur(4px)" },
visible: { opacity: 1, scale: 1, filter: "blur(0px)" },
};
const hasFocus = focusedId !== null;
return (
<SectionShell spacingMode="section" className="bg-background">
<ContentRail maxWidth="max-w-5xl" className="space-y-8 md:space-y-10">
<motion.div
className="max-w-xl space-y-2"
initial={reduceMotion ? false : { opacity: 0, y: 8, filter: "blur(4px)" }}
transition={defaultSpring}
viewport={motionViewport}
whileInView={reduceMotion ? undefined : { opacity: 1, y: 0, filter: "blur(0px)" }}
>
<p className="font-medium text-primary text-xs uppercase tracking-[0.22em]">
Registry
</p>
<h2 className="text-balance font-medium text-2xl tracking-tight md:text-4xl">
What ships in every block
</h2>
<p className="text-pretty text-muted-foreground text-sm md:text-base">
Each cell ships with a label — four include a visual crop you can swap
later. Click to sharpen one while peers recede.
</p>
</motion.div>
<motion.div
className="relative border border-border bg-border p-px shadow-[0_1px_2px_rgba(0,0,0,0.04)] dark:shadow-[0_1px_2px_rgba(0,0,0,0.2)]"
initial={reduceMotion ? false : { opacity: 0, y: 14 }}
transition={{ ...defaultSpring, delay: motionStagger.item }}
viewport={motionViewport}
whileInView={reduceMotion ? undefined : { opacity: 1, y: 0 }}
>
<DecorIcon position="top-left" />
<DecorIcon position="top-right" />
<DecorIcon position="bottom-left" />
<DecorIcon position="bottom-right" />
<motion.div
animate={gridInView ? "visible" : "hidden"}
className="grid grid-cols-2 grid-rows-[12rem_repeat(3,minmax(10.5rem,1fr))] gap-px bg-border md:grid-cols-3 md:grid-rows-[minmax(12rem,1fr)_minmax(12rem,1fr)_minmax(11rem,1fr)]"
initial="hidden"
onClick={(event) => {
if (event.target === event.currentTarget) {
setFocusedId(null);
}
}}
ref={gridRef}
variants={{
hidden: {},
visible: {
transition: {
staggerChildren: motionStagger.item,
delayChildren: 0.04,
},
},
}}
>
{capabilities.map((cell) => (
<BentoCapabilityCell
cell={cell}
cellVariants={cellVariants}
hasFocus={hasFocus}
isFocused={focusedId === cell.id}
key={cell.id}
onClear={() => setFocusedId(null)}
onFocus={() =>
setFocusedId((current) => (current === cell.id ? null : cell.id))
}
reduceMotion={!!reduceMotion}
/>
))}
</motion.div>
</motion.div>
</ContentRail>
</SectionShell>
);
}




























