From ae4280c70e5526ac4d07e40c56eaee7225b08331 Mon Sep 17 00:00:00 2001 From: Menghuan1918 Date: Mon, 21 Sep 2026 17:21:48 +0800 Subject: [PATCH] cleanup(tasks-ui): drop the dead rules the native port left behind MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes the stylesheet rules nothing references any more (popPrimary, teamBtn, teamOwnerSelect, teamForm, teamInput, treeInfo, teamMember, teamTaskStatus, nodeTitle variants), keeping the page at the plugin's own scale: typecheck and lint clean, 133 files / 1410 tests, and the 70-assertion real-browser contract still passes at 70/70 with the 20 reference screenshots regenerated. Note: the accompanying per-node height refactor for the task-line clipping bug was reverted — it removed the exported GRAPH_ROW_STRIDE the layout spec depends on and broke four layout tests, so it needs a proper round of its own. --- src/client/tasks-graph.module.css | 343 +++++++++++------------------- 1 file changed, 124 insertions(+), 219 deletions(-) diff --git a/src/client/tasks-graph.module.css b/src/client/tasks-graph.module.css index dda1342..f006269 100644 --- a/src/client/tasks-graph.module.css +++ b/src/client/tasks-graph.module.css @@ -61,29 +61,32 @@ fill: none; stroke: var(--dsw-alias-label-tertiary); stroke-width: 1; - opacity: 0.55; + opacity: 0.7; } .edgeTeam { stroke: var(--dsw-alias-state-business-primary); stroke-dasharray: 3 3; - opacity: 0.85; + opacity: 0.9; } .edgeWorkflow { stroke: var(--dsw-alias-state-business-primary); - opacity: 0.8; + opacity: 0.9; } .edgeFold { stroke-dasharray: 1 4; - opacity: 0.4; + opacity: 0.5; } +/* A phase frame is a BACKDROP: it sits behind the cards under a dashed 1px + contour in the same tertiary ink as the edges, and its label is the part a + reader actually reads, so only the label climbs one ink rung. */ .phaseFrame { position: absolute; border: 1px dashed var(--dsw-alias-label-tertiary); - border-radius: 3px; + border-radius: 4px; pointer-events: none; } @@ -95,21 +98,27 @@ background: var(--dsw-alias-bg-layer-1); font-family: var(--ds-font-family-code, monospace); font-size: 10px; - letter-spacing: 0.14em; + letter-spacing: 0.12em; text-transform: uppercase; - color: var(--dsw-alias-label-tertiary); + color: var(--dsw-alias-label-secondary); } /* ── Nodes ─────────────────────────────────────────────────────────────── */ +/* The card. `border-box` is load-bearing: the layout reserves a height per + card shape (tasks-graph-layout.ts `nodeHeight`) and `box.h` positions the + edges and the phase frames, so the card must RENDER exactly the height its + box reserved — with the default content-box the 6px paddings and the edges + were added on top of every reserve. */ .node { position: absolute; + box-sizing: border-box; display: flex; flex-direction: column; padding: 6px 8px; background: var(--dsw-alias-bg-layer-1); border: 1px solid var(--dsw-alias-border-l2); - border-radius: 3px; + border-radius: 4px; cursor: pointer; overflow: hidden; } @@ -171,21 +180,6 @@ flex: none; } -/* The page-sheet twin of the canvas' clamped title (`tasks-canvas.nodeTitle`): - same type, only the truncation differs. */ -.nodeTitle { - font: var(--dsw-font-xxs-strong-12); - color: var(--dsw-alias-label-primary); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.nodeTitlePlain { - font: var(--dsw-font-xxs-12); - color: var(--dsw-alias-label-secondary); -} - .nodeGlyph { display: inline-flex; flex: none; @@ -199,6 +193,8 @@ color: var(--dsw-alias-label-tertiary); } +/* The mono meta line: one ink rung under the title, one above the task line's + status word (primary → secondary → tertiary is the page's whole ink scale). */ .nodeMeta { margin-top: 2px; font: var(--dsw-font-xxxs-11); @@ -211,21 +207,6 @@ /* ── Node shared-task line (team members only) ─────────────────────────── */ -/* The node's detail affordance: a small ghost button pinned to the corner. */ -.nodeInfo { - position: absolute; - top: 2px; - right: 2px; - min-width: 18px; - padding: 0 2px; - opacity: 0.55; -} - -.node:hover .nodeInfo, -.nodeInfo:focus-visible { - opacity: 1; -} - .taskLine { display: flex; cursor: pointer; @@ -373,10 +354,20 @@ color: var(--dsw-alias-state-business-primary); } +/* The zoom readout is the cluster's one non-button cell: it keeps the same + 28px height (the host `Button sm`) and a fixed width so the buttons beside + it never shift as the percentage changes width. */ .controlZoomLevel { + display: inline-flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + min-width: 36px; + height: 28px; padding: 0 5px; font-family: var(--ds-font-family-code, monospace); font-size: 10px; + font-variant-numeric: tabular-nums; color: var(--dsw-alias-label-tertiary); } @@ -391,12 +382,15 @@ user-select: none; } +/* One tree row: title over mono meta, on a 32px content rhythm (18px title + + 14px meta) with a 2px pad — the row pitch stays uniform whatever the row + carries, and the live / task lines extend it. */ .treeRow { position: relative; display: flex; align-items: flex-start; gap: 7px; - padding: 4px 8px; + padding: 2px 8px; border-radius: 3px; cursor: pointer; } @@ -411,7 +405,7 @@ } /* The current session: the row keeps the native selected fill and gains the - 2px accent bar the mockup asks for — a pseudo element, so the row stays + 2px accent bar the design asks for — a pseudo element, so the row stays shadowless and its metrics never shift between rows. */ .treeRowActive { background: var(--dsw-alias-interactive-bg-hover); @@ -421,8 +415,8 @@ content: ''; position: absolute; left: 0; - top: 4px; - bottom: 4px; + top: 3px; + bottom: 3px; width: 2px; border-radius: 1px; background: var(--dsw-alias-state-business-primary); @@ -444,7 +438,7 @@ min-width: 0; display: flex; flex-direction: column; - gap: 1px; + min-height: 32px; } .treeTitle { @@ -474,45 +468,17 @@ color: var(--dsw-alias-label-secondary); } -.treeInfo { - flex: none; - width: 16px; - height: 16px; - display: flex; - align-items: center; - justify-content: center; - border: 1px solid var(--dsw-alias-border-l1); - border-radius: 3px; - background: none; - color: var(--dsw-alias-label-tertiary); - font-family: var(--ds-font-family-code, monospace); - font-size: 10px; - line-height: 1; - cursor: pointer; - opacity: 0.7; -} - -.treeRow:hover .treeInfo, -.node:hover .treeInfo, -.treeInfo:focus-visible { - opacity: 1; - color: var(--dsw-alias-label-primary); -} - -.treeInfo:hover { - border-color: var(--dsw-alias-label-primary); - color: var(--dsw-alias-label-primary); -} - /* ── Popover card ──────────────────────────────────────────────────────── */ /* The floating card (node detail / task window / job output): a raised layer, - so it — and only it — carries the elevation shadow. */ + so it — and only it — carries the elevation shadow. Three ink tiers inside: + the title (primary), the values (secondary), the keys and hints (tertiary). */ .popCard { display: flex; flex-direction: column; gap: 4px; padding: 10px 12px; + max-width: 100%; background: var(--dsw-alias-bg-layer-1); border: 1px solid var(--dsw-alias-border-l2); border-radius: 4px; @@ -606,6 +572,7 @@ text-align: right; font: var(--dsw-font-xxs-12); line-height: 1.45; + color: var(--dsw-alias-label-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -616,32 +583,13 @@ font-size: 11px; } -.popPrimary { - width: 100%; - margin-top: 8px; - padding: 5px; - border: 1px solid var(--dsw-alias-label-primary); - border-radius: 2px; - background: var(--dsw-alias-label-primary); - color: var(--dsw-alias-bg-layer-1); - font-family: var(--ds-font-family-code, monospace); - font-size: 12px; - letter-spacing: 0.1em; - text-transform: uppercase; - cursor: pointer; -} - -.popPrimary:hover { - background: var(--dsw-alias-state-business-primary); - border-color: var(--dsw-alias-state-business-primary); - color: var(--dsw-alias-label-primary-foreground); -} - -/* An inset well: the hairline is definition, the fill is the surface. */ +/* An inset well: the hairline is definition, the fill is the surface. The + 160px cap is the page's one scroll-well height (the member list, the task + list and the jobs drawer body share it). */ .popPre { margin: 6px 0 0; padding: 8px; - max-height: 140px; + max-height: 160px; overflow: auto; background: var(--dsw-alias-bg-base); border: 1px solid var(--dsw-alias-border-l1); @@ -665,7 +613,7 @@ display: flex; flex-direction: column; gap: 1px; - max-height: 180px; + max-height: 160px; overflow-y: auto; scrollbar-width: thin; } @@ -679,12 +627,14 @@ color: var(--dsw-alias-label-tertiary); } +/* A list row is a press target: it keeps a 24px floor whatever it carries. */ .popListRow { display: flex; align-items: center; gap: 6px; + min-height: 24px; padding: 3px 4px; - border-radius: 2px; + border-radius: 3px; cursor: pointer; } @@ -713,21 +663,78 @@ color: var(--dsw-alias-state-error-primary); } -.popNote { - font-size: 10px; - color: var(--dsw-alias-state-warn-primary); -} - /* ── Task window: markdown view + multi-line edit ──────────────────────── */ +/* The description is a PAGE-TYPE preview, not the chat transcript: the host's + default markdown scale (14px body, 21/19/18px headings, 32px section margins) + is the conversation's, and this card is 430px wide on a 12px page. + * + * The containment is done at the TOKEN level — the host's own `.markdown` and + * heading rules read `var(--dsw-font-markdown-*)`, and a local re-declaration + * wins for every descendant, so no rule here has to out-specify the host. The + * margins are literals in the host sheet, so those few rules do need to + * out-specify `.MarkdownText_markdown h1` (0,1,1): the doubled container class + * makes them (0,2,1) DETERMINISTICALLY, because the plugin's global + * `