forked from emre/www_projectmycelium_com
refactor: remove placeholder CTAs and links across multiple pages
- Removed unused Button imports from AgentHeroAlt, GallerySection, ComputeCapabilities, and StorageCapabilitiesNew - Replaced placeholder buttons/links with TODO comments indicating future implementation - Changed StorageCoreValue value items from <a> to <div> and removed href/target/rel attributes - Added descriptive TODO comments explaining what was previously rendered and what needs to be added - Affected components: AgentHeroAlt (
This commit is contained in:
@@ -8,7 +8,7 @@ export function Footer() {
|
||||
<div className="flex flex-col items-start justify-between gap-y-12 pt-16 pb-6 lg:flex-row lg:items-center lg:py-8">
|
||||
<div>
|
||||
<div className="flex items-center text-gray-900">
|
||||
<img src="src/images/logos/logomark.svg" alt="Mycelium Logomark" className="h-13 w-13 flex-none" />
|
||||
<img src="/images/logomark.svg" alt="Mycelium Logomark" className="h-13 w-13 flex-none" />
|
||||
<div className="ml-4">
|
||||
<p className="text-base lg:text-lg font-semibold">Project Mycelium</p>
|
||||
<p className="mt-1 text-sm">Unleash the Power of Decentralization</p>
|
||||
|
||||
@@ -71,30 +71,27 @@ const clusterNodes = (nodeList: GeoNode[], cellSize = 2) => {
|
||||
function DynamicMapContainer() {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [nodes, setNodes] = useState<GeoNode[]>([]);
|
||||
const API_URL = "https://gridproxy.grid.tf/nodes?healthy=true&size=99999";
|
||||
const API_URL = "https://gridproxy.grid.tf/nodes?healthy=true&size=500";
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchNodeData() {
|
||||
try {
|
||||
const response = await fetch(API_URL);
|
||||
const data: RawNode[] = await response.json(); // Type the incoming data
|
||||
const data: RawNode[] = await response.json();
|
||||
|
||||
// 🚨 Map the API response to your component's expected GeoNode format
|
||||
const geoNodes: GeoNode[] = data
|
||||
.filter((node: RawNode) => node.location && node.location.latitude && node.location.longitude)
|
||||
.map((node: RawNode) => ({
|
||||
// Convert string coordinates to numbers
|
||||
lat: parseFloat(node.location.latitude),
|
||||
lng: parseFloat(node.location.longitude),
|
||||
label: `${node.location.city}, ${node.location.country} (${node.node_id})`,
|
||||
// Optionally set color based on some node property if available
|
||||
}));
|
||||
|
||||
const clusteredNodes = clusterNodes(geoNodes);
|
||||
setNodes(clusteredNodes);
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch node data:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
@@ -102,30 +99,24 @@ function DynamicMapContainer() {
|
||||
fetchNodeData();
|
||||
}, []);
|
||||
|
||||
// --- RENDERING ---
|
||||
|
||||
// While fetching, show a loading state
|
||||
if (loading) {
|
||||
// Show a loading state while data is being fetched
|
||||
return (
|
||||
<div className="flex justify-center items-center w-full aspect-[2/1] bg-[#111111] rounded-lg text-cyan-500">
|
||||
<motion.span
|
||||
animate={{ rotate: 360 }}
|
||||
transition={{ duration: 1, repeat: Infinity, ease: "linear" }}
|
||||
className="text-4xl"
|
||||
>
|
||||
🌎
|
||||
</motion.span>
|
||||
<p className="ml-4">Loading nodes...</p>
|
||||
</div>
|
||||
<div className="flex justify-center items-center w-full aspect-[2/1] bg-[#111111] rounded-lg text-cyan-500">
|
||||
<motion.span
|
||||
animate={{ rotate: 360 }}
|
||||
transition={{ duration: 1, repeat: Infinity, ease: "linear" }}
|
||||
className="text-4xl"
|
||||
>
|
||||
🌎
|
||||
</motion.span>
|
||||
<p className="ml-4">Loading nodes...</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Pass the dynamically fetched nodes to your WorldMap component
|
||||
return (
|
||||
<WorldMap
|
||||
nodes={nodes}
|
||||
/>
|
||||
);
|
||||
// After data is loaded, render the map
|
||||
return <WorldMap nodes={nodes} />;
|
||||
}
|
||||
|
||||
export default DynamicMapContainer;
|
||||
@@ -1,6 +1,5 @@
|
||||
'use client'
|
||||
|
||||
import { Button } from '@/components/Button'
|
||||
import { Eyebrow, H3, P } from '@/components/Texts'
|
||||
|
||||
export function AgentHeroAlt() {
|
||||
@@ -30,12 +29,8 @@ Private, local, and autonomous by design, they give you everything you need to b
|
||||
</P>
|
||||
|
||||
<div className="mt-10 flex items-center gap-x-6">
|
||||
<Button href="#" variant="solid" color="cyan">
|
||||
Follow Development
|
||||
</Button>
|
||||
<Button href="#" variant="outline">
|
||||
Explore Docs <span aria-hidden="true">→</span>
|
||||
</Button>
|
||||
{/* TODO: Hero CTAs (Follow Development / Explore Docs) to be added when links are ready.
|
||||
Previously two Buttons here with href="#". */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useEffect, useMemo, useState } from 'react'
|
||||
import { useResponsiveCarousel } from '@/hooks/useResponsiveCarousel';
|
||||
import { motion, AnimatePresence } from 'framer-motion'
|
||||
import { wrap } from 'popmotion'
|
||||
import { Button } from '@/components/Button';
|
||||
import { SectionHeader, P, Eyebrow, CP } from '@/components/Texts';
|
||||
import { TypeAnimation } from 'react-type-animation'
|
||||
import { FadeIn } from '@/components/FadeIn';
|
||||
@@ -147,9 +146,8 @@ export function GallerySection() {
|
||||
repeat={0}
|
||||
/>
|
||||
</CP>
|
||||
<Button href="#" color="cyan" className="text-sm px-4 py-2 lg:text-base whitespace-nowrap">
|
||||
Start
|
||||
</Button>
|
||||
{/* TODO: Desktop CTA (Start) button to be added when link target is defined.
|
||||
Previously: <Button href="#" color="cyan">Start</Button> */}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -166,9 +164,8 @@ export function GallerySection() {
|
||||
repeat={0}
|
||||
/>
|
||||
</CP>
|
||||
<Button href="#" color="cyan" className="text-xs px-3 py-1.5 whitespace-nowrap">
|
||||
Start
|
||||
</Button>
|
||||
{/* TODO: Mobile CTA (Start) button to be added when link target is defined.
|
||||
Previously: <Button href="#" color="cyan">Start</Button> */}
|
||||
</div>
|
||||
</div>
|
||||
</FadeIn>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import { Container } from '@/components/Container'
|
||||
import { Eyebrow, H3, P } from '@/components/Texts'
|
||||
import { Button } from '@/components/Button'
|
||||
|
||||
const capabilities = [
|
||||
{
|
||||
@@ -76,14 +75,8 @@ export function ComputeCapabilities() {
|
||||
</ul>
|
||||
|
||||
{/* Button section */}
|
||||
<div className="mx-auto mt-12 flex justify-center gap-6">
|
||||
<Button variant="solid" color="cyan" href="#">
|
||||
Get Started
|
||||
</Button>
|
||||
<Button variant="outline" color="white" href="#">
|
||||
Explore Docs
|
||||
</Button>
|
||||
</div>
|
||||
{/* TODO: CTA buttons (Get Started / Explore Docs) to be re-enabled when real links are available.
|
||||
Previously rendered here as two Buttons with href="#". */}
|
||||
</Container>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -78,12 +78,8 @@ export function ComputeCapabilitiesNew() {
|
||||
|
||||
{/* Arrows inside first card */}
|
||||
<div className="flex items-center gap-x-4 mt-2">
|
||||
<a
|
||||
href="#"
|
||||
className="inline-flex items-center gap-1 text-cyan-400 hover:text-cyan-300 text-sm font-medium mr-auto"
|
||||
>
|
||||
Learn more →
|
||||
</a>
|
||||
{/* TODO: Intro card CTA (Learn more) to be added here when destination is defined.
|
||||
Previously: <a href="#" className="inline-flex items-center ...">Learn more →</a> */}
|
||||
<button
|
||||
onClick={scrollLeft}
|
||||
className="h-8 w-8 flex items-center justify-center border border-gray-800 rounded-md hover:border-cyan-500 transition-colors"
|
||||
|
||||
@@ -35,9 +35,8 @@ export function ComputeHero({ onGetStartedClick = () => {} }: { onGetStartedClic
|
||||
>
|
||||
Get started
|
||||
</Button>
|
||||
<Button to="#" variant="outline">
|
||||
Documentation <span aria-hidden="true">→</span>
|
||||
</Button>
|
||||
{/* TODO: Secondary CTA (Documentation) link to be wired when docs route is ready.
|
||||
Previously: <Button to="#" variant="outline">Documentation →</Button> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -103,7 +103,7 @@ export function HomeMap() {
|
||||
Mycelium runs on nodes hosted by people and organizations around the world.
|
||||
Each node adds compute, storage, and bandwidth, expanding the network’s capacity and resilience.
|
||||
</P>
|
||||
<P className="text-sm md:text-lg text-gray-200 max-w-3xl mx-auto py-4">
|
||||
<P className="text-sm md:text-lg text-gray-200 max-w-3xl mx-auto mt-2 mb-6">
|
||||
You can share your idle resources and earn rewards when they are used.
|
||||
Configure it once. Your node takes over from there.
|
||||
</P>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { AnimatedSection } from '../../components/AnimatedSection'
|
||||
import { CallToAction } from './CallToAction'
|
||||
import { HomeTab } from './HomeTab'
|
||||
@@ -7,7 +7,50 @@ import { HomeAurora } from './HomeAurora'
|
||||
import { HomeArchitecture } from './HomeArchitecture';
|
||||
import { HomeDesign } from './HomeDesign';
|
||||
|
||||
function LazyHomeMapSection() {
|
||||
const [isVisible, setIsVisible] = useState(false)
|
||||
const containerRef = useRef<HTMLDivElement | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const el = containerRef.current
|
||||
if (!el || isVisible) return
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
const [entry] = entries
|
||||
if (entry.isIntersecting) {
|
||||
setIsVisible(true)
|
||||
observer.disconnect()
|
||||
}
|
||||
},
|
||||
{
|
||||
root: null,
|
||||
rootMargin: '200px 0px',
|
||||
threshold: 0.1,
|
||||
},
|
||||
)
|
||||
|
||||
observer.observe(el)
|
||||
|
||||
return () => {
|
||||
observer.disconnect()
|
||||
}
|
||||
}, [isVisible])
|
||||
|
||||
return (
|
||||
<div ref={containerRef}>
|
||||
{isVisible ? (
|
||||
<HomeMap />
|
||||
) : (
|
||||
<div className="max-w-7xl mx-auto px-6 py-16 text-center text-gray-400">
|
||||
<p className="text-sm md:text-base">
|
||||
Loading live node map when you scroll here…
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
@@ -17,7 +60,7 @@ export default function HomePage() {
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<HomeArchitecture/>
|
||||
<HomeArchitecture />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
@@ -25,16 +68,16 @@ export default function HomePage() {
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<HomeMap />
|
||||
<LazyHomeMapSection />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
|
||||
<HomeDesign />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
|
||||
|
||||
<CallToAction />
|
||||
</AnimatedSection>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -116,20 +116,8 @@ export function PodsPricing() {
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* CTA */}
|
||||
<a
|
||||
href={tier.href}
|
||||
aria-describedby={tier.id}
|
||||
className={`mt-8 block rounded-md px-3 py-2 text-center text-sm font-semibold
|
||||
focus-visible:outline-2 focus-visible:outline-offset-2
|
||||
${
|
||||
tier.mostPopular
|
||||
? "bg-cyan-500 text-white hover:bg-cyan-400 focus-visible:outline-cyan-500"
|
||||
: "bg-white/10 text-white hover:bg-white/20 focus-visible:outline-cyan-500"
|
||||
}`}
|
||||
>
|
||||
Choose Pod
|
||||
</a>
|
||||
{/* TODO: Plan-specific CTA (Choose Pod) to be reinstated when purchase/upgrade flows are ready.
|
||||
Previously rendered an <a href={tier.href}>Choose Pod</a> button here. */}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -70,12 +70,8 @@ export function StorageCapabilitiesNew() {
|
||||
|
||||
{/* Arrows inside first card */}
|
||||
<div className="flex items-center gap-x-4 mt-2">
|
||||
<a
|
||||
href="#"
|
||||
className="inline-flex items-center gap-1 text-cyan-400 hover:text-cyan-300 text-sm font-medium mr-auto"
|
||||
>
|
||||
Learn more →
|
||||
</a>
|
||||
{/* TODO: Intro card CTA (Learn more) to be added here when destination is defined.
|
||||
Previously: <a href="#" className="inline-flex items-center ...">Learn more →</a> */}
|
||||
<button
|
||||
onClick={scrollLeft}
|
||||
className="h-8 w-8 flex items-center justify-center border border-gray-800 rounded-md hover:border-cyan-500 transition-colors"
|
||||
|
||||
@@ -51,18 +51,15 @@ export function StorageCoreValue() {
|
||||
{/* ✅ 3x2 logo grid */}
|
||||
<div className="mt-12 grid grid-cols-3 gap-x-8 gap-y-12">
|
||||
{values.map((value, i) => (
|
||||
<a
|
||||
<div
|
||||
key={i}
|
||||
href={value.href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex flex-col items-center text-center p-6 border border-gray-200 rounded-lg transition-transform duration-300 hover:scale-105 hover:shadow-lg"
|
||||
>
|
||||
<value.animation />
|
||||
<CT className="text-gray-900 mt-4 font-semibold">
|
||||
{value.title}
|
||||
</CT>
|
||||
</a>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Container>
|
||||
|
||||
Reference in New Issue
Block a user