forked from emre/www_projectmycelium_com
feat: redesign CloudArchitecture section with dark theme and animated icons
- Added animated icon components (MeshNetworkIcon, SovereignComputer, DeterministicOrchestration) to architecture cards - Updated styling to match dark theme with bordered container layout consistent with HomeHosting section - Improved card layout with better spacing, hover effects, and visual hierarchy
This commit is contained in:
103
src/pages/cloud/animations/DeterministicOrchestration.tsx
Normal file
103
src/pages/cloud/animations/DeterministicOrchestration.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
"use client";
|
||||
|
||||
import { motion, useReducedMotion } from "framer-motion";
|
||||
import clsx from "clsx";
|
||||
|
||||
export function DeterministicOrchestration({ className }: { className?: string }) {
|
||||
const prefersReducedMotion = useReducedMotion();
|
||||
|
||||
// Hex coordinates (simple honeycomb layout)
|
||||
const hexes = [
|
||||
{ x: 60, y: 25 },
|
||||
{ x: 100, y: 25 },
|
||||
{ x: 140, y: 25 },
|
||||
|
||||
{ x: 40, y: 65 },
|
||||
{ x: 80, y: 65 },
|
||||
{ x: 120, y: 65 },
|
||||
{ x: 160, y: 65 },
|
||||
|
||||
{ x: 60, y: 105 },
|
||||
{ x: 100, y: 105 },
|
||||
{ x: 140, y: 105 },
|
||||
];
|
||||
|
||||
// simple hex path generator
|
||||
const hexPath = (cx: number, cy: number, r = 14) => {
|
||||
const p = (a: number) => ({
|
||||
x: cx + r * Math.cos((Math.PI / 180) * a),
|
||||
y: cy + r * Math.sin((Math.PI / 180) * a),
|
||||
});
|
||||
const pts = [30, 90, 150, 210, 270, 330].map((a) => p(a));
|
||||
return `M ${pts[0].x} ${pts[0].y} L ${pts[1].x} ${pts[1].y} L ${pts[2].x} ${pts[2].y}
|
||||
L ${pts[3].x} ${pts[3].y} L ${pts[4].x} ${pts[4].y} L ${pts[5].x} ${pts[5].y} Z`;
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"w-full h-24 flex items-center justify-center bg-[#0a0a0a]",
|
||||
className
|
||||
)}
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
>
|
||||
<svg viewBox="0 0 200 140" className="w-full h-full" fill="none">
|
||||
{/* Hex outlines */}
|
||||
{hexes.map((h, i) => (
|
||||
<motion.path
|
||||
key={i}
|
||||
d={hexPath(h.x, h.y)}
|
||||
stroke="#4B5563" // gray-600
|
||||
strokeWidth={1.6}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.6, delay: 0.03 * i }}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Deterministic sequence highlight — hexes fill in predictable order */}
|
||||
{hexes.map((h, i) => (
|
||||
<motion.path
|
||||
key={`fill-${i}`}
|
||||
d={hexPath(h.x, h.y)}
|
||||
fill="#00b8db"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{
|
||||
opacity:
|
||||
prefersReducedMotion
|
||||
? 1
|
||||
: [0, 1, 1, 0], // flash on, stay, fade
|
||||
}}
|
||||
transition={{
|
||||
duration: 1.2,
|
||||
delay: i * 0.12,
|
||||
repeat: prefersReducedMotion ? 0 : Infinity,
|
||||
repeatDelay: 0.6,
|
||||
ease: "easeInOut",
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Optional center stability indicator */}
|
||||
<motion.circle
|
||||
cx={100}
|
||||
cy={65}
|
||||
r={5}
|
||||
fill="#00b8db"
|
||||
initial={{ scale: 0.8, opacity: 0 }}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
scale: prefersReducedMotion ? 1 : [1, 1.15, 1],
|
||||
}}
|
||||
transition={{
|
||||
duration: 1.6,
|
||||
repeat: prefersReducedMotion ? 0 : Infinity,
|
||||
repeatType: "mirror",
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
}}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
112
src/pages/cloud/animations/MeshNetworkIcon.tsx
Normal file
112
src/pages/cloud/animations/MeshNetworkIcon.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
"use client";
|
||||
|
||||
import { motion, useReducedMotion } from "framer-motion";
|
||||
import clsx from "clsx";
|
||||
|
||||
export function MeshNetworkIcon({ className }: { className?: string }) {
|
||||
const prefersReducedMotion = useReducedMotion();
|
||||
|
||||
const nodes = [
|
||||
{ x: 50, y: 25 },
|
||||
{ x: 120, y: 25 },
|
||||
{ x: 150, y: 65 },
|
||||
{ x: 120, y: 100 },
|
||||
{ x: 60, y: 100 },
|
||||
{ x: 30, y: 65 },
|
||||
{ x: 90, y: 55 }, // center-ish node
|
||||
];
|
||||
|
||||
// Lines between nodes (pairs of indices)
|
||||
const links: [number, number][] = [
|
||||
[0, 6], [6, 1],
|
||||
[1, 2], [2, 3],
|
||||
[3, 6], [6, 4],
|
||||
[4, 5], [5, 0],
|
||||
];
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"w-full h-24 flex items-center justify-center bg-[#0a0a0a]",
|
||||
className
|
||||
)}
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 180 120"
|
||||
className="w-full h-full"
|
||||
fill="none"
|
||||
>
|
||||
{/* Lines */}
|
||||
{links.map(([a, b], i) => (
|
||||
<motion.line
|
||||
key={i}
|
||||
x1={nodes[a].x}
|
||||
y1={nodes[a].y}
|
||||
x2={nodes[b].x}
|
||||
y2={nodes[b].y}
|
||||
stroke="#4B5563" /* gray-600 */
|
||||
strokeWidth={1.5}
|
||||
initial={{ pathLength: 0, opacity: 0 }}
|
||||
animate={{ pathLength: 1, opacity: 1 }}
|
||||
transition={{
|
||||
delay: 0.1 * i,
|
||||
duration: 0.5,
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Nodes */}
|
||||
{nodes.map((n, i) => (
|
||||
<motion.circle
|
||||
key={i}
|
||||
cx={n.x}
|
||||
cy={n.y}
|
||||
r={6}
|
||||
fill="#00b8db" // cyan nodes
|
||||
initial={{ scale: 0.8, opacity: 0 }}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
scale:
|
||||
!prefersReducedMotion && i !== 6 // central node pulses more
|
||||
? [1, 1.12, 1]
|
||||
: 1,
|
||||
}}
|
||||
transition={{
|
||||
duration: 1.4,
|
||||
repeat: i !== 6 && !prefersReducedMotion ? Infinity : 0,
|
||||
repeatType: "mirror",
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
delay: 0.05 * i,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Center node extra pulse */}
|
||||
<motion.circle
|
||||
cx={nodes[6].x}
|
||||
cy={nodes[6].y}
|
||||
r={10}
|
||||
stroke="#00b8db"
|
||||
strokeWidth={1}
|
||||
fill="none"
|
||||
initial={{ scale: 0 }}
|
||||
animate={{
|
||||
scale:
|
||||
prefersReducedMotion
|
||||
? 0
|
||||
: [0.6, 1.3, 0.6],
|
||||
opacity: [0.3, 0.8, 0.3],
|
||||
}}
|
||||
transition={{
|
||||
duration: 1.8,
|
||||
repeat: prefersReducedMotion ? 0 : Infinity,
|
||||
repeatType: "mirror",
|
||||
}}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
113
src/pages/cloud/animations/SovereignComputer.tsx
Normal file
113
src/pages/cloud/animations/SovereignComputer.tsx
Normal file
@@ -0,0 +1,113 @@
|
||||
"use client";
|
||||
|
||||
import { motion, useReducedMotion } from "framer-motion";
|
||||
import clsx from "clsx";
|
||||
|
||||
export function SovereignComputer({ className }: { className?: string }) {
|
||||
const prefersReducedMotion = useReducedMotion();
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"w-full h-24 flex items-center justify-center bg-[#0a0a0a]",
|
||||
className
|
||||
)}
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
>
|
||||
<svg viewBox="0 0 180 120" className="w-full h-full" fill="none">
|
||||
{/* Outer secure boundary (shield / isolation) */}
|
||||
<motion.rect
|
||||
x={40}
|
||||
y={20}
|
||||
width={100}
|
||||
height={80}
|
||||
rx={14}
|
||||
stroke="#4B5563"
|
||||
strokeWidth={2}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
/>
|
||||
|
||||
{/* Inner compute chip */}
|
||||
<motion.rect
|
||||
x={70}
|
||||
y={45}
|
||||
width={40}
|
||||
height={30}
|
||||
rx={4}
|
||||
fill="#00b8db"
|
||||
initial={{ scale: 0.8, opacity: 0 }}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
scale:
|
||||
!prefersReducedMotion
|
||||
? [1, 1.12, 1]
|
||||
: 1,
|
||||
}}
|
||||
transition={{
|
||||
duration: 1.6,
|
||||
repeat: prefersReducedMotion ? 0 : Infinity,
|
||||
repeatType: "mirror",
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Compute lines out → show isolation of data paths */}
|
||||
{[
|
||||
[90, 45, 90, 20],
|
||||
[90, 75, 90, 100],
|
||||
[70, 60, 40, 60],
|
||||
[110, 60, 140, 60],
|
||||
].map(([x1, y1, x2, y2], i) => (
|
||||
<motion.line
|
||||
key={i}
|
||||
x1={x1}
|
||||
y1={y1}
|
||||
x2={x2}
|
||||
y2={y2}
|
||||
stroke="#4B5563"
|
||||
strokeWidth={2}
|
||||
initial={{ pathLength: 0, opacity: 0 }}
|
||||
animate={{ pathLength: 1, opacity: 1 }}
|
||||
transition={{
|
||||
delay: 0.1 * i,
|
||||
duration: 0.6,
|
||||
ease: [0.22, 1, 0.36, 1],
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Cyan data pulses traveling outward */}
|
||||
{[
|
||||
[90, 45, 90, 20],
|
||||
[90, 75, 90, 100],
|
||||
[70, 60, 40, 60],
|
||||
[110, 60, 140, 60],
|
||||
].map(([x1, y1, x2, y2], i) => (
|
||||
<motion.circle
|
||||
key={`pulse-${i}`}
|
||||
cx={x1}
|
||||
cy={y1}
|
||||
r={3}
|
||||
fill="#00b8db"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{
|
||||
opacity: [0, 1, 0],
|
||||
cx: [x1, x2],
|
||||
cy: [y1, y2],
|
||||
}}
|
||||
transition={{
|
||||
delay: 0.15 * i,
|
||||
duration: 1.4,
|
||||
repeat: prefersReducedMotion ? 0 : Infinity,
|
||||
repeatType: "loop",
|
||||
ease: "linear",
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user