Initial commit

This commit is contained in:
2025-10-11 11:55:25 +08:00
parent 467dad8449
commit 8107dee8d3
2879 changed files with 610575 additions and 0 deletions

View File

@@ -0,0 +1,165 @@
import { useRef, useState } from "react";
import { Link } from "react-router-dom";
// import { Splide, SplideTrack, SplideSlide } from "@splidejs/react-splide";
import Section from "../../../components/Section";
import Heading from "../../../components/Heading/index.js";
import Image from "../../../components/Image";
// 简化版数据避免依赖外部mock文件
const benefits = [
{
id: "0",
title: "智能问答",
text: "让用户能够快速找到问题答案,无需在多个信息源中搜索,提升投研效率。",
backgroundUrl: "/images/benefits/card-1.svg",
iconUrl: "/images/benefits/icon-1.svg",
imageUrl: "/images/benefits/image-2.png",
light: true,
},
{
id: "1",
title: "持续学习",
text: "系统采用自然语言处理技术理解用户查询,提供准确相关的投研分析结果。",
backgroundUrl: "/images/benefits/card-2.svg",
iconUrl: "/images/benefits/icon-2.svg",
imageUrl: "/images/benefits/image-2.png",
},
{
id: "2",
title: "全域连接",
text: "随时随地连接AI投研助手支持多设备访问让专业分析更便捷。",
backgroundUrl: "/images/benefits/card-3.svg",
iconUrl: "/images/benefits/icon-3.svg",
imageUrl: "/images/benefits/image-2.png",
},
{
id: "3",
title: "快速响应",
text: "毫秒级响应速度,让用户快速获得投研洞察,把握市场先机。",
backgroundUrl: "/images/benefits/card-4.svg",
iconUrl: "/images/benefits/icon-4.svg",
imageUrl: "/images/benefits/image-2.png",
light: true,
},
{
id: "4",
title: "深度分析",
text: "基于海量数据训练的专业投研模型,提供超越传统分析工具的深度洞察。",
backgroundUrl: "/images/benefits/card-5.svg",
iconUrl: "/images/benefits/icon-1.svg",
imageUrl: "/images/benefits/image-2.png",
},
{
id: "5",
title: "智能预测",
text: "结合机器学习算法,为投资决策提供智能预测和风险评估建议。",
backgroundUrl: "/images/benefits/card-6.svg",
iconUrl: "/images/benefits/icon-2.svg",
imageUrl: "/images/benefits/image-2.png",
},
];
const Benefits = () => {
const [activeIndex, setActiveIndex] = useState(0);
const handleClick = (index) => {
setActiveIndex(index);
};
return (
<Section className="overflow-hidden bg-n-8">
<div className="container relative z-2">
<Heading
className="md:max-w-md lg:max-w-2xl"
title="智能投研,让分析更简单"
text="利用先进的人工智能技术,为您提供专业的投资研究分析服务"
/>
{/* 简化版网格布局暂时不使用Splide */}
<div className="max-w-[24rem] md:max-w-none grid grid-cols-1 md:grid-cols-3 gap-6">
{benefits.map((item, index) => (
<div key={item.id}>
<Link
className="block relative p-0.5 bg-no-repeat bg-[length:100%_100%] md:max-w-[24rem] rounded-xl"
to="/features"
style={{
backgroundImage: `url(${item.backgroundUrl})`,
}}
>
<div className="relative z-2 flex flex-col h-[22.625rem] p-[2.375rem] pointer-events-none">
<h5 className="h5 mb-5">
{item.title}
</h5>
<p className="body-2 mb-6 text-n-3">
{item.text}
</p>
<div className="flex items-center mt-auto">
<Image
className=""
src={item.iconUrl}
width={48}
height={48}
alt={item.title}
/>
<div className="ml-auto font-code text-xs font-bold text-n-1 uppercase tracking-wider">
了解更多
</div>
<svg
className="ml-5 fill-n-1"
width="24"
height="24"
>
<path d="M8.293 5.293a1 1 0 0 1 1.414 0l6 6a1 1 0 0 1 0 1.414l-6 6a1 1 0 0 1-1.414-1.414L13.586 12 8.293 6.707a1 1 0 0 1 0-1.414z" />
</svg>
</div>
</div>
{item.light && (
<div className="absolute top-0 left-1/4 w-full aspect-square bg-radial-gradient from-[#28206C] to-[#28206C]/0 to-70% pointer-events-none"></div>
)}
<div
className="absolute inset-0.5 bg-n-8 rounded-xl"
>
<div className="absolute inset-0 opacity-0 transition-opacity hover:opacity-10">
{item.imageUrl && (
<Image
className="w-full h-full object-cover rounded-xl"
src={item.imageUrl}
width={380}
height={362}
alt={item.title}
/>
)}
</div>
</div>
</Link>
</div>
))}
</div>
{/* 指示器 */}
<div className="flex mt-12 -mx-2 md:mt-15 lg:justify-center xl:mt-20">
{benefits.map((item, index) => (
<button
className="relative w-6 h-6 mx-2"
onClick={() => handleClick(index)}
key={item.id}
>
<span
className={`absolute inset-0 bg-conic-gradient rounded-full transition-opacity ${
index === activeIndex
? "opacity-100"
: "opacity-0"
}`}
></span>
<span className="absolute inset-0.25 bg-n-8 rounded-full">
<span className="absolute inset-2 bg-n-1 rounded-full"></span>
</span>
</button>
))}
</div>
</div>
</Section>
);
};
export default Benefits;

