diff --git a/README.md b/README.md index 8fe818f..70c14cb 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ DiffLens 是一款跨平台桌面文本对比工具,帮助你快速定位两 - **大文件防护**:超过 10MB 的文件自动拦截并提示;行数过多时给出耗时预警;超长单行自动跳过词级高亮,避免卡顿 - **二进制文件预警**:疑似二进制内容给出乱码提示,避免误读为差异 - **差异统计徽章**:实时统计新增 / 删除 / 修改行数 -- **导出一键报告**:将对比结果导出为 HTML / 纯文本 / Markdown 三种格式(始终包含全量行),便于分享与归档 +- **导出一键报告**:将对比结果导出为 HTML / 纯文本 / Markdown 三种格式(始终包含全量行)。HTML 报告为"给人看"设计:一句话结论、文件卡片、统计概览、图例说明、差异分块目录导航,相同内容段自动折叠(点击展开零丢失),并支持打印与窄屏 - **拖拽与按钮双入口**:支持文件拖拽导入,也可通过界面按钮选择文件或粘贴文本 - **滚动联动**:左右两个面板滚动位置自动同步 @@ -96,7 +96,7 @@ src/ - 作者:thzxx - 组织:MetonaTeam - 许可证:MIT License(见 [LICENSE](./LICENSE)) -- 版本:0.4.1 +- 版本:0.4.2 --- diff --git a/docs/应用开发与版本迭代规范.md b/docs/应用开发与版本迭代规范.md index cd94df2..ddddfcb 100644 --- a/docs/应用开发与版本迭代规范.md +++ b/docs/应用开发与版本迭代规范.md @@ -20,7 +20,7 @@ z = 补丁版本号(Patch) > **`x` 永远是 `0`,永远不要提升到 `1.0.0`。** > 版本迭代**只允许修改 `y` 和 `z`**,`x` 保持 `0` 不变。 -当前基线版本:**`0.4.1`** +当前基线版本:**`0.4.2`** --- @@ -67,7 +67,8 @@ z = 补丁版本号(Patch) 0.3.1 ← 稳健性与测试补强(已发布):超长单行词级 diff 防护 · 打开对话框补“所有文件”筛选 · 虚拟滚动 minWidth 测试覆盖 · 滚动同步去锁化重构 0.3.2 ← 报告对齐与性能收尾(已发布):纯文本报告行号右对齐 · 超长行列宽封顶防卡顿 · 对话框与拖拽扩展名清单对齐 · 右键菜单打开时导航快捷键守卫 · 清理导出死属性 0.4.0 ← 差异计算 worker 化(已发布):大文件 diff 移入 Worker 后台计算不阻塞界面 · 输入去抖与过期任务丢弃(终止重建实现取消) · 小输入同步快路径 · 无 Worker 环境回退 · 计算中遮罩与导出禁用 -0.4.1 ← worker 创建开销优化与文档对齐(当前):worker 延迟至去抖到期才创建(去抖期内取消零创建开销,无 Worker 回退同样走去抖) · 质量门禁文档补 npm test · README 架构树补 hooks · Markdown 报告标题移出引用块 · 安装包排除开发期文件 +0.4.1 ← worker 创建开销优化与文档对齐(已发布):worker 延迟至去抖到期才创建(去抖期内取消零创建开销,无 Worker 回退同样走去抖) · 质量门禁文档补 npm test · README 架构树补 hooks · Markdown 报告标题移出引用块 · 安装包排除开发期文件 +0.4.2 ← 导出菜单溢出修复与报告可读性重设计(当前):底部工具栏导出菜单改向上弹出(修复超出窗口底边选不到) · HTML 报告全新设计(Hero 概览/人话结论/文件卡片/统计卡/图例/差异分块目录/相同段折叠可展开/打印亮色/窄屏适配,零 JS) · TXT 与 Markdown 报告头部补人话结论 0.5.0 ← 新增功能(候选:主进程解码 worker 化 · Playwright E2E · 文件夹对比) ... 0.y.z ← 长期停留,永不进入 1.x diff --git a/docs/测试策略与方案.md b/docs/测试策略与方案.md index f69cc78..9e752fc 100644 --- a/docs/测试策略与方案.md +++ b/docs/测试策略与方案.md @@ -60,7 +60,7 @@ src/renderer/src/ │ ├── ContextMenu.test.tsx # 右键菜单(含边缘防溢出) │ ├── DiffView.test.tsx # 对比视图(渲染/滚动同步/右键/拖放) │ ├── TextInputModal.test.tsx # 粘贴文本弹窗 -│ └── Toolbar.test.tsx # 工具栏(选项/导航/导出菜单/计算中禁用) +│ └── Toolbar.test.tsx # 工具栏(选项/导航/导出菜单向上弹出/计算中禁用) └── __tests__/ ├── App.test.tsx # 应用集成级测试(加载/拖拽/粘贴/导出/容错/大输入回退) └── main.test.ts # 入口挂载冒烟测试 @@ -82,9 +82,11 @@ src/renderer/src/ - 行切分:结尾换行不产生多余空行 ### 5.2 报告生成(`report.ts`) -- HTML:输出合法文档、含文件名/统计/类型高亮语义 -- 纯文本:含增删改标记(`+ -`)、行号按最大位数右对齐 -- Markdown:表格化、管道符转义保持表格结构 +- HTML:输出合法文档;Hero 区含人话结论(verdict)、文件卡片、统计卡与图例;差异分块(hunk-head)与块内行渲染;多块时输出目录锚点(toc/href="#seg-N"),单块不输出;相同内容段折叠(details/summary)且折叠段内保留全量行数据;一致场景 verdict ok;两侧空内容提示 +- 纯文本:含增删改标记(`+ -`)、行号按最大位数右对齐、头部人话结论 +- Markdown:表格化、管道符转义保持表格结构、引用块含人话结论 +- 差异分块(`buildSegments`):空行集 / 无变更单段全展示 / 上下文 3 行与边界收敛 / 相邻区间合并 / 远距分两段省略数正确 / 自定义 context +- 人话总结(`plainSummary`):无差异一致结论 / 为 0 项省略 / 三类齐全完整罗列 - 格式分发与扩展名映射(`REPORT_EXT`) ### 5.3 文本工具(`textUtils.ts`) diff --git a/package.json b/package.json index 805cea2..b47b5d5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "DiffLens", - "version": "0.4.1", + "version": "0.4.2", "description": "DiffLens — 精美酷炫的文本对比桌面应用", "author": "thzxx", "license": "MIT", diff --git a/src/renderer/src/components/Toolbar.test.tsx b/src/renderer/src/components/Toolbar.test.tsx index 9e1715a..0de8c32 100644 --- a/src/renderer/src/components/Toolbar.test.tsx +++ b/src/renderer/src/components/Toolbar.test.tsx @@ -86,6 +86,12 @@ describe('Toolbar', () => { expect(onExport).toHaveBeenCalledWith('html') }) + it('导出菜单向上弹出(工具栏贴窗口底部,防止溢出底边)', () => { + const { container } = setup() + fireEvent.click(screen.getByText('导出报告')) + expect(container.querySelector('.export-menu.up')).not.toBeNull() + }) + it('点击外部区域关闭导出菜单', () => { setup() fireEvent.click(screen.getByText('导出报告')) diff --git a/src/renderer/src/components/Toolbar.tsx b/src/renderer/src/components/Toolbar.tsx index 1858f11..d953216 100644 --- a/src/renderer/src/components/Toolbar.tsx +++ b/src/renderer/src/components/Toolbar.tsx @@ -125,7 +125,7 @@ export default function Toolbar({ 导出报告 {exportOpen && ( -
+
{FORMATS.map((f) => (