forked from emre/www_projectmycelium_com
feat: redesign compute page sections with interactive code examples
- Replaced static use cases section with tabbed interface showing AI/ML, application hosting, and edge compute capabilities - Added ComputeCodeTabs component with interactive code examples (train.py, deploy.yaml, edge.ts) - Updated CallToAction section with new bordered layout and restructured CTA buttons for hosting and deploying
This commit is contained in:
@@ -1,42 +1,55 @@
|
||||
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 (
|
||||
<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">
|
||||
Choose How You Want to Start
|
||||
</h2>
|
||||
<p className="mt-6 text-lg text-gray-300">
|
||||
Run workloads using Mycelium Cloud, or host your own compute node.
|
||||
Both use the same deterministic execution fabric.
|
||||
<section className="relative overflow-hidden bg-gray-900">
|
||||
{/* ✅ Top horizontal line with spacing */}
|
||||
<div className="max-w-7xl bg-[#090909] mx-auto py-6 border border-t-0 border-b-0 border-gray-700"></div>
|
||||
<div className="w-full border-t border-l border-r border-gray-700" />
|
||||
|
||||
</p>
|
||||
<div className="mt-10 flex flex-wrap justify-center gap-x-6 gap-y-4">
|
||||
<Button to="/download" variant="solid" color="white">
|
||||
Deploy Workloads
|
||||
</Button>
|
||||
<Button
|
||||
to="https://threefold.info/mycelium_network/docs/"
|
||||
as="a"
|
||||
target="_blank"
|
||||
variant="outline"
|
||||
color="white"
|
||||
>
|
||||
Host A Node
|
||||
</Button>
|
||||
{/* ✅ Main boxed area */}
|
||||
<div
|
||||
id="get-started"
|
||||
className="relative py-18 max-w-7xl mx-auto bg-[#090909] border border-t-0 border-b-0 border-gray-700"
|
||||
>
|
||||
|
||||
|
||||
<Container className="relative">
|
||||
<div className="mx-auto max-w-3xl text-center">
|
||||
<h2 className="text-3xl lg:text-4xl font-medium tracking-tight text-white sm:text-4xl">
|
||||
Choose How You Want to Start
|
||||
</h2>
|
||||
|
||||
<p className="mt-6 text-lg text-gray-300">
|
||||
Host your own node to contribute capacity or deploy workloads using the Mycelium Cloud.
|
||||
You don’t need to host before deploying, and you don’t need to deploy before hosting.
|
||||
|
||||
</p>
|
||||
|
||||
{/* ✅ Two cards, stacked center with spacing */}
|
||||
<div className="mt-10 flex flex-wrap justify-center gap-x-10 gap-y-8">
|
||||
<div className="flex flex-col items-center text-center max-w-xs">
|
||||
<Button to="/host" variant="solid" color="cyan" className="mt-4">
|
||||
Host a Node
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center text-center max-w-xs">
|
||||
<Button to="/cloud" variant="outline" color="white" className="mt-4">
|
||||
Start Deploying
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</Container>
|
||||
</div>
|
||||
|
||||
{/* ✅ Bottom horizontal line with spacing */}
|
||||
<div className="w-full border-b border-gray-700" />
|
||||
<div className="max-w-7xl mx-auto py-6 border border-t-0 border-b-0 border-gray-700 bg-transparent" />
|
||||
</section>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -110,7 +110,6 @@ export function ComputeCapabilitiesNew() {
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="w-full border-b border-gray-800" />
|
||||
<div className="max-w-7xl mx-auto py-6 border border-t-0 border-b-0 border-gray-800" />
|
||||
</section>
|
||||
|
||||
112
src/pages/compute/ComputeCodeTabs.tsx
Normal file
112
src/pages/compute/ComputeCodeTabs.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
|
||||
const files = [
|
||||
{
|
||||
id: "train",
|
||||
label: "train.py",
|
||||
code: `from mycelium import GPUCluster, Dataset
|
||||
|
||||
# connect to private GPU cluster
|
||||
cluster = GPUCluster("secure://my-node")
|
||||
|
||||
# load training data
|
||||
data = Dataset.load("s3://models/private-dataset")
|
||||
|
||||
# run a reproducible training job
|
||||
job = cluster.train(
|
||||
model="resnet50",
|
||||
dataset=data,
|
||||
epochs=40,
|
||||
deterministic=True
|
||||
)
|
||||
|
||||
job.save("s3://models/checkpoints/resnet-private")`,
|
||||
},
|
||||
{
|
||||
id: "deploy",
|
||||
label: "deploy.yaml",
|
||||
code: `apiVersion: mycelium/v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: vector-api
|
||||
spec:
|
||||
image: registry.mycelium/vector:latest
|
||||
replicas: 3
|
||||
selfHeal: true
|
||||
mesh: private
|
||||
resources:
|
||||
gpu: 1
|
||||
cpu: 2
|
||||
memory: 4Gi`,
|
||||
},
|
||||
{
|
||||
id: "edge",
|
||||
label: "edge.ts",
|
||||
code: `import { EdgeClient } from "@mycelium/sdk"
|
||||
|
||||
// deploy inference to nearest node
|
||||
const client = new EdgeClient()
|
||||
|
||||
await client.deploy({
|
||||
model: "resnet-private",
|
||||
region: "eu-home-nodes",
|
||||
autoscale: true,
|
||||
cache: "on-device"
|
||||
})`,
|
||||
},
|
||||
];
|
||||
|
||||
export function ComputeCodeTabs() {
|
||||
const [active, setActive] = useState("train");
|
||||
const file = files.find((f) => f.id === active)!;
|
||||
|
||||
return (
|
||||
<div className="sm:px-6 lg:px-0">
|
||||
<div className="relative isolate overflow-hidden bg-indigo-500 px-6 pt-8 sm:mx-auto sm:max-w-2xl sm:rounded-3xl sm:pt-16 sm:pr-0 sm:pl-16 lg:mx-0 lg:max-w-none">
|
||||
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="absolute -inset-y-px -left-3 -z-10 w-full origin-bottom-left skew-x-[-30deg] bg-indigo-100 opacity-20 ring-1 ring-white ring-inset"
|
||||
/>
|
||||
|
||||
<div className="mx-auto max-w-2xl sm:mx-0 sm:max-w-none">
|
||||
<div className="w-screen overflow-hidden rounded-tl-xl bg-gray-900 ring-1 ring-white/10">
|
||||
|
||||
{/* FILE TABS */}
|
||||
<div className="flex bg-gray-800/40 ring-1 ring-white/5">
|
||||
<div className="-mb-px flex text-sm font-medium text-gray-400">
|
||||
|
||||
{files.map((f) => (
|
||||
<button
|
||||
key={f.id}
|
||||
onClick={() => setActive(f.id)}
|
||||
className={`px-4 py-2 border-r border-white/10 ${
|
||||
active === f.id
|
||||
? "border-b border-b-white/20 bg-white/5 text-white"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{f.label}
|
||||
</button>
|
||||
))}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* CODE BLOCK */}
|
||||
<div className="px-6 pt-6 pb-14 font-mono text-xs leading-relaxed text-gray-200 whitespace-pre overflow-x-auto">
|
||||
{file.code}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="pointer-events-none absolute inset-0 ring-1 ring-white/10 ring-inset sm:rounded-3xl"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,53 +1,137 @@
|
||||
import { Container } from '@/components/Container'
|
||||
import { Eyebrow, SectionHeader } from '@/components/Texts'
|
||||
"use client";
|
||||
|
||||
const useCases = [
|
||||
import { useState } from "react";
|
||||
import { ComputeCodeTabs } from "./ComputeCodeTabs"; // ✅ Make sure path is correct
|
||||
import { Eyebrow, SectionHeader, H3, P } from "@/components/Texts";
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
title: 'AI / ML Training',
|
||||
description:
|
||||
'Reproducible pipelines, private model execution, scalable GPU orchestration.',
|
||||
id: "ai",
|
||||
label: "AI / ML TRAINING",
|
||||
content: [
|
||||
{
|
||||
item: "Reproducible pipelines",
|
||||
desc: "Build deterministic, version-locked training pipelines that produce the same result every time.",
|
||||
},
|
||||
{
|
||||
|
||||
item: "Private model execution",
|
||||
desc: "Train sensitive models on hardware you control, keeping datasets and checkpoints off hyperscalers.",
|
||||
},
|
||||
{
|
||||
item: "Scalable GPU orchestration",
|
||||
desc: "Scale training and inference across decentralized GPU nodes with automated orchestration.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Application Hosting',
|
||||
description:
|
||||
'Private, reliable, self-healing services – without cloud vendor lock-in.',
|
||||
id: "apps",
|
||||
label: "APPLICATION HOSTING",
|
||||
content: [
|
||||
{
|
||||
item: "Self-healing services",
|
||||
desc: "Private, reliable services that repair automatically without cloud vendor lock-in.",
|
||||
},
|
||||
{
|
||||
item: "Zero cloud lock-in",
|
||||
desc: "Deploy containers, VMs, or full Kubernetes clusters — migrate off AWS/GCP/Azure with no code changes.",
|
||||
},
|
||||
{
|
||||
item: "Encrypted networking",
|
||||
desc: "All services communicate through Mycelium Mesh — no VPNs, no exposed ports.",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Distributed & Edge Compute',
|
||||
description:
|
||||
'Run workloads where data lives, in homes, offices, datacenters, or remote regions.',
|
||||
id: "edge",
|
||||
label: "DISTRIBUTED & EDGE COMPUTE",
|
||||
content: [
|
||||
{
|
||||
item: "Distributed workloads",
|
||||
desc: "Run compute where data lives — homes, factories, hospitals, or remote regions.",
|
||||
},
|
||||
{
|
||||
item: "Offline-first resilience",
|
||||
desc: "Nodes keep working even with weak internet or outages — ideal for mission-critical edge.",
|
||||
},
|
||||
{
|
||||
item: "Global deployment, local data",
|
||||
desc: "Keep data in-country or on-prem for compliance, privacy, and regulated industries.",
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
];
|
||||
|
||||
export function ComputeUseCases() {
|
||||
const [active, setActive] = useState("ai");
|
||||
const current = tabs.find((t) => t.id === active)!;
|
||||
|
||||
return (
|
||||
<section className="bg-gray-950 py-24 sm:py-32">
|
||||
<Container>
|
||||
<div className="mx-auto max-w-3xl text-center">
|
||||
<Eyebrow color="accent" className="tracking-[0.32em] uppercase">
|
||||
<section className="relative w-full bg-[#171717] overflow-hidden">
|
||||
{/* ✅ Top horizontal line with spacing */}
|
||||
<div className="max-w-7xl bg-[#111111] 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">
|
||||
|
||||
{/* ✅ H3 on own row */}
|
||||
<div className="mb-16">
|
||||
<Eyebrow color="accent" className="">
|
||||
Use Cases
|
||||
</Eyebrow>
|
||||
<SectionHeader as="h2" color="light" className="mt-6">
|
||||
Built for Serious Workloads
|
||||
</SectionHeader>
|
||||
<H3 color="white">
|
||||
Built for Serious Workloads
|
||||
</H3>
|
||||
<P className="max-w-3xl text-gray-400 mt-6">
|
||||
Mycelium Compute is a decentralized physical infrastructure network
|
||||
(DePIN) for high-performance workloads. Run reproducible AI/ML
|
||||
pipelines, host self-healing applications, or deploy to the edge — all
|
||||
on a fabric that’s more resilient and private than the cloud.
|
||||
</P>
|
||||
</div>
|
||||
|
||||
<div className="mx-auto mt-16 max-w-4xl space-y-6">
|
||||
{useCases.map((useCase) => (
|
||||
<div
|
||||
key={useCase.title}
|
||||
className="rounded-3xl border border-white/10 bg-white/5 p-8 backdrop-blur-sm transition hover:-translate-y-1 hover:border-cyan-200/40 hover:bg-white/10"
|
||||
>
|
||||
<h3 className="text-xl font-semibold text-white">
|
||||
{useCase.title}
|
||||
</h3>
|
||||
<p className="mt-3 text-sm leading-relaxed text-gray-200">
|
||||
{useCase.description}
|
||||
</p>
|
||||
{/* ✅ Two-column layout */}
|
||||
<div className="flex flex-col lg:flex-row gap-16">
|
||||
|
||||
{/* ✅ Replace image with CodeTabs */}
|
||||
<div className="w-full lg:w-1/2">
|
||||
<ComputeCodeTabs />
|
||||
</div>
|
||||
|
||||
{/* ✅ Right side tabs & content */}
|
||||
<div className="w-full lg:w-1/2 text-white">
|
||||
|
||||
{/* Tabs Nav */}
|
||||
<div className="flex gap-6 border-b border-white/10 pb-2">
|
||||
{tabs.map((tab) => (
|
||||
<button
|
||||
key={tab.id}
|
||||
onClick={() => setActive(tab.id)}
|
||||
className={`text-sm font-medium tracking-wide pb-2 ${
|
||||
active === tab.id
|
||||
? "border-b-2 border-cyan-500 text-white"
|
||||
: "text-gray-400 hover:text-white"
|
||||
}`}
|
||||
>
|
||||
{tab.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Tab Content */}
|
||||
<div className="mt-6 space-y-6">
|
||||
{current.content.map((c, i) => (
|
||||
<div key={i} className="space-y-1">
|
||||
<p className="text-base font-medium text-white">{c.item}</p>
|
||||
<p className="text-sm text-gray-400 leading-relaxed">{c.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</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>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user