View File

@@ -0,0 +1,130 @@
import Section from "@/components/Section";
import Button from "@/components/Button";
import Image from "@/components/Image";
import { text, content, apps } from "@/mocks/collaboration";
type CollaborationProps = {};
const Collaboration = ({}: CollaborationProps) => {
return (
<Section crosses>
<div className="container lg:flex">
<div className="max-w-[25rem]">
<h2 className="h2 mb-4 md:mb-8">
AI chat app for seamless collaboration
</h2>
<ul className="max-w-[22.5rem] mb-10 md:mb-14">
{content.map((item) => (
<li className="mb-3 py-3" key={item.id}>
<div className="flex items-center">
<Image
src="/images/check.svg"
width={24}
height={24}
alt="Check"
/>
<h6 className="body-2 ml-5">
{item.title}
</h6>
</div>
{item.text && (
<p className="body-2 mt-3 text-n-4">
{item.text}
</p>
)}
</li>
))}
</ul>
<Button>Try it now</Button>
</div>
<div className="mt-15 lg:mt-0 lg:ml-auto xl:w-[37.5rem]">
<div className="relative lg:w-[22.5rem] lg:mx-auto">
<p className="body-2 mb-4 text-n-4 md:mb-16 lg:mb-32">
{text}
</p>
<div className="relative left-1/2 flex w-[22.5rem] aspect-square border border-n-6 rounded-full -translate-x-1/2 scale-75 md:scale-100">
<div className="flex w-60 aspect-square m-auto border border-n-6 rounded-full">
<div className="w-[5.75rem] aspect-square m-auto p-[0.1875rem] bg-conic-gradient rounded-full">
<div className="flex items-center justify-center w-full h-full bg-n-8 rounded-full">
<Image
src="/images/brainwave-symbol.svg"
width={48}
height={48}
alt="Brainwave"
/>
</div>
</div>
</div>
<ul>
{apps.map((app, index) => (
<li
className={`absolute top-0 left-1/2 h-1/2 -ml-[1.625rem] ${
index === 1 && "rotate-[45deg]"
} ${index === 2 && "rotate-[90deg]"} ${
index === 3 && "rotate-[135deg]"
} ${index === 4 && "rotate-[180deg]"} ${
index === 5 && "rotate-[225deg]"
} ${index === 6 && "rotate-[270deg]"} ${
index === 7 && "rotate-[315deg]"
} origin-bottom`}
key={app.id}
>
<div
className={`relative -top-[1.625rem] flex w-[3.25rem] h-[3.25rem] bg-n-7 border border-n-1/15 rounded-xl ${
index === 1 && "-rotate-[45deg]"
} ${
index === 2 && "-rotate-[90deg]"
} ${
index === 3 &&
"-rotate-[135deg]"
} ${
index === 4 &&
"-rotate-[180deg]"
} ${
index === 5 &&
"-rotate-[225deg]"
} ${
index === 6 &&
"-rotate-[270deg]"
} ${
index === 7 &&
"-rotate-[315deg]"
}`}
>
<Image
className="m-auto"
src={app.icon}
width={app.width}
height={app.height}
alt={app.title}
/>
</div>
</li>
))}
</ul>
<div className="hidden absolute top-1/2 right-full w-[32.625rem] -mt-1 mr-10 pointer-events-none xl:block">
<Image
src="/images/collaboration/curve-1.svg"
width={522}
height={182}
alt="Curve 1"
/>
</div>
<div className="hidden absolute top-1/2 left-full w-[10.125rem] -mt-1 ml-10 pointer-events-none xl:block">
<Image
src="/images/collaboration/curve-2.svg"
width={162}
height={76}
alt="Curve 2"
/>
</div>
</div>
</div>
</div>
</div>
</Section>
);
};
export default Collaboration;

View File

