Skip to content

Commit dd04158

Browse files
committed
feat: 完善 NoteGen 样式复刻组件库
1 parent 8031592 commit dd04158

12 files changed

Lines changed: 608 additions & 45 deletions

‎app/[lang]/components/component-gallery.tsx‎

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@ import {
2121

2222
import {
2323
NoteGenDesktopReplica,
24+
NoteGenAgentPanel,
25+
NoteGenActivityHeatmap,
26+
NoteGenAppShell,
27+
NoteGenCanvasWorkspace,
28+
NoteGenConfirmationDialog,
29+
NoteGenDialogBackdrop,
30+
NoteGenEditorWorkspace,
31+
NoteGenGlobalSearch,
32+
NoteGenImageViewer,
33+
NoteGenMobileReplica,
34+
NoteGenRecordingOverlay,
35+
NoteGenRecordWorkspace,
2436
NoteGenReplicaFrame,
2537
NoteGenReplicaIconButton,
2638
NoteGenReplicaMenuGroup,
@@ -30,9 +42,11 @@ import {
3042
NoteGenSettingSegmentedControl,
3143
NoteGenSettingSelect,
3244
NoteGenSettingsPage,
33-
NoteGenSettingsReplica,
45+
NoteGenSettingsDialogReplica,
3446
NoteGenSettingsSection,
3547
NoteGenSettingSwitch,
48+
NoteGenSyncStatus,
49+
NoteGenUpdatePrompt,
3650
NoteGenWindowTitleBar,
3751
NoteGenWorkspaceSwitcher,
3852
type NoteGenReplicaLanguage,
@@ -65,6 +79,9 @@ export function NoteGenComponentGallery({ lang }: { lang: NoteGenReplicaLanguage
6579
const navigation = [
6680
["desktop", text("完整应用", "Desktop app")],
6781
["chrome", text("窗口与工具栏", "Chrome and toolbars")],
82+
["workspaces", text("核心工作区", "Core workspaces")],
83+
["mobile", text("移动端", "Mobile")],
84+
["overlays", text("弹窗与状态", "Overlays and states")],
6885
["settings-primitives", text("设置组件", "Settings primitives")],
6986
["settings", text("完整设置页", "Settings page")],
7087
]
@@ -185,9 +202,52 @@ export function NoteGenComponentGallery({ lang }: { lang: NoteGenReplicaLanguage
185202
</div>
186203
</GallerySection>
187204

205+
<GallerySection
206+
id="workspaces"
207+
eyebrow="03 · Workspace replicas"
208+
title={text("记录、写作、Agent 与画布", "Capture, writing, Agent, and canvas")}
209+
description={text("每个工作区都由更小的列表、工具栏、内容区和状态组件组合而成。", "Each workspace is composed from smaller lists, toolbars, content areas, and state components.")}
210+
>
211+
<div className="grid gap-6">
212+
<ComponentCard title="NoteGenRecordWorkspace" description={text("记录列表与详情", "Capture list and detail")}><div className="h-[520px] overflow-hidden rounded-lg border"><NoteGenRecordWorkspace lang={lang} /></div></ComponentCard>
213+
<ComponentCard title="NoteGenEditorWorkspace" description={text("文件树、标签页与 Markdown 编辑器", "File tree, tabs, and Markdown editor")}><div className="h-[520px] overflow-hidden rounded-lg border"><NoteGenEditorWorkspace lang={lang} /></div></ComponentCard>
214+
<div className="grid gap-6 xl:grid-cols-2">
215+
<ComponentCard title="NoteGenAgentPanel" description={text("消息、思考过程、工具调用与上下文", "Messages, reasoning, tool calls, and context")}><div className="h-[560px] overflow-hidden rounded-lg border"><NoteGenAgentPanel lang={lang} /></div></ComponentCard>
216+
<ComponentCard title="NoteGenCanvasWorkspace" description={text("画布项目、节点、连线和缩放工具", "Canvas projects, nodes, edges, and zoom tools")}><div className="h-[560px] overflow-hidden rounded-lg border"><NoteGenCanvasWorkspace lang={lang} /></div></ComponentCard>
217+
</div>
218+
<ComponentCard title="NoteGenAppShell" description={text("当前桌面外壳:平台窗口控制、记录工具与状态栏", "Current desktop shell with platform controls, capture toolbar, and status bar")}><NoteGenAppShell lang={lang}><div className="grid h-full grid-cols-[28%_42%_30%]"><div className="border-r"><NoteGenRecordWorkspace lang={lang} /></div><div className="border-r"><NoteGenEditorWorkspace lang={lang} /></div><NoteGenAgentPanel lang={lang} /></div></NoteGenAppShell></ComponentCard>
219+
</div>
220+
</GallerySection>
221+
222+
<GallerySection
223+
id="mobile"
224+
eyebrow="04 · Mobile replicas"
225+
title={text("移动端核心页面", "Core mobile screens")}
226+
description={text("移动端使用独立的手机框架、状态栏、页面标题和底部导航,可按 screen 属性直接切换展示。", "Mobile uses a dedicated device frame, status bar, headers, and dock. Select a screen through a single prop.")}
227+
>
228+
<div className="grid gap-6 sm:grid-cols-2 xl:grid-cols-5">
229+
{(["capture", "chat", "writing", "canvas", "settings"] as const).map((screen) => <ComponentCard key={screen} title={`Mobile · ${screen}`} description={text("代码实时渲染", "Rendered live from code")}><NoteGenMobileReplica lang={lang} screen={screen} /></ComponentCard>)}
230+
</div>
231+
</GallerySection>
232+
233+
<GallerySection
234+
id="overlays"
235+
eyebrow="05 · Dialogs and states"
236+
title={text("全局弹窗、录音与同步状态", "Global dialogs, recording, and sync states")}
237+
description={text("用于文档说明搜索、录音、同步、冲突、图片预览和关闭确认等瞬时界面。", "Transient UI for documenting search, recording, sync, conflicts, image viewing, and close confirmation.")}
238+
>
239+
<div className="grid gap-6 lg:grid-cols-2">
240+
<ComponentCard title="NoteGenGlobalSearch" description={text("全局搜索面板", "Global search palette")}><NoteGenDialogBackdrop><NoteGenGlobalSearch lang={lang} /></NoteGenDialogBackdrop></ComponentCard>
241+
<ComponentCard title="NoteGenRecordingOverlay" description={text("悬浮录音状态", "Floating recording state")}><NoteGenDialogBackdrop><NoteGenRecordingOverlay lang={lang} /></NoteGenDialogBackdrop></ComponentCard>
242+
<ComponentCard title="NoteGenSyncStatus" description={text("同步完成与冲突状态", "Sync and conflict states")}><div className="flex min-h-64 flex-col items-center justify-center gap-3 rounded-xl border bg-muted/25 p-4"><NoteGenSyncStatus lang={lang} /><NoteGenSyncStatus lang={lang} state="conflict" /></div></ComponentCard>
243+
<ComponentCard title="ImageViewer · Confirmation" description={text("图片预览与关闭确认", "Image viewer and close confirmation")}><NoteGenDialogBackdrop className="min-h-72"><NoteGenImageViewer lang={lang} /><div className="absolute bottom-4 right-4 z-20 w-64"><NoteGenConfirmationDialog lang={lang} /></div></NoteGenDialogBackdrop></ComponentCard>
244+
<ComponentCard title="Update · Activity" description={text("更新提示与写作活动", "Update prompt and writing activity")}><div className="grid min-h-72 gap-3 rounded-xl border bg-muted/25 p-4 sm:grid-cols-2"><NoteGenUpdatePrompt lang={lang} /><NoteGenActivityHeatmap lang={lang} /></div></ComponentCard>
245+
</div>
246+
</GallerySection>
247+
188248
<GallerySection
189249
id="settings-primitives"
190-
eyebrow="03 · Settings primitives"
250+
eyebrow="06 · Settings primitives"
191251
title={text("从一个控件到完整设置分组", "From one control to a complete settings section")}
192252
description={text(
193253
"设置页的页面标题、分组、设置项和操作控件都可以单独导入,用真实组件还原任意设置文档。",
@@ -258,16 +318,14 @@ export function NoteGenComponentGallery({ lang }: { lang: NoteGenReplicaLanguage
258318

259319
<GallerySection
260320
id="settings"
261-
eyebrow="04 · NoteGenSettingsReplica"
321+
eyebrow="07 · NoteGenSettingsReplica"
262322
title={text("完整设置页", "Complete settings page")}
263323
description={text(
264324
"搜索左侧设置项,切换导航,并操作常规设置中的主题与开关。这个完整场景也可以直接放进文档页面。",
265325
"Search the sidebar, switch sections, and interact with theme and behavior controls. This complete scene can also be embedded directly in documentation."
266326
)}
267327
>
268-
<div className="h-[720px] overflow-hidden rounded-2xl border bg-background shadow-xl">
269-
<NoteGenSettingsReplica lang={lang} />
270-
</div>
328+
<NoteGenSettingsDialogReplica lang={lang} className="h-[760px]" />
271329
</GallerySection>
272330
</div>
273331

‎components/notegen/README.md‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# NoteGen replica components
22

3+
This folder contains style-only, code-native replicas for documentation and marketing pages. They do not connect to NoteGen stores, Tauri, databases, file APIs, or AI services.
4+
5+
## Component families
6+
7+
- `app-shell-replica`: platform window controls, capture toolbar, panel handle, app shell, and status bar.
8+
- `record-replica`: tag chips, capture filters, list items, audio waveform, sidebar, and detail view.
9+
- `file-editor-replica`: file tree, tabs, editor toolbar, bubble menu, document page, and editor status.
10+
- `agent-replica`: message bubbles, thinking block, tool calls, execution timeline, context tray, and composer.
11+
- `canvas-replica`: project cards, canvas tools, nodes, edges, grid, and zoom footer.
12+
- `settings-replica`: reusable setting rows plus all current NoteGen settings categories and dialog presentation.
13+
- `mobile-replica`: phone frame, status bar, dock, capture, Agent, writing, and settings screens.
14+
- `feedback-replica`: global search, recording, sync states, image viewer, confirmation, and activity heatmap.
15+
16+
Import every public component from `@/components/notegen`. Display-state props only change the rendered appearance; they intentionally do not implement product behavior.
17+
318
Code-native NoteGen interface replicas for documentation and marketing pages. Import from `@/components/notegen` when composing a complete scene, or import a specific file when the component is used inside the replica implementation.
419

520
```tsx
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import type { ReactNode } from "react"
2+
import {
3+
Bot,
4+
Brain,
5+
Check,
6+
ChevronDown,
7+
Circle,
8+
Clock3,
9+
Copy,
10+
FileText,
11+
Globe2,
12+
History,
13+
Paperclip,
14+
Plus,
15+
Search,
16+
Send,
17+
ShieldCheck,
18+
Sparkles,
19+
Terminal,
20+
User,
21+
Wrench,
22+
} from "lucide-react"
23+
24+
import type { NoteGenReplicaLanguage } from "@/components/notegen/types"
25+
import { cn } from "@/lib/utils"
26+
27+
export function NoteGenAgentHeader({ lang = "cn" }: { lang?: NoteGenReplicaLanguage }) {
28+
return <header className="flex h-10 items-center gap-2 border-b px-3"><Bot className="size-4" /><span className="font-medium">{lang === "en" ? "NoteGen Agent" : "NoteGen 助手"}</span><span className="rounded-full bg-emerald-500/10 px-2 py-0.5 text-[7px] text-emerald-600">GPT-5</span><div className="ml-auto flex gap-2 text-muted-foreground"><Search className="size-3.5" /><History className="size-3.5" /><Plus className="size-3.5" /></div></header>
29+
}
30+
31+
export function NoteGenAgentMessage({ role, children, time = "10:28" }: { role: "user" | "assistant"; children: ReactNode; time?: string }) {
32+
const Icon = role === "assistant" ? Sparkles : User
33+
return <div className={cn("flex gap-2.5", role === "user" && "flex-row-reverse")}><span className={cn("flex size-6 shrink-0 items-center justify-center rounded-full border", role === "assistant" ? "bg-foreground text-background" : "bg-muted")}><Icon className="size-3" /></span><div className={cn("max-w-[82%]", role === "user" && "text-right")}><div className={cn("rounded-xl px-3 py-2 text-left text-[9px] leading-4", role === "assistant" ? "rounded-tl-sm bg-muted/60" : "rounded-tr-sm bg-foreground text-background")}>{children}</div><span className="mt-1 block text-[7px] text-muted-foreground">{time}</span></div></div>
34+
}
35+
36+
export function NoteGenThinkingBlock({ lang = "cn" }: { lang?: NoteGenReplicaLanguage }) {
37+
return <div className="rounded-lg border bg-muted/20 p-2.5"><div className="flex items-center gap-2 text-[8px] font-medium"><Brain className="size-3.5" />{lang === "en" ? "Thinking" : "思考过程"}<ChevronDown className="ml-auto size-3 text-muted-foreground" /></div><p className="mt-2 border-l pl-2 text-[8px] leading-4 text-muted-foreground">{lang === "en" ? "I’ll compare the selected notes, identify repeated ideas, and preserve the original references." : "我会对比选中的笔记,识别重复观点,并保留原始引用。"}</p></div>
38+
}
39+
40+
export function NoteGenToolCall({ type = "search", lang = "cn", status = "done" }: { type?: "search" | "file" | "terminal"; lang?: NoteGenReplicaLanguage; status?: "running" | "done" }) {
41+
const icons = { search: Globe2, file: FileText, terminal: Terminal }
42+
const Icon = icons[type]
43+
const labels = { search: lang === "en" ? "Search workspace" : "搜索工作区", file: lang === "en" ? "Read document" : "读取文档", terminal: lang === "en" ? "Run tool" : "运行工具" }
44+
return <div className="flex items-center gap-2 rounded-md border bg-background px-2.5 py-2"><span className="flex size-6 items-center justify-center rounded bg-muted"><Icon className="size-3" /></span><div className="min-w-0 flex-1"><div className="text-[8px] font-medium">{labels[type]}</div><div className="truncate text-[7px] text-muted-foreground">{type === "file" ? "notes/product/design.md" : "NoteGen design principles"}</div></div>{status === "done" ? <Check className="size-3 text-emerald-500" /> : <Clock3 className="size-3 animate-pulse text-muted-foreground" />}</div>
45+
}
46+
47+
export function NoteGenExecutionTimeline({ lang = "cn" }: { lang?: NoteGenReplicaLanguage }) {
48+
return <div className="rounded-lg border p-2.5"><div className="mb-2 flex items-center gap-2 text-[8px] font-medium"><Wrench className="size-3.5" />{lang === "en" ? "3 actions completed" : "已完成 3 个操作"}</div><div className="space-y-1.5"><NoteGenToolCall lang={lang} /><NoteGenToolCall lang={lang} type="file" /><NoteGenToolCall lang={lang} type="terminal" /></div></div>
49+
}
50+
51+
export function NoteGenAgentApproval({ lang = "cn" }: { lang?: NoteGenReplicaLanguage }) {
52+
return <div className="rounded-lg border border-amber-500/35 bg-amber-500/5 p-3"><div className="flex items-start gap-2"><ShieldCheck className="mt-0.5 size-4 text-amber-600" /><div><h4 className="text-[9px] font-medium">{lang === "en" ? "Permission required" : "需要你的确认"}</h4><p className="mt-1 text-[8px] leading-4 text-muted-foreground">{lang === "en" ? "Allow Agent to update notes/product/design.md?" : "允许 Agent 更新 notes/product/design.md?"}</p></div></div><div className="mt-3 flex justify-end gap-2"><span className="rounded-md border bg-background px-2.5 py-1 text-[8px]">{lang === "en" ? "Deny" : "拒绝"}</span><span className="rounded-md bg-foreground px-2.5 py-1 text-[8px] text-background">{lang === "en" ? "Allow" : "允许"}</span></div></div>
53+
}
54+
55+
export function NoteGenAgentMessageActions({ lang = "cn" }: { lang?: NoteGenReplicaLanguage }) {
56+
return <div className="inline-flex items-center gap-1 rounded-md border bg-background p-1 text-muted-foreground shadow-xs"><span className="flex size-6 items-center justify-center"><Copy className="size-3" /></span><span className="flex size-6 items-center justify-center"><Check className="size-3" /></span><span className="px-1 text-[7px]">{lang === "en" ? "Insert into note" : "插入笔记"}</span></div>
57+
}
58+
59+
export function NoteGenAgentModelControl({ lang = "cn" }: { lang?: NoteGenReplicaLanguage }) {
60+
return <div className="flex items-center gap-1.5"><span className="flex items-center gap-1 rounded-md border px-2 py-1 text-[7px]"><Bot className="size-3" />GPT-5<ChevronDown className="size-2.5" /></span><span className="flex items-center gap-1 rounded-md border px-2 py-1 text-[7px]"><ShieldCheck className="size-3" />{lang === "en" ? "Ask first" : "操作前询问"}<ChevronDown className="size-2.5" /></span></div>
61+
}
62+
63+
export function NoteGenContextTray({ lang = "cn" }: { lang?: NoteGenReplicaLanguage }) {
64+
return <div className="flex items-center gap-1.5 overflow-hidden border-t px-3 py-2"><span className="flex items-center gap-1.5 rounded-md border bg-muted/30 px-2 py-1 text-[7px]"><FileText className="size-3" />design.md <span className="text-muted-foreground">4.2k</span></span><span className="flex items-center gap-1.5 rounded-md border bg-muted/30 px-2 py-1 text-[7px]"><Circle className="size-2 fill-violet-500 text-violet-500" />{lang === "en" ? "Product notes" : "产品笔记"}</span><span className="ml-auto text-[7px] text-muted-foreground">12k / 128k</span></div>
65+
}
66+
67+
export function NoteGenAgentComposer({ lang = "cn" }: { lang?: NoteGenReplicaLanguage }) {
68+
return <div className="m-2 rounded-xl border bg-background p-2 shadow-sm"><p className="min-h-10 px-1 text-[9px] text-muted-foreground">{lang === "en" ? "Ask about your notes, or describe what to create…" : "询问笔记内容,或描述你想创建的内容……"}</p><div className="flex items-center gap-2 text-muted-foreground"><Paperclip className="size-3.5" /><NoteGenAgentModelControl lang={lang} /><span className="ml-auto flex size-7 items-center justify-center rounded-lg bg-foreground text-background"><Send className="size-3" /></span></div></div>
69+
}
70+
71+
export function NoteGenAgentPanel({ lang = "cn", className }: { lang?: NoteGenReplicaLanguage; className?: string }) {
72+
return <aside className={cn("flex h-full min-h-0 flex-col bg-background", className)}><NoteGenAgentHeader lang={lang} /><div className="min-h-0 flex-1 space-y-4 overflow-hidden p-3"><NoteGenAgentMessage role="user">{lang === "en" ? "Turn these fragments into a short design note." : "把这些碎片整理成一篇简短的设计说明。"}</NoteGenAgentMessage><NoteGenAgentMessage role="assistant"><div className="space-y-2"><NoteGenThinkingBlock lang={lang} /><NoteGenExecutionTimeline lang={lang} /><p>{lang === "en" ? "I found three recurring principles: low interruption, progressive structure, and visible context." : "我找到三个反复出现的原则:低打扰、渐进式结构和始终可见的上下文。"}</p></div></NoteGenAgentMessage></div><NoteGenContextTray lang={lang} /><NoteGenAgentComposer lang={lang} /></aside>
73+
}

0 commit comments

Comments
 (0)