JSON-UI报告渲染器Skill json-ui

JSON-UI 是一个强大的 JSON 到 HTML 报告渲染器,支持 React 组件和双语国际化。它允许开发者通过定义 JSON 结构快速生成美观、交互式的学术或数据报告网页。核心功能包括组件化架构、Zod 模式验证、静态 HTML 输出、React 组件库以及无缝的中英文语言切换。适用于学术论文展示、数据分析报告、自动化文档生成等场景。关键词:JSON渲染,HTML报告,React组件,双语国际化,i18n,学术报告,数据可视化,前端开发工具。

前端开发 0 次安装 4 次浏览 更新于 2/27/2026

name: json-ui description: | 关键:用于 json-ui 组件的渲染和开发。触发词包括: json-ui, json 渲染, 组件目录, 报告渲染, HTML 报告, I18nString, i18n, 双语, 语言切换, 双语言, PaperHeader, AuthorList, Abstract, MetricsGrid, Section, Highlight, Zod schema, catalog.ts, cli.ts, components/index.tsx, “如何添加组件”, “如何渲染 JSON”, JSON 渲染, 组件目录, 报告渲染, 多语言, 中英文切换

json-ui

版本: 1.0.0 | 最后更新: 2026-01-29

您是 json-ui 包的专家——这是一个支持 React 组件、双语 i18n 和 CLI 工具的 JSON 到 HTML 报告渲染器。通过以下方式帮助用户:

  • 编写组件:按照现有模式添加新的组件类型
  • 渲染报告:从 JSON 报告定义生成 HTML
  • 调试:修复渲染、构建或 i18n 问题
  • 回答问题:解释架构、组件目录、数据流

快速参考

任务 文件 模式
定义组件模式 src/catalog.ts 添加 Zod 模式 + 在 catalog 对象中导出
渲染组件 (HTML) src/cli.ts renderNode() 的 switch 语句中添加 case
渲染组件 (React) src/components/index.tsx 使用目录类型导出 React FC
添加 i18n 文本 任何 JSON { "en": "Hello", "zh": "你好" } 或纯文本 "Hello"
构建 终端 pnpm build (使用 tsup,输出 ESM + DTS)
渲染报告 终端 json-ui render report.json [-o out.html] [--no-open]

文档

请参考本地源文件获取详细文档:

  • packages/json-ui/src/catalog.ts - 所有 Zod 模式和类型定义
  • packages/json-ui/src/cli.ts - HTML 渲染器和 CLI 入口点
  • packages/json-ui/src/components/index.tsx - React 组件实现

重要:文档完整性检查

在回答问题之前,Claude 必须:

  1. 阅读上面列出的相关源文件
  2. 如果文件读取失败:通知用户“本地文档不完整,建议更新”
  3. 仍然基于 SKILL.md 模式和内置知识进行回答

架构

JSON 报告格式

报告是节点的树状结构:

{
  "type": "Report",
  "props": { "title": "我的报告", "theme": "auto" },
  "children": [
    {
      "type": "Section",
      "props": { "title": "概述", "icon": "bulb" },
      "children": [
        { "type": "Abstract", "props": { "text": "..." } }
      ]
    }
  ]
}

三层渲染

文件 输出 使用场景
Zod 模式 catalog.ts 类型定义 验证、类型安全
HTML 渲染器 cli.ts 静态 HTML 字符串 CLI render 命令
React 组件 components/index.tsx React 元素 嵌入式使用

数据流

JSON 文件 → CLI 解析 → renderNode() 递归 → HTML 字符串 → 文件写入 → 浏览器打开

组件目录 (38 种类型)

布局

组件 关键属性 描述
Report title?, theme 根包装器,800px 最大宽度
Section title, icon?, collapsible? 带标题的可折叠部分
Grid cols, gap CSS 网格布局
Card variant, padding, shadow 卡片容器

论文信息

组件 关键属性 描述
PaperHeader title, arxivId, date, categories? 论文标题 + 元数据
AuthorList authors, layout?, maxVisible? 作者姓名 + 所属机构
Abstract text, highlights?, maxLength? 带关键词高亮的摘要
TagList tags, variant 标签/类别药丸

内容

组件 关键属性 描述
ContributionList items, numbered? 带徽章的编号贡献列表
MethodOverview steps, showConnectors? 分步方法流程
Highlight text, type, source? 引用块 (引用/重要/警告/代码)
KeyPoint icon, title, description 图标 + 标题 + 描述
CodeBlock code, language, showLineNumbers? 语法高亮代码
Prose content Markdown 内容块
Callout type, title?, content 信息/提示/警告/重要/注意框

富内容

组件 关键属性 描述
Image src, alt?, caption?, width? 单张图片
Figure images, caption?, label? 多图组合
Formula latex, block?, label? LaTeX 公式
DefinitionList items 术语-定义对
Theorem type, number?, title?, content 定理/引理/命题
Algorithm title, steps, caption? 算法伪代码
ResultsTable columns, rows, highlights? 带最佳单元格高亮的结果表

数据显示

组件 关键属性 描述
Metric label, value, trend?, icon? 单个指标卡片
MetricsGrid metrics, cols? 指标卡片网格
Table columns, rows, striped?, caption? 数据表

交互式

组件 关键属性 描述
LinkButton href, label, icon?, external? 样式化链接按钮
LinkGroup links, layout? 链接按钮组

品牌

组件 关键属性 描述
BrandHeader badge?, poweredBy?, showBadge? AI 生成徽章页眉
BrandFooter timestamp, attribution?, disclaimer? 带归属信息的页脚

I18n 系统

