feat(help): 新增应用内帮助页 /help(功能介绍 + 新手上手)
- 暖深色英雄 + 快速上手三步 + 三个核心理念 + 功能一览(写作/资料库/审阅/工具全局) + 顺手小技巧 + 常见问题,全部用设计系统组件与语义 token - 内容对齐 PRODUCT_SPEC:立项→设定→大纲→写章→四审→验收、四审四维、多提供商网关、单一真相源 - 顶栏新增「帮助」入口(FileQuestion → /help)
This commit is contained in:
298
apps/web/app/help/page.tsx
Normal file
298
apps/web/app/help/page.tsx
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
import type { LucideIcon } from "lucide-react";
|
||||||
|
import {
|
||||||
|
BookMarked,
|
||||||
|
BookOpen,
|
||||||
|
Blocks,
|
||||||
|
CheckCircle2,
|
||||||
|
ClipboardCheck,
|
||||||
|
FileText,
|
||||||
|
Flag,
|
||||||
|
LayoutGrid,
|
||||||
|
ListTree,
|
||||||
|
Moon,
|
||||||
|
PanelLeftClose,
|
||||||
|
PenLine,
|
||||||
|
Route,
|
||||||
|
Search,
|
||||||
|
Settings,
|
||||||
|
ShieldCheck,
|
||||||
|
Sparkles,
|
||||||
|
} from "lucide-react";
|
||||||
|
|
||||||
|
import { AppShell } from "@/components/AppShell";
|
||||||
|
import { Badge } from "@/components/ui/Badge";
|
||||||
|
import { Card } from "@/components/ui/Card";
|
||||||
|
import { Eyebrow } from "@/components/ui/Eyebrow";
|
||||||
|
import { PageContainer } from "@/components/ui/PageContainer";
|
||||||
|
import { buttonClass } from "@/lib/ui/variants";
|
||||||
|
|
||||||
|
// 帮助中心:功能介绍 + 新手上手(静态内容,Server Component)。
|
||||||
|
|
||||||
|
interface Step {
|
||||||
|
icon: LucideIcon;
|
||||||
|
title: string;
|
||||||
|
body: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const STEPS: Step[] = [
|
||||||
|
{
|
||||||
|
icon: PenLine,
|
||||||
|
title: "立项,或直接开始写",
|
||||||
|
body: "从一句灵感开始:点「先立项」从核心卖点搭好世界观、人物与大纲;或「直接开始写」落笔即成书,边写边补设定。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Sparkles,
|
||||||
|
title: "让 AI 写这章",
|
||||||
|
body: "在写作台告诉 AI 这章想怎么写,它对着大纲给出草稿(流式出稿)。你可以续写接着写、润色选段、或整章重写——原文永远你说了算。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: ClipboardCheck,
|
||||||
|
title: "四审,然后验收",
|
||||||
|
body: "写完点「审稿」,AI 从一致性 / 伏笔 / 文风 / 节奏四个维度逐条检查、就地标注冲突。你裁决后验收,系统更新真相源与伏笔账本。",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
interface Principle {
|
||||||
|
title: string;
|
||||||
|
body: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PRINCIPLES: Principle[] = [
|
||||||
|
{
|
||||||
|
title: "把写小说当软件工程",
|
||||||
|
body: "先立架构(世界观 + 人物 + 大纲),再对着规格逐章生成,每章写完即测,全程维护单一真相源。不让 AI 一口气瞎写十万字。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "单一真相源 · 记忆不衰减",
|
||||||
|
body: "设定、状态、伏笔集中记账;AI 写每一章都按需读取相关记忆(确定性选择,非一次性塞满上下文),对抗长篇遗忘。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "你始终掌控",
|
||||||
|
body: "AI 是灵感增幅器 + 质检员,不是全自动黑箱。四审只读、只给建议,任何写入都要你裁决采纳,不会静默覆盖你的原文。",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
interface Feature {
|
||||||
|
icon: LucideIcon;
|
||||||
|
name: string;
|
||||||
|
desc: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FeatureGroup {
|
||||||
|
label: string;
|
||||||
|
features: Feature[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const FEATURE_GROUPS: FeatureGroup[] = [
|
||||||
|
{
|
||||||
|
label: "写作",
|
||||||
|
features: [
|
||||||
|
{
|
||||||
|
icon: PenLine,
|
||||||
|
name: "写作台",
|
||||||
|
desc: "对着大纲逐章生成、流式出稿;续写接着写、润色选段、整章重写,随时进入专注模式沉浸写作。",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "资料库",
|
||||||
|
features: [
|
||||||
|
{ icon: ListTree, name: "大纲", desc: "卷 → 章 → 场景逐层细化,像模块分解,场景约等于一个函数。" },
|
||||||
|
{ icon: BookMarked, name: "设定库", desc: "世界观圣经 + 人物卡(动机/目标像接口约束行为)+ 关系图谱。" },
|
||||||
|
{ icon: Flag, name: "伏笔", desc: "「埋设 → 回收」的显式账本,逾期未收自动提醒,不再漏坑。" },
|
||||||
|
{ icon: FileText, name: "文风", desc: "抽取你的文风指纹并注入生成,抵抗机翻腔与风格漂移。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "审阅",
|
||||||
|
features: [
|
||||||
|
{
|
||||||
|
icon: ClipboardCheck,
|
||||||
|
name: "审稿 · 四审",
|
||||||
|
desc: "每章写完即审:一致性 / 伏笔 / 文风 / 节奏,冲突就地标注、逐条裁决后验收。",
|
||||||
|
},
|
||||||
|
{ icon: Route, name: "多章链", desc: "把多章连成工作流链,批量推进与联审。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "工具与全局",
|
||||||
|
features: [
|
||||||
|
{ icon: Blocks, name: "工具箱", desc: "通用生成器:角色、世界观、大纲等批量产出并入库。" },
|
||||||
|
{ icon: ShieldCheck, name: "规则", desc: "沉淀你的创作规则(四级规则),约束 AI 少犯同类错。" },
|
||||||
|
{ icon: LayoutGrid, name: "模板库", desc: "可复用的题材/结构模板,立项时一键套用。" },
|
||||||
|
{ icon: Settings, name: "设置", desc: "写手 / 分析 / 轻量三档模型路由 + API Key / Kimi OAuth。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
interface Tip {
|
||||||
|
icon: LucideIcon;
|
||||||
|
title: string;
|
||||||
|
body: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TIPS: Tip[] = [
|
||||||
|
{ icon: Search, title: "命令面板 ⌘K", body: "任意页面按 ⌘K 快速跳转页面或执行命令。" },
|
||||||
|
{ icon: PanelLeftClose, title: "专注写作模式", body: "写作台底栏点「专注」,隐藏侧栏、加宽正文,沉浸写作。" },
|
||||||
|
{ icon: Moon, title: "夜读模式", body: "顶栏月亮图标切换暖色夜读,长时间写作更护眼。" },
|
||||||
|
{ icon: CheckCircle2, title: "原文永远你说了算", body: "AI 给的是草稿,采不采用由你定,绝不静默覆盖你的正文。" },
|
||||||
|
];
|
||||||
|
|
||||||
|
interface Faq {
|
||||||
|
q: string;
|
||||||
|
a: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FAQS: Faq[] = [
|
||||||
|
{
|
||||||
|
q: "AI 会自动改我的正文吗?",
|
||||||
|
a: "不会。四审是只读的、只给建议;任何写入都要你在验收环节裁决,冲突未解决会阻止验收。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: "用的是哪个大模型?",
|
||||||
|
a: "后端是多提供商网关,写手 / 分析 / 轻量三档可各自路由(Claude / DeepSeek / Kimi / GPT / Gemini / 通义 / GLM 等,可回退),在「设置 → 模型与提供商」里配。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: "写到几十万字会不会记忆衰减?",
|
||||||
|
a: "靠单一真相源 + 按需记忆注入:写每章只挑相关的设定、角色与最近若干章,而不是把全书塞进上下文。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: "我的数据在哪里?",
|
||||||
|
a: "本地 Postgres,单用户原型;设定/正文/审稿结果都以数据库为唯一真相源,记忆追加保留历史、不就地覆盖。",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function SectionTitle({ eyebrow, title }: { eyebrow: string; title: string }) {
|
||||||
|
return (
|
||||||
|
<div className="mb-5">
|
||||||
|
<Eyebrow className="mb-1.5">{eyebrow}</Eyebrow>
|
||||||
|
<h2 className="font-serif text-display-sm text-ink">{title}</h2>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function IconChip({ icon: Icon }: { icon: LucideIcon }) {
|
||||||
|
return (
|
||||||
|
<span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-md bg-[var(--color-cinnabar-wash)] text-cinnabar">
|
||||||
|
<Icon className="h-4 w-4" aria-hidden="true" />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function HelpPage() {
|
||||||
|
return (
|
||||||
|
<AppShell>
|
||||||
|
<PageContainer>
|
||||||
|
{/* 英雄:暖深色编辑部条(对标 DESIGN.md cta-band-dark)。 */}
|
||||||
|
<section className="mb-12 rounded-xl border border-line/50 bg-callout px-8 py-12 shadow-paper sm:px-10">
|
||||||
|
<Eyebrow className="text-on-callout-soft">墨痕 · 使用指南</Eyebrow>
|
||||||
|
<h1 className="mt-3 max-w-2xl font-serif text-display-md text-on-callout">
|
||||||
|
把写小说,当软件工程来做
|
||||||
|
</h1>
|
||||||
|
<p className="mt-4 max-w-2xl text-body leading-7 text-on-callout-soft">
|
||||||
|
立项 → 设定 → 大纲 → 写章 → 四审 → 验收。先立架构再对着规格生成,每章写完即测,全程维护单一真相源。下面三步带你上手,并逐一介绍每个功能。
|
||||||
|
</p>
|
||||||
|
<div className="mt-6 flex flex-wrap gap-2">
|
||||||
|
<Link href="/write" className={buttonClass({ variant: "primary" })}>
|
||||||
|
<PenLine className="h-4 w-4" aria-hidden="true" />
|
||||||
|
直接开始写
|
||||||
|
</Link>
|
||||||
|
<Link href="/projects/new" className={buttonClass({ variant: "secondary" })}>
|
||||||
|
先立项
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* 新手三步 */}
|
||||||
|
<section className="mb-14">
|
||||||
|
<SectionTitle eyebrow="快速上手" title="三步写出第一章" />
|
||||||
|
<ol className="grid gap-4 sm:grid-cols-3">
|
||||||
|
{STEPS.map((step, i) => (
|
||||||
|
<li key={step.title}>
|
||||||
|
<Card tone="card" className="flex h-full flex-col gap-3 p-5">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<IconChip icon={step.icon} />
|
||||||
|
<span className="font-mono text-caption text-muted-soft">
|
||||||
|
第 {i + 1} 步
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<h3 className="font-serif text-title-md text-ink">{step.title}</h3>
|
||||||
|
<p className="text-caption leading-6 text-ink-soft">{step.body}</p>
|
||||||
|
</Card>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ol>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* 核心理念 */}
|
||||||
|
<section className="mb-14">
|
||||||
|
<SectionTitle eyebrow="为什么这样设计" title="三个核心理念" />
|
||||||
|
<div className="grid gap-4 sm:grid-cols-3">
|
||||||
|
{PRINCIPLES.map((p) => (
|
||||||
|
<Card key={p.title} tone="soft" flat className="p-5">
|
||||||
|
<h3 className="font-serif text-title-md text-ink">{p.title}</h3>
|
||||||
|
<p className="mt-2 text-caption leading-6 text-ink-soft">{p.body}</p>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* 功能一览 */}
|
||||||
|
<section className="mb-14">
|
||||||
|
<SectionTitle eyebrow="功能介绍" title="每个板块是做什么的" />
|
||||||
|
<div className="space-y-8">
|
||||||
|
{FEATURE_GROUPS.map((group) => (
|
||||||
|
<div key={group.label}>
|
||||||
|
<h3 className="mb-3 flex items-center gap-2 font-sans text-title-md text-ink">
|
||||||
|
{group.label}
|
||||||
|
<Badge variant="neutral">{group.features.length}</Badge>
|
||||||
|
</h3>
|
||||||
|
<div className="grid gap-4 sm:grid-cols-2">
|
||||||
|
{group.features.map((f) => (
|
||||||
|
<Card key={f.name} className="flex gap-3 p-4">
|
||||||
|
<IconChip icon={f.icon} />
|
||||||
|
<div className="min-w-0">
|
||||||
|
<p className="font-serif text-title-md text-ink">{f.name}</p>
|
||||||
|
<p className="mt-1 text-caption leading-6 text-ink-soft">{f.desc}</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* 小技巧 */}
|
||||||
|
<section className="mb-14">
|
||||||
|
<SectionTitle eyebrow="顺手小技巧" title="用得更顺" />
|
||||||
|
<div className="grid gap-4 sm:grid-cols-2">
|
||||||
|
{TIPS.map((t) => (
|
||||||
|
<div key={t.title} className="flex gap-3">
|
||||||
|
<IconChip icon={t.icon} />
|
||||||
|
<div className="min-w-0">
|
||||||
|
<p className="font-medium text-ink">{t.title}</p>
|
||||||
|
<p className="mt-0.5 text-caption leading-6 text-ink-soft">{t.body}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* 常见问题 */}
|
||||||
|
<section>
|
||||||
|
<SectionTitle eyebrow="常见问题" title="你可能想问" />
|
||||||
|
<dl className="space-y-3">
|
||||||
|
{FAQS.map((f) => (
|
||||||
|
<Card key={f.q} as="div" className="p-5">
|
||||||
|
<dt className="font-serif text-title-md text-ink">{f.q}</dt>
|
||||||
|
<dd className="mt-2 text-caption leading-6 text-ink-soft">{f.a}</dd>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</dl>
|
||||||
|
</section>
|
||||||
|
</PageContainer>
|
||||||
|
</AppShell>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
import { Settings } from "lucide-react";
|
import { FileQuestion, Settings } from "lucide-react";
|
||||||
|
|
||||||
import type { ActiveNav } from "@/lib/nav/items";
|
import type { ActiveNav } from "@/lib/nav/items";
|
||||||
import { buttonClass, focusRing } from "@/lib/ui/variants";
|
import { buttonClass, focusRing } from "@/lib/ui/variants";
|
||||||
@@ -68,6 +68,19 @@ export function AppShell({
|
|||||||
>
|
>
|
||||||
<CommandSearchButton />
|
<CommandSearchButton />
|
||||||
<ThemeToggle />
|
<ThemeToggle />
|
||||||
|
<Link
|
||||||
|
href="/help"
|
||||||
|
aria-label="帮助"
|
||||||
|
title="帮助"
|
||||||
|
className={buttonClass({
|
||||||
|
variant: "ghost",
|
||||||
|
size: "sm",
|
||||||
|
className: "border-transparent",
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<FileQuestion className="h-4 w-4" aria-hidden="true" />
|
||||||
|
<span className="hidden sm:inline">帮助</span>
|
||||||
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
href="/settings/providers"
|
href="/settings/providers"
|
||||||
aria-label="设置"
|
aria-label="设置"
|
||||||
|
|||||||
Reference in New Issue
Block a user