feat: redesign cloud features section with new UI and content
- Replaced mobile phone mockups with full-width desktop screenshots for cloud platform features - Updated feature descriptions to focus on cloud/Kubernetes capabilities instead of network features - Changed section layout to improve desktop view with left-aligned feature tabs - Removed unused phone frame component and related mobile UI elements - Updated image assets from jpg to png format and reorganized image paths - Reordered page
|
Before Width: | Height: | Size: 878 KiB After Width: | Height: | Size: 878 KiB |
BIN
public/images/cloud/billing.png
Normal file
|
After Width: | Height: | Size: 778 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
BIN
public/images/cloud/kubeconfig.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
BIN
public/images/cloud/reserve.png
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
@@ -11,7 +11,6 @@ import {
|
||||
} from 'framer-motion'
|
||||
import { useDebouncedCallback } from 'use-debounce'
|
||||
|
||||
import { AppScreen } from '../network/AppScreen'
|
||||
import {
|
||||
Eyebrow,
|
||||
FeatureDescription,
|
||||
@@ -23,10 +22,9 @@ import {
|
||||
import { CircleBackground } from '@/components/CircleBackground'
|
||||
import { Container } from '@/components/Container'
|
||||
|
||||
import connectorImg from '@/images/connector.png'
|
||||
import peersImg from '@/images/peers.png'
|
||||
import settingImg from '@/images/setting.png'
|
||||
import { PhoneFrame } from '@/components/PhoneFrame'
|
||||
import reservenodeimg from '/images/cloud/reserve.png'
|
||||
import billingImg from '/images/cloud/billing.png'
|
||||
import kubeconfigImg from '/images/cloud/kubeconfig.png'
|
||||
|
||||
|
||||
interface CustomAnimationProps {
|
||||
@@ -36,25 +34,25 @@ interface CustomAnimationProps {
|
||||
|
||||
const features = [
|
||||
{
|
||||
name: 'Mycelium Connector',
|
||||
name: 'Decentralized Kubernetes',
|
||||
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.",
|
||||
"Reserve a node and deploy sovereign Kubernetes clusters on decentralized infrastructure.",
|
||||
icon: DeviceUserIcon,
|
||||
screen: InviteScreen,
|
||||
screen: ReserveNodeScreen,
|
||||
},
|
||||
{
|
||||
name: 'Mycelium Peers',
|
||||
name: 'Manage Your Cluster',
|
||||
description:
|
||||
'Search and discover active peers on the Mycelium Network, or add your own.',
|
||||
'Manage your cluster with ease, with a simple and intuitive interface.',
|
||||
icon: DeviceNotificationIcon,
|
||||
screen: StocksScreen,
|
||||
screen: ManageClusterScreen,
|
||||
},
|
||||
{
|
||||
name: 'Network Setting',
|
||||
name: 'Personalised Billings & Accounts',
|
||||
description:
|
||||
'Find version and network information and trigger light or dark mode.',
|
||||
'Easily manage your cluster billing and accounts with personalised configurations.',
|
||||
icon: DeviceTouchIcon,
|
||||
screen: InvestScreen,
|
||||
screen: PersonalisedBillingsScreen,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -182,28 +180,40 @@ const bodyAnimation: MotionProps = {
|
||||
}
|
||||
|
||||
|
||||
function InviteScreen() {
|
||||
function ReserveNodeScreen() {
|
||||
return (
|
||||
<AppScreen className="w-full">
|
||||
<img src={connectorImg} alt="Mycelium Connector" width="366" height="732" className="-mt-8" />
|
||||
</AppScreen>
|
||||
)
|
||||
<img
|
||||
src={reservenodeimg}
|
||||
alt="Mycelium Reserve Node"
|
||||
width={2432}
|
||||
height={1442}
|
||||
className="w-4xl max-w-none rounded-xl shadow-xl ring-1 ring-gray-400/10 sm:w-240 md:-ml-4 lg:ml-0"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function StocksScreen() {
|
||||
function ManageClusterScreen() {
|
||||
return (
|
||||
<AppScreen className="w-full">
|
||||
<img src={peersImg} alt="Mycelium Peers" width="366" height="732" className="-mt-8" />
|
||||
</AppScreen>
|
||||
)
|
||||
<img
|
||||
src={kubeconfigImg}
|
||||
alt="Mycelium Kubeconfig"
|
||||
width={2432}
|
||||
height={1442}
|
||||
className="w-4xl max-w-none rounded-xl shadow-xl ring-1 ring-gray-400/10 sm:w-240 md:-ml-4 lg:ml-0"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function InvestScreen() {
|
||||
function PersonalisedBillingsScreen() {
|
||||
return (
|
||||
<AppScreen className="w-full">
|
||||
<img src={settingImg} alt="Mycelium Settings" width="366" height="732" className="-mt-8" />
|
||||
</AppScreen>
|
||||
)
|
||||
<img
|
||||
src={billingImg}
|
||||
alt="Mycelium Billing"
|
||||
width={2432}
|
||||
height={1442}
|
||||
className="w-4xl max-w-none rounded-xl shadow-xl ring-1 ring-gray-400/10 sm:w-240 md:-ml-4 lg:ml-0"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function usePrevious<T>(value: T) {
|
||||
@@ -216,7 +226,7 @@ function usePrevious<T>(value: T) {
|
||||
return ref.current
|
||||
}
|
||||
|
||||
function FeaturesDesktop() {
|
||||
function CloudFeaturesDesktop() {
|
||||
let [changeCount, setChangeCount] = useState(0)
|
||||
let [selectedIndex, setSelectedIndex] = useState(0)
|
||||
let prevIndex = usePrevious(selectedIndex)
|
||||
@@ -238,12 +248,12 @@ function FeaturesDesktop() {
|
||||
onChange={onChange}
|
||||
vertical
|
||||
>
|
||||
<TabList className="z-10 order-last col-span-6 space-y-6">
|
||||
<TabList className="z-10 col-span-6 space-y-6 pl-4 sm:pl-6 lg:pl-8">
|
||||
{features.map((feature, featureIndex) => (
|
||||
<div
|
||||
key={feature.name}
|
||||
className={clsx(
|
||||
'relative rounded-2xl outline-2 transition-all duration-300 ease-in-out hover:scale-105 hover:bg-gray-800/30',
|
||||
'relative rounded-2xl outline-2 transition-all duration-300 ease-in-out hover:scale-105 hover:bg-gray-800/30 ml-16',
|
||||
selectedIndex === featureIndex
|
||||
? 'outline-cyan-500'
|
||||
: 'outline-transparent hover:outline-cyan-500',
|
||||
@@ -252,7 +262,7 @@ function FeaturesDesktop() {
|
||||
{featureIndex === selectedIndex && (
|
||||
<motion.div
|
||||
layoutId="activeBackground"
|
||||
className="absolute inset-0 bg-gray-800"
|
||||
className="absolute inset-0 bg-gray-800 "
|
||||
initial={{ borderRadius: 16 }}
|
||||
/>
|
||||
)}
|
||||
@@ -271,11 +281,11 @@ function FeaturesDesktop() {
|
||||
</div>
|
||||
))}
|
||||
</TabList>
|
||||
<div className="relative col-span-6">
|
||||
<div className="relative col-span-6 overflow-hidden">
|
||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||
<CircleBackground id="primaryfeatures_desktop_circle" color="#13B5C8" className="animate-spin-slower" />
|
||||
</div>
|
||||
<PhoneFrame className="z-10 mx-auto w-full max-w-[366px]">
|
||||
<div className="z-10 mx-auto w-full max-w-[366px]">
|
||||
<TabPanels as={Fragment}>
|
||||
<AnimatePresence
|
||||
initial={false}
|
||||
@@ -296,13 +306,13 @@ function FeaturesDesktop() {
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</TabPanels>
|
||||
</PhoneFrame>
|
||||
</div>
|
||||
</div>
|
||||
</TabGroup>
|
||||
)
|
||||
}
|
||||
|
||||
function FeaturesMobile() {
|
||||
function CloudFeaturesMobile() {
|
||||
let [activeIndex, setActiveIndex] = useState(0)
|
||||
let slideContainerRef = useRef<React.ElementRef<'div'>>(null)
|
||||
let slideRefs = useRef<Array<React.ElementRef<'div'>>>([])
|
||||
@@ -361,9 +371,9 @@ function FeaturesMobile() {
|
||||
className={featureIndex % 2 === 1 ? 'rotate-180' : undefined}
|
||||
/>
|
||||
</div>
|
||||
<PhoneFrame className="relative mx-auto w-full max-w-[366px]">
|
||||
<div className="relative mx-auto w-full max-w-[366px]">
|
||||
<feature.screen />
|
||||
</PhoneFrame>
|
||||
</div>
|
||||
<div className="absolute inset-x-0 bottom-0 bg-gray-800/95 p-6 backdrop-blur-sm sm:p-10">
|
||||
<feature.icon className="h-8 w-8" />
|
||||
<MobileFeatureTitle color="white" className="mt-6">
|
||||
@@ -405,29 +415,27 @@ function FeaturesMobile() {
|
||||
export function CloudFeatures() {
|
||||
return (
|
||||
<section
|
||||
id="howitworks"
|
||||
id="overview"
|
||||
aria-label="Features for investing all your money"
|
||||
className="bg-gray-900 py-20 sm:py-32"
|
||||
>
|
||||
<Container>
|
||||
<div className="mx-auto max-w-2xl lg:mx-0 lg:max-w-3xl">
|
||||
<Eyebrow color="accent">How It Works</Eyebrow>
|
||||
<div className="mx-auto max-w-2xl lg:mx-0 lg:max-w-none">
|
||||
<Eyebrow color="accent">Platform Overview</Eyebrow>
|
||||
<SectionHeader color="white" className="mt-2">
|
||||
How Mycelium Operates
|
||||
A Decentralized Cloud that Operates Itself
|
||||
</SectionHeader>
|
||||
<P color="light" className="mt-6">
|
||||
Mycelium, like its natural namesake, thrives on decentralization,
|
||||
efficiency, and security, making it a truly powerful force in the world
|
||||
of decentralized networks.
|
||||
Mycelium Cloud orchestrates Kubernetes clusters on the ThreeFold Grid with cryptographic certainty. Networking, storage, and orchestration are all built-in so developers can deploy critical workloads without wrestling infrastructure.
|
||||
</P>
|
||||
</div>
|
||||
</Container>
|
||||
<div className="mt-16 md:hidden">
|
||||
<FeaturesMobile />
|
||||
<div className="hidden md:mt-20 md:block">
|
||||
<CloudFeaturesDesktop />
|
||||
</div>
|
||||
<div className="mt-16 md:hidden">
|
||||
<CloudFeaturesMobile />
|
||||
</div>
|
||||
<Container className="hidden md:mt-20 md:block">
|
||||
<FeaturesDesktop />
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { AnimatedSection } from '../../components/AnimatedSection'
|
||||
import { CloudHero } from './CloudHero'
|
||||
import { CloudOverview } from './CloudOverview'
|
||||
import { CloudArchitecture } from './CloudArchitecture'
|
||||
import { CloudFeatures } from './CloudFeatures'
|
||||
@@ -17,14 +16,13 @@ export default function CloudPage() {
|
||||
<CloudHeroNew />
|
||||
</AnimatedSection>
|
||||
<AnimatedSection>
|
||||
<CloudOverview />
|
||||
<CloudFeatures />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<CloudArchitecture />
|
||||
</AnimatedSection>
|
||||
<AnimatedSection>
|
||||
<CloudFeatures />
|
||||
</AnimatedSection>
|
||||
|
||||
<AnimatedSection>
|
||||
<CloudGettingStarted />
|
||||
</AnimatedSection>
|
||||
|
||||