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() {
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-3xl font-semibold tracking-tight leading-tight text-white lg:text-5xl">
Say Hello to Decentralized AI Agents that are Truly Yours
</h2>
<p className="mx-auto mt-6 mb-4 max-w-xl text-base font-light text-pretty text-white lg:text-lg">
import { H2, P } from '@/components/Texts'
export function CallTo() {
return (
<div className="relative isolate overflow-hidden max-w-5xl mx-auto py-24">
<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">
<div className="mx-auto max-w-4xl text-center">
<H2 color="primary">
Say hello to Decentralized AI Agents that are Truly Yours
</H2>
<P color="custom" className="mt-8 max-w-3xl">
Why hand out your intelligence to centralized giants when you can build your own?
</p>
<p className="mx-auto max-w-xl text-base font-light text-pretty text-white lg:text-lg">
With Project Myceliums Decentralized Agentic Cloud, youre not just adopting AIyoure claiming your own sovereign, autonomous AI infrastructure that grows and evolves with you.
</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-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)]"
</P>
<div className="mt-10 flex items-center justify-center gap-x-6">
<a
href="#"
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]"
>
<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>
Book a Meeting
</a>
<a href="#" className="text-sm/6 font-semibold text-[#2F3178] hover:text-[#2F3178]/80">
Join the Waitlist <span aria-hidden="true"></span>
</a>
</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>
)
}

View File