@@ -0,0 +1,99 @@
import { useRef, useState } from "react";
import Section from "../../../components/Section";
import Button from "../../../components/Button";
import Image from "../../../components/Image";
import Notification from "../../../components/Notification";
// 简化版特性数据
const features = [
{
id: "0",
title: "智能投研分析",
text: "利用先进的AI技术为您提供全面的投资研究分析包括市场趋势、公司基本面、技术指标等多维度分析帮助您做出更明智的投资决策。",
imageUrl: "/images/features/features.png",
iconUrl: "/images/icons/recording-01.svg",
notification: "AI分析完成 - 发现3个潜在投资机会",
},
{
id: "1",
title: "实时市场监控",
text: "24/7全天候监控全球金融市场动态实时捕捉市场变化和投资机会。智能预警系统会在关键时刻及时提醒您确保不错过任何重要的投资时机。",
imageUrl: "/images/features/image-1.jpg",
iconUrl: "/images/icons/chrome-cast.svg",
notification: "市场异动提醒 - 科技股出现上涨信号",
},
];
const Features = () => {
const [currentFeature, setCurrentFeature] = useState(0);
return (
<Section
className="py-10 md:pb-20 lg:pt-16 lg:pb-32 xl:pb-40 overflow-hidden bg-n-7"
customPaddings
>
<div className="container relative z-2">
{features.map((item, index) => (
<div key={item.id} className={index === currentFeature ? "block" : "hidden"}>
<div className="lg:flex">
<div className="lg:flex lg:flex-col lg:items-start lg:max-w-[18.75rem] lg:mr-auto">
<h2 className="h2 mb-6">
{item.title}
</h2>
<p className="body-2 mb-10 text-n-3">
{item.text}
</p>
<Button className="" onClick={null} px="px-7">
了解工作原理
</Button>
</div>
<div className="relative h-[27.5rem] border border-n-1/20 rounded-3xl md:rounded-[2.5rem] lg:flex-1 lg:max-w-[34.625rem] lg:h-[34.5rem] lg:ml-24 xl:h-[36rem] mt-10 lg:mt-0">
<div className="absolute top-[8.5rem] -left-[2rem] w-[21rem] md:w-[25.25rem] md:top-[6.4rem] md:-left-[4.5rem] lg:top-[12rem] lg:-left-[3rem] xl:top-[7.625rem] xl:-left-[4.5rem] xl:w-[32.75rem]">
<Image
className="w-full rounded-xl"
src={item.imageUrl}
width={512}
height={512}
alt="Feature"
/>
</div>
<div className="absolute left-4 right-4 bottom-4 bg-n-8/95 md:left-8 md:right-8 md:bottom-8 rounded-xl">
<Notification
className=""
title={item.notification}
/>
</div>
<div className="absolute top-6 right-6 flex items-center justify-center w-15 h-15 bg-n-1 rounded-full xl:top-8 xl:right-8">
<Image
className=""
src={item.iconUrl}
width={24}
height={24}
alt="Icon"
/>
</div>
<div className="hidden absolute top-0 left-full ml-5 w-full h-full bg-n-8/50 border border-n-1/10 rounded-[2.5rem] md:block"></div>
</div>
</div>
</div>
))}
{/* 简化版导航 */}
<div className="flex justify-center mt-12 gap-4">
{features.map((_, index) => (
<button
key={index}
className={`w-3 h-3 rounded-full transition-colors ${
index === currentFeature ? 'bg-color-1' : 'bg-n-4'
}`}
onClick={() => setCurrentFeature(index)}
/>
))}
</div>
</div>
</Section>
);
};
export default Features;

View File

@@ -0,0 +1,91 @@
import { useRef } from "react";
import { Splide, SplideTrack, SplideSlide } from "@splidejs/react-splide";
import Section from "@/components/Section";
import Button from "@/components/Button";
import Image from "@/components/Image";
import Notification from "@/components/Notification";
import { features } from "@/mocks/features";
import Arrows from "@/components/Arrows";
type FeaturesProps = {};
const Features = ({}: FeaturesProps) => {
const ref = useRef<any>(null);
return (
<Section
className="py-10 md:pb-20 lg:pt-16 lg:pb-32 xl:pb-40 overflow-hidden"
customPaddings
>
<div className="container relative z-2">
<Splide
className="splide-custom splide-visible"
options={{
type: "fade",
rewind: true,
pagination: false,
}}
hasTrack={false}
ref={ref}
>
<SplideTrack>
{features.map((item) => (
<SplideSlide key={item.id}>
<div className="lg:flex" key={item.id}>
<div className="lg:flex lg:flex-col lg:items-start lg:max-w-[18.75rem] lg:mr-auto">
<h2 className="h2 mb-6">
{item.title}
</h2>
<p className="body-2 mb-10 text-n-3">
{item.text}
</p>
<Button>See how it work</Button>
</div>
<Arrows
className="my-10 lg:hidden"
prevClassName="mr-3"
onPrev={() => ref.current?.go("<")}
onNext={() => ref.current?.go(">")}
/>
<div className="relative h-[27.5rem] border border-n-1/20 rounded-3xl md:rounded-[2.5rem] lg:flex-1 lg:max-w-[34.625rem] lg:h-[34.5rem] lg:ml-24 xl:h-[36rem]">
<div className="absolute top-[8.5rem] -left-[2rem] w-[21rem] md:w-[25.25rem] md:top-[6.4rem] md:-left-[4.5rem] lg:top-[12rem] lg:-left-[3rem] xl:top-[7.625rem] xl:-left-[4.5rem] xl:w-[32.75rem]">
<Image
className="w-full"
src={item.imageUrl}
width={512}
height={512}
alt="Figure"
/>
</div>
<Notification
className="absolute left-4 right-4 bottom-4 bg-n-8/95 md:left-8 md:right-8 md:bottom-8"
title={item.notification}
/>
<div className="absolute top-6 right-6 flex items-center justify-center w-15 h-15 bg-n-1 rounded-full xl:top-8 xl:right-8">
<Image
src={item.iconUrl}
width={24}
height={24}
alt="Icon"
/>
</div>
<div className="hidden absolute top-0 left-full ml-5 w-full h-full bg-n-8/50 border border-n-1/10 rounded-[2.5rem] md:block"></div>
</div>
</div>
</SplideSlide>
))}
</SplideTrack>
<Arrows
className="hidden -mt-12 lg:flex"
prevClassName="mr-3"
onPrev={() => ref.current?.go("<")}
onNext={() => ref.current?.go(">")}
/>
</Splide>
</div>
</Section>
);
};
export default Features;

