From c02b03f8ebeadc45c4b20f52c68ca6b2660a4c37 Mon Sep 17 00:00:00 2001 From: ThreeFish Date: Tue, 30 Jun 2026 00:33:40 +0800 Subject: [PATCH] =?UTF-8?q?fix(Log):=20Graph=20=E5=90=8E=E6=96=87=E5=AD=97?= =?UTF-8?q?=E8=87=AA=E9=80=82=E5=BA=94=E8=B4=B4=E8=BF=91=E4=BB=A5=E6=B6=88?= =?UTF-8?q?=E9=99=A4=E7=95=99=E7=99=BD;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原实现每行 Graph SVG 宽度取全局 maxLanes(基于已加载全部提交),分支型仓库中仅用 1-2 条 lane 的行仍预留整宽,导致节点与文字间大片留白。改为按「本行实际绘制的最右列」计算行宽,文字随即向左贴近本行 Graph(lane x 坐标仍全局一致,竖线跨行衔接不变)。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang --- CHANGELOG.md | 4 ++++ src/adapter/webview/log-webview.ts | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54b3390..058f5cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ - **品牌图标统一**:将活动栏图标(`media/hyper-git-icon.svg`)、Marketplace 市场徽标(`media/icon.png`)与 README 头图统一为辨识度更高的「Git Pull Request」造型(字形改编自 Tabler Icons,MIT);市场徽标基于新字形重新栅格化为 256×256 RGBA 蓝→紫渐变图,设计源沉淀至 `media-src/icon.svg`;README 头部重构为居中布局(徽标 + 标题 + 一句话定位 + License 徽章)。 +### Fixed + +- **Log Graph 文字与节点间留白**:原实现每行 Graph SVG 宽度取「已加载全部提交」的全局 `maxLanes`,分支型仓库中仅用 1–2 条 lane 的行仍预留整宽,导致节点与文字间大片留白。改为按「本行实际绘制的最右列」自适应行宽,文字随即向左贴近本行 Graph(lane x 坐标仍全局一致,竖线跨行衔接不变),对齐 IDEA「文字紧随 Graph」观感。 + ## [0.0.1-rc.4] - 2026-06-29 — 第四个预发布候选 > 修复用户截图反馈的两处工具窗口缺陷:活动栏图标缺失「未提交文件数」角标、Branches「Push」对无上游分支失败。 diff --git a/src/adapter/webview/log-webview.ts b/src/adapter/webview/log-webview.ts index ba179e0..85c4891 100644 --- a/src/adapter/webview/log-webview.ts +++ b/src/adapter/webview/log-webview.ts @@ -411,13 +411,14 @@ const detailsList = document.getElementById('details-list'); function esc(s) { return String(s == null ? '' : s).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); } function laneColor(i) { return PALETTE[((i % PALETTE.length) + PALETTE.length) % PALETTE.length]; } function colX(c) { return c * LANE_W + LANE_W / 2; } -function graphPx() { return model.maxLanes * LANE_W + GUTTER; } +/** 本行实际绘制的最右列号(node + 各边 from/to 的最大值)——行宽据此自适应,消除「全局 maxLanes 撑宽」的留白。 */ +function rowMaxCol(row) { const L = row.layout; let m = L.node.col; for (const e of L.incoming) { if (e.fromCol > m) m = e.fromCol; if (e.toCol > m) m = e.toCol; } for (const e of L.outgoing) { if (e.fromCol > m) m = e.fromCol; if (e.toCol > m) m = e.toCol; } for (const e of L.passThrough) { if (e.fromCol > m) m = e.fromCol; if (e.toCol > m) m = e.toCol; } return m; } function fmtDate(iso) { if (!iso) return ''; const d = new Date(iso); if (isNaN(d)) return ''; const m = String(d.getMonth() + 1).padStart(2, '0'); const da = String(d.getDate()).padStart(2, '0'); return d.getFullYear() + '-' + m + '-' + da; } function rowSvg(row) { const L = row.layout; const cy = ROW_H / 2; - const W = graphPx(); + const W = (rowMaxCol(row) + 1) * LANE_W + GUTTER; const p = ['']; const seg = (e) => 'stroke="' + laneColor(e.colorIdx) + '" stroke-width="1.6" stroke-linecap="round"'; for (const e of L.passThrough) p.push('');