@@ -1,8 +1,8 @@
'use client'
import { useEffect, useMemo, useState } from 'react'
import { useEffect, useMemo, useState, useRef } from 'react'
import Image from 'next/image'
import { motion, AnimatePresence } from 'framer-motion'
import { motion, AnimatePresence, useInView } from 'framer-motion'
import { wrap } from 'popmotion'
import { Button } from '@/components/Button';
import { H2, P, H4 } from '@/components/Texts';
@@ -34,6 +34,8 @@ const AUTOPLAY_MS = 3200
export function ClickableGallery() {
const [active, setActive] = useState(0)
const [hovering, setHovering] = useState(false)
const ref = useRef(null);
const isInView = useInView(ref, { once: true });
// autoplay
useEffect(() => {
@@ -51,17 +53,20 @@ export function ClickableGallery() {
const prev = () => setActive((i) => wrap(0, galleryItems.length, i - 1))
return (
<>
<div ref={ref}>
<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>
</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">
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>
</motion.div>
<div
<motion.div
initial={{ opacity: 0 }}
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
transition={{ duration: 1, delay: 0.3 }}
aria-hidden="true"
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]"
/>
</div>
</motion.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"
onMouseEnter={() => setHovering(true)}
onMouseLeave={() => setHovering(false)}
@@ -180,7 +188,7 @@ export function ClickableGallery() {
</div>
</div>
</div>
</section>
</>
</motion.section>
</div>
)
}

View File

@@ -1,4 +1,8 @@
'use client'
import { Container } from '@/components/Container'
import { motion, useInView } from 'framer-motion'
import { useRef } from 'react'
const faqs = [
[
@@ -22,7 +26,7 @@ const faqs = [
{
question: 'How can I find and use my Mycelium address?',
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?',
@@ -50,17 +54,41 @@ const faqs = [
]
export function Faqs() {
const ref = useRef(null);
const isInView = useInView(ref, { once: true });
return (
<section
id="faqs"
ref={ref}
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>
<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
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
</h2>
@@ -74,26 +102,34 @@ export function Faqs() {
</a>
.
</p>
</div>
<ul
</motion.div>
<motion.ul
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"
>
{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">
{column.map((faq, 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}
</h3>
<p className="mt-4 text-sm text-gray-700">{faq.answer}</p>
</li>
))}
</ul>
</li>
</motion.li>
))}
</ul>
</motion.ul>
</Container>
</section>
)

View File

@@ -1,7 +1,7 @@
'use client'
import { useState } from 'react'
import { motion } from 'framer-motion'
import { useState, useRef } from 'react'
import { motion, useInView } from 'framer-motion'
import { TypeAnimation } from 'react-type-animation'
import { Dialog, DialogPanel } from '@headlessui/react'
import { Bars3Icon, XMarkIcon, ChevronDoubleDownIcon } from '@heroicons/react/24/outline'
@@ -37,51 +37,73 @@ const features = [
];
export function HomeAbout() {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
const ref = useRef(null);
const isInView = useInView(ref, { once: true });
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 -top-10 mx-auto max-w-8xl h-screen flex items-center justify-center">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 2, delay: 0.5 }}
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)]"
>
<div
style={{
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%)',
}}
className="aspect-1108/632 w-277 bg-linear-to-r from-[#80caff] to-[#4f46e5] opacity-20"
/>
</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">
<div className="relative -top-10 mx-auto max-w-8xl h-screen flex items-center justify-center">
<motion.div
initial={{ opacity: 0 }}
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
transition={{ duration: 2, delay: 0.5 }}
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)]"
>
<div
style={{
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%)',
}}
className="aspect-1108/632 w-277 bg-linear-to-r from-[#80caff] to-[#4f46e5] opacity-20"
/>
</motion.div>
<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>
Enterprise AI Agents
That Never Sleep.
</H2>
</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">
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>
</motion.div>
<Candy />
<div className="absolute bottom-24 right-0 h-96 w-full md:w-2/3 overflow-hidden">
<motion.div
initial={{ opacity: 0 }}
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
transition={{ duration: 1, delay: 0.6 }}
>
<Candy />
</motion.div>
<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">
{[...features, ...features].map((feature, index) => (
<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" />
<H3 as="p">{feature}</H3>
<H3>{feature}</H3>
</div>
))}
</div>
</div>
</motion.div>
</div>
</div>
</div>

View File

@@ -19,7 +19,12 @@ export function HomeHero() {
return (
<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
autoPlay
loop
@@ -29,7 +34,7 @@ export function HomeHero() {
>
<source src="/videos/mycelium.mp4" type="video/mp4" />
</video>
</div>
</motion.div>
<div className="relative isolate px-6 lg:px-8">
<div
aria-hidden="true"
@@ -40,7 +45,7 @@ export function HomeHero() {
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%-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
@@ -52,7 +57,7 @@ export function HomeHero() {
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 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 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 (
<section ref={ref} className="w-full h-screen bg-transparent lg:px-0 pt-24 pb-12 px-6 relative">
{/* 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-[200px] h-[100px] bg-gradient-to-br from-[#505050] to-[#7e7e7e] opacity-50 rounded-full blur-[150px] top-[200px] right-[-150px] z-0" />
<motion.div
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="grid grid-cols-1 lg:grid-cols-3 gap-4 lg:gap-16 items-center lg:items-start">
{/* Left Column - Text (1/3 width) */}

View File

@@ -1,16 +1,10 @@
'use client'
import React, { useEffect, useMemo, useRef, useState } from 'react'
import clsx from 'clsx'
import { useInView } from 'framer-motion'
import { Container } from '@/components/Container'
import React, { useRef } from 'react'
import { motion, useInView } from 'framer-motion'
import { H2, P, CT, CP } from '@/components/Texts'
import { TbCircleNumber1Filled, TbCircleNumber2Filled, TbCircleNumber3Filled } from 'react-icons/tb'
const features = [
{
name: 'Choose Your Intelligence',
@@ -32,29 +26,45 @@ const features = [
]
export function Steps() {
const ref = useRef(null);
const isInView = useInView(ref, { once: true });
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-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">
Deploy Scalable LLMs and AI Agents in Seconds
</H2>
<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.
</P>
</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">
{features.map((feature) => (
<li
</motion.div>
<motion.ul
initial={{ opacity: 0 }}
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}
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"
>
<feature.icon className="h-8 w-8 mb-4 text-[#2F3178]" />
<CT as="span" className="font-semibold">{feature.name}</CT>
<CP className="mt-2 text-sm" color="custom">{feature.description}</CP>
</li>
</motion.li>
))}
</ul>
</motion.ul>
</div>
</section>
)

View File

@@ -1,48 +1,60 @@
import React from 'react';
import { cn } from '@/lib/utils';
'use client'
import React from 'react'
import { cn } from '@/lib/utils'
const colorVariants = {
primary: 'text-[#2F3178]',
secondary: 'text-gray-600',
custom: 'text-[#1c1c49]',
};
} as const
type TextProps<E extends React.ElementType> = {
as?: E;
children: React.ReactNode;
className?: string;
color?: keyof typeof colorVariants;
} & Omit<React.ComponentPropsWithoutRef<E>, 'as' | 'children' | 'className' | 'color'>;
type TextOwnProps = {
color?: keyof typeof colorVariants
className?: string
}
const createTextComponent = <E extends React.ElementType>(
defaultElement: E,
// Polymorphic helpers (no forwardRef needed)
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
) => {
const Component = React.forwardRef<React.ElementRef<E>, TextProps<E>>(
({ as, color = 'primary', className, children, ...props }, ref) => {
const Tag = as || defaultElement;
return (
<Tag
ref={ref}
className={cn(defaultClassName, colorVariants[color], className)}
{...props}
>
{children}
</Tag>
);
}
);
type Props<E extends React.ElementType = DefaultElement> =
PolymorphicProps<E, TextOwnProps>
Component.displayName = `Text(${defaultElement})`;
return Component;
};
function Text<E extends React.ElementType = DefaultElement>({
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');
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 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');
;(Text as any).displayName = `Text(${typeof defaultElement === 'string' ? defaultElement : 'Component'})`
return Text
}
// Exports
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 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')
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 clsx from 'clsx'
import { useInView } from 'framer-motion'
import {
ArchiveBoxIcon,
CodeBracketIcon,
@@ -16,6 +15,7 @@ import {
import { Container } from '@/components/Container'
import { H2, P, CT, CP } from '@/components/Texts'
import { motion, useInView } from 'framer-motion'
interface Review {
title: string
@@ -94,7 +94,7 @@ function Review({
>
<blockquote className="text-gray-900">
{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}
</CT>
<CP color="custom" className="mt-3 text-sm">{body}</CP>
@@ -213,14 +213,23 @@ function ReviewGrid() {
}
export function UseCases() {
const ref = useRef(null);
const isInView = useInView(ref, { once: true });
return (
<section
id="usecases"
ref={ref}
aria-labelledby="usecases-title"
className="py-12"
>
<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
id="usecases-title"
color="primary"
@@ -231,7 +240,22 @@ export function UseCases() {
<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.
</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 />
</Container>
</section>

View File