chore: remove Next.js dependencies and update UI components with standard React

This commit is contained in:
2025-10-23 14:18:16 +02:00
parent 8f8d45c7ff
commit 4cc98af570
19 changed files with 275 additions and 3928 deletions

3748
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -28,8 +28,6 @@
"framer-motion": "^10.18.0",
"lucide-react": "^0.544.0",
"motion": "^12.23.24",
"next": "^14.2.33",
"next-themes": "^0.4.6",
"popmotion": "^11.0.5",
"react": "^18.3.1",
"react-countup": "^6.5.3",
@@ -49,7 +47,6 @@
"@vitejs/plugin-react": "^5.0.4",
"autoprefixer": "^10.4.20",
"eslint": "^8.57.1",
"eslint-config-next": "^14.2.33",
"prettier": "^3.6.2",
"prettier-plugin-tailwindcss": "^0.6.14",
"sharp": "^0.33.1",

BIN
public/images/mchip2.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

View File

@@ -12,112 +12,111 @@ function NavLinks() {
let [hoveredIndex, setHoveredIndex] = useState<number | null>(null)
let timeoutRef = useRef<number | null>(null)
return (
<div className="flex items-center gap-x-5">
<Link to="/" aria-label="Home">
<img src="/src/images/logomark.svg" alt="Mycelium" className="h-10 w-auto" />
</Link>
<div className="flex items-center gap-x-5 border-l border-white/10 pl-5">
{[
['Home', '/'],
['Cloud', '/cloud'],
['Network', '/network'],
['Agents', '/agents'],
].map(([label, href], index) => (
<Link
key={label}
to={href}
className={clsx(
'relative rounded-lg px-3 py-2 text-sm text-black transition-colors delay-150 hover:text-cyan-500 hover:delay-0',
<>
{[
['Home', '/'],
['Cloud', '/cloud'],
['Network', '/network'],
['Agents', '/agents'],
].map(([label, href], index) => (
<Link
key={label}
to={href}
className={clsx(
'relative rounded-lg px-3 py-2 text-sm text-black transition-colors delay-150 hover:text-cyan-500 hover:delay-0',
)}
onMouseEnter={() => {
if (timeoutRef.current) {
window.clearTimeout(timeoutRef.current)
}
setHoveredIndex(index)
}}
onMouseLeave={() => {
timeoutRef.current = window.setTimeout(() => {
setHoveredIndex(null)
}, 200)
}}
>
<AnimatePresence>
{hoveredIndex === index && (
<motion.span
className="absolute inset-0 rounded-lg bg-white/10"
layoutId="hoverBackground"
initial={{ opacity: 0 }}
animate={{ opacity: 1, transition: { duration: 0.15 } }}
exit={{
opacity: 0,
transition: { duration: 0.15 },
}}
/>
)}
onMouseEnter={() => {
if (timeoutRef.current) {
window.clearTimeout(timeoutRef.current)
}
setHoveredIndex(index)
}}
onMouseLeave={() => {
timeoutRef.current = window.setTimeout(() => {
setHoveredIndex(null)
}, 200)
}}
>
<AnimatePresence>
{hoveredIndex === index && (
<motion.span
className="absolute inset-0 rounded-lg bg-white/10"
layoutId="hoverBackground"
initial={{ opacity: 0 }}
animate={{ opacity: 1, transition: { duration: 0.15 } }}
exit={{
opacity: 0,
transition: { duration: 0.15 },
}}
/>
)}
</AnimatePresence>
<span className="relative z-10">{label}</span>
</Link>
))}
</div>
<div className="flex items-center gap-8">
<div className="flex items-center gap-6 max-lg:hidden">
<Button
to="https://threefold.info/mycelium_network/docs/"
variant="outline"
as="a"
target="_blank"
rel="noopener noreferrer"
>
Docs
</Button>
<Button to="/download" variant="solid" color="cyan">
Get Mycelium
</Button>
</div>
</div>
</div>
</AnimatePresence>
<span className="relative z-10">{label}</span>
</Link>
))}
</>
)
}
export function Header() {
const [isVisible, setIsVisible] = useState(true);
const [lastScrollY, setLastScrollY] = useState(0);
const [isVisible, setIsVisible] = useState(true)
const [lastScrollY, setLastScrollY] = useState(0)
const controlHeader = () => {
if (typeof window !== 'undefined') {
if (window.scrollY > lastScrollY && window.scrollY > 100) { // Hides when scrolling down past 100px
setIsVisible(false);
} else { // Shows when scrolling up
setIsVisible(true);
if (window.scrollY > lastScrollY && window.scrollY > 100) {
// Hides when scrolling down past 100px
setIsVisible(false)
} else {
// Shows when scrolling up
setIsVisible(true)
}
setLastScrollY(window.scrollY);
setLastScrollY(window.scrollY)
}
};
}
useEffect(() => {
if (typeof window !== 'undefined') {
window.addEventListener('scroll', controlHeader);
window.addEventListener('scroll', controlHeader)
return () => {
window.removeEventListener('scroll', controlHeader);
};
window.removeEventListener('scroll', controlHeader)
}
}
}, [lastScrollY]);
}, [lastScrollY])
return (
<motion.header
className="fixed top-4 left-0 right-0 z-50 flex justify-center"
<motion.header
className="fixed top-0 left-0 right-0 z-50 bg-white/10 shadow-lg ring-1 ring-white/10 backdrop-blur-sm"
initial={{ y: 0, opacity: 1 }}
animate={{ y: isVisible ? 0 : -100, opacity: isVisible ? 1 : 0 }}
transition={{ duration: 0.3, ease: 'easeInOut' }}
>
<div className="rounded-full bg-white/10 px-5 py-3 shadow-lg ring-1 ring-white/10 backdrop-blur-sm">
<NavLinks />
<div className="mx-auto flex max-w-7xl items-center justify-between px-4 py-3 sm:px-6 lg:px-8">
<div className="flex items-center gap-x-5">
<Link to="/" aria-label="Home">
<img src="/src/images/logomark.svg" alt="Mycelium" className="h-10 w-auto" />
</Link>
</div>
<div className="flex items-center gap-x-5">
<NavLinks />
</div>
<div className="flex items-center gap-8">
<div className="flex items-center gap-6 max-lg:hidden">
<Button
to="https://threefold.info/mycelium_network/docs/"
variant="outline"
as="a"
target="_blank"
rel="noopener noreferrer"
>
Docs
</Button>
<Button to="/download" variant="solid" color="cyan">
Get Mycelium
</Button>
</div>
</div>
</div>
</motion.header>
)

