/** * json-render 注册表 * * 使用官方 defineRegistry API 创建组件注册表 */ 'use client'; import { useState } from 'react'; import { defineRegistry, type BaseComponentProps } from '@json-render/react'; import { useActionEmit } from '@/lib/action-context'; import { z } from 'zod'; import catalog, { CardProps, StackProps, HeadingProps, TextProps, ButtonProps, BadgeProps, SeparatorProps, InputProps, TextAreaProps, DataTableProps, TranslationResultProps, NovelListProps, ChapterReaderProps, CodeBlockProps, ToolCallProps, LoginPanelProps, McpStatusProps, SuggestionButtonsProps, } from './catalog/catalog'; // ============ 基础组件 ============ const Card = ({ props, children }: BaseComponentProps>) => (
{props.title &&

{props.title}

} {children}
); const Stack = ({ props, children }: BaseComponentProps>) => { const directionClass = props.direction === 'row' ? 'flex-row' : 'flex-col'; const spacingClass = (props.spacing ?? 2) > 0 ? `gap-${props.spacing ?? 2}` : ''; const alignClass = props.align === 'center' ? 'items-center' : props.align === 'end' ? 'items-end' : props.align === 'stretch' ? 'items-stretch' : 'items-start'; return (
{children}
); }; const Heading = ({ props }: BaseComponentProps>) => { const level = props.level || 'h2'; const Tag = level as 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; const sizeClasses: Record = { h1: 'text-3xl font-bold', h2: 'text-2xl font-semibold', h3: 'text-xl font-semibold', h4: 'text-lg font-medium', h5: 'text-base font-medium', h6: 'text-sm font-medium', }; const sizeClass = sizeClasses[level] || sizeClasses.h2; return {props.text}; }; const Text = ({ props }: BaseComponentProps>) => { const variantClasses: Record = { default: 'text-gray-700 dark:text-gray-300', muted: 'text-gray-500 dark:text-gray-400', primary: 'text-blue-600 dark:text-blue-400', success: 'text-green-600 dark:text-green-400', warning: 'text-yellow-600 dark:text-yellow-400', destructive: 'text-red-600 dark:text-red-400', }; const sizeClasses: Record = { xs: 'text-xs', sm: 'text-sm', md: 'text-base', lg: 'text-lg', xl: 'text-xl', }; const color = props.color || 'default'; const size = props.size || 'md'; return

{props.text}

; }; const Button = ({ props, emit }: BaseComponentProps>) => { const variantClasses: Record = { default: 'bg-gray-200 hover:bg-gray-300 text-gray-800 dark:bg-gray-700 dark:hover:bg-gray-600 dark:text-gray-200', primary: 'bg-blue-600 hover:bg-blue-700 text-white', secondary: 'bg-purple-600 hover:bg-purple-700 text-white', outline: 'border border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-300', ghost: 'hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-300', destructive: 'bg-red-600 hover:bg-red-700 text-white', }; const variant = props.variant || 'default'; const handleClick = () => { if (props.disabled) return; if (props.onClick) { emit(props.onClick); } }; return ( ); }; const Badge = ({ props }: BaseComponentProps>) => { const variantClasses: Record = { default: 'bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200', primary: 'bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-200', secondary: 'bg-purple-100 dark:bg-purple-900/30 text-purple-800 dark:text-purple-200', success: 'bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-200', warning: 'bg-yellow-100 dark:bg-yellow-900/30 text-yellow-800 dark:text-yellow-200', destructive: 'bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-200', }; const variant = props.variant || 'default'; return ( {props.text} ); }; const Separator = ({ props }: BaseComponentProps>) => { const orientation = props.orientation || 'horizontal'; const orientationClass = orientation === 'vertical' ? 'w-px h-full' : 'h-px w-full'; return
; }; const Input = ({ props }: BaseComponentProps>) => ( ); const TextArea = ({ props }: BaseComponentProps>) => (