diff --git a/public/images/encrypted.png b/public/images/encrypted.png new file mode 100644 index 0000000..bb72f48 Binary files /dev/null and b/public/images/encrypted.png differ diff --git a/public/images/filesystem.png b/public/images/filesystem.png new file mode 100644 index 0000000..df1348e Binary files /dev/null and b/public/images/filesystem.png differ diff --git a/public/images/ipfs.png b/public/images/ipfs.png new file mode 100644 index 0000000..bb4cc6f Binary files /dev/null and b/public/images/ipfs.png differ diff --git a/public/images/s3.png b/public/images/s3.png new file mode 100644 index 0000000..300aab7 Binary files /dev/null and b/public/images/s3.png differ diff --git a/src/components/Texts.tsx b/src/components/Texts.tsx index f69d585..918068b 100644 --- a/src/components/Texts.tsx +++ b/src/components/Texts.tsx @@ -106,7 +106,7 @@ export const H5 = createTextComponent( ) export const Eyebrow = createTextComponent( 'h2', - 'text-base/7 font-semibold tracking-[0.18em] uppercase', + 'text-base/7 font-semibold uppercase tracking-[0.16em]', { color: 'accent' } ) export const SectionHeader = createTextComponent( diff --git a/src/pages/storage/CallToAction.tsx b/src/pages/storage/CallToAction.tsx index 687bae3..e2588ff 100644 --- a/src/pages/storage/CallToAction.tsx +++ b/src/pages/storage/CallToAction.tsx @@ -1,48 +1,66 @@ -import { CircleBackground } from '../../components/CircleBackground' -import { Container } from '@/components/Container' -import { Button } from '@/components/Button' +"use client"; + +import { Container } from "@/components/Container"; +import { Button } from "@/components/Button"; export function CallToAction() { return ( -
-
- -
- -
-

- Choose How You Want to Start -

-

- Store data in your Mycelium Cloud environment -or host your own node for full sovereignty. +

+ {/* ✅ Top horizontal line with spacing */} +
+
-

-
- - + {/* ✅ Main boxed area */} +
+ +
+

+ Choose How You Want to Start +

+ +

+ Store data in your Mycelium Cloud environment + or host your own node for full sovereignty. +

+ + {/* ✅ Two cards, stacked center with spacing */} +
+
+ +
+ +
+ +
+
-
- + +
+ + {/* ✅ Bottom horizontal line with spacing */} +
+
- ) + ); } diff --git a/src/pages/storage/StorageArchitecture.tsx b/src/pages/storage/StorageArchitecture.tsx index dbcce3d..649deee 100644 --- a/src/pages/storage/StorageArchitecture.tsx +++ b/src/pages/storage/StorageArchitecture.tsx @@ -1,54 +1,81 @@ -import { Container } from '@/components/Container' -import { Eyebrow, SectionHeader, P } from '@/components/Texts' +"use client"; + +import { useState } from "react"; +import { Container } from "@/components/Container"; +import { Eyebrow, SectionHeader, P, H3, H4, H5, CT, CP } from "@/components/Texts"; const architecture = [ { - title: 'Encrypted Storage Substrate', - description: 'Keeps data private and verifiable.', + title: "Encrypted Storage Substrate", + description: "Keeps data private and verifiable.", }, { - title: 'Mesh Routing Layer', - description: 'Connects clients and workloads securely, anywhere.', + title: "Mesh Routing Layer", + description: "Connects clients and workloads securely, anywhere.", }, { - title: 'Protocol Gateway Layer', + title: "Protocol Gateway Layer", description: - 'Serve the same dataset over S3, IPFS, WebDAV, or HTTP.', + "Serve the same dataset over S3, IPFS, WebDAV, or HTTP.", }, -] +]; export function StorageArchitecture() { + const [active, setActive] = useState(0); + return ( -
- +
+ {/* ✅ Top horizontal line with spacing */} +
+
+ {/* ✅ Boxed container */} +
ARCHITECTURE - - HOW IT WORKS - -

+

+ How it Works +

+

A layered design that encrypts, routes, and exposes storage through multiple protocols — without duplicating data or compromising sovereignty.

-
- {architecture.map((item) => ( + {/* ✅ New 2-column layout */} +
+ {/* LEFT — 1 column (3 rows) */} +
+ {architecture.map((item, index) => ( + + ))} +
+ + {/* RIGHT — 2 columns */} +
-

- {item.title} -

-

- {item.description} -

+
{architecture[active].title}
+

+ {architecture[active].description} +

- ))} +
+
+
- ) + ); } diff --git a/src/pages/storage/StorageCapabilitiesNew.tsx b/src/pages/storage/StorageCapabilitiesNew.tsx new file mode 100644 index 0000000..80533cc --- /dev/null +++ b/src/pages/storage/StorageCapabilitiesNew.tsx @@ -0,0 +1,110 @@ +"use client"; + +import { useRef } from "react"; +import { Eyebrow, CP, CT, H5 } from "@/components/Texts"; +import { IoArrowBackOutline, IoArrowForwardOutline } from "react-icons/io5"; + +const capabilities = [ + { + isIntro: true, + eyebrow: "CAPABILITIES", + title: "Flexible, Resilient, and Controllable Storage", + description: + "Mycelium Storage is designed for modern data workloads, providing a range of access methods and control over data placement.", + }, + { + title: "S3-Compatible Object Storage", + description: "Works with existing SDKs & tooling.", + imageUrl: "/images/s3.png", + }, + { + title: "IPFS & Content-Addressed Access", + description: "Ideal for distributed and decentralized workloads.", + imageUrl: "/images/ipfs.png", + }, + { + title: "Filesystem Mounts (WebDAV / POSIX)", + description: "Mount storage directly into workflows and apps.", + imageUrl: "/images/filesystem.png", + }, + { + title: "Encrypted Replication & Placement Control", + description: "Choose data's ownership and locations.", + imageUrl: "/images/encrypted.png", + }, +]; + +export function StorageCapabilitiesNew() { + const sliderRef = useRef(null); + + const scrollLeft = () => sliderRef.current?.scrollBy({ left: -400, behavior: "smooth" }); + const scrollRight = () => sliderRef.current?.scrollBy({ left: 400, behavior: "smooth" }); + + return ( +
+
+
+ +
+ + {/* Horizontal Slider — shows part of next card */} +
    + {capabilities.map((item, idx) => ( +
  • +
    + {/* First card with arrows */} + {item.isIntro ? ( +
    +
    + {item.eyebrow} +
    {item.title}
    +

    {item.description}

    +
    + + {/* Arrows inside first card */} +
    + + Learn more → + + + + +
    +
    + ) : ( +
    +

    {item.title}

    +

    {item.description}

    +
    + )} +
    +
  • + ))} + +
+
+
+
+
+ ); +} diff --git a/src/pages/storage/StorageCoreValue.tsx b/src/pages/storage/StorageCoreValue.tsx index e95b177..81fd195 100644 --- a/src/pages/storage/StorageCoreValue.tsx +++ b/src/pages/storage/StorageCoreValue.tsx @@ -1,21 +1,38 @@ "use client"; import { Container } from "@/components/Container"; -import { H3, P, Eyebrow } from "@/components/Texts"; +import { H3, P, Eyebrow, CT, CP } from "@/components/Texts"; +import Encrypted from "./animation/Encrypted"; +import SelfHealing from "./animation/SelfHealing"; +import Residency from "./animation/Residency"; export function StorageCoreValue() { - const logos = [ - { src: '/images/logo/cryptpad.png', href: 'https://cryptpad.fr' }, - { src: '/images/logo/gitea.png', href: 'https://about.gitea.com' }, - { src: '/images/logo/lifekit.png', href: '#' }, // No link available - { src: '/images/logo/matrix.png', href: 'https://matrix.org' }, - { src: '/images/logo/nextcloud.png', href: 'https://nextcloud.com' }, - { src: '/images/logo/stalwart.png', href: 'https://stalw.art' }, - ]; + const values = [ + { id: "Encrypted", + title: "Encrypted and verifiable at rest and in motion", + href: "#", + animation: Encrypted, + }, + { id: "SelfHealing", + title: "Self-healing replication and integrity checks", + href: "#", + animation: SelfHealing, + }, + { id: "Residency", + title: "Residency + governance policies you actually control", + href: "#", + animation: Residency, + }, + + ] + return (
- + {/* ✅ Top horizontal line with spacing */} +
+
+ {/* ✅ Boxed container */}
@@ -23,31 +40,29 @@ export function StorageCoreValue() { Featured Blueprint

- Your Personal Sovereign Cloud Workspace + Sovereign Storage That Heals Itself

- Digital Me is an example environment built to demonstrate what’s possible on top of the Mycelium Stack — a full personal cloud you can deploy, customize, or extend. Your files, communication, apps, and optional AI agent, all running privately on infrastructure you choose. + Mycelium Storage continuously verifies integrity and restores replicas automatically, so data stays available without operational overhead.

{/* ✅ 3x2 logo grid */}
- {logos.map((logo, i) => ( -
- - {`Logo - -
+ {values.map((value, i) => ( + + + + {value.title} + + ))}
diff --git a/src/pages/storage/StorageOverview.tsx b/src/pages/storage/StorageOverview.tsx index 870c82d..9fb5532 100644 --- a/src/pages/storage/StorageOverview.tsx +++ b/src/pages/storage/StorageOverview.tsx @@ -1,4 +1,3 @@ -import { Container } from '@/components/Container' import { Eyebrow, SectionHeader, P, Small } from '@/components/Texts' const highlights = [ @@ -24,27 +23,17 @@ const highlights = [ export function StorageOverview() { return ( -
- - -
- - Platform Overview - - - Core Features - -

- Built on sovereign infrastructure, Mycelium Storage keeps data - resilient, verifiable, and instantly accessible. Encryption, - replication, and governance are woven directly into the substrate. -

-
-
+
+ {/* ✅ Top horizontal line with spacing */} +
+
+ +
+
{highlights.map((item) => (
@@ -61,7 +50,9 @@ export function StorageOverview() {
))}
- +
+
+
) } diff --git a/src/pages/storage/StoragePage.tsx b/src/pages/storage/StoragePage.tsx index 44023eb..fa4a3d3 100644 --- a/src/pages/storage/StoragePage.tsx +++ b/src/pages/storage/StoragePage.tsx @@ -4,8 +4,8 @@ import { StorageOverview } from './StorageOverview' import { StorageArchitecture } from './StorageArchitecture' import { StorageUseCases } from './StorageUseCases' import { CallToAction } from './CallToAction' -import { StorageCapabilities } from './StorageCapabilities' -import { StorageDesign } from './StorageDesign' +import { StorageCapabilitiesNew } from './StorageCapabilitiesNew' +import { StorageCoreValue } from './StorageCoreValue' export default function StoragePage() { return ( @@ -15,11 +15,11 @@ export default function StoragePage() { - + - + diff --git a/src/pages/storage/animation/Residency.tsx b/src/pages/storage/animation/Residency.tsx new file mode 100644 index 0000000..998761c --- /dev/null +++ b/src/pages/storage/animation/Residency.tsx @@ -0,0 +1,223 @@ +"use client"; + +import { motion, useReducedMotion } from "framer-motion"; +import clsx from "clsx"; + +type Props = { + className?: string; + accent?: string; + gridStroke?: string; + stroke?: string; +}; + +const W = 760; +const H = 420; + +export default function Residency({ + className, + accent = "#00b8db", + gridStroke = "#e5e7eb", + stroke = "#111111", +}: Props) { + const prefers = useReducedMotion(); + + // Layout: central governance node + 3 regional nodes + const center = { x: 380, y: 200 }; + const regions = [ + { x: 220, y: 120 }, + { x: 540, y: 120 }, + { x: 380, y: 300 }, + ]; + + // Path for data transfer (circular motion between regions) + const flowPath = `M ${regions[0].x} ${regions[0].y} + C 300 80, 460 80, ${regions[1].x} ${regions[1].y} + C 480 160, 420 260, ${regions[2].x} ${regions[2].y} + C 340 260, 280 160, ${regions[0].x} ${regions[0].y} Z`; + + return ( + + ); +} diff --git a/src/pages/storage/animation/SelfHealing.tsx b/src/pages/storage/animation/SelfHealing.tsx new file mode 100644 index 0000000..cb0b0b4 --- /dev/null +++ b/src/pages/storage/animation/SelfHealing.tsx @@ -0,0 +1,214 @@ +"use client"; + +import { motion, useReducedMotion } from "framer-motion"; +import clsx from "clsx"; + +type Props = { + className?: string; + accent?: string; + gridStroke?: string; + stroke?: string; +}; + +const W = 760; +const H = 420; + +export default function SelfHealing({ + className, + accent = "#00b8db", + gridStroke = "#e5e7eb", + stroke = "#111111", +}: Props) { + const prefers = useReducedMotion(); + + // diamond node layout + const nodes = [ + { x: 380, y: 130 }, // top + { x: 240, y: 240 }, // left + { x: 520, y: 240 }, // right + { x: 380, y: 320 }, // bottom + ]; + + // connection paths + const links = [ + [0, 1], + [0, 2], + [1, 3], + [2, 3], + [1, 2], + ]; + + // helper for path drawing + const drawLine = (i: number, j: number) => { + const a = nodes[i]; + const b = nodes[j]; + return `M ${a.x} ${a.y} L ${b.x} ${b.y}`; + }; + + return ( + + ); +}