View File

@@ -0,0 +1,18 @@
'use client'
import CountUp from 'react-countup'
import { SectionHeader } from '@/components/Texts'
interface CountUpNumberProps {
end: number
className?: string
color?: 'light' | 'primary' | 'secondary'
}
export function CountUpNumber({ end, className, color }: CountUpNumberProps) {
return (
<SectionHeader color={color} className={className}>
<CountUp end={end} duration={2.75} separator="," />
</SectionHeader>
)
}

View File

@@ -0,0 +1,28 @@
'use client'
import { motion, type Transition } from 'framer-motion'
import React from 'react'
import { useMediaQuery } from '@/hooks/useMediaQuery'
type FadeInProps = {
children: React.ReactNode
transition?: Transition
className?: string
}
export function FadeIn({ children, transition, className }: FadeInProps) {
const isMobile = useMediaQuery('(max-width: 768px)')
return (
<motion.div
className={className}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: false, margin: isMobile ? '0px 0px -50px 0px' : '0px 0px -100px 0px' }}
transition={transition || { duration: 0.5 }}
>
{children}
</motion.div>
)
}

View File

@@ -0,0 +1,47 @@
import { useEffect, useRef } from 'react'
import createGlobe from 'cobe'
export function Globe({ className }: { className?: string }) {
const canvasRef = useRef<HTMLCanvasElement>(null)
useEffect(() => {
let phi = 0
if (!canvasRef.current) return
const globe = createGlobe(canvasRef.current, {
devicePixelRatio: 2,
width: 600 * 2,
height: 600 * 2,
phi: 0,
theta: 0,
dark: 0,
diffuse: 1.2,
mapSamples: 16000,
mapBrightness: 6,
baseColor: [0.3, 0.3, 0.3],
markerColor: [0.1, 0.8, 1],
glowColor: [1, 1, 1],
markers: [
{ location: [37.7595, -122.4367], size: 0.03 },
{ location: [40.7128, -74.006], size: 0.1 },
],
onRender: (state) => {
state.phi = phi
phi += 0.01
},
})
return () => {
globe.destroy()
}
}, [])
return (
<canvas
ref={canvasRef}
className={className}
style={{ width: '100%', height: '100%', maxWidth: '100%', aspectRatio: 1 }}
/>
)
}

