feat: add mobile navigation menu to header

- Implemented responsive mobile menu using Headless UI Dialog component with hamburger toggle
- Refactored hero sections to use consistent boxed layout with background images and improved spacing
- Standardized button styling across hero components with arrow indicators for secondary actions
This commit is contained in:
2025-11-06 23:43:28 +01:00
parent 0f2f6df299
commit 8d1e2f4c7d
5 changed files with 170 additions and 92 deletions

BIN
public/images/agents.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@@ -1,10 +1,12 @@
import { useState } from 'react'
import { Link, useLocation } from 'react-router-dom' import { Link, useLocation } from 'react-router-dom'
import { Dropdown } from './ui/Dropdown' import { Dropdown } from './ui/Dropdown'
import { ChevronDownIcon } from '@heroicons/react/20/solid' import { ChevronDownIcon } from '@heroicons/react/20/solid'
import { Container } from './Container' import { Container } from './Container'
import { Button } from './Button' import { Button } from './Button'
import pmyceliumLogo from '../images/logos/logo_1.png' import pmyceliumLogo from '../images/logos/logo_1.png'
import { Dialog } from '@headlessui/react'
import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline'
const cloudNavItems = [ const cloudNavItems = [
{ name: 'Cloud', href: '/cloud' }, { name: 'Cloud', href: '/cloud' },
@@ -15,6 +17,7 @@ const cloudNavItems = [
export function Header() { export function Header() {
const location = useLocation() const location = useLocation()
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
const getCurrentPageName = () => { const getCurrentPageName = () => {
const currentPath = location.pathname; const currentPath = location.pathname;
@@ -72,9 +75,84 @@ export function Header() {
Get Mycelium Connector Get Mycelium Connector
</Button> </Button>
</div> </div>
<div className="lg:hidden">
<button
type="button"
className="-m-2.5 inline-flex items-center justify-center rounded-md p-2.5 text-gray-700 hover:text-cyan-500 transition-colors"
onClick={() => setMobileMenuOpen(true)}
>
<span className="sr-only">Open main menu</span>
<Bars3Icon className="h-6 w-6" aria-hidden="true" />
</button>
</div>
</div> </div>
</Container> </Container>
</nav> </nav>
<Dialog as="div" className="lg:hidden" open={mobileMenuOpen} onClose={setMobileMenuOpen}>
<div className="fixed inset-0 z-10" />
<Dialog.Panel className="fixed inset-y-0 right-0 z-10 w-full overflow-y-auto bg-white px-6 py-6 sm:max-w-sm sm:ring-1 sm:ring-gray-900/10">
<div className="flex items-center justify-between">
<Link to="#" className="-m-1.5 p-1.5">
<span className="sr-only">Mycelium</span>
<img
className="h-8 w-auto"
src={pmyceliumLogo}
alt=""
/>
</Link>
<button
type="button"
className="-m-2.5 rounded-md p-2.5 text-gray-700 hover:text-cyan-500 transition-colors"
onClick={() => setMobileMenuOpen(false)}
>
<span className="sr-only">Close menu</span>
<XMarkIcon className="h-6 w-6" aria-hidden="true" />
</button>
</div>
<div className="mt-6 flow-root">
<div className="-my-6 divide-y divide-gray-500/10">
<div className="space-y-2 py-6">
{cloudNavItems.map((item) => (
<Link
key={item.name}
to={item.href}
className="-mx-3 block rounded-lg px-3 py-2 text-base font-semibold leading-7 text-gray-900 hover:bg-gray-50"
>
{item.name}
</Link>
))}
<Link
to="/network"
className="-mx-3 block rounded-lg px-3 py-2 text-base font-semibold leading-7 text-gray-900 hover:bg-gray-50"
>
Network
</Link>
<Link
to="/agents"
className="-mx-3 block rounded-lg px-3 py-2 text-base font-semibold leading-7 text-gray-900 hover:bg-gray-50"
>
Agents
</Link>
</div>
<div className="py-6">
<Button
to="https://myceliumcloud.tf"
variant="outline"
as="a"
target="_blank"
rel="noopener noreferrer"
className="w-full"
>
Start Deployment
</Button>
<Button to="/download" variant="solid" color="cyan" className="mt-4 w-full">
Get Mycelium Connector
</Button>
</div>
</div>
</div>
</Dialog.Panel>
</Dialog>
</header> </header>
) )
} }

View File

@@ -1,40 +1,43 @@
'use client' 'use client'
import { Button } from '@/components/Button' import { Button } from '@/components/Button'
import { Eyebrow, P, H3 } from '@/components/Texts' import { Eyebrow, H3 } from '@/components/Texts'
export function AgentHeroAlt() { export function AgentHeroAlt() {
return ( return (
<div className="relative bg-white lg:mt-10 mt-0"> <div className="">
<div className="relative h-80 overflow-hidden bg-transparent md:absolute md:right-0 md:h-full md:w-1/3 lg:w-2/3"> {/* Boxed container */}
<img <div
alt="" className="relative mx-auto max-w-7xl border border-t-0 border-b-0 border-gray-200 bg-white overflow-hidden bg-contain bg-right bg-no-repeat"
src="/images/agents.png" style={{ backgroundImage: "url('/images/agents.webp')", backgroundSize: "contain" }}
className="size-full object-cover" >
/> {/* Inner padding */}
<div className="px-6 py-16 lg:py-16">
</div> <div className="max-w-2xl lg:pl-6">
<div className="relative mx-auto max-w-7xl py-24 sm:py-32 lg:px-8"> <Eyebrow>MYCELIUM AGENTS</Eyebrow>
<div className="pr-6 pl-6 md:mr-auto md:w-2/3 md:pr-16 lg:w-1/2 lg:pl-0 lg:pr-24 xl:pr-32"> <H3 as="h1" className="mt-4">
<Eyebrow className="text-base/7 font-semibold text-cyan-500">MYCELIUM AGENTS</Eyebrow> Sovereign AI Agents, Coming Soon.
<H3 as="h1" className="mt-2 text-gray-900">Sovereign AI Agents, Coming Soon.</H3> </H3>
<P className="mt-6 text-gray-600"> <p className="mt-6 text-lg">
The Agent layer will allow you to run autonomous, policy-governed AI that operates on infrastructure you control, with private memory, verifiable execution, and coordination across your personal or organizational environment. The Agent layer will allow you to run autonomous, policy-governed AI that operates on infrastructure you control, with private memory, verifiable execution, and coordination across your personal or organizational environment.
</P> </p>
<P className="mt-6 text-gray-600"> <p className="mt-4 lg:text-base italic text-gray-600 text-sm">
Works Alone. Works Together. Works Alone. Works Together. Use Agents on top of any Mycelium Cloud deployment or pair them with the Mycelium Network for private, encrypted collaboration across users and systems.
Use Agents on top of any Mycelium Cloud deployment or pair them with the Mycelium Network for private, encrypted collaboration across users and systems. </p>
</P> <div className="mt-10 flex items-center gap-x-6">
<div className="mt-8"> <Button href="#" variant="solid" color="cyan">
<Button href="#" variant="solid" color="cyan"> Follow Deployment
Follow Deployment </Button>
</Button> <Button href="#" variant="outline">
<Button href="#" variant="outline" color="white"> Explore Docs <span aria-hidden="true"></span>
Explore Docs </Button>
</Button> </div>
</div> </div>
</div> </div>
</div> </div>
{/* ✅ Bottom horizontal line with spacing */}
<div className="w-full border-b border-gray-200" />
<div className="max-w-7xl bg-transparent mx-auto py-6 border border-t-0 border-b-0 border-gray-200"></div>
</div> </div>
) )
} }

View File

@@ -1,42 +1,40 @@
'use client' 'use client'
import { Button } from '@/components/Button' import { Button } from '@/components/Button'
import { Eyebrow, SectionHeader, P } from '@/components/Texts' import { Eyebrow, H3 } from '@/components/Texts'
export function GpuHero() { export function GpuHero() {
return ( return (
<div className="relative bg-white"> <div className="">
<div className="relative h-80 overflow-hidden bg-transparent md:absolute md:right-0 md:h-full md:w-1/3 lg:w-1/2"> {/* Boxed container */}
<img <div
alt="Mycelium GPU nebula illustration" className="relative mx-auto max-w-7xl border border-t-0 border-b-0 border-gray-200 bg-white overflow-hidden bg-contain bg-right bg-no-repeat"
src="/images/gpuhero2.png" style={{ backgroundImage: "url('/images/gpuhero2.png')", backgroundSize: "contain" }}
className="size-full object-contain" >
/> {/* Inner padding */}
</div> <div className="px-6 py-16 lg:py-16">
<div className="relative mx-auto max-w-7xl py-24 lg:py-32 lg:px-8"> <div className="max-w-2xl lg:pl-6">
<div className="pr-6 pl-6 md:mr-auto md:w-2/3 md:pr-16 lg:w-1/2 lg:pl-0 lg:pr-24 "> <Eyebrow>Mycelium GPU</Eyebrow>
<Eyebrow className="tracking-[0.35em] uppercase text-cyan-500"> <H3 as="h1" className="mt-4">
Mycelium GPU Sovereign GPU Acceleration for AI and High-Performance Compute
</Eyebrow> </H3>
<SectionHeader as="h1" className="mt-4 text-gray-900"> <p className="mt-6 text-lg">
Sovereign GPU Acceleration for AI and High-Performance Compute Access GPUs across the Mycelium mesh without waitlists, inflated pricing, or centralized control. Run inference, training, and compute workloads where they make sense: cloud, edge, or on your own hardware.
</SectionHeader> </p>
<P className="mt-6 text-gray-600"> <div className="mt-10 flex items-center gap-x-6">
Access GPUs across the Mycelium mesh without waitlists, <Button to="#gpu-getting-started" as="a" variant="solid" color="cyan">
inflated pricing, or centralized control. How it works
Run inference, training, and compute workloads where they make sense: </Button>
cloud, edge, or on your own hardware. <Button to="#gpu-architecture" as="a" variant="outline">
</P> Explore Docs <span aria-hidden="true"></span>
<div className="mt-10 flex flex-wrap gap-4"> </Button>
<Button to="#gpu-getting-started" as="a" variant="solid" color="cyan"> </div>
How it works
</Button>
<Button to="#gpu-architecture" as="a" variant="outline" color="cyan">
Explore Docs
</Button>
</div> </div>
</div> </div>
</div> </div>
{/* ✅ Bottom horizontal line with spacing */}
<div className="w-full border-b border-gray-200" />
<div className="max-w-7xl bg-transparent mx-auto py-6 border border-t-0 border-b-0 border-gray-200"></div>
</div> </div>
) )
} }

View File

@@ -1,45 +1,44 @@
'use client' 'use client'
import { Button } from '@/components/Button' import { Button } from '@/components/Button'
import { Eyebrow, SectionHeader, P } from '@/components/Texts' import { Eyebrow, H3 } from '@/components/Texts'
export function StorageHero() { export function StorageHero() {
return ( return (
<div className="relative bg-white"> <div className="">
<div className="relative h-80 overflow-hidden bg-transparent md:absolute md:right-0 md:h-full md:w-1/3 lg:w-1/2"> {/* Boxed container */}
<img <div
alt="Mycelium Storage visual" className="relative mx-auto max-w-7xl border border-t-0 border-b-0 border-gray-200 bg-white overflow-hidden bg-contain bg-right bg-no-repeat"
src="/images/computehero11.webp" style={{ backgroundImage: "url('/images/computehero11.webp')", backgroundSize: "contain" }}
className="size-full object-contain" >
/> {/* Inner padding */}
</div> <div className="px-6 py-16 lg:py-16">
<div className="relative mx-auto max-w-7xl py-24 lg:py-32 lg:px-8"> <div className="max-w-2xl lg:pl-6">
<div className="pr-6 pl-6 md:mr-auto md:w-2/3 md:pr-16 lg:w-1/2 lg:pl-0 lg:pr-24 xl:pr-32"> <Eyebrow>Mycelium Storage</Eyebrow>
<Eyebrow className="tracking-[0.35em] uppercase text-cyan-500"> <H3 as="h1" className="mt-4">
Mycelium Storage Sovereign Storage With Self-Healing and Multi-Protocol Access
</Eyebrow> </H3>
<SectionHeader as="h1" className="mt-4 text-gray-900"> <p className="mt-6 text-lg">
Sovereign Storage With Self-Healing and Multi-Protocol Access Store, replicate, and serve data across the global mesh with encrypted, quantum safe, verifiable storage you control at the infrastructure layer.
</SectionHeader> </p>
<P className="mt-6 text-gray-600"> <div className="mt-10 flex items-center gap-x-6">
Store, replicate, and serve data across the global mesh <Button to="#storage-features" as="a" variant="solid" color="cyan">
with encrypted, quantum safe, verifiable storage you control at the infrastructure layer. How It Works
</P> </Button>
<div className="mt-10 flex flex-wrap gap-4"> <Button
<Button to="#storage-features" as="a" variant="solid" color="cyan"> to="#storage-developer-experience"
How It Works as="a"
</Button> variant="outline"
<Button >
to="#storage-developer-experience" Explore Docs <span aria-hidden="true"></span>
as="a" </Button>
variant="outline" </div>
color="cyan"
>
Explore Docs
</Button>
</div> </div>
</div> </div>
</div> </div>
{/* ✅ Bottom horizontal line with spacing */}
<div className="w-full border-b border-gray-200" />
<div className="max-w-7xl bg-transparent mx-auto py-6 border border-t-0 border-b-0 border-gray-200"></div>
</div> </div>
) )
} }