refactor: extract bento cards into data-driven component

- Replaced hardcoded card markup with array-based configuration for maintainability
- Added Link components to enable navigation to individual product pages
- Implemented hover animation for improved user interaction
This commit is contained in:
2025-11-06 20:28:13 +01:00
parent 15cc1f70e3
commit 8b4e0defb9

View File

@@ -1,8 +1,83 @@
"use client";
import { useState } from "react";
import { Link } from "react-router-dom";
import { Eyebrow, H3, P } from "@/components/Texts";
const bentoCards = [
{
id: 'network',
title: 'Mycelium Network',
eyebrow: 'Network',
description: 'Encrypted peer-to-peer mesh networking across the globe.',
image: '/images/bento-network.png',
link: '/network',
colSpan: 'lg:col-span-3',
rowSpan: 'lg:row-span-1',
rounded: 'lg:rounded-tl-4xl max-lg:rounded-t-4xl',
innerRounded: 'lg:rounded-tl-[calc(2rem+1px)] max-lg:rounded-t-[calc(2rem+1px)]'
},
{
id: 'agents',
title: 'Mycelium Agents',
eyebrow: 'Agents',
description: 'Private, programmable AI systems that run on your hardware.',
image: '/images/bento-agent.jpg',
link: '/agents',
colSpan: 'lg:col-span-3',
rowSpan: 'lg:row-span-1',
rounded: 'lg:rounded-tr-4xl',
innerRounded: 'lg:rounded-tr-[calc(2rem+1px)]'
},
{
id: 'cloud',
title: 'Mycelium Cloud',
eyebrow: 'Cloud',
description: 'Deploy Kubernetes clusters on sovereign infrastructure.',
image: '/images/bento-cloud.jpg',
link: '/cloud',
colSpan: 'lg:col-span-6',
rowSpan: 'lg:row-span-1',
rounded: 'rounded-lg',
innerRounded: 'rounded-[calc(var(--radius-lg)+1px)]'
},
{
id: 'compute',
title: 'Mycelium Compute',
eyebrow: 'Compute',
description: 'The Compute resource layers powering the stack.',
image: '/images/bento-compute.png',
link: '/compute',
colSpan: 'lg:col-span-2',
rowSpan: 'lg:row-span-1',
rounded: 'lg:rounded-bl-4xl',
innerRounded: 'lg:rounded-bl-[calc(2rem+1px)]'
},
{
id: 'storage',
title: 'Mycelium Storage',
eyebrow: 'Storage',
description: 'The Storage resource layers powering the stack.',
image: '/images/bento-storage.png',
link: '/storage',
colSpan: 'lg:col-span-2',
rowSpan: 'lg:row-span-1',
rounded: 'rounded-lg',
innerRounded: 'rounded-[calc(var(--radius-lg)+1px)]'
},
{
id: 'gpu',
title: 'Mycelium GPU',
eyebrow: 'GPU',
description: 'The GPU resource layers powering the stack.',
image: '/images/bento-gpu.jpg',
link: '/gpu',
colSpan: 'lg:col-span-2',
rowSpan: 'lg:row-span-1',
rounded: 'lg:rounded-br-4xl max-lg:rounded-b-4xl',
innerRounded: 'lg:rounded-br-[calc(2rem+1px)] max-lg:rounded-b-[calc(2rem+1px)]'
},
];
export function HomeTab() {
return (
<section className="w-full max-w-8xl mx-auto bg-transparent">
@@ -21,123 +96,26 @@ export function HomeTab() {
</P>
<div className="mt-8 grid grid-cols-1 gap-4 sm:mt-10 lg:grid-cols-6 lg:grid-rows-3 pb-12">
{/* ✅ TOP ROW */}
<div className="relative lg:col-span-3">
<div className="absolute inset-0 rounded-md bg-white max-lg:rounded-t-4xl lg:rounded-tl-4xl" />
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] max-lg:rounded-t-[calc(2rem+1px)] lg:rounded-tl-[calc(2rem+1px)]">
<img
alt=""
src="/images/bento-network.png"
className="h-50 object-cover object-center"
/>
<div className="px-8 pt-4 pb-0">
<h3 className="text-sm/4 font-semibold text-cyan-500">Network</h3>
<p className="mt-2 text-lg font-medium lg:text-xl tracking-tight text-gray-950">Mycelium Network</p>
<p className="mt-1 max-w-lg text-sm/6 text-gray-600">
Encrypted peer-to-peer mesh networking across the globe.
</p>
{bentoCards.map((card) => (
<Link to={card.link} key={card.id} className={`relative ${card.colSpan} ${card.rowSpan} transition-transform duration-300 hover:scale-102 cursor-pointer`}>
<div className={`absolute inset-0 rounded-md bg-white ${card.rounded}`} />
<div className={`relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] ${card.innerRounded}`}>
<img
alt={card.title}
src={card.image}
className="h-50 object-cover object-center"
/>
<div className="px-8 pt-4 pb-0">
<h3 className="text-sm/4 font-semibold text-cyan-500">{card.eyebrow}</h3>
<p className="mt-2 text-lg font-medium lg:text-xl tracking-tight text-gray-950">{card.title}</p>
<p className="mt-1 max-w-lg text-sm/6 text-gray-600">
{card.description}
</p>
</div>
</div>
</div>
<div className="pointer-events-none absolute inset-0 rounded-lg shadow-sm outline outline-black/5 max-lg:rounded-t-4xl lg:rounded-tl-4xl" />
</div>
<div className="relative lg:col-span-3">
<div className="absolute inset-0 rounded-lg bg-white lg:rounded-tr-4xl" />
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] lg:rounded-tr-[calc(2rem+1px)]">
<img
alt=""
src="/images/bento-agent.jpg"
className="h-50 object-cover object-left lg:object-right"
/>
<div className="px-8 pt-4 pb-0">
<h3 className="text-sm/4 font-semibold text-cyan-500">Agents</h3>
<p className="mt-2 text-lg font-medium lg:text-xl tracking-tight text-gray-950">Mycelium Agents</p>
<p className="mt-1 max-w-lg text-sm/6 text-gray-600">
Private, programmable AI systems that run on your hardware.
</p>
</div>
</div>
<div className="pointer-events-none absolute inset-0 rounded-lg shadow-sm outline outline-black/5 lg:rounded-tr-4xl" />
</div>
{/* ✅ ✅ MIDDLE ROW (half-height, equal spacing) */}
<div className="relative lg:col-span-6">
<div className="absolute inset-0 bg-white rounded-[calc(var(--radius-lg)+1px)]" />
<div className="relative flex flex-col items-center justify-center pb-4 text-center rounded-[calc(var(--radius-lg)+1px)] shadow-sm">
<img
alt=""
src="/images/bento-cloud.jpg"
className=" object-cover object-center lg:object-center"
/>
<div className="px-8 pt-4 pb-0">
<h3 className="text-sm/4 font-semibold text-cyan-500">Agents</h3>
<p className="mt-2 text-lg font-medium lg:text-xl tracking-tight text-gray-950">Mycelium Cloud</p>
<p className="mt-1 max-w-lg text-sm/6 text-gray-600">
Private, programmable AI systems that run on your hardware.
</p>
</div>
</div>
<div className="pointer-events-none absolute inset-0 rounded-lg shadow-sm outline outline-black/5" />
</div>
{/* ✅ BOTTOM ROW */}
<div className="relative lg:col-span-2">
<div className="absolute inset-0 rounded-lg bg-white lg:rounded-bl-4xl" />
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] lg:rounded-bl-[calc(2rem+1px)]">
<img
alt=""
src="/images/bento-compute.png"
className="h-50 object-cover object-left"
/>
<div className="px-8 pt-4 pb-0">
<h3 className="text-sm/4 font-semibold text-cyan-500">Compute</h3>
<p className="mt-2 text-lg font-medium lg:text-xl tracking-tight text-gray-950">Mycelium Compute</p>
<p className="mt-1 max-w-lg text-sm/6 text-gray-600">
The Compute resource layers powering the stack.
</p>
</div>
</div>
<div className="pointer-events-none absolute inset-0 rounded-lg shadow-sm outline outline-black/5 lg:rounded-bl-4xl" />
</div>
<div className="relative lg:col-span-2">
<div className="absolute inset-0 rounded-lg bg-white" />
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)]">
<img
alt=""
src="/images/bento-storage.png"
className="h-50 object-contain px-1"
/>
<div className="px-8 pt-4 pb-0">
<h3 className="text-sm/4 font-semibold text-cyan-500">Storage</h3>
<p className="mt-2 text-lg font-medium lg:text-xl tracking-tight text-gray-950">Mycelium Storage</p>
<p className="mt-1 max-w-lg text-sm/6 text-gray-600">
The Storage resource layers powering the stack.
</p>
</div>
</div>
<div className="pointer-events-none absolute inset-0 rounded-lg shadow-sm outline outline-black/5" />
</div>
<div className="relative lg:col-span-2">
<div className="absolute inset-0 rounded-lg bg-white max-lg:rounded-b-4xl lg:rounded-br-4xl" />
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] max-lg:rounded-b-[calc(2rem+1px)] lg:rounded-br-[calc(2rem+1px)]">
<img
alt=""
src="/images/bento-gpu.jpg"
className="h-50 object-cover"
/>
<div className="px-8 pt-4 pb-0">
<h3 className="text-sm/4 font-semibold text-cyan-500">GPU</h3>
<p className="mt-2 text-lg font-medium lg:text-xl tracking-tight text-gray-950">Mycelium GPU</p>
<p className="mt-1 max-w-lg text-sm/6 text-gray-600">
The GPU resource layers powering the stack.
</p>
</div>
</div>
<div className="pointer-events-none absolute inset-0 rounded-lg shadow-sm outline outline-black/5 max-lg:rounded-b-4xl lg:rounded-br-4xl" />
</div>
<div className={`pointer-events-none absolute inset-0 rounded-lg shadow-sm outline outline-black/5 ${card.rounded}`} />
</Link>
))}
</div>
</div>