catalog.ts 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /**
  2. * Catalog 定义 - 使用 Zod schemas 定义组件 props
  3. */
  4. import { z } from 'zod';
  5. import { defineSchema, defineCatalog } from '@json-render/core';
  6. // 使用 defineSchema 定义 schema
  7. const schema = defineSchema((s) => ({
  8. spec: s.object({
  9. type: s.ref('catalog.components'),
  10. props: s.propsOf('catalog.components'),
  11. }),
  12. catalog: s.object({
  13. components: s.map({
  14. props: s.zod(),
  15. description: s.string(),
  16. }),
  17. }),
  18. }));
  19. // 组件 props Zod schemas
  20. export const CardProps = z.object({
  21. title: z.string().optional(),
  22. variant: z.enum(['default', 'outlined', 'elevated']).optional(),
  23. className: z.string().optional(),
  24. });
  25. export const StackProps = z.object({
  26. direction: z.enum(['row', 'column']).optional(),
  27. spacing: z.number().optional(),
  28. align: z.enum(['start', 'center', 'end', 'stretch']).optional(),
  29. className: z.string().optional(),
  30. });
  31. export const HeadingProps = z.object({
  32. text: z.string(),
  33. level: z.enum(['h1', 'h2', 'h3', 'h4', 'h5', 'h6']).optional(),
  34. className: z.string().optional(),
  35. });
  36. export const TextProps = z.object({
  37. text: z.string(),
  38. size: z.enum(['xs', 'sm', 'md', 'lg', 'xl']).optional(),
  39. color: z.enum(['default', 'muted', 'primary', 'success', 'warning', 'destructive']).optional(),
  40. className: z.string().optional(),
  41. });
  42. export const ButtonProps = z.object({
  43. label: z.string(),
  44. variant: z.enum(['default', 'primary', 'secondary', 'outline', 'ghost', 'destructive']).optional(),
  45. onClick: z.string().optional(),
  46. disabled: z.boolean().optional(),
  47. className: z.string().optional(),
  48. });
  49. export const BadgeProps = z.object({
  50. text: z.string(),
  51. variant: z.enum(['default', 'primary', 'secondary', 'success', 'warning', 'destructive']).optional(),
  52. className: z.string().optional(),
  53. });
  54. export const SeparatorProps = z.object({
  55. orientation: z.enum(['horizontal', 'vertical']).optional(),
  56. className: z.string().optional(),
  57. });
  58. export const InputProps = z.object({
  59. placeholder: z.string().optional(),
  60. type: z.enum(['text', 'password', 'email', 'number']).optional(),
  61. disabled: z.boolean().optional(),
  62. className: z.string().optional(),
  63. });
  64. export const TextAreaProps = z.object({
  65. placeholder: z.string().optional(),
  66. rows: z.number().optional(),
  67. disabled: z.boolean().optional(),
  68. className: z.string().optional(),
  69. });
  70. export const DataTableProps = z.object({
  71. columns: z.array(z.object({
  72. key: z.string(),
  73. label: z.string(),
  74. })).optional(),
  75. data: z.array(z.record(z.string(), z.any())).optional(),
  76. className: z.string().optional(),
  77. });
  78. // MCP 专用组件 props
  79. export const TranslationResultProps = z.object({
  80. original: z.string().optional(),
  81. translated: z.string(),
  82. termsUsed: z.array(z.string()).optional(),
  83. className: z.string().optional(),
  84. });
  85. export const NovelListProps = z.object({
  86. novels: z.array(z.object({
  87. id: z.union([z.string(), z.number()]),
  88. title: z.string(),
  89. author: z.string().optional(),
  90. description: z.string().optional(),
  91. chapterCount: z.number().optional(),
  92. tags: z.array(z.string()).optional(),
  93. })),
  94. className: z.string().optional(),
  95. });
  96. export const ChapterReaderProps = z.object({
  97. novelTitle: z.string().optional(),
  98. chapterTitle: z.string().optional(),
  99. content: z.string(),
  100. chapterNumber: z.number().optional(),
  101. totalChapters: z.number().optional(),
  102. className: z.string().optional(),
  103. });
  104. export const CodeBlockProps = z.object({
  105. code: z.string(),
  106. language: z.string().optional(),
  107. className: z.string().optional(),
  108. });
  109. export const ToolCallProps = z.object({
  110. toolName: z.string(),
  111. status: z.enum(['pending', 'running', 'success', 'error']).optional(),
  112. result: z.any().optional(),
  113. className: z.string().optional(),
  114. });
  115. export const LoginPanelProps = z.object({
  116. serverName: z.string().optional(),
  117. onLogin: z.string().optional(),
  118. className: z.string().optional(),
  119. });
  120. export const McpStatusProps = z.object({
  121. serverId: z.string(),
  122. connected: z.boolean(),
  123. className: z.string().optional(),
  124. });
  125. export const SuggestionButtonsProps = z.object({
  126. suggestions: z.array(z.object({
  127. label: z.string(),
  128. message: z.string().optional(),
  129. icon: z.string().optional(),
  130. })),
  131. className: z.string().optional(),
  132. });
  133. // 创建 catalog
  134. const catalog = defineCatalog(schema, {
  135. components: {
  136. card: {
  137. props: CardProps,
  138. description: '卡片容器组件,用于包装内容区块',
  139. },
  140. stack: {
  141. props: StackProps,
  142. description: '布局容器组件,支持水平和垂直排列',
  143. },
  144. heading: {
  145. props: HeadingProps,
  146. description: '标题组件',
  147. },
  148. text: {
  149. props: TextProps,
  150. description: '文本组件',
  151. },
  152. button: {
  153. props: ButtonProps,
  154. description: '按钮组件',
  155. },
  156. badge: {
  157. props: BadgeProps,
  158. description: '徽章组件,用于标签和状态标识',
  159. },
  160. separator: {
  161. props: SeparatorProps,
  162. description: '分隔线组件',
  163. },
  164. input: {
  165. props: InputProps,
  166. description: '输入框组件',
  167. },
  168. 'text-area': {
  169. props: TextAreaProps,
  170. description: '多行文本输入组件',
  171. },
  172. 'data-table': {
  173. props: DataTableProps,
  174. description: '数据表格组件',
  175. },
  176. 'translation-result': {
  177. props: TranslationResultProps,
  178. description: '翻译结果展示组件',
  179. },
  180. 'novel-list': {
  181. props: NovelListProps,
  182. description: '小说列表组件',
  183. },
  184. 'chapter-reader': {
  185. props: ChapterReaderProps,
  186. description: '章节阅读器组件',
  187. },
  188. 'code-block': {
  189. props: CodeBlockProps,
  190. description: '代码块组件,支持语法高亮',
  191. },
  192. 'tool-call': {
  193. props: ToolCallProps,
  194. description: 'MCP 工具调用状态组件',
  195. },
  196. 'login-panel': {
  197. props: LoginPanelProps,
  198. description: 'MCP 登录面板组件',
  199. },
  200. 'mcp-status': {
  201. props: McpStatusProps,
  202. description: 'MCP 服务器状态组件',
  203. },
  204. 'suggestion-buttons': {
  205. props: SuggestionButtonsProps,
  206. description: '建议按钮组组件,用于快速选择预定义消息',
  207. },
  208. },
  209. });
  210. export default catalog;
  211. export { schema };
  212. // 兼容旧的导出
  213. export interface GetCatalogPromptOptions {
  214. mode?: 'standalone' | 'inline';
  215. }
  216. export function getCatalogPrompt(options?: GetCatalogPromptOptions): string {
  217. return catalog.prompt({ mode: options?.mode ?? 'inline' });
  218. }