181 lines
5.8 KiB
TypeScript
181 lines
5.8 KiB
TypeScript
/**
|
|
* 组件元数据清单。
|
|
*
|
|
* 这是文档站的唯一数据源,三处消费它:
|
|
* - `config.ts` 生成侧边栏导航
|
|
* - `plugins/docgen.ts` 按 `entry` 定位源码并交给 vue-docgen-api 解析
|
|
* - 页面内的 `<api-table />` 按 `name` 查询解析结果
|
|
*
|
|
* 新增组件时只需在此追加一项,导航、API 表、文档路由会同步生效。
|
|
*/
|
|
|
|
/** 分类展示顺序即数组顺序。 */
|
|
export const CATEGORY_LIST = [
|
|
"布局组件",
|
|
"编辑器组件",
|
|
"交互组件",
|
|
"AI 对话组件"
|
|
] as const;
|
|
|
|
export type ComponentCategory = (typeof CATEGORY_LIST)[number];
|
|
|
|
export interface ComponentMeta {
|
|
/** 组件名,与组件内 `defineOptions` 的 name 一致,同时是 api-table 的查询键。 */
|
|
name: string;
|
|
/** 文档与侧边栏展示的中文标题。 */
|
|
title: string;
|
|
/** 一句话功能描述。 */
|
|
description: string;
|
|
/** 所属分类。 */
|
|
category: ComponentCategory;
|
|
/** 组件入口源码,相对仓库根目录。 */
|
|
entry: string;
|
|
/** 文档路径覆盖,默认由文件名或目录名推导。 */
|
|
slug?: string;
|
|
}
|
|
|
|
export const COMPONENT_LIST: ComponentMeta[] = [
|
|
// ---------- 布局组件 ----------
|
|
{
|
|
name: "RootLayout",
|
|
title: "RootLayout 根布局",
|
|
description: "移动端页面骨架,主体内容之外自动渲染版权与备案信息。",
|
|
category: "布局组件",
|
|
entry: "src/components/root-layout/index.vue"
|
|
},
|
|
{
|
|
name: "Space",
|
|
title: "Space 间距",
|
|
description: "控制子元素之间的间距与排列方向,支持分隔符。",
|
|
category: "布局组件",
|
|
entry: "src/components/space/index.vue"
|
|
},
|
|
|
|
// ---------- 编辑器组件 ----------
|
|
{
|
|
name: "CodeEditor",
|
|
title: "CodeEditor 代码编辑器",
|
|
description: "带行号、语法高亮与查找替换的代码输入框。",
|
|
category: "编辑器组件",
|
|
entry: "src/components/code-editor/index.vue"
|
|
},
|
|
{
|
|
name: "TiptapEditor",
|
|
title: "TiptapEditor 富文本编辑器",
|
|
description: "基于 Tiptap 的富文本编辑器,工具栏覆盖媒体、表格、链接与代码块。",
|
|
category: "编辑器组件",
|
|
entry: "src/components/tiptap-editor/index.vue"
|
|
},
|
|
{
|
|
name: "TiptapView",
|
|
title: "TiptapView 富文本视图",
|
|
description: "Tiptap 内容的只读渲染视图,与编辑器共用同一套样式。",
|
|
category: "编辑器组件",
|
|
entry: "src/components/tiptap-view/index.vue"
|
|
},
|
|
{
|
|
name: "ArticleEditor",
|
|
title: "ArticleEditor 文章编辑器",
|
|
description: "以 Article 为数据模型,按正文类型切换纯文本、Markdown 与富文本编辑。",
|
|
category: "编辑器组件",
|
|
entry: "src/components/article-editor/index.vue"
|
|
},
|
|
{
|
|
name: "ArticleView",
|
|
title: "ArticleView 文章视图",
|
|
description: "按 Article 的正文类型渲染正文与附件列表。",
|
|
category: "编辑器组件",
|
|
entry: "src/components/article-view/index.vue"
|
|
},
|
|
{
|
|
name: "NotifyEditor",
|
|
title: "NotifyEditor 通知编辑器",
|
|
description: "以 NotifyDetail 为数据模型的通知编辑表单,复用文章编辑器能力。",
|
|
category: "编辑器组件",
|
|
entry: "src/components/notify-editor/index.vue"
|
|
},
|
|
{
|
|
name: "NotifyView",
|
|
title: "NotifyView 通知视图",
|
|
description: "渲染通知的正文内容。",
|
|
category: "编辑器组件",
|
|
entry: "src/components/notify-view/index.vue"
|
|
},
|
|
|
|
// ---------- 交互组件 ----------
|
|
{
|
|
name: "BottomPopup",
|
|
title: "BottomPopup 底部弹层",
|
|
description: "从底部升起的操作面板,可带标题与左右按钮。",
|
|
category: "交互组件",
|
|
entry: "src/components/bottom-popup/index.vue"
|
|
},
|
|
{
|
|
name: "DurationPicker",
|
|
title: "DurationPicker 时长选择",
|
|
description: "按时长值选择并回填,单位与候选项由外部决定。",
|
|
category: "交互组件",
|
|
entry: "src/components/duration-picker/index.vue"
|
|
},
|
|
|
|
// ---------- AI 对话组件 ----------
|
|
{
|
|
name: "AiChatPanel",
|
|
title: "AiChatPanel 对话面板",
|
|
description: "把消息列表与输入框组装成完整对话界面,由业务侧驱动数据。",
|
|
category: "AI 对话组件",
|
|
entry: "src/components/ai/AiChatPanel.vue"
|
|
},
|
|
{
|
|
name: "AiChatMessageList",
|
|
title: "AiChatMessageList 消息列表",
|
|
description: "渲染对话消息,含思考过程、引用与流式光标。",
|
|
category: "AI 对话组件",
|
|
entry: "src/components/ai/AiChatMessageList.vue"
|
|
},
|
|
{
|
|
name: "AiChatComposer",
|
|
title: "AiChatComposer 输入框",
|
|
description: "对话输入框,按状态在发送、停止与重试之间切换。",
|
|
category: "AI 对话组件",
|
|
entry: "src/components/ai/AiChatComposer.vue"
|
|
},
|
|
{
|
|
name: "AiChatThinking",
|
|
title: "AiChatThinking 思考过程",
|
|
description: "折叠展示模型的思考分段,生成中自动展开。",
|
|
category: "AI 对话组件",
|
|
entry: "src/components/ai/AiChatThinking.vue"
|
|
}
|
|
];
|
|
|
|
/**
|
|
* 文档路径与路由片段。
|
|
*
|
|
* `index.vue` 取所在目录名,具名文件取文件名——`ai` 目录下有多个组件,
|
|
* 只靠目录名会全部撞成 `ai`。两种写法都会再转成短横线形式。
|
|
*/
|
|
export function toSlug(meta: ComponentMeta): string {
|
|
if (meta.slug) {
|
|
return meta.slug;
|
|
}
|
|
const segments = meta.entry.split("/");
|
|
const fileName = segments[segments.length - 1];
|
|
const baseName = fileName.replace(/\.\w+$/, "");
|
|
const raw = baseName === "index" ? segments[segments.length - 2] : baseName;
|
|
return raw.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
}
|
|
|
|
/** 组件文档页的站内绝对路径。 */
|
|
export function toDocLink(meta: ComponentMeta): string {
|
|
return `/components/${toSlug(meta)}`;
|
|
}
|
|
|
|
/** 按分类分组,保持 CATEGORY_LIST 的声明顺序。 */
|
|
export function groupByCategory(): Array<{ category: ComponentCategory; items: ComponentMeta[] }> {
|
|
return CATEGORY_LIST.map(category => ({
|
|
category,
|
|
items: COMPONENT_LIST.filter(item => item.category === category)
|
|
})).filter(group => group.items.length > 0);
|
|
}
|