'use client' import { Fragment, useEffect, useId, useRef, useState } from 'react' import { Tab, TabGroup, TabList, TabPanel, TabPanels } from '@headlessui/react' import clsx from 'clsx' import { type MotionProps, type Variant, type Variants, AnimatePresence, motion, } from 'framer-motion' import { useDebouncedCallback } from 'use-debounce' import { AppScreen } from '@/components/AppScreen' import { CircleBackground } from '@/components/CircleBackground' import { Container } from '@/components/Container' import Image from 'next/image' import { PhoneFrame } from '@/components/PhoneFrame' import { DiageoLogo, LaravelLogo, MirageLogo, ReversableLogo, StatamicLogo, StaticKitLogo, TransistorLogo, TupleLogo, } from '@/components/StockLogos' const MotionAppScreenHeader = motion(AppScreen.Header) const MotionAppScreenBody = motion(AppScreen.Body) interface CustomAnimationProps { isForwards: boolean changeCount: number } const features = [ { name: 'Mycelium Connector', description: "Start (and stop) your Mycelium connector to gain access to sites, apps, and workloads available exclusively on the Mycelium Network. View statistics around peers and traffic.", icon: DeviceUserIcon, screen: InviteScreen, }, { name: 'Mycelium Peers', description: 'Search and discover active peers on the Mycelium Network, or add your own.', icon: DeviceNotificationIcon, screen: StocksScreen, }, { name: 'Network Setting', description: 'Find version and network information and trigger light or dark mode.', icon: DeviceTouchIcon, screen: InvestScreen, }, ] function DeviceUserIcon(props: React.ComponentPropsWithoutRef<'svg'>) { return ( ) } function DeviceNotificationIcon(props: React.ComponentPropsWithoutRef<'svg'>) { return ( ) } function DeviceTouchIcon(props: React.ComponentPropsWithoutRef<'svg'>) { let id = useId() return ( ) } const headerAnimation: Variants = { initial: { opacity: 0, transition: { duration: 0.3 } }, animate: { opacity: 1, transition: { duration: 0.3, delay: 0.3 } }, exit: { opacity: 0, transition: { duration: 0.3 } }, } const maxZIndex = 2147483647 const bodyVariantBackwards: Variant = { opacity: 0.4, scale: 0.8, zIndex: 0, filter: 'blur(4px)', transition: { duration: 0.4 }, } const bodyVariantForwards: Variant = (custom: CustomAnimationProps) => ({ y: '100%', zIndex: maxZIndex - custom.changeCount, transition: { duration: 0.4 }, }) const bodyAnimation: MotionProps = { initial: 'initial', animate: 'animate', exit: 'exit', variants: { initial: (custom: CustomAnimationProps, ...props) => custom.isForwards ? bodyVariantForwards(custom, ...props) : bodyVariantBackwards, animate: (custom: CustomAnimationProps) => ({ y: '0%', opacity: 1, scale: 1, zIndex: maxZIndex / 2 - custom.changeCount, filter: 'blur(0px)', transition: { duration: 0.4 }, }), exit: (custom: CustomAnimationProps, ...props) => custom.isForwards ? bodyVariantBackwards : bodyVariantForwards(custom, ...props), }, } type ScreenProps = | { animated: true custom: CustomAnimationProps } | { animated?: false } function InviteScreen(props: ScreenProps) { return ( Mycelium Connector ) } function StocksScreen(props: ScreenProps) { return ( Mycelium Peers ) } function InvestScreen(props: ScreenProps) { return ( Mycelium Settings ) } function usePrevious(value: T) { let ref = useRef() useEffect(() => { ref.current = value }, [value]) return ref.current } function FeaturesDesktop() { let [changeCount, setChangeCount] = useState(0) let [selectedIndex, setSelectedIndex] = useState(0) let prevIndex = usePrevious(selectedIndex) let isForwards = prevIndex === undefined ? true : selectedIndex > prevIndex let onChange = useDebouncedCallback( (selectedIndex) => { setSelectedIndex(selectedIndex) setChangeCount((changeCount) => changeCount + 1) }, 100, { leading: true }, ) return ( {features.map((feature, featureIndex) => (
{featureIndex === selectedIndex && ( )}

{feature.name}

{feature.description}

))}
{features.map((feature, featureIndex) => selectedIndex === featureIndex ? ( ) : null, )}
) } function FeaturesMobile() { let [activeIndex, setActiveIndex] = useState(0) let slideContainerRef = useRef>(null) let slideRefs = useRef>>([]) useEffect(() => { let observer = new window.IntersectionObserver( (entries) => { for (let entry of entries) { if (entry.isIntersecting && entry.target instanceof HTMLDivElement) { setActiveIndex(slideRefs.current.indexOf(entry.target)) break } } }, { root: slideContainerRef.current, threshold: 0.6, }, ) for (let slide of slideRefs.current) { if (slide) { observer.observe(slide) } } return () => { observer.disconnect() } }, [slideContainerRef, slideRefs]) return ( <>
{features.map((feature, featureIndex) => (
ref && (slideRefs.current[featureIndex] = ref)} className="w-full flex-none snap-center px-4 sm:px-6 transition-all duration-300 ease-in-out hover:scale-105" >

{feature.name}

{feature.description}

))}
{features.map((_, featureIndex) => ( ))}
) } export function PrimaryFeatures() { return (

How It Works

How Mycelium Operates

Mycelium, like its natural namesake, thrives on decentralization, efficiency, and security, making it a truly powerful force in the world of decentralized networks.

) }