From 4ab3e4f7abf0dc821615e2cc83eabfe394a9f575 Mon Sep 17 00:00:00 2001 From: dotta Date: Fri, 20 Mar 2026 06:59:10 -0500 Subject: [PATCH] =?UTF-8?q?fix:=20org=20chart=20layout=20refinements=20?= =?UTF-8?q?=E2=80=94=20retina,=20text=20spacing,=20logo=20alignment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Increase card height from 88 to 96px for better text spacing - Move name/role text down (y+58/y+74) so text sits properly below emoji - Fix Paperclip logo watermark — vertically center text with icon - Render PNG at 2x density (144 DPI) for retina-quality output Co-Authored-By: Paperclip --- server/src/routes/org-chart-svg.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/server/src/routes/org-chart-svg.ts b/server/src/routes/org-chart-svg.ts index 1f239516..ef2bdeb2 100644 --- a/server/src/routes/org-chart-svg.ts +++ b/server/src/routes/org-chart-svg.ts @@ -235,8 +235,8 @@ const THEMES: Record = { const bgColor = isCeo ? "rgba(168,85,247,0.06)" : theme.cardBg; const avatarCY = ln.y + 24; - const nameY = ln.y + 52; - const roleY = ln.y + 68; + const nameY = ln.y + 58; + const roleY = ln.y + 74; return ` @@ -299,8 +299,8 @@ const THEMES: Record = { const roleText = schemaRoles[tag] || schemaRoles.default; const avatarCY = ln.y + 24; - const nameY = ln.y + 52; - const roleY = ln.y + 68; + const nameY = ln.y + 58; + const roleY = ln.y + 74; return ` @@ -316,7 +316,7 @@ const THEMES: Record = { // ── Layout constants ───────────────────────────────────────────── -const CARD_H = 88; +const CARD_H = 96; const CARD_MIN_W = 150; const CARD_PAD_X = 22; const AVATAR_SIZE = 34; @@ -483,9 +483,10 @@ function treeBounds(ln: LayoutNode): { minX: number; minY: number; maxX: number; return { minX, minY, maxX, maxY }; } +// Paperclip logo: 24×24 icon + wordmark, vertically centered const PAPERCLIP_LOGO_SVG = ` - Paperclip + Paperclip `; // ── Public API ─────────────────────────────────────────────────── @@ -529,5 +530,6 @@ export function renderOrgChartSvg(orgTree: OrgNode[], style: OrgChartStyle = "wa export async function renderOrgChartPng(orgTree: OrgNode[], style: OrgChartStyle = "warmth"): Promise { const svg = renderOrgChartSvg(orgTree, style); - return sharp(Buffer.from(svg)).png().toBuffer(); + // Render at 2x density for retina-quality output + return sharp(Buffer.from(svg), { density: 144 }).png().toBuffer(); }