96 lines
3.3 KiB
TypeScript
96 lines
3.3 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { motion } from "framer-motion";
|
|
import { Cube } from "@/components/ui/Cube"
|
|
|
|
const stackData = [
|
|
{
|
|
id: "agent",
|
|
title: "Agent Layer",
|
|
descriptionTitle: "Personal Agents - Secure & Sovereign",
|
|
description:
|
|
"Personal AI agents operate as secure digital twins, providing tailored intelligent assistance. They interact with existing chat, MCP agents, and coding tools while maintaining sovereignty and ecosystem compatibility.",
|
|
position: "top",
|
|
},
|
|
{
|
|
id: "ai",
|
|
title: "AI Layer",
|
|
descriptionTitle: "AI Agents & AI Brains + Mycelium Code & Compute Sandboxes",
|
|
description:
|
|
"Intelligence core combining LLMs with specialized AI agents. Mycelium-powered sandboxes provide secure environments for development, testing, and compilation with active memory systems and unbreakable network architecture.",
|
|
position: "middle",
|
|
},
|
|
{
|
|
id: "cloud",
|
|
title: "Cloud Layer",
|
|
descriptionTitle: "Mycelium Compute & Storage - Decentralized Infrastructure Layer",
|
|
description:
|
|
"Foundation runs bare metal Zero OS enabling autonomous cloud. Decentralized infrastructure supports Web2, Web3, AI workloads with superior scalability. Built on twenty years cloud experience.",
|
|
position: "bottom",
|
|
},
|
|
];
|
|
|
|
export function StackedCubes() {
|
|
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,
|
|
}}
|
|
>
|
|
<Cube
|
|
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-800/50 rounded-lg">
|
|
<h4 className="text-white text-lg font-semibold mb-2 text-center">
|
|
{selectedMobileLayer.descriptionTitle}
|
|
</h4>
|
|
<p className="text-gray-300 text-sm leading-relaxed text-center">
|
|
{selectedMobileLayer.description}
|
|
</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|