View File

@@ -0,0 +1,236 @@
import { useEffect, useRef, useState } from "react";
// import { MouseParallax, ScrollParallax } from "react-just-parallax";
import Section from "../../../components/Section";
import Button from "../../../components/Button";
import Image from "../../../components/Image";
import Generating from "../../../components/Generating";
import Notification from "../../../components/Notification";
import Logos from "../../../components/Logos";
const Hero = () => {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
const parallaxRef = useRef(null);
return (
<Section
className="-mt-[4.75rem] pt-[8.25rem] pb-4 overflow-hidden md:pt-[9.75rem] md:pb-[4.8rem] lg:-mt-[5.25rem] lg:-mb-40 lg:pt-[12.25rem] lg:pb-[13.8rem]"
crosses
crossesOffset="lg:translate-y-[5.25rem]"
customPaddings
>
{/* 添加深色渐变背景 */}
<div className="absolute inset-0 bg-gradient-to-br from-n-8 via-n-7 to-n-6"></div>
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_center,rgba(172,106,255,0.1)_0%,transparent_70%)]"></div>
<div className="container relative" ref={parallaxRef}>
<div
className="relative z-1 max-w-[62rem] mx-auto mb-[3.875rem] text-center md:mb-20 lg:mb-[6.25rem]"
style={{ position: 'relative', zIndex: 10 }}
>
<h1
className="h1 mb-6"
style={{
color: '#FFFFFF',
fontSize: '3.75rem',
lineHeight: '4.5rem',
fontWeight: '600',
marginBottom: '24px'
}}
>
探索&nbsp;
<span style={{
background: 'linear-gradient(to right, #AC6AFF, #FFC876)',
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
backgroundClip: 'text'
}}>
AI投研
</span>
&nbsp;的无限可能性 {" "}
<span className="inline-block relative">
<span style={{
background: 'linear-gradient(to right, #FFC876, #AC6AFF)',
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
backgroundClip: 'text'
}}>
价值前沿
</span>
<Image
className="absolute top-full left-0 w-full xl:-mt-2"
src="/images/curve.png"
width={624}
height={28}
alt="Curve"
/>
</span>
</h1>
<p
className="body-1 max-w-3xl mx-auto mb-6 lg:mb-8"
style={{
color: '#CAC6DD',
fontSize: '1.25rem',
lineHeight: '2rem',
marginBottom: '32px',
maxWidth: '48rem',
margin: '0 auto 32px'
}}
>
释放AI的力量升级您的投研效率
体验专业的开放式AI投研平台超越传统分析工具
</p>
<Button href="/community" white className="" onClick={null} px="px-7">
开始使用
</Button>
</div>
<div className="relative max-w-[23.25rem] mx-auto md:max-w-5xl xl:mb-24">
<div className="relative z-1 p-0.5 rounded-2xl bg-conic-gradient">
<div className="relative bg-n-8 rounded-[0.875rem]">
<div className="h-[1.375rem] bg-[#43435C] rounded-t-[0.875rem]"></div>
<div className="aspect-[33/40] rounded-b-[0.875rem] overflow-hidden md:aspect-[688/490] lg:aspect-[1024/490]">
<Image
className="w-full scale-[1.7] translate-y-[8%] md:scale-[1] md:-translate-y-[10.5%] lg:-translate-y-[23.5%]"
src="/images/hero/robot.jpg"
width={1024}
height={490}
alt="AI"
/>
</div>
<Generating className="absolute left-4 right-4 bottom-5 md:left-1/2 md:right-auto md:bottom-8 md:w-[30.5rem] md:-translate-x-1/2" />
{/* 简化版本暂时不使用ScrollParallax */}
<div className="hidden absolute -left-[5.5rem] bottom-[7.625rem] px-1 py-1 bg-[#474060]/40 backdrop-blur border border-n-1/10 rounded-2xl xl:flex">
{[
"/images/icons/home-smile.svg",
"/images/icons/file-02.svg",
"/images/icons/search-md.svg",
"/images/icons/plus-square.svg",
].map((icon, index) => (
<div className="p-5" key={index}>
<Image
className=""
src={icon}
width={24}
height={25}
alt={`Icon ${index}`}
/>
</div>
))}
</div>
<div className="hidden absolute -right-[5.5rem] bottom-[11.25rem] w-[18.375rem] xl:flex">
<Notification
className=""
title="AI投研分析完成"
/>
</div>
</div>
</div>
<div className="relative z-1 h-6 mx-2.5 bg-[#1B1B2E] shadow-xl rounded-b-[1.25rem] lg:h-6 lg:mx-8"></div>
<div className="relative z-1 h-6 mx-6 bg-[#1B1B2E]/70 shadow-xl rounded-b-[1.25rem] lg:h-6 lg:mx-20"></div>
<div className="absolute -top-[54%] left-1/2 w-[234%] -translate-x-1/2 md:-top-[46%] md:w-[138%] lg:-top-[104%]">
<Image
className="w-full"
src="/images/hero/background.jpg"
width={1440}
height={1800}
alt="Hero"
/>
</div>
<div className="absolute -top-[42.375rem] left-1/2 w-[78rem] aspect-square border border-n-2/5 rounded-full -translate-x-1/2 md:-top-[38.5rem] xl:-top-[32rem]">
<div className="absolute top-1/2 left-1/2 w-[65.875rem] aspect-square border border-n-2/10 rounded-full -translate-x-1/2 -translate-y-1/2"></div>
<div className="absolute top-1/2 left-1/2 w-[51.375rem] aspect-square border border-n-2/10 rounded-full -translate-x-1/2 -translate-y-1/2"></div>
<div className="absolute top-1/2 left-1/2 w-[36.125rem] aspect-square border border-n-2/10 rounded-full -translate-x-1/2 -translate-y-1/2"></div>
<div className="absolute top-1/2 left-1/2 w-[23.125rem] aspect-square border border-n-2/10 rounded-full -translate-x-1/2 -translate-y-1/2"></div>
{/* 浮动装饰点 */}
<div className="absolute bottom-1/2 left-1/2 w-0.25 h-1/2 origin-bottom rotate-[46deg]">
<div
className={`w-2 h-2 -ml-1 -mt-36 bg-gradient-to-b from-[#DD734F] to-[#1A1A32] rounded-full transition-transform duration-500 ease-out ${
mounted
? "translate-y-0 opacity-100"
: "translate-y-10 opacity-0"
}`}
></div>
</div>
<div className="absolute bottom-1/2 left-1/2 w-0.25 h-1/2 origin-bottom -rotate-[56deg]">
<div
className={`w-4 h-4 -ml-1 -mt-32 bg-gradient-to-b from-[#DD734F] to-[#1A1A32] rounded-full transition-transform duration-500 ease-out ${
mounted
? "translate-y-0 opacity-100"
: "translate-y-10 opacity-0"
}`}
></div>
</div>
<div className="absolute bottom-1/2 left-1/2 w-0.25 h-1/2 origin-bottom rotate-[54deg]">
<div
className={`hidden w-4 h-4 -ml-1 mt-[12.9rem] bg-gradient-to-b from-[#B9AEDF] to-[#1A1A32] rounded-full xl:block transition-transform duration-500 ease-out ${
mounted
? "translate-y-0 opacity-100"
: "translate-y-10 opacity-0"
}`}
></div>
</div>
<div className="absolute bottom-1/2 left-1/2 w-0.25 h-1/2 origin-bottom -rotate-[65deg]">
<div
className={`w-3 h-3 -ml-1.5 mt-52 bg-gradient-to-b from-[#B9AEDF] to-[#1A1A32] rounded-full transition-transform duration-500 ease-out ${
mounted
? "translate-y-0 opacity-100"
: "translate-y-10 opacity-0"
}`}
></div>
</div>
<div className="absolute bottom-1/2 left-1/2 w-0.25 h-1/2 origin-bottom -rotate-[85deg]">
<div
className={`w-6 h-6 -ml-3 -mt-3 bg-gradient-to-b from-[#88E5BE] to-[#1A1A32] rounded-full transition-transform duration-500 ease-out ${
mounted
? "translate-y-0 opacity-100"
: "translate-y-10 opacity-0"
}`}
></div>
</div>
<div className="absolute bottom-1/2 left-1/2 w-0.25 h-1/2 origin-bottom rotate-[70deg]">
<div
className={`w-6 h-6 -ml-3 -mt-3 bg-gradient-to-b from-[#88E5BE] to-[#1A1A32] rounded-full transition-transform duration-500 ease-out ${
mounted
? "translate-y-0 opacity-100"
: "translate-y-10 opacity-0"
}`}
></div>
</div>
</div>
</div>
<Logos className="hidden relative z-10 mt-20 lg:block" />
</div>
<div className="hidden absolute top-[55.25rem] left-10 right-10 h-0.25 bg-n-6 pointer-events-none xl:block"></div>
<svg
className="hidden absolute top-[54.9375rem] left-[2.1875rem] z-2 pointer-events-none xl:block"
width="11"
height="11"
fill="none"
>
<path
d="M7 1a1 1 0 0 0-1-1H5a1 1 0 0 0-1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1h2a1 1 0 0 1 1 1v2a1 1 0 0 0 1 1h1a1 1 0 0 0 1-1V8a1 1 0 0 1 1-1h2a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H8a1 1 0 0 1-1-1V1z"
fill="#ada8c4"
/>
</svg>
<svg
className="hidden absolute top-[54.9375rem] right-[2.1875rem] z-2 pointer-events-none xl:block"
width="11"
height="11"
fill="none"
>
<path
d="M7 1a1 1 0 0 0-1-1H5a1 1 0 0 0-1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1h2a1 1 0 0 1 1 1v2a1 1 0 0 0 1 1h1a1 1 0 0 0 1-1V8a1 1 0 0 1 1-1h2a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H8a1 1 0 0 1-1-1V1z"
fill="#ada8c4"
/>
</svg>
</Section>
);
};
export default Hero;

