80 lines
11 KiB
TypeScript
80 lines
11 KiB
TypeScript
/**
|
||
* 公开落地页的客户端展示组件。包含品牌导航、可点击的创作示意图、功能说明、工作方式、FAQ与登录/演示入口。
|
||
* 示意卡片只改变本页高亮,不创建真实画布元素;本模块不读取账号、不调用编辑器,也不持久化状态。
|
||
*/
|
||
"use client";
|
||
|
||
import { useState } from "react";
|
||
import Link from "next/link";
|
||
import { ArrowUpRight, ArrowRight, ChevronDown, FileText, Image as ImageIcon, Layers, MousePointer2, Plus, Sparkles, Type } from "lucide-react";
|
||
import { Brand } from "@/components/brand";
|
||
import styles from "./landing-page.module.css";
|
||
|
||
/** 三个示意卡片对应的页脚说明;数组索引与active及预览按钮一一对应。 */
|
||
const cards = ["先留住一个念头", "让不同的线索相遇", "慢慢成为你的作品"];
|
||
/** FAQ静态问答数据;这里只呈现文案,访问权限与演示存储的实际执行在对应业务模块中。 */
|
||
const questions = [
|
||
["还没想好要做什么,也可以开始吗?", "当然。一个词、一张参考图、一段还不成形的想法,都可以成为起点。先放下来,再慢慢找到它们之间的联系。"],
|
||
["我可以放些什么在画布里?", "文字、笔记、图片、脚本和图标。你可以自由移动、调整样式、用线连接,也可以用分区把相关内容放在一起。"],
|
||
["我的创作会自动公开吗?", "不会。工作空间需要登录访问,内容的访问范围由空间和材料权限控制。"],
|
||
["可以先体验,再注册吗?", "可以。点击「先逛逛工作台」进入本地演示。演示内容保留在当前浏览器,登录后可以建立自己的工作空间。"],
|
||
];
|
||
|
||
/** 本页只有两个交互状态:预览卡片单选,以及最多展开一个问题的FAQ。
|
||
* 导航锚点定位本页三个section;登录入口进入/login,本地演示入口携带demo=1进入工作台。
|
||
* 主体的SVG连线、花朵、光标和功能插图是展示图形,不接入画布命中、拖动或同步链路。 */
|
||
export default function LandingPage() {
|
||
// 初始选中第一张预览卡;三张卡片与底部三个圆点均直接设置同一个索引,aria-pressed同步表达选择。
|
||
const [active, setActive] = useState(0);
|
||
// null表示全部收起;点击当前问题置null,点击其它问题改索引。hidden与aria-expanded/controls对应同一状态。
|
||
const [faq, setFaq] = useState<number | null>(null);
|
||
// 页面顺序:导航→首屏交互预览→理念横条→三个功能说明→工作步骤→FAQ→行动入口→页脚。
|
||
// 功能卡与步骤通过静态内容展示;FAQ以问题文本作key,步骤以序号作key,预览以说明作key。
|
||
// 状态仅在本次组件挂载期间保留;切换预览不自动轮播,FAQ展开不发网络请求。
|
||
return <div className="landing"><div className={styles.page}>
|
||
<header className={styles.nav}>
|
||
<Brand />
|
||
<nav aria-label="主导航"><a href="#space">创作空间</a><a href="#workflow">工作方式</a><a href="#questions">一些问题</a></nav>
|
||
<div className={styles.navActions}><Link href="/login">登录</Link><Link href="/login" className={styles.smallCta}>开始创作 <ArrowUpRight size={15} /></Link></div>
|
||
</header>
|
||
<main>
|
||
<section className={styles.hero}>
|
||
<div className={styles.heroCopy}>
|
||
<div className={styles.eyebrow}><span className={styles.statusDot} /> A LITTLE SPACE. ENDLESS POSSIBILITIES.</div>
|
||
<h1>给想法一点<br /><span>自由生长</span>的空间。</h1>
|
||
<p>不必一开始就井井有条。<br />把零散的灵感放下来,连接起来,<br className={styles.mobileBreak} />慢慢做成自己的作品。</p>
|
||
<div className={styles.heroActions}><Link href="/login" className={styles.primary}>打开你的创作空间 <ArrowUpRight size={18} /></Link><Link href="/dashboard?demo=1" className={styles.textLink}>先逛逛工作台 <ArrowRight size={16} /></Link></div>
|
||
<div className={styles.heroNote}><span className={styles.scribbleStar}>✳</span> 留一点空白,给还没发生的好想法。</div>
|
||
</div>
|
||
<div className={styles.preview} aria-label="创作空间交互预览">
|
||
<div className={styles.previewHeading}><span><span className={styles.tinyLogo}>↗</span> 一些还不错的想法 <ChevronDown size={11} /></span><span>PRIVATE SPACE</span></div>
|
||
<div className={styles.scene}>
|
||
<svg className={styles.wires} viewBox="0 0 600 440" fill="none" aria-hidden="true"><path d="M250 177 C335 177 315 137 393 137" /><path d="M416 220 C416 300 255 290 255 336" /><circle cx="250" cy="177" r="3" /><circle cx="393" cy="137" r="3" /><circle cx="416" cy="220" r="3" /><circle cx="255" cy="336" r="3" /></svg>
|
||
<button className={`${styles.ideaCard} ${active === 0 ? styles.activeCard : ""}`} aria-pressed={active === 0} onClick={() => setActive(0)}><span className={styles.cardLabel}><FileText size={12} /> 随手记下</span><strong>如果灵感<br />有自己的形状?</strong><span className={styles.cardText}>也许从一片叶子,<br />或一个突然冒出来的问题开始。</span><span className={styles.paperCorner} /></button>
|
||
<button className={`${styles.artCard} ${active === 1 ? styles.activeCard : ""}`} aria-pressed={active === 1} onClick={() => setActive(1)}><span className={styles.cardLabel}><ImageIcon size={12} /> 一点视觉线索</span><svg viewBox="0 0 180 200" aria-hidden="true"><path d="M92 164C89 133 94 111 94 88M94 125C72 125 59 110 57 94C78 91 90 105 94 125M94 143C118 143 134 129 137 110C112 107 96 123 94 143" /><path d="M93 88C47 109 32 78 60 62C35 32 67 11 87 43C96 7 130 18 116 50C151 37 168 66 132 79C158 104 119 121 101 89" /><circle cx="95" cy="68" r="13" /><path d="M67 173C85 168 108 170 126 175" /></svg><span className={styles.artCaption}>ordinary things, new eyes.</span></button>
|
||
<button className={`${styles.noteCard} ${active === 2 ? styles.activeCard : ""}`} aria-pressed={active === 2} onClick={() => setActive(2)}><span className={styles.cardLabel}><Sparkles size={12} /> 连接之后</span><strong>把日常,<br />做成一点不日常。</strong><span className={styles.noteTag}>下一个小作品 ↗</span></button>
|
||
<span className={styles.looseNote}>keep wondering.</span><div className={styles.cursor} aria-hidden="true"><MousePointer2 size={21} fill="currentColor" /><span>你</span></div>
|
||
</div>
|
||
<div className={styles.previewFooter}><div aria-label="预览选择">{cards.map((label, index) => <button key={label} aria-label={label} aria-pressed={active === index} onClick={() => setActive(index)} />)}</div><span>{cards[active]}</span><span>100%</span></div>
|
||
</div>
|
||
</section>
|
||
<div className={styles.manifestoStrip}><span>FOR THE CURIOUS MINDS.</span><p>认真生活的人,<span>总有一些想法值得留下。</span></p><span>COLLECT / CONNECT / CREATE</span></div>
|
||
<section id="space" className={styles.space}>
|
||
<div className={styles.sectionHeading}><div><div className={styles.eyebrow}>01 — YOUR THINKING SPACE</div><h2>思路可以自由,<br />也可以有迹可循。</h2></div><p>从随手收集,到看见联系。<br />把整理变成创作的一部分。</p></div>
|
||
<div className={styles.featureGrid}>
|
||
<article><div className={`${styles.featureArt} ${styles.collectArt}`} aria-hidden="true"><span><Type size={18} /> 一句还没写完的话</span><span><ImageIcon size={18} /> 某个让你停下来的画面</span><span><Sparkles size={18} /> 一点突如其来的好奇心</span></div><span className={styles.featureNumber}>01 / COLLECT</span><h3>先留下,再想一想。</h3><p>文字、图片、参考和碎片。灵感来的时候,<br />不需要先决定它应该放在哪个文件夹。</p></article>
|
||
<article><div className={`${styles.featureArt} ${styles.connectArt}`} aria-hidden="true"><svg viewBox="0 0 320 170" fill="none"><path d="M68 57C150 57 130 115 220 115M220 115C240 115 250 60 280 60" /></svg><span>一个念头</span><span>另一种可能</span><i>✳</i></div><span className={styles.featureNumber}>02 / CONNECT</span><h3>让线索,自己说话。</h3><p>在无限画布上自由摆放、连接与分组。<br />原本无关的东西,也许正好能碰出火花。</p></article>
|
||
<article><div className={`${styles.featureArt} ${styles.createArt}`} aria-hidden="true"><div><span>UNTITLED PROJECT</span><strong>想法,有形。</strong><span>文字 × 图像 × 你自己的表达</span></div><span className={styles.editBadge}><Layers size={13} /> 持续打磨中</span></div><span className={styles.featureNumber}>03 / CREATE</span><h3>慢慢变成,你的作品。</h3><p>调整文字、图标和画面细节。<br />让收集的每一点灵感,都有继续生长的可能。</p></article>
|
||
</div>
|
||
</section>
|
||
<section id="workflow" className={styles.workflow}>
|
||
<div className={styles.quote}><span className={styles.quoteMark}>“</span><h2>不急着有答案。<br />先和自己的想法,<em>待一会儿。</em></h2><p>一个属于你的工作空间,<br />也是一张可以反复涂改的草稿纸。</p><span className={styles.signature}>a work in progress, always.</span></div>
|
||
<div className={styles.workflowList}>{[["01", "带着一点好奇,开始。", "从一张空白画布,或一个还没想好的念头出发。"], ["02", "把线索,放在一起。", "拖动、连接、分区,让自己的思路慢慢清晰。"], ["03", "继续打磨,不必着急完成。", "随时回来,加一点新想法,留下新的可能。"]].map(([number, title, copy]) => <div key={number}><span>{number}</span><div><h3>{title}</h3><p>{copy}</p></div><ArrowUpRight size={18} /></div>)}</div>
|
||
</section>
|
||
<section id="questions" className={styles.faq}><div><div className={styles.eyebrow}>A FEW THINGS TO KNOW</div><h2>开始之前,<br />你也许想知道。</h2></div><div>{questions.map(([question, answer], index) => <div className={styles.faqItem} key={question}><button aria-expanded={faq === index} aria-controls={`landing-faq-${index}`} onClick={() => setFaq(faq === index ? null : index)}><span>{question}</span><Plus size={17} style={{ rotate: faq === index ? "45deg" : "0deg" }} /></button><div id={`landing-faq-${index}`} hidden={faq !== index}><p>{answer}</p></div></div>)}</div></section>
|
||
<section className={styles.closing}><span className={styles.closingDoodle} aria-hidden="true">✳</span><div className={styles.eyebrow}>YOUR NEXT IDEA STARTS HERE</div><h2>好想法,<br className={styles.mobileBreak} />值得一个好地方。</h2><p>不用准备好全部。带着一点好奇,先开始。</p><Link href="/login" className={styles.primary}>给想法留个位置 <ArrowUpRight size={18} /></Link></section>
|
||
</main>
|
||
<footer className={styles.footer}><Brand /><p>给想法留白,给创作空间。</p><a href="#space">回到创作空间 <ArrowUpRight size={14} /></a><span>© 2026 ENDOLEAP</span></footer>
|
||
</div></div>;
|
||
}
|