fix rbuild

This commit is contained in:
2025-09-14 16:12:31 +02:00
parent e77b4744c7
commit aaab070de1
10 changed files with 276 additions and 152 deletions

View File

@@ -1,46 +1,43 @@
export function CallTo() { import { H2, P } from '@/components/Texts'
return (
<div className="bg-transparent"> export function CallTo() {
<div className="mx-auto max-w-7xl py-24 px-6 lg:px-4"> return (
<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="relative isolate overflow-hidden max-w-5xl mx-auto py-24">
<div className="mx-auto max-w-2xl lg:max-w-2xl"> <div className="relative isolate overflow-hidden bg-gray-50/10 px-6 py-24 text-center shadow-md shadow-gray-900/5 sm:rounded-3xl sm:px-16 border border-gray-200">
<h2 className="text-3xl font-semibold tracking-tight leading-tight text-white lg:text-5xl"> <div className="mx-auto max-w-4xl text-center">
Say Hello to Decentralized AI Agents that are Truly Yours <H2 color="primary">
</h2> Say hello to Decentralized AI Agents that are Truly Yours
<p className="mx-auto mt-6 mb-4 max-w-xl text-base font-light text-pretty text-white lg:text-lg"> </H2>
<P color="custom" className="mt-8 max-w-3xl">
Why hand out your intelligence to centralized giants when you can build your own? Why hand out your intelligence to centralized giants when you can build your own?
</p> </P>
<p className="mx-auto max-w-xl text-base font-light text-pretty text-white lg:text-lg"> <div className="mt-10 flex items-center justify-center gap-x-6">
With Project Myceliums Decentralized Agentic Cloud, youre not just adopting AIyoure claiming your own sovereign, autonomous AI infrastructure that grows and evolves with you. <a
</p> href="#"
<div className="mt-10 flex items-center justify-center gap-x-6"> className="rounded-md bg-[#2F3178] px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-[#2F3178]/80 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#2F3178]"
<a
href="#"
className="rounded-md bg-white/10 px-3.5 py-2.5 text-base font-semibold text-white hover:bg-white/15"
>
{' '}
Book a Meeting{' '}
</a>
<a href="#" className="rounded-md bg-white/10 px-3.5 py-2.5 text-base font-semibold text-white hover:bg-white/15">
Join the Waitlist
</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" /> Book a Meeting
<defs> </a>
<radialGradient id="827591b1-ce8c-4110-b064-7cb85a0b1217"> <a href="#" className="text-sm/6 font-semibold text-[#2F3178] hover:text-[#2F3178]/80">
<stop stopColor="#fff4f8" /> Join the Waitlist <span aria-hidden="true"></span>
<stop offset={1} stopColor="#97979d" /> </a>
</radialGradient>
</defs>
</svg>
</div> </div>
</div> </div>
</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(#8d958450-c69f-4251-94bc-4e091a323369)" fillOpacity="1" />
<defs>
<radialGradient id="8d958450-c69f-4251-94bc-4e091a323369">
<stop stopColor="#B5A8EF" />
<stop offset={1} stopColor="#8479D9" />
</radialGradient>
</defs>
</svg>
</div> </div>
)
} </div>
)
}

View File

@@ -1,8 +1,8 @@
'use client' 'use client'
import { useEffect, useMemo, useState } from 'react' import { useEffect, useMemo, useState, useRef } from 'react'
import Image from 'next/image' import Image from 'next/image'
import { motion, AnimatePresence } from 'framer-motion' import { motion, AnimatePresence, useInView } from 'framer-motion'
import { wrap } from 'popmotion' import { wrap } from 'popmotion'
import { Button } from '@/components/Button'; import { Button } from '@/components/Button';
import { H2, P, H4 } from '@/components/Texts'; import { H2, P, H4 } from '@/components/Texts';
@@ -34,6 +34,8 @@ const AUTOPLAY_MS = 3200
export function ClickableGallery() { export function ClickableGallery() {
const [active, setActive] = useState(0) const [active, setActive] = useState(0)
const [hovering, setHovering] = useState(false) const [hovering, setHovering] = useState(false)
const ref = useRef(null);
const isInView = useInView(ref, { once: true });
// autoplay // autoplay
useEffect(() => { useEffect(() => {
@@ -51,17 +53,20 @@ export function ClickableGallery() {
const prev = () => setActive((i) => wrap(0, galleryItems.length, i - 1)) const prev = () => setActive((i) => wrap(0, galleryItems.length, i - 1))
return ( return (
<> <div ref={ref}>
<div className="relative isolate pt-24 pb-0 text-center w-full"> <div className="relative isolate pt-24 pb-0 text-center w-full">
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 1, delay: 1 }} className="mx-auto max-w-5xl"> <motion.div initial={{ opacity: 0, y: 20 }} animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }} transition={{ duration: 0.8, delay: 0.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-4xl mt-6"> <motion.div initial={{ opacity: 0, y: 20 }} animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }} transition={{ duration: 0.8, delay: 0.2 }} className="mx-auto max-w-4xl mt-6">
<P className="text-center" color="custom"> <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>
<div <motion.div
initial={{ opacity: 0 }}
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
transition={{ duration: 1, delay: 0.3 }}
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 sm:-top-80"
> >
@@ -72,9 +77,12 @@ export function ClickableGallery() {
}} }}
className="relative left-[calc(50%-30rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#93c5fd] to-[#9089fc] opacity-30 sm:left-[calc(50%-36rem)] sm:w-[72.1875rem]" className="relative left-[calc(50%-30rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#93c5fd] to-[#9089fc] opacity-30 sm:left-[calc(50%-36rem)] sm:w-[72.1875rem]"
/> />
</div> </motion.div>
</div> </div>
<section <motion.section
initial={{ opacity: 0 }}
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
transition={{ duration: 1, delay: 0.4 }}
className="relative w-full flex items-center justify-center overflow-hidden bg-background -mt-16 pt-0 pb-32" className="relative w-full flex items-center justify-center overflow-hidden bg-background -mt-16 pt-0 pb-32"
onMouseEnter={() => setHovering(true)} onMouseEnter={() => setHovering(true)}
onMouseLeave={() => setHovering(false)} onMouseLeave={() => setHovering(false)}
@@ -180,7 +188,7 @@ export function ClickableGallery() {
</div> </div>
</div> </div>
</div> </div>
</section> </motion.section>
</> </div>
) )
} }

View File

@@ -1,4 +1,8 @@
'use client'
import { Container } from '@/components/Container' import { Container } from '@/components/Container'
import { motion, useInView } from 'framer-motion'
import { useRef } from 'react'
const faqs = [ const faqs = [
[ [
@@ -22,7 +26,7 @@ const faqs = [
{ {
question: 'How can I find and use my Mycelium address?', question: 'How can I find and use my Mycelium address?',
answer: answer:
'Upon using the Mycelium app, you\'re assigned a unique Mycelium address. To copy this address, click the button located to the right of the displayed address in the app interface.', "Upon using the Mycelium app, you're assigned a unique Mycelium address. To copy this address, click the button located to the right of the displayed address in the app interface.",
}, },
{ {
question: 'Can I deploy workloads on the TFGrid using Mycelium?', question: 'Can I deploy workloads on the TFGrid using Mycelium?',
@@ -50,17 +54,41 @@ const faqs = [
] ]
export function Faqs() { export function Faqs() {
const ref = useRef(null);
const isInView = useInView(ref, { once: true });
return ( return (
<section <section
id="faqs" id="faqs"
ref={ref}
aria-labelledby="faqs-title" aria-labelledby="faqs-title"
className="border-t border-gray-200 py-20 sm:py-32" className="border-t border-gray-200 py-20 sm:py-32 relative overflow-hidden"
> >
<motion.div
initial={{ opacity: 0 }}
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
transition={{ duration: 1, delay: 0.1 }}
aria-hidden="true"
className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
>
<div
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
className="relative left-[calc(50%-30rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#93c5fd] to-[#9089fc] opacity-30 sm:left-[calc(50%-36rem)] sm:w-[72.1875rem]"
/>
</motion.div>
<Container> <Container>
<div className="mx-auto max-w-2xl lg:mx-0"> <motion.div
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
transition={{ duration: 0.8, delay: 0.2 }}
className="mx-auto max-w-2xl lg:mx-0"
>
<h2 <h2
id="faqs-title" id="faqs-title"
className="text-3xl font-medium tracking-tight text-gray-900" className="text-3xl font-medium tracking-tight text-[#2F3178]"
> >
Frequently asked questions Frequently asked questions
</h2> </h2>
@@ -74,26 +102,34 @@ export function Faqs() {
</a> </a>
. .
</p> </p>
</div> </motion.div>
<ul <motion.ul
role="list" role="list"
initial={{ opacity: 0 }}
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
transition={{ duration: 0.5, delay: 0.3, staggerChildren: 0.2 }}
className="mx-auto mt-16 grid max-w-2xl grid-cols-1 gap-8 sm:mt-20 lg:max-w-none lg:grid-cols-3" className="mx-auto mt-16 grid max-w-2xl grid-cols-1 gap-8 sm:mt-20 lg:max-w-none lg:grid-cols-3"
> >
{faqs.map((column, columnIndex) => ( {faqs.map((column, columnIndex) => (
<li key={columnIndex}> <motion.li
key={columnIndex}
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
transition={{ duration: 0.5, delay: 0.4 + columnIndex * 0.2 }}
>
<ul role="list" className="space-y-10"> <ul role="list" className="space-y-10">
{column.map((faq, faqIndex) => ( {column.map((faq, faqIndex) => (
<li key={faqIndex}> <li key={faqIndex}>
<h3 className="text-lg/6 font-semibold text-gray-900"> <h3 className="text-lg/6 font-semibold text-[#2F3178]">
{faq.question} {faq.question}
</h3> </h3>
<p className="mt-4 text-sm text-gray-700">{faq.answer}</p> <p className="mt-4 text-sm text-gray-700">{faq.answer}</p>
</li> </li>
))} ))}
</ul> </ul>
</li> </motion.li>
))} ))}
</ul> </motion.ul>
</Container> </Container>
</section> </section>
) )

View File

@@ -1,7 +1,7 @@
'use client' 'use client'
import { useState } from 'react' import { useState, useRef } from 'react'
import { motion } from 'framer-motion' import { motion, useInView } from 'framer-motion'
import { TypeAnimation } from 'react-type-animation' import { TypeAnimation } from 'react-type-animation'
import { Dialog, DialogPanel } from '@headlessui/react' import { Dialog, DialogPanel } from '@headlessui/react'
import { Bars3Icon, XMarkIcon, ChevronDoubleDownIcon } from '@heroicons/react/24/outline' import { Bars3Icon, XMarkIcon, ChevronDoubleDownIcon } from '@heroicons/react/24/outline'
@@ -37,51 +37,73 @@ const features = [
]; ];
export function HomeAbout() { export function HomeAbout() {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false) const ref = useRef(null);
const isInView = useInView(ref, { once: true });
return ( return (
<div id="about" className="relative h-screen"> <div id="about" ref={ref} className="relative h-screen">
<div className="relative isolate px-6 lg:px-8"> <div className="relative isolate px-6 lg:px-8">
<div className="relative -top-10 mx-auto max-w-8xl h-screen flex items-center justify-center"> <div className="relative -top-10 mx-auto max-w-8xl h-screen flex items-center justify-center">
<motion.div <motion.div
initial={{ opacity: 0 }} initial={{ opacity: 0 }}
animate={{ opacity: 1 }} animate={isInView ? { opacity: 1 } : { opacity: 0 }}
transition={{ duration: 2, delay: 0.5 }} transition={{ duration: 2, delay: 0.5 }}
aria-hidden="true" aria-hidden="true"
className="absolute top-10 left-[calc(50%-4rem)] -z-10 transform-gpu blur-3xl sm:left-[calc(50%-18rem)] lg:top-[calc(50%-30rem)] lg:left-48 xl:left-[calc(50%-24rem)]" className="absolute top-10 left-[calc(50%-4rem)] -z-10 transform-gpu blur-3xl sm:left-[calc(50%-18rem)] lg:top-[calc(50%-30rem)] lg:left-48 xl:left-[calc(50%-24rem)]"
> >
<div <div
style={{ style={{
clipPath: clipPath:
'polygon(73.6% 51.7%, 91.7% 11.8%, 100% 46.4%, 97.4% 82.2%, 92.5% 84.9%, 75.7% 64%, 55.3% 47.5%, 46.5% 49.4%, 45% 62.9%, 50.3% 87.2%, 21.3% 64.1%, 0.1% 100%, 5.4% 51.1%, 21.4% 63.9%, 58.9% 0.2%, 73.6% 51.7%)', 'polygon(73.6% 51.7%, 91.7% 11.8%, 100% 46.4%, 97.4% 82.2%, 92.5% 84.9%, 75.7% 64%, 55.3% 47.5%, 46.5% 49.4%, 45% 62.9%, 50.3% 87.2%, 21.3% 64.1%, 0.1% 100%, 5.4% 51.1%, 21.4% 63.9%, 58.9% 0.2%, 73.6% 51.7%)',
}} }}
className="aspect-1108/632 w-277 bg-linear-to-r from-[#80caff] to-[#4f46e5] opacity-20" className="aspect-1108/632 w-277 bg-linear-to-r from-[#80caff] to-[#4f46e5] opacity-20"
/> />
</motion.div> </motion.div>
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 1, delay: 1 }} className="absolute top-24 left-0 max-w-xl text-left"> <motion.div
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
transition={{ duration: 1, delay: 0.2 }}
className="absolute top-24 left-0 max-w-xl text-left"
>
<H2> <H2>
Enterprise AI Agents Enterprise AI Agents
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-54 left-0 max-w-xl text-left"> <motion.div
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
transition={{ duration: 1, delay: 0.4 }}
className="absolute top-54 left-0 max-w-xl text-left"
>
<P color="custom"> <P color="custom">
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. 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>
<Candy /> <motion.div
initial={{ opacity: 0 }}
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
transition={{ duration: 1, delay: 0.6 }}
>
<Candy />
</motion.div>
<div className="absolute bottom-24 right-0 h-96 w-full md:w-2/3 overflow-hidden"> <motion.div
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
transition={{ duration: 1, delay: 0.8 }}
className="absolute bottom-24 right-0 h-96 w-full md:w-2/3 overflow-hidden"
>
<div className="animate-marquee-vertical space-y-8 text-right"> <div className="animate-marquee-vertical space-y-8 text-right">
{[...features, ...features].map((feature, index) => ( {[...features, ...features].map((feature, index) => (
<div key={index} className="flex items-center justify-end gap-x-4" aria-hidden={index >= features.length}> <div key={index} className="flex items-center justify-end gap-x-4" aria-hidden={index >= features.length}>
<Image src={diamondSvg} alt="" className="h-6 w-6" /> <Image src={diamondSvg} alt="" className="h-6 w-6" />
<H3 as="p">{feature}</H3> <H3>{feature}</H3>
</div> </div>
))} ))}
</div> </div>
</div> </motion.div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -19,7 +19,12 @@ export function HomeHero() {
return ( return (
<div className="relative h-screen -top-15"> <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"> <motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 2 }}
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
loop loop
@@ -29,7 +34,7 @@ export function HomeHero() {
> >
<source src="/videos/mycelium.mp4" type="video/mp4" /> <source src="/videos/mycelium.mp4" type="video/mp4" />
</video> </video>
</div> </motion.div>
<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"
@@ -40,7 +45,7 @@ export function HomeHero() {
clipPath: clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)', 'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}} }}
className="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#93c5fd] to-[#9089fc] opacity-25 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]" className="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#a4caf6] to-[#aaa4fa] opacity-15 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]"
/> />
</div> </div>
<div <div
@@ -52,7 +57,7 @@ export function HomeHero() {
clipPath: clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)', 'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}} }}
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-15 sm:left-[calc(50%+30rem)] sm:w-[72.1875rem]"
/> />
</div> </div>
<div className="relative -top-15 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">

View File

@@ -13,8 +13,18 @@ export function StackSectionPreview() {
return ( return (
<section ref={ref} className="w-full h-screen bg-transparent lg:px-0 pt-24 pb-12 px-6 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" /> <motion.div
<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" /> initial={{ opacity: 0 }}
animate={isInView ? { opacity: 0.4 } : { opacity: 0 }}
transition={{ duration: 1, delay: 0.1 }}
className="absolute w-[400px] h-[200px] bg-gradient-to-br from-[#505050] to-[#7e7e7e] rounded-full blur-[150px] bottom-[200px] left-[-150px] z-0"
/>
<motion.div
initial={{ opacity: 0 }}
animate={isInView ? { opacity: 0.5 } : { opacity: 0 }}
transition={{ duration: 1, delay: 0.15 }}
className="absolute w-[200px] h-[100px] bg-gradient-to-br from-[#505050] to-[#7e7e7e] rounded-full blur-[150px] top-[200px] right-[-150px] z-0"
/>
<div className="mx-auto max-w-7xl"> <div className="mx-auto max-w-7xl">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4 lg:gap-16 items-center lg:items-start"> <div className="grid grid-cols-1 lg:grid-cols-3 gap-4 lg:gap-16 items-center lg:items-start">
{/* Left Column - Text (1/3 width) */} {/* Left Column - Text (1/3 width) */}

View File

@@ -1,16 +1,10 @@
'use client' 'use client'
import React, { useEffect, useMemo, useRef, useState } from 'react' import React, { useRef } from 'react'
import clsx from 'clsx' import { motion, useInView } from 'framer-motion'
import { useInView } from 'framer-motion'
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' import { TbCircleNumber1Filled, TbCircleNumber2Filled, TbCircleNumber3Filled } from 'react-icons/tb'
const features = [ const features = [
{ {
name: 'Choose Your Intelligence', name: 'Choose Your Intelligence',
@@ -32,29 +26,45 @@ const features = [
] ]
export function Steps() { export function Steps() {
const ref = useRef(null);
const isInView = useInView(ref, { once: true });
return ( return (
<section id="benefits" className="bg-white pt-0 pb-24 dark:bg-gray-900"> <section id="benefits" ref={ref} className="bg-white pt-0 pb-24 dark:bg-gray-900">
<div className="mx-auto max-w-7xl px-6 lg:px-0"> <div className="mx-auto max-w-7xl px-6 lg:px-0">
<div className="mx-auto max-w-5xl lg:mx-0"> <motion.div
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
transition={{ duration: 0.8, delay: 0.1 }}
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 LLMs and AI Agents in Seconds Deploy Scalable LLMs and AI Agents in Seconds
</H2> </H2>
<P className="mt-6 text-lg" color="custom"> <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> </motion.div>
<ul className="mx-auto mt-16 grid max-w-2xl grid-cols-1 gap-x-8 gap-y-16 text-base/7 sm:grid-cols-2 lg:mx-0 lg:max-w-none lg:grid-cols-3"> <motion.ul
{features.map((feature) => ( initial={{ opacity: 0 }}
<li animate={isInView ? { opacity: 1 } : { opacity: 0 }}
transition={{ duration: 0.5, delay: 0.2, staggerChildren: 0.2 }}
className="mx-auto mt-16 grid max-w-2xl grid-cols-1 gap-x-8 gap-y-16 text-base/7 sm:grid-cols-2 lg:mx-0 lg:max-w-none lg:grid-cols-3"
>
{features.map((feature, index) => (
<motion.li
key={feature.name} key={feature.name}
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
transition={{ duration: 0.5, delay: 0.3 + index * 0.2 }}
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"
> >
<feature.icon className="h-8 w-8 mb-4 text-[#2F3178]" /> <feature.icon className="h-8 w-8 mb-4 text-[#2F3178]" />
<CT as="span" className="font-semibold">{feature.name}</CT> <CT as="span" className="font-semibold">{feature.name}</CT>
<CP className="mt-2 text-sm" color="custom">{feature.description}</CP> <CP className="mt-2 text-sm" color="custom">{feature.description}</CP>
</li> </motion.li>
))} ))}
</ul> </motion.ul>
</div> </div>
</section> </section>
) )

View File

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

View File

@@ -2,7 +2,6 @@
import React, { useEffect, useMemo, useRef, useState } from 'react' import React, { useEffect, useMemo, useRef, useState } from 'react'
import clsx from 'clsx' import clsx from 'clsx'
import { useInView } from 'framer-motion'
import { import {
ArchiveBoxIcon, ArchiveBoxIcon,
CodeBracketIcon, CodeBracketIcon,
@@ -16,6 +15,7 @@ import {
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 { motion, useInView } from 'framer-motion'
interface Review { interface Review {
title: string title: string
@@ -94,7 +94,7 @@ function Review({
> >
<blockquote className="text-gray-900"> <blockquote className="text-gray-900">
{React.createElement(getReviewIcon(title), { className: "h-6 w-6 text-[#2F3178] mb-2" })} {React.createElement(getReviewIcon(title), { className: "h-6 w-6 text-[#2F3178] mb-2" })}
<CT as="h3" color="primary" className="mt-4 text-lg/6 font-semibold"> <CT color="primary" className="mt-4 text-lg/6 font-semibold">
{title} {title}
</CT> </CT>
<CP color="custom" className="mt-3 text-sm">{body}</CP> <CP color="custom" className="mt-3 text-sm">{body}</CP>
@@ -213,14 +213,23 @@ function ReviewGrid() {
} }
export function UseCases() { export function UseCases() {
const ref = useRef(null);
const isInView = useInView(ref, { once: true });
return ( return (
<section <section
id="usecases" id="usecases"
ref={ref}
aria-labelledby="usecases-title" aria-labelledby="usecases-title"
className="py-12" className="py-12"
> >
<Container className=''> <Container className=''>
<div className="mx-auto max-w-2xl lg:max-w-5xl"> <motion.div
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
transition={{ duration: 0.8, delay: 0.1 }}
className="mx-auto max-w-2xl lg:max-w-5xl"
>
<H2 <H2
id="usecases-title" id="usecases-title"
color="primary" color="primary"
@@ -231,7 +240,22 @@ export function UseCases() {
<P className="mt-6 text-center" color="custom"> <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> </motion.div>
<motion.div
initial={{ opacity: 0 }}
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
transition={{ duration: 1, delay: 0.2 }}
aria-hidden="true"
className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
>
<div
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
className="relative left-[calc(50%-30rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#93c5fd] to-[#9089fc] opacity-30 sm:left-[calc(50%-36rem)] sm:w-[72.1875rem]"
/>
</motion.div>
<ReviewGrid /> <ReviewGrid />
</Container> </Container>
</section> </section>

View File