View File

@@ -0,0 +1,152 @@
import { useRef, useState } from "react";
import { Splide, SplideTrack, SplideSlide } from "@splidejs/react-splide";
import Section from "@/components/Section";
import Image from "@/components/Image";
import Button from "@/components/Button";
import Tagline from "@/components/Tagline";
import Arrows from "@/components/Arrows";
import { howItWorks } from "@/mocks/how-it-works";
type HowItWorksProps = {};
const HowItWorks = ({}: HowItWorksProps) => {
const [activeIndex, setActiveIndex] = useState<number>(0);
const ref = useRef<any>(null);
const handleClick = (index: number) => {
setActiveIndex(index);
ref.current?.go(index);
};
return (
<Section className="lg:-mb-16" crosses>
<div className="container">
<Splide
className="splide-custom"
options={{
type: "fade",
rewind: true,
pagination: false,
}}
hasTrack={false}
ref={ref}
>
<SplideTrack>
{howItWorks.map((item, index) => (
<SplideSlide key={item.id}>
<div className="lg:flex lg:flex-row-reverse lg:items-center">
<div className="">
<Tagline className="mb-4 lg:mb-6">
How it work: 0{index + 1}.
</Tagline>
<h2 className="h2 mb-4 lg:mb-6">
{item.title}
</h2>
<p className="body-2 mb-10 text-n-3">
{item.text}
</p>
<Button href="/login">
Connect now
</Button>
<Arrows
className="my-10 lg:hidden"
prevClassName="mr-3"
onPrev={() => ref.current?.go("<")}
onNext={() => ref.current?.go(">")}
/>
</div>
<div className="relative lg:w-[29.375rem] lg:flex-shrink-0 lg:mr-[7.125rem] xl:w-[34.375rem] xl:mr-40">
<div className="pt-0.25 pl-0.25 overflow-hidden bg-gradient-to-tl from-n-1/0 via-n-1/0 to-n-1/15 rounded-3xl">
<div className="h-[30.5rem] bg-n-7 rounded-[1.4375rem] xl:h-[35.625rem]">
<Image
className="w-full h-full object-contain"
src={item.image}
width={550}
height={570}
alt={item.title}
/>
<div className="absolute left-4 right-4 bottom-4 flex items-center h-16 px-5 bg-n-8 border border-n-1/10 rounded-xl lg:left-6 lg:right-6 lg:bottom-6">
<div className="flex items-center justify-center w-6 h-6 mr-5 bg-color-1 rounded-full">
<svg
className="w-2.5 h-2.5 fill-n-1"
viewBox="0 0 10 10"
>
<path d="M5 0a1 1 0 0 1 .993.883L6 1v3h3a1 1 0 0 1 .117 1.993L9 6H6v3a1 1 0 0 1-1.993.117L4 9V6H1a1 1 0 0 1-.117-1.993L1 4h3V1a1 1 0 0 1 1-1z" />
</svg>
</div>
<div className="text-base text-n-3/75">
Ask anything
</div>
<div className="w-6 h-6 ml-auto opacity-50">
<Image
className="w-full"
src="/images/icons/recording-01.svg"
width={24}
height={24}
alt="Recording"
/>
</div>
</div>
</div>
</div>
<div className="absolute -right-6 top-8 bottom-8 w-6 bg-[#1B1B2E] rounded-r-3xl"></div>
<div className="absolute -right-12 top-16 bottom-16 w-6 bg-[#1B1B2E]/50 rounded-r-3xl"></div>
</div>
</div>
</SplideSlide>
))}
</SplideTrack>
<Arrows
className="hidden justify-center mt-12 lg:flex lg:mt-15 xl:hidden"
prevClassName="mr-3"
onPrev={() => ref.current?.go("<")}
onNext={() => ref.current?.go(">")}
/>
<div className="absolute top-0 -left-[10rem] w-[29.5rem] h-[29.5rem] mix-blend-color-dodge opacity-20 pointer-events-none">
<Image
className="absolute top-1/2 left-1/2 w-[55.5rem] max-w-[55.5rem] h-[61.5rem] -translate-x-1/2 -translate-y-1/2"
src="/images/how-it-works/gradient.png"
width={984}
height={984}
alt="Gradient"
/>
</div>
<div className="hidden grid-cols-4 gap-6 mt-20 xl:grid">
{howItWorks.map((item, index) => (
<div
className="group cursor-pointer"
onClick={() => handleClick(index)}
key={item.id}
>
<div
className={`h-[0.125rem] mb-10 transition-colors ${
index === activeIndex
? "bg-color-1"
: "bg-[#D9D9D9]/10 group-hover:bg-[#D9D9D9]/50"
}`}
></div>
<div className="tagline mb-1 text-n-3">
0{index + 1}.
</div>
<h2 className="mb-[0.625rem] text-2xl leading-8">
{item.title}
</h2>
<p
className={`body-2 text-n-3 line-clamp-3 transition-opacity ${
index !== activeIndex && "opacity-0"
}`}
>
{item.text}
</p>
</div>
))}
</div>
</Splide>
</div>
</Section>
);
};
export default HowItWorks;

