feat: add interactive stacked cube components with hover descriptions

This commit is contained in:
2025-10-22 17:33:29 +02:00
parent fa0a55d846
commit 6c0ed3cd65
8 changed files with 883 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
"use client";
import { useState } from "react";
import { motion } from "framer-motion";
import { CubeLight } from "@/components/ui/CubeLight"
const stackData = [
{
id: "agent",
title: "Agent Layer",
descriptionTitle: "Your sovereign agent with private memory and permissioned data access—always under your control.",
description:
"Choose from a wide library of open-source LLMs, paired with built-in semantic search and retrieval.\nIt coordinates across people, apps, and other agents to plan, create, and execute.\nIt operates inside a compliant legal & financial sandbox, ready for real-world transactions and operations.\nMore than just an assistant—an intelligent partner that learns and does your way.",
position: "top",
},
{
id: "network",
title: "Network Layer",
descriptionTitle: "A global, end-to-end encrypted overlay that simply doesnt break.",
description:
"Shortest-path routing moves your traffic the fastest way, every time.\nInstant discovery with integrated DNS, semantic search, and indexing.\nA distributed CDN and edge delivery keep content available and tamper-resistant worldwide.\nBuilt-in tool services and secure coding sandboxes—seamless on phones, desktops, and edge.",
position: "middle",
},
{
id: "cloud",
title: "Cloud Layer",
descriptionTitle: "An autonomous, stateless OS that enforces pre-deterministic deployments you define.",
description:
"Workloads are cryptographically bound to your private key—location and access are yours.\nNo cloud vendor or middleman in the path: end-to-end ownership and isolation by default.\nGeo-aware placement delivers locality, compliance, and ultra-low latency where it matters.\nEncrypted, erasure-coded storage, decentralized compute and GPU on demand—including LLMs.",
position: "bottom",
},
];
export function StackedCubesLight() {
const [active, setActive] = useState<string | null>("agent");
const [selectedForMobile, setSelectedForMobile] = useState<string | null>("agent");
const handleCubeClick = (id: string) => {
setSelectedForMobile(prev => (prev === id ? null : id));
};
const selectedMobileLayer = stackData.find(layer => layer.id === selectedForMobile);
return (
<div className="flex flex-col items-center">
<div
className="relative w-full flex items-center justify-center lg:justify-center min-h-[450px] lg:min-h-[400px]"
onMouseLeave={() => setActive("agent")}
>
<motion.div
className="relative lg:pl-0 pl-6 h-[300px] lg:h-[400px] w-64 sm:w-80 lg:w-96 scale-120 lg:scale-100"
animate={{ y: ["-8px", "8px"] }}
transition={{
duration: 4,
repeat: Infinity,
repeatType: "reverse",
ease: "easeInOut",
}}
>
{stackData.map((layer, index) => (
<div
key={layer.id}
className="absolute"
style={{
top: `calc(${index * 30}% - ${index * 10}px)`,
zIndex: active === layer.id ? 20 : 10 - index,
}}
>
<CubeLight
title={layer.title}
descriptionTitle={layer.descriptionTitle}
description={layer.description}
isActive={active === layer.id}
index={index}
onHover={() => setActive(layer.id)}
onLeave={() => {}}
onClick={() => handleCubeClick(layer.id)}
/>
</div>
))}
</motion.div>
</div>
{selectedMobileLayer && (
<div className="lg:hidden w-full max-w-md p-6 -mt-8 bg-gray-200/50 rounded-lg">
<h4 className="text-black text-lg font-semibold mb-2 text-center">
{selectedMobileLayer.descriptionTitle}
</h4>
<p className="text-gray-700 text-sm leading-relaxed text-center">
{selectedMobileLayer.description}
</p>
</div>
)}
</div>
);
}