This commit is contained in:
2025-09-13 20:51:04 +02:00
parent 9ae2f3bbcb
commit 5cff4fe86d
21 changed files with 311 additions and 96 deletions

10
package-lock.json generated
View File

@@ -21,6 +21,7 @@
"popmotion": "^11.0.5", "popmotion": "^11.0.5",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-icons": "^5.5.0",
"react-type-animation": "^3.2.0", "react-type-animation": "^3.2.0",
"tailwind-merge": "^3.3.1", "tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.7", "tailwindcss": "^4.1.7",
@@ -11897,6 +11898,15 @@
"react-dom": ">=16.8.1" "react-dom": ">=16.8.1"
} }
}, },
"node_modules/react-icons": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",
"integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==",
"license": "MIT",
"peerDependencies": {
"react": "*"
}
},
"node_modules/react-is": { "node_modules/react-is": {
"version": "16.13.1", "version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",

View File

@@ -23,6 +23,7 @@
"popmotion": "^11.0.5", "popmotion": "^11.0.5",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-icons": "^5.5.0",
"react-type-animation": "^3.2.0", "react-type-animation": "^3.2.0",
"tailwind-merge": "^3.3.1", "tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.7", "tailwindcss": "^4.1.7",

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 718 KiB

View File

@@ -1,27 +1,48 @@
import { CallToAction } from '@/components/CallToAction'
import { Faqs } from '@/components/Faqs' import { Faqs } from '@/components/Faqs'
import { UseCases } from '@/components/UseCases' import { UseCases } from '@/components/UseCases'
import { SecondaryFeatures } from '@/components/SecondaryFeatures'
import { Steps } from '@/components/Steps' import { Steps } from '@/components/Steps'
import { HomeHero } from '@/components/HomeHero' import { HomeHero } from '@/components/HomeHero'
import { HomeAbout } from '@/components/HomeAbout' import { HomeAbout } from '@/components/HomeAbout'
import { ClickableGallery } from '@/components/ClickableGallery' import { ClickableGallery } from '@/components/ClickableGallery'
import { StackSectionPreview } from '@/components/StackSection' import { StackSectionPreview } from '@/components/StackSection'
import { Companies } from '@/components/Companies' import { Companies } from '@/components/Companies'
import { CallTo } from '@/components/CallTo'
import { ScrollDown } from '@/components/ui/ScrollDown'
import { ScrollUp } from '@/components/ui/ScrollUp'
export default function Home() { export default function Home() {
return ( return (
<> <>
<HomeHero /> <section id="home-hero">
<Companies /> <HomeHero />
<HomeAbout /> </section>
<StackSectionPreview /> <section id="companies">
<Steps /> <Companies />
<ClickableGallery /> </section>
<UseCases /> <section id="home-about">
<CallToAction /> <HomeAbout />
<SecondaryFeatures /> </section>
<Faqs /> <section id="stack-section">
<StackSectionPreview />
</section>
<section id="steps">
<Steps />
</section>
<section id="clickable-gallery">
<ClickableGallery />
</section>
<section id="use-cases">
<UseCases />
</section>
<section id="call-to-action">
<CallTo />
</section>
<section id="faqs">
<Faqs />
</section>
<ScrollDown />
<ScrollUp />
</> </>
) )
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

47
src/components/CallTo.tsx Normal file
View File

@@ -0,0 +1,47 @@
export function CallTo() {
return (
<div className="bg-transparent">
<div className="mx-auto max-w-7xl py-24 px-6 lg:px-4">
<div className="relative isolate overflow-hidden bg-stat-gradient py-16 text-center after:pointer-events-none after:absolute after:inset-0 sm:rounded-3xl sm:px-16">
<div className="mx-auto max-w-2xl lg:max-w-2xl">
<h2 className="text-2xl font-semibold tracking-tight leading-tight text-white lg:text-4xl">
More Resilient, More Powerful, More Diverse With You
</h2>
<p className="mx-auto mt-6 max-w-xl text-sm font-light text-pretty text-white lg:text-base">
Unlike the corporate internet, where users are the product, in the new internet, participants are the owners and beneficiaries.
</p>
<p className="mx-auto mt-6 max-w-xl text-sm font-light text-pretty text-white lg:text-base">
By participating, you're not just using the technology, you're also helping to build a digital world that protects privacy, promotes fairness, and returns control to the people.
</p>
<div className="mt-10 flex items-center justify-center gap-x-6">
<a
href="#"
className="rounded-md bg-white/10 px-3.5 py-2.5 text-sm font-semibold text-white hover:bg-white/15"
>
{' '}
Get started{' '}
</a>
<a href="#" className="text-sm/6 font-semibold text-white">
Learn more
<span aria-hidden="true"></span>
</a>
</div>
<svg
viewBox="0 0 1024 1024"
aria-hidden="true"
className="absolute top-1/2 left-1/2 -z-10 size-256 -translate-x-1/2 mask-[radial-gradient(closest-side,white,transparent)]"
>
<circle r={512} cx={512} cy={512} fill="url(#827591b1-ce8c-4110-b064-7cb85a0b1217)" fillOpacity="0.7" />
<defs>
<radialGradient id="827591b1-ce8c-4110-b064-7cb85a0b1217">
<stop stopColor="#fff4f8" />
<stop offset={1} stopColor="#97979d" />
</radialGradient>
</defs>
</svg>
</div>
</div>
</div>
</div>
)
}

View File

@@ -52,12 +52,12 @@ export function ClickableGallery() {
return ( return (
<> <>
<div className="relative isolate pt-24 pb-12 text-center"> <div className="relative isolate pt-24 pb-0 text-center w-full h-screen">
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 1, delay: 1 }} className="mx-auto max-w-5xl"> <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 1, delay: 1 }} className="mx-auto max-w-5xl">
<H2 className="text-center">One Agent, Endless Possibilities.</H2> <H2 className="text-center">One Agent, Endless Possibilities.</H2>
</motion.div> </motion.div>
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 1, delay: 1.5 }} className="mx-auto max-w-3xl mt-8"> <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 1, delay: 1.5 }} className="mx-auto max-w-4xl mt-6">
<P className="text-center"> <P className="text-center" color="custom">
The future isnt about more tools. Its about one intelligent partner that can do it all. This is your gateway to creativity, automation, and discovery. The future isnt about more tools. Its about one intelligent partner that can do it all. This is your gateway to creativity, automation, and discovery.
</P> </P>
</motion.div> </motion.div>
@@ -75,7 +75,7 @@ export function ClickableGallery() {
</div> </div>
</div> </div>
<section <section
className="relative w-full h-[900px] flex items-center justify-center overflow-hidden bg-background -mt-48" className="relative w-full h-[900px] flex items-center justify-center overflow-hidden bg-background -mt-32"
onMouseEnter={() => setHovering(true)} onMouseEnter={() => setHovering(true)}
onMouseLeave={() => setHovering(false)} onMouseLeave={() => setHovering(false)}
> >
@@ -165,7 +165,7 @@ export function ClickableGallery() {
{/* Foreground pill */} {/* Foreground pill */}
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-[60]"> <div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-[60]">
<div className="flex items-center justify-between w-[1040px] gap-6 rounded-3xl bg-white/95 shadow-[0_8px_40px_rgba(0,0,0,0.15)] px-12 py-6 backdrop-blur"> <div className="flex items-center justify-between w-[1040px] gap-6 rounded-3xl bg-white/95 shadow-[0_8px_40px_rgba(0,0,0,0.15)] px-12 py-6 backdrop-blur">
<H4 as="div" className="max-w-[820px] h-[72px]"> <H4 as="h4" className="max-w-[820px] h-[72px]">
<TypeAnimation <TypeAnimation
key={active} key={active}
sequence={[galleryItems[active].text]} sequence={[galleryItems[active].text]}

View File

@@ -27,8 +27,8 @@ const row4 = [TencentCloud, OpenAI, XAI];
export function Companies() { export function Companies() {
return ( return (
<div className="relative flex h-screen w-full overflow-hidden rounded-md bg-transparent antialiased md:items-center md:justify-center"> <div id="companies" className="relative flex h-screen w-full overflow-hidden rounded-md bg-transparent antialiased md:items-center md:justify-center">
<div className="relative z-10 mx-auto w-full max-w-6xl p-4 pt-16"> <div className="relative z-10 mx-auto w-full max-w-6xl p-4 py-12">
{/* Heading */} {/* Heading */}
<motion.div <motion.div
@@ -37,10 +37,10 @@ export function Companies() {
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
transition={{ duration: 1 }} transition={{ duration: 1 }}
> >
<H2 className="text-center"> <H2 className="text-center pb-6">
Seamlessly Deploy the Worlds Leading AI Models Deploy the Worlds Leading AI Models
</H2> </H2>
<P className="mt-6 text-center"> <P className="pb-8 text-center" color="custom">
Deploy and scale AI from top global providers on a decentralized, privacy-first infrastructure. Mycelium Cloud lets you integrate state-of-the-art intelligence into your workflows with full control, sovereignty, and cost efficiency. Deploy and scale AI from top global providers on a decentralized, privacy-first infrastructure. Mycelium Cloud lets you integrate state-of-the-art intelligence into your workflows with full control, sovereignty, and cost efficiency.
</P> </P>
</motion.div> </motion.div>

View File

@@ -22,14 +22,14 @@ function QrCodeBorder(props: React.ComponentPropsWithoutRef<'svg'>) {
export function Footer() { export function Footer() {
return ( return (
<footer className="border-t border-gray-200"> <footer id="footer" className="border-t border-gray-200">
<Container> <Container>
<div className="flex flex-col items-start justify-between gap-y-12 pt-16 pb-6 lg:flex-row lg:items-center lg:py-16"> <div className="flex flex-col items-start justify-between gap-y-12 pt-16 pb-6 lg:flex-row lg:items-center lg:py-16">
<div> <div>
<div className="flex items-center text-gray-900"> <div className="flex items-center text-gray-900">
<Logomark className="h-10 w-10 flex-none fill-cyan-500" /> <Logomark className="h-10 w-10 flex-none fill-cyan-500" />
<div className="ml-4"> <div className="ml-4">
<p className="text-base font-semibold">Mycelium</p> <p className="text-base font-semibold">Project Mycelium</p>
<p className="mt-1 text-sm">Unleash the Power of Decentralized Networks</p> <p className="mt-1 text-sm">Unleash the Power of Decentralized Networks</p>
</div> </div>
</div> </div>

View File

@@ -64,9 +64,9 @@ export function HomeAbout() {
That Never Sleep. That Never Sleep.
</H2> </H2>
</motion.div> </motion.div>
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 1, delay: 1.5 }} className="absolute top-64 left-0 max-w-xl text-left"> <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 1, delay: 1.5 }} className="absolute top-54 left-0 max-w-xl text-left">
<P> <P>
With Mycelium, you could deploy AI agents that handle your most complex workflows while maintaining complete data sovereignty and control. With Mycelium Cloud, you can deploy purpose-built AI agents to automate any workflow. Keep complete control of your data while scaling from simple tasks to complex decision-making.
</P> </P>
</motion.div> </motion.div>

View File

@@ -18,7 +18,7 @@ export function HomeHero() {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false) const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
return ( return (
<div className="relative h-screen -top-10"> <div className="relative h-screen -top-15">
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[700px] h-[700px] -z-10 rounded-full overflow-hidden"> <div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[700px] h-[700px] -z-10 rounded-full overflow-hidden">
<video <video
autoPlay autoPlay
@@ -33,7 +33,7 @@ export function HomeHero() {
<div className="relative isolate px-6 lg:px-8"> <div className="relative isolate px-6 lg:px-8">
<div <div
aria-hidden="true" aria-hidden="true"
className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80" className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl lg:-top-80"
> >
<div <div
style={{ style={{
@@ -45,7 +45,7 @@ export function HomeHero() {
</div> </div>
<div <div
aria-hidden="true" aria-hidden="true"
className="absolute inset-x-0 bottom-10 -z-10 transform-gpu overflow-hidden blur-3xl sm:bottom-40" className="absolute inset-x-0 bottom-10 -z-10 transform-gpu overflow-hidden blur-3xl lg:bottom-40"
> >
<div <div
style={{ style={{
@@ -55,12 +55,12 @@ export function HomeHero() {
className="relative bottom-[calc(50%+3rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#93c5fd] to-[#9089fc] opacity-20 sm:left-[calc(50%+30rem)] sm:w-[72.1875rem]" className="relative bottom-[calc(50%+3rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#93c5fd] to-[#9089fc] opacity-20 sm:left-[calc(50%+30rem)] sm:w-[72.1875rem]"
/> />
</div> </div>
<div className="relative -top-10 mx-auto max-w-8xl h-screen flex items-center justify-center"> <div className="relative -top-15 mx-auto max-w-8xl h-screen flex items-center justify-center">
<div className="text-center max-w-5xl"> <div className="text-center max-w-5xl">
<H1> <H1>
<TypeAnimation <TypeAnimation
sequence={[ sequence={[
'Decentralized Autonomous Agentic Cloud', 'Decentralized Autonomous Agentic Cloud.',
1000, 1000,
]} ]}
wrapper="span" wrapper="span"
@@ -74,14 +74,10 @@ export function HomeHero() {
animate={{ opacity: 1 }} animate={{ opacity: 1 }}
transition={{ duration: 1, delay: 1 }} transition={{ duration: 1, delay: 1 }}
> >
<PL className="absolute bottom-12 left-0 max-w-xl text-left"> <PL className="absolute bottom-0 left-0 max-w-xl text-left" color="custom">
Mycelium's advancements in Agentic infrastructure supports private, secure and autonomous Agents that connect, learn and grow with you. Mycelium's advancements in Agentic infrastructure supports private, secure and autonomous Agents that connect, learn and grow with you.
</PL> </PL>
</motion.div> </motion.div>
<a href="#about" className="absolute bottom-24 right-0 flex items-center gap-x-2 text-2xl font-medium text-[#2F3178] lg:text-3xl animate-bounce-y">
<span>scroll</span>
<ChevronDoubleDownIcon className="h-6 w-6" />
</a>
</div> </div>
</div> </div>
</div> </div>

File diff suppressed because one or more lines are too long

View File

@@ -11,7 +11,7 @@ export function StackSectionPreview() {
const isInView = useInView(ref); const isInView = useInView(ref);
return ( return (
<section ref={ref} className="w-full bg-transparent px-4 py-8 sm:px-6 sm:pb-12 lg:px-8 relative"> <section ref={ref} className="w-full h-screen bg-transparent lg:px-0 pt-24 pb-12 px-6 relative">
{/* Gradient Blob Component */} {/* Gradient Blob Component */}
<div className="absolute w-[400px] h-[200px] bg-gradient-to-br from-[#505050] to-[#7e7e7e] opacity-40 rounded-full blur-[150px] bottom-[200px] left-[-150px] z-0" /> <div className="absolute w-[400px] h-[200px] bg-gradient-to-br from-[#505050] to-[#7e7e7e] opacity-40 rounded-full blur-[150px] bottom-[200px] left-[-150px] z-0" />
<div className="absolute w-[200px] h-[100px] bg-gradient-to-br from-[#505050] to-[#7e7e7e] opacity-50 rounded-full blur-[150px] top-[200px] right-[-150px] z-0" /> <div className="absolute w-[200px] h-[100px] bg-gradient-to-br from-[#505050] to-[#7e7e7e] opacity-50 rounded-full blur-[150px] top-[200px] right-[-150px] z-0" />
@@ -34,19 +34,11 @@ export function StackSectionPreview() {
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 30 }} animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 30 }}
transition={{ duration: 0.8, delay: 0.6 }} transition={{ duration: 0.8, delay: 0.6 }}
> >
<P className="mx-auto mt-8 max-w-3xl"> <P className="mx-auto mt-8 max-w-3xl" color="custom">
Built with Mycelium technology, our AI infrastructure ensures unbreakable networks, complete data sovereignty, ultra-secure agent-human communication, and unhackable data storage systems. Built with Mycelium technology, our AI infrastructure ensures unbreakable networks, complete data sovereignty, ultra-secure agent-human communication, and unhackable data storage systems.
</P> </P>
</motion.div> </motion.div>
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 30 }}
transition={{ duration: 0.8, delay: 0.6 }}
>
<Button className="mt-12" variant="outline" href="https://threefold.io/build" >Discover How It Works </Button>
</motion.div>
</div> </div>
{/* Right Column - Stacked Cubes (2/3 width) */} {/* Right Column - Stacked Cubes (2/3 width) */}
<div className="lg:col-span-2 flex items-center justify-center lg:justify-start order-2 lg:order-2"> <div className="lg:col-span-2 flex items-center justify-center lg:justify-start order-2 lg:order-2">
<motion.div <motion.div

View File

@@ -5,6 +5,7 @@ import clsx from 'clsx'
import { useInView } from 'framer-motion' import { useInView } from 'framer-motion'
import { Container } from '@/components/Container' import { Container } from '@/components/Container'
import { H2, P, CT, CP } from '@/components/Texts' import { H2, P, CT, CP } from '@/components/Texts'
import { TbCircleNumber1Filled, TbCircleNumber2Filled, TbCircleNumber3Filled } from 'react-icons/tb'
@@ -12,33 +13,33 @@ import { H2, P, CT, CP } from '@/components/Texts'
const features = [ const features = [
{ {
name: '1. Choose Your Intelligence', name: 'Choose Your Intelligence',
description: 'Explore a library of leading LLMs and agentic functions. Pick the ones that fit your use case, from general assistants to specialized reasoning models.', description: 'Explore a library of leading LLMs and agentic functions. Pick the ones that fit your use case, from general assistants to specialized reasoning models.',
icon: 'step1', icon: TbCircleNumber1Filled,
}, },
{ {
name: '2. Add Your Knowledge', name: 'Add Your Knowledge',
description: description:
'Connect your data or knowledge base to enable personalized, context-aware results while keeping your information private.', 'Connect your data or knowledge base to enable personalized, context-aware results while keeping your information private.',
icon: 'step2', icon: TbCircleNumber2Filled,
}, },
{ {
name: '3. Define Your Network', name: 'Define Your Network',
description: description:
'Set up and manage your nodes with ease. Scale compute and storage as you grow, while staying fully sovereign and decentralized.', 'Set up and manage your nodes with ease. Scale compute and storage as you grow, while staying fully sovereign and decentralized.',
icon: 'step3', icon: TbCircleNumber3Filled,
}, },
] ]
export function Steps() { export function Steps() {
return ( return (
<section id="benefits" className="bg-white py-24 sm:py-32 dark:bg-gray-900"> <section id="benefits" className="bg-white pt-0 pb-12 dark:bg-gray-900">
<div className="mx-auto max-w-7xl px-6 lg:px-8"> <div className="mx-auto max-w-7xl px-6 lg:px-0">
<div className="mx-auto max-w-5xl lg:mx-0"> <div className="mx-auto max-w-5xl lg:mx-0">
<H2 className="text-3xl font-medium tracking-tight"> <H2 className="text-3xl font-medium tracking-tight">
Deploy Scalable, Decentralized LLMs and AI Agents in Seconds Deploy Scalable LLMs and AI Agents in Seconds
</H2> </H2>
<P className="mt-6 text-lg"> <P className="mt-6 text-lg" color="custom">
Launch and scale intelligence on your own terms. Mycelium Cloud makes it simple to deploy models, integrate knowledge, and run everything on a network you control. Launch and scale intelligence on your own terms. Mycelium Cloud makes it simple to deploy models, integrate knowledge, and run everything on a network you control.
</P> </P>
</div> </div>
@@ -48,13 +49,9 @@ export function Steps() {
key={feature.name} key={feature.name}
className="rounded-2xl border border-gray-200 p-8 dark:border-gray-700" className="rounded-2xl border border-gray-200 p-8 dark:border-gray-700"
> >
<img <feature.icon className="h-8 w-8 mb-4 text-[#2F3178]" />
src={`/images/${feature.icon}.svg`} <CT as="span" className="font-semibold">{feature.name}</CT>
alt={feature.name} <CP className="mt-2 text-sm" color="custom">{feature.description}</CP>
className="h-8 w-8 mb-4"
/>
<CT as="h3" className="font-semibold">{feature.name}</CT>
<CP className="mt-2 text-sm">{feature.description}</CP>
</li> </li>
))} ))}
</ul> </ul>

View File

@@ -1,38 +1,48 @@
import React from 'react'; import React from 'react';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
const textColors = 'text-[#2F3178]'; const colorVariants = {
primary: 'text-[#2F3178]',
secondary: 'text-gray-600',
custom: 'text-[#1c1c49]',
};
type TextOwnProps<E extends React.ElementType> = { type TextProps<E extends React.ElementType> = {
as?: E; as?: E;
children: React.ReactNode; children: React.ReactNode;
className?: string; className?: string;
}; color?: keyof typeof colorVariants;
} & Omit<React.ComponentPropsWithoutRef<E>, 'as' | 'children' | 'className' | 'color'>;
type TextProps<E extends React.ElementType> = TextOwnProps<E> & Omit<React.ComponentProps<E>, keyof TextOwnProps<E>>;
const createTextComponent = <E extends React.ElementType>( const createTextComponent = <E extends React.ElementType>(
defaultElement: E, defaultElement: E,
defaultClassName: string defaultClassName: string
) => { ) => {
const Text = <C extends React.ElementType = E>({ as, children, className, ...rest }: TextProps<C>) => { const Component = React.forwardRef<React.ElementRef<E>, TextProps<E>>(
const Component = as || defaultElement; ({ as, color = 'primary', className, children, ...props }, ref) => {
const Tag = as || defaultElement;
return (
<Tag
ref={ref}
className={cn(defaultClassName, colorVariants[color], className)}
{...props}
>
{children}
</Tag>
);
}
);
return ( Component.displayName = `Text(${defaultElement})`;
<Component className={cn(defaultClassName, textColors, className)} {...rest}> return Component;
{children}
</Component>
);
};
return Text;
}; };
export const H1 = createTextComponent('h1', 'text-5xl font-medium tracking-tight text-balance lg:text-8xl'); export const H1 = createTextComponent('h1', 'text-5xl font-medium tracking-tight text-balance lg:text-8xl');
export const PL = createTextComponent('p', 'text-2xl font-medium text-pretty leading-[1.2] lg:text-3xl'); export const PL = createTextComponent('p', 'text-2xl font-medium text-pretty leading-[1.2] lg:text-3xl');
export const H2 = createTextComponent('h2', 'text-4xl font-medium text-pretty lg:text-5xl'); export const H2 = createTextComponent('h2', 'text-4xl font-medium text-pretty lg:text-5xl');
export const P = createTextComponent('p', 'text-xl font-medium text-pretty lg:text-2xl'); export const P = createTextComponent('p', 'text-xl font-normal text-pretty lg:text-2xl');
export const H3 = createTextComponent('h3', 'text-3xl lg:text-4xl font-medium'); export const H3 = createTextComponent('h3', 'text-3xl lg:text-4xl font-medium');
export const H4 = createTextComponent('h4', 'text-2xl lg:text-3xl font-semibold leading-tight'); export const H4 = createTextComponent('h4', 'text-2xl lg:text-3xl font-semibold leading-tight');
export const CT = createTextComponent('span', 'text-sm lg:text-base font-semibold text-center'); export const CT = createTextComponent('span', 'text-base lg:text-xl font-semibold text-center');
export const CP = createTextComponent('p', 'text-sm leading-relaxed font-light'); export const CP = createTextComponent('p', 'text-sm lg:text-base leading-relaxed font-light');
export const NL = createTextComponent('span', 'text-lg font-semibold leading-6'); export const NL = createTextComponent('span', 'text-lg font-semibold leading-6');

View File

@@ -15,6 +15,7 @@ import {
} from '@heroicons/react/24/solid' } from '@heroicons/react/24/solid'
import { Container } from '@/components/Container' import { Container } from '@/components/Container'
import { H2, P } from '@/components/Texts'
interface Review { interface Review {
title: string title: string
@@ -175,7 +176,7 @@ function ReviewGrid() {
return ( return (
<div <div
ref={containerRef} ref={containerRef}
className="relative -mx-4 mt-16 grid h-196 max-h-[150vh] grid-cols-1 items-start gap-8 overflow-hidden px-4 sm:mt-20 md:grid-cols-2 lg:grid-cols-3" className="relative -mx-4 mt-0 grid h-196 max-h-[150vh] grid-cols-1 items-start gap-8 overflow-hidden px-4 sm:mt-20 md:grid-cols-2 lg:grid-cols-3"
> >
{isInView && ( {isInView && (
<> <>
@@ -220,15 +221,15 @@ export function UseCases() {
> >
<Container className=''> <Container className=''>
<div className="mx-auto max-w-2xl lg:max-w-5xl"> <div className="mx-auto max-w-2xl lg:max-w-5xl">
<h2 <H2
id="usecases-title" id="usecases-title"
className="text-3xl font-medium tracking-tight text-gray-900 sm:text-center" color="custom"
> >
Coming Soon: The Future of Mycelium Coming Soon: The Future of Mycelium
</h2> </H2>
<p className="mt-6 text-lg text-gray-600 sm:text-center"> <P className="mt-6 text-center" color="custom">
Mycelium Cloud is evolving to bring even more powerful decentralized features, designed to enhance your experience and expand possibilities. Be the first to explore what's coming next by staying connected with our latest updates. Mycelium Cloud is evolving to bring even more powerful decentralized features, designed to enhance your experience and expand possibilities. Be the first to explore what's coming next by staying connected with our latest updates.
</p> </P>
</div> </div>
<ReviewGrid /> <ReviewGrid />
</Container> </Container>

View File

@@ -88,7 +88,7 @@ export function Cube({ title, descriptionTitle, description, isActive, index, on
<h4 className="text-base font-semibold mb-2"> <h4 className="text-base font-semibold mb-2">
{descriptionTitle} {descriptionTitle}
</h4> </h4>
<CP>{description}</CP> <CP color="custom">{description}</CP>
</div> </div>
</motion.div> </motion.div>
)} )}
@@ -106,7 +106,7 @@ export function Cube({ title, descriptionTitle, description, isActive, index, on
<h4 className="text-base font-semibold mb-2 text-center"> <h4 className="text-base font-semibold mb-2 text-center">
{descriptionTitle} {descriptionTitle}
</h4> </h4>
<CP className="text-center">{description}</CP> <CP className="text-center" color="custom">{description}</CP>
</div> </div>
</motion.div> </motion.div>
)} )}

View File

@@ -0,0 +1,22 @@
'use client'
import { ChevronDoubleDownIcon } from '@heroicons/react/24/outline'
import { useScroll } from '@/hooks/useScroll'
export function ScrollDown() {
const { isAtBottom, scrollToNext } = useScroll()
if (isAtBottom) {
return null
}
return (
<button
onClick={scrollToNext}
className="fixed bottom-8 right-8 z-50 flex items-center gap-x-2 text-2xl font-medium text-[#1c1c49] lg:text-3xl animate-blink"
>
<span>scroll</span>
<ChevronDoubleDownIcon className="h-6 w-6" />
</button>
)
}

View File

@@ -0,0 +1,22 @@
'use client'
import { ChevronDoubleUpIcon } from '@heroicons/react/24/outline'
import { useScroll } from '@/hooks/useScroll'
export function ScrollUp() {
const { isAtBottom, scrollToTop } = useScroll()
if (!isAtBottom) {
return null
}
return (
<button
onClick={scrollToTop}
className="fixed bottom-8 right-8 z-50 flex items-center gap-x-2 text-2xl font-medium text-[#1c1c49] lg:text-3xl animate-blink"
>
<span>top</span>
<ChevronDoubleUpIcon className="h-6 w-6" />
</button>
)
}

45
src/hooks/useScroll.ts Normal file
View File

@@ -0,0 +1,45 @@
'use client'
import { useState, useEffect, useCallback } from 'react'
export function useScroll() {
const [isAtBottom, setIsAtBottom] = useState(false)
const handleScroll = useCallback(() => {
const footer = document.querySelector('footer')
if (footer) {
const footerTop = footer.getBoundingClientRect().top
setIsAtBottom(footerTop < window.innerHeight)
}
}, [])
useEffect(() => {
window.addEventListener('scroll', handleScroll)
handleScroll() // Initial check
return () => window.removeEventListener('scroll', handleScroll)
}, [handleScroll])
const scrollToNext = () => {
const sections = Array.from(
document.querySelectorAll('section[id]')
) as HTMLElement[]
const scrollPosition = window.scrollY + window.innerHeight / 2
const currentSection = sections.reduce((acc, section) => {
return section.offsetTop < scrollPosition ? section : acc
}, sections[0])
const currentIndex = sections.findIndex((sec) => sec.id === currentSection.id)
const nextIndex = currentIndex + 1
if (nextIndex < sections.length) {
sections[nextIndex].scrollIntoView({ behavior: 'smooth' })
}
}
const scrollToTop = () => {
window.scrollTo({ top: 0, behavior: 'smooth' })
}
return { isAtBottom, scrollToNext, scrollToTop }
}

View File

@@ -73,6 +73,11 @@
} }
} }
@keyframes blink {
0%, 100% { opacity: 1; }
50% { opacity: 0.3; }
}
@keyframes bounce-y { @keyframes bounce-y {
0%, 100% { 0%, 100% {
transform: translateY(-10%); transform: translateY(-10%);
@@ -95,6 +100,16 @@
} }
@layer utilities {
.animate-blink {
animation: blink 2s infinite;
}
.bg-stat-gradient {
background: linear-gradient(to bottom, #9089fc, #93c5fd);
}
}
@theme inline { @theme inline {
--animate-marquee: marquee var(--marquee-duration) linear infinite; --animate-marquee: marquee var(--marquee-duration) linear infinite;