View File

@@ -0,0 +1,69 @@
import Link from "next/link";
import Section from "@/components/Section";
import Image from "@/components/Image";
import Heading from "@/components/Heading";
import PricingList from "@/components/PricingList";
type PricingProps = {};
const Pricing = ({}: PricingProps) => {
return (
<Section className="overflow-hidden">
<div className="container relative z-2">
<div className="hidden relative justify-center mb-[6.5rem] lg:flex">
<Image
className="relative z-1"
src="/images/figures/4-small.png"
width={255}
height={255}
alt="Sphere"
/>
<div className="absolute top-1/2 left-1/2 w-[59.5rem] -translate-x-1/2 -translate-y-1/2 pointer-events-none">
<Image
className="w-full"
src="/images/pricing/stars.svg"
width={952}
height={396}
alt="Stars"
/>
</div>
</div>
<Heading
tag="Get started with Brainwave"
title="Pay once, use forever"
/>
<div className="relative">
<PricingList />
<div className="hidden lg:block absolute top-1/2 right-full w-[92.5rem] h-[11.0625rem] -translate-y-1/2 pointer-events-none">
<Image
className="w-full"
src="/images/pricing/lines.svg"
width={1480}
height={177}
alt="Lines"
/>
</div>
<div className="hidden lg:block absolute top-1/2 left-full w-[92.5rem] h-[11.0625rem] -translate-y-1/2 -scale-x-100 pointer-events-none">
<Image
className="w-full"
src="/images/pricing/lines.svg"
width={1480}
height={177}
alt="Lines"
/>
</div>
</div>
<div className="flex justify-center mt-8 md:mt-15 xl:mt-20">
<Link
className="text-xs font-code font-bold tracking-wider uppercase border-b border-n-1 transition-colors hover:border-n-1/0"
href="/pricing"
>
See the full details
</Link>
</div>
</div>
</Section>
);
};
export default Pricing;

