feat: redesign benefits section with image cards

- Replaced icon-based feature cards with new image-based card layout using product benefit images
- Updated grid layout to 7-column system with asymmetric card sizes for better visual hierarchy
- Added hover effects with cyan highlights and scale transitions for better interactivity
- Implemented responsive design with custom rounded corners for mobile/desktop views
- Removed unused FeatureCard, FeatureTitle and FeatureDescription components
- Adde
This commit is contained in:
2025-10-27 15:22:42 +01:00
parent d82d3351f3
commit 2ba55566b5
8 changed files with 169 additions and 54 deletions

10
package-lock.json generated
View File

@@ -12,6 +12,7 @@
"@headlessui/react": "^2.2.9", "@headlessui/react": "^2.2.9",
"@heroicons/react": "^2.2.0", "@heroicons/react": "^2.2.0",
"@lobehub/icons": "^1.97.2", "@lobehub/icons": "^1.97.2",
"@radix-ui/react-icons": "^1.3.2",
"@react-three/drei": "^9.89.2", "@react-three/drei": "^9.89.2",
"@react-three/fiber": "^8.15.12", "@react-three/fiber": "^8.15.12",
"@tabler/icons-react": "^3.35.0", "@tabler/icons-react": "^3.35.0",
@@ -2478,6 +2479,15 @@
"react": "^16.8 || ^17.0 || ^18.0" "react": "^16.8 || ^17.0 || ^18.0"
} }
}, },
"node_modules/@radix-ui/react-icons": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.2.tgz",
"integrity": "sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==",
"license": "MIT",
"peerDependencies": {
"react": "^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc"
}
},
"node_modules/@radix-ui/react-id": { "node_modules/@radix-ui/react-id": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz",

View File

@@ -14,6 +14,7 @@
"@headlessui/react": "^2.2.9", "@headlessui/react": "^2.2.9",
"@heroicons/react": "^2.2.0", "@heroicons/react": "^2.2.0",
"@lobehub/icons": "^1.97.2", "@lobehub/icons": "^1.97.2",
"@radix-ui/react-icons": "^1.3.2",
"@react-three/drei": "^9.89.2", "@react-three/drei": "^9.89.2",
"@react-three/fiber": "^8.15.12", "@react-three/fiber": "^8.15.12",
"@tabler/icons-react": "^3.35.0", "@tabler/icons-react": "^3.35.0",

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@@ -0,0 +1,77 @@
import type { ReactNode } from "react";
import { Button } from "@/components/ui/button";
import { ArrowRightIcon } from "@radix-ui/react-icons";
import { cn } from "@/lib/utils";
const BentoGrid = ({
children,
className,
}: {
children: ReactNode;
className?: string;
}) => {
return (
<div
className={cn(
"grid w-full auto-rows-[22rem] grid-cols-3 gap-4",
className,
)}
>
{children}
</div>
);
};
const BentoCard = ({
name,
className,
background,
Icon,
description,
href,
cta,
}: {
name: string;
className: string;
background: ReactNode;
Icon: any;
description: string;
href: string;
cta: string;
}) => (
<div
key={name}
className={cn(
"group relative col-span-3 flex flex-col justify-between overflow-hidden rounded-xl",
// light styles
"bg-white [box-shadow:0_0_0_1px_rgba(0,0,0,.03),0_2px_4px_rgba(0,0,0,.05),0_12px_24px_rgba(0,0,0,.05)]",
// dark styles
"transform-gpu dark:bg-black dark:[border:1px_solid_rgba(255,255,255,.1)] dark:[box-shadow:0_-20px_80px_-20px_#ffffff1f_inset]",
className,
)}
>
<div>{background}</div>
<div className="pointer-events-none z-10 flex transform-gpu flex-col gap-1 p-6 transition-all duration-300 group-hover:-translate-y-10">
<Icon className="h-12 w-12 origin-left transform-gpu text-neutral-700 -translate-y-12 transition-all duration-300 ease-in-out group-hover:scale-75 group-hover:text-sky-700" />
<h3 className="text-xl font-semibold text-neutral-700 dark:text-neutral-300">
{name}
</h3>
<p className="max-w-lg text-neutral-400">{description}</p>
</div>
<div
className={cn(
"pointer-events-none absolute bottom-0 flex w-full translate-y-10 transform-gpu flex-row items-center p-4 opacity-0 transition-all duration-300 group-hover:translate-y-0 group-hover:opacity-100",
)}
>
<Button variant="ghost" asChild size="sm" className="pointer-events-auto">
<a href={href}>
{cta}
<ArrowRightIcon className="ml-2 h-4 w-4" />
</a>
</Button>
</div>
</div>
);
export { BentoCard, BentoGrid };

View File

@@ -3,7 +3,6 @@ import createGlobe from "cobe";
import { useEffect, useRef, type ReactNode } from "react"; import { useEffect, useRef, type ReactNode } from "react";
import { motion } from "motion/react"; import { motion } from "motion/react";
import { IconBrandYoutubeFilled } from "@tabler/icons-react"; import { IconBrandYoutubeFilled } from "@tabler/icons-react";
import { LockClosedIcon, CogIcon, BoltIcon, CurrencyDollarIcon } from '@heroicons/react/24/solid'
import { H2, P } from '@/components/Texts' import { H2, P } from '@/components/Texts'
@@ -13,30 +12,30 @@ export function HomeBenefits() {
title: "Sovereign", title: "Sovereign",
description: description:
"Own your infrastructure and your data. Mycelium Cloud eliminates dependency on centralized providers, giving you full digital sovereignty.", "Own your infrastructure and your data. Mycelium Cloud eliminates dependency on centralized providers, giving you full digital sovereignty.",
icon: <LockClosedIcon className="h-6 w-6 text-cyan-500" />, image: "/images/benefits/sovereign.webp",
}, },
{ {
title: "Autonomous", title: "Autonomous",
description: description:
"The cloud that runs itself. From deployment to scaling, Mycelium Cloud automates everything — so your systems stay fast, resilient, and adaptive.", "The cloud that runs itself. From deployment to scaling, Mycelium Cloud automates everything — so your systems stay fast, resilient, and adaptive.",
icon: <CogIcon className="h-6 w-6 text-cyan-500" />, image: "/images/benefits/autonomous.webp",
}, },
{ {
title: "Energy Efficient", title: "Energy Efficient",
description: description:
"Built on distributed nodes designed for minimal energy use, Mycelium Cloud redefines sustainability without compromising performance.", "Built on distributed nodes designed for minimal energy use, Mycelium Cloud redefines sustainability without compromising performance.",
icon: <BoltIcon className="h-6 w-6 text-cyan-500" />, image: "/images/benefits/energy.webp",
}, },
{ {
title: "Cost Efficient", title: "Cost Efficient",
description: description:
"No middlemen. No inflated bills. Just pure compute power at a fraction of traditional cloud costs — optimized, transparent, and fair.", "No middlemen. No inflated bills. Just pure compute power at a fraction of traditional cloud costs — optimized, transparent, and fair.",
icon: <CurrencyDollarIcon className="h-6 w-6 text-cyan-500" />, image: "/images/benefits/cost.webp",
}, },
]; ];
return ( return (
<div className="relative z-20 py-10 lg:py-40 max-w-7xl mx-auto"> <div className="relative z-20 py-10 lg:py-40 max-w-7xl mx-auto">
<div className="px-8"> <div className="px-12">
<H2 className="text-3xl lg:text-5xl lg:leading-tight max-w-5xl mx-auto text-center tracking-tight font-medium text-black dark:text-white"> <H2 className="text-3xl lg:text-5xl lg:leading-tight max-w-5xl mx-auto text-center tracking-tight font-medium text-black dark:text-white">
Why It Changes Everything Why It Changes Everything
</H2> </H2>
@@ -46,15 +45,81 @@ export function HomeBenefits() {
</P> </P>
</div> </div>
<div className="relative "> <div className="mt-10 grid grid-cols-1 gap-4 sm:mt-16 lg:grid-cols-7 lg:grid-rows-2 lg:px-12 px-6">
<div className="mt-12 rounded-2xl border border-neutral-200/70 bg-white/40 dark:bg-black/40 dark:border-neutral-800/60 backdrop-blur"> <div className="flex p-px lg:col-span-4">
<div className="grid grid-cols-1 md:grid-cols-2 divide-y md:divide-y-0 md:divide-x divide-neutral-200/70 dark:divide-neutral-800/60"> <div className="w-full overflow-hidden rounded-lg bg-white/40 dark:bg-black/40 shadow-sm border border-transparent transition-all duration-300 hover:scale-105 hover:shadow-lg hover:shadow-cyan-500/50 hover:border-cyan-500 max-lg:rounded-t-4xl lg:rounded-tl-4xl">
{features.map((feature) => ( <div className="flex items-center">
<FeatureCard key={feature.title}> <div className="w-1/3 p-2">
<FeatureTitle icon={feature.icon}>{feature.title}</FeatureTitle> <img
<FeatureDescription>{feature.description}</FeatureDescription> alt={features[0].title}
</FeatureCard> src={features[0].image}
))} className="w-40 h-40 object-contain"
/>
</div>
<div className="w-2/3 p-2 pr-12">
<h3 className="text-lg font-semibold text-black dark:text-white">{features[0].title}</h3>
<p className="mt-2 text-sm text-gray-600 dark:text-gray-300">
{features[0].description}
</p>
</div>
</div>
</div>
</div>
<div className="flex p-px lg:col-span-3">
<div className="w-full overflow-hidden rounded-lg bg-white/40 dark:bg-black/40 shadow-sm border border-transparent transition-all duration-300 hover:scale-105 hover:shadow-lg hover:shadow-cyan-500/50 hover:border-cyan-500 lg:rounded-tr-4xl">
<div className="flex items-center">
<div className="w-1/3 p-4">
<img
alt={features[1].title}
src={features[1].image}
className="w-40 h-40 object-contain"
/>
</div>
<div className="w-2/3 p-4">
<h3 className="text-lg font-semibold text-black dark:text-white">{features[1].title}</h3>
<p className="mt-2 text-sm text-gray-600 dark:text-gray-300">
{features[1].description}
</p>
</div>
</div>
</div>
</div>
<div className="flex p-px lg:col-span-3">
<div className="w-full overflow-hidden rounded-lg bg-white/40 dark:bg-black/40 shadow-sm border border-transparent transition-all duration-300 hover:scale-105 hover:shadow-lg hover:shadow-cyan-500/50 hover:border-cyan-500 lg:rounded-bl-4xl">
<div className="flex items-center">
<div className="w-1/3 p-4">
<img
alt={features[2].title}
src={features[2].image}
className="w-40 h-40 object-contain"
/>
</div>
<div className="w-2/3 p-4">
<h3 className="text-lg font-semibold text-black dark:text-white">{features[2].title}</h3>
<p className="mt-2 text-sm text-gray-600 dark:text-gray-300">
{features[2].description}
</p>
</div>
</div>
</div>
</div>
<div className="flex p-px lg:col-span-4">
<div className="w-full overflow-hidden rounded-lg bg-white/40 dark:bg-black/40 shadow-sm border border-transparent transition-all duration-300 hover:scale-105 hover:shadow-lg hover:shadow-cyan-500/50 hover:border-cyan-500 max-lg:rounded-b-4xl lg:rounded-br-4xl">
<div className="flex items-center">
<div className="w-1/3 p-2">
<img
alt={features[3].title}
src={features[3].image}
className="w-40 h-40 object-contain"
/>
</div>
<div className="w-2/3 p-2 pr-12">
<h3 className="text-lg font-semibold text-black dark:text-white">{features[3].title}</h3>
<p className="mt-2 text-sm text-gray-600 dark:text-gray-300">
{features[3].description}
</p>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -62,44 +127,6 @@ export function HomeBenefits() {
); );
} }
const FeatureCard = ({
children,
className,
}: {
children?: ReactNode;
className?: string;
}) => {
return (
<div className={cn(`p-6 lg:p-8 relative overflow-hidden`, className)}>
{children}
</div>
);
};
const FeatureTitle = ({ children, icon }: { children?: ReactNode; icon?: ReactNode }) => {
return (
<div className="flex items-center gap-2">
{icon}
<p className="max-w-5xl text-left tracking-tight text-black dark:text-white text-xl md:text-2xl md:leading-snug">
{children}
</p>
</div>
);
};
const FeatureDescription = ({ children }: { children?: ReactNode }) => {
return (
<p
className={cn(
"text-sm md:text-base max-w-4xl",
"text-neutral-500 font-normal dark:text-neutral-300",
"text-left max-w-sm mx-0 md:text-sm my-2"
)}
>
{children}
</p>
);
};
export const SkeletonOne = () => { export const SkeletonOne = () => {
return ( return (