/** * Catalog 定义 - 使用 Zod schemas 定义组件 props */ import { z } from 'zod'; import { defineSchema, defineCatalog } from '@json-render/core'; // 使用 defineSchema 定义 schema const schema = defineSchema((s) => ({ spec: s.object({ type: s.ref('catalog.components'), props: s.propsOf('catalog.components'), }), catalog: s.object({ components: s.map({ props: s.zod(), description: s.string(), }), }), })); // 组件 props Zod schemas export const CardProps = z.object({ title: z.string().optional(), variant: z.enum(['default', 'outlined', 'elevated']).optional(), className: z.string().optional(), }); export const StackProps = z.object({ direction: z.enum(['row', 'column']).optional(), spacing: z.number().optional(), align: z.enum(['start', 'center', 'end', 'stretch']).optional(), className: z.string().optional(), }); export const HeadingProps = z.object({ text: z.string(), level: z.enum(['h1', 'h2', 'h3', 'h4', 'h5', 'h6']).optional(), className: z.string().optional(), }); export const TextProps = z.object({ text: z.string(), size: z.enum(['xs', 'sm', 'md', 'lg', 'xl']).optional(), color: z.enum(['default', 'muted', 'primary', 'success', 'warning', 'destructive']).optional(), className: z.string().optional(), }); export const ButtonProps = z.object({ label: z.string(), variant: z.enum(['default', 'primary', 'secondary', 'outline', 'ghost', 'destructive']).optional(), onClick: z.string().optional(), disabled: z.boolean().optional(), className: z.string().optional(), }); export const BadgeProps = z.object({ text: z.string(), variant: z.enum(['default', 'primary', 'secondary', 'success', 'warning', 'destructive']).optional(), className: z.string().optional(), }); export const SeparatorProps = z.object({ orientation: z.enum(['horizontal', 'vertical']).optional(), className: z.string().optional(), }); export const InputProps = z.object({ placeholder: z.string().optional(), type: z.enum(['text', 'password', 'email', 'number']).optional(), disabled: z.boolean().optional(), className: z.string().optional(), }); export const TextAreaProps = z.object({ placeholder: z.string().optional(), rows: z.number().optional(), disabled: z.boolean().optional(), className: z.string().optional(), }); export const DataTableProps = z.object({ columns: z.array(z.object({ key: z.string(), label: z.string(), })).optional(), data: z.array(z.record(z.string(), z.any())).optional(), className: z.string().optional(), }); // MCP 专用组件 props export const TranslationResultProps = z.object({ original: z.string().optional(), translated: z.string(), termsUsed: z.array(z.string()).optional(), className: z.string().optional(), }); export const NovelListProps = z.object({ novels: z.array(z.object({ id: z.union([z.string(), z.number()]), title: z.string(), author: z.string().optional(), description: z.string().optional(), chapterCount: z.number().optional(), tags: z.array(z.string()).optional(), })), className: z.string().optional(), }); export const ChapterReaderProps = z.object({ novelTitle: z.string().optional(), chapterTitle: z.string().optional(), content: z.string(), chapterNumber: z.number().optional(), totalChapters: z.number().optional(), className: z.string().optional(), }); export const CodeBlockProps = z.object({ code: z.string(), language: z.string().optional(), className: z.string().optional(), }); export const ToolCallProps = z.object({ toolName: z.string(), status: z.enum(['pending', 'running', 'success', 'error']).optional(), result: z.any().optional(), className: z.string().optional(), }); export const LoginPanelProps = z.object({ serverName: z.string().optional(), onLogin: z.string().optional(), className: z.string().optional(), }); export const McpStatusProps = z.object({ serverId: z.string(), connected: z.boolean(), className: z.string().optional(), }); export const SuggestionButtonsProps = z.object({ suggestions: z.array(z.object({ label: z.string(), message: z.string().optional(), icon: z.string().optional(), })), className: z.string().optional(), }); // 创建 catalog const catalog = defineCatalog(schema, { components: { card: { props: CardProps, description: '卡片容器组件,用于包装内容区块', }, stack: { props: StackProps, description: '布局容器组件,支持水平和垂直排列', }, heading: { props: HeadingProps, description: '标题组件', }, text: { props: TextProps, description: '文本组件', }, button: { props: ButtonProps, description: '按钮组件', }, badge: { props: BadgeProps, description: '徽章组件,用于标签和状态标识', }, separator: { props: SeparatorProps, description: '分隔线组件', }, input: { props: InputProps, description: '输入框组件', }, 'text-area': { props: TextAreaProps, description: '多行文本输入组件', }, 'data-table': { props: DataTableProps, description: '数据表格组件', }, 'translation-result': { props: TranslationResultProps, description: '翻译结果展示组件', }, 'novel-list': { props: NovelListProps, description: '小说列表组件', }, 'chapter-reader': { props: ChapterReaderProps, description: '章节阅读器组件', }, 'code-block': { props: CodeBlockProps, description: '代码块组件,支持语法高亮', }, 'tool-call': { props: ToolCallProps, description: 'MCP 工具调用状态组件', }, 'login-panel': { props: LoginPanelProps, description: 'MCP 登录面板组件', }, 'mcp-status': { props: McpStatusProps, description: 'MCP 服务器状态组件', }, 'suggestion-buttons': { props: SuggestionButtonsProps, description: '建议按钮组组件,用于快速选择预定义消息', }, }, }); export default catalog; export { schema }; // 兼容旧的导出 export interface GetCatalogPromptOptions { mode?: 'standalone' | 'inline'; } export function getCatalogPrompt(options?: GetCatalogPromptOptions): string { return catalog.prompt({ mode: options?.mode ?? 'inline' }); }