向后兼容的双语字符串

I18nString 类型接受纯字符串和双语对象:

// catalog.ts
export const I18nString = z.union([
  z.string(),
  z.object({ en: z.string(), zh: z.string() }),
]);

JSON 用法

// 纯字符串 (向后兼容)
{ "title": "Hello World" }

// 双语对象
{ "title": { "en": "Hello World", "zh": "你好世界" } }

HTML 渲染 (cli.ts)

对于 HTML 输出,i18n 字符串渲染为双 span:

// renderI18n() 输出:
<span class="i18n-en">Hello</span><span class="i18n-zh">你好</span>

// CSS 控制可见性:
html[lang="en"] .i18n-zh { display: none; }
html[lang="zh"] .i18n-en { display: none; }

对于仅支持纯字符串的 HTML 属性 (alt, title):

// resolveI18n() 选择一种语言:
const alt = resolveI18n(props.alt, 'en'); // 返回纯字符串

React 渲染 (components/index.tsx)

// 在 JSX 中使用 <I18nText> 组件:
<I18nText value={props.title} />

// 在纯字符串上下文中使用 resolveI18nStr():
const altText = resolveI18nStr(props.alt, 'en');

语言切换器

  • 固定右上角按钮:EN | 中文
  • 切换 <html lang="en|zh"> 属性
  • 通过 localStorage.getItem('json-ui-lang') 持久化选择

关键模式

模式 1:添加新组件

  1. catalog.ts 中定义模式
export const MyWidgetSchema = z.object({
  label: I18nString,        // 对用户可见的文本使用 I18nString
  count: z.number(),        // 对数据使用 z.string()/z.number()
  variant: VariantType.default('default'),
});

// 添加到 catalog 对象:
export const catalog = {
  // ...existing...
  MyWidget: MyWidgetSchema,
} as const;

// 导出类型:
export type MyWidgetProps = z.infer<typeof MyWidgetSchema>;
  1. cli.tsrenderNode() switch 语句中添加 HTML 渲染器
case 'MyWidget': {
  const { label, count, variant } = props;
  return `<div class="my-widget ${variant}">
    <span>${renderI18n(label)}</span>
    <strong>${escapeHtml(String(count))}</strong>
  </div>`;
}
  1. components/index.tsx 中添加 React 组件
export const MyWidget: React.FC<MyWidgetProps> = ({ label, count, variant = 'default' }) => (
  <div className={`my-widget ${variant}`}>
    <span><I18nText value={label} /></span>
    <strong>{count}</strong>
  </div>
);

模式 2:处理特殊情况下的 I18n

对于需要处理的文本(例如,Abstract 高亮):

// HTML (cli.ts) - 分别处理每种语言:
if (isI18n(text)) {
  return `<span class="i18n-en">${processText(text.en)}</span>
          <span class="i18n-zh">${processText(text.zh)}</span>`;
} else {
  return processText(String(text));
}

// React (components/index.tsx):
if (typeof text === 'object' && 'en' in text && 'zh' in text) {
  return (
    <>
      <span className="i18n-en" dangerouslySetInnerHTML={{ __html: processText(text.en) }} />
      <span className="i18n-zh" dangerouslySetInnerHTML={{ __html: processText(text.zh) }} />
    </>
  );
}

常见错误

错误 原因 解决方案
Type 'I18nStringType' is not assignable to 'ReactNode' 将 i18n 对象直接传递给 JSX <I18nText value={...} /> 包装
Property 'length' does not exist on type 'I18nStringType' 在 i18n 值上调用字符串方法 使用类型守卫:typeof text === 'string' ? text : text.en
来自 arxiv 的图片无法加载 <img> 标签上的 crossorigin="anonymous" 移除 crossorigin;仅保留 referrerpolicy="no-referrer"
语言切换器不工作 缺少 CSS 规则或 JS 确保模板中包含 html[lang] .i18n-* CSS 规则和切换 JS
构建失败并出现类型错误 模式已更改但组件未更新 更新所有三个文件:catalog, cli, components

关键:图片处理

请勿在 <img> 标签上使用 crossorigin="anonymous"

arxiv.org 这样的网站不发送 CORS 头。添加 crossorigin="anonymous" 会导致浏览器要求 CORS,这会失败并阻止图片加载。

<!-- 错误 - 破坏来自 arxiv 和类似网站的图片 -->
<img src="..." referrerpolicy="no-referrer" crossorigin="anonymous" />

<!-- 正确 -->
<img src="..." referrerpolicy="no-referrer" />

中文翻译指南

为 ML/AI 论文撰写中文翻译时:

错误 正确 原因
评论器 价值函数(critic) 标准 ML 术语
运行估计 滑动估计 Running estimate = 滑动估计
重加权因子 加权系数 更自然的中文
不断演化的 动态更新的 含义更清晰
简单修复 改动小 学术语气

构建 & CLI

# 构建 (通过 tsup 输出 ESM + DTS)
cd packages/json-ui && pnpm build

# 将报告渲染为 HTML
node dist/cli.js render example-report-rich.json

# 带选项
node dist/cli.js render report.json -o output.html --no-open

编写代码时

  1. 在模式中始终对用户可见的文本属性使用 I18nString
  2. 在渲染器中始终处理字符串和 {en, zh} 两种形式
  3. 切勿在 img 标签上使用 crossorigin="anonymous"
  4. 在 img 标签上保留 referrerpolicy="no-referrer" 以保护隐私
  5. 任何模式或组件更改后,使用 pnpm build 进行测试
  6. 添加组件时更新所有三层 (catalog, cli, components)