feat(team): sharp org-chart elbow connectors + fit text in cards

Match the Paperclip look: connectors are now right-angle elbows (parent → shared
horizontal bus → drop to each child) instead of bezier curves; siblings share a
bus Y so it reads as a clean org chart. The traveling pulse follows the elbow
path. Role/model line truncates with ellipsis inside the card (no more text
spilling past the edge); nodes clip overflow. Slightly more compact nodes/gaps.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
chahinebrini 2026-07-08 05:10:49 +02:00
parent ab35389f9c
commit 722c8598e9

View File

@ -151,11 +151,12 @@ export function renderTeamHtml(cwd: string): string {
.chart { position: relative; display: inline-flex; min-width: 100%; justify-content: center; padding: 12px 24px 40px; }
.edges { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 0; overflow: visible; }
.subtree { position: relative; z-index: 1; display: inline-flex; flex-direction: column; align-items: center; }
.children { display: flex; flex-direction: row; align-items: flex-start; justify-content: center; gap: 13px; margin-top: 40px; }
.children { display: flex; flex-direction: row; align-items: flex-start; justify-content: center; gap: 11px; margin-top: 42px; }
.node {
position: relative;
width: 176px;
width: 168px;
overflow: hidden;
background: linear-gradient(180deg, rgba(255,255,255,.02), rgba(0,0,0,.10)), var(--surface);
border: 1px solid var(--border);
border-radius: 14px;
@ -171,7 +172,7 @@ export function renderTeamHtml(cwd: string): string {
.node-id { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.node-name { font-weight: 700; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; outline: none; border-radius: 4px; }
.node-name[contenteditable="true"] { background: rgba(88,166,255,.12); box-shadow: 0 0 0 1px rgba(88,166,255,.5); padding: 0 4px; cursor: text; }
.node-role { font: 10.5px/1.2 var(--font-mono); color: var(--muted); white-space: nowrap; text-transform: uppercase; letter-spacing: .04em; }
.node-role { display: block; max-width: 100%; font: 10.5px/1.2 var(--font-mono); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-transform: uppercase; letter-spacing: .04em; }
.node-model { text-transform: none; letter-spacing: 0; }
.node-badge { margin-left: auto; align-self: flex-start; font: 700 9px/1 var(--font-mono); text-transform: uppercase; letter-spacing: .06em; padding: 3px 6px; border-radius: 999px; }
@ -254,9 +255,12 @@ export function renderTeamHtml(cwd: string): string {
if (!parent) return;
parentOf[n.getAttribute('data-node-id')] = pid;
var s = centerBottom(parent, box), e = centerTop(n, box);
var midY = s.y + (e.y - s.y) * 0.5;
var fwd = 'M ' + s.x + ' ' + s.y + ' C ' + s.x + ' ' + midY + ', ' + e.x + ' ' + midY + ', ' + e.x + ' ' + e.y;
var rev = 'M ' + e.x + ' ' + e.y + ' C ' + e.x + ' ' + midY + ', ' + s.x + ' ' + midY + ', ' + s.x + ' ' + s.y;
// Sharp org-chart elbow: down from the parent to the shared bus, across, down to the child.
// Siblings share the same top Y, so their bus Y matches → one clean horizontal bus.
var busY = Math.round(s.y + (e.y - s.y) * 0.5);
var sx = Math.round(s.x), ex = Math.round(e.x);
var fwd = 'M ' + sx + ' ' + Math.round(s.y) + ' L ' + sx + ' ' + busY + ' L ' + ex + ' ' + busY + ' L ' + ex + ' ' + Math.round(e.y);
var rev = 'M ' + ex + ' ' + Math.round(e.y) + ' L ' + ex + ' ' + busY + ' L ' + sx + ' ' + busY + ' L ' + sx + ' ' + Math.round(s.y);
edgeMap[n.getAttribute('data-node-id')] = { fwd: fwd, rev: rev };
var base = document.createElementNS(NS, 'path');
base.setAttribute('class', 'edge-base'); base.setAttribute('d', fwd);