View File

@@ -1,6 +1,5 @@
import { cn } from "@/lib/utils";
import { CT, CP } from "@/components/Texts";
import Image from 'next/image';
import React from 'react';
import { motion } from 'framer-motion';
@@ -55,11 +54,9 @@ export const BentoGridItem = React.forwardRef<HTMLDivElement, BentoGridItemProps
className="w-full h-full object-cover opacity-90 group-hover/bento:opacity-100 transition-opacity duration-300"
/>
) : img ? (
<Image
<img
src={img}
alt={title as string}
width={300}
height={300}
className="w-full h-full object-cover opacity-90 group-hover/bento:opacity-100 transition-opacity duration-300"
/>
) : null}

View File

@@ -1,6 +1,6 @@
"use client";
import React, { useState, useEffect } from "react";
import { motion, AnimatePresence } from "motion/react";
import { useState, useEffect } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { cn } from "@/lib/utils";
export const LayoutTextFlip = ({
@@ -33,7 +33,7 @@ export const LayoutTextFlip = ({
<motion.span
layout
className="relative w-fit overflow-hidden px-2 py-2 font-neuton font-medium italic tracking-tight"
className="relative w-fit overflow-hidden px-2 py-2 font-medium italic tracking-tight"
>
<AnimatePresence mode="popLayout">
<motion.span

View File

@@ -4,8 +4,6 @@ import { useRef } from "react";
import { motion } from "motion/react";
import DottedMap from "dotted-map";
import { useTheme } from "next-themes";
interface MapProps {
dots?: Array<{
start: { lat: number; lng: number; label?: string };
@@ -21,13 +19,11 @@ export default function WorldMap({
const svgRef = useRef<SVGSVGElement>(null);
const map = new DottedMap({ height: 100, grid: "diagonal" });
const { theme } = useTheme();
const svgMap = map.getSVG({
radius: 0.22,
color: theme === "dark" ? "#FFFFFF40" : "#00000040",
color: "#FFFFFF40", // Hardcoded for dark theme
shape: "circle",
backgroundColor: theme === "dark" ? "black" : "white",
backgroundColor: "black", // Hardcoded for dark theme
});
const projectPoint = (lat: number, lng: number) => {

View File

@@ -1,5 +1,5 @@
import { motion } from 'framer-motion'
import { Globe } from '../../components/ui/Globe'
import { Globe } from '../../components/ui/Globe2'
import { CountUpNumber } from '../../components/CountUpNumber'
import { Container } from '../../components/Container'

View File

@@ -9,7 +9,7 @@ export function HomeAgent() {
<div className="mx-auto max-w-4xl text-center">
<H2>
Deploy your own{" "}
<span className="font-neuton text-left text-black font-medium text-7xl italic bg-clip-text bg-gradient-to-r from-blue-400 via-cyan-400 to-violet-400">
<span className="text-left text-black font-medium text-7xl italic bg-clip-text bg-gradient-to-r from-blue-400 via-cyan-400 to-violet-400">
<LayoutTextFlip
text=""
words={[

View File

@@ -1,13 +1,11 @@
"use client";
import { motion } from "motion/react";
import { motion } from "framer-motion";
import { H1, H2, H3, H4, H5 } from "@/components/Texts";
import { AuroraBackground } from "@/components/ui/aurora-background";
import { ScrollDownArrow } from '@/components/ScrollDownArrow';
export function HomeAurora() {
return (
<AuroraBackground>
<motion.div
initial={{ opacity: 0.0, y: 40 }}
whileInView={{ opacity: 1, y: 0 }}
@@ -16,10 +14,15 @@ export function HomeAurora() {
duration: 1,
ease: "easeInOut",
}}
className="relative mb-20 flex flex-col items-center justify-center gap-4 px-4 max-w-5xl"
style={{
backgroundImage: "url(/images/mchip2.webp)",
backgroundSize: "cover",
backgroundPosition: "center",
}}
className="relative mx-auto py-24 h-screen flex flex-col items-center justify-center gap-4 px-4 max-w-5xl"
>
<div className="text-center text-gray-800">
<H1>Decentralized Autonomous <span className="font-neuton text-bold lg:text-8xl italic">Agentic Cloud.</span></H1>
<H1>Decentralized Autonomous <span className="text-bold lg:text-8xl">Agentic Cloud.</span></H1>
</div>
<div className="pt-8 text-center font-light text-gray-500 max-w-4xl">
<H5>Mycelium Project is a decentralized platform for autonomous AI, powered by distributed compute, sovereign memory, encrypted networking, and stateless GPU orchestration.</H5>
@@ -27,8 +30,6 @@ export function HomeAurora() {
<div className="pt-8">
<ScrollDownArrow />
</div>
</motion.div>
</AuroraBackground>
);
}

View File

@@ -23,7 +23,7 @@ export function HomeCloud() {
/>
<div className="w-full flex-auto">
<H2 className="">
Mycelium <span className="font-neuton font-medium text-7xl italic">Cloud</span>
Mycelium <span className="font-medium text-7xl italic">Cloud</span>
</H2>
<P className="mt-6 text-lg/8 text-pretty text-gray-600">
A comprehensive platform for deploying and managing Kubernetes clusters on the decentralized Mycelium Grid infrastructure

View File

@@ -49,7 +49,7 @@ export function HomeFeatures() {
<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 Building Blocks of <span className="font-neuton font-medium text-7xl italic">Decentralized Future</span>
The Building Blocks of <span className="font-medium text-7xl italic">Decentralized Future</span>
</H2>
<P className="mt-6 ">
From compute and networking to intelligent automation, these components work together to empower users, developers, and organizations to build freely, without intermediaries.

View File

@@ -5,11 +5,11 @@ import { H2, P } from "@/components/Texts";
export function HomeMapSection() {
return (
<div className=" py-24 dark:bg-black bg-white w-full">
<div className=" py-24 dark:bg-black bg-tra w-full">
<div className="max-w-7xl mx-auto text-center">
<H2 className="font-medium text-xl md:text-4xl dark:text-white text-gray-800">
Mycelium Network is{" "}
<span className="text-black font-neuton text-bold italic">
<span className="text-black text-bold italic">
{"Live.".split("").map((word, idx) => (
<motion.span
key={idx}

View File

@@ -1,14 +1,11 @@
import { AnimatedSection } from '../../components/AnimatedSection'
import { HomeHero } from './HomeHero'
import { WorldMapSection } from './WorldMapSection'
import { StackSection } from './StackSection'
import { HomeHeroLight2 } from './HomeHeroLight2'
import { HomeHeroDark } from './HomeHeroDark'
import { HomeAurora } from './HomeAurora'
import { HomeMapSection } from './HomeMap'
import { HomeFeatures } from './HomeFeatures'
import { HomeCloud } from './HomeCloud'
import { HomeAgent } from './HomeAgent'
import { StackSectionLight } from './StackSection'
export default function HomePage() {
return (
@@ -17,12 +14,12 @@ export default function HomePage() {
<HomeAurora />
</AnimatedSection>
<AnimatedSection id="next-section">
<HomeFeatures />
<AnimatedSection>
<StackSectionLight />
</AnimatedSection>
<AnimatedSection >
<HomeMapSection />
<AnimatedSection>
<HomeFeatures />
</AnimatedSection>
<AnimatedSection>

View File

@@ -1,66 +1,75 @@
import { motion } from 'framer-motion'
import { Container } from '../../components/Container'
"use client";
const stackData = [
{
id: 'agent',
title: 'Agent Layer',
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.',
},
{
id: 'network',
title: 'Network Layer',
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.',
},
{
id: 'cloud',
title: 'Cloud Layer',
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.',
},
]
import { motion } from "framer-motion";
import { StackedCubesLight } from "@/components/ui/StackedCubesLight";
import { H2, P, SectionHeader, Eyebrow } from "@/components/Texts";
import { FadeIn } from "@/components/ui/FadeIn";
import { DottedGlowBackground } from '@/components/ui/dotted-glow-background';
export function StackSection() {
export function StackSectionLight() {
return (
<section className="relative bg-black py-20 lg:py-32">
<Container>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-12 items-start">
{/* Left Column - Text */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="lg:col-span-1"
>
<h2 className="text-3xl lg:text-4xl font-medium tracking-tight text-white">
The Mycelium Stack
</h2>
<p className="mt-6 text-lg text-gray-600">
Built with Mycelium technology, our AI infrastructure ensures unbreakable networks, complete data sovereignty, ultra-secure agent-human communication, and unhackable data storage systems.
</p>
</motion.div>
{/* Right Column - Stack Cards */}
<div className="lg:col-span-2 space-y-6">
{stackData.map((layer, index) => (
<motion.div
key={layer.id}
initial={{ opacity: 0, x: 20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: index * 0.1 }}
className="rounded-2xl bg-gray-50 border border-gray-200 p-6 hover:border-cyan-500 hover:shadow-lg transition-all duration-300"
>
<h3 className="text-xl font-semibold text-gray-900">{layer.title}</h3>
<p className="mt-3 text-gray-600">{layer.description}</p>
</motion.div>
))}
</div>
<section className="relative w-full overflow-hidden py-24 lg:py-40">
{/* === Background Layer === */}
<div className="absolute inset-0 -z-10 bg-transparent">
{/* Dotted Glow Background */}
<DottedGlowBackground
gap={15}
radius={2}
color="rgba(0,0,0,0.4)"
glowColor="rgba(0,170,255,0.85)"
opacity={0.2}
/>
{/* Faint 3D grid floor */}
<div className="absolute inset-0 flex items-end justify-center overflow-hidden">
<div className="w-[200vw] h-[200vh] bg-[linear-gradient(to_right,rgba(0,0,0,0.03)_1px,transparent_1px),linear-gradient(to_bottom,rgba(0,0,0,0.03)_1px,transparent_1px)] bg-[size:60px_60px] [transform:perspective(800px)_rotateX(70deg)] origin-bottom opacity-50" />
</div>
</Container>
</div>
{/* === Content === */}
<div className="relative mx-auto max-w-7xl px-6 lg:px-8 grid grid-cols-1 lg:grid-cols-3 gap-16 items-center">
{/* Left Column - Text */}
<div className="text-center lg:text-left">
<FadeIn>
<Eyebrow color="accent">Technology Layers</Eyebrow>
<SectionHeader color="dark" className="text-4xl sm:text-5xl font-semibold">
The Mycelium Stack
</SectionHeader>
</FadeIn>
<FadeIn>
<P color="dark" className="mt-6 text-lg leading-relaxed text-gray-600">
Built with Mycelium technology, our AI infrastructure ensures
unbreakable networks, complete data sovereignty, ultra-secure
agent-human communication, and unhackable data storage systems.
</P>
</FadeIn>
</div>
{/* Right Column - Animated Stack */}
<div className="lg:col-span-2 flex items-center justify-center lg:justify-start relative">
<motion.div
initial={{ y: 30, opacity: 0 }}
whileInView={{ y: 0, opacity: 1 }}
transition={{ duration: 1.2, ease: "easeOut" }}
viewport={{ once: true }}
>
<motion.div
animate={{
y: [0, -10, 0],
rotateZ: [0, 0.5, -0.5, 0],
}}
transition={{
duration: 6,
repeat: Infinity,
ease: "easeInOut",
}}
className="relative"
>
<StackedCubesLight />
</motion.div>
</motion.div>
</div>
</div>
</section>
)
);
}

View File

@@ -1,5 +1,5 @@
import { motion } from 'framer-motion'
import { Globe } from '../../components/ui/Globe'
import { Globe } from '../../components/ui/Globe2'
import { CountUpNumber } from '../../components/CountUpNumber'
import { Container } from '../../components/Container'