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:
BIN
public/images/dark-bento-01-integrations.png
Normal file
BIN
public/images/dark-bento-01-integrations.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 355 KiB |
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 Homepod from './Homepod';
|
||||||
|
import { PodsCapabilities } from './PodsCapabilities';
|
||||||
|
import { PodsHow } from './PodsHow';
|
||||||
|
|
||||||
const PodsPage = () => {
|
const PodsPage = () => {
|
||||||
return (
|
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