forked from emre/www_projectmycelium_com
feat: add Pods capabilities and how-it-works sections
- Created PodsCapabilities component showcasing four key features (communicate, organization, manage, storage) with icon-based layout - Added PodsHow section with CloudPods animation demonstrating pod-to-pod communication concept - Implemented animated CloudPods visualization with inter-cluster data flow and pulsing effects
This commit is contained in:
92
src/pages/pods/PodsCapabilities.tsx
Normal file
92
src/pages/pods/PodsCapabilities.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
import {
|
||||
ChatBubbleLeftRightIcon,
|
||||
CalendarDaysIcon,
|
||||
UserGroupIcon,
|
||||
ShieldCheckIcon,
|
||||
} from '@heroicons/react/24/solid'
|
||||
|
||||
import { Eyebrow, H3, P } from '@/components/Texts'
|
||||
|
||||
export function PodsCapabilities() {
|
||||
return (
|
||||
<section className="w-full max-w-8xl mx-auto bg-[#121212]">
|
||||
|
||||
{/* ✅ 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" />
|
||||
|
||||
{/* ✅ Main content */}
|
||||
<div className="mx-auto max-w-7xl px-6 bg-[#111111] lg:px-8 grid grid-cols-1 lg:grid-cols-2 gap-20 py-12 border border-t-0 border-b-0 border-gray-800">
|
||||
|
||||
{/* ✅ LEFT SIDE — Title + Intro */}
|
||||
<div className="max-w-xl ">
|
||||
<Eyebrow>What You Can Do</Eyebrow>
|
||||
|
||||
<H3 className="mt-6 text-white">
|
||||
Pods Features
|
||||
</H3>
|
||||
|
||||
<P className="mt-6 text-gray-200">
|
||||
Access everything from any device — your data follows you, not the other way around.
|
||||
💡 It’s like having your own tiny cloud that belongs only to you.
|
||||
</P>
|
||||
</div>
|
||||
|
||||
{/* ✅ RIGHT SIDE — 4 stacked features */}
|
||||
<div className="space-y-8">
|
||||
|
||||
{/* 1 — Communicate */}
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-white flex items-center">
|
||||
<ChatBubbleLeftRightIcon className="h-6 w-6 text-cyan-500 mr-3" />
|
||||
Communicate
|
||||
</h3>
|
||||
<p className="mt-2 text-gray-200 max-w-2xl">
|
||||
Message, call, and share files privately — no tracking or ads.
|
||||
</p>
|
||||
<div className="mt-8 h-px w-full bg-cyan-500/50" />
|
||||
</div>
|
||||
|
||||
{/* 2 — Organization */}
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-white flex items-center">
|
||||
<CalendarDaysIcon className="h-6 w-6 text-cyan-500 mr-3" />
|
||||
Organization
|
||||
</h3>
|
||||
<p className="mt-2 text-gray-200 max-w-2xl">
|
||||
Organize your calendar and meetings inside your own space.
|
||||
</p>
|
||||
<div className="mt-8 h-px w-full bg-cyan-500/50" />
|
||||
</div>
|
||||
|
||||
{/* 3 — Manage */}
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-white flex items-center">
|
||||
<UserGroupIcon className="h-6 w-6 text-cyan-500 mr-3" />
|
||||
Manage
|
||||
</h3>
|
||||
<p className="mt-2 text-gray-200 max-w-2xl">
|
||||
Create small communities or teams that interact directly, Pod-to-Pod.
|
||||
</p>
|
||||
<div className="mt-8 h-px w-full bg-cyan-500/50" />
|
||||
</div>
|
||||
|
||||
{/* 4 — Storage */}
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-white flex items-center">
|
||||
<ShieldCheckIcon className="h-6 w-6 text-cyan-500 mr-3" />
|
||||
Storage
|
||||
</h3>
|
||||
<p className="mt-2 text-gray-200 max-w-2xl">
|
||||
Store data safely with Quantum Safe File System (QSFS) built in.
|
||||
</p>
|
||||
</div>
|
||||
</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>
|
||||
)
|
||||
}
|
||||
53
src/pages/pods/PodsHow.tsx
Normal file
53
src/pages/pods/PodsHow.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
"use client";
|
||||
|
||||
import { Eyebrow, H3, P } from "@/components/Texts";
|
||||
import CloudPods from "./animations/CloudPods";
|
||||
|
||||
export function PodsHow() {
|
||||
return (
|
||||
<section className="relative w-full bg-[#121212] overflow-hidden">
|
||||
{/* ✅ Top horizontal line with spacing */}
|
||||
<div className="max-w-7xl bg-[#121212] 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 px-6 lg:px-8 py-12 border border-t-0 border-b-0 border-gray-800 bg-[#111111] overflow-hidden">
|
||||
|
||||
{/* ✅ Two-column layout */}
|
||||
<div className="flex flex-col lg:flex-row-reverse gap-16">
|
||||
|
||||
{/* ✅ Right side animation */}
|
||||
<div className="w-full lg:w-1/2">
|
||||
<CloudPods />
|
||||
</div>
|
||||
|
||||
{/* ✅ Left side content */}
|
||||
<div className="w-full lg:w-1/2 text-white">
|
||||
<Eyebrow color="accent" className="">
|
||||
How it works
|
||||
</Eyebrow>
|
||||
<H3 color="white" className="mt-6">
|
||||
What Living in a Pod Feels Like
|
||||
</H3>
|
||||
<P className="max-w-3xl text-gray-400 mt-6">
|
||||
When you use Mycelium, everything — your messages, calls, files — runs directly from your Pod.
|
||||
</P>
|
||||
<P className="max-w-3xl text-gray-400 mt-4">
|
||||
It’s your personal digital hub:
|
||||
When you message someone, it goes Pod to Pod, not through a central server.
|
||||
When you host a call, it runs on your Pod — no third-party data centers.
|
||||
</P>
|
||||
<P className="max-w-3xl text-gray-400 mt-4">
|
||||
When you save a file, it stays on your Pod, encrypted and always available.
|
||||
No one else can read it, rent it, or switch it off.
|
||||
</P>
|
||||
<P className="max-w-3xl text-gray-400 mt-4">
|
||||
You don’t log in to the internet — you are part of it.
|
||||
</P>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="max-w-7xl mx-auto py-6 border border-t-0 border-b-0 border-gray-800" />
|
||||
<div className="w-full border-b border-gray-800" />
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
import Homepod from './Homepod';
|
||||
import { PodsCapabilities } from './PodsCapabilities';
|
||||
import { PodsHow } from './PodsHow';
|
||||
|
||||
const PodsPage = () => {
|
||||
return (
|
||||
<>
|
||||
<Homepod />
|
||||
<Homepod />
|
||||
<PodsCapabilities />
|
||||
<PodsHow />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
195
src/pages/pods/animations/CloudPods.tsx
Normal file
195
src/pages/pods/animations/CloudPods.tsx
Normal file
@@ -0,0 +1,195 @@
|
||||
"use client";
|
||||
|
||||
import { motion, useReducedMotion } from "framer-motion";
|
||||
import clsx from "clsx";
|
||||
|
||||
type Props = {
|
||||
className?: string;
|
||||
accent?: string;
|
||||
bg?: string;
|
||||
};
|
||||
|
||||
const W = 760;
|
||||
const H = 420;
|
||||
|
||||
export default function CloudPods({
|
||||
className,
|
||||
accent = "#00b8db",
|
||||
bg = "#0b0b0b",
|
||||
}: Props) {
|
||||
const prefers = useReducedMotion();
|
||||
|
||||
// Pods: 2 clusters (top-right & bottom-left)
|
||||
const clusterA = [
|
||||
{ x: 180, y: 300 },
|
||||
{ x: 240, y: 330 },
|
||||
{ x: 300, y: 290 },
|
||||
];
|
||||
|
||||
const clusterB = [
|
||||
{ x: 480, y: 100 },
|
||||
{ x: 540, y: 130 },
|
||||
{ x: 600, y: 90 },
|
||||
];
|
||||
|
||||
// Combine all pods for rendering
|
||||
const pods = [...clusterA, ...clusterB];
|
||||
|
||||
// Inter-cluster communication paths (cross connections)
|
||||
const links = [
|
||||
[0, 3],
|
||||
[1, 4],
|
||||
[2, 5],
|
||||
[0, 4],
|
||||
[1, 5],
|
||||
];
|
||||
|
||||
const drawLink = (i: number, j: number) => {
|
||||
const a = pods[i];
|
||||
const b = pods[j];
|
||||
return `M ${a.x} ${a.y} L ${b.x} ${b.y}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={clsx("relative overflow-hidden", className)}>
|
||||
<svg viewBox={`0 0 ${W} ${H}`} className="w-full h-full" style={{ background: bg }}>
|
||||
<defs>
|
||||
{/* Subtle cyan glow */}
|
||||
<filter id="glow">
|
||||
<feGaussianBlur stdDeviation="3" result="b" />
|
||||
<feMerge>
|
||||
<feMergeNode in="b" />
|
||||
<feMergeNode in="SourceGraphic" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
|
||||
{/* Cyan gradient for pods */}
|
||||
<radialGradient id="podGradient" cx="50%" cy="50%" r="60%">
|
||||
<stop offset="0%" stopColor={accent} stopOpacity="0.9" />
|
||||
<stop offset="100%" stopColor={accent} stopOpacity="0.05" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
|
||||
{/* ✅ Static base links between clusters */}
|
||||
{links.map(([i, j], idx) => (
|
||||
<motion.path
|
||||
key={idx}
|
||||
d={drawLink(i, j)}
|
||||
stroke="#1f2937"
|
||||
strokeWidth={1.8}
|
||||
strokeLinecap="round"
|
||||
fill="none"
|
||||
opacity="0.5"
|
||||
initial={{ pathLength: 0 }}
|
||||
animate={{ pathLength: 1 }}
|
||||
transition={{ duration: 1.2, delay: idx * 0.05 }}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* ✅ Cyan data signals moving across clusters */}
|
||||
{!prefers &&
|
||||
links.map(([i, j], idx) => (
|
||||
<motion.circle
|
||||
key={`pulse-${idx}`}
|
||||
r={4}
|
||||
fill={accent}
|
||||
style={{ offsetPath: `path('${drawLink(i, j)}')` }}
|
||||
initial={{ offsetDistance: "0%", opacity: 0 }}
|
||||
animate={{
|
||||
offsetDistance: ["0%", "100%"],
|
||||
opacity: [0.2, 1, 0.2],
|
||||
}}
|
||||
transition={{
|
||||
duration: 2.6,
|
||||
delay: idx * 0.25,
|
||||
repeat: Infinity,
|
||||
ease: "linear",
|
||||
}}
|
||||
filter="url(#glow)"
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* ✅ Cloud Pods */}
|
||||
{pods.map((p, i) => (
|
||||
<g key={i}>
|
||||
<motion.ellipse
|
||||
cx={p.x}
|
||||
cy={p.y}
|
||||
rx={34}
|
||||
ry={22}
|
||||
fill="url(#podGradient)"
|
||||
stroke="#1f2937"
|
||||
strokeWidth={1.6}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.6, delay: 0.05 * i }}
|
||||
filter="url(#glow)"
|
||||
/>
|
||||
|
||||
{/* Soft inner cyan pulse */}
|
||||
{!prefers && (
|
||||
<motion.ellipse
|
||||
cx={p.x}
|
||||
cy={p.y}
|
||||
rx={18}
|
||||
ry={12}
|
||||
fill={accent}
|
||||
opacity={0.08}
|
||||
animate={{ opacity: [0.05, 0.3, 0.05], scale: [1, 1.1, 1] }}
|
||||
transition={{
|
||||
duration: 2.4,
|
||||
delay: i * 0.15,
|
||||
repeat: Infinity,
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</g>
|
||||
))}
|
||||
|
||||
{/* ✅ Cluster halos */}
|
||||
{!prefers && (
|
||||
<>
|
||||
<motion.circle
|
||||
cx="250"
|
||||
cy="310"
|
||||
r="100"
|
||||
fill="none"
|
||||
stroke={accent}
|
||||
strokeWidth={1.2}
|
||||
opacity={0.1}
|
||||
animate={{
|
||||
scale: [1, 1.1, 1.2],
|
||||
opacity: [0.05, 0.2, 0],
|
||||
}}
|
||||
transition={{
|
||||
duration: 3.8,
|
||||
repeat: Infinity,
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
}}
|
||||
/>
|
||||
<motion.circle
|
||||
cx="560"
|
||||
cy="110"
|
||||
r="100"
|
||||
fill="none"
|
||||
stroke={accent}
|
||||
strokeWidth={1.2}
|
||||
opacity={0.1}
|
||||
animate={{
|
||||
scale: [1, 1.1, 1.2],
|
||||
opacity: [0.05, 0.2, 0],
|
||||
}}
|
||||
transition={{
|
||||
duration: 3.8,
|
||||
delay: 1.2,
|
||||
repeat: Infinity,
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user