打磨细节

This commit is contained in:
2026-01-28 17:55:01 +08:00
parent 08af95116e
commit 0a1bd07492
36 changed files with 1649 additions and 466 deletions

View File

@@ -2,14 +2,15 @@
import { useState, useEffect, useRef } from 'react';
import Image from 'next/image';
import { useLanguage } from '@/contexts/LanguageContext';
// 数字增长动画Hook
function useCountUp(end: number, duration: number = 1500, startRangePercent: number = 0.75) {
const [mounted, setMounted] = useState(false);
const [count, setCount] = useState(end);
const [hasAnimated, setHasAnimated] = useState(false);
const elementRef = useRef<HTMLDivElement>(null);
const startValueRef = useRef<number>(end);
const animationRef = useRef<number | null>(null);
useEffect(() => {
setMounted(true);
@@ -22,8 +23,7 @@ function useCountUp(end: number, duration: number = 1500, startRangePercent: num
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting && !hasAnimated) {
setHasAnimated(true);
if (entries[0].isIntersecting) {
const start = startValueRef.current;
const startTime = Date.now();
@@ -42,7 +42,13 @@ function useCountUp(end: number, duration: number = 1500, startRangePercent: num
}
}, 16);
animationRef.current = timer as unknown as number;
return () => clearInterval(timer);
} else {
if (animationRef.current) {
clearInterval(animationRef.current);
}
setCount(startValueRef.current);
}
},
{ threshold: 0.1 }
@@ -53,14 +59,14 @@ function useCountUp(end: number, duration: number = 1500, startRangePercent: num
}
return () => observer.disconnect();
}, [end, duration, hasAnimated, mounted]);
}, [end, duration, mounted]);
return { count, elementRef };
}
export default function HowItWorksSection() {
const [mounted, setMounted] = useState(false);
const [visible, setVisible] = useState(false);
const { t } = useLanguage();
const [animate, setAnimate] = useState(false);
const [activeStep, setActiveStep] = useState(1); // 默认第1步激活
const sectionRef = useRef<HTMLElement>(null);
@@ -69,49 +75,40 @@ export default function HowItWorksSection() {
const earnAmount = useCountUp(5150, 1500, 0.85);
useEffect(() => {
setMounted(true);
const currentRef = sectionRef.current;
if (!currentRef) return;
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting && !visible) {
setVisible(true);
}
});
if (entries[0].isIntersecting) {
setAnimate(true);
observer.disconnect();
}
},
{
threshold: 0.1,
}
{ threshold: 0.3 }
);
if (sectionRef.current) {
observer.observe(sectionRef.current);
}
return () => {
if (sectionRef.current) {
observer.unobserve(sectionRef.current);
}
};
}, [visible]);
observer.observe(currentRef);
return () => observer.disconnect();
}, []);
const steps = [
{
number: 1,
title: 'Deposit & Mint WUSD',
description: 'Connect your wallet and deposit USDC to swap WUSD. This serves as the native stablecoin and gateway to the entire AssetX ecosystem.',
title: t('how.step1.title'),
description: t('how.step1.desc'),
hasLine: true
},
{
number: 2,
title: 'Dual Investment Options',
description: 'Choose your strategy: use WUSD to purchase specific Yield-Bearing Assets for real-world returns, or provide liquidity in DeFi Pools to earn trading fees.',
title: t('how.step2.title'),
description: t('how.step2.desc'),
hasLine: true
},
{
number: 3,
title: 'Earn & Boost',
description: 'Receive daily yield distributions. Use Asset Tokens as collateral to borrow WUSD and leverage up to 2.5x for maximized returns.',
title: t('how.step3.title'),
description: t('how.step3.desc'),
hasLine: false
}
];
@@ -128,7 +125,7 @@ export default function HowItWorksSection() {
}}
>
{/* .container20 - Main container */}
<div className="flex flex-row items-start justify-between flex-shrink-0 relative w-[1200px]">
<div className="flex flex-row items-start justify-between flex-shrink-0 relative w-[1440px]">
{/* Left Side - Steps (.container21) */}
<div className="flex flex-col gap-10 items-start justify-start flex-shrink-0 relative w-[520px]">
@@ -144,7 +141,7 @@ export default function HowItWorksSection() {
fontWeight: 700
}}
>
How it works
{t('how.title')}
</h2>
</div>
@@ -159,7 +156,7 @@ export default function HowItWorksSection() {
key={step.number}
onClick={() => setActiveStep(step.number)}
className={`flex flex-row gap-6 items-start justify-start flex-shrink-0 relative cursor-pointer transition-all duration-300 ease-out hover:opacity-80 ${
mounted && visible
animate
? 'translate-x-0 opacity-100'
: '-translate-x-12 opacity-0'
}`}
@@ -224,12 +221,13 @@ export default function HowItWorksSection() {
}}
>
<h3
className="text-[#111827] text-left relative flex items-center justify-start font-inter transition-all duration-300"
className="text-left relative flex items-center justify-start font-inter transition-all duration-300"
style={{
fontSize: '24px',
fontSize: '28px',
lineHeight: '130%',
letterSpacing: '-0.005em',
fontWeight: isActive ? 700 : 500
fontWeight: 600,
color: isActive ? '#111827' : '#6b7280'
}}
>
{step.title}
@@ -251,30 +249,33 @@ export default function HowItWorksSection() {
</div>
</div>
{/* Right Side - Calculator Card */}
{/* Right Side - Dynamic Cards Container */}
<div
className={`calculator-card-container flex flex-col items-start justify-start flex-shrink-0 w-[558px] relative transition-all duration-700 ease-out ${
mounted && visible
? 'translate-y-0 opacity-100'
: 'translate-y-12 opacity-0'
}`}
className="calculator-card-container flex flex-col items-start justify-start flex-shrink-0 w-[558px] relative"
style={{
transitionDelay: '450ms',
height: '439px'
}}
>
{/* Coin Images Container - Rotated Card */}
<div
className="bg-[#111827] rounded-[16px] flex flex-row gap-4 items-start justify-start h-[162px] absolute z-0"
style={{
padding: '25px 25px 1px 25px',
left: '205.43px',
top: '15.96px',
boxShadow: '0px 25px 50px -12px rgba(0, 0, 0, 0.25)',
transformOrigin: '0 0',
transform: 'rotate(6.535deg) scale(1, 1)'
}}
>
{/* Step 1: Deposit & Mint WUSD Card */}
<>
{/* Coin Images Container - Rotated Card */}
<div
className={`bg-[#111827] rounded-[16px] flex flex-row gap-4 items-start justify-start h-[162px] absolute z-0 transition-all duration-700 ease-out ${
animate && activeStep === 1 ? 'opacity-100' : 'opacity-0'
}`}
style={{
padding: '25px 25px 1px 25px',
left: '205.43px',
top: '15.96px',
boxShadow: '0px 25px 50px -12px rgba(0, 0, 0, 0.25)',
transformOrigin: '0 0',
transform: animate && activeStep === 1
? 'rotate(6.535deg) scale(1, 1) translateY(0)'
: 'rotate(6.535deg) scale(1, 1) translateY(3rem)',
transitionDelay: activeStep === 1 ? '200ms' : '0ms',
pointerEvents: activeStep === 1 ? 'auto' : 'none'
}}
>
{/* USDC Logo */}
<Image
src="/usd-coin-usdc-logo-10.svg"
@@ -299,10 +300,16 @@ export default function HowItWorksSection() {
{/* Calculator Card */}
<div
className="bg-white/85 backdrop-blur-md rounded-[24px] border border-[#e5e7eb] p-8 absolute left-0 top-[99px] w-full shadow-lg z-10"
className={`bg-white/85 backdrop-blur-md rounded-[24px] border border-[#e5e7eb] p-8 absolute left-0 top-[99px] w-full shadow-lg z-10 transition-all duration-700 ease-out ${
animate && activeStep === 1 ? 'opacity-100' : 'opacity-0'
}`}
style={{
transform: 'rotate(-3deg)',
transformOrigin: 'center center'
transform: animate && activeStep === 1
? 'rotate(-3deg) translateY(0)'
: 'rotate(-3deg) translateY(3rem)',
transformOrigin: 'center center',
transitionDelay: activeStep === 1 ? '200ms' : '0ms',
pointerEvents: activeStep === 1 ? 'auto' : 'none'
}}
>
@@ -325,7 +332,7 @@ export default function HowItWorksSection() {
fontWeight: 500
}}
>
Portfolio Overview Simulator
{t('how.simulator.title')}
</span>
</div>
@@ -345,7 +352,7 @@ export default function HowItWorksSection() {
fontWeight: 400
}}
>
If you invest
{t('how.simulator.invest')}
</span>
<span
ref={investAmount.elementRef}
@@ -377,7 +384,7 @@ export default function HowItWorksSection() {
fontWeight: 400
}}
>
You earn per year
{t('how.simulator.earn')}
</span>
<div className="flex flex-row gap-2 items-center">
<Image
@@ -401,6 +408,286 @@ export default function HowItWorksSection() {
</div>
</div>
</div>
</>
{/* Step 2: Dual Investment Options Card */}
<div
className={`bg-white rounded-[16px] border border-[#f3f4f6] p-6 flex flex-col gap-6 absolute left-0 top-[99px] w-full transition-all duration-700 ease-out ${
animate && activeStep === 2
? 'opacity-100'
: 'opacity-0'
}`}
style={{
boxShadow: '0px 25px 50px -12px rgba(0, 0, 0, 0.25)',
transform: animate && activeStep === 2
? 'rotate(3deg) translateY(0)'
: 'rotate(3deg) translateY(3rem)',
transformOrigin: '0 0',
transitionDelay: activeStep === 2 ? '200ms' : '0ms',
pointerEvents: activeStep === 2 ? 'auto' : 'none'
}}
>
{/* Header */}
<div
className="border-b border-[#f3f4f6] pb-4 flex flex-row items-center justify-between w-full"
>
<span className="text-[#000000] font-inter text-[18px] font-bold leading-7">
Fund Market
</span>
<span className="text-[#059669] font-inter text-[16px] font-bold leading-6">
Connect Wallet
</span>
</div>
{/* Investment Options Container */}
<div className="flex flex-col gap-4 w-full">
{/* Option 1 - Active */}
<div className="bg-[#f9fafb] rounded-[12px] border border-[#f3f4f6] p-4 flex flex-row gap-4 items-center h-24">
{/* Icon */}
<div className="bg-[#000000] rounded-full w-12 h-12 flex items-center justify-center flex-shrink-0">
<span className="text-white font-inter text-[16px] font-bold">O</span>
</div>
{/* Text Placeholders */}
<div className="flex flex-col gap-2 flex-1">
<div className="bg-[#e5e7eb] rounded h-4 w-24" />
<div className="bg-[#f3f4f6] rounded h-3 w-16" />
</div>
{/* APY Info */}
<div className="flex flex-col gap-2 items-end flex-shrink-0">
<div className="bg-[#e5e7eb] rounded h-4 w-20" />
<span className="text-[#059669] font-inter text-[16px] font-bold leading-6">
APY 30.2%
</span>
</div>
</div>
{/* Option 2 - Inactive */}
<div className="bg-[#f9fafb] rounded-[12px] border border-[#f3f4f6] p-4 flex flex-row gap-4 items-center h-24 opacity-60">
{/* Icon */}
<div className="bg-[#d1d5db] rounded-full w-12 h-12 flex-shrink-0" />
{/* Text Placeholders */}
<div className="flex flex-col gap-2 flex-1">
<div className="bg-[#e5e7eb] rounded h-4 w-32" />
<div className="bg-[#f3f4f6] rounded h-3 w-20" />
</div>
{/* APY Info */}
<div className="flex flex-col gap-2 items-end flex-shrink-0">
<div className="bg-[#e5e7eb] rounded h-4 w-20" />
<span className="text-[#059669] font-inter text-[16px] font-bold leading-6">
APY 15.2%
</span>
</div>
</div>
</div>
</div>
{/* Step 3: Earn & Boost Card */}
<div
className={`bg-white rounded-[16px] border border-[#f3f4f6] p-6 flex flex-col gap-6 absolute left-0 top-[99px] w-[520px] transition-all duration-700 ease-out ${
animate && activeStep === 3 ? 'opacity-100' : 'opacity-0'
}`}
style={{
boxShadow: '0px 25px 50px -12px rgba(0, 0, 0, 0.25)',
transform: animate && activeStep === 3
? 'rotate(3deg) translateY(0)'
: 'rotate(3deg) translateY(3rem)',
transformOrigin: '0 0',
transitionDelay: activeStep === 3 ? '200ms' : '0ms',
overflow: 'hidden',
pointerEvents: activeStep === 3 ? 'auto' : 'none'
}}
>
{/* Header */}
<div className="border-b border-[#f3f4f6] pb-[17px] flex flex-row items-center justify-between" style={{ width: '470px', height: '45px' }}>
<span className="text-[#000000] font-inter text-[18px] font-bold leading-7">
Defi
</span>
<span className="text-[#059669] font-inter text-[16px] font-bold leading-6">
+5.2% APY
</span>
</div>
{/* Cards Grid Container */}
<div
className="relative"
style={{
width: '466px',
height: '195px',
transform: 'rotate(-3deg)',
transformOrigin: '0 0',
overflow: 'hidden'
}}
>
{/* Container 1 */}
<div
className="absolute"
style={{
width: '135.53px',
height: '165.15px',
left: '8.58px',
top: '0.46px',
transform: 'rotate(3deg)',
transformOrigin: '0 0'
}}
>
<div className="bg-[#f9fafb] rounded-[12px] border border-[#f3f4f6] p-4 flex flex-col gap-4 items-center absolute" style={{ width: '134.91px', height: '165.18px', left: '0px', top: '0px' }}>
<div className="bg-[#000000] rounded-full w-12 h-12 flex items-center justify-center flex-shrink-0">
<span className="text-white font-inter text-[16px] font-bold leading-6">O</span>
</div>
<span
className="text-[#000000] font-inter text-[16px] font-bold text-center"
style={{ width: '124px', height: '17px', transform: 'rotate(-3deg)', transformOrigin: '0 0', display: 'flex', alignItems: 'center', justifyContent: 'center' }}
>
+10% APY
</span>
<div
className="bg-[#000000] rounded-lg px-4 py-2"
style={{ transform: 'rotate(-3deg)', transformOrigin: '0 0' }}
>
<span className="text-white font-inter text-[12px] font-bold leading-4">
Boost
</span>
</div>
</div>
</div>
{/* Container 2 */}
<div
className="absolute"
style={{
width: '135.53px',
height: '165.15px',
left: '160.18px',
top: '11.66px',
transform: 'rotate(3deg)',
transformOrigin: '0 0'
}}
>
<div className="bg-[#f9fafb] rounded-[12px] border border-[#f3f4f6] p-4 flex flex-col gap-4 items-center absolute" style={{ width: '134.91px', height: '165.18px', left: '0px', top: '0px' }}>
<div className="bg-[#000000] rounded-full w-12 h-12 flex items-center justify-center flex-shrink-0">
<span className="text-white font-inter text-[16px] font-bold leading-6">O</span>
</div>
<span
className="text-[#000000] font-inter text-[16px] font-bold text-center"
style={{ width: '124px', height: '17px', transform: 'rotate(-3deg)', transformOrigin: '0 0', display: 'flex', alignItems: 'center', justifyContent: 'center' }}
>
+10% APY
</span>
<div
className="bg-[#000000] rounded-lg px-4 py-2"
style={{ transform: 'rotate(-3deg)', transformOrigin: '0 0' }}
>
<span className="text-white font-inter text-[12px] font-bold leading-4">
Boost
</span>
</div>
</div>
</div>
{/* Container 3 */}
<div
className="absolute"
style={{
width: '135.53px',
height: '165.15px',
left: '312.18px',
top: '19.66px',
transform: 'rotate(3deg)',
transformOrigin: '0 0'
}}
>
<div className="bg-[#f9fafb] rounded-[12px] border border-[#f3f4f6] p-4 flex flex-col gap-4 items-center absolute" style={{ width: '134.91px', height: '165.18px', left: '0px', top: '0px' }}>
<div className="bg-[#000000] rounded-full w-12 h-12 flex items-center justify-center flex-shrink-0">
<span className="text-white font-inter text-[16px] font-bold leading-6">O</span>
</div>
<span
className="text-[#000000] font-inter text-[16px] font-bold text-center"
style={{ width: '124px', height: '17px', transform: 'rotate(-3deg)', transformOrigin: '0 0', display: 'flex', alignItems: 'center', justifyContent: 'center' }}
>
+10% APY
</span>
<div
className="bg-[#000000] rounded-lg px-4 py-2"
style={{ transform: 'rotate(-3deg)', transformOrigin: '0 0' }}
>
<span className="text-white font-inter text-[12px] font-bold leading-4">
Boost
</span>
</div>
</div>
</div>
{/* Container 4 - with SWAP button */}
<div
className="absolute"
style={{
width: '135.53px',
height: '165.15px',
left: '160.18px',
top: '11.66px',
transform: 'rotate(3deg)',
transformOrigin: '0 0'
}}
>
<div className="bg-[#f9fafb] rounded-[12px] border border-[#f3f4f6] p-4 flex flex-col gap-4 items-center absolute" style={{ width: '134.91px', height: '165.18px', left: '0px', top: '0px' }}>
<div className="bg-[#000000] rounded-full w-12 h-12 flex items-center justify-center flex-shrink-0">
<span className="text-white font-inter text-[16px] font-bold leading-6">O</span>
</div>
<span
className="text-[#000000] font-inter text-[16px] font-bold text-center"
style={{ width: '124px', height: '17px', transform: 'rotate(-3deg)', transformOrigin: '0 0', display: 'flex', alignItems: 'center', justifyContent: 'center' }}
>
Get USDC
</span>
<div
className="bg-[#000000] rounded-lg px-4 py-2"
style={{ transform: 'rotate(-3deg)', transformOrigin: '0 0' }}
>
<span className="text-white font-inter text-[12px] font-bold leading-4">
SWAP
</span>
</div>
</div>
</div>
{/* Container 5 - with LP button */}
<div
className="absolute"
style={{
width: '135.53px',
height: '165.15px',
left: '312.18px',
top: '19.66px',
transform: 'rotate(3deg)',
transformOrigin: '0 0'
}}
>
<div className="bg-[#f9fafb] rounded-[12px] border border-[#f3f4f6] p-4 flex flex-col gap-4 items-center absolute" style={{ width: '134.91px', height: '165.18px', left: '0px', top: '0px' }}>
<div className="bg-[#000000] rounded-full w-12 h-12 flex items-center justify-center flex-shrink-0">
<span className="text-white font-inter text-[16px] font-bold leading-6">O</span>
</div>
<span
className="text-[#000000] font-inter text-[16px] font-bold text-center"
style={{ width: '124px', height: '17px', transform: 'rotate(-3deg)', transformOrigin: '0 0', display: 'flex', alignItems: 'center', justifyContent: 'center' }}
>
10% APY
</span>
<div
className="bg-[#000000] rounded-lg px-4 py-2"
style={{ transform: 'rotate(-3deg)', transformOrigin: '0 0' }}
>
<span className="text-white font-inter text-[12px] font-bold leading-4">
LP
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>