| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 |
- /**
- * json-render 组件测试页面
- *
- * 测试所有 15 个 json-render 组件的渲染效果
- */
- 'use client';
- import { useState } from 'react';
- import JsonRenderer from '@/components/JsonRenderer';
- import type { ComponentSpec } from '@/lib/json-render-catalog';
- // ============ 基础组件示例数据 ============
- const cardSpec: ComponentSpec = {
- type: 'card',
- title: '卡片标题',
- children: [
- {
- type: 'text',
- content: '这是一个卡片组件示例,用于包装和展示相关内容。',
- variant: 'body',
- },
- ],
- };
- const stackSpec: ComponentSpec = {
- type: 'stack',
- direction: 'row',
- spacing: 4,
- align: 'center',
- children: [
- {
- type: 'badge',
- text: '项目 A',
- variant: 'info',
- },
- {
- type: 'badge',
- text: '项目 B',
- variant: 'success',
- },
- {
- type: 'badge',
- text: '项目 C',
- variant: 'warning',
- },
- ],
- };
- const headingSpecs: ComponentSpec[] = [
- { type: 'heading', level: 'h1', text: 'Heading Level 1' },
- { type: 'heading', level: 'h2', text: 'Heading Level 2' },
- { type: 'heading', level: 'h3', text: 'Heading Level 3' },
- { type: 'heading', level: 'h4', text: 'Heading Level 4' },
- { type: 'heading', level: 'h5', text: 'Heading Level 5' },
- { type: 'heading', level: 'h6', text: 'Heading Level 6' },
- ];
- const textSpecs: ComponentSpec[] = [
- { type: 'text', content: '这是默认样式的正文文本,用于主要内容展示。', variant: 'body' },
- { type: 'text', content: '这是静音样式的文本,用于次要信息。', variant: 'muted' },
- { type: 'text', content: 'const code = "这是代码样式的文本";', variant: 'code' },
- ];
- const buttonSpecs: ComponentSpec[] = [
- { type: 'button', label: 'Default Button', variant: 'default' },
- { type: 'button', label: 'Primary Button', variant: 'primary' },
- { type: 'button', label: 'Secondary Button', variant: 'secondary' },
- { type: 'button', label: 'Ghost Button', variant: 'ghost' },
- { type: 'button', label: 'Danger Button', variant: 'danger' },
- { type: 'button', label: 'Disabled Button', variant: 'default', disabled: true },
- ];
- const inputSpecs: ComponentSpec[] = [
- { type: 'input', placeholder: '请输入用户名...' },
- { type: 'input', placeholder: '禁用状态', value: '固定值', disabled: true },
- ];
- const badgeSpecs: ComponentSpec[] = [
- { type: 'badge', text: 'Default', variant: 'default' },
- { type: 'badge', text: 'Success', variant: 'success' },
- { type: 'badge', text: 'Warning', variant: 'warning' },
- { type: 'badge', text: 'Error', variant: 'error' },
- { type: 'badge', text: 'Info', variant: 'info' },
- ];
- const separatorSpecs: ComponentSpec[] = [
- { type: 'separator', orientation: 'horizontal' },
- { type: 'separator', orientation: 'vertical' },
- ];
- // ============ MCP 组件示例数据 ============
- const translationResultSpec: ComponentSpec = {
- type: 'translation-result',
- translated: 'Lin Feng is an outer disciple of the Spirit Sect, possessing a mysterious cultivation technique that allows him to absorb the energy of heaven and earth.',
- termsUsed: ['Lin Feng', 'outer disciple', 'Spirit Sect', 'cultivation technique'],
- };
- const novelListSpec: ComponentSpec = {
- type: 'novel-list',
- novels: [
- {
- id: '1',
- title: '修仙之王',
- author: '张三',
- description: '一个凡人逆天改命,最终成就仙道的故事。',
- chapterCount: 1500,
- tags: ['修仙', '热血', '爽文'],
- },
- {
- id: '2',
- title: '都市医仙',
- author: '李四',
- description: '一代医仙重回都市,悬壶济世。',
- chapterCount: 800,
- tags: ['都市', '医术', '重生'],
- },
- {
- id: '3',
- title: '星际霸主',
- author: '王五',
- description: '银河系战神,征服星辰大海。',
- chapterCount: 2000,
- tags: ['科幻', '星际', '战争'],
- },
- ],
- };
- const chapterReaderSpec: ComponentSpec = {
- type: 'chapter-reader',
- novelTitle: '修仙之王',
- chapterTitle: '第一章: 重生',
- content: `林峰睁开眼睛,发现自己躺在一张简陋的木床上。
- 周围是熟悉的茅草屋,空气中弥漫着淡淡的药草味。他猛地坐起身来,看着自己瘦弱的手臂,难以置信地喃喃自语:"我...我竟然重生了?"
- 上一世,他是修仙界赫赫有名的丹尊,却因渡劫失败而陨落。没想到,竟然回到了少年时期,那个他还只是外门弟子的时候。
- "既然上天给我重来的机会,这一世,我定要登临仙道巅峰!"`,
- chapterNumber: 1,
- totalChapters: 1500,
- };
- const mcpToolCallSpecs: ComponentSpec[] = [
- {
- type: 'mcp-tool-call',
- tool: 'translate_text',
- status: 'pending',
- args: { text: 'Hello, world!', target_lang: 'zh' },
- timestamp: new Date().toISOString(),
- },
- {
- type: 'mcp-tool-call',
- tool: 'get_novels',
- status: 'running',
- args: { page: 1, limit: 10 },
- timestamp: new Date().toISOString(),
- },
- {
- type: 'mcp-tool-call',
- tool: 'translate_text',
- status: 'success',
- args: { text: 'Hello' },
- result: { translated: '你好' },
- timestamp: new Date().toISOString(),
- },
- {
- type: 'mcp-tool-call',
- tool: 'get_chapter',
- status: 'error',
- error: 'Chapter not found',
- timestamp: new Date().toISOString(),
- },
- ];
- const loginPanelSpec: ComponentSpec = {
- type: 'login-panel',
- server: 'novel-platform-user',
- };
- const codeBlockSpecs: ComponentSpec[] = [
- {
- type: 'code-block',
- code: 'function greet(name: string) {\n return `Hello, ${name}!`;\n}',
- language: 'typescript',
- },
- {
- type: 'code-block',
- code: 'SELECT * FROM users WHERE active = true;',
- language: 'sql',
- },
- {
- type: 'code-block',
- code: 'const inline = true;',
- language: 'javascript',
- inline: true,
- },
- ];
- const dataTableSpec: ComponentSpec = {
- type: 'data-table',
- columns: [
- { key: 'id', label: 'ID', sortable: true },
- { key: 'name', label: '名称', sortable: true },
- { key: 'status', label: '状态', sortable: true },
- { key: 'updated', label: '更新时间', sortable: true },
- ],
- rows: [
- { id: '1', name: '小说 A', status: '已完结', updated: '2026-03-15' },
- { id: '2', name: '小说 B', status: '连载中', updated: '2026-03-16' },
- { id: '3', name: '小说 C', status: '已完结', updated: '2026-03-17' },
- { id: '4', name: '小说 D', status: '连载中', updated: '2026-03-18' },
- ],
- sortable: true,
- };
- // ============ 测试页面组件 ============
- export default function TestPage() {
- const [selectedTab, setSelectedTab] = useState<'basic' | 'mcp'>('basic');
- return (
- <div className="min-h-screen bg-gray-50 dark:bg-gray-900">
- {/* 页面头部 */}
- <header className="bg-white dark:bg-gray-800 shadow-sm">
- <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
- <h1 className="text-3xl font-bold text-gray-900 dark:text-white">
- json-render 组件测试页面
- </h1>
- <p className="mt-2 text-gray-600 dark:text-gray-400">
- 测试所有 15 个 json-render 组件的渲染效果
- </p>
- </div>
- </header>
- {/* Tab 导航 */}
- <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 mt-6">
- <div className="border-b border-gray-200 dark:border-gray-700">
- <nav className="-mb-px flex space-x-8">
- <button
- onClick={() => setSelectedTab('basic')}
- className={`${
- selectedTab === 'basic'
- ? 'border-blue-500 text-blue-600 dark:text-blue-400'
- : 'border-transparent text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300'
- } whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm transition-colors`}
- >
- 基础组件 (8)
- </button>
- <button
- onClick={() => setSelectedTab('mcp')}
- className={`${
- selectedTab === 'mcp'
- ? 'border-blue-500 text-blue-600 dark:text-blue-400'
- : 'border-transparent text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300'
- } whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm transition-colors`}
- >
- MCP 组件 (7)
- </button>
- </nav>
- </div>
- </div>
- {/* 内容区域 */}
- <main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
- {selectedTab === 'basic' ? (
- <div className="space-y-12">
- {/* Card 组件 */}
- <section>
- <h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
- <span className="w-6 h-6 bg-blue-100 dark:bg-blue-900 text-blue-600 dark:text-blue-300 rounded-full flex items-center justify-center text-xs">1</span>
- Card - 卡片容器
- </h2>
- <JsonRenderer spec={cardSpec} />
- </section>
- {/* Stack 组件 */}
- <section>
- <h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
- <span className="w-6 h-6 bg-blue-100 dark:bg-blue-900 text-blue-600 dark:text-blue-300 rounded-full flex items-center justify-center text-xs">2</span>
- Stack - 弹性布局容器
- </h2>
- <JsonRenderer spec={stackSpec} />
- </section>
- {/* Heading 组件 */}
- <section>
- <h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
- <span className="w-6 h-6 bg-blue-100 dark:bg-blue-900 text-blue-600 dark:text-blue-300 rounded-full flex items-center justify-center text-xs">3</span>
- Heading - 标题 (h1-h6)
- </h2>
- <div className="bg-white dark:bg-gray-800 rounded-lg p-6 shadow-sm">
- <JsonRenderer specs={headingSpecs} />
- </div>
- </section>
- {/* Text 组件 */}
- <section>
- <h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
- <span className="w-6 h-6 bg-blue-100 dark:bg-blue-900 text-blue-600 dark:text-blue-300 rounded-full flex items-center justify-center text-xs">4</span>
- Text - 文本内容
- </h2>
- <div className="bg-white dark:bg-gray-800 rounded-lg p-6 shadow-sm">
- <JsonRenderer specs={textSpecs} />
- </div>
- </section>
- {/* Button 组件 */}
- <section>
- <h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
- <span className="w-6 h-6 bg-blue-100 dark:bg-blue-900 text-blue-600 dark:text-blue-300 rounded-full flex items-center justify-center text-xs">5</span>
- Button - 按钮
- </h2>
- <div className="bg-white dark:bg-gray-800 rounded-lg p-6 shadow-sm">
- <div className="flex flex-wrap gap-3">
- <JsonRenderer specs={buttonSpecs} />
- </div>
- </div>
- </section>
- {/* Input 组件 */}
- <section>
- <h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
- <span className="w-6 h-6 bg-blue-100 dark:bg-blue-900 text-blue-600 dark:text-blue-300 rounded-full flex items-center justify-center text-xs">6</span>
- Input - 输入框
- </h2>
- <div className="bg-white dark:bg-gray-800 rounded-lg p-6 shadow-sm space-y-3">
- <JsonRenderer specs={inputSpecs} />
- </div>
- </section>
- {/* Badge 组件 */}
- <section>
- <h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
- <span className="w-6 h-6 bg-blue-100 dark:bg-blue-900 text-blue-600 dark:text-blue-300 rounded-full flex items-center justify-center text-xs">7</span>
- Badge - 徽章标签
- </h2>
- <div className="bg-white dark:bg-gray-800 rounded-lg p-6 shadow-sm">
- <div className="flex flex-wrap gap-3">
- <JsonRenderer specs={badgeSpecs} />
- </div>
- </div>
- </section>
- {/* Separator 组件 */}
- <section>
- <h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
- <span className="w-6 h-6 bg-blue-100 dark:bg-blue-900 text-blue-600 dark:text-blue-300 rounded-full flex items-center justify-center text-xs">8</span>
- Separator - 分隔线
- </h2>
- <div className="bg-white dark:bg-gray-800 rounded-lg p-6 shadow-sm">
- <div className="flex items-center gap-4">
- <span className="text-gray-600 dark:text-gray-400">左侧内容</span>
- <JsonRenderer specs={separatorSpecs} />
- <span className="text-gray-600 dark:text-gray-400">右侧内容</span>
- </div>
- <div className="mt-4">
- <JsonRenderer spec={separatorSpecs[0]} />
- </div>
- </div>
- </section>
- </div>
- ) : (
- <div className="space-y-12">
- {/* TranslationResult 组件 */}
- <section>
- <h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
- <span className="w-6 h-6 bg-purple-100 dark:bg-purple-900 text-purple-600 dark:text-purple-300 rounded-full flex items-center justify-center text-xs">1</span>
- TranslationResult - 翻译结果展示
- </h2>
- <JsonRenderer spec={translationResultSpec} />
- </section>
- {/* NovelList 组件 */}
- <section>
- <h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
- <span className="w-6 h-6 bg-purple-100 dark:bg-purple-900 text-purple-600 dark:text-purple-300 rounded-full flex items-center justify-center text-xs">2</span>
- NovelList - 小说列表
- </h2>
- <JsonRenderer spec={novelListSpec} />
- </section>
- {/* ChapterReader 组件 */}
- <section>
- <h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
- <span className="w-6 h-6 bg-purple-100 dark:bg-purple-900 text-purple-600 dark:text-purple-300 rounded-full flex items-center justify-center text-xs">3</span>
- ChapterReader - 章节阅读器
- </h2>
- <JsonRenderer spec={chapterReaderSpec} />
- </section>
- {/* McpToolCall 组件 */}
- <section>
- <h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
- <span className="w-6 h-6 bg-purple-100 dark:bg-purple-900 text-purple-600 dark:text-purple-300 rounded-full flex items-center justify-center text-xs">4</span>
- McpToolCall - 工具调用可视化
- </h2>
- <div className="space-y-3">
- <JsonRenderer specs={mcpToolCallSpecs} />
- </div>
- </section>
- {/* LoginPanel 组件 */}
- <section>
- <h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
- <span className="w-6 h-6 bg-purple-100 dark:bg-purple-900 text-purple-600 dark:text-purple-300 rounded-full flex items-center justify-center text-xs">5</span>
- LoginPanel - 登录面板
- </h2>
- <JsonRenderer spec={loginPanelSpec} />
- </section>
- {/* CodeBlock 组件 */}
- <section>
- <h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
- <span className="w-6 h-6 bg-purple-100 dark:bg-purple-900 text-purple-600 dark:text-purple-300 rounded-full flex items-center justify-center text-xs">6</span>
- CodeBlock - 代码块
- </h2>
- <div className="space-y-4">
- <JsonRenderer specs={codeBlockSpecs} />
- </div>
- </section>
- {/* DataTable 组件 */}
- <section>
- <h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
- <span className="w-6 h-6 bg-purple-100 dark:bg-purple-900 text-purple-600 dark:text-purple-300 rounded-full flex items-center justify-center text-xs">7</span>
- DataTable - 数据表格
- </h2>
- <JsonRenderer spec={dataTableSpec} />
- </section>
- </div>
- )}
- </main>
- {/* 页脚 */}
- <footer className="bg-white dark:bg-gray-800 border-t border-gray-200 dark:border-gray-700 mt-12">
- <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
- <p className="text-sm text-gray-500 dark:text-gray-400">
- json-render 组件测试页面 | AI MCP Web UI - 模板 240
- </p>
- </div>
- </footer>
- </div>
- );
- }
|