Files
timi-tdesign-mobile/docs/.vitepress/components.ts
T
2026-09-21 16:05:14 +08:00

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);
}