feat: replace card stack with new feature grid and add product icons
This commit is contained in:
BIN
public/images/agent_icon.png
Normal file
BIN
public/images/agent_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 802 KiB |
BIN
public/images/cloud1.png
Normal file
BIN
public/images/cloud1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
BIN
public/images/cloud_icon.png
Normal file
BIN
public/images/cloud_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 757 KiB |
BIN
public/images/cloudimg.png
Normal file
BIN
public/images/cloudimg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
BIN
public/images/network_icon.png
Normal file
BIN
public/images/network_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 835 KiB |
@@ -1,48 +0,0 @@
|
||||
"use client";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
type Card = {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
icon: React.ReactNode;
|
||||
};
|
||||
|
||||
export const CardStack = ({
|
||||
items,
|
||||
offset,
|
||||
scaleFactor,
|
||||
}: {
|
||||
items: Card[];
|
||||
offset?: number;
|
||||
scaleFactor?: number;
|
||||
}) => {
|
||||
const CARD_OFFSET = offset || 10;
|
||||
const HORIZONTAL_OFFSET = 336; // Adjusted for 1/8 overlap
|
||||
const SCALE_FACTOR = scaleFactor || 0.06;
|
||||
|
||||
return (
|
||||
<div className="relative h-[20rem] w-full flex items-center justify-center">
|
||||
{items.map((card, index) => (
|
||||
<motion.div
|
||||
key={card.id}
|
||||
className="absolute dark:bg-black bg-white h-[16rem] w-[24rem] rounded-3xl p-4 shadow-xl border border-neutral-200 dark:border-white/[0.1] shadow-black/[0.1] dark:shadow-white/[0.05] flex flex-col justify-between"
|
||||
style={{
|
||||
transformOrigin: "top center",
|
||||
}}
|
||||
animate={{
|
||||
top: index * -CARD_OFFSET,
|
||||
left: index * HORIZONTAL_OFFSET,
|
||||
scale: 1 - index * SCALE_FACTOR,
|
||||
zIndex: items.length - index,
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-col p-4">
|
||||
<h3 className="text-base/7 font-semibold text-gray-900 dark:text-white">{card.name}</h3>
|
||||
<p className="mt-1 flex-auto text-base/7 text-gray-600 dark:text-neutral-300">{card.description}</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
158
src/components/ui/glowing-stars.tsx
Normal file
158
src/components/ui/glowing-stars.tsx
Normal file
@@ -0,0 +1,158 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { AnimatePresence, motion } from "motion/react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export const GlowingStarsBackgroundCard = ({
|
||||
className,
|
||||
children,
|
||||
}: {
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
}) => {
|
||||
const [mouseEnter, setMouseEnter] = useState(false);
|
||||
|
||||
return (
|
||||
<div
|
||||
onMouseEnter={() => {
|
||||
setMouseEnter(true);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setMouseEnter(false);
|
||||
}}
|
||||
className={cn(
|
||||
"bg-[linear-gradient(110deg,#333_0.6%,#222)] p-4 max-w-md max-h-[20rem] h-full w-full rounded-xl border border-[#eaeaea] dark:border-neutral-600",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className="flex justify-center items-center">
|
||||
<Illustration mouseEnter={mouseEnter} />
|
||||
</div>
|
||||
<div className="px-2 pb-6">{children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const GlowingStarsDescription = ({
|
||||
className,
|
||||
children,
|
||||
}: {
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
}) => {
|
||||
return (
|
||||
<p className={cn("text-base text-white max-w-[16rem]", className)}>
|
||||
{children}
|
||||
</p>
|
||||
);
|
||||
};
|
||||
|
||||
export const GlowingStarsTitle = ({
|
||||
className,
|
||||
children,
|
||||
}: {
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
}) => {
|
||||
return (
|
||||
<h2 className={cn("font-bold text-2xl text-[#eaeaea]", className)}>
|
||||
{children}
|
||||
</h2>
|
||||
);
|
||||
};
|
||||
|
||||
export const Illustration = ({ mouseEnter }: { mouseEnter: boolean }) => {
|
||||
const stars = 108;
|
||||
const columns = 18;
|
||||
|
||||
const [glowingStars, setGlowingStars] = useState<number[]>([]);
|
||||
|
||||
const highlightedStars = useRef<number[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
highlightedStars.current = Array.from({ length: 5 }, () =>
|
||||
Math.floor(Math.random() * stars)
|
||||
);
|
||||
setGlowingStars([...highlightedStars.current]);
|
||||
}, 3000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="h-48 p-1 w-full"
|
||||
style={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: `repeat(${columns}, 1fr)`,
|
||||
gap: `1px`,
|
||||
}}
|
||||
>
|
||||
{[...Array(stars)].map((_, starIdx) => {
|
||||
const isGlowing = glowingStars.includes(starIdx);
|
||||
const delay = (starIdx % 10) * 0.1;
|
||||
const staticDelay = starIdx * 0.01;
|
||||
return (
|
||||
<div
|
||||
key={`matrix-col-${starIdx}}`}
|
||||
className="relative flex items-center justify-center"
|
||||
>
|
||||
<Star
|
||||
isGlowing={mouseEnter ? true : isGlowing}
|
||||
delay={mouseEnter ? staticDelay : delay}
|
||||
/>
|
||||
{mouseEnter && <Glow delay={staticDelay} />}
|
||||
<AnimatePresence mode="wait">
|
||||
{isGlowing && <Glow delay={delay} />}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const Star = ({ isGlowing, delay }: { isGlowing: boolean; delay: number }) => {
|
||||
return (
|
||||
<motion.div
|
||||
key={delay}
|
||||
initial={{
|
||||
scale: 1,
|
||||
}}
|
||||
animate={{
|
||||
scale: isGlowing ? [1, 1.2, 2.5, 2.2, 1.5] : 1,
|
||||
background: isGlowing ? "#fff" : "#666",
|
||||
}}
|
||||
transition={{
|
||||
duration: 2,
|
||||
ease: "easeInOut",
|
||||
delay: delay,
|
||||
}}
|
||||
className={cn("bg-[#666] h-[1px] w-[1px] rounded-full relative z-20")}
|
||||
></motion.div>
|
||||
);
|
||||
};
|
||||
|
||||
const Glow = ({ delay }: { delay: number }) => {
|
||||
return (
|
||||
<motion.div
|
||||
initial={{
|
||||
opacity: 0,
|
||||
}}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
}}
|
||||
transition={{
|
||||
duration: 2,
|
||||
ease: "easeInOut",
|
||||
delay: delay,
|
||||
}}
|
||||
exit={{
|
||||
opacity: 0,
|
||||
}}
|
||||
className="absolute left-1/2 -translate-x-1/2 z-10 h-[4px] w-[4px] rounded-full bg-blue-500 blur-[1px] shadow-2xl shadow-blue-400"
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -1,56 +1,80 @@
|
||||
import { InboxIcon, TrashIcon, UsersIcon } from '@heroicons/react/24/outline'
|
||||
import { H2, P } from '@/components/Texts'
|
||||
import { CardStack } from '@/components/ui/card-stack'
|
||||
|
||||
const features = [
|
||||
{
|
||||
name: 'Network Layer',
|
||||
name: 'Mycelium Network',
|
||||
description:
|
||||
"A global, end-to-end encrypted overlay that simply doesn't break. Shortest-path routing moves your traffic the fastest way, every time with instant discovery.",
|
||||
href: '#',
|
||||
"A global, end-to-end encrypted overlay that simply doesn't break.",
|
||||
href: '/network',
|
||||
icon: UsersIcon,
|
||||
image: '/images/network_icon.png',
|
||||
},
|
||||
{
|
||||
name: 'Cloud Layer',
|
||||
name: 'Mycelium Cloud',
|
||||
description:
|
||||
'An autonomous, stateless OS that enforces pre-deterministic deployments you define. Workloads are cryptographically bound to your private key—location and access are yours.',
|
||||
href: '#',
|
||||
'An autonomous, stateless OS that enforces pre-deterministic deployments you define.',
|
||||
href: '/cloud',
|
||||
icon: TrashIcon,
|
||||
image: '/images/cloud_icon.png',
|
||||
},
|
||||
{
|
||||
name: 'Agent Layer',
|
||||
name: 'Mycelium Agents',
|
||||
description:
|
||||
'Your sovereign agent with private memory and permissioned data access—always under your control. Choose from a wide library of open-source LLMs, paired with built-in semantic search and retrieval.',
|
||||
href: '#',
|
||||
'Your sovereign agent with private memory and permissioned data access—always under your control.',
|
||||
href: '/agents',
|
||||
icon: InboxIcon,
|
||||
image: '/images/agent_icon.png',
|
||||
},
|
||||
]
|
||||
|
||||
export function HomeFeatures() {
|
||||
const cards = features.map((feature, index) => ({
|
||||
id: index,
|
||||
name: feature.name,
|
||||
description: feature.description,
|
||||
icon: <feature.icon aria-hidden="true" className="size-6 text-white" />,
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className="bg-white py-24">
|
||||
<div className="">
|
||||
<div className="relative bg-transparent py-24 overflow-hidden">
|
||||
{/* --- Soft background gradients --- */}
|
||||
<div
|
||||
className="absolute -top-32 right-0 w-[600px] h-[600px] rounded-full blur-3xl opacity-50 -z-10"
|
||||
style={{
|
||||
background:
|
||||
'radial-gradient(circle at center, rgba(147,197,253,0.6) 0%, rgba(165,180,252,0.4) 40%, rgba(221,214,254,0.2) 80%)',
|
||||
}}
|
||||
></div>
|
||||
|
||||
<div
|
||||
className="absolute -bottom-40 -left-40 w-[600px] h-[600px] rounded-full blur-3xl opacity-50 -z-10"
|
||||
style={{
|
||||
background:
|
||||
'radial-gradient(circle at center, rgba(115,207,255,0.5) 0%, rgba(59,130,246,0.4) 40%, rgba(221,214,254,0.2) 90%)',
|
||||
}}
|
||||
></div>
|
||||
<div className="mx-auto max-w-7xl px-6 lg:px-8">
|
||||
<div className="mx-auto max-w-2xl lg:mx-0">
|
||||
<H2 className="">
|
||||
The Mycelium <span className="font-neuton font-bold italic">Stack</span>
|
||||
The Building Blocks of <span className="font-neuton font-medium text-7xl italic">Decentralized Future</span>
|
||||
</H2>
|
||||
<P className="mt-6 ">
|
||||
Built with Mycelium technology, our AI infrastructure ensures unbreakable networks, complete data sovereignty, ultra-secure agent-human communication, and unhackable data storage systems.
|
||||
From compute and networking to intelligent automation, these components work together to empower users, developers, and organizations to build freely, without intermediaries.
|
||||
</P>
|
||||
</div>
|
||||
<div className="mx-auto mt-16 max-w-2xl sm:mt-20 lg:mt-32 lg:max-w-7xl">
|
||||
<div className="flex items-center justify-center w-full">
|
||||
<CardStack items={cards} offset={80} />
|
||||
<div className="mx-auto mt-16 max-w-2xl lg:max-w-7xl">
|
||||
<div className="grid grid-cols-1 gap-x-12 gap-y-12 lg:grid-cols-3">
|
||||
{features.map((feature) => (
|
||||
<div key={feature.name} className="relative flex flex-col p-8 rounded-3xl border border-gray-100 bg-white backdrop-blur-lg overflow-hidden shadow-lg hover:shadow-xl hover:border-cyan-500 hover:scale-105 transform transition-all duration-300">
|
||||
<div className="w-30 h-30 bg-white/80 rounded-full flex items-center justify-center">
|
||||
<img src={feature.image} alt="" className="w-25 h-25" />
|
||||
</div>
|
||||
<h3 className="mt-6 text-xl font-semibold text-black">{feature.name}</h3>
|
||||
<p className="mt-4 text-base text-gray-800">{feature.description}</p>
|
||||
<a href={feature.href} className="mt-6 text-base font-semibold text-black">Learn more ></a>
|
||||
<div className="absolute -bottom-10 -right-10 h-50 w-50 -z-10" style={{ background: 'radial-gradient(circle, rgba(173, 239, 255, 0.6) 0%, rgba(115, 207, 255, 0.4) 100%)', filter: 'blur(80px)' }}></div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user