Initial commit
This commit is contained in:
22
src/pages/agents/AgentsPage.tsx
Normal file
22
src/pages/agents/AgentsPage.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { AnimatedSection } from '../../components/AnimatedSection'
|
||||
import { DeploySection } from './DeploySection'
|
||||
import { GallerySection } from './GallerySection'
|
||||
import { BentoSection } from './BentoSection'
|
||||
|
||||
export default function AgentsPage() {
|
||||
return (
|
||||
<div>
|
||||
<AnimatedSection>
|
||||
<DeploySection />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<GallerySection />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<BentoSection />
|
||||
</AnimatedSection>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
75
src/pages/agents/BentoSection.tsx
Normal file
75
src/pages/agents/BentoSection.tsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import { Container } from '../../components/Container'
|
||||
|
||||
const items = [
|
||||
{
|
||||
title: 'FungiStor',
|
||||
subtitle: 'Long-Term AI Memory',
|
||||
description: 'Erasure coding + compression slash storage bloat by up to 10× vs basic replication. Source-encrypted shards are geo-dispersed—lose pieces, rebuild perfectly from a quorum.',
|
||||
},
|
||||
{
|
||||
title: 'HeroDB',
|
||||
subtitle: 'Active AI Memory',
|
||||
description: 'Multimodal vector+keyword retrieval makes RAG feel instant across text, image, audio. Time-aware, policy-guarded context keeps results fresh while access stays governed.',
|
||||
},
|
||||
{
|
||||
title: 'MOS Sandboxes',
|
||||
subtitle: 'Secure Agent Workspaces',
|
||||
description: 'Attested, signed workspaces spin up ≈5s worldwide—ready to execute. Hardware isolation and scoped egress: run hard, tear down clean, zero residue.',
|
||||
},
|
||||
{
|
||||
title: 'Mycelium Mesh',
|
||||
subtitle: 'Secure Communication Network',
|
||||
description: 'A private, public-key fabric with self-healing multi-path routing. Glides through NATs and firewalls—direct, low-latency, no middlemen.',
|
||||
},
|
||||
{
|
||||
title: 'Deterministic Deployment',
|
||||
subtitle: 'Verifiable Code Execution',
|
||||
description: 'Declare intent, get a hash; remote attestation proves that is what runs. Reproducible builds, signed artifacts, immutable logs—supply chain, sealed.',
|
||||
},
|
||||
{
|
||||
title: 'Agent Coordination',
|
||||
subtitle: 'Sovereign Workflow Management',
|
||||
description: 'Your private agent conducts swarms of specialists in parallel. Policies fan out work; human checkpoints keep you in command.',
|
||||
},
|
||||
]
|
||||
|
||||
export function BentoSection() {
|
||||
return (
|
||||
<section className="bg-white py-20 lg:py-32">
|
||||
<Container>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="mx-auto max-w-3xl text-center mb-16"
|
||||
>
|
||||
<h2 className="text-3xl lg:text-4xl font-medium tracking-tight text-gray-900">
|
||||
Augmented Intelligence Fabric
|
||||
</h2>
|
||||
<p className="mt-6 text-lg text-gray-600">
|
||||
A complete infrastructure for building and deploying AI agents with enterprise-grade security and performance.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{items.map((item, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: index * 0.1 }}
|
||||
className="rounded-2xl bg-gray-50 border border-gray-200 p-6 hover:border-cyan-500 hover:shadow-lg transition-all duration-300"
|
||||
>
|
||||
<h3 className="text-xl font-semibold text-gray-900">{item.title}</h3>
|
||||
<p className="mt-2 text-sm font-medium text-cyan-500">{item.subtitle}</p>
|
||||
<p className="mt-3 text-sm text-gray-600">{item.description}</p>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
69
src/pages/agents/DeploySection.tsx
Normal file
69
src/pages/agents/DeploySection.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import { motion, useInView } from 'framer-motion'
|
||||
import { useRef } from 'react'
|
||||
import { TbCircleNumber1Filled, TbCircleNumber2Filled, TbCircleNumber3Filled } from 'react-icons/tb'
|
||||
import { Container } from '../../components/Container'
|
||||
|
||||
const features = [
|
||||
{
|
||||
name: 'Choose Your Intelligence',
|
||||
description: 'Explore a library of leading LLMs and agentic functions. Pick the ones that fit your use case, from general assistants to specialized reasoning models.',
|
||||
icon: TbCircleNumber1Filled,
|
||||
},
|
||||
{
|
||||
name: 'Add Your Knowledge',
|
||||
description:
|
||||
'Connect your data or knowledge base to enable personalized, context-aware results while keeping your information private.',
|
||||
icon: TbCircleNumber2Filled,
|
||||
},
|
||||
{
|
||||
name: 'Define Your Network',
|
||||
description:
|
||||
'Set up and manage your nodes with ease. Scale compute and storage as you grow, while staying fully sovereign and decentralized.',
|
||||
icon: TbCircleNumber3Filled,
|
||||
},
|
||||
]
|
||||
|
||||
export function DeploySection() {
|
||||
const ref = useRef(null)
|
||||
const isInView = useInView(ref, { once: true })
|
||||
|
||||
return (
|
||||
<section ref={ref} className="bg-white py-20 lg:py-32">
|
||||
<Container>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
||||
transition={{ duration: 0.8, delay: 0.1 }}
|
||||
className="mx-auto max-w-3xl text-center"
|
||||
>
|
||||
<h2 className="text-3xl lg:text-4xl font-medium tracking-tight text-gray-900">
|
||||
Deploy Scalable LLMs and AI Agents in Seconds
|
||||
</h2>
|
||||
<p className="mt-6 text-lg text-gray-600">
|
||||
Launch and scale intelligence on your own terms. Mycelium Cloud makes it simple to deploy models, integrate knowledge, and run everything on a network you control.
|
||||
</p>
|
||||
</motion.div>
|
||||
<motion.ul
|
||||
initial={{ opacity: 0 }}
|
||||
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
|
||||
transition={{ duration: 0.5, delay: 0.2, staggerChildren: 0.2 }}
|
||||
className="mx-auto mt-16 grid max-w-2xl grid-cols-1 gap-6 sm:grid-cols-2 lg:mx-0 lg:max-w-none lg:grid-cols-3"
|
||||
>
|
||||
{features.map((feature, index) => (
|
||||
<motion.li
|
||||
key={feature.name}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
||||
transition={{ duration: 0.5, delay: 0.3 + index * 0.2 }}
|
||||
className="rounded-2xl border border-gray-200 bg-gray-50 p-8 hover:border-cyan-500 hover:shadow-lg transition-all duration-300"
|
||||
>
|
||||
<feature.icon className="h-8 w-8 mb-4 text-cyan-500" />
|
||||
<h3 className="text-lg font-semibold text-gray-900">{feature.name}</h3>
|
||||
<p className="mt-3 text-sm text-gray-600">{feature.description}</p>
|
||||
</motion.li>
|
||||
))}
|
||||
</motion.ul>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
58
src/pages/agents/GallerySection.tsx
Normal file
58
src/pages/agents/GallerySection.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import { Container } from '../../components/Container'
|
||||
|
||||
const galleryItems = [
|
||||
{ text: 'Navigate and interact with any web interface', image: '/images/gallery/interface.jpg' },
|
||||
{ text: 'Process documents across all formats', image: '/images/gallery/docs.jpg' },
|
||||
{ text: 'Execute multi-step workflows autonomously', image: '/images/gallery/flow.jpg' },
|
||||
{ text: 'Manage calendars, emails, and tasks', image: '/images/gallery/calendar.jpg' },
|
||||
{ text: 'Perform deep semantic search across all data sources', image: '/images/gallery/data.jpg' },
|
||||
{ text: 'Identify patterns in complex datasets', image: '/images/gallery/datasets.jpg' },
|
||||
]
|
||||
|
||||
export function GallerySection() {
|
||||
return (
|
||||
<section className="bg-gray-50 py-20 lg:py-32">
|
||||
<Container>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="mx-auto max-w-3xl text-center mb-16"
|
||||
>
|
||||
<h2 className="text-3xl lg:text-4xl font-medium tracking-tight text-gray-900">
|
||||
Agents with Endless Possibilities.
|
||||
</h2>
|
||||
<p className="mt-6 text-lg text-gray-600">
|
||||
Your private agent coordinates a team of specialists that spin up on demand, collaborate across your world, and deliver end-to-end results. Many agents, one intelligence—yours.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{galleryItems.map((item, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: index * 0.1 }}
|
||||
className="group relative overflow-hidden rounded-2xl bg-white border border-gray-200 hover:border-cyan-500 hover:shadow-lg transition-all duration-300"
|
||||
>
|
||||
<div className="aspect-video overflow-hidden">
|
||||
<img
|
||||
src={item.image}
|
||||
alt={item.text}
|
||||
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
|
||||
/>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<p className="text-sm font-medium text-gray-900">{item.text}</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
36
src/pages/cloud/CloudCTA.tsx
Normal file
36
src/pages/cloud/CloudCTA.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import { Container } from '../../components/Container'
|
||||
import { Button } from '../../components/Button'
|
||||
import { CircleBackground } from '../../components/CircleBackground'
|
||||
|
||||
export function CloudCTA() {
|
||||
return (
|
||||
<section className="relative bg-white py-20 lg:py-32 overflow-hidden">
|
||||
<CircleBackground color="cyan" className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" />
|
||||
<Container className="relative">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="mx-auto max-w-3xl text-center"
|
||||
>
|
||||
<h2 className="text-3xl lg:text-5xl font-medium tracking-tight text-gray-900">
|
||||
Ready to Transform Your Kubernetes Experience?
|
||||
</h2>
|
||||
<p className="mt-6 text-lg lg:text-xl text-gray-600">
|
||||
Join thousands of developers and DevOps engineers who trust Mycelium Cloud for their production workloads.
|
||||
</p>
|
||||
<div className="mt-10 flex flex-wrap gap-4 justify-center">
|
||||
<Button to="/download" variant="solid" color="cyan">
|
||||
Start Your Free Trial
|
||||
</Button>
|
||||
<Button to="https://manual.grid.tf" variant="outline" color="gray">
|
||||
Read Documentation
|
||||
</Button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
65
src/pages/cloud/CloudHero.tsx
Normal file
65
src/pages/cloud/CloudHero.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import { Globe } from '../../components/ui/Globe'
|
||||
import { CountUpNumber } from '../../components/CountUpNumber'
|
||||
import { Container } from '../../components/Container'
|
||||
|
||||
const stats = [
|
||||
{ value: 54958, label: 'CPU Cores' },
|
||||
{ value: 1493, label: 'Nodes' },
|
||||
{ value: 5388956, label: 'GB Storage' },
|
||||
{ value: 44, label: 'Countries' },
|
||||
]
|
||||
|
||||
export function CloudHero() {
|
||||
return (
|
||||
<section className="relative bg-white py-20 lg:py-32">
|
||||
<Container>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
||||
{/* Text Content */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
>
|
||||
<h1 className="text-4xl lg:text-6xl font-medium tracking-tight text-gray-900">
|
||||
Mycelium Cloud
|
||||
</h1>
|
||||
<p className="mt-6 text-lg lg:text-xl text-gray-600">
|
||||
Revolutionary Kubernetes platform that transforms how teams deploy and manage cloud-native applications at scale
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
{/* Globe */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.8, delay: 0.2 }}
|
||||
className="flex items-center justify-center"
|
||||
>
|
||||
<div className="relative w-full max-w-[500px] aspect-square">
|
||||
<Globe className="w-full h-full" />
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* Stats */}
|
||||
<div className="mt-16 grid grid-cols-2 md:grid-cols-4 gap-6">
|
||||
{stats.map((stat, index) => (
|
||||
<motion.div
|
||||
key={stat.label}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5, delay: 0.4 + index * 0.1 }}
|
||||
className="rounded-2xl bg-gray-50 border border-gray-200 p-6 text-center hover:shadow-md transition-shadow"
|
||||
>
|
||||
<div className="text-2xl lg:text-3xl font-bold text-cyan-500">
|
||||
<CountUpNumber end={stat.value} />
|
||||
</div>
|
||||
<p className="mt-2 text-sm text-gray-600">{stat.label}</p>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
42
src/pages/cloud/CloudPage.tsx
Normal file
42
src/pages/cloud/CloudPage.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import { AnimatedSection } from '../../components/AnimatedSection'
|
||||
import { CloudHero } from './CloudHero'
|
||||
import { FeaturesSection } from './FeaturesSection'
|
||||
import { MyceliumNetworking } from './MyceliumNetworking'
|
||||
import { WebGateway } from './WebGateway'
|
||||
import { MultiMaster } from './MultiMaster'
|
||||
import { LoadBalancing } from './LoadBalancing'
|
||||
import { CloudCTA } from './CloudCTA'
|
||||
|
||||
export default function CloudPage() {
|
||||
return (
|
||||
<div>
|
||||
<AnimatedSection>
|
||||
<CloudHero />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<FeaturesSection />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<MyceliumNetworking />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<WebGateway />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<MultiMaster />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<LoadBalancing />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<CloudCTA />
|
||||
</AnimatedSection>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
75
src/pages/cloud/FeaturesSection.tsx
Normal file
75
src/pages/cloud/FeaturesSection.tsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import { Container } from '../../components/Container'
|
||||
|
||||
const features = [
|
||||
{
|
||||
icon: '☁️',
|
||||
title: 'Cloud-Native Architecture',
|
||||
description: 'Built for the cloud with support for all major cloud providers and on-premise deployments.',
|
||||
},
|
||||
{
|
||||
icon: '🛡️',
|
||||
title: 'Enterprise Security',
|
||||
description: 'Advanced security features including RBAC, network policies, and compliance monitoring.',
|
||||
},
|
||||
{
|
||||
icon: '📊',
|
||||
title: 'Real-time Monitoring',
|
||||
description: 'Comprehensive monitoring and alerting with detailed metrics and performance insights.',
|
||||
},
|
||||
{
|
||||
icon: '🚀',
|
||||
title: 'One-Click Deployments',
|
||||
description: 'Streamlined deployment process with automated CI/CD pipelines and rollback capabilities.',
|
||||
},
|
||||
{
|
||||
icon: '👥',
|
||||
title: 'Team Collaboration',
|
||||
description: 'Built-in collaboration tools for teams with role-based access and shared workspaces.',
|
||||
},
|
||||
{
|
||||
icon: '⚙️',
|
||||
title: 'Advanced Configuration',
|
||||
description: 'Flexible configuration management with support for Helm charts and custom resources.',
|
||||
},
|
||||
]
|
||||
|
||||
export function FeaturesSection() {
|
||||
return (
|
||||
<section className="bg-gray-50 py-20 lg:py-32">
|
||||
<Container>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="text-center mb-16"
|
||||
>
|
||||
<h2 className="text-3xl lg:text-4xl font-medium tracking-tight text-gray-900">
|
||||
Everything You Need to Succeed
|
||||
</h2>
|
||||
<p className="mt-6 text-lg text-gray-600 max-w-3xl mx-auto">
|
||||
Powerful tools and features designed for modern cloud-native applications
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{features.map((feature, index) => (
|
||||
<motion.div
|
||||
key={feature.title}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: index * 0.1 }}
|
||||
className="rounded-2xl bg-white border border-gray-200 p-8 hover:border-cyan-500 hover:shadow-lg transition-all duration-300 text-center"
|
||||
>
|
||||
<div className="text-4xl mb-4">{feature.icon}</div>
|
||||
<h3 className="text-xl font-semibold text-gray-900 mb-3">{feature.title}</h3>
|
||||
<p className="text-gray-600">{feature.description}</p>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
52
src/pages/cloud/LoadBalancing.tsx
Normal file
52
src/pages/cloud/LoadBalancing.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import { Container } from '../../components/Container'
|
||||
|
||||
export function LoadBalancing() {
|
||||
return (
|
||||
<section className="bg-gray-50 py-20 lg:py-32">
|
||||
<Container>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
||||
{/* Visual Placeholder */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="relative aspect-square rounded-2xl bg-gradient-to-br from-blue-50 to-cyan-50 border border-gray-200 flex items-center justify-center"
|
||||
>
|
||||
<div className="text-center p-8">
|
||||
<div className="text-6xl mb-4">⚖️</div>
|
||||
<p className="text-gray-600">Auto-scaling & Load Balancing</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Content */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: 20 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
>
|
||||
<h2 className="text-3xl lg:text-4xl font-medium tracking-tight text-gray-900">
|
||||
Effortless Load Balancing & Scaling
|
||||
</h2>
|
||||
<p className="mt-6 text-lg text-gray-600">
|
||||
Mycelium Cloud automatically balances traffic and scales your services up or down based on demand. Enjoy high availability and optimal performance with zero manual intervention.
|
||||
</p>
|
||||
<div className="mt-6 flex flex-wrap gap-3">
|
||||
<span className="inline-flex items-center rounded-full border border-cyan-500 px-4 py-2 text-sm font-medium text-cyan-500">
|
||||
Auto-scaling
|
||||
</span>
|
||||
<span className="inline-flex items-center rounded-full border border-cyan-500 px-4 py-2 text-sm font-medium text-cyan-500">
|
||||
Built-in load balancing
|
||||
</span>
|
||||
<span className="inline-flex items-center rounded-full border border-cyan-500 px-4 py-2 text-sm font-medium text-cyan-500">
|
||||
High availability
|
||||
</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
52
src/pages/cloud/MultiMaster.tsx
Normal file
52
src/pages/cloud/MultiMaster.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import { Container } from '../../components/Container'
|
||||
|
||||
export function MultiMaster() {
|
||||
return (
|
||||
<section className="bg-white py-20 lg:py-32">
|
||||
<Container>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
||||
{/* Content */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
>
|
||||
<h2 className="text-3xl lg:text-4xl font-medium tracking-tight text-gray-900">
|
||||
Multi-Master Clusters
|
||||
</h2>
|
||||
<p className="mt-6 text-lg text-gray-600">
|
||||
High-availability Kubernetes clusters with multiple control plane nodes. Automatic failover, leader election, and zero-downtime upgrades built-in.
|
||||
</p>
|
||||
<div className="mt-6 flex flex-wrap gap-3">
|
||||
<span className="inline-flex items-center rounded-full border border-cyan-500 px-4 py-2 text-sm font-medium text-cyan-500">
|
||||
HA Control Plane
|
||||
</span>
|
||||
<span className="inline-flex items-center rounded-full border border-cyan-500 px-4 py-2 text-sm font-medium text-cyan-500">
|
||||
Automatic Failover
|
||||
</span>
|
||||
<span className="inline-flex items-center rounded-full border border-cyan-500 px-4 py-2 text-sm font-medium text-cyan-500">
|
||||
Zero-downtime Upgrades
|
||||
</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Visual Placeholder */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: 20 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="relative aspect-square rounded-2xl bg-gradient-to-br from-cyan-50 to-blue-50 border border-gray-200 flex items-center justify-center"
|
||||
>
|
||||
<div className="text-center p-8">
|
||||
<div className="text-6xl mb-4">⚡</div>
|
||||
<p className="text-gray-600">High Availability Clusters</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
49
src/pages/cloud/MyceliumNetworking.tsx
Normal file
49
src/pages/cloud/MyceliumNetworking.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import { Container } from '../../components/Container'
|
||||
|
||||
export function MyceliumNetworking() {
|
||||
return (
|
||||
<section className="bg-white py-20 lg:py-32">
|
||||
<Container>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
||||
{/* Content */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
>
|
||||
<h2 className="text-3xl lg:text-4xl font-medium tracking-tight text-gray-900">
|
||||
Mycelium Networking
|
||||
</h2>
|
||||
<p className="mt-6 text-lg text-gray-600">
|
||||
Ultra-fast, decentralized networking inspired by nature. Mycelium Networking forms a resilient, adaptive mesh that routes around failures and optimizes for speed and security.
|
||||
</p>
|
||||
<div className="mt-6 flex flex-wrap gap-3">
|
||||
<span className="inline-flex items-center rounded-full border border-cyan-500 px-4 py-2 text-sm font-medium text-cyan-500">
|
||||
End-to-end encrypted
|
||||
</span>
|
||||
<span className="inline-flex items-center rounded-full border border-cyan-500 px-4 py-2 text-sm font-medium text-cyan-500">
|
||||
Nature-inspired
|
||||
</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Visual Placeholder */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: 20 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="relative aspect-square rounded-2xl bg-gradient-to-br from-cyan-50 to-blue-50 border border-gray-200 flex items-center justify-center"
|
||||
>
|
||||
<div className="text-center p-8">
|
||||
<div className="text-6xl mb-4">🕸️</div>
|
||||
<p className="text-gray-600">Decentralized Mesh Network</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
52
src/pages/cloud/WebGateway.tsx
Normal file
52
src/pages/cloud/WebGateway.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import { Container } from '../../components/Container'
|
||||
|
||||
export function WebGateway() {
|
||||
return (
|
||||
<section className="bg-gray-50 py-20 lg:py-32">
|
||||
<Container>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
||||
{/* Visual Placeholder */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="relative aspect-square rounded-2xl bg-gradient-to-br from-blue-50 to-cyan-50 border border-gray-200 flex items-center justify-center"
|
||||
>
|
||||
<div className="text-center p-8">
|
||||
<div className="text-6xl mb-4">🌐</div>
|
||||
<p className="text-gray-600">Simple Web Gateway</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Content */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: 20 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8 }}
|
||||
>
|
||||
<h2 className="text-3xl lg:text-4xl font-medium tracking-tight text-gray-900">
|
||||
Simple Web Gateway Access
|
||||
</h2>
|
||||
<p className="mt-6 text-lg text-gray-600">
|
||||
Expose any service to the public web with a simple Kubernetes resource. No complex Ingress controllers. Domain and prefix-based routing is built-in.
|
||||
</p>
|
||||
<div className="mt-6 flex flex-wrap gap-3">
|
||||
<span className="inline-flex items-center rounded-full border border-cyan-500 px-4 py-2 text-sm font-medium text-cyan-500">
|
||||
Simple configuration
|
||||
</span>
|
||||
<span className="inline-flex items-center rounded-full border border-cyan-500 px-4 py-2 text-sm font-medium text-cyan-500">
|
||||
Built-in routing
|
||||
</span>
|
||||
<span className="inline-flex items-center rounded-full border border-cyan-500 px-4 py-2 text-sm font-medium text-cyan-500">
|
||||
No ingress controllers
|
||||
</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
36
src/pages/home/HomeHero.tsx
Normal file
36
src/pages/home/HomeHero.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import { TypeAnimation } from 'react-type-animation'
|
||||
import { Container } from '../../components/Container'
|
||||
|
||||
export function HomeHero() {
|
||||
return (
|
||||
<section className="relative bg-white py-20 lg:py-32">
|
||||
<Container>
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h1 className="text-4xl lg:text-6xl font-medium tracking-tight text-gray-900">
|
||||
<TypeAnimation
|
||||
sequence={[
|
||||
'Decentralized Autonomous Agentic Cloud.',
|
||||
1000,
|
||||
]}
|
||||
wrapper="span"
|
||||
speed={50}
|
||||
repeat={0}
|
||||
/>
|
||||
</h1>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 1, delay: 1 }}
|
||||
className="mt-8"
|
||||
>
|
||||
<p className="text-lg lg:text-xl text-gray-600">
|
||||
Mycelium's advancements in Agentic infrastructure supports private, secure and autonomous Agents that connect, learn and grow with you.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
22
src/pages/home/HomePage.tsx
Normal file
22
src/pages/home/HomePage.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { AnimatedSection } from '../../components/AnimatedSection'
|
||||
import { HomeHero } from './HomeHero'
|
||||
import { WorldMapSection } from './WorldMapSection'
|
||||
import { StackSection } from './StackSection'
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<div>
|
||||
<AnimatedSection>
|
||||
<HomeHero />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<WorldMapSection />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<StackSection />
|
||||
</AnimatedSection>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
66
src/pages/home/StackSection.tsx
Normal file
66
src/pages/home/StackSection.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import { Container } from '../../components/Container'
|
||||
|
||||
const stackData = [
|
||||
{
|
||||
id: 'agent',
|
||||
title: 'Agent Layer',
|
||||
description:
|
||||
'Your sovereign agent with private memory and permissioned data access—always under your control. Choose from a wide library of open-source LLMs, paired with built-in semantic search and retrieval.',
|
||||
},
|
||||
{
|
||||
id: 'network',
|
||||
title: 'Network Layer',
|
||||
description:
|
||||
'A global, end-to-end encrypted overlay that simply doesn\'t break. Shortest-path routing moves your traffic the fastest way, every time with instant discovery.',
|
||||
},
|
||||
{
|
||||
id: 'cloud',
|
||||
title: 'Cloud Layer',
|
||||
description:
|
||||
'An autonomous, stateless OS that enforces pre-deterministic deployments you define. Workloads are cryptographically bound to your private key—location and access are yours.',
|
||||
},
|
||||
]
|
||||
|
||||
export function StackSection() {
|
||||
return (
|
||||
<section className="relative bg-white py-20 lg:py-32">
|
||||
<Container>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-12 items-start">
|
||||
{/* Left Column - Text */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5 }}
|
||||
className="lg:col-span-1"
|
||||
>
|
||||
<h2 className="text-3xl lg:text-4xl font-medium tracking-tight text-gray-900">
|
||||
The Mycelium Stack
|
||||
</h2>
|
||||
<p className="mt-6 text-lg text-gray-600">
|
||||
Built with Mycelium technology, our AI infrastructure ensures unbreakable networks, complete data sovereignty, ultra-secure agent-human communication, and unhackable data storage systems.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
{/* Right Column - Stack Cards */}
|
||||
<div className="lg:col-span-2 space-y-6">
|
||||
{stackData.map((layer, index) => (
|
||||
<motion.div
|
||||
key={layer.id}
|
||||
initial={{ opacity: 0, x: 20 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: index * 0.1 }}
|
||||
className="rounded-2xl bg-gray-50 border border-gray-200 p-6 hover:border-cyan-500 hover:shadow-lg transition-all duration-300"
|
||||
>
|
||||
<h3 className="text-xl font-semibold text-gray-900">{layer.title}</h3>
|
||||
<p className="mt-3 text-gray-600">{layer.description}</p>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
106
src/pages/home/WorldMapSection.tsx
Normal file
106
src/pages/home/WorldMapSection.tsx
Normal file
@@ -0,0 +1,106 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import { Globe } from '../../components/ui/Globe'
|
||||
import { CountUpNumber } from '../../components/CountUpNumber'
|
||||
import { Container } from '../../components/Container'
|
||||
|
||||
export function WorldMapSection() {
|
||||
return (
|
||||
<section className="relative bg-gray-50 py-20 lg:py-32">
|
||||
<Container>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5 }}
|
||||
className="mb-12"
|
||||
>
|
||||
<h2 className="text-3xl lg:text-4xl font-medium tracking-tight text-gray-900">
|
||||
Mycelium Network is Live.
|
||||
</h2>
|
||||
</motion.div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
||||
{/* Globe */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
whileInView={{ opacity: 1, scale: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: 0.2 }}
|
||||
className="flex items-center justify-center"
|
||||
>
|
||||
<div className="relative w-full max-w-[500px] aspect-square">
|
||||
<Globe className="w-full h-full" />
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Stats Cards */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: 0.3 }}
|
||||
className="rounded-2xl bg-white border border-gray-200 p-6 shadow-sm hover:shadow-md transition-shadow"
|
||||
>
|
||||
<p className="text-sm font-semibold uppercase tracking-wide text-cyan-500">CORES</p>
|
||||
<div className="mt-2 text-3xl font-bold text-gray-900">
|
||||
<CountUpNumber end={54958} />
|
||||
</div>
|
||||
<p className="mt-2 text-sm text-gray-600">
|
||||
Total Central Processing Unit Cores available on the grid.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: 0.4 }}
|
||||
className="rounded-2xl bg-white border border-gray-200 p-6 shadow-sm hover:shadow-md transition-shadow"
|
||||
>
|
||||
<p className="text-sm font-semibold uppercase tracking-wide text-cyan-500">NODES</p>
|
||||
<div className="mt-2 text-3xl font-bold text-gray-900">
|
||||
<CountUpNumber end={1493} />
|
||||
</div>
|
||||
<p className="mt-2 text-sm text-gray-600">
|
||||
Total number of nodes on the grid.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: 0.5 }}
|
||||
className="rounded-2xl bg-white border border-gray-200 p-6 shadow-sm hover:shadow-md transition-shadow"
|
||||
>
|
||||
<p className="text-sm font-semibold uppercase tracking-wide text-cyan-500">SSD CAPACITY</p>
|
||||
<div className="mt-2 text-3xl font-bold text-gray-900">
|
||||
<CountUpNumber end={5388956} />
|
||||
</div>
|
||||
<p className="mt-2 text-sm text-gray-600">
|
||||
Total GB amount of storage (SSD, HDD, & RAM) on the grid.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: 0.6 }}
|
||||
className="rounded-2xl bg-white border border-gray-200 p-6 shadow-sm hover:shadow-md transition-shadow"
|
||||
>
|
||||
<p className="text-sm font-semibold uppercase tracking-wide text-cyan-500">COUNTRIES</p>
|
||||
<div className="mt-2 text-3xl font-bold text-gray-900">
|
||||
<CountUpNumber end={44} />
|
||||
</div>
|
||||
<p className="mt-2 text-sm text-gray-600">
|
||||
Total number of countries with active nodes.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
41
src/pages/network/About.tsx
Normal file
41
src/pages/network/About.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import { Button } from '../../components/Button'
|
||||
import { CircleBackground } from '../../components/CircleBackground'
|
||||
import { Container } from '../../components/Container'
|
||||
|
||||
export function About() {
|
||||
return (
|
||||
<section
|
||||
id="about"
|
||||
className="relative overflow-hidden bg-gray-900 py-20 lg:py-32 lg:top-0 top-0"
|
||||
>
|
||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||
<CircleBackground color="#06b6d4" className="animate-spin-slower" />
|
||||
</div>
|
||||
<Container className="relative">
|
||||
<div className="mx-auto max-w-3xl text-center">
|
||||
<h2 className="text-base/7 font-semibold text-cyan-500">Our Mission</h2>
|
||||
<p className="text-3xl lg:text-4xl font-medium tracking-tight text-white sm:text-4xl">
|
||||
Discover Mycelium
|
||||
</p>
|
||||
<p className="mt-6 text-lg text-gray-300">
|
||||
Mycelium is an unbreakable network, always finding the shortest path and providing 100% secure, peer-to-peer communication. But this is just the beginning.
|
||||
</p>
|
||||
<p className="mt-6 text-lg text-gray-300">
|
||||
Our mission is to create a sustainable digital ecosystem where communication is seamless, data is secure, and scalability knows no bounds.
|
||||
</p>
|
||||
<div className="mt-8 flex justify-center">
|
||||
<Button
|
||||
to="https://threefold.info/mycelium_network/docs/"
|
||||
as="a"
|
||||
target="_blank"
|
||||
variant="outline"
|
||||
color="white"
|
||||
>
|
||||
Learn More
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
40
src/pages/network/CallToAction.tsx
Normal file
40
src/pages/network/CallToAction.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import { CircleBackground } from '../../components/CircleBackground'
|
||||
import { Container } from '../../components/Container'
|
||||
import { Button } from '../../components/Button'
|
||||
|
||||
export function CallToAction() {
|
||||
return (
|
||||
<section
|
||||
id="get-started"
|
||||
className="relative overflow-hidden bg-gray-900 py-20 sm:py-28"
|
||||
>
|
||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||
<CircleBackground color="#06b6d4" className="animate-spin-slower" />
|
||||
</div>
|
||||
<Container className="relative">
|
||||
<div className="mx-auto max-w-2xl text-center">
|
||||
<h2 className="text-3xl lg:text-4xl font-medium tracking-tight text-white sm:text-4xl">
|
||||
Get Started Today
|
||||
</h2>
|
||||
<p className="mt-6 text-lg text-gray-300">
|
||||
Download the Mycelium app and step into the future of secure, peer-to-peer networking; fast, private, and decentralized.
|
||||
</p>
|
||||
<div className="mt-10 flex flex-wrap justify-center gap-x-6 gap-y-4">
|
||||
<Button to="/download" variant="solid" color="white">
|
||||
Get Mycelium
|
||||
</Button>
|
||||
<Button
|
||||
to="https://threefold.info/mycelium_network/docs/"
|
||||
as="a"
|
||||
target="_blank"
|
||||
variant="outline"
|
||||
color="white"
|
||||
>
|
||||
Read Docs
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
111
src/pages/network/Features.tsx
Normal file
111
src/pages/network/Features.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
import Pathfinding from './animations/Pathfinding'
|
||||
import MessageBus from './animations/MessageBus'
|
||||
import ProxyDetection from './animations/ProxyDetection'
|
||||
import ProxyForwarding from './animations/ProxyForwarding'
|
||||
import ContentDistribution from './animations/ContentDistribution'
|
||||
|
||||
export function Features() {
|
||||
return (
|
||||
<section id="features" className="py-24">
|
||||
<div className="mx-auto max-w-2xl px-6 lg:max-w-7xl lg:px-8">
|
||||
<h2 className="text-base/7 font-semibold text-cyan-500">Core Components</h2>
|
||||
<p className="mt-2 max-w-2xl text-3xl lg:text-4xl font-medium tracking-tight text-pretty text-gray-950">
|
||||
Network Capabilities
|
||||
</p>
|
||||
<p className="mt-4 max-w-4xl text-lg text-gray-600">
|
||||
Built for resilience and autonomy, the Mycelium Network dynamically connects nodes through intelligent routing, proxy discovery, and decentralized delivery.
|
||||
</p>
|
||||
<p className="mt-2 max-w-4xl text-lg text-gray-600">
|
||||
Each component — from message passing to content distribution — works in harmony to create a fully self-healing, self-optimizing data mesh.
|
||||
</p>
|
||||
<div className="mt-10 grid grid-cols-1 gap-x-4 gap-y-8 sm:mt-16 lg:grid-cols-6 lg:grid-rows-2">
|
||||
<div className="group relative lg:col-span-3 transition-all duration-300 ease-in-out hover:scale-105">
|
||||
<div className="absolute inset-0 rounded-lg bg-white max-lg:rounded-t-4xl lg:rounded-tl-4xl" />
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] max-lg:rounded-t-[calc(2rem+1px)] lg:rounded-tl-[calc(2rem+1px)]">
|
||||
<Pathfinding />
|
||||
<div className="p-10 pt-4">
|
||||
<h3 className="text-sm/4 font-semibold text-cyan-500">Routing</h3>
|
||||
<p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
|
||||
Automatic pathfinding
|
||||
</p>
|
||||
<p className="mt-2 max-w-lg text-sm/6 text-gray-600">
|
||||
The Mycelium Network automatically discovers the shortest and fastest routes between nodes,
|
||||
ensuring optimal data flow and network efficiency without manual configuration.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pointer-events-none absolute inset-0 rounded-lg shadow-sm outline outline-black/5 max-lg:rounded-t-4xl lg:rounded-tl-4xl group-hover:outline-cyan-500 group-hover:shadow-lg group-hover:shadow-cyan-500/20" />
|
||||
</div>
|
||||
<div className="group relative lg:col-span-3 transition-all duration-300 ease-in-out hover:scale-105">
|
||||
<div className="absolute inset-0 rounded-lg bg-white lg:rounded-tr-4xl" />
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] lg:rounded-tr-[calc(2rem+1px)]">
|
||||
<MessageBus />
|
||||
<div className="p-10 pt-4">
|
||||
<h3 className="text-sm/4 font-semibold text-cyan-500">Communication</h3>
|
||||
<p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
|
||||
Distributed message bus
|
||||
</p>
|
||||
<p className="mt-2 max-w-lg text-sm/6 text-gray-600">
|
||||
Acts as a global message layer that lets nodes exchange information seamlessly.
|
||||
Enables resilient, asynchronous communication across the entire decentralized mesh.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pointer-events-none absolute inset-0 rounded-lg shadow-sm outline outline-black/5 lg:rounded-tr-4xl group-hover:outline-cyan-500 group-hover:shadow-lg group-hover:shadow-cyan-500/20" />
|
||||
</div>
|
||||
<div className="group relative lg:col-span-2 transition-all duration-300 ease-in-out hover:scale-105">
|
||||
<div className="absolute inset-0 rounded-lg bg-white lg:rounded-bl-4xl" />
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] lg:rounded-bl-[calc(2rem+1px)]">
|
||||
<ProxyDetection className="h-80" />
|
||||
<div className="p-10 pt-4">
|
||||
<h3 className="text-sm/4 font-semibold text-cyan-500">Discovery</h3>
|
||||
<p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
|
||||
Automatic proxy detection
|
||||
</p>
|
||||
<p className="mt-2 max-w-lg text-sm/6 text-gray-600">
|
||||
The system continuously scans for open SOCKS5 proxies within the network,
|
||||
making it effortless to find available connection points without manual setup.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pointer-events-none absolute inset-0 rounded-lg shadow-sm outline outline-black/5 lg:rounded-bl-4xl group-hover:outline-cyan-500 group-hover:shadow-lg group-hover:shadow-cyan-500/20" />
|
||||
</div>
|
||||
<div className="group relative lg:col-span-2 transition-all duration-300 ease-in-out hover:scale-105">
|
||||
<div className="absolute inset-0 rounded-lg bg-white" />
|
||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)]">
|
||||
<ProxyForwarding className="h-80" />
|
||||
<div className="p-10 pt-4">
|
||||
<h3 className="text-sm/4 font-semibold text-cyan-500">Connectivity</h3>
|
||||
<p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
|
||||
Seamless proxy forwarding
|
||||
</p>
|
||||
<p className="mt-2 max-w-lg text-sm/6 text-gray-600">
|
||||
Local SOCKS5 connections can be forwarded through nearby nodes or remote proxies.
|
||||
When browsers use the local proxy, traffic moves securely through the mesh—like a built-in VPN.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pointer-events-none absolute inset-0 rounded-lg shadow-sm outline outline-black/5 group-hover:outline-cyan-500 group-hover:shadow-lg group-hover:shadow-cyan-500/20" />
|
||||
</div>
|
||||
<div className="group relative lg:col-span-2 transition-all duration-300 ease-in-out hover:scale-105">
|
||||
<div className="absolute inset-0 rounded-lg bg-white max-lg:rounded-b-4xl lg:rounded-br-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-br-[calc(2rem+1px)]">
|
||||
<ContentDistribution className="h-80" />
|
||||
<div className="p-10 pt-4">
|
||||
<h3 className="text-sm/4 font-semibold text-cyan-500">Delivery</h3>
|
||||
<p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
|
||||
Decentralized content distribution
|
||||
</p>
|
||||
<p className="mt-2 max-w-lg text-sm/6 text-gray-600">
|
||||
Mycelium can serve data from distributed 0-DBs, creating a CDN-like layer that delivers
|
||||
content faster and more reliably—without relying on centralized servers.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pointer-events-none absolute inset-0 rounded-lg shadow-sm outline outline-black/5 max-lg:rounded-b-4xl lg:rounded-br-4xl group-hover:outline-cyan-500 group-hover:shadow-lg group-hover:shadow-cyan-500/20" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
114
src/pages/network/Hero.tsx
Normal file
114
src/pages/network/Hero.tsx
Normal file
@@ -0,0 +1,114 @@
|
||||
import { useId } from 'react'
|
||||
import { Container } from '../../components/Container'
|
||||
import { Button } from '../../components/Button'
|
||||
|
||||
function BackgroundIllustration(props: React.ComponentPropsWithoutRef<'div'>) {
|
||||
let id = useId()
|
||||
|
||||
return (
|
||||
<div {...props}>
|
||||
<svg
|
||||
viewBox="0 0 1026 1026"
|
||||
fill="none"
|
||||
aria-hidden="true"
|
||||
className="absolute inset-0 h-full w-full animate-spin-slow"
|
||||
>
|
||||
<path
|
||||
d="M1025 513c0 282.77-229.23 512-512 512S1 795.77 1 513 230.23 1 513 1s512 229.23 512 512Z"
|
||||
stroke="#D4D4D4"
|
||||
strokeOpacity="0.7"
|
||||
/>
|
||||
<path
|
||||
d="M513 1025C230.23 1025 1 795.77 1 513"
|
||||
stroke={`url(#${id}-gradient-1)`}
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id={`${id}-gradient-1`}
|
||||
x1="1"
|
||||
y1="513"
|
||||
x2="1"
|
||||
y2="1025"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#06b6d4" />
|
||||
<stop offset="1" stopColor="#06b6d4" stopOpacity="0" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
<svg
|
||||
viewBox="0 0 1026 1026"
|
||||
fill="none"
|
||||
aria-hidden="true"
|
||||
className="absolute inset-0 h-full w-full animate-spin-reverse-slower"
|
||||
>
|
||||
<path
|
||||
d="M913 513c0 220.914-179.086 400-400 400S113 733.914 113 513s179.086-400 400-400 400 179.086 400 400Z"
|
||||
stroke="#D4D4D4"
|
||||
strokeOpacity="0.7"
|
||||
/>
|
||||
<path
|
||||
d="M913 513c0 220.914-179.086 400-400 400"
|
||||
stroke={`url(#${id}-gradient-2)`}
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id={`${id}-gradient-2`}
|
||||
x1="913"
|
||||
y1="513"
|
||||
x2="913"
|
||||
y2="913"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#06b6d4" />
|
||||
<stop offset="1" stopColor="#06b6d4" stopOpacity="0" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function Hero() {
|
||||
return (
|
||||
<div className="overflow-hidden lg:py-32 lg:pb-0 pb-24">
|
||||
<Container>
|
||||
<div className="flex flex-col-reverse gap-y-16 lg:grid lg:grid-cols-12 lg:gap-x-8 lg:gap-y-20">
|
||||
<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">
|
||||
<h1 className="text-4xl lg:text-6xl font-medium tracking-tight text-gray-900">
|
||||
Mycelium
|
||||
</h1>
|
||||
<h2 className="mt-6 lg:text-2xl text-xl tracking-tight leading-normal text-gray-600">
|
||||
Unleashing the Power of Decentralized Networks
|
||||
</h2>
|
||||
<p className="mt-6 lg:text-xl text-lg text-gray-600 lg:leading-normal leading-tight">
|
||||
Discover Mycelium, an end-to-end encrypted IPv6 overlay network. The future of secure, efficient, and scalable networking.
|
||||
</p>
|
||||
<p className="mt-6 text-lg text-gray-600">
|
||||
Coming Soon: New Decentralized Features
|
||||
</p>
|
||||
<div className="mt-8 flex flex-wrap gap-x-6 gap-y-4">
|
||||
<Button to="/download" variant="solid" color="cyan">
|
||||
Get Mycelium
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative lg:mt-10 mt-0 lg:col-span-5 lg:row-span-2 xl:col-span-6">
|
||||
<BackgroundIllustration className="absolute top-4 left-1/2 h-[1026px] w-[1026px] -translate-x-1/2 stroke-gray-300/70 sm:top-16 lg:-top-12 lg:ml-12 ml-0" />
|
||||
<div className="mx-auto h-[448px] mask-[linear-gradient(to_bottom,white_60%,transparent)] lg:px-0 lg:absolute lg:-inset-x-10 lg:-top-24 lg:h-auto lg:pt-10 xl:-bottom-32">
|
||||
<img
|
||||
src="/src/images/phoneframe.png"
|
||||
alt="Mycelium application demo"
|
||||
className="mx-auto max-w-[366px]"
|
||||
width={366}
|
||||
height={729}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
32
src/pages/network/NetworkPage.tsx
Normal file
32
src/pages/network/NetworkPage.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import { AnimatedSection } from '../../components/AnimatedSection'
|
||||
import { Hero } from './Hero'
|
||||
import { About } from './About'
|
||||
import { Features } from './Features'
|
||||
import { PrimaryFeatures } from './PrimaryFeatures'
|
||||
import { SecondaryFeatures } from './SecondaryFeatures'
|
||||
import { CallToAction } from './CallToAction'
|
||||
|
||||
export default function NetworkPage() {
|
||||
return (
|
||||
<>
|
||||
<AnimatedSection>
|
||||
<Hero />
|
||||
</AnimatedSection>
|
||||
<AnimatedSection>
|
||||
<About />
|
||||
</AnimatedSection>
|
||||
<AnimatedSection>
|
||||
<Features />
|
||||
</AnimatedSection>
|
||||
<AnimatedSection>
|
||||
<PrimaryFeatures />
|
||||
</AnimatedSection>
|
||||
<AnimatedSection>
|
||||
<SecondaryFeatures />
|
||||
</AnimatedSection>
|
||||
<AnimatedSection>
|
||||
<CallToAction />
|
||||
</AnimatedSection>
|
||||
</>
|
||||
)
|
||||
}
|
||||
28
src/pages/network/PrimaryFeatures.tsx
Normal file
28
src/pages/network/PrimaryFeatures.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Container } from '../../components/Container'
|
||||
|
||||
export function PrimaryFeatures() {
|
||||
return (
|
||||
<section
|
||||
id="howitworks"
|
||||
aria-label="How Mycelium works"
|
||||
className="bg-gray-900 py-20 sm:py-32"
|
||||
>
|
||||
<Container>
|
||||
<div className="mx-auto max-w-2xl lg:mx-0 lg:max-w-3xl">
|
||||
<h2 className="text-base/7 font-semibold text-cyan-500">How It Works</h2>
|
||||
<p className="text-3xl lg:text-4xl font-medium tracking-tight text-white">
|
||||
How Mycelium Operates
|
||||
</p>
|
||||
<p className="mt-6 text-lg text-gray-300">
|
||||
Mycelium, like its natural namesake, thrives on decentralization, efficiency, and security, making it a truly powerful force in the world of decentralized networks.
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-16 text-center">
|
||||
<p className="text-lg text-gray-400">
|
||||
Interactive features demonstration coming soon...
|
||||
</p>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
225
src/pages/network/SecondaryFeatures.tsx
Normal file
225
src/pages/network/SecondaryFeatures.tsx
Normal file
@@ -0,0 +1,225 @@
|
||||
import { useId } from 'react'
|
||||
import { Container } from '../../components/Container'
|
||||
|
||||
const features = [
|
||||
{
|
||||
name: 'Quantum Safe Storage Functionality',
|
||||
description:
|
||||
"Mycelium's quantum safe storage enables flexible, scalable, and efficient data distribution across a decentralized network, ensuring redundancy and security.",
|
||||
icon: DeviceArrowIcon,
|
||||
},
|
||||
{
|
||||
name: 'Entry and Exit Points for AI Workloads',
|
||||
description:
|
||||
'Seamlessly connect AI applications to Mycelium, providing optimized and secured data pipelines for training, inference, and real-time processing.',
|
||||
icon: DeviceCardsIcon,
|
||||
},
|
||||
{
|
||||
name: 'Data Storage and Retrieval Mechanisms',
|
||||
description:
|
||||
'Users can choose between storing data locally for quick access or utilizing the distributed grid for enhanced scalability and resilience.',
|
||||
icon: DeviceClockIcon,
|
||||
},
|
||||
{
|
||||
name: 'Integrated Name Services (DNS)',
|
||||
description:
|
||||
'The Integrated DNS system efficiently finds the shortest path between users and websites, automatically balancing loads and identifying alternative routes in case of internet issues.',
|
||||
icon: DeviceListIcon,
|
||||
},
|
||||
{
|
||||
name: 'Frontend/Backend Integration',
|
||||
description:
|
||||
'Mycelium provides seamless integration with existing applications, enabling developers to leverage decentralized storage across both frontend and backend architectures.',
|
||||
icon: DeviceLockIcon,
|
||||
},
|
||||
{
|
||||
name: 'CDN (Content Delivery Network)',
|
||||
description:
|
||||
'Mycelium accelerates data distribution by acting as a decentralized CDN, ensuring fast, secure, and efficient content delivery across global nodes with minimal latency.',
|
||||
icon: DeviceChartIcon,
|
||||
},
|
||||
]
|
||||
|
||||
function DeviceArrowIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
|
||||
return (
|
||||
<svg viewBox="0 0 32 32" aria-hidden="true" {...props}>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M9 0a4 4 0 00-4 4v24a4 4 0 004 4h14a4 4 0 004-4V4a4 4 0 00-4-4H9zm0 2a2 2 0 00-2 2v24a2 2 0 002 2h14a2 2 0 002-2V4a2 2 0 00-2-2h-1.382a1 1 0 00-.894.553l-.448.894a1 1 0 01-.894.553h-6.764a1 1 0 01-.894-.553l-.448-.894A1 1 0 0010.382 2H9z"
|
||||
fill="#737373"
|
||||
/>
|
||||
<path
|
||||
d="M12 25l8-8m0 0h-6m6 0v6"
|
||||
stroke="#171717"
|
||||
strokeWidth={2}
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<circle cx={16} cy={16} r={16} fill="#A3A3A3" fillOpacity={0.2} />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function DeviceCardsIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
|
||||
let id = useId()
|
||||
|
||||
return (
|
||||
<svg viewBox="0 0 32 32" aria-hidden="true" {...props}>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M9 0a4 4 0 00-4 4v24a4 4 0 004 4h14a4 4 0 004-4V4a4 4 0 00-4-4H9zm0 2a2 2 0 00-2 2v24a2 2 0 002 2h14a2 2 0 002-2V4a2 2 0 00-2-2h-1.382a1 1 0 00-.894.553l-.448.894a1 1 0 01-.894.553h-6.764a1 1 0 01-.894-.553l-.448-.894A1 1 0 0010.382 2H9z"
|
||||
fill="#737373"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M9 13a1 1 0 011-1h12a1 1 0 011 1v2a1 1 0 01-1 1H10a1 1 0 01-1-1v-2zm0 6a1 1 0 011-1h12a1 1 0 011 1v2a1 1 0 01-1 1H10a1 1 0 01-1-1v-2zm1 5a1 1 0 00-1 1v2a1 1 0 001 1h12a1 1 0 001-1v-2a1 1 0 00-1-1H10z"
|
||||
fill={`url(#${id}-gradient)`}
|
||||
/>
|
||||
<rect x={9} y={6} width={14} height={4} rx={1} fill="#171717" />
|
||||
<circle cx={16} cy={16} r={16} fill="#A3A3A3" fillOpacity={0.2} />
|
||||
<defs>
|
||||
<linearGradient
|
||||
id={`${id}-gradient`}
|
||||
x1={16}
|
||||
y1={12}
|
||||
x2={16}
|
||||
y2={28}
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#737373" />
|
||||
<stop offset={1} stopColor="#737373" stopOpacity={0} />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function DeviceClockIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
|
||||
return (
|
||||
<svg viewBox="0 0 32 32" aria-hidden="true" {...props}>
|
||||
<circle cx={16} cy={16} r={16} fill="#A3A3A3" fillOpacity={0.2} />
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M5 4a4 4 0 014-4h14a4 4 0 014 4v10h-2V4a2 2 0 00-2-2h-1.382a1 1 0 00-.894.553l-.448.894a1 1 0 01-.894.553h-6.764a1 1 0 01-.894-.553l-.448-.894A1 1 0 0010.382 2H9a2 2 0 00-2 2v24a2 2 0 002 2h5v2H9a4 4 0 01-4-4V4z"
|
||||
fill="#737373"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M24 32a8 8 0 100-16 8 8 0 000 16zm1-8.414V19h-2v5.414l4 4L28.414 27 25 23.586z"
|
||||
fill="#171717"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function DeviceListIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
|
||||
return (
|
||||
<svg viewBox="0 0 32 32" fill="none" aria-hidden="true" {...props}>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M9 0a4 4 0 00-4 4v24a4 4 0 004 4h14a4 4 0 004-4V4a4 4 0 00-4-4H9zm0 2a2 2 0 00-2 2v24a2 2 0 002 2h14a2 2 0 002-2V4a2 2 0 00-2-2h-1.382a1 1 0 00-.894.553l-.448.894a1 1 0 01-.894.553h-6.764a1 1 0 01-.894-.553l-.448-.894A1 1 0 0010.382 2H9z"
|
||||
fill="#737373"
|
||||
/>
|
||||
<circle cx={11} cy={14} r={2} fill="#171717" />
|
||||
<circle cx={11} cy={20} r={2} fill="#171717" />
|
||||
<circle cx={11} cy={26} r={2} fill="#171717" />
|
||||
<path
|
||||
d="M16 14h6M16 20h6M16 26h6"
|
||||
stroke="#737373"
|
||||
strokeWidth={2}
|
||||
strokeLinecap="square"
|
||||
/>
|
||||
<circle cx={16} cy={16} r={16} fill="#A3A3A3" fillOpacity={0.2} />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function DeviceLockIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
|
||||
return (
|
||||
<svg viewBox="0 0 32 32" aria-hidden="true" {...props}>
|
||||
<circle cx={16} cy={16} r={16} fill="#A3A3A3" fillOpacity={0.2} />
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M5 4a4 4 0 014-4h14a4 4 0 014 4v10h-2V4a2 2 0 00-2-2h-1.382a1 1 0 00-.894.553l-.448.894a1 1 0 01-.894.553h-6.764a1 1 0 01-.894-.553l-.448-.894A1 1 0 0010.382 2H9a2 2 0 00-2 2v24a2 2 0 002 2h5v2H9a4 4 0 01-4-4V4z"
|
||||
fill="#737373"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M18 19.5a3.5 3.5 0 117 0V22a2 2 0 012 2v6a2 2 0 01-2 2h-7a2 2 0 01-2-2v-6a2 2 0 012-2v-2.5zm2 2.5h3v-2.5a1.5 1.5 0 00-3 0V22z"
|
||||
fill="#171717"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function DeviceChartIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
|
||||
return (
|
||||
<svg viewBox="0 0 32 32" fill="none" aria-hidden="true" {...props}>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M9 0a4 4 0 00-4 4v24a4 4 0 004 4h14a4 4 0 004-4V4a4 4 0 00-4-4H9zm0 2a2 2 0 00-2 2v24a2 2 0 002 2h14a2 2 0 002-2V4a2 2 0 00-2-2h-1.382a1 1 0 00-.894.553l-.448.894a1 1 0 01-.894.553h-6.764a1 1 0 01-.894-.553l-.448-.894A1 1 0 0010.382 2H9z"
|
||||
fill="#737373"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M23 13.838V26a2 2 0 01-2 2H11a2 2 0 01-2-2V15.65l2.57 3.212a1 1 0 001.38.175L15.4 17.2a1 1 0 011.494.353l1.841 3.681c.399.797 1.562.714 1.843-.13L23 13.837z"
|
||||
fill="#171717"
|
||||
/>
|
||||
<path
|
||||
d="M10 12h12"
|
||||
stroke="#737373"
|
||||
strokeWidth={2}
|
||||
strokeLinecap="square"
|
||||
/>
|
||||
<circle cx={16} cy={16} r={16} fill="#A3A3A3" fillOpacity={0.2} />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function SecondaryFeatures() {
|
||||
return (
|
||||
<section
|
||||
id="comingsoon"
|
||||
aria-label="Features for building a portfolio"
|
||||
className="py-20 sm:py-32"
|
||||
>
|
||||
<Container>
|
||||
<div className="mx-auto max-w-4xl sm:text-center">
|
||||
<h2 className="text-base/7 font-semibold text-cyan-500">Roadmap</h2>
|
||||
<p className="text-3xl lg:text-4xl font-medium tracking-tight text-gray-900">
|
||||
Coming Soon: The Future of Mycelium
|
||||
</p>
|
||||
<p className="mt-6 text-lg text-gray-600">
|
||||
Mycelium is evolving to bring even more powerful decentralized features, designed to enhance your experience and expand possibilities. Be the first to explore what's coming next by staying connected with our latest updates.
|
||||
</p>
|
||||
</div>
|
||||
<ul
|
||||
role="list"
|
||||
className="mx-auto mt-16 grid max-w-2xl grid-cols-1 gap-6 text-sm sm:mt-20 sm:grid-cols-2 md:gap-y-10 lg:max-w-none lg:grid-cols-3"
|
||||
>
|
||||
{features.map((feature) => (
|
||||
<li
|
||||
key={feature.name}
|
||||
className="rounded-2xl border border-gray-200 p-8 transition-all duration-300 ease-in-out hover:scale-105 hover:border-cyan-500 hover:shadow-lg hover:shadow-cyan-500/20"
|
||||
>
|
||||
<feature.icon className="h-8 w-8" />
|
||||
<h3 className="mt-6 font-semibold text-gray-900">
|
||||
{feature.name}
|
||||
</h3>
|
||||
<p className="mt-2 text-gray-700">{feature.description}</p>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
161
src/pages/network/animations/ContentDistribution.tsx
Normal file
161
src/pages/network/animations/ContentDistribution.tsx
Normal file
@@ -0,0 +1,161 @@
|
||||
import { motion, useReducedMotion } from 'framer-motion';
|
||||
|
||||
type Props = {
|
||||
className?: string;
|
||||
bg?: string;
|
||||
};
|
||||
|
||||
const ACCENT = '#00b8db';
|
||||
const STROKE = '#111827';
|
||||
const GRAY = '#9CA3AF';
|
||||
const GRAY_LT = '#E5E7EB';
|
||||
|
||||
const IconSquare = () => (
|
||||
<rect x={-14} y={-14} width={28} height={28} rx={6} fill={ACCENT} stroke={STROKE} strokeWidth={3} />
|
||||
);
|
||||
const IconTriangle = () => (
|
||||
<path d="M 0 -15 L 14 12 L -14 12 Z" fill="#fff" stroke={STROKE} strokeWidth={3} />
|
||||
);
|
||||
const IconHex = () => (
|
||||
<path
|
||||
d="M 0 -15 L 13 -7 L 13 7 L 0 15 L -13 7 L -13 -7 Z"
|
||||
fill="#fff"
|
||||
stroke={STROKE}
|
||||
strokeWidth={3}
|
||||
/>
|
||||
);
|
||||
const IconBolt = () => (
|
||||
<path d="M -5 -14 L 4 -2 L -1 -2 L 5 14 L -6 1 L -1 1 Z" fill={ACCENT} stroke={STROKE} strokeWidth={3} />
|
||||
);
|
||||
const IconPlay = () => (
|
||||
<circle r={15} fill="#fff" stroke={STROKE} strokeWidth={3} />
|
||||
);
|
||||
const IconDB = () => (
|
||||
<>
|
||||
<ellipse cx={0} cy={-10} rx={16} ry={8} fill="#fff" stroke={STROKE} strokeWidth={3} />
|
||||
<rect x={-16} y={-10} width={32} height={20} fill="#fff" stroke={STROKE} strokeWidth={3} />
|
||||
<ellipse cx={0} cy={10} rx={16} ry={8} fill="#fff" stroke={STROKE} strokeWidth={3} />
|
||||
</>
|
||||
);
|
||||
|
||||
function Cloud({ pulse = true }: { pulse?: boolean }) {
|
||||
const prefersReduced = useReducedMotion();
|
||||
return (
|
||||
<g>
|
||||
<g fill={STROKE}>
|
||||
<circle cx={-18} cy={0} r={14} />
|
||||
<circle cx={0} cy={-10} r={18} />
|
||||
<circle cx={18} cy={0} r={16} />
|
||||
<rect x={-30} y={0} width={54} height={16} rx={8} />
|
||||
</g>
|
||||
<motion.circle
|
||||
r={36}
|
||||
fill="none"
|
||||
stroke={ACCENT}
|
||||
strokeWidth={4}
|
||||
initial={{ opacity: 0.15, scale: 0.9 }}
|
||||
animate={pulse && !prefersReduced ? { opacity: [0.15, 0.35, 0.15], scale: [0.9, 1.05, 0.9] } : {}}
|
||||
transition={{ duration: 1.8, repeat: Infinity }}
|
||||
/>
|
||||
</g>
|
||||
);
|
||||
}
|
||||
|
||||
function Beam({
|
||||
x2,
|
||||
y2,
|
||||
delay = 0,
|
||||
}: {
|
||||
x2: number;
|
||||
y2: number;
|
||||
delay?: number;
|
||||
}) {
|
||||
const prefersReduced = useReducedMotion();
|
||||
return (
|
||||
<motion.line
|
||||
x1={0}
|
||||
y1={0}
|
||||
x2={x2}
|
||||
y2={y2}
|
||||
stroke={ACCENT}
|
||||
strokeWidth={4}
|
||||
strokeLinecap="round"
|
||||
initial={{ pathLength: 0, opacity: 0.0 }}
|
||||
animate={{ pathLength: 1, opacity: 0.9 }}
|
||||
transition={{
|
||||
duration: prefersReduced ? 0.01 : 0.9,
|
||||
delay,
|
||||
repeat: prefersReduced ? 0 : Infinity,
|
||||
repeatDelay: 1.2,
|
||||
repeatType: 'reverse',
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default function ContentDistribution({ className, bg = '#ffffff' }: Props) {
|
||||
const W = 900;
|
||||
const H = 560;
|
||||
|
||||
const rings = [110, 190, 270];
|
||||
|
||||
const layout = [
|
||||
{ r: rings[1], a: -20, icon: <IconSquare /> },
|
||||
{ r: rings[2], a: 20, icon: <IconTriangle /> },
|
||||
{ r: rings[0], a: 155, icon: <IconHex /> },
|
||||
{ r: rings[2], a: -145, icon: <IconBolt /> },
|
||||
{ r: rings[1], a: 210, icon: <IconDB /> },
|
||||
{ r: rings[0], a: 60, icon: <IconPlay /> },
|
||||
];
|
||||
|
||||
const prefersReduced = useReducedMotion();
|
||||
|
||||
return (
|
||||
<div className={className} aria-hidden="true" role="img" style={{ background: bg }}>
|
||||
<svg viewBox={`0 0 ${W} ${H}`} width="100%" height="100%">
|
||||
<defs>
|
||||
<radialGradient id="fade" cx="50%" cy="50%" r="60%">
|
||||
<stop offset="0%" stopColor="#ffffff" />
|
||||
<stop offset="100%" stopColor="#ffffff" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<rect width={W} height={H} fill="url(#fade)" />
|
||||
<g transform={`translate(${W / 2}, ${H / 2})`}>
|
||||
{rings.map((r, i) => (
|
||||
<circle key={i} r={r} fill="none" stroke={GRAY_LT} strokeWidth={2} />
|
||||
))}
|
||||
|
||||
<Cloud />
|
||||
|
||||
<motion.g
|
||||
initial={{ rotate: 0 }}
|
||||
animate={{ rotate: prefersReduced ? 0 : 360 }}
|
||||
transition={{ duration: 40, ease: 'linear', repeat: prefersReduced ? 0 : Infinity }}
|
||||
>
|
||||
{layout.map((n, i) => {
|
||||
const rad = (n.a * Math.PI) / 180;
|
||||
const x = n.r * Math.cos(rad);
|
||||
const y = n.r * Math.sin(rad);
|
||||
return <Beam key={`beam-${i}`} x2={x} y2={y} delay={i * 0.15} />;
|
||||
})}
|
||||
|
||||
{layout.map((n, i) => {
|
||||
const rad = (n.a * Math.PI) / 180;
|
||||
const x = n.r * Math.cos(rad);
|
||||
const y = n.r * Math.sin(rad);
|
||||
return (
|
||||
<g key={`badge-${i}`} transform={`translate(${x}, ${y})`}>
|
||||
<circle r={34} fill="#fff" stroke={GRAY_LT} strokeWidth={3} />
|
||||
<g transform="scale(1)">
|
||||
{n.icon}
|
||||
</g>
|
||||
</g>
|
||||
);
|
||||
})}
|
||||
</motion.g>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
132
src/pages/network/animations/MessageBus.tsx
Normal file
132
src/pages/network/animations/MessageBus.tsx
Normal file
@@ -0,0 +1,132 @@
|
||||
import { motion, useReducedMotion } from 'framer-motion';
|
||||
|
||||
type Props = {
|
||||
className?: string;
|
||||
bg?: string;
|
||||
};
|
||||
|
||||
const ACCENT = '#00b8db';
|
||||
const STROKE = '#111827';
|
||||
const GRAY = '#9CA3AF';
|
||||
const GRAY_LT = '#E5E7EB';
|
||||
|
||||
function Envelope({
|
||||
x, y, w = 88, h = 56, fill = GRAY_LT, accent = false, delay = 0, duration = 1.6,
|
||||
path = 'none',
|
||||
reverse = false,
|
||||
}: {
|
||||
x: number; y: number; w?: number; h?: number; fill?: string; accent?: boolean;
|
||||
delay?: number; duration?: number; path?: 'left1'|'left2'|'rightTop'|'rightBottom'|'none'; reverse?: boolean;
|
||||
}) {
|
||||
const prefersReduced = useReducedMotion();
|
||||
|
||||
const paths: Record<string, { x: number[]; y: number[] }> = {
|
||||
left1: { x: [x, 380], y: [y, 220] },
|
||||
left2: { x: [x, 380], y: [y, 220] },
|
||||
rightTop: { x: [380, 720], y: [220, 150] },
|
||||
rightBottom: { x: [380, 720], y: [220, 290] },
|
||||
none: { x: [x], y: [y] },
|
||||
};
|
||||
|
||||
const k = paths[path];
|
||||
|
||||
return (
|
||||
<motion.g
|
||||
initial={{ opacity: 0, scale: 0.98 }}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
x: prefersReduced ? 0 : (reverse ? [...k.x].reverse() : k.x),
|
||||
y: prefersReduced ? 0 : (reverse ? [...k.y].reverse() : k.y),
|
||||
}}
|
||||
transition={{
|
||||
delay,
|
||||
duration: prefersReduced ? 0.01 : duration,
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
repeat: prefersReduced ? 0 : Infinity,
|
||||
repeatDelay: 0.6,
|
||||
}}
|
||||
>
|
||||
<rect x={-w / 2} y={-h / 2} width={w} height={h} rx={8} fill={fill} stroke={STROKE} strokeWidth={3} />
|
||||
<path
|
||||
d={`M ${-w/2+4} ${-h/2+6} L 0 ${-h/2+26} L ${w/2-4} ${-h/2+6}`}
|
||||
fill="none"
|
||||
stroke={accent ? ACCENT : STROKE}
|
||||
strokeWidth={4}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</motion.g>
|
||||
);
|
||||
}
|
||||
|
||||
export default function MessageBus({ className, bg = '#ffffff' }: Props) {
|
||||
const W = 900;
|
||||
const H = 460;
|
||||
|
||||
return (
|
||||
<div className={className} aria-hidden="true" role="img" style={{ background: bg }}>
|
||||
<svg viewBox={`0 0 ${W} ${H}`} width="100%" height="100%">
|
||||
<defs>
|
||||
<pattern id="grid" width="24" height="24" patternUnits="userSpaceOnUse">
|
||||
<path d="M 24 0 L 0 0 0 24" fill="none" stroke={GRAY_LT} strokeWidth="1" />
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect width={W} height={H} fill="url(#grid)" />
|
||||
|
||||
{[{cx:140,cy:120},{cx:140,cy:340}].map((n,i)=>(
|
||||
<g key={i}>
|
||||
<circle cx={n.cx} cy={n.cy} r={44} fill="#fff" stroke={STROKE} strokeWidth={4}/>
|
||||
<motion.path
|
||||
d={`M ${n.cx+48} ${n.cy} L 320 ${n.cy>200?260:180}`}
|
||||
fill="none" stroke={STROKE} strokeWidth={4} strokeLinecap="round"
|
||||
initial={{ pathLength: 0, opacity: 0.3 }}
|
||||
animate={{ pathLength: 1, opacity: 1 }}
|
||||
transition={{ duration: 0.9, delay: 0.1 + i*0.1, ease: [0.22,1,0.36,1] }}
|
||||
/>
|
||||
</g>
|
||||
))}
|
||||
|
||||
{[{cx:760,cy:120},{cx:760,cy:340}].map((n,i)=>(
|
||||
<g key={i}>
|
||||
<circle cx={n.cx} cy={n.cy} r={44} fill="#fff" stroke={STROKE} strokeWidth={4}/>
|
||||
<motion.path
|
||||
d={`M 560 ${i===0?180:260} L ${n.cx-48} ${n.cy}`}
|
||||
fill="none" stroke={STROKE} strokeWidth={4} strokeLinecap="round"
|
||||
initial={{ pathLength: 0, opacity: 0.3 }}
|
||||
animate={{ pathLength: 1, opacity: 1 }}
|
||||
transition={{ duration: 0.9, delay: 0.2 + i*0.1, ease: [0.22,1,0.36,1] }}
|
||||
/>
|
||||
</g>
|
||||
))}
|
||||
|
||||
<rect x={330} y={150} width={240} height={140} rx={24} fill="#fff" stroke={STROKE} strokeWidth={4} />
|
||||
{[0,1,2].map(i=>(
|
||||
<rect key={i} x={350 + i*76} y={170} width={64} height={100} rx={12} fill="none" stroke={GRAY} strokeWidth={3}/>
|
||||
))}
|
||||
|
||||
<Envelope x={200} y={120} accent fill="#fff" path="left1" delay={0.0} duration={2.0}/>
|
||||
<Envelope x={200} y={340} fill={GRAY_LT} path="left2" delay={0.4} duration={2.2}/>
|
||||
<Envelope x={200} y={340} accent fill="#fff" path="left2" delay={0.9} duration={2.0}/>
|
||||
|
||||
{[0,1,2].map((i)=>(
|
||||
<motion.g key={i} transform={`translate(${382 + i*76} 220)`}>
|
||||
<motion.rect
|
||||
x={-28} y={-18} width={56} height={36} rx={8}
|
||||
fill={i===2 ? ACCENT : GRAY_LT}
|
||||
stroke={STROKE} strokeWidth={3}
|
||||
initial={{ opacity: 0.6 }}
|
||||
animate={{ opacity: [0.6, 1, 0.6] }}
|
||||
transition={{ duration: 1.8, repeat: Infinity, delay: i*0.2 }}
|
||||
/>
|
||||
<path d="M -24 -12 L 0 0 L 24 -12" fill="none" stroke={STROKE} strokeWidth={4} strokeLinecap="round" />
|
||||
</motion.g>
|
||||
))}
|
||||
|
||||
<Envelope x={560} y={180} accent fill="#fff" path="rightTop" delay={0.6} duration={2.1}/>
|
||||
<Envelope x={560} y={260} fill={GRAY_LT} path="rightBottom" delay={1.0} duration={2.3}/>
|
||||
<Envelope x={560} y={260} accent fill="#fff" path="rightBottom" delay={1.5} duration={2.0}/>
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
209
src/pages/network/animations/Pathfinding.tsx
Normal file
209
src/pages/network/animations/Pathfinding.tsx
Normal file
@@ -0,0 +1,209 @@
|
||||
// Animated SVG illustrating "Automatic pathfinding"
|
||||
import { motion, useReducedMotion } from 'framer-motion';
|
||||
import clsx from 'clsx';
|
||||
|
||||
type Props = {
|
||||
className?: string;
|
||||
accent?: string;
|
||||
stroke?: string;
|
||||
bg?: string;
|
||||
};
|
||||
|
||||
const Node = ({
|
||||
cx,
|
||||
cy,
|
||||
r = 16,
|
||||
fill = "#00b8db",
|
||||
ring = "#E5E7EB",
|
||||
pulse = false,
|
||||
rMotion = 2,
|
||||
}: {
|
||||
cx: number;
|
||||
cy: number;
|
||||
r?: number;
|
||||
fill?: string;
|
||||
ring?: string;
|
||||
pulse?: boolean;
|
||||
rMotion?: number;
|
||||
}) => {
|
||||
const prefersReduced = useReducedMotion();
|
||||
|
||||
return (
|
||||
<>
|
||||
<motion.circle
|
||||
cx={cx}
|
||||
cy={cy}
|
||||
r={r + 14}
|
||||
fill="none"
|
||||
stroke={ring}
|
||||
strokeWidth={2}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
/>
|
||||
<motion.circle
|
||||
cx={cx}
|
||||
cy={cy}
|
||||
r={r}
|
||||
fill={fill}
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
scale: pulse && !prefersReduced ? [1, 1 + rMotion / 16, 1] : 1,
|
||||
}}
|
||||
transition={{
|
||||
duration: pulse && !prefersReduced ? 1.8 : 0.6,
|
||||
repeat: pulse && !prefersReduced ? Infinity : 0,
|
||||
repeatType: "loop",
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const Arrow = ({
|
||||
d,
|
||||
color = "#111827",
|
||||
delay = 0,
|
||||
}: {
|
||||
d: string;
|
||||
color?: string;
|
||||
delay?: number;
|
||||
}) => (
|
||||
<motion.path
|
||||
d={d}
|
||||
fill="none"
|
||||
stroke={color}
|
||||
strokeWidth={3}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
initial={{ pathLength: 0, opacity: 0 }}
|
||||
animate={{ pathLength: 1, opacity: 1 }}
|
||||
transition={{
|
||||
delay,
|
||||
duration: 0.8,
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const DashedPath = ({
|
||||
d,
|
||||
color = "#9CA3AF",
|
||||
dash = 6,
|
||||
delay = 0,
|
||||
loop = false,
|
||||
}: {
|
||||
d: string;
|
||||
color?: string;
|
||||
dash?: number;
|
||||
delay?: number;
|
||||
loop?: boolean;
|
||||
}) => {
|
||||
const prefersReduced = useReducedMotion();
|
||||
|
||||
return (
|
||||
<motion.path
|
||||
d={d}
|
||||
fill="none"
|
||||
stroke={color}
|
||||
strokeWidth={3}
|
||||
strokeDasharray={dash}
|
||||
strokeLinecap="round"
|
||||
initial={{ pathLength: 0, opacity: 0.4 }}
|
||||
animate={{
|
||||
pathLength: 1,
|
||||
opacity: 1,
|
||||
}}
|
||||
transition={{
|
||||
delay,
|
||||
duration: 0.9,
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
repeat: !prefersReduced && loop ? Infinity : 0,
|
||||
repeatDelay: 1.2,
|
||||
repeatType: "reverse",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default function Pathfinding({
|
||||
className,
|
||||
accent = "#00b8db",
|
||||
stroke = "#111827",
|
||||
bg = "#FFFFFF",
|
||||
}: Props) {
|
||||
const W = 760;
|
||||
const H = 420;
|
||||
|
||||
const center = { x: 380, y: 210 };
|
||||
const nodes = [
|
||||
{ x: 130, y: 210 },
|
||||
{ x: 670, y: 210 },
|
||||
{ x: 380, y: 70 },
|
||||
{ x: 280, y: 340 },
|
||||
{ x: 500, y: 340 },
|
||||
];
|
||||
|
||||
const arrowTo = (from: { x: number; y: number }, to: { x: number; y: number }) => {
|
||||
const dx = to.x - from.x;
|
||||
const dy = to.y - from.y;
|
||||
const len = Math.hypot(dx, dy);
|
||||
const ux = dx / len;
|
||||
const uy = dy / len;
|
||||
const end = { x: to.x - ux * 18, y: to.y - uy * 18 };
|
||||
const headL = {
|
||||
x: end.x - uy * 8 - ux * 6,
|
||||
y: end.y + ux * 8 - uy * 6,
|
||||
};
|
||||
const headR = {
|
||||
x: end.x + uy * 8 - ux * 6,
|
||||
y: end.y - ux * 8 - uy * 6,
|
||||
};
|
||||
return `M ${from.x} ${from.y} L ${end.x} ${end.y} M ${headL.x} ${headL.y} L ${end.x} ${end.y} L ${headR.x} ${headR.y}`;
|
||||
};
|
||||
|
||||
const highlightA = `M ${nodes[0].x} ${nodes[0].y} L ${center.x} ${center.y}`;
|
||||
const highlightB = `M ${center.x} ${center.y} L ${nodes[4].x} ${nodes[4].y}`;
|
||||
|
||||
const alt1 = `M ${nodes[2].x} ${nodes[2].y} L ${center.x} ${center.y}`;
|
||||
const alt2 = `M ${nodes[3].x} ${nodes[3].y} L ${center.x} ${center.y}`;
|
||||
const alt3 = `M ${center.x} ${center.y} L ${nodes[1].x} ${nodes[1].y}`;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx("relative overflow-hidden", className)}
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
aria-label="Automatic pathfinding between nodes"
|
||||
style={{ background: bg }}
|
||||
>
|
||||
<svg viewBox={`0 0 ${W} ${H}`} className="w-full h-full">
|
||||
<defs>
|
||||
<pattern id="grid" width="24" height="24" patternUnits="userSpaceOnUse">
|
||||
<path d="M 24 0 L 0 0 0 24" fill="none" stroke="#F3F4F6" strokeWidth="1" />
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect width={W} height={H} fill="url(#grid)" />
|
||||
|
||||
<DashedPath d={alt1} color="#E5E7EB" dash={5} delay={0.1} />
|
||||
<DashedPath d={alt2} color="#E5E7EB" dash={5} delay={0.2} />
|
||||
<DashedPath d={alt3} color="#E5E7EB" dash={5} delay={0.3} />
|
||||
|
||||
<DashedPath d={highlightA} color={accent} dash={8} delay={0.2} loop />
|
||||
<DashedPath d={highlightB} color={accent} dash={8} delay={0.4} loop />
|
||||
|
||||
<Arrow d={arrowTo(nodes[0], center)} color={stroke} delay={0.1} />
|
||||
<Arrow d={arrowTo(nodes[2], center)} color={stroke} delay={0.2} />
|
||||
<Arrow d={arrowTo(nodes[3], center)} color={stroke} delay={0.25} />
|
||||
<Arrow d={arrowTo(nodes[1], center)} color={stroke} delay={0.3} />
|
||||
|
||||
<Node cx={center.x} cy={center.y} r={18} fill={accent} ring="#E5E7EB" pulse />
|
||||
{nodes.map((n, i) => (
|
||||
<Node key={i} cx={n.x} cy={n.y} r={14} fill="#FFFFFF" ring="#E5E7EB" />
|
||||
))}
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
174
src/pages/network/animations/ProxyDetection.tsx
Normal file
174
src/pages/network/animations/ProxyDetection.tsx
Normal file
@@ -0,0 +1,174 @@
|
||||
import { motion, useReducedMotion } from 'framer-motion';
|
||||
|
||||
type Props = {
|
||||
className?: string;
|
||||
bg?: string;
|
||||
};
|
||||
|
||||
const ACCENT = '#00b8db';
|
||||
const STROKE = '#111827';
|
||||
const GRAY = '#9CA3AF';
|
||||
const GRAY_LT = '#E5E7EB';
|
||||
|
||||
function Magnifier({
|
||||
x = 0,
|
||||
y = 0,
|
||||
flip = false,
|
||||
delay = 0,
|
||||
duration = 3,
|
||||
}: {
|
||||
x?: number;
|
||||
y?: number;
|
||||
flip?: boolean;
|
||||
delay?: number;
|
||||
duration?: number;
|
||||
}) {
|
||||
const prefersReduced = useReducedMotion();
|
||||
|
||||
return (
|
||||
<motion.g
|
||||
initial={{ x: 0 }}
|
||||
animate={{ x: [0, 520] }}
|
||||
transition={{
|
||||
delay,
|
||||
duration: prefersReduced ? 0.01 : duration,
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
repeat: prefersReduced ? 0 : Infinity,
|
||||
repeatType: 'reverse',
|
||||
repeatDelay: 0.4,
|
||||
}}
|
||||
transform={`translate(${x}, ${y})`}
|
||||
>
|
||||
<circle cx={0} cy={0} r={38} fill="#fff" stroke={STROKE} strokeWidth={6} />
|
||||
<motion.circle
|
||||
cx={0}
|
||||
cy={0}
|
||||
r={26}
|
||||
fill="none"
|
||||
stroke={ACCENT}
|
||||
strokeWidth={4}
|
||||
initial={{ opacity: 0.15, scale: 0.8 }}
|
||||
animate={{ opacity: [0.15, 0.35, 0.15], scale: [0.8, 1.05, 0.8] }}
|
||||
transition={{ duration: 1.6, repeat: Infinity }}
|
||||
/>
|
||||
<g transform={`rotate(${flip ? 40 : -40}) translate(35, 10)`}>
|
||||
<rect x={0} y={-6} width={80} height={12} rx={6} fill={STROKE} />
|
||||
<rect x={0} y={-12} width={14} height={24} rx={6} fill={GRAY} />
|
||||
</g>
|
||||
</motion.g>
|
||||
);
|
||||
}
|
||||
|
||||
function ServerBox({
|
||||
x,
|
||||
y,
|
||||
w = 88,
|
||||
h = 50,
|
||||
delay = 0,
|
||||
accentPulse = false,
|
||||
}: {
|
||||
x: number;
|
||||
y: number;
|
||||
w?: number;
|
||||
h?: number;
|
||||
delay?: number;
|
||||
accentPulse?: boolean;
|
||||
}) {
|
||||
const prefersReduced = useReducedMotion();
|
||||
|
||||
return (
|
||||
<motion.g
|
||||
transform={`translate(${x}, ${y})`}
|
||||
initial={{ opacity: 0.6 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay, duration: 0.4 }}
|
||||
>
|
||||
<rect
|
||||
x={-w / 2}
|
||||
y={-h / 2}
|
||||
width={w}
|
||||
height={h}
|
||||
rx={10}
|
||||
fill="#fff"
|
||||
stroke={STROKE}
|
||||
strokeWidth={3}
|
||||
/>
|
||||
<rect
|
||||
x={-w / 2 + 6}
|
||||
y={-h / 2 + 8}
|
||||
width={w - 12}
|
||||
height={12}
|
||||
rx={6}
|
||||
fill={GRAY_LT}
|
||||
/>
|
||||
<motion.rect
|
||||
x={-w / 2 + 10}
|
||||
y={-h / 2 + 26}
|
||||
width={w - 20}
|
||||
height={10}
|
||||
rx={5}
|
||||
fill={GRAY_LT}
|
||||
initial={{ width: w * 0.2 }}
|
||||
animate={{ width: [w * 0.2, w - 20, w * 0.2] }}
|
||||
transition={{
|
||||
delay,
|
||||
duration: prefersReduced ? 0.01 : 1.8,
|
||||
repeat: prefersReduced ? 0 : Infinity,
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
}}
|
||||
/>
|
||||
<motion.circle
|
||||
cx={w / 2 - 14}
|
||||
cy={h / 2 - 14}
|
||||
r={6}
|
||||
fill={accentPulse ? ACCENT : GRAY}
|
||||
initial={{ scale: 0.9, opacity: 0.8 }}
|
||||
animate={
|
||||
accentPulse && !prefersReduced
|
||||
? { scale: [0.9, 1.15, 0.9], opacity: [0.8, 1, 0.8] }
|
||||
: { scale: 1, opacity: 0.9 }
|
||||
}
|
||||
transition={{ duration: 1.4, repeat: accentPulse && !prefersReduced ? Infinity : 0 }}
|
||||
/>
|
||||
</motion.g>
|
||||
);
|
||||
}
|
||||
|
||||
export default function ProxyDetection({ className, bg = '#ffffff' }: Props) {
|
||||
const W = 900;
|
||||
const H = 180;
|
||||
|
||||
const rowY = H / 2;
|
||||
const xs = [180, 320, 460, 600, 740];
|
||||
const delays = [0.8, 0.6, 0.4, 0.2, 0.0];
|
||||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
style={{ background: bg }}
|
||||
>
|
||||
<svg viewBox={`0 0 ${W} ${H}`} width="100%" height="100%">
|
||||
<defs>
|
||||
<pattern id="grid" width="24" height="24" patternUnits="userSpaceOnUse">
|
||||
<path d="M 24 0 L 0 0 0 24" fill="none" stroke={GRAY_LT} strokeWidth="1" />
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect width={W} height={H} fill="url(#grid)" />
|
||||
|
||||
{xs.map((x, i) => (
|
||||
<ServerBox
|
||||
key={`b-${i}`}
|
||||
x={x}
|
||||
y={rowY}
|
||||
delay={delays[i]}
|
||||
accentPulse
|
||||
/>
|
||||
))}
|
||||
|
||||
<Magnifier x={120} y={rowY} flip={true} delay={0.25} duration={3.2} />
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
156
src/pages/network/animations/ProxyForwarding.tsx
Normal file
156
src/pages/network/animations/ProxyForwarding.tsx
Normal file
@@ -0,0 +1,156 @@
|
||||
import { motion, useReducedMotion } from 'framer-motion';
|
||||
|
||||
type Props = {
|
||||
className?: string;
|
||||
bg?: string;
|
||||
};
|
||||
|
||||
const ACCENT = '#00b8db';
|
||||
const STROKE = '#111827';
|
||||
const GRAY = '#9CA3AF';
|
||||
const GRAY_LT = '#E5E7EB';
|
||||
|
||||
function Laptop({ x, y }: { x: number; y: number }) {
|
||||
return (
|
||||
<g transform={`translate(${x}, ${y})`}>
|
||||
<rect x={-48} y={-32} width={96} height={64} rx={8} fill="#fff" stroke={STROKE} strokeWidth={3} />
|
||||
<rect x={-44} y={-28} width={88} height={40} rx={6} fill={GRAY_LT} />
|
||||
<rect x={-56} y={32} width={112} height={10} rx={5} fill={STROKE} />
|
||||
</g>
|
||||
);
|
||||
}
|
||||
|
||||
function ServerStack({ x, y }: { x: number; y: number }) {
|
||||
return (
|
||||
<g transform={`translate(${x}, ${y})`}>
|
||||
{[0, 1, 2].map((i) => (
|
||||
<g key={i} transform={`translate(0, ${-38 + i * 28})`}>
|
||||
<rect x={-56} y={-12} width={112} height={24} rx={8} fill="#fff" stroke={STROKE} strokeWidth={3} />
|
||||
<rect x={-46} y={-6} width={56} height={12} rx={6} fill={GRAY_LT} />
|
||||
<circle cx={20} cy={0} r={4} fill={GRAY} />
|
||||
<circle cx={30} cy={0} r={4} fill={ACCENT} />
|
||||
<circle cx={40} cy={0} r={4} fill={GRAY} />
|
||||
</g>
|
||||
))}
|
||||
<rect x={-18} y={48} width={36} height={6} rx={3} fill={GRAY} />
|
||||
<rect x={-10} y={54} width={20} height={6} rx={3} fill={ACCENT} />
|
||||
</g>
|
||||
);
|
||||
}
|
||||
|
||||
function Cloud({ x, y }: { x: number; y: number }) {
|
||||
return (
|
||||
<g transform={`translate(${x}, ${y})`} fill={STROKE}>
|
||||
<circle cx={-30} cy={0} r={18} fill={STROKE} />
|
||||
<circle cx={-8} cy={-10} r={22} fill={STROKE} />
|
||||
<circle cx={16} cy={0} r={20} fill={STROKE} />
|
||||
<rect x={-40} y={0} width={72} height={20} rx={10} fill={STROKE} />
|
||||
<rect x={-46} y={18} width={88} height={6} rx={3} fill={STROKE} />
|
||||
</g>
|
||||
);
|
||||
}
|
||||
|
||||
function Arrow({ d, delay = 0 }: { d: string; delay?: number }) {
|
||||
return (
|
||||
<motion.path
|
||||
d={d}
|
||||
fill="none"
|
||||
stroke={STROKE}
|
||||
strokeWidth={4}
|
||||
strokeLinecap="round"
|
||||
initial={{ pathLength: 0, opacity: 0.3 }}
|
||||
animate={{ pathLength: 1, opacity: 1 }}
|
||||
transition={{ duration: 0.8, delay, ease: [0.22, 1, 0.36, 1] }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function Packet({
|
||||
xs,
|
||||
ys,
|
||||
delay = 0,
|
||||
color = ACCENT,
|
||||
duration = 2.2,
|
||||
}: {
|
||||
xs: number[];
|
||||
ys: number[];
|
||||
delay?: number;
|
||||
color?: string;
|
||||
duration?: number;
|
||||
}) {
|
||||
const prefersReduced = useReducedMotion();
|
||||
return (
|
||||
<motion.circle
|
||||
r={6}
|
||||
fill={color}
|
||||
initial={{ x: xs[0], y: ys[0], opacity: 0 }}
|
||||
animate={{
|
||||
x: prefersReduced ? xs[0] : xs,
|
||||
y: prefersReduced ? ys[0] : ys,
|
||||
opacity: 1,
|
||||
}}
|
||||
transition={{
|
||||
delay,
|
||||
duration: prefersReduced ? 0.01 : duration,
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
repeat: prefersReduced ? 0 : Infinity,
|
||||
repeatDelay: 0.6,
|
||||
}}
|
||||
stroke="#fff"
|
||||
strokeWidth={2}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default function ProxyForwarding({ className, bg = '#ffffff' }: Props) {
|
||||
const W = 1000;
|
||||
const H = 420;
|
||||
|
||||
const C1 = { x: 140, y: 90 };
|
||||
const C2 = { x: 140, y: 210 };
|
||||
const C3 = { x: 140, y: 330 };
|
||||
|
||||
const PROXY = { x: 420, y: 210 };
|
||||
const CLOUD = { x: 640, y: 210 };
|
||||
const DEST = { x: 860, y: 210 };
|
||||
|
||||
return (
|
||||
<div className={className} aria-hidden="true" role="img" style={{ background: bg }}>
|
||||
<svg viewBox={`0 0 ${W} ${H}`} width="100%" height="100%">
|
||||
<defs>
|
||||
<pattern id="grid" width="24" height="24" patternUnits="userSpaceOnUse">
|
||||
<path d="M 24 0 L 0 0 0 24" fill="none" stroke={GRAY_LT} strokeWidth="1" />
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect width={W} height={H} fill="url(#grid)" />
|
||||
|
||||
<Laptop x={C1.x} y={C1.y} />
|
||||
<Laptop x={C2.x} y={C2.y} />
|
||||
<Laptop x={C3.x} y={C3.y} />
|
||||
|
||||
<ServerStack x={PROXY.x} y={PROXY.y} />
|
||||
|
||||
<Cloud x={CLOUD.x} y={CLOUD.y} />
|
||||
|
||||
<ServerStack x={DEST.x} y={DEST.y} />
|
||||
|
||||
<Arrow d={`M ${C1.x + 70} ${C1.y} C 260 ${C1.y}, 320 150, ${PROXY.x - 80} 170`} delay={0.05} />
|
||||
<Arrow d={`M ${C2.x + 70} ${C2.y} L ${PROXY.x - 80} ${PROXY.y}`} delay={0.1} />
|
||||
<Arrow d={`M ${C3.x + 70} ${C3.y} C 260 ${C3.y}, 320 270, ${PROXY.x - 80} 250`} delay={0.15} />
|
||||
|
||||
<Arrow d={`M ${PROXY.x + 80} ${PROXY.y} L ${CLOUD.x - 60} ${CLOUD.y}`} delay={0.2} />
|
||||
<Arrow d={`M ${CLOUD.x + 60} ${CLOUD.y} L ${DEST.x - 80} ${DEST.y}`} delay={0.25} />
|
||||
|
||||
<Packet xs={[C1.x + 70, PROXY.x - 80]} ys={[C1.y, 170]} delay={0.0} />
|
||||
<Packet xs={[C2.x + 70, PROXY.x - 80]} ys={[C2.y, PROXY.y]} delay={0.3} color={GRAY} />
|
||||
<Packet xs={[C3.x + 70, PROXY.x - 80]} ys={[C3.y, 250]} delay={0.6} />
|
||||
|
||||
<Packet xs={[PROXY.x + 80, CLOUD.x - 60]} ys={[PROXY.y, CLOUD.y]} delay={0.4} />
|
||||
<Packet xs={[PROXY.x + 80, CLOUD.x - 60]} ys={[PROXY.y, CLOUD.y]} delay={0.9} color={GRAY} />
|
||||
|
||||
<Packet xs={[CLOUD.x + 60, DEST.x - 80]} ys={[CLOUD.y, DEST.y]} delay={0.7} />
|
||||
<Packet xs={[CLOUD.x + 60, DEST.x - 80]} ys={[CLOUD.y, DEST.y]} delay={1.1} color={GRAY} />
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user