View File

@@ -0,0 +1,97 @@
import Section from "@/components/Section";
import Tagline from "@/components/Tagline";
import Image from "@/components/Image";
import { roadmap } from "@/mocks/roadmap";
import Button from "@/components/Button";
import Heading from "@/components/Heading";
type RoadmapProps = {};
const Roadmap = ({}: RoadmapProps) => (
<Section className="overflow-hidden">
<div className="container md:pb-10">
<Heading tag="Ready to get started" title="What were working on" />
<div className="relative grid gap-6 md:grid-cols-2 md:gap-4 md:pb-[7rem]">
{roadmap.map((item, index) => (
<div
className={`md:flex ${
index % 2 !== 0 ? "md:translate-y-[7rem]" : ""
} p-0.25 rounded-[2.5rem] ${
item.colorful ? "bg-conic-gradient" : "bg-n-6"
}`}
key={item.id}
>
<div className="relative p-8 bg-n-8 rounded-[2.4375rem] overflow-hidden xl:p-15">
<div className="absolute top-0 left-0 max-w-full">
<Image
className="w-full"
src="/images/grid.png"
width={550}
height={550}
alt="Grid"
/>
</div>
<div className="relative z-1">
<div className="flex items-center justify-between max-w-[27rem] mb-8 md:mb-20">
<Tagline>{item.date}</Tagline>
<div className="flex items-center px-4 py-1 bg-n-1 rounded text-n-8">
<Image
className="mr-2.5"
src={
item.status === "done"
? "/images/icons/check.svg"
: "/images/icons/loading-01.svg"
}
width={16}
height={16}
alt={
item.status === "done"
? "Done"
: "In progress"
}
/>
<div className="tagline">
{item.status === "done"
? "Done"
: "In progress"}
</div>
</div>
</div>
<div className="mb-8 md:mb-20">
<div className="-my-10 -mx-15">
<Image
className="w-full"
src={item.imageUrl}
width={628}
height={426}
alt={item.title}
/>
</div>
</div>
<h4 className="h4 mb-4">{item.title}</h4>
<p className="body-2 text-n-4">{item.text}</p>
</div>
</div>
</div>
))}
<div className="absolute top-[18.25rem] -left-[30.375rem] w-[56.625rem] opacity-60 mix-blend-color-dodge pointer-events-none">
<div className="absolute top-1/2 left-1/2 w-[58.85rem] h-[58.85rem] -translate-x-3/4 -translate-y-1/2">
<Image
className="w-full"
src="/images/gradient.png"
width={942}
height={942}
alt="Gradient"
/>
</div>
</div>
</div>
<div className="flex justify-center mt-12 md:mt-15 xl:mt-20">
<Button href="/roadmap">Our roadmap</Button>
</div>
</div>
</Section>
);
export default Roadmap;

View File

@@ -0,0 +1,90 @@
import { Splide, SplideTrack, SplideSlide } from "@splidejs/react-splide";
import Section from "@/components/Section";
import Tagline from "@/components/Tagline";
import Button from "@/components/Button";
import Image from "@/components/Image";
import { testimonials } from "@/mocks/testimonials";
import Arrows from "@/components/Arrows";
import Heading from "@/components/Heading";
type TestimonialsProps = {};
const Testimonials = ({}: TestimonialsProps) => (
<Section className="overflow-hidden">
<div className="container relative z-2">
<Heading
tag="Ready to get started"
title="What the community is saying"
/>
<Splide
className="splide-custom splide-visible"
options={{
mediaQuery: "min",
gap: "1.5rem",
breakpoints: {
1024: {
autoWidth: true,
},
},
rewind: true,
pagination: false,
}}
hasTrack={false}
>
<SplideTrack>
{testimonials.map((item) => (
<SplideSlide key={item.id}>
<div className="relative flex h-full p-4 rounded-t-xl overflow-hidden lg:w-[46.125rem]">
<div className="absolute top-0 left-0 right-0 bottom-[3.25rem] border border-n-4/50 rounded-3xl"></div>
<div className="absolute inset-px rounded-t-[1.4375rem] overflow-hidden">
<div className="absolute -inset-0.25">
<Image
className="w-full h-full object-cover"
src={item.imageUrl}
width={739}
height={472}
alt={item.name}
/>
</div>
</div>
<div className="absolute inset-0 bg-gradient-to-r from-n-8/50 to-n-8/0"></div>
<div className="hidden relative z-1 md:flex flex-col flex-1 pt-12 px-4 pb-16">
<div className="w-[12.75rem] h-10 mb-auto">
<Image
className="w-full h-full object-contain"
src={item.logoUrl}
width={204}
height={40}
alt={item.name}
/>
</div>
<div className="h5">{item.name}</div>
<div className="h5 text-n-4">
{item.role}
</div>
</div>
<div className="relative flex z-1 bg-conic-gradient p-0.25 rounded-2xl md:ml-auto">
<div className="flex flex-col items-start p-8 bg-n-8 rounded-[0.9375rem] md:w-[21.75rem]">
<p className="quote mb-8">
{item.text}
</p>
<Button className="mt-auto">
Visit link
</Button>
</div>
</div>
</div>
</SplideSlide>
))}
</SplideTrack>
<Arrows
className="justify-center mt-12 md:mt-15 xl:mt-20"
prevClassName="mr-8"
/>
</Splide>
</div>
</Section>
);
export default Testimonials;

View File

@@ -0,0 +1,31 @@
import Layout from "../../components/Layout/index.js";
import Hero from "./Hero/index.js";
import Benefits from "./Benefits/index.js";
import Features from "./Features/index.js";
// import Collaboration from "./Collaboration";
// import HowItWorks from "./HowItWorks";
// import Pricing from "./Pricing";
// import Testimonials from "./Testimonials";
// import Roadmap from "./Roadmap";
// import Services from "../../components/Services";
// import Join from "../../components/Join";
const HomePage = () => {
return (
<Layout>
<Hero />
<Benefits />
<Features />
{/* 其他组件将在后续逐步修复 */}
{/* <Collaboration />
<HowItWorks />
<Services />
<Pricing />
<Testimonials />
<Roadmap />
<Join /> */}
</Layout>
);
};
export default HomePage;