Compare commits
90 Commits
developmen
...
1ec9741283
| Author | SHA1 | Date | |
|---|---|---|---|
| 1ec9741283 | |||
| 5d7272ff6c | |||
| c68b4e5de9 | |||
| c3b171e3b2 | |||
| ed995113df | |||
| 357b2f58c3 | |||
| 7d8ae1d26d | |||
| 3c4da26ecb | |||
| 023921a6cc | |||
| 8e033a3c21 | |||
| 01b1c20b60 | |||
| c962743737 | |||
| e62c4a5688 | |||
| 6b735b5a40 | |||
| 7b9cf135e4 | |||
| 544d7d541b | |||
| b21f874a05 | |||
| e6b194e8c7 | |||
| a8105a0551 | |||
| de5d990fc9 | |||
| 29d2b76db9 | |||
| a0beec808e | |||
| 96c445aa41 | |||
| ce4b4b3360 | |||
| c849c74a53 | |||
| 7bc895d8be | |||
| c0b84fd578 | |||
| 6d96ff9ea8 | |||
| f1e1721b25 | |||
| aed3e8ed25 | |||
| f126287018 | |||
| 9f1e78e116 | |||
| d469bb7b99 | |||
| 97fdf3aa4f | |||
| c1ca5e35f0 | |||
| e5ed88b676 | |||
| 6beb9c1432 | |||
| a9f53224cf | |||
| 3df73ec418 | |||
| c6efc29ab6 | |||
| bec52e7185 | |||
| 29f713cd2f | |||
| d8a7a7331a | |||
| 3f89d1c441 | |||
| fa30aeff43 | |||
| cbbc87cc29 | |||
| 8dfc46cabe | |||
| 00c5f7f880 | |||
| 2dbcda4997 | |||
| 979d151537 | |||
| 252e2335c2 | |||
| 9b2c406e9e | |||
| 791216433c | |||
| a4a6c95612 | |||
| da5cf2d4a2 | |||
| d2e2e87a0c | |||
| a8d91a1624 | |||
| f9ee299362 | |||
| 8509b80f47 | |||
| 7d6bbc2763 | |||
| 4cf6f63139 | |||
| ef9865862b | |||
| 8fdcf1777d | |||
| 503fe26303 | |||
| 39b20f30a4 | |||
| d53f2d943f | |||
| 3213179ff6 | |||
| c289c63856 | |||
| 6329d2dcac | |||
| 3604b47137 | |||
| fe0e231204 | |||
| da539a5e55 | |||
| b7e003a680 | |||
| 0324b2e8ad | |||
| 49d9c22de3 | |||
| 828fe93f46 | |||
| 8b04b668b6 | |||
| 618e1b0f5b | |||
| e46848b98d | |||
| 1fb08e83f2 | |||
| fb35ede79d | |||
| 1a34508699 | |||
| 97da7ba907 | |||
| 2b7559ab47 | |||
| 3ab559aa84 | |||
| 57c39a8b2b | |||
| 6ff539b3fc | |||
| 29e2d942de | |||
| def0972762 | |||
| 1c37cc08ee |
1
google5dd3a8b700455c0e.html
Normal file
@@ -0,0 +1 @@
|
||||
google-site-verification: google5dd3a8b700455c0e.html
|
||||
@@ -4,8 +4,10 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Project Mycelium - Unleash the Power of Decentralized Networks</title>
|
||||
<meta name="description" content="Project Mycelium's technology enables anyone to deploy their own Internet infrastructure, anywhere." />
|
||||
<meta name="google-site-verification" content="rRrZkMEhdC4yFe_BrENEzYmy2bRfD-VE6RTRiDJNLkg" />
|
||||
<title>Project Mycelium - Built for Digital Sovereignty</title>
|
||||
<meta name="description" content="Discover Project Mycelium. A sovereign peer-to-peer network for private communication, storage, and compute. Build and run your digital environment on infrastructure you control." />
|
||||
<meta name="keywords" content="Project Mycelium, Mycelium, digital sovereignty, decentralized network, peer-to-peer infrastructure, private storage, secure compute, sovereign cloud, edge cloud" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Mulish:wght@400;500;700&display=swap" rel="stylesheet" />
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
BIN
public/images/agent1.png
Normal file
|
After Width: | Height: | Size: 618 KiB |
|
Before Width: | Height: | Size: 510 KiB After Width: | Height: | Size: 508 KiB |
BIN
public/images/autonomous.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
public/images/edge.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 796 KiB After Width: | Height: | Size: 792 KiB |
BIN
public/images/encryptednode.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
public/images/energy.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
public/images/fullstack.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 1.5 KiB |
BIN
public/images/mainlogo.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
public/images/mobile/agents.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
public/images/mobile/cloudpage.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
public/images/mobile/homepage.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
public/images/mobile/nodes.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
public/images/mobile/pods.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
public/images/uptime.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 156 KiB |
@@ -3,23 +3,30 @@ import clsx from 'clsx'
|
||||
|
||||
const baseStyles = {
|
||||
solid:
|
||||
'inline-flex justify-center rounded-full py-2 px-5 text-base font-semibold transition-colors',
|
||||
'inline-flex justify-center rounded-full py-2 px-5 text-sm md:text-base font-semibold transition-colors',
|
||||
outline:
|
||||
'inline-flex justify-center bg-transparent rounded-full border py-[calc(--spacing(2)-1px)] px-[calc(--spacing(5)-1px)] text-base transition-colors',
|
||||
'inline-flex justify-center bg-transparent font-semibold rounded-full border border-2 py-[calc(--spacing(2)-1px)] px-[calc(--spacing(5)-1px)] text-sm md:text-base transition-colors',
|
||||
link:
|
||||
'inline-flex items-center text-sm md:text-base font-semibold transition-colors',
|
||||
}
|
||||
|
||||
const variantStyles = {
|
||||
solid: {
|
||||
cyan: 'relative overflow-hidden bg-cyan-500 text-white before:absolute before:inset-0 active:before:bg-transparent hover:before:bg-white/10 active:bg-cyan-600 active:text-white/80 before:transition-colors',
|
||||
cyan: 'relative overflow-hidden bg-cyan-500 text-white before:absolute before:inset-0 hover:bg-cyan-400 active:before:bg-transparent hover:before:bg-white/10 active:bg-cyan-500 active:text-white/80 before:transition-colors',
|
||||
white:
|
||||
'bg-white text-cyan-900 hover:bg-white/90 active:bg-white/90 active:text-cyan-900/70',
|
||||
gray: 'bg-gray-800 text-white hover:bg-gray-900 active:bg-gray-800 active:text-white/80',
|
||||
green: 'bg-green-500 text-white hover:bg-green-600',
|
||||
},
|
||||
outline: {
|
||||
cyan: 'border-cyan-500 text-cyan-500',
|
||||
gray: 'border-gray-300 text-gray-700 hover:border-cyan-500 active:border-cyan-500',
|
||||
white: 'border-gray-300 text-white hover:border-cyan-500 active:border-cyan-500',
|
||||
cyan: 'border-cyan-500 text-cyan-500 hover:border-cyan-400 hover:text-cyan-400 active:border-cyan-400',
|
||||
gray: 'border-gray-200 text-gray-600 hover:text-cyan-400 hover:border-cyan-400 active:border-cyan-400',
|
||||
white: 'border-gray-300 text-white hover:text-cyan-400 hover:border-cyan-400 active:border-cyan-400',
|
||||
},
|
||||
link: {
|
||||
cyan: 'text-cyan-400 underline hover:text-cyan-300',
|
||||
white: 'text-white underline hover:text-cyan-300',
|
||||
dark: 'text-gray-900 underline hover:text-cyan-400',
|
||||
},
|
||||
}
|
||||
|
||||
@@ -30,7 +37,11 @@ type ButtonProps = (
|
||||
}
|
||||
| {
|
||||
variant: 'outline'
|
||||
color?: (keyof typeof variantStyles.outline) | 'cyan'
|
||||
color?: keyof typeof variantStyles.outline
|
||||
}
|
||||
| {
|
||||
variant: 'link'
|
||||
color?: keyof typeof variantStyles.link
|
||||
}
|
||||
) &
|
||||
(
|
||||
@@ -43,16 +54,33 @@ type ButtonProps = (
|
||||
)
|
||||
|
||||
export function Button({ className, as, ...props }: ButtonProps) {
|
||||
props.variant ??= 'solid'
|
||||
props.color ??= 'gray'
|
||||
// Set safe defaults per variant so color always matches a valid palette key
|
||||
if (!props.variant) {
|
||||
props.variant = 'solid'
|
||||
}
|
||||
|
||||
if (!props.color) {
|
||||
if (props.variant === 'solid') {
|
||||
props.color = 'gray'
|
||||
} else if (props.variant === 'outline') {
|
||||
props.color = 'gray'
|
||||
} else if (props.variant === 'link') {
|
||||
props.color = 'cyan'
|
||||
}
|
||||
}
|
||||
|
||||
const variant = props.variant
|
||||
const color = props.color as string
|
||||
|
||||
className = clsx(
|
||||
baseStyles[props.variant],
|
||||
props.variant === 'outline'
|
||||
? variantStyles.outline[props.color]
|
||||
: props.variant === 'solid'
|
||||
? variantStyles.solid[props.color]
|
||||
: undefined,
|
||||
baseStyles[variant],
|
||||
variant === 'outline'
|
||||
? variantStyles.outline[color as keyof typeof variantStyles.outline]
|
||||
: variant === 'solid'
|
||||
? variantStyles.solid[color as keyof typeof variantStyles.solid]
|
||||
: variant === 'link'
|
||||
? variantStyles.link[color as keyof typeof variantStyles.link]
|
||||
: undefined,
|
||||
className,
|
||||
)
|
||||
|
||||
|
||||
@@ -8,10 +8,10 @@ export function Footer() {
|
||||
<div className="flex flex-col items-start justify-between gap-y-12 pt-16 pb-6 lg:flex-row lg:items-center lg:py-8">
|
||||
<div>
|
||||
<div className="flex items-center text-gray-900">
|
||||
<img src="/images/logomark.svg" alt="Mycelium Logomark" className="h-15 w-15 flex-none" />
|
||||
<div className="ml-4">
|
||||
<p className="text-base font-semibold">Project Mycelium</p>
|
||||
<p className="mt-1 text-sm">Unleash the Power of Decentralization</p>
|
||||
<img src="/images/logomark.svg" alt="Mycelium Logomark" className="h-20 w-20 flex-none" />
|
||||
<div className="">
|
||||
<p className="text-base lg:text-lg font-semibold">Project Mycelium</p>
|
||||
<p className="mt-1 text-sm">Built for Digital Sovereignty</p>
|
||||
</div>
|
||||
</div>
|
||||
<nav className="mt-10 flex gap-8">
|
||||
@@ -49,11 +49,11 @@ export function Footer() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-center border-t border-gray-100 pt-8 pb-12 md:flex-row-reverse md:justify-between md:pt-6">
|
||||
<div className="flex flex-col items-center border-t border-gray-100 py-8 md:flex-row-reverse md:justify-between md:pt-6">
|
||||
<p className="mt-6 text-sm text-gray-500 md:mt-0">
|
||||
© Copyright{' '}
|
||||
<a href="https://www.threefold.io" target="_blank" rel="noopener noreferrer" className="hover:text-cyan-500 transition-colors">
|
||||
ThreeFold
|
||||
<a href="https://ourworld.tf/" target="_blank" rel="noopener noreferrer" className="font-semibold hover:text-cyan-500 transition-colors">
|
||||
OurWorld
|
||||
</a>{' '}
|
||||
{new Date().getFullYear()}. All rights reserved.
|
||||
</p>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useState } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Container } from './Container'
|
||||
import { Button } from './Button'
|
||||
import pmyceliumLogo from '../images/logos/logo_1.png'
|
||||
import pmyceliumLogo from '../images/logos/mainlogo.svg'
|
||||
import { Dialog } from '@headlessui/react'
|
||||
import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline'
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useState } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Container } from './Container'
|
||||
import { Button } from './Button'
|
||||
import pmyceliumLogo from '../images/logos/logo_1.png'
|
||||
import pmyceliumLogo from '../images/logos/mainlogo.svg'
|
||||
import { Dialog } from '@headlessui/react'
|
||||
import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline'
|
||||
|
||||
|
||||
@@ -1,8 +1,42 @@
|
||||
import { useEffect } from 'react'
|
||||
import { Outlet } from 'react-router-dom'
|
||||
import { Footer } from './Footer'
|
||||
import { Header } from './Header'
|
||||
|
||||
export function Layout() {
|
||||
useEffect(() => {
|
||||
if (typeof window === 'undefined') return
|
||||
|
||||
if (document.getElementById('mailerlite-universal')) return
|
||||
|
||||
const script = document.createElement('script')
|
||||
script.id = 'mailerlite-universal'
|
||||
script.innerHTML = `
|
||||
(function(m,a,i,l,e,r){
|
||||
m['MailerLiteObject']=e;
|
||||
function f(){
|
||||
var c={a:arguments,q:[]};
|
||||
var r=this.push(c);
|
||||
return "number"!=typeof r?r:f.bind(c.q);
|
||||
}
|
||||
f.q=f.q||[];
|
||||
m[e]=m[e]||f.bind(f.q);
|
||||
m[e].q=m[e].q||f.q;
|
||||
r=a.createElement(i);
|
||||
var _=a.getElementsByTagName(i)[0];
|
||||
r.async=1;
|
||||
r.src=l+'?v'+(~~(new Date().getTime()/1000000));
|
||||
_.parentNode.insertBefore(r,_);
|
||||
})(window, document, 'script', 'https://static.mailerlite.com/js/universal.js', 'ml');
|
||||
window.ml_account = ml('accounts', '1778010', 'x2d3d9f8n1', 'load');
|
||||
`
|
||||
|
||||
document.body.appendChild(script)
|
||||
|
||||
return () => {
|
||||
script.remove()
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="bg-[#fdfdfd] antialiased relative" style={{ fontFamily: 'var(--font-inter)' }}>
|
||||
|
||||
@@ -12,8 +12,8 @@ const colorVariants = {
|
||||
primary: 'text-gray-900',
|
||||
secondary: 'text-gray-600',
|
||||
light: 'text-gray-50',
|
||||
accent: 'text-cyan-500',
|
||||
cyan: 'text-cyan-50',
|
||||
accent: 'text-cyan-400',
|
||||
cyan: 'text-cyan-400',
|
||||
white: 'text-white',
|
||||
dark: 'text-gray-950',
|
||||
tertiary: 'text-gray-700',
|
||||
@@ -162,5 +162,5 @@ export const DownloadCardDescription = createTextComponent(
|
||||
'text-base/7 leading-normal tracking-normal'
|
||||
)
|
||||
|
||||
export const CT = createTextComponent('span', 'text-base lg:text-lg font-medium')
|
||||
export const CP = createTextComponent('p', 'text-sm lg:text-base tracking-wide leading-tight font-light')
|
||||
export const CT = createTextComponent('span', 'text-base lg:text-lg leading-normal font-medium')
|
||||
export const CP = createTextComponent('p', 'text-sm lg:text-base tracking-wide leading-normal font-light')
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
|
||||
export const InfiniteMovingCards = ({
|
||||
items,
|
||||
direction = "left",
|
||||
speed = "fast",
|
||||
speed = "slow",
|
||||
pauseOnHover = true,
|
||||
className,
|
||||
}: {
|
||||
@@ -15,43 +15,39 @@ export const InfiniteMovingCards = ({
|
||||
speed?: "fast" | "normal" | "slow";
|
||||
pauseOnHover?: boolean;
|
||||
className?: string;
|
||||
}): JSX.Element => {
|
||||
const containerRef = React.useRef<HTMLDivElement>(null);
|
||||
const scrollerRef = React.useRef<HTMLUListElement>(null);
|
||||
const [start, setStart] = useState(false);
|
||||
|
||||
|
||||
const getSpeed = useCallback(() => {
|
||||
if (containerRef.current) {
|
||||
if (speed === "fast") {
|
||||
containerRef.current.style.setProperty("--animation-duration", "20s");
|
||||
} else if (speed === "normal") {
|
||||
containerRef.current.style.setProperty("--animation-duration", "40s");
|
||||
} else {
|
||||
containerRef.current.style.setProperty("--animation-duration", "80s");
|
||||
}
|
||||
}
|
||||
}, [speed]);
|
||||
|
||||
const addAnimation = useCallback(() => {
|
||||
if (containerRef.current && scrollerRef.current) {
|
||||
const scrollerContent = Array.from(scrollerRef.current.children);
|
||||
|
||||
scrollerContent.forEach((item) => {
|
||||
const duplicatedItem = item.cloneNode(true);
|
||||
if (scrollerRef.current) {
|
||||
scrollerRef.current.appendChild(duplicatedItem);
|
||||
}
|
||||
});
|
||||
|
||||
getSpeed();
|
||||
setStart(true);
|
||||
}
|
||||
}, [getSpeed]);
|
||||
}) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const scrollerRef = useRef<HTMLUListElement>(null);
|
||||
const [isReady, setIsReady] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
addAnimation();
|
||||
}, [addAnimation]);
|
||||
if (!scrollerRef.current) return;
|
||||
|
||||
const children = Array.from(scrollerRef.current.children);
|
||||
|
||||
// duplicate each item ONCE
|
||||
children.forEach((item) => {
|
||||
const clone = item.cloneNode(true);
|
||||
scrollerRef.current!.appendChild(clone);
|
||||
});
|
||||
|
||||
// set speed variable
|
||||
const duration =
|
||||
speed === "fast" ? "20s" : speed === "normal" ? "40s" : "80s";
|
||||
|
||||
containerRef.current?.style.setProperty(
|
||||
"--animation-duration",
|
||||
duration
|
||||
);
|
||||
|
||||
// set direction variable
|
||||
containerRef.current?.style.setProperty(
|
||||
"--animation-direction",
|
||||
direction === "left" ? "forwards" : "reverse"
|
||||
);
|
||||
|
||||
setIsReady(true);
|
||||
}, [direction, speed]);
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -61,16 +57,16 @@ export const InfiniteMovingCards = ({
|
||||
<ul
|
||||
ref={scrollerRef}
|
||||
className={cn(
|
||||
"flex min-w-full shrink-0 gap-16 py-4 w-max flex-nowrap",
|
||||
start && "animate-scroll",
|
||||
pauseOnHover && "hover:[animation-play-state:paused]",
|
||||
"flex w-max shrink-0 gap-16 py-4",
|
||||
isReady &&
|
||||
(direction === "left"
|
||||
? "animate-infinite-scroll"
|
||||
: "animate-infinite-scroll-right"),
|
||||
pauseOnHover && "hover:[animation-play-state:paused]"
|
||||
)}
|
||||
style={{
|
||||
"--animation-direction": direction === "left" ? "forwards" : "reverse",
|
||||
} as React.CSSProperties}
|
||||
>
|
||||
{items.map((item, idx) => (
|
||||
<li className="relative flex-shrink-0" key={idx}>
|
||||
{items.map((item, i) => (
|
||||
<li key={i} className="flex-shrink-0">
|
||||
{item}
|
||||
</li>
|
||||
))}
|
||||
|
||||
122
src/components/ui/DynamicMapContainer.tsx
Normal file
@@ -0,0 +1,122 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import WorldMap from './world-map';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
// Interface for the simplified data passed to WorldMap
|
||||
interface GeoNode {
|
||||
lat: number;
|
||||
lng: number;
|
||||
label?: string;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
// Interface for the raw data structure expected from the gridproxy API
|
||||
interface RawNode {
|
||||
node_id: number;
|
||||
location: {
|
||||
latitude: string; // API often returns these as strings
|
||||
longitude: string; // API often returns these as strings
|
||||
city: string;
|
||||
country: string;
|
||||
};
|
||||
// ... other raw fields you don't need
|
||||
}
|
||||
|
||||
const clusterNodes = (nodeList: GeoNode[], cellSize = 2) => {
|
||||
const buckets = new Map<
|
||||
string,
|
||||
{ latSum: number; lngSum: number; count: number }
|
||||
>();
|
||||
|
||||
nodeList.forEach((node) => {
|
||||
const latBucket = Math.round(node.lat / cellSize) * cellSize;
|
||||
const lngBucket = Math.round(node.lng / cellSize) * cellSize;
|
||||
const key = `${latBucket}|${lngBucket}`;
|
||||
|
||||
const bucket = buckets.get(key);
|
||||
if (bucket) {
|
||||
bucket.latSum += node.lat;
|
||||
bucket.lngSum += node.lng;
|
||||
bucket.count += 1;
|
||||
} else {
|
||||
buckets.set(key, {
|
||||
latSum: node.lat,
|
||||
lngSum: node.lng,
|
||||
count: 1,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return Array.from(buckets.values()).map((bucket) => {
|
||||
const avgLat = bucket.latSum / bucket.count;
|
||||
const avgLng = bucket.lngSum / bucket.count;
|
||||
const count = bucket.count;
|
||||
|
||||
let color = "#06b6d4";
|
||||
if (count > 20) {
|
||||
color = "#0891b2";
|
||||
} else if (count > 5) {
|
||||
color = "#22d3ee";
|
||||
}
|
||||
|
||||
return {
|
||||
lat: avgLat,
|
||||
lng: avgLng,
|
||||
color,
|
||||
label: `${count} nodes`,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
function DynamicMapContainer() {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [nodes, setNodes] = useState<GeoNode[]>([]);
|
||||
const API_URL = "https://gridproxy.grid.tf/nodes?healthy=true&size=500";
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchNodeData() {
|
||||
try {
|
||||
const response = await fetch(API_URL);
|
||||
const data: RawNode[] = await response.json();
|
||||
|
||||
const geoNodes: GeoNode[] = data
|
||||
.filter((node: RawNode) => node.location && node.location.latitude && node.location.longitude)
|
||||
.map((node: RawNode) => ({
|
||||
lat: parseFloat(node.location.latitude),
|
||||
lng: parseFloat(node.location.longitude),
|
||||
label: `${node.location.city}, ${node.location.country} (${node.node_id})`,
|
||||
}));
|
||||
|
||||
const clusteredNodes = clusterNodes(geoNodes);
|
||||
setNodes(clusteredNodes);
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch node data:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
fetchNodeData();
|
||||
}, []);
|
||||
|
||||
// While fetching, show a loading state
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex justify-center items-center w-full aspect-[2/1] bg-[#111111] rounded-lg text-cyan-500">
|
||||
<motion.span
|
||||
animate={{ rotate: 360 }}
|
||||
transition={{ duration: 1, repeat: Infinity, ease: "linear" }}
|
||||
className="text-4xl"
|
||||
>
|
||||
🌎
|
||||
</motion.span>
|
||||
<p className="ml-4">Loading nodes...</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// After data is loaded, render the map
|
||||
return <WorldMap nodes={nodes} />;
|
||||
}
|
||||
|
||||
export default DynamicMapContainer;
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useRef } from "react";
|
||||
import { motion } from "motion/react";
|
||||
import { motion } from "framer-motion";
|
||||
import DottedMap from "dotted-map";
|
||||
|
||||
interface MapProps {
|
||||
@@ -9,34 +9,39 @@ interface MapProps {
|
||||
start: { lat: number; lng: number; label?: string };
|
||||
end: { lat: number; lng: number; label?: string };
|
||||
}>;
|
||||
// New prop for dynamic standalone nodes
|
||||
nodes?: Array<{ lat: number; lng: number; label?: string; color?: string }>;
|
||||
lineColor?: string;
|
||||
}
|
||||
|
||||
export default function WorldMap({
|
||||
dots = [],
|
||||
lineColor = "#06b6d4", // cyan-500
|
||||
nodes = [],
|
||||
lineColor = "#06b6d4",
|
||||
}: MapProps) {
|
||||
const svgRef = useRef<SVGSVGElement>(null);
|
||||
|
||||
// ✅ Force dark-dotted map theme
|
||||
// ✅ Force dark-dotted map theme
|
||||
const map = new DottedMap({ height: 100, grid: "diagonal" });
|
||||
const svgMap = map.getSVG({
|
||||
radius: 0.22,
|
||||
color: "#06b6d480", // cyan-500 at 50% opacity
|
||||
color: "#06b6d480",
|
||||
shape: "circle",
|
||||
backgroundColor: "#111111",
|
||||
});
|
||||
|
||||
// ✅ Point projection stays the same
|
||||
// ✅ Point projection stays the same
|
||||
// Projects lat/lng to the SVG's 800x400 viewBox coordinates
|
||||
const projectPoint = (lat: number, lng: number) => {
|
||||
const x = (lng + 180) * (800 / 360);
|
||||
const y = (90 - lat) * (400 / 180);
|
||||
const y = (90 - lat) * (400 / 180) + 45;
|
||||
return { x, y };
|
||||
};
|
||||
|
||||
const createCurvedPath = (start: any, end: any) => {
|
||||
const midX = (start.x + end.x) / 2;
|
||||
const midY = Math.min(start.y, end.y) - 50;
|
||||
// Creates an arc that bows upward by 50 units
|
||||
const midY = Math.min(start.y, end.y) - 50;
|
||||
return `M ${start.x} ${start.y} Q ${midX} ${midY} ${end.x} ${end.y}`;
|
||||
};
|
||||
|
||||
@@ -49,13 +54,53 @@ export default function WorldMap({
|
||||
draggable={false}
|
||||
/>
|
||||
|
||||
{/* ✅ Lines + points */}
|
||||
{/* ✅ Lines + points + new standalone nodes */}
|
||||
<svg
|
||||
ref={svgRef}
|
||||
viewBox="0 0 800 400"
|
||||
className="w-full h-full absolute inset-0 pointer-events-none select-none"
|
||||
>
|
||||
{/* ✅ animated curved travel lines */}
|
||||
{/* Glowing path gradient DEFS */}
|
||||
<defs>
|
||||
<linearGradient id="path-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" stopColor="black" stopOpacity="0" />
|
||||
<stop offset="5%" stopColor={lineColor} stopOpacity="1" />
|
||||
<stop offset="95%" stopColor={lineColor} stopOpacity="1" />
|
||||
<stop offset="100%" stopColor="black" stopOpacity="0" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
{/* ✅ DYNAMIC STANDALONE NODE DOTS (New Section) */}
|
||||
{nodes.map((node, i) => {
|
||||
const p = projectPoint(node.lat, node.lng);
|
||||
const dotColor = node.color || lineColor;
|
||||
|
||||
return (
|
||||
<g key={`node-${i}`}>
|
||||
{/* Outer pulsing circle */}
|
||||
<circle cx={p.x} cy={p.y} r="2" fill={dotColor} opacity="0.5">
|
||||
<animate
|
||||
attributeName="r"
|
||||
from="2"
|
||||
to="7"
|
||||
dur="1.4s"
|
||||
repeatCount="indefinite"
|
||||
/>
|
||||
<animate
|
||||
attributeName="opacity"
|
||||
from="0.6"
|
||||
to="0"
|
||||
dur="1.4s"
|
||||
repeatCount="indefinite"
|
||||
/>
|
||||
</circle>
|
||||
{/* Inner fixed circle */}
|
||||
<circle cx={p.x} cy={p.y} r="2" fill={dotColor} />
|
||||
</g>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* ✅ Animated curved travel lines (Existing Logic) */}
|
||||
{dots.map((dot, i) => {
|
||||
const startPoint = projectPoint(dot.start.lat, dot.start.lng);
|
||||
const endPoint = projectPoint(dot.end.lat, dot.end.lng);
|
||||
@@ -78,17 +123,7 @@ export default function WorldMap({
|
||||
);
|
||||
})}
|
||||
|
||||
{/* ✅ glowing path gradient */}
|
||||
<defs>
|
||||
<linearGradient id="path-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" stopColor="black" stopOpacity="0" />
|
||||
<stop offset="5%" stopColor={lineColor} stopOpacity="1" />
|
||||
<stop offset="95%" stopColor={lineColor} stopOpacity="1" />
|
||||
<stop offset="100%" stopColor="black" stopOpacity="0" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
{/* ✅ start & end points with pulsing cyan glow */}
|
||||
{/* ✅ Start & end points with pulsing cyan glow (Existing Logic) */}
|
||||
{dots.map((dot, i) => {
|
||||
const s = projectPoint(dot.start.lat, dot.start.lng);
|
||||
const e = projectPoint(dot.end.lat, dot.end.lng);
|
||||
@@ -122,4 +157,4 @@ export default function WorldMap({
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
1
src/images/logos/logomark.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="77" zoomAndPan="magnify" viewBox="0 0 57.75 54" height="72" preserveAspectRatio="xMidYMid meet" version="1.0"><defs><clipPath id="6b820d2194"><path d="M 0.402344 0 L 57.101562 0 L 57.101562 6 L 0.402344 6 Z M 0.402344 0 " clip-rule="nonzero"/></clipPath><clipPath id="3794aac157"><path d="M 0.402344 23 L 57 23 L 57 30 L 0.402344 30 Z M 0.402344 23 " clip-rule="nonzero"/></clipPath><clipPath id="a8068b094c"><path d="M 0.402344 46 L 57.101562 46 L 57.101562 53 L 0.402344 53 Z M 0.402344 46 " clip-rule="nonzero"/></clipPath></defs><g clip-path="url(#6b820d2194)"><path stroke-linecap="butt" transform="matrix(0.736364, 0, 0, 0.736364, 0.402273, 0.00000196364)" fill="none" stroke-linejoin="miter" d="M 0.000096737 3.999805 L 76.537522 3.999805 " stroke="#43d7ff" stroke-width="8" stroke-opacity="1" stroke-miterlimit="4"/></g><g clip-path="url(#3794aac157)"><path fill="#43d7ff" d="M 0.402344 23.136719 L 35.746094 23.136719 L 35.746094 29.027344 L 0.402344 29.027344 M 41.636719 23.136719 L 56.761719 23.136719 L 56.761719 29.027344 L 41.636719 29.027344 " fill-opacity="1" fill-rule="nonzero"/></g><g clip-path="url(#a8068b094c)"><path stroke-linecap="butt" transform="matrix(0.736364, 0, 0, 0.736364, 0.402273, 46.951043)" fill="none" stroke-linejoin="miter" d="M 0.000096737 4.002635 L 76.537522 4.002635 " stroke="#43d7ff" stroke-width="8" stroke-opacity="1" stroke-miterlimit="4"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
1
src/images/logos/mainlogo.svg
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
@@ -23,7 +23,7 @@ const bentos: {
|
||||
{
|
||||
id: "core",
|
||||
eyebrow: "ARCHITECTURE",
|
||||
title: "Augmented Intelligence Fabric",
|
||||
title: "Intelligence Fabric",
|
||||
description:
|
||||
"The sovereign substrate for autonomous AI. Stateless, geo-aware, end-to-end encrypted—and verifiable from intent to execution.",
|
||||
animation: null,
|
||||
@@ -123,7 +123,7 @@ export function AgentBento() {
|
||||
<div className="w-full h-full object-cover"><card.animation /></div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="h-48 w-full flex items-center justify-center bg-transparent" />
|
||||
<div className="hidden md:flex md:h-48 w-full items-center justify-center bg-transparent" />
|
||||
)}
|
||||
|
||||
<div className="px-8 pt-4 pb-6">
|
||||
@@ -136,7 +136,7 @@ export function AgentBento() {
|
||||
) : (
|
||||
<>
|
||||
{/* ✅ NEW SUBTITLE */}
|
||||
<p className="text-sm text-cyan-400">{card.subtitle}</p>
|
||||
<p className="text-sm text-cyan-500">{card.subtitle}</p>
|
||||
|
||||
<p className="mt-1 text-lg font-medium lg:text-xl tracking-tight text-white">
|
||||
{card.title}
|
||||
@@ -161,6 +161,9 @@ export function AgentBento() {
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{/* ✅ Bottom horizontal line with spacing */}
|
||||
<div className="w-full border-b border-gray-800" />
|
||||
<div className="max-w-7xl bg-transparent mx-auto py-6 border border-t-0 border-b-0 border-gray-800"></div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use client'
|
||||
|
||||
import { Button } from '@/components/Button'
|
||||
import { Eyebrow, H3, P } from '@/components/Texts'
|
||||
|
||||
export function AgentHeroAlt() {
|
||||
@@ -8,28 +7,32 @@ export function AgentHeroAlt() {
|
||||
<div className="">
|
||||
{/* Boxed container */}
|
||||
<div
|
||||
className="relative mx-auto max-w-7xl border border-t-0 border-b-0 border-gray-100 bg-white overflow-hidden bg-contain bg-right bg-no-repeat"
|
||||
style={{ backgroundImage: "url('/images/agents.webp')", backgroundSize: "contain" }}
|
||||
className="relative mx-auto max-w-7xl border border-t-0 border-b-0 border-gray-100 bg-white overflow-hidden md:bg-[url('/images/agents.webp')] md:bg-contain md:bg-right md:bg-no-repeat"
|
||||
>
|
||||
{/* Inner padding */}
|
||||
<div className="px-6 py-16 lg:py-16">
|
||||
<div className="max-w-2xl lg:pl-6">
|
||||
<div className="px-6 pt-4 pb-12 lg:py-24">
|
||||
{/* Mobile-only hero image */}
|
||||
<img
|
||||
src="/images/mobile/agents.jpg"
|
||||
alt="Mycelium Agents visual"
|
||||
className="mb-8 w-full object-cover md:hidden"
|
||||
/>
|
||||
|
||||
<div className="max-w-xl lg:pl-6">
|
||||
<Eyebrow>MYCELIUM AGENTS - COMING IN 2026</Eyebrow>
|
||||
<H3 as="h1" className="mt-4">
|
||||
Private, Sovereign and Distributed AI You Control
|
||||
</H3>
|
||||
<P className="mt-6 text-gray-800">
|
||||
<P className="mt-6 text-gray-600">
|
||||
Mycelium Agents let you deploy and run intelligent systems on your own infrastructure.
|
||||
</P>
|
||||
<P className="mt-4 text-gray-600">
|
||||
Private, local, and autonomous by design, they give you everything you need to build, host, and connect AI agents without relying on centralized clouds.
|
||||
</P>
|
||||
|
||||
<div className="mt-10 flex items-center gap-x-6">
|
||||
<Button href="#" variant="solid" color="cyan">
|
||||
Follow Development
|
||||
</Button>
|
||||
<Button href="#" variant="outline">
|
||||
Explore Docs <span aria-hidden="true">→</span>
|
||||
</Button>
|
||||
{/* TODO: Hero CTAs (Follow Development / Explore Docs) to be added when links are ready.
|
||||
Previously two Buttons here with href="#". */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
90
src/pages/agents/AgentPro.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import { Small } from "@/components/Texts";
|
||||
import { Eyebrow, H3, P } from "@/components/Texts";
|
||||
|
||||
const highlights = [
|
||||
{
|
||||
label: "Local Execution",
|
||||
title: "Agents run entirely inside your environment.",
|
||||
description:
|
||||
"Models, logic, and memory stay within your own trusted hardware, never behind third-party APIs.",
|
||||
},
|
||||
{
|
||||
label: "Mesh Connectivity",
|
||||
title: "They communicate peer-to-peer across trusted nodes.",
|
||||
description:
|
||||
"Agents form direct encrypted paths between environments, without relays or central servers.",
|
||||
},
|
||||
{
|
||||
label: "Private Data Access",
|
||||
title: "They use your data without sending it elsewhere.",
|
||||
description:
|
||||
"Your datasets, embeddings, and context never leave your boundaries. Processing stays local.",
|
||||
},
|
||||
{
|
||||
label: "Portability",
|
||||
title: "They move with you, not with a cloud provider.",
|
||||
description:
|
||||
"Agents follow your devices, networks, and workflows, remaining sovereign across every location.",
|
||||
},
|
||||
];
|
||||
|
||||
export function AgentPro() {
|
||||
return (
|
||||
<section className="relative w-full bg-[#FDFDFD] overflow-hidden">
|
||||
{/* Top spacing line */}
|
||||
<div className="max-w-7xl bg-[#FDFDFD] mx-auto py-6 border border-t-0 border-b-0 border-gray-100"></div>
|
||||
<div className="w-full border-t border-l border-r border-gray-100" />
|
||||
|
||||
{/* Intro Block */}
|
||||
<div className="bg-white w-full max-w-7xl mx-auto border border-t-0 border-b-0 border-gray-100">
|
||||
<div className="px-8 py-12 max-w-4xl mx-auto flex flex-col items-center justify-center min-h-[220px] text-center">
|
||||
<Eyebrow className="text-cyan-500">
|
||||
Advantages
|
||||
</Eyebrow>
|
||||
|
||||
<H3 className="mt-4 text-black">
|
||||
Why It’s Different
|
||||
</H3>
|
||||
|
||||
<P className="mt-4 text-gray-700 text-base leading-relaxed">
|
||||
Most AI systems run on centralized clouds, where the models, data, and
|
||||
logic operate behind third-party APIs. Mycelium Agents flip that
|
||||
architecture, it runs entirely inside your environment so control,
|
||||
privacy, and autonomy stay with you.
|
||||
</P>
|
||||
</div>
|
||||
|
||||
{/* Grid */}
|
||||
<div className="grid lg:grid-cols-4">
|
||||
{highlights.map((item) => (
|
||||
<div
|
||||
key={item.title}
|
||||
className="group relative overflow-hidden border border-gray-100 bg-white p-8 transition hover:border-cyan-400/40 hover:bg-white"
|
||||
>
|
||||
{/* Glow */}
|
||||
<div className="absolute inset-0 bg-linear-to-br from-cyan-200/0 via-cyan-100/20 to-cyan-300/20 opacity-0 transition group-hover:opacity-100" />
|
||||
|
||||
<div className="relative">
|
||||
<Small className="text-xs uppercase tracking-[0.16em] text-cyan-600">
|
||||
{item.label}
|
||||
</Small>
|
||||
|
||||
<h3 className="mt-4 text-lg font-semibold leading-tight text-black">
|
||||
{item.title}
|
||||
</h3>
|
||||
|
||||
<p className="mt-4 text-base leading-relaxed text-gray-600">
|
||||
{item.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom spacing */}
|
||||
<div className="w-full border-b border-gray-100 bg-[#FDFDFD]" />
|
||||
<div className="max-w-7xl mx-auto py-6 border border-t-0 border-b-0 border-gray-100" />
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useRef } from "react";
|
||||
import { Eyebrow, SectionHeader, P } from "@/components/Texts";
|
||||
import { IoArrowBackOutline, IoArrowForwardOutline } from "react-icons/io5";
|
||||
|
||||
import { Eyebrow, P, CT, CP, H3} from "@/components/Texts";
|
||||
import {
|
||||
CpuChipIcon,
|
||||
GlobeAltIcon,
|
||||
@@ -23,7 +20,7 @@ const networkUseCases = [
|
||||
{
|
||||
title: "Run agents on your own hardware",
|
||||
description:
|
||||
"Deploy AI processes on laptops, homelabs, edge nodes, or full clusters — no cloud dependency.",
|
||||
"Deploy AI processes on laptops, homelabs, edge nodes, or full clusters with no cloud dependency.",
|
||||
icon: CpuChipIcon,
|
||||
},
|
||||
{
|
||||
@@ -50,98 +47,74 @@ const networkUseCases = [
|
||||
"Run agents in sectors requiring strict data residency, verified identity, and controlled connectivity.",
|
||||
icon: ShieldCheckIcon,
|
||||
},
|
||||
{
|
||||
title: "Blend local + remote intelligence",
|
||||
description:
|
||||
"Let lightweight agents run locally while offloading heavy tasks to trusted nodes, maintaining privacy and performance balance.",
|
||||
icon: CpuChipIcon,
|
||||
},
|
||||
];
|
||||
|
||||
export function AgentUsecase() {
|
||||
const sliderRef = useRef<HTMLUListElement>(null);
|
||||
|
||||
const scrollLeft = () =>
|
||||
sliderRef.current?.scrollBy({ left: -400, behavior: "smooth" });
|
||||
|
||||
const scrollRight = () =>
|
||||
sliderRef.current?.scrollBy({ left: 400, behavior: "smooth" });
|
||||
|
||||
return (
|
||||
<section className="w-full max-w-8xl mx-auto bg-transparent">
|
||||
|
||||
{/* ✅ Top horizontal line with spacing */}
|
||||
<div className="max-w-7xl bg-transparent mx-auto py-6 border border-t-0 border-b-0 border-gray-100"></div>
|
||||
{/* Top horizontal spacing line */}
|
||||
<div className="max-w-7xl mx-auto py-6 border border-t-0 border-b-0 border-gray-100"></div>
|
||||
<div className="w-full border-t border-l border-r border-gray-100" />
|
||||
|
||||
<div className="relative mx-auto max-w-7xl border border-t-0 border-b-0 border-slate-200 bg-white overflow-hidden">
|
||||
|
||||
{/* Main framed section */}
|
||||
<div className="max-w-7xl bg-white mx-auto py-12 border border-t-0 border-b-0 border-gray-100">
|
||||
<div className="mx-auto max-w-3xl sm:text-center px-6 lg:px-8">
|
||||
{/* Intro block (from isIntro item) */}
|
||||
{networkUseCases[0].isIntro && (
|
||||
<>
|
||||
<Eyebrow className="text-cyan-500">{networkUseCases[0].eyebrow}</Eyebrow>
|
||||
<H3
|
||||
className="mt-4 text-gray-900"
|
||||
>
|
||||
{networkUseCases[0].title}
|
||||
</H3>
|
||||
<P className="mt-4 text-lg text-gray-600">
|
||||
{networkUseCases[0].description}
|
||||
</P>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Grid of features (excluding intro) */}
|
||||
<ul
|
||||
ref={sliderRef}
|
||||
className="flex overflow-x-auto snap-x snap-mandatory scroll-smooth no-scrollbar"
|
||||
role="list"
|
||||
className="mx-auto mt-8 max-w-6xl grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 md:gap-y-10 px-6"
|
||||
>
|
||||
{networkUseCases.map((item, idx) => (
|
||||
{networkUseCases.slice(1).map((item, idx) => (
|
||||
<li
|
||||
key={idx}
|
||||
className={`snap-start shrink-0 w-[85%] sm:w-[50%] lg:w-[33%]
|
||||
border border-slate-200 px-10 py-12 relative
|
||||
${item.isIntro ? "bg-gray-50/80" : "bg-white"}`}
|
||||
className="rounded-2xl border border-gray-200 p-8 transition-all duration-300 ease-in-out hover:scale-[1.03] hover:border-cyan-500 hover:shadow-lg hover:shadow-cyan-500/20 bg-white"
|
||||
>
|
||||
{/* INTRO CARD */}
|
||||
{item.isIntro ? (
|
||||
<div className="flex flex-col justify-between h-full">
|
||||
<div>
|
||||
<Eyebrow>{item.eyebrow}</Eyebrow>
|
||||
<SectionHeader
|
||||
as="h3"
|
||||
className="mt-4 text-gray-900 text-xl lg:text-2xl"
|
||||
>
|
||||
{item.title}
|
||||
</SectionHeader>
|
||||
<P className="mt-4 text-gray-600 text-sm lg:text-base">
|
||||
{item.description}
|
||||
</P>
|
||||
</div>
|
||||
|
||||
{/* slider buttons */}
|
||||
<div className="flex items-center gap-x-4 mt-6">
|
||||
<button
|
||||
onClick={scrollLeft}
|
||||
className="h-8 w-8 flex items-center justify-center
|
||||
border border-slate-300 rounded-md
|
||||
hover:border-cyan-500 transition-colors"
|
||||
>
|
||||
<IoArrowBackOutline className="text-gray-600" size={16} />
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={scrollRight}
|
||||
className="h-8 w-8 flex items-center justify-center
|
||||
border border-slate-300 rounded-md
|
||||
hover:border-cyan-500 transition-colors"
|
||||
>
|
||||
<IoArrowForwardOutline className="text-gray-600" size={16} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
/* REGULAR CARD */
|
||||
<div className="flex flex-col h-full">
|
||||
{item.icon && (
|
||||
<div className="h-12 w-12 flex items-center justify-center rounded-xl bg-gray-100 mb-6">
|
||||
<item.icon className="h-6 w-6 text-cyan-600" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<p className="text-lg font-semibold text-gray-900">
|
||||
{item.title}
|
||||
</p>
|
||||
|
||||
<p className="mt-2 text-gray-600 leading-snug">
|
||||
{item.description}
|
||||
</p>
|
||||
{/* Icon */}
|
||||
{item.icon && (
|
||||
<div className="h-10 w-10 mb-2 flex items-center justify-center rounded-xl bg-gray-100">
|
||||
<item.icon className="h-6 w-6 text-cyan-500" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Title */}
|
||||
<CT className="leading-normal text-gray-900">
|
||||
{item.title}
|
||||
</CT>
|
||||
|
||||
{/* Description */}
|
||||
<CP className="mt-2 text-gray-600 text-sm leading-snug">
|
||||
{item.description}
|
||||
</CP>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
{/* ✅ Bottom horizontal line with spacing */}
|
||||
<div className="w-full border-b border-gray-100" />
|
||||
<div className="max-w-7xl bg-transparent mx-auto py-6 border border-t-0 border-b-0 border-gray-100"></div>
|
||||
|
||||
{/* Bottom horizontal line */}
|
||||
<div className="w-full border-b border-gray-100" />
|
||||
<div className="max-w-7xl mx-auto py-6 border border-t-0 border-b-0 border-gray-100"></div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ import { AgentBento } from './AgentBento'
|
||||
import { AgentHeroAlt } from './AgentHeroAlt'
|
||||
import { CallToAction } from './CallToAction'
|
||||
import { AgentUsecase } from './AgentUseCase'
|
||||
import { AgentDesign } from './AgentDesign'
|
||||
|
||||
import { AgentPro } from './AgentPro'
|
||||
|
||||
export default function AgentsPage() {
|
||||
return (
|
||||
@@ -31,7 +32,7 @@ export default function AgentsPage() {
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<AgentDesign />
|
||||
<AgentPro />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
|
||||
@@ -13,7 +13,7 @@ export function CallToAction() {
|
||||
{/* ✅ Main boxed area */}
|
||||
<div
|
||||
id="get-started"
|
||||
className="relative py-18 max-w-7xl mx-auto bg-[#111111] border border-t-0 border-b-0 border-gray-800"
|
||||
className="relative py-18 max-w-7xl mx-auto overflow-hidden bg-[#111111] border border-t-0 border-b-0 border-gray-800"
|
||||
>
|
||||
{/* ✅ Cyan Radial Glow */}
|
||||
<svg
|
||||
@@ -26,7 +26,7 @@ export function CallToAction() {
|
||||
cx={512}
|
||||
cy={512}
|
||||
fill="url(#mycelium-cyan-glow)"
|
||||
fillOpacity="0.2"
|
||||
fillOpacity="0.3"
|
||||
/>
|
||||
<defs>
|
||||
<radialGradient id="mycelium-cyan-glow">
|
||||
@@ -41,32 +41,42 @@ export function CallToAction() {
|
||||
Start with Mycelium Today
|
||||
</h2>
|
||||
|
||||
<p className="mt-6 text-lg text-gray-300">
|
||||
<p className="mt-6 lg:text-lg text-base leading-normal text-gray-300">
|
||||
The Agent Framework launches in H1 2026, but the foundation is ready now.
|
||||
</p>
|
||||
<p className="mt-6 text-lg text-gray-300">
|
||||
<p className="mt-2 lg:text-lg text-base leading-normal text-gray-300">
|
||||
Use today’s components —models, storage, compute, and network— to deploy workloads, connect nodes, and prepare for the next generation of distributed AI.
|
||||
</p>
|
||||
|
||||
{/* ✅ Two cards, stacked center with spacing */}
|
||||
<div className="mt-10 flex flex-wrap justify-center gap-x-10 gap-y-8">
|
||||
<div className="flex flex-col items-center text-center max-w-xs">
|
||||
<Button to="/deploy" variant="solid" color="cyan" className="mt-4">
|
||||
Deploy a Model
|
||||
</Button>
|
||||
</div>
|
||||
{/* ✅ Button row – same structure as homepage CTA */}
|
||||
<div className="mt-10 flex flex-wrap justify-center items-center gap-x-6 gap-y-4">
|
||||
<Button
|
||||
as="a"
|
||||
to="https://myceliumcloud.tf"
|
||||
variant="solid"
|
||||
color="cyan"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Deploy a Model
|
||||
</Button>
|
||||
|
||||
<div className="flex flex-col items-center text-center max-w-xs">
|
||||
<Button to="/host" as="a" variant="outline" color="white" className="mt-4">
|
||||
Host a Node
|
||||
</Button>
|
||||
</div>
|
||||
<Button to="/nodes" variant="outline" color="white">
|
||||
Host a Node
|
||||
</Button>
|
||||
|
||||
<div className="flex flex-col items-center text-center max-w-xs">
|
||||
<Button to="https://threefold.info/mycelium_network/docs/" as="a" target="_blank" variant="outline" color="white" className="mt-4">
|
||||
Follow Development
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
as="a"
|
||||
to="https://threefold.info/mycelium_network/docs/"
|
||||
variant="link"
|
||||
color="white"
|
||||
className="inline-flex items-center gap-1.5"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Follow Development
|
||||
<span aria-hidden="true">→</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useEffect, useMemo, useState } from 'react'
|
||||
import { useResponsiveCarousel } from '@/hooks/useResponsiveCarousel';
|
||||
import { motion, AnimatePresence } from 'framer-motion'
|
||||
import { wrap } from 'popmotion'
|
||||
import { Button } from '@/components/Button';
|
||||
import { SectionHeader, P, Eyebrow, CP } from '@/components/Texts';
|
||||
import { TypeAnimation } from 'react-type-animation'
|
||||
import { FadeIn } from '@/components/FadeIn';
|
||||
@@ -147,9 +146,8 @@ export function GallerySection() {
|
||||
repeat={0}
|
||||
/>
|
||||
</CP>
|
||||
<Button href="#" color="cyan" className="text-sm px-4 py-2 lg:text-base whitespace-nowrap">
|
||||
Start
|
||||
</Button>
|
||||
{/* TODO: Desktop CTA (Start) button to be added when link target is defined.
|
||||
Previously: <Button href="#" color="cyan">Start</Button> */}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -166,9 +164,8 @@ export function GallerySection() {
|
||||
repeat={0}
|
||||
/>
|
||||
</CP>
|
||||
<Button href="#" color="cyan" className="text-xs px-3 py-1.5 whitespace-nowrap">
|
||||
Start
|
||||
</Button>
|
||||
{/* TODO: Mobile CTA (Start) button to be added when link target is defined.
|
||||
Previously: <Button href="#" color="cyan">Start</Button> */}
|
||||
</div>
|
||||
</div>
|
||||
</FadeIn>
|
||||
|
||||
@@ -132,7 +132,7 @@ export default function AgentCoordination({
|
||||
aria-label="Agent coordination and sovereign workflow management"
|
||||
style={{ background: bg }}
|
||||
>
|
||||
<svg viewBox={`0 0 ${W} ${H}`} className="w-full h-full" preserveAspectRatio="xMidYMid slice">
|
||||
<svg viewBox={`0 0 ${W} ${H}`} className="w-full h-full lg:-translate-y-6" preserveAspectRatio="xMidYMid slice">
|
||||
|
||||
{/* background */}
|
||||
<defs>
|
||||
|
||||
@@ -103,7 +103,7 @@ export default function DeterministicExecution({
|
||||
aria-label="Deterministic deployment and verifiable code execution"
|
||||
style={{ background: bg }}
|
||||
>
|
||||
<svg viewBox={`0 0 ${W} ${H}`} className="w-full h-full" preserveAspectRatio="xMidYMid slice">
|
||||
<svg viewBox={`0 0 ${W} ${H}`} className="w-full h-full lg:-translate-y-6" preserveAspectRatio="xMidYMid slice">
|
||||
|
||||
{/* background grid */}
|
||||
<defs>
|
||||
|
||||
@@ -123,10 +123,10 @@ export default function FungiStor({
|
||||
className={clsx("relative overflow-hidden", className)}
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
aria-label="FungiStor — distributed long-term AI memory"
|
||||
aria-label="FungiStor, a distributed long-term AI memory"
|
||||
style={{ background: bg }}
|
||||
>
|
||||
<svg viewBox={`0 0 ${W} ${H}`} className="w-full h-full" preserveAspectRatio="xMidYMid slice">
|
||||
<svg viewBox={`0 0 ${W} ${H}`} className="w-full h-full lg:-translate-y-16" preserveAspectRatio="xMidYMid slice">
|
||||
{/* Background grid */}
|
||||
<defs>
|
||||
<pattern id="grid-dark" width="28" height="28" patternUnits="userSpaceOnUse">
|
||||
|
||||
@@ -175,10 +175,10 @@ export default function Herodb({
|
||||
className={clsx("relative overflow-hidden", className)}
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
aria-label="HeroDB — active AI memory retrieval"
|
||||
aria-label="HeroDB, active AI memory retrieval"
|
||||
style={{ background: bg }}
|
||||
>
|
||||
<svg viewBox={`0 0 ${W} ${H}`} className="w-full h-full" preserveAspectRatio="xMidYMid slice">
|
||||
<svg viewBox={`0 0 ${W} ${H}`} className="w-full h-full lg:-translate-y-18" preserveAspectRatio="xMidYMid slice">
|
||||
{/* Background grid */}
|
||||
<defs>
|
||||
<pattern id="grid-dark" width="28" height="28" patternUnits="userSpaceOnUse">
|
||||
|
||||
@@ -124,7 +124,7 @@ export default function MOSSandboxes({
|
||||
aria-label="MOS Secure Agent Sandboxes"
|
||||
style={{ background: bg }}
|
||||
>
|
||||
<svg viewBox={`0 0 ${W} ${H}`} className="w-full h-full" preserveAspectRatio="xMidYMid slice">
|
||||
<svg viewBox={`0 0 ${W} ${H}`} className="w-full h-full lg:-translate-y-16" preserveAspectRatio="xMidYMid slice">
|
||||
{/* BACKGROUND GRID */}
|
||||
<defs>
|
||||
<pattern id="grid-dark" width="28" height="28" patternUnits="userSpaceOnUse">
|
||||
|
||||
@@ -142,10 +142,10 @@ export default function MyceliumMesh({
|
||||
)}
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
aria-label="Mycelium Mesh — secure communication network"
|
||||
aria-label="Mycelium Mesh, a secure communication network"
|
||||
style={{ background: bg }}
|
||||
>
|
||||
<svg viewBox={`0 0 ${W} ${H}`} className="w-full h-full" preserveAspectRatio="xMidYMid slice">
|
||||
<svg viewBox={`0 0 ${W} ${H}`} className="w-full h-full lg:-translate-y-4" preserveAspectRatio="xMidYMid slice">
|
||||
{/* Background grid */}
|
||||
<defs>
|
||||
<pattern id="grid-dark" width="28" height="28" patternUnits="userSpaceOnUse">
|
||||
|
||||
@@ -13,7 +13,7 @@ export function CallToAction() {
|
||||
{/* ✅ Main boxed area */}
|
||||
<div
|
||||
id="get-started"
|
||||
className="relative py-18 max-w-7xl mx-auto bg-[#111111] border border-t-0 border-b-0 border-gray-800"
|
||||
className="relative py-18 max-w-7xl overflow-hidden mx-auto bg-[#111111] border border-t-0 border-b-0 border-gray-800"
|
||||
>
|
||||
{/* ✅ Cyan Radial Glow */}
|
||||
<svg
|
||||
@@ -26,7 +26,7 @@ export function CallToAction() {
|
||||
cx={512}
|
||||
cy={512}
|
||||
fill="url(#mycelium-cyan-glow)"
|
||||
fillOpacity="0.2"
|
||||
fillOpacity="0.3"
|
||||
/>
|
||||
<defs>
|
||||
<radialGradient id="mycelium-cyan-glow">
|
||||
@@ -52,13 +52,21 @@ export function CallToAction() {
|
||||
{/* ✅ Two cards, stacked center with spacing */}
|
||||
<div className="mt-10 flex flex-wrap justify-center gap-x-10 gap-y-8">
|
||||
<div className="flex flex-col items-center text-center max-w-xs">
|
||||
<Button to="/host" variant="solid" color="cyan" className="mt-4">
|
||||
<Button to="/nodes" variant="solid" color="cyan" className="mt-4">
|
||||
Host a Node
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center text-center max-w-xs">
|
||||
<Button to="/cloud" variant="outline" color="white" className="mt-4">
|
||||
<Button
|
||||
as="a"
|
||||
to="https://myceliumcloud.tf"
|
||||
variant="outline"
|
||||
color="white"
|
||||
className="mt-4"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Start Deploying
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -40,7 +40,7 @@ export function CloudArchitecture() {
|
||||
<div className="relative mx-auto max-w-7xl border border-t-0 border-b-0 border-gray-800 bg-[#111111] py-12">
|
||||
<Container>
|
||||
<div className="mx-auto max-w-4xl sm:text-center">
|
||||
<Eyebrow className="text-cyan-400">ARCHITECTURE</Eyebrow>
|
||||
<Eyebrow className="">ARCHITECTURE</Eyebrow>
|
||||
|
||||
<H3 className="text-3xl lg:text-4xl font-medium tracking-tight text-white">
|
||||
How Mycelium Cloud Works
|
||||
|
||||
@@ -20,14 +20,14 @@ export function CloudBluePrint() {
|
||||
<div className="max-w-7xl bg-white mx-auto py-12 border border-t-0 border-b-0 border-gray-100">
|
||||
<Container>
|
||||
<div className="mx-auto max-w-4xl sm:text-center">
|
||||
<Eyebrow className="text-cyan-500">Featured Blueprint</Eyebrow>
|
||||
<Eyebrow className="text-cyan-400">Featured Blueprint</Eyebrow>
|
||||
|
||||
<H3 className="text-3xl lg:text-4xl font-medium tracking-tight text-gray-900 mt-2">
|
||||
Your Personal Sovereign Cloud Workspace
|
||||
</H3>
|
||||
|
||||
<P className="mt-6 text-lg text-gray-600">
|
||||
Digital Me is an example environment built to demonstrate what’s possible on top of the Mycelium Stack — a full personal cloud you can deploy, customize, or extend. Your files, communication, apps, and optional AI agent, all running privately on infrastructure you choose.
|
||||
Digital Me is an example environment built to demonstrate what’s possible on top of the Mycelium Stack, which is a full personal cloud you can deploy, customize, or extend. Your files, communication, apps, and optional AI agent, all running privately on infrastructure you choose.
|
||||
</P>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -254,8 +254,8 @@ function CloudFeaturesDesktop() {
|
||||
className={clsx(
|
||||
'relative rounded-2xl outline-2 transition-all duration-300 ease-in-out hover:scale-105 hover:bg-gray-800/30 ml-16',
|
||||
selectedIndex === featureIndex
|
||||
? 'outline-cyan-500'
|
||||
: 'outline-transparent hover:outline-cyan-500',
|
||||
? 'outline-cyan-400'
|
||||
: 'outline-transparent hover:outline-cyan-400',
|
||||
)}
|
||||
>
|
||||
{featureIndex === selectedIndex && (
|
||||
|
||||
@@ -153,8 +153,8 @@ function CloudFeaturesDesktop() {
|
||||
className={clsx(
|
||||
'relative rounded-2xl outline-2 transition-all duration-300 ease-in-out hover:scale-105 hover:bg-gray-100',
|
||||
selectedIndex === featureIndex
|
||||
? 'outline-cyan-500'
|
||||
: 'outline-transparent hover:outline-cyan-500',
|
||||
? 'outline-cyan-400'
|
||||
: 'outline-transparent hover:outline-cyan-400',
|
||||
)}
|
||||
>
|
||||
{featureIndex === selectedIndex && (
|
||||
@@ -257,7 +257,7 @@ export function CloudFeaturesLight() {
|
||||
</SectionHeader>
|
||||
<P className="mt-6 text-gray-600">
|
||||
Mycelium Cloud runs Kubernetes on a sovereign, self-healing network
|
||||
with compute, storage, and networking built in — so you don’t need
|
||||
with compute, storage, and networking built in, so you don’t need
|
||||
external cloud dependencies.
|
||||
</P>
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
import { H3, Eyebrow } from "@/components/Texts"
|
||||
import { H3, Eyebrow, P } from "@/components/Texts"
|
||||
import { Button } from "@/components/Button"
|
||||
|
||||
export function CloudHeroNew({ onGetStartedClick = () => {} }: { onGetStartedClick?: () => void }) {
|
||||
export function CloudHeroNew() {
|
||||
return (
|
||||
<div className="">
|
||||
{/* Boxed container */}
|
||||
<div
|
||||
className="relative mx-auto max-w-7xl border border-t-0 border-b-0 border-gray-100 bg-white overflow-hidden bg-contain bg-right bg-no-repeat"
|
||||
style={{ backgroundImage: "url('/images/cloudhero4.webp')", backgroundSize: "contain" }}
|
||||
className="relative mx-auto max-w-7xl border border-t-0 border-b-0 border-gray-100 bg-white overflow-hidden md:bg-[url('/images/cloudhero4.webp')] md:bg-contain md:bg-right md:bg-no-repeat"
|
||||
>
|
||||
{/* Inner padding */}
|
||||
<div className="px-6 py-16 lg:py-16">
|
||||
<div className="px-6 pt-4 pb-12 lg:py-24">
|
||||
{/* Mobile-only hero image */}
|
||||
<img
|
||||
src="/images/mobile/cloudpage.jpg"
|
||||
alt="Mycelium Cloud page visual"
|
||||
className="mb-8 w-full object-cover md:hidden"
|
||||
/>
|
||||
|
||||
<div className="max-w-2xl lg:pl-6">
|
||||
<Eyebrow>
|
||||
MYCELIUM CLOUD
|
||||
@@ -18,30 +24,36 @@ export function CloudHeroNew({ onGetStartedClick = () => {} }: { onGetStartedCli
|
||||
<H3 className="mt-4">
|
||||
Sovereign Edge Cloud Infrastructure
|
||||
</H3>
|
||||
<p className="mt-6 text-lg text-gray-600">
|
||||
<P className="mt-6 text-gray-600">
|
||||
Run compute, storage, and AI resources on infrastructure you control.
|
||||
</p>
|
||||
<p className="mt-4 text-lg text-gray-600">
|
||||
The Mycelium Cloud runs on a distributed grid of independent nodes,
|
||||
delivering secure, scalable performance wherever your users or data live.
|
||||
</p>
|
||||
</P>
|
||||
<div className="mt-10 flex items-center gap-x-6">
|
||||
<Button
|
||||
onClick={onGetStartedClick}
|
||||
as="a"
|
||||
to="https://myceliumcloud.tf"
|
||||
variant="solid"
|
||||
color="cyan"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Deploy Workloads
|
||||
</Button>
|
||||
<Button to="#" variant="outline">
|
||||
<Button
|
||||
as="a"
|
||||
to="https://myceliumcloud.tf/docs"
|
||||
variant="outline"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Explore Docs <span aria-hidden="true">→</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{/* ✅ Bottom horizontal line with spacing */}
|
||||
{/* Bottom horizontal line with spacing */}
|
||||
<div className="w-full border-b border-gray-100" />
|
||||
<div className="max-w-7xl bg-transparent mx-auto py-6 border border-t-0 border-b-0 border-gray-100"></div>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { CloudCodeTabs } from "./CloudCodeTabs";
|
||||
import { Eyebrow, H3, P } from "@/components/Texts";
|
||||
import { Button } from "@/components/Button";
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
@@ -59,9 +59,37 @@ const tabs = [
|
||||
},
|
||||
];
|
||||
|
||||
const tabButtons = {
|
||||
kubernetes: {
|
||||
primary: "Deploy a Cluster",
|
||||
secondary: "Learn More",
|
||||
},
|
||||
vdc: {
|
||||
primary: "Follow Development",
|
||||
secondary: "Learn More",
|
||||
},
|
||||
qsfs: {
|
||||
primary: "View Docs",
|
||||
secondary: "Explore Integration",
|
||||
},
|
||||
} as const;
|
||||
|
||||
export function CloudIntro() {
|
||||
const [active, setActive] = useState("kubernetes");
|
||||
const current = tabs.find((t) => t.id === active)!.content;
|
||||
const currentButtons = tabButtons[active as keyof typeof tabButtons];
|
||||
|
||||
const primaryLinks: Record<string, string | undefined> = {
|
||||
kubernetes: "https://myceliumcloud.tf",
|
||||
vdc: undefined,
|
||||
qsfs: undefined,
|
||||
};
|
||||
|
||||
const secondaryLinks: Record<string, string | undefined> = {
|
||||
kubernetes: "https://myceliumcloud.tf/docs",
|
||||
vdc: "https://threefold.info/mycelium_vdc/docs/",
|
||||
qsfs: undefined,
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="relative w-full bg-[#121212] overflow-hidden">
|
||||
@@ -79,8 +107,8 @@ export function CloudIntro() {
|
||||
|
||||
<H3 color="white">What You Can Run on Mycelium Cloud</H3>
|
||||
|
||||
<P className="max-w-3xl text-gray-400 mt-6">
|
||||
Host nodes, deploy workloads, or build private AI systems — all on
|
||||
<P className="max-w-3xl text-gray-200 mt-6">
|
||||
Host nodes, deploy workloads, or build private AI systems all on
|
||||
infrastructure you own and control. Mycelium gives you scalable compute,
|
||||
secure storage, and sovereign orchestration without depending on
|
||||
hyperscalers.
|
||||
@@ -94,7 +122,11 @@ export function CloudIntro() {
|
||||
|
||||
{/* Left: Code UI */}
|
||||
<div className="w-full lg:w-1/2">
|
||||
<CloudCodeTabs />
|
||||
<img
|
||||
src="/images/cloud/reserve.png"
|
||||
alt="Mycelium Cloud reserve"
|
||||
className="w-full h-auto rounded-xl border border-white/10 object-cover"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Right: Tabs */}
|
||||
@@ -106,7 +138,7 @@ export function CloudIntro() {
|
||||
<button
|
||||
key={tab.id}
|
||||
onClick={() => setActive(tab.id)}
|
||||
className={`text-sm font-medium tracking-wide pb-2 ${
|
||||
className={`text-sm font-medium tracking-wide leading-tight pb-2 ${
|
||||
active === tab.id
|
||||
? "border-b-2 border-cyan-500 text-white"
|
||||
: "text-gray-400 hover:text-white"
|
||||
@@ -120,20 +152,20 @@ export function CloudIntro() {
|
||||
{/* Tab Content */}
|
||||
<div className="mt-6 space-y-6">
|
||||
<div>
|
||||
<p className="text-lg font-medium text-white">{current.item}</p>
|
||||
<p className="mt-2 text-base text-gray-400 leading-relaxed">
|
||||
<p className="text-lg lg:text-xl font-medium text-white">{current.item}</p>
|
||||
<p className="mt-2 text-base text-gray-300 leading-relaxed">
|
||||
{current.desc}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 space-y-2">
|
||||
<p className="text-sm uppercase tracking-wide text-cyan-400 font-semibold">
|
||||
<p className="text-sm uppercase tracking-wide text-cyan-500 font-semibold">
|
||||
Key capabilities
|
||||
</p>
|
||||
|
||||
<ul className="space-y-2">
|
||||
{current.bullets.map((b, i) => (
|
||||
<li key={i} className="text-base text-gray-300 flex gap-2">
|
||||
<li key={i} className="text-base text-gray-400 flex gap-2">
|
||||
<span className="text-cyan-500">•</span>
|
||||
{b}
|
||||
</li>
|
||||
@@ -141,6 +173,34 @@ export function CloudIntro() {
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{currentButtons && (
|
||||
<div className="mt-8 flex flex-wrap gap-4">
|
||||
<Button
|
||||
as={primaryLinks[active] ? "a" : undefined}
|
||||
to={primaryLinks[active] ?? "#"}
|
||||
variant="solid"
|
||||
color="cyan"
|
||||
{...(primaryLinks[active]
|
||||
? { target: "_blank", rel: "noopener noreferrer" }
|
||||
: {})}
|
||||
>
|
||||
{currentButtons.primary}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
as={secondaryLinks[active] ? "a" : undefined}
|
||||
to={secondaryLinks[active] ?? "#"}
|
||||
variant="outline"
|
||||
color="white"
|
||||
{...(secondaryLinks[active]
|
||||
? { target: "_blank", rel: "noopener noreferrer" }
|
||||
: {})}
|
||||
>
|
||||
{currentButtons.secondary}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,6 @@ import { AnimatedSection } from '../../components/AnimatedSection'
|
||||
import { CloudHeroNew } from './CloudHeroNew'
|
||||
import { CallToAction } from './CalltoAction'
|
||||
import { CloudIntro } from './CloudIntro'
|
||||
import { CloudFeaturesLight } from './CloudFeaturesLight'
|
||||
import { CloudPros } from './CloudPros'
|
||||
|
||||
|
||||
@@ -18,10 +17,6 @@ export default function CloudPage() {
|
||||
<CloudIntro />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<CloudFeaturesLight />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<CloudPros />
|
||||
</AnimatedSection>
|
||||
|
||||
@@ -1,47 +1,66 @@
|
||||
import { Small } from '@/components/Texts'
|
||||
import { H3, P, Eyebrow, Small } from "@/components/Texts";
|
||||
|
||||
const highlights = [
|
||||
{
|
||||
label: 'Platform Architecture',
|
||||
title: 'Unified compute, storage & orchestration.',
|
||||
label: "Local Execution",
|
||||
title: "Agents run entirely inside your environment.",
|
||||
description:
|
||||
'One unified platform for compute, storage, and orchestration.',
|
||||
"Models, logic, and memory stay within your own trusted hardware—never behind third-party APIs.",
|
||||
},
|
||||
{
|
||||
label: 'Reliability',
|
||||
title: 'Consistent performance everywhere.',
|
||||
label: "Mesh Connectivity",
|
||||
title: "They communicate peer-to-peer across trusted nodes.",
|
||||
description:
|
||||
'Runs reliably across distributed environments.',
|
||||
"Agents form direct encrypted paths between environments, without relays or central servers.",
|
||||
},
|
||||
{
|
||||
label: 'Compatibility',
|
||||
title: 'Works with your existing stack.',
|
||||
label: "Private Data Access",
|
||||
title: "They use your data without sending it elsewhere.",
|
||||
description:
|
||||
'Works with your existing tools and workflows.',
|
||||
"Your datasets, embeddings, and context never leave your boundaries—processing stays local.",
|
||||
},
|
||||
{
|
||||
label: 'Scalability',
|
||||
title: 'Grows with your needs.',
|
||||
label: "Portability",
|
||||
title: "They move with you, not with a cloud provider.",
|
||||
description:
|
||||
'Scales from small projects to full environments.',
|
||||
"Agents follow your devices, networks, and workflows, remaining sovereign across every location.",
|
||||
},
|
||||
]
|
||||
];
|
||||
|
||||
export function CloudPros() {
|
||||
export function CloudPros() {
|
||||
return (
|
||||
<section className="relative w-full bg-[#FDFDFD] overflow-hidden">
|
||||
{/* Top spacing line */}
|
||||
<div className="max-w-7xl bg-[#FDFDFD] mx-auto py-6 border border-t-0 border-b-0 border-gray-100"></div>
|
||||
<div className="w-full border-t border-l border-r border-gray-100" />
|
||||
|
||||
<div className="bg-[#FDFDFD] w-full max-w-7xl mx-auto border border-t-0 border-b-0 border-gray-100">
|
||||
{/* Intro Block */}
|
||||
<div className="bg-white w-full max-w-7xl mx-auto border border-t-0 border-b-0 border-gray-100">
|
||||
<div className="px-8 py-12 max-w-4xl">
|
||||
<Eyebrow className="uppercase tracking-[0.16em] text-cyan-400">
|
||||
Cloud Advantages
|
||||
</Eyebrow>
|
||||
|
||||
<H3 className="mt-4 text-black">
|
||||
Why It’s Different
|
||||
</H3>
|
||||
|
||||
<P className="mt-4 text-gray-700 leading-relaxed">
|
||||
Most AI systems run on centralized clouds, where the models, data, and
|
||||
logic operate behind third-party APIs. Mycelium Agents flip that
|
||||
architecture, running entirely inside your environment so control,
|
||||
privacy, and autonomy stay with you.
|
||||
</P>
|
||||
</div>
|
||||
|
||||
{/* Grid */}
|
||||
<div className="grid lg:grid-cols-4">
|
||||
{highlights.map((item) => (
|
||||
<div
|
||||
key={item.title}
|
||||
className="group relative overflow-hidden border border-gray-100 bg-white p-8 transition hover:border-cyan-400/40 hover:bg-white"
|
||||
>
|
||||
{/* Hover glow */}
|
||||
{/* Glow */}
|
||||
<div className="absolute inset-0 bg-linear-to-br from-cyan-200/0 via-cyan-100/20 to-cyan-300/20 opacity-0 transition group-hover:opacity-100" />
|
||||
|
||||
<div className="relative">
|
||||
@@ -53,7 +72,7 @@ export function CloudPros() {
|
||||
{item.title}
|
||||
</h3>
|
||||
|
||||
<p className="mt-4 text-sm leading-relaxed text-gray-600">
|
||||
<p className="mt-4 text-base leading-relaxed text-gray-600">
|
||||
{item.description}
|
||||
</p>
|
||||
</div>
|
||||
@@ -62,8 +81,9 @@ export function CloudPros() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom spacing */}
|
||||
<div className="w-full border-b border-gray-100 bg-[#FDFDFD]" />
|
||||
<div className="max-w-7xl mx-auto py-6 border border-t-0 border-b-0 border-gray-100" />
|
||||
</section>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ export function CloudUseCases() {
|
||||
<div className="max-w-7xl bg-white mx-auto py-12 border border-t-0 border-b-0 border-gray-100">
|
||||
<Container>
|
||||
<div className="mx-auto max-w-4xl sm:text-center">
|
||||
<Eyebrow className="text-cyan-500">USE CASES</Eyebrow>
|
||||
<Eyebrow className="text-cyan-400">USE CASES</Eyebrow>
|
||||
|
||||
<H3 className="text-3xl lg:text-4xl font-medium tracking-tight text-gray-900">
|
||||
Built for intelligent workloads across every edge.
|
||||
|
||||
@@ -13,7 +13,7 @@ export function CallToAction() {
|
||||
{/* ✅ Main boxed area */}
|
||||
<div
|
||||
id="get-started"
|
||||
className="relative py-18 max-w-7xl mx-auto bg-[#111111] border border-t-0 border-b-0 border-gray-800"
|
||||
className="relative py-18 max-w-7xl overflow-hidden mx-auto bg-[#111111] border border-t-0 border-b-0 border-gray-800"
|
||||
>
|
||||
{/* ✅ Cyan Radial Glow */}
|
||||
<svg
|
||||
@@ -26,7 +26,7 @@ export function CallToAction() {
|
||||
cx={512}
|
||||
cy={512}
|
||||
fill="url(#mycelium-cyan-glow)"
|
||||
fillOpacity="0.2"
|
||||
fillOpacity="0.3"
|
||||
/>
|
||||
<defs>
|
||||
<radialGradient id="mycelium-cyan-glow">
|
||||
@@ -43,7 +43,7 @@ export function CallToAction() {
|
||||
Choose How You Want to Start
|
||||
</h2>
|
||||
|
||||
<p className="mt-6 text-lg text-gray-300">
|
||||
<p className="mt-6 lg:text-lg text-base leading-normal text-gray-300">
|
||||
Host your own node to contribute capacity or deploy workloads using the Mycelium Cloud.
|
||||
You don’t need to host before deploying, and you don’t need to deploy before hosting.
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import { Container } from '@/components/Container'
|
||||
import { Eyebrow, H3, P } from '@/components/Texts'
|
||||
import { Button } from '@/components/Button'
|
||||
|
||||
const capabilities = [
|
||||
{
|
||||
@@ -76,14 +75,8 @@ export function ComputeCapabilities() {
|
||||
</ul>
|
||||
|
||||
{/* Button section */}
|
||||
<div className="mx-auto mt-12 flex justify-center gap-6">
|
||||
<Button variant="solid" color="cyan" href="#">
|
||||
Get Started
|
||||
</Button>
|
||||
<Button variant="outline" color="white" href="#">
|
||||
Explore Docs
|
||||
</Button>
|
||||
</div>
|
||||
{/* TODO: CTA buttons (Get Started / Explore Docs) to be re-enabled when real links are available.
|
||||
Previously rendered here as two Buttons with href="#". */}
|
||||
</Container>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -78,12 +78,8 @@ export function ComputeCapabilitiesNew() {
|
||||
|
||||
{/* Arrows inside first card */}
|
||||
<div className="flex items-center gap-x-4 mt-2">
|
||||
<a
|
||||
href="#"
|
||||
className="inline-flex items-center gap-1 text-cyan-400 hover:text-cyan-300 text-sm font-medium mr-auto"
|
||||
>
|
||||
Learn more →
|
||||
</a>
|
||||
{/* TODO: Intro card CTA (Learn more) to be added here when destination is defined.
|
||||
Previously: <a href="#" className="inline-flex items-center ...">Learn more →</a> */}
|
||||
<button
|
||||
onClick={scrollLeft}
|
||||
className="h-8 w-8 flex items-center justify-center border border-gray-800 rounded-md hover:border-cyan-500 transition-colors"
|
||||
|
||||
@@ -33,7 +33,7 @@ export function ComputeFeatures() {
|
||||
</P>
|
||||
|
||||
<P className="mt-3 text-lg text-gray-600">
|
||||
Each component — from message passing to content distribution — works in harmony
|
||||
Each component, from message passing to content distribution — works in harmony
|
||||
to create a fully self-healing, self-optimizing data mesh.
|
||||
</P>
|
||||
</div>
|
||||
|
||||
@@ -35,9 +35,8 @@ export function ComputeHero({ onGetStartedClick = () => {} }: { onGetStartedClic
|
||||
>
|
||||
Get started
|
||||
</Button>
|
||||
<Button to="#" variant="outline">
|
||||
Documentation <span aria-hidden="true">→</span>
|
||||
</Button>
|
||||
{/* TODO: Secondary CTA (Documentation) link to be wired when docs route is ready.
|
||||
Previously: <Button to="#" variant="outline">Documentation →</Button> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -34,11 +34,11 @@ const tabs = [
|
||||
},
|
||||
{
|
||||
item: "Zero cloud lock-in",
|
||||
desc: "Deploy containers, VMs, or full Kubernetes clusters — migrate off AWS/GCP/Azure with no code changes.",
|
||||
desc: "Deploy containers, VMs, or full Kubernetes clusters, migrate off AWS/GCP/Azure with no code changes.",
|
||||
},
|
||||
{
|
||||
item: "Encrypted networking",
|
||||
desc: "All services communicate through Mycelium Mesh — no VPNs, no exposed ports.",
|
||||
desc: "All services communicate through Mycelium Mesh without VPNs, no exposed ports.",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -48,11 +48,11 @@ const tabs = [
|
||||
content: [
|
||||
{
|
||||
item: "Distributed workloads",
|
||||
desc: "Run compute where data lives — homes, factories, hospitals, or remote regions.",
|
||||
desc: "Run compute where data lives; homes, factories, hospitals, or remote regions.",
|
||||
},
|
||||
{
|
||||
item: "Offline-first resilience",
|
||||
desc: "Nodes keep working even with weak internet or outages — ideal for mission-critical edge.",
|
||||
desc: "Nodes keep working even with weak internet or outages, ideal for mission-critical edge.",
|
||||
},
|
||||
{
|
||||
item: "Global deployment, local data",
|
||||
@@ -85,7 +85,7 @@ export function ComputeUseCases() {
|
||||
<P className="max-w-3xl text-gray-400 mt-6">
|
||||
Mycelium Compute is a decentralized physical infrastructure network
|
||||
(DePIN) for high-performance workloads. Run reproducible AI/ML
|
||||
pipelines, host self-healing applications, or deploy to the edge — all
|
||||
pipelines, host self-healing applications, or deploy to the edge, all
|
||||
on a fabric that’s more resilient and private than the cloud.
|
||||
</P>
|
||||
</div>
|
||||
|
||||
@@ -36,8 +36,12 @@ const features = [
|
||||
|
||||
export function DevHub() {
|
||||
return (
|
||||
<div className="bg-[#121212] py-24 sm:py-32">
|
||||
<div className="mx-auto max-w-7xl px-6 lg:px-8">
|
||||
<section className="bg-[#121212] w-full max-w-8xl mx-auto">
|
||||
{/* Top spacing + border */}
|
||||
<div className="max-w-7xl mx-auto py-6 border border-t-0 border-b-0 border-gray-800" />
|
||||
<div className="w-full border-t border-l border-r border-gray-800" />
|
||||
|
||||
<div className="relative px-6 lg:px-6 py-12 bg-[#111111] border border-t-0 border-b-0 border-gray-800 max-w-7xl mx-auto">
|
||||
<div className="mx-auto grid max-w-2xl grid-cols-1 gap-x-8 gap-y-16 sm:gap-y-20 lg:mx-0 lg:max-w-none lg:grid-cols-5">
|
||||
<div className="col-span-2">
|
||||
<h2 className="mb-2 text-base font-semibold leading-7 text-cyan-500">Get Started</h2>
|
||||
@@ -63,7 +67,11 @@ export function DevHub() {
|
||||
))}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom horizontal line with spacing (match NetworkDownload) */}
|
||||
<div className="w-full border-b border-gray-800" />
|
||||
<div className="max-w-7xl bg-transparent mx-auto py-6 border border-t-0 border-b-0 border-gray-800"></div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -40,14 +40,14 @@ const features = [
|
||||
|
||||
export function DownloadHero() {
|
||||
return (
|
||||
<div className="py-16 sm:py-32">
|
||||
<div className="mx-auto max-w-7xl px-6 lg:px-8">
|
||||
<section id="download" className="w-full max-w-8xl mx-auto bg-transparent">
|
||||
<div className="mx-auto max-w-7xl px-6 lg:px-8 bg-white pt-24 pb-12 border border-t-0 border-b-0 border-gray-100">
|
||||
<div className="mx-auto max-w-2xl lg:mx-0">
|
||||
<motion.h2
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
className="text-5xl font-medium tracking-tight text-gray-900 lg:text-6xl"
|
||||
className="text-4xl font-medium tracking-tight text-gray-900 lg:text-5xl"
|
||||
>
|
||||
Download Mycelium Network
|
||||
</motion.h2>
|
||||
@@ -55,7 +55,7 @@ export function DownloadHero() {
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5, delay: 0.2 }}
|
||||
className="mt-6 text-lg text-gray-600 lg:leading-8"
|
||||
className="mt-8 text-lg text-gray-600 lg:leading-8"
|
||||
>
|
||||
Get Mycelium Network for Android, Windows, macOS, and iOS to securely connect, store, and interact with the decentralized network—seamlessly and efficiently. Not sure how it works?{' '}
|
||||
<a
|
||||
@@ -68,8 +68,9 @@ export function DownloadHero() {
|
||||
</a>
|
||||
</motion.p>
|
||||
</div>
|
||||
<div className="mx-auto mt-16 max-w-2xl sm:mt-20 lg:mt-24 lg:max-w-none">
|
||||
<dl className="grid max-w-xl grid-cols-1 gap-x-8 gap-y-16 md:grid-cols-2 lg:max-w-none lg:grid-cols-4">
|
||||
|
||||
<div className="mx-auto mt-8 max-w-2xl lg:mt-12 lg:max-w-none">
|
||||
<dl className="grid max-w-xl grid-cols-1 gap-x-8 lg:gap-y-16 gap-y-8 md:grid-cols-2 lg:max-w-none lg:grid-cols-4">
|
||||
{features.map((feature) => (
|
||||
<div
|
||||
key={feature.name}
|
||||
@@ -99,6 +100,10 @@ export function DownloadHero() {
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom horizontal line with spacing (match NetworkDownload) */}
|
||||
<div className="w-full border-b border-gray-100" />
|
||||
<div className="max-w-7xl bg-transparent mx-auto py-6 border border-t-0 border-b-0 border-gray-100"></div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ export function CallToAction() {
|
||||
{/* ✅ Main boxed area */}
|
||||
<div
|
||||
id="get-started"
|
||||
className="relative py-18 max-w-7xl mx-auto bg-[#111111] border border-t-0 border-b-0 border-gray-800"
|
||||
className="relative py-18 max-w-7xl overflow-hidden mx-auto bg-[#111111] border border-t-0 border-b-0 border-gray-800"
|
||||
>
|
||||
{/* ✅ Cyan Radial Glow */}
|
||||
<svg
|
||||
@@ -26,7 +26,7 @@ export function CallToAction() {
|
||||
cx={512}
|
||||
cy={512}
|
||||
fill="url(#mycelium-cyan-glow)"
|
||||
fillOpacity="0.2"
|
||||
fillOpacity="0.3"
|
||||
/>
|
||||
<defs>
|
||||
<radialGradient id="mycelium-cyan-glow">
|
||||
@@ -43,7 +43,7 @@ export function CallToAction() {
|
||||
Choose How You Want to Start
|
||||
</h2>
|
||||
|
||||
<p className="mt-6 text-lg text-gray-300">
|
||||
<p className="mt-6 lg:text-lg text-base leading-normal text-gray-300">
|
||||
Use GPUs through Mycelium Cloud, or contribute GPU nodes to the mesh and run your own workloads.
|
||||
</p>
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ export function GpuArchitecture() {
|
||||
Sovereign Compute Nodes
|
||||
</h3>
|
||||
<p className="mt-2 text-gray-600 max-w-2xl">
|
||||
GPUs run only on hardware you control — eliminating reliance on centralized clouds.
|
||||
GPUs run only on hardware you control, eliminating reliance on centralized clouds.
|
||||
</p>
|
||||
<div className="mt-8 h-px w-full bg-cyan-500/50" />
|
||||
</div>
|
||||
@@ -52,7 +52,7 @@ export function GpuArchitecture() {
|
||||
Encrypted Mesh Networking
|
||||
</h3>
|
||||
<p className="mt-2 text-gray-600 max-w-2xl">
|
||||
Nodes form private, encrypted tunnels to workloads — no public exposure required.
|
||||
Nodes form private, encrypted tunnels to workloads, no public exposure required.
|
||||
</p>
|
||||
<div className="mt-8 h-px w-full bg-cyan-500/50" />
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,7 @@ const gpuCapabilities = [
|
||||
eyebrow: "CAPABILITIES",
|
||||
title: "What You Can Run on Mycelium Cloud",
|
||||
description:
|
||||
"GPU acceleration for inference, training, rendering, and agent workloads — on sovereign hardware.",
|
||||
"GPU acceleration for inference, training, rendering, and agent workload on sovereign hardware.",
|
||||
},
|
||||
{
|
||||
name: "AI / ML Inference & Training",
|
||||
@@ -84,7 +84,7 @@ export function GpuCapabilities() {
|
||||
<div className="flex items-center gap-x-4 mt-3">
|
||||
<a
|
||||
href="#"
|
||||
className="inline-flex items-center gap-1 text-cyan-400 hover:text-cyan-300 text-sm font-medium mr-auto"
|
||||
className="inline-flex items-center gap-1 text-cyan-500 hover:text-cyan-400 text-sm font-medium mr-auto"
|
||||
>
|
||||
Learn more →
|
||||
</a>
|
||||
|
||||
@@ -42,7 +42,7 @@ export function GpuOverview() {
|
||||
<div className="relative mx-auto max-w-7xl border border-t-0 border-b-0 border-gray-800 bg-[#111111] py-12">
|
||||
<Container>
|
||||
<div className="mx-auto max-w-3xl text-center">
|
||||
<Eyebrow className="text-cyan-400 tracking-[0.32em] uppercase">
|
||||
<Eyebrow className="text-cyan-500 tracking-[0.32em] uppercase">
|
||||
PLATFORM OVERVIEW
|
||||
</Eyebrow>
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Container } from '@/components/Container'
|
||||
import { Button } from '@/components/Button'
|
||||
import { H3, P } from '@/components/Texts'
|
||||
@@ -27,7 +26,7 @@ export function CallToAction() {
|
||||
cx={512}
|
||||
cy={512}
|
||||
fill="url(#mycelium-cyan-glow)"
|
||||
fillOpacity="0.2"
|
||||
fillOpacity="0.3"
|
||||
/>
|
||||
<defs>
|
||||
<radialGradient id="mycelium-cyan-glow">
|
||||
@@ -43,30 +42,33 @@ export function CallToAction() {
|
||||
Use the Mycelium Stack Your Way
|
||||
</H3>
|
||||
|
||||
<P className="mt-6 text-gray-300">
|
||||
<P className="mt-6 lg:text-lg text-base leading-normal text-gray-300">
|
||||
Deploy infrastructure, run workloads, connect environments, and build distributed AI systems, all on one network designed for autonomy and control.
|
||||
</P>
|
||||
|
||||
<P className="mt-4 text-gray-300">
|
||||
<P className="mt-4 lg:text-lg text-base leading-normal text-gray-300">
|
||||
Start wherever you are. Scale on your own terms.
|
||||
</P>
|
||||
|
||||
<div className="mt-10 flex flex-wrap justify-center items-center gap-x-6 gap-y-4">
|
||||
<Button to="/network" variant="solid" color="cyan">
|
||||
<Button to="/network#download" variant="solid" color="cyan">
|
||||
Join the Network
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
to="/cloud"
|
||||
as="a"
|
||||
to="https://myceliumcloud.tf"
|
||||
variant="outline"
|
||||
color="white"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Deploy in Cloud
|
||||
</Button>
|
||||
|
||||
<Link to="/nodes" className="text-cyan-400 hover:text-cyan-300 transition-colors">
|
||||
<Button to="/nodes" variant="link" color="white">
|
||||
Host a Node →
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
|
||||
@@ -24,7 +24,7 @@ const deterministicCards = [
|
||||
title: "No central servers.",
|
||||
description:
|
||||
"Your devices form a distributed network, eliminating reliance on centralized data centers.",
|
||||
animation: <NoCentral className="lg:-mt-12" />, // ✅ NEW
|
||||
animation: <NoCentral />, // ✅ NEW
|
||||
colSpan: "lg:col-span-3",
|
||||
rowSpan: "lg:row-span-1",
|
||||
rounded: "lg:rounded-tr-4xl max-lg:rounded-t-4xl",
|
||||
@@ -35,7 +35,7 @@ const deterministicCards = [
|
||||
title: "No data extraction.",
|
||||
description:
|
||||
"You own your data. Run services and AI models on your own devices, ensuring privacy and control.",
|
||||
animation: <NoExtraction className="lg:-mt-12" />, // ✅ NEW
|
||||
animation: <NoExtraction />, // ✅ NEW
|
||||
colSpan: "lg:col-span-2",
|
||||
rowSpan: "lg:row-span-1",
|
||||
rounded: "lg:rounded-bl-4xl max-lg:rounded-b-4xl",
|
||||
@@ -97,7 +97,7 @@ export function HomeArchitecture() {
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="h-48 w-full flex items-center justify-center bg-transparent" />
|
||||
<div className="h-48 w-full items-center justify-center bg-transparent hidden md:flex" />
|
||||
)}
|
||||
|
||||
<div className="px-8 pt-4 pb-6">
|
||||
|
||||
@@ -1,38 +1,50 @@
|
||||
import { H1, H4, H3, H5, Eyebrow } from "@/components/Texts"
|
||||
import { H3, H5, Eyebrow } from "@/components/Texts"
|
||||
import { Button } from "@/components/Button"
|
||||
import { H3Icon } from "@heroicons/react/20/solid"
|
||||
|
||||
export function HomeAurora({ onGetStartedClick }: { onGetStartedClick: () => void }) {
|
||||
export function HomeAurora() {
|
||||
return (
|
||||
<div className="px-4">
|
||||
{/* Boxed container */}
|
||||
<div
|
||||
className="relative mx-auto max-w-7xl border border-t-0 border-gray-100 bg-white overflow-hidden bg-size-[65%] bg-right bg-no-repeat"
|
||||
style={{ backgroundImage: "url('/images/hero11.webp')" }}
|
||||
className="relative mx-auto max-w-7xl border border-t-0 border-gray-100 bg-white overflow-hidden bg-size-[65%] bg-right bg-no-repeat bg-none md:bg-[url('/images/hero11.webp')]"
|
||||
>
|
||||
{/* Inner padding */}
|
||||
<div className="px-6 py-16 lg:py-32 ">
|
||||
<div className="px-6 pb-12 pt-8 lg:py-32 ">
|
||||
{/* Mobile-only hero image */}
|
||||
<img
|
||||
src="/images/mobile/homepage.jpg"
|
||||
alt="Mycelium homepage visual"
|
||||
className="mb-8 w-full object-cover md:hidden"
|
||||
/>
|
||||
|
||||
<div className="max-w-2xl lg:pl-6">
|
||||
<Eyebrow> Project MYCELIUM</Eyebrow>
|
||||
<H3 className="mt-4">
|
||||
Private, Distributed Infrastructure Built
|
||||
Secure, Distributed Infrastructure Built
|
||||
<br />
|
||||
for Digital Sovereignty
|
||||
</H3>
|
||||
|
||||
<H5 className="mt-4 text-lg text-gray-600 max-w-xl">
|
||||
<H5 className="mt-6 text-lg text-gray-600 max-w-xl">
|
||||
Run your apps, data, and intelligence on infrastructure that belongs to you
|
||||
</H5>
|
||||
|
||||
<div className="mt-8 flex items-center gap-x-6">
|
||||
<Button
|
||||
to="/nodes"
|
||||
variant="solid"
|
||||
color="cyan"
|
||||
onClick={onGetStartedClick}
|
||||
>
|
||||
Start Hosting
|
||||
</Button>
|
||||
<Button to="#" variant="outline">
|
||||
Deploy in Cloud →
|
||||
<Button
|
||||
as="a"
|
||||
to="https://myceliumcloud.tf"
|
||||
variant="outline"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Deploy in Cloud
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -39,10 +39,10 @@ export function HomeBlink({ onGetStartedClick }: { onGetStartedClick: () => void
|
||||
<H4 className="text-center mt-8">The Living Network of the Next Internet</H4>
|
||||
|
||||
<H5 className="mx-auto mt-6 max-w-4xl text-center font-normal text-neutral-500">
|
||||
A new internet is emerging — private, distributed, and self-sovereign.
|
||||
A new internet is emerging, a private, distributed, and self-sovereign.
|
||||
Mycelium is the living network that makes it possible.
|
||||
A peer-to-peer foundation where people, data, and intelligence connect
|
||||
directly — without intermediaries, without compromise.
|
||||
directly without intermediaries, without compromise.
|
||||
</H5>
|
||||
|
||||
<div className="mt-8 flex justify-center gap-6">
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Eyebrow, H3, P } from "@/components/Texts";
|
||||
|
||||
const benefits = [
|
||||
{
|
||||
id: 1,
|
||||
@@ -27,18 +29,32 @@ const benefits = [
|
||||
export function HomeDesign() {
|
||||
return (
|
||||
<section className="w-full max-w-8xl mx-auto bg-white">
|
||||
|
||||
{/* Top spacing line */}
|
||||
<div className="max-w-7xl mx-auto py-6 border border-t-0 border-b-0 border-gray-200" />
|
||||
<div className="w-full border border-l border-r border-gray-200" />
|
||||
<div className="max-w-7xl mx-auto py-6 border border-t-0 border-b-0 border-gray-100" />
|
||||
<div className="w-full border border-l border-r border-gray-100" />
|
||||
|
||||
{/* Content */}
|
||||
<div className="mx-auto max-w-7xl border-gray-200">
|
||||
<dl className="grid grid-cols-1 lg:grid-cols-3 gap-4 lg:gap-0">
|
||||
<div className="mx-auto max-w-7xl border border-t-0 border-b-0 bg-white border-gray-100">
|
||||
{/* Centered intro */}
|
||||
<div className="px-6 pt-12 pb-4 text-center max-w-4xl mx-auto ">
|
||||
<Eyebrow className="text-cyan-500">
|
||||
Who's it For
|
||||
</Eyebrow>
|
||||
|
||||
<H3 className="mt-4 text-black">
|
||||
Built for Real-World Impact
|
||||
</H3>
|
||||
|
||||
<P className="mt-4 text-gray-700 text-base leading-relaxed">
|
||||
Whether you’re deploying infrastructure, securing sensitive operations, or simply taking back control of your digital life, Mycelium provides the foundation to build confidently in a connected world.
|
||||
</P>
|
||||
</div>
|
||||
|
||||
<dl className="grid grid-cols-1 lg:grid-cols-3 gap-2 lg:gap-0">
|
||||
{benefits.map((item) => (
|
||||
<div
|
||||
key={item.id}
|
||||
className="group flex items-start gap-2 bg-white px-8 py-12 border border-gray-200 0 lg:border-t-0 lg:border-b-0"
|
||||
className="mt-8 group flex items-start gap-2 bg-white px-8 py-12 border border-gray-100 lg:border-t lg:border-b border-l-0.5 border-r-0.5 transition-all duration-300 ease-in-out hover:scale-[1.02] hover:border-cyan-500 hover:shadow-lg hover:shadow-cyan-500/20"
|
||||
>
|
||||
{/* Image on the LEFT */}
|
||||
<img
|
||||
|
||||
@@ -67,7 +67,7 @@ export function WorldMap() {
|
||||
>
|
||||
<DarkCard>
|
||||
<div><CT color="light" className="uppercase tracking-wide ">CORES</CT></div>
|
||||
<div><CountUpNumber end={54958} className="mt-2 text-3xl font-bold text-white" /></div>
|
||||
<div><CountUpNumber end={31611} className="mt-2 text-3xl font-bold text-white" /></div>
|
||||
<CP color="light" className="mt-2 text-sm">
|
||||
Total Central Processing Unit Cores available on the grid.
|
||||
</CP>
|
||||
@@ -83,7 +83,7 @@ export function WorldMap() {
|
||||
>
|
||||
<DarkCard>
|
||||
<div><CT color="light" className="uppercase tracking-wide">NODES</CT></div>
|
||||
<div><CountUpNumber end={1493} className="mt-4 text-3xl font-bold text-white" /></div>
|
||||
<div><CountUpNumber end={1153} className="mt-4 text-3xl font-bold text-white" /></div>
|
||||
<CP color="light" className="mt-2 text-sm">
|
||||
Total number of nodes on the grid.
|
||||
</CP>
|
||||
@@ -99,7 +99,7 @@ export function WorldMap() {
|
||||
>
|
||||
<DarkCard>
|
||||
<div><CT color="light" className="uppercase tracking-wide">SSD CAPACITY</CT></div>
|
||||
<div><CountUpNumber end={5388956} className="mt-2 text-3xl font-bold text-white" /></div>
|
||||
<div><CountUpNumber end={4203991} className="mt-2 text-3xl font-bold text-white" /></div>
|
||||
<CP color="light" className="mt-2 text-sm">
|
||||
Total GB amount of storage (SSD, HDD, & RAM) on the grid.
|
||||
</CP>
|
||||
|
||||
@@ -1,29 +1,109 @@
|
||||
"use client";
|
||||
import WorldMap from "@/components/ui/world-map";
|
||||
import { useEffect, useState } from "react";
|
||||
import DynamicMapContainer from "@/components/ui/DynamicMapContainer";
|
||||
import { Eyebrow, H3, P } from "@/components/Texts";
|
||||
|
||||
const stats = [
|
||||
{ id: 1, name: 'CORES', value: '54,958', description: 'Total Central Processing Unit cores available on the grid.' },
|
||||
{ id: 2, name: 'NODES', value: '1,493', description: 'Total number of nodes on the grid.' },
|
||||
{ id: 3, name: 'SSD CAPACITY', value: '5,388,956', description: 'Total GB of storage (SSD, HDD, & RAM) on the grid.' },
|
||||
{ id: 4, name: 'COUNTRIES', value: '44', description: 'Total number of countries with active nodes.' },
|
||||
]
|
||||
type StatKey = "cores" | "nodes" | "ssd" | "countries";
|
||||
|
||||
type StatsData = Record<StatKey, string>;
|
||||
|
||||
const STAT_API_URL = "https://stats.grid.tf/api/stats-summary";
|
||||
|
||||
const DEFAULT_STATS: StatsData = {
|
||||
cores: "31,669",
|
||||
nodes: "1157",
|
||||
ssd: "4,199,303",
|
||||
countries: "41",
|
||||
};
|
||||
|
||||
const STAT_CARDS: Array<{ key: StatKey; title: string; description: string }> = [
|
||||
{
|
||||
key: "ssd",
|
||||
title: "SSD CAPACITY",
|
||||
description: "Total GB of storage (SSD, HDD, & RAM) on the grid.",
|
||||
},
|
||||
{
|
||||
key: "cores",
|
||||
title: "CORES",
|
||||
description: "Total Central Processing Unit cores available on the grid.",
|
||||
},
|
||||
{
|
||||
key: "nodes",
|
||||
title: "NODES",
|
||||
description: "Total number of nodes on the grid.",
|
||||
},
|
||||
|
||||
{
|
||||
key: "countries",
|
||||
title: "COUNTRIES",
|
||||
description: "Total number of countries with active nodes.",
|
||||
},
|
||||
];
|
||||
|
||||
export function HomeMap() {
|
||||
const [stats, setStats] = useState<StatsData>(DEFAULT_STATS);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
|
||||
const formatValue = (value: unknown, fallback: string) => {
|
||||
if (typeof value === "number") {
|
||||
return value.toLocaleString();
|
||||
}
|
||||
if (typeof value === "string" && value.trim().length) {
|
||||
const numeric = Number(value);
|
||||
return Number.isNaN(numeric) ? value : numeric.toLocaleString();
|
||||
}
|
||||
return fallback;
|
||||
};
|
||||
|
||||
async function fetchStats() {
|
||||
try {
|
||||
const response = await fetch(STAT_API_URL);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Request failed with ${response.status}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
|
||||
if (!isMounted) return;
|
||||
|
||||
setStats({
|
||||
cores: formatValue(data?.cores, DEFAULT_STATS.cores),
|
||||
nodes: formatValue(data?.nodes, DEFAULT_STATS.nodes),
|
||||
ssd: formatValue(data?.ssd, DEFAULT_STATS.ssd),
|
||||
countries: formatValue(data?.countries, DEFAULT_STATS.countries),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("[HomeMap] Failed to load stats", error);
|
||||
} finally {
|
||||
if (isMounted) {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fetchStats();
|
||||
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="bg-[#121212] w-full">
|
||||
{/* ✅ Top horizontal line with spacing */}
|
||||
<div className="max-w-7xl bg-transparent mx-auto py-6 border border-t-0 border-b-0 border-gray-800"></div>
|
||||
<div className="w-full border-t border-l border-r border-gray-800" />
|
||||
|
||||
<div className="max-w-7xl mx-auto text-center pt-12 border border-t-0 border-b-0 border-gray-800">
|
||||
<div className="max-w-7xl mx-auto text-center pt-12 border border-t-0 border-b-0 border-gray-800 px-4">
|
||||
<Eyebrow>PROJECT MYCELIUM IS LIVE. </Eyebrow>
|
||||
<H3 className="text-white">Host a Node, Grow the Network</H3>
|
||||
<P className="text-sm md:text-lg text-gray-200 max-w-3xl mx-auto py-4">
|
||||
Mycelium runs on nodes hosted by people and organizations around the world.
|
||||
Each node adds compute, storage, and bandwidth, expanding the network’s capacity and resilience.
|
||||
</P>
|
||||
<P className="text-sm md:text-lg text-gray-200 max-w-3xl mx-auto py-4">
|
||||
<P className="text-sm md:text-lg text-gray-200 max-w-3xl mx-auto mt-2 mb-6">
|
||||
You can share your idle resources and earn rewards when they are used.
|
||||
Configure it once. Your node takes over from there.
|
||||
</P>
|
||||
@@ -32,37 +112,28 @@ Configure it once. Your node takes over from there.
|
||||
<div className="max-w-7xl mx-auto border border-t-0 border-b-0 border-gray-800 ">
|
||||
{/* ✅ Match same side margins */}
|
||||
<div className="max-w-5xl mx-auto px-6 ">
|
||||
<WorldMap
|
||||
dots={[
|
||||
{ start: { lat: 64.2008, lng: -149.4937 }, end: { lat: 34.0522, lng: -118.2437 } }, // Alaska → LA
|
||||
{ start: { lat: 64.2008, lng: -149.4937 }, end: { lat: -15.7975, lng: -47.8919 } }, // Alaska → Brasília
|
||||
{ start: { lat: -15.7975, lng: -47.8919 }, end: { lat: 38.7223, lng: -9.1393 } }, // Brasília → Lisbon
|
||||
{ start: { lat: 51.5074, lng: -0.1278 }, end: { lat: 28.6139, lng: 77.209 } }, // London → New Delhi
|
||||
{ start: { lat: 28.6139, lng: 77.209 }, end: { lat: 43.1332, lng: 131.9113 } }, // New Delhi → Vladivostok
|
||||
{ start: { lat: 28.6139, lng: 77.209 }, end: { lat: -1.2921, lng: 36.8219 } }, // New Delhi → Nairobi
|
||||
]}
|
||||
/>
|
||||
<DynamicMapContainer />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mx-auto max-w-7xl px-6 lg:px-8 border border-t-0 border-b-0 border-gray-800 pb-12">
|
||||
|
||||
<dl className="pt-6 grid grid-cols-1 gap-0.5 overflow-hidden rounded-md text-center sm:grid-cols-2 lg:grid-cols-4">
|
||||
{stats.map((stat) => (
|
||||
{STAT_CARDS.map(({ key, title, description }) => (
|
||||
<div
|
||||
key={stat.id}
|
||||
key={key}
|
||||
className="flex flex-col bg-white/1 p-8"
|
||||
>
|
||||
<dt className="text-sm/6 font-semibold text-gray-300">
|
||||
{stat.name}
|
||||
{title}
|
||||
</dt>
|
||||
|
||||
<dd className="order-first text-3xl font-semibold tracking-tight text-white">
|
||||
{stat.value}
|
||||
{isLoading ? "…" : stats[key]}
|
||||
</dd>
|
||||
|
||||
<p className="mt-2 text-sm text-gray-400">
|
||||
{stat.description}
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
import { useRef } from 'react'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { AnimatedSection } from '../../components/AnimatedSection'
|
||||
import { CallToAction } from './CallToAction'
|
||||
import { HomeTab } from './HomeTab'
|
||||
@@ -8,22 +7,60 @@ import { HomeAurora } from './HomeAurora'
|
||||
import { HomeArchitecture } from './HomeArchitecture';
|
||||
import { HomeDesign } from './HomeDesign';
|
||||
|
||||
function LazyHomeMapSection() {
|
||||
const [isVisible, setIsVisible] = useState(false)
|
||||
const containerRef = useRef<HTMLDivElement | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const el = containerRef.current
|
||||
if (!el || isVisible) return
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
const [entry] = entries
|
||||
if (entry.isIntersecting) {
|
||||
setIsVisible(true)
|
||||
observer.disconnect()
|
||||
}
|
||||
},
|
||||
{
|
||||
root: null,
|
||||
rootMargin: '200px 0px',
|
||||
threshold: 0.1,
|
||||
},
|
||||
)
|
||||
|
||||
observer.observe(el)
|
||||
|
||||
return () => {
|
||||
observer.disconnect()
|
||||
}
|
||||
}, [isVisible])
|
||||
|
||||
return (
|
||||
<div ref={containerRef}>
|
||||
{isVisible ? (
|
||||
<HomeMap />
|
||||
) : (
|
||||
<div className="max-w-7xl mx-auto px-6 py-16 text-center text-gray-400">
|
||||
<p className="text-sm md:text-base">
|
||||
Loading live node map when you scroll here…
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function HomePage() {
|
||||
const sliderRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const handleScrollToSlider = () => {
|
||||
sliderRef.current?.scrollIntoView({ behavior: 'smooth' })
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<AnimatedSection>
|
||||
<HomeAurora onGetStartedClick={handleScrollToSlider} />
|
||||
<HomeAurora />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<HomeArchitecture/>
|
||||
<HomeArchitecture />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
@@ -31,16 +68,16 @@ export default function HomePage() {
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<HomeMap />
|
||||
<LazyHomeMapSection />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
|
||||
<HomeDesign />
|
||||
</AnimatedSection>
|
||||
|
||||
|
||||
<AnimatedSection>
|
||||
|
||||
<CallToAction />
|
||||
</AnimatedSection>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -34,10 +34,10 @@ export function HomeSpotlight({
|
||||
<H4 className="text-center mt-4">The Living Network of the Next Internet</H4>
|
||||
|
||||
<H5 className="mx-auto mt-6 max-w-4xl text-center font-normal text-neutral-500">
|
||||
A new internet is emerging — private, distributed, and self-sovereign.
|
||||
A new internet is emerging, a private, distributed, and self-sovereign.
|
||||
Mycelium is the living network that makes it possible.
|
||||
A peer-to-peer foundation where people, data, and intelligence connect
|
||||
directly — without intermediaries, without compromise.
|
||||
directly without intermediaries, without compromise.
|
||||
</H5>
|
||||
|
||||
<div className="mt-8 flex justify-center gap-6">
|
||||
|
||||
@@ -8,7 +8,7 @@ export function HomeTab() {
|
||||
<section className="w-full max-w-8xl mx-auto bg-transparent">
|
||||
|
||||
{/* Top section separators */}
|
||||
<div className="max-w-7xl mx-auto py-6 border-x border-gray-100 bg-white border-t-0 border-b-0" />
|
||||
<div className="max-w-7xl mx-auto py-6 border-x border-gray-100 border-t-0 border-b-0" />
|
||||
<div className="w-full border-t border-l border-r border-gray-100" />
|
||||
|
||||
{/* Main content */}
|
||||
@@ -24,7 +24,7 @@ export function HomeTab() {
|
||||
<div className="mt-10 grid gap-4 sm:mt-16 lg:grid-cols-3 lg:grid-rows-2 pb-12">
|
||||
|
||||
{/* ------------------ LEFT TALL CARD ------------------ */}
|
||||
<Link to="/network" className="relative lg:row-span-2 cursor-pointer">
|
||||
<Link to="/network" className="relative lg:row-span-2 cursor-pointer transition-transform duration-300 ease-in-out hover:scale-105">
|
||||
<div className="absolute inset-px rounded-lg bg-white lg:rounded-l-4xl" />
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] lg:rounded-l-[calc(2rem+1px)]">
|
||||
|
||||
@@ -50,11 +50,11 @@ export function HomeTab() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pointer-events-none absolute inset-px rounded-lg shadow-sm outline outline-black/5 lg:rounded-l-4xl" />
|
||||
<div className="pointer-events-none absolute inset-px rounded-lg border border-transparent shadow-sm outline outline-black/5 lg:rounded-l-4xl hover:border-cyan-500" />
|
||||
</Link>
|
||||
|
||||
{/* ------------------ MIDDLE TOP ------------------ */}
|
||||
<Link to="/pods" className="relative cursor-pointer max-lg:row-start-1">
|
||||
<Link to="/pods" className="relative cursor-pointer max-lg:row-start-1 transition-transform duration-300 ease-in-out hover:scale-105">
|
||||
<div className="absolute inset-px rounded-lg bg-white max-lg:rounded-t-4xl" />
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] max-lg:rounded-t-[calc(2rem+1px)]">
|
||||
|
||||
@@ -75,11 +75,11 @@ export function HomeTab() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pointer-events-none absolute inset-px rounded-lg shadow-sm outline outline-black/5 max-lg:rounded-t-4xl" />
|
||||
<div className="pointer-events-none absolute inset-px rounded-lg border border-transparent shadow-sm outline outline-black/5 max-lg:rounded-t-4xl hover:border-cyan-500" />
|
||||
</Link>
|
||||
|
||||
{/* ------------------ MIDDLE BOTTOM ------------------ */}
|
||||
<Link to="/agents" className="relative cursor-pointer max-lg:row-start-3 lg:col-start-2 lg:row-start-2">
|
||||
<Link to="/agents" className="relative cursor-pointer max-lg:row-start-3 lg:col-start-2 lg:row-start-2 transition-transform duration-300 ease-in-out hover:scale-105">
|
||||
<div className="absolute inset-px rounded-lg bg-white" />
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)]">
|
||||
|
||||
@@ -99,11 +99,11 @@ export function HomeTab() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pointer-events-none absolute inset-px rounded-lg shadow-sm outline outline-black/5" />
|
||||
<div className="pointer-events-none absolute inset-px rounded-lg border border-transparent shadow-sm outline outline-black/5 hover:border-cyan-500" />
|
||||
</Link>
|
||||
|
||||
{/* ------------------ RIGHT TALL ------------------ */}
|
||||
<Link to="/cloud" className="relative lg:row-span-2 cursor-pointer">
|
||||
<Link to="/cloud" className="relative lg:row-span-2 cursor-pointer transition-transform duration-300 ease-in-out hover:scale-105">
|
||||
<div className="absolute inset-px rounded-lg bg-white max-lg:rounded-b-4xl lg:rounded-r-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-r-[calc(2rem+1px)]">
|
||||
|
||||
@@ -126,7 +126,7 @@ export function HomeTab() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pointer-events-none absolute inset-px rounded-lg shadow-sm outline outline-black/5 max-lg:rounded-b-4xl lg:rounded-r-4xl" />
|
||||
<div className="pointer-events-none absolute inset-px rounded-lg border border-transparent shadow-sm outline outline-black/5 max-lg:rounded-b-4xl lg:rounded-r-4xl hover:border-cyan-500" />
|
||||
</Link>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -41,7 +41,7 @@ export function HomeWhy() {
|
||||
<Eyebrow>Why It Matters</Eyebrow>
|
||||
<H3 className="mt-2 text-gray-200">Why Mycelium?</H3>
|
||||
<P className="mx-auto mt-5 max-w-prose text-gray-400">
|
||||
The current internet is a rent-seeking one. Mycelium builds one that belongs to everyone — where infrastructure, data, and intelligence stay with the people and organizations who create them.
|
||||
The current internet is a rent-seeking one. Mycelium builds one that belongs to everyone where infrastructure, data, and intelligence stay with the people and organizations who create them.
|
||||
|
||||
</P>
|
||||
<div className="mt-16">
|
||||
|
||||
@@ -131,7 +131,7 @@ export default function NoCentral({
|
||||
aria-label="Distributed network illustration"
|
||||
style={{ background: bg }}
|
||||
>
|
||||
<svg viewBox={`0 0 ${W} ${H}`} className="w-full h-full">
|
||||
<svg viewBox={`0 0 ${W} ${H}`} className="w-full h-full lg:-translate-y-10">
|
||||
{/* Background grid */}
|
||||
<defs>
|
||||
<pattern id="grid-dark" width="28" height="28" patternUnits="userSpaceOnUse">
|
||||
@@ -210,13 +210,13 @@ export default function NoCentral({
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Faded red “no central” mark at middle */}
|
||||
{/* Faded grey “no central” mark at middle */}
|
||||
<motion.circle
|
||||
cx={center.x}
|
||||
cy={center.y}
|
||||
r={18}
|
||||
fill="none"
|
||||
stroke="#FF4D4D"
|
||||
stroke="#8B8B8B"
|
||||
strokeWidth={3}
|
||||
strokeDasharray="6 4"
|
||||
initial={{ scale: 0, opacity: 0 }}
|
||||
@@ -225,7 +225,7 @@ export default function NoCentral({
|
||||
/>
|
||||
<motion.path
|
||||
d={`M ${center.x - 10} ${center.y - 10} L ${center.x + 10} ${center.y + 10} M ${center.x - 10} ${center.y + 10} L ${center.x + 10} ${center.y - 10}`}
|
||||
stroke="#FF4D4D"
|
||||
stroke="#8B8B8B"
|
||||
strokeWidth={3}
|
||||
strokeLinecap="round"
|
||||
initial={{ opacity: 0, scale: 0 }}
|
||||
|
||||
@@ -162,7 +162,7 @@ export default function NoControl({
|
||||
{/* Cross mark over center node (control denied) */}
|
||||
<motion.path
|
||||
d={`M ${center.x - 12} ${center.y - 12} L ${center.x + 12} ${center.y + 12} M ${center.x - 12} ${center.y + 12} L ${center.x + 12} ${center.y - 12}`}
|
||||
stroke="#FF4D4D"
|
||||
stroke="#8B8B8B"
|
||||
strokeWidth={3}
|
||||
strokeLinecap="round"
|
||||
initial={{ opacity: 0, scale: 0 }}
|
||||
|
||||
@@ -230,7 +230,7 @@ export default function NoExtraction({
|
||||
cx={center.x + 130}
|
||||
cy={center.y - 10}
|
||||
r={10}
|
||||
fill="#FF4D4D"
|
||||
fill="#8B8B8B"
|
||||
initial={{ scale: 0, opacity: 0 }}
|
||||
animate={{ scale: [0, 1.2, 0.8], opacity: [0, 1, 0] }}
|
||||
transition={{
|
||||
|
||||
@@ -10,8 +10,8 @@ type Props = {
|
||||
gridStroke?: string;
|
||||
};
|
||||
|
||||
const W = 720; // 4:3
|
||||
const H = 540; // 4:3
|
||||
const W = 760; // match aspect ratio closer to other home animations
|
||||
const H = 420; // align visual height with other cards
|
||||
|
||||
export default function NoSinglePoint({
|
||||
className,
|
||||
|
||||
@@ -20,7 +20,7 @@ export function HomeComparisonTable() {
|
||||
<Eyebrow>COMPARISON</Eyebrow>
|
||||
<H3 className="mt-2">Why People Choose Mycelium</H3>
|
||||
<P className="mx-auto mt-5 max-w-prose">
|
||||
Mycelium brings cloud-grade automation to infrastructure you control — without surrendering data, identity,
|
||||
Mycelium brings cloud-grade automation to infrastructure you control without surrendering data, identity,
|
||||
or uptime to centralized platforms.
|
||||
</P>
|
||||
|
||||
|
||||
@@ -19,7 +19,14 @@ export function HomeHero() {
|
||||
Start Hosting
|
||||
</Button>
|
||||
|
||||
<Button href="#" variant="outline" color="white">
|
||||
<Button
|
||||
as="a"
|
||||
to="https://myceliumcloud.tf"
|
||||
variant="outline"
|
||||
color="white"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Deploy in Cloud <span aria-hidden="true">→</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -39,8 +39,14 @@ export function HomeAurora({ onGetStartedClick }: { onGetStartedClick: () => voi
|
||||
>
|
||||
Start Hosting
|
||||
</Button>
|
||||
<Button to="#" variant="outline">
|
||||
Deploy in Cloud →
|
||||
<Button
|
||||
as="a"
|
||||
to="https://myceliumcloud.tf"
|
||||
variant="outline"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Deploy in Cloud
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@ const tabs = [
|
||||
label: "K8s Clusters",
|
||||
title: "K8s Clusters",
|
||||
description:
|
||||
"Deploy and scale containerized apps across your own hardware — enabling a world of possibilities.",
|
||||
"Deploy and scale containerized apps across your own hardware, enabling a world of possibilities.",
|
||||
link: "#",
|
||||
icon: CubeIcon,
|
||||
},
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Container } from '@/components/Container'
|
||||
import { Button } from "@/components/Button";
|
||||
|
||||
@@ -14,7 +13,7 @@ export function CallToAction() {
|
||||
{/* ✅ Main boxed area */}
|
||||
<div
|
||||
id="get-started"
|
||||
className="relative py-18 max-w-7xl mx-auto bg-[#111111] border border-t-0 border-b-0 border-gray-800"
|
||||
className="relative py-18 max-w-7xl mx-auto overflow-hidden bg-[#111111] border border-t-0 border-b-0 border-gray-800"
|
||||
>
|
||||
{/* ✅ Cyan Radial Glow */}
|
||||
<svg
|
||||
@@ -27,7 +26,7 @@ export function CallToAction() {
|
||||
cx={512}
|
||||
cy={512}
|
||||
fill="url(#mycelium-cyan-glow)"
|
||||
fillOpacity="0.2"
|
||||
fillOpacity="0.3"
|
||||
/>
|
||||
<defs>
|
||||
<radialGradient id="mycelium-cyan-glow">
|
||||
@@ -44,7 +43,7 @@ export function CallToAction() {
|
||||
Choose How You Want to Connect
|
||||
</h2>
|
||||
|
||||
<p className="mt-6 text-lg text-gray-300">
|
||||
<p className="mt-6 lg:text-lg text-base leading-normal text-gray-300">
|
||||
Choose How You Want to Connect
|
||||
Use the network to link environments, deploy workloads, or host nodes to strengthen the mesh and run on your own hardware.
|
||||
</p>
|
||||
@@ -56,16 +55,19 @@ Use the network to link environments, deploy workloads, or host nodes to strengt
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
to="/cloud"
|
||||
as="a"
|
||||
to="https://myceliumcloud.tf"
|
||||
variant="outline"
|
||||
color="white"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Deploy in Cloud
|
||||
</Button>
|
||||
|
||||
<Link to="/nodes" className="text-cyan-400 hover:text-cyan-300 transition-colors">
|
||||
<Button to="/nodes" variant="link" color="white">
|
||||
Host a Node →
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
|
||||
@@ -76,38 +76,45 @@ function BackgroundIllustration(props: React.ComponentPropsWithoutRef<'div'>) {
|
||||
|
||||
export function Hero() {
|
||||
return (
|
||||
<div className="overflow-hidden pb-24 lg:py-12 mt-10 lg:pb-0 border border-t-0 border-b border-gray-100">
|
||||
<div className="overflow-hidden pb-12 lg:py-12 mt-10 lg:pb-0 border border-t-0 border-b border-gray-100">
|
||||
<Container>
|
||||
<div className="flex flex-col-reverse gap-y-16 lg:grid lg:grid-cols-12 lg:gap-x-8 lg:gap-y-20 px-6 lg:px-8">
|
||||
<div className="relative z-10 mx-auto max-w-2xl lg:col-span-7 lg:max-w-none lg:pt-6 xl:col-span-6">
|
||||
<Eyebrow className="mb-4">
|
||||
MYCELIUM NETWORK
|
||||
</Eyebrow>
|
||||
<H3 className="mt-8 ">
|
||||
<H3 className="mt-4">
|
||||
The Network Stack for Private, Autonomous Networking
|
||||
</H3>
|
||||
<P className="mt-6 text-lg leading-tight text-gray-600 lg:text-xl lg:leading-normal">
|
||||
Connect once. Get private networking, censorship-resistant publishing, and on-network AI in one encrypted fabric.
|
||||
</P>
|
||||
<P className="mt-6 text-lg leading-tight text-gray-600 lg:text-xl lg:leading-normal">
|
||||
<P className="mt-4 text-lg leading-tight text-gray-600 lg:text-xl lg:leading-normal">
|
||||
Your Pod is your personal gateway to the network.
|
||||
</P>
|
||||
<div className="mt-8 flex flex-wrap gap-x-6 gap-y-4">
|
||||
<Button to="/download" variant="solid" color="cyan">
|
||||
Get Started
|
||||
</Button>
|
||||
<Button to="/download" variant="outline" color="cyan">
|
||||
Explore Docs
|
||||
<Button
|
||||
as="a"
|
||||
to="https://threefold.info/mycelium_network/docs/"
|
||||
variant="outline"
|
||||
color="gray"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Explore Docs
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative mt-0 lg:mt-10 lg:col-span-5 lg:row-span-2 xl:col-span-6">
|
||||
<BackgroundIllustration className="absolute left-1/2 top-4 h-[1026px] w-[1026px] -translate-x-1/2 stroke-gray-300/70 sm:top-16 lg:-top-12 lg:ml-12" />
|
||||
<div className="mx-auto h-[460px] max-w-[520px] mask-[linear-gradient(to_bottom,white_60%,transparent)] lg:absolute lg:-inset-x-10 lg:-top-24 lg:h-auto lg:pt-10 xl:-bottom-32">
|
||||
<div className="relative mt-8 lg:mt-10 lg:col-span-5 lg:row-span-2 xl:col-span-6">
|
||||
<BackgroundIllustration className="hidden md:block absolute left-1/2 top-4 h-[1026px] w-[1026px] -translate-x-1/2 stroke-gray-300/70 sm:top-16 lg:-top-12 lg:ml-12" />
|
||||
<div className="mx-auto max-w-[520px] flex items-center justify-center mask-[linear-gradient(to_bottom,white_60%,transparent)] lg:absolute lg:-inset-x-10 lg:-top-24 lg:h-auto lg:pt-10 xl:-bottom-32">
|
||||
<img
|
||||
src={phoneFrame}
|
||||
alt="Mycelium application demo"
|
||||
className="mx-auto w-auto max-w-[366px]"
|
||||
className="mx-auto w-full max-w-[366px] h-auto"
|
||||
width={366}
|
||||
height={729}
|
||||
/>
|
||||
|
||||