ok
This commit is contained in:
374
src/components/UseCases.tsx
Normal file
374
src/components/UseCases.tsx
Normal file
@@ -0,0 +1,374 @@
|
||||
'use client'
|
||||
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import clsx from 'clsx'
|
||||
import { useInView } from 'framer-motion'
|
||||
import {
|
||||
ArchiveBoxIcon,
|
||||
ChatBubbleBottomCenterIcon,
|
||||
CloudIcon,
|
||||
CodeBracketIcon,
|
||||
ComputerDesktopIcon,
|
||||
CpuChipIcon,
|
||||
DocumentIcon,
|
||||
EnvelopeIcon,
|
||||
GlobeAltIcon,
|
||||
GlobeAmericasIcon,
|
||||
PlayCircleIcon,
|
||||
ShareIcon,
|
||||
EyeSlashIcon,
|
||||
UserGroupIcon,
|
||||
VideoCameraIcon,
|
||||
} from '@heroicons/react/24/solid'
|
||||
|
||||
import { Container } from '@/components/Container'
|
||||
|
||||
interface Review {
|
||||
title: string
|
||||
body: string
|
||||
author: string
|
||||
rating: 1 | 2 | 3 | 4 | 5
|
||||
}
|
||||
|
||||
const reviews: Array<Review> = [
|
||||
{
|
||||
title: 'Secure remote work collaboration.',
|
||||
body: 'Mycelium provides a secure, encrypted network for a wide range of use cases, from private communication to decentralized infrastructure.',
|
||||
author: 'CrazyInvestor',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Private file sharing between trusted nodes.',
|
||||
body: 'Mycelium enables private file sharing between trusted nodes, ensuring that sensitive information remains confidential and secure.',
|
||||
author: 'CluelessButRich',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Encrypted voice/video calls.',
|
||||
body: 'Mycelium enables secure voice and video calls between users, ensuring that conversations remain private and protected from eavesdropping.',
|
||||
author: 'LivingDaDream',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Self-hosted messaging systems.',
|
||||
body: 'Mycelium allows users to create their own self-hosted messaging systems, ensuring complete control over their communications.',
|
||||
author: 'JordanBelfort1962',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Secure document collaboration.',
|
||||
body: 'Mycelium enables secure document collaboration between users, ensuring that sensitive information remains confidential and protected.',
|
||||
author: 'MrBurns',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Private cloud computing resources.',
|
||||
body: 'Mycelium provides private cloud computing resources, allowing users to run their applications in a secure and isolated environment.',
|
||||
author: 'LazyRich99',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Secure IoT device networks.',
|
||||
body: 'Mycelium provides secure IoT device networks, ensuring that all connected devices can communicate privately and securely.',
|
||||
author: 'SarahLuvzCash',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Remote system administration.',
|
||||
body: 'Mycelium enables secure remote system administration, allowing users to manage their systems from anywhere without compromising security.',
|
||||
author: 'ScroogeMcduck',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Virtual private networks (VPNs).',
|
||||
body: 'Mycelium enables the creation of virtual private networks (VPNs), allowing users to securely connect to remote networks and access resources without compromising their privacy.',
|
||||
author: 'BruceWayne',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Secure backup systems.',
|
||||
body: 'Mycelium provides secure backup systems, ensuring that users can easily and safely back up their important data without the risk of unauthorized access.',
|
||||
author: 'RichieRich',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Self-hosted web services.',
|
||||
body: 'Mycelium allows users to create their own self-hosted web services, ensuring complete control over their data and applications.',
|
||||
author: 'TheCountOfMonteChristo',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Private file sharing between trusted nodes.',
|
||||
body: 'Mycelium enables private file sharing between trusted nodes, ensuring that sensitive information remains confidential and secure.',
|
||||
author: 'ClarkKent',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Private DNS systems.',
|
||||
body: 'Mycelium enables the creation of private DNS systems, allowing users to maintain control over their domain name resolution and protect their privacy.',
|
||||
author: 'GeorgeCostanza',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Personal email servers.',
|
||||
body: 'Mycelium allows users to create their own personal email servers, ensuring complete control over their communications and data.',
|
||||
author: 'JeffBezos',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Secure document collaboration.',
|
||||
body: 'Mycelium enables secure document collaboration between users, ensuring that sensitive information remains confidential and protected.',
|
||||
author: 'JeffBezos',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Private media streaming.',
|
||||
body: 'Mycelium enables private media streaming between users, ensuring that sensitive content remains confidential and protected.',
|
||||
author: 'JeffBezos',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Personal cloud storage.',
|
||||
body: 'Mycelium allows users to create their own personal cloud storage solutions, ensuring complete control over their data and privacy.',
|
||||
author: 'JeffBezos',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Personal email servers.',
|
||||
body: 'Mycelium allows users to create their own personal email servers, ensuring complete control over their communications and data.',
|
||||
author: 'JeffBezos',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Protected content distribution.',
|
||||
body: 'Mycelium enables protected content distribution, allowing users to securely share and distribute sensitive information without compromising its confidentiality.',
|
||||
author: 'JeffBezos',
|
||||
rating: 5,
|
||||
},
|
||||
{
|
||||
title: 'Secure game servers.',
|
||||
body: 'Mycelium enables the creation of secure game servers, allowing users to host and manage their own gaming environments with complete control over their data and privacy.',
|
||||
author: 'JeffBezos',
|
||||
rating: 5,
|
||||
}, {
|
||||
title: 'Private git repositories.',
|
||||
body: 'Mycelium enables the creation of private git repositories, allowing users to host and manage their own version control systems with complete control over their data and privacy.',
|
||||
author: 'JeffBezos',
|
||||
rating: 5,
|
||||
},
|
||||
]
|
||||
|
||||
function StarIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
||||
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function StarRating({ rating }: { rating: Review['rating'] }) {
|
||||
return (
|
||||
<div className="flex">
|
||||
{[...Array(5).keys()].map((index) => (
|
||||
<StarIcon
|
||||
key={index}
|
||||
className={clsx(
|
||||
'h-5 w-5',
|
||||
rating > index ? 'fill-cyan-500' : 'fill-gray-300',
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function getReviewIcon(title: string) {
|
||||
if (title.toLowerCase().includes('collaboration')) return UserGroupIcon;
|
||||
if (title.toLowerCase().includes('file sharing')) return ShareIcon;
|
||||
if (title.toLowerCase().includes('voice') || title.toLowerCase().includes('video')) return VideoCameraIcon;
|
||||
if (title.toLowerCase().includes('messaging')) return ChatBubbleBottomCenterIcon;
|
||||
if (title.toLowerCase().includes('document')) return DocumentIcon;
|
||||
if (title.toLowerCase().includes('cloud')) return CloudIcon;
|
||||
if (title.toLowerCase().includes('iot')) return CpuChipIcon;
|
||||
if (title.toLowerCase().includes('administration')) return ComputerDesktopIcon;
|
||||
if (title.toLowerCase().includes('vpn')) return GlobeAmericasIcon;
|
||||
if (title.toLowerCase().includes('backup')) return ArchiveBoxIcon;
|
||||
if (title.toLowerCase().includes('web services')) return GlobeAltIcon;
|
||||
if (title.toLowerCase().includes('dns')) return GlobeAmericasIcon;
|
||||
if (title.toLowerCase().includes('email')) return EnvelopeIcon;
|
||||
if (title.toLowerCase().includes('media streaming') || title.toLowerCase().includes('streaming')) return PlayCircleIcon;
|
||||
if (title.toLowerCase().includes('storage')) return CloudIcon;
|
||||
if (title.toLowerCase().includes('distribution')) return EyeSlashIcon;
|
||||
if (title.toLowerCase().includes('game')) return ComputerDesktopIcon;
|
||||
if (title.toLowerCase().includes('git')) return CodeBracketIcon;
|
||||
return ComputerDesktopIcon; // default
|
||||
}
|
||||
|
||||
function Review({
|
||||
title,
|
||||
body,
|
||||
author,
|
||||
rating,
|
||||
className,
|
||||
...props
|
||||
}: Omit<React.ComponentPropsWithoutRef<'figure'>, keyof Review> & Review) {
|
||||
let animationDelay = useMemo(() => {
|
||||
let possibleAnimationDelays = ['0s', '0.1s', '0.2s', '0.3s', '0.4s', '0.5s']
|
||||
return possibleAnimationDelays[
|
||||
Math.floor(Math.random() * possibleAnimationDelays.length)
|
||||
]
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<figure
|
||||
className={clsx(
|
||||
'animate-fade-in rounded-3xl bg-white p-6 opacity-0 shadow-md shadow-gray-900/5',
|
||||
className,
|
||||
)}
|
||||
style={{ animationDelay }}
|
||||
{...props}
|
||||
>
|
||||
<blockquote className="text-gray-900">
|
||||
{React.createElement(getReviewIcon(title), { className: "h-6 w-6 text-gray-700 mb-2" })}
|
||||
<p className="mt-4 text-lg/6 font-semibold">
|
||||
{title}
|
||||
</p>
|
||||
<p className="mt-3 text-sm text-gray-600">{body}</p>
|
||||
</blockquote>
|
||||
|
||||
</figure>
|
||||
)
|
||||
}
|
||||
|
||||
function splitArray<T>(array: Array<T>, numParts: number) {
|
||||
let result: Array<Array<T>> = []
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
let index = i % numParts
|
||||
if (!result[index]) {
|
||||
result[index] = []
|
||||
}
|
||||
result[index].push(array[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function ReviewColumn({
|
||||
reviews,
|
||||
className,
|
||||
reviewClassName,
|
||||
msPerPixel = 0,
|
||||
}: {
|
||||
reviews: Array<Review>
|
||||
className?: string
|
||||
reviewClassName?: (reviewIndex: number) => string
|
||||
msPerPixel?: number
|
||||
}) {
|
||||
let columnRef = useRef<React.ElementRef<'div'>>(null)
|
||||
let [columnHeight, setColumnHeight] = useState(0)
|
||||
let duration = `${columnHeight * msPerPixel}ms`
|
||||
|
||||
useEffect(() => {
|
||||
if (!columnRef.current) {
|
||||
return
|
||||
}
|
||||
|
||||
let resizeObserver = new window.ResizeObserver(() => {
|
||||
setColumnHeight(columnRef.current?.offsetHeight ?? 0)
|
||||
})
|
||||
|
||||
resizeObserver.observe(columnRef.current)
|
||||
|
||||
return () => {
|
||||
resizeObserver.disconnect()
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={columnRef}
|
||||
className={clsx('animate-marquee space-y-8 py-4', className)}
|
||||
style={{ '--marquee-duration': duration } as React.CSSProperties}
|
||||
>
|
||||
{reviews.concat(reviews).map((review, reviewIndex) => (
|
||||
<Review
|
||||
key={reviewIndex}
|
||||
aria-hidden={reviewIndex >= reviews.length}
|
||||
className={reviewClassName?.(reviewIndex % reviews.length)}
|
||||
{...review}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function ReviewGrid() {
|
||||
let containerRef = useRef<React.ElementRef<'div'>>(null)
|
||||
let isInView = useInView(containerRef, { once: true, amount: 0.4 })
|
||||
let columns = splitArray(reviews, 3)
|
||||
let column1 = columns[0]
|
||||
let column2 = columns[1]
|
||||
let column3 = splitArray(columns[2], 2)
|
||||
|
||||
return (
|
||||
<div
|
||||
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"
|
||||
>
|
||||
{isInView && (
|
||||
<>
|
||||
<ReviewColumn
|
||||
reviews={[...column1, ...column3.flat(), ...column2]}
|
||||
reviewClassName={(reviewIndex) =>
|
||||
clsx(
|
||||
reviewIndex >= column1.length + column3[0].length &&
|
||||
'md:hidden',
|
||||
reviewIndex >= column1.length && 'lg:hidden',
|
||||
)
|
||||
}
|
||||
msPerPixel={10}
|
||||
/>
|
||||
<ReviewColumn
|
||||
reviews={[...column2, ...column3[1]]}
|
||||
className="hidden md:block"
|
||||
reviewClassName={(reviewIndex) =>
|
||||
reviewIndex >= column2.length ? 'lg:hidden' : ''
|
||||
}
|
||||
msPerPixel={15}
|
||||
/>
|
||||
<ReviewColumn
|
||||
reviews={column3.flat()}
|
||||
className="hidden lg:block"
|
||||
msPerPixel={10}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<div className="pointer-events-none absolute inset-x-0 top-0 h-32 bg-linear-to-b from-gray-50" />
|
||||
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-32 bg-linear-to-t from-gray-50" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function UseCases() {
|
||||
return (
|
||||
<section
|
||||
id="usecases"
|
||||
aria-labelledby="usecases-title"
|
||||
className="pt-20 pb-16 sm:pt-32 sm:pb-24"
|
||||
>
|
||||
<Container className=''>
|
||||
<div className="mx-auto max-w-2xl lg:max-w-5xl">
|
||||
<h2
|
||||
id="usecases-title"
|
||||
className="text-3xl font-medium tracking-tight text-gray-900 sm:text-center"
|
||||
>
|
||||
Powering Secure & Decentralized Connectivity
|
||||
</h2>
|
||||
<p className="mt-6 text-lg text-gray-600 sm:text-center">
|
||||
The ThreeFold Dashboard offers dozens of applications with built-in Mycelium support, making it easy to deploy and utilize. Once installed, Mycelium provides a secure, encrypted network for a wide range of use cases, from private communication to decentralized infrastructure.
|
||||
</p>
|
||||
</div>
|
||||
<ReviewGrid />
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
Reference in New Issue
Block a user