revert(tasks-ui): drop the shadcn/Tailwind layer and return to the plugin's own UI system

shadcn's defaults are built for a standalone app: 14px body, 36px controls,
solid primary fills and elevation read as a foreign surface next to this
plugin's own tabs (files, changes, side chat, settings), which are 12/11/10px
type, 28px controls, hairline borders and flat panels. Retuning the layer did
not converge, so the layer goes.

- Removed: src/client/ui/** (21 vendored components), components.json,
  scripts/ui-css.mjs, the Tailwind/PostCSS compile step in tsdown, and the deps
  tailwindcss / @tailwindcss/postcss / postcss / radix-ui /
  class-variance-authority / tailwind-merge. (diff and simple-icons stay: they
  patch undeclared bare imports of the host primitives, unrelated to shadcn.)
- The seven page surfaces are back on the plugin's own base: *.module.css with
  --dsw-* tokens plus the host primitives (Button/Menu/Modal/Pill/Tag/Switch/
  Input/Tooltip/StateDot/MarkdownText). Behaviour, data-* hooks, aria labels,
  i18n keys and the AnchoredPopover geometry/drag/dismiss contract are
  unchanged; the non-styling fixes landed during the shadcn era (model id
  dedupe, task-window CAS, drawer arming, popover dragging, the chunk packaging
  glob) were re-applied and are covered by the existing specs.
- The tasks page returns to the core bundle: `tasks` left CHUNK_NAMES /
  CHUNKS / ChunkName, src/client/chunks/tasks.tsx is gone and tabs.tsx imports
  SubagentView directly.
- The reverted stylesheet was retuned to the plugin's measured vocabulary
  (12/11/10px, 28px controls, border-l2 with border-l1 hairlines, hover fills,
  no static shadows, --dsw-shadow-lv2/3 on floating layers only) and verified
  against a 70-assertion real-browser contract; the harness's own two
  measurement defects were fixed with a falsification test proving the
  assertions still catch injected regressions (56/70, 14 FAIL).
- Tests: ui-foundation / ui-bundle / ui-shadows (the shadcn guards) deleted,
  theme.spec scoped back to the plugin's own stylesheets, bundle-route and
  manifest-consistency chunk lists back to four. Docs: AGENTS.md and the plugin
  guide drop the Tailwind/shadcn guidance; the design doc marks those sections
  superseded and records why the layer was removed.

Verified: typecheck/lint clean; 133 files / 1410 tests; core bundle 987.3 KiB
with no radix-ui/--tw-/tailwind strings and no client-tasks.js; mount e2e 7/7;
20 real-browser screenshots at 360/720 for graph, tree, board, task window,
drawer (including armed), both popovers and the 77-node fixture.
This commit is contained in:
Menghuan1918
2026-09-27 22:18:19 +08:00
parent e500a3d2b9
commit a71d158f9a
47 changed files with 2373 additions and 4107 deletions
+53 -59
View File
@@ -1,69 +1,63 @@
/**
* Canvas-only styles of the workflow graph (TasksGraph.tsx): the dotted grid,
* the transformed node layer, the SVG relation layer and the edge stroke
* recipe. These are the four pieces Tailwind utilities cannot express in the
* markup (a radial-gradient background image, `transform-origin: 0 0` on the
* scaled layer, an overflow-visible SVG stage, and SVG stroke/dash painting) —
* everything else in the graph is a utility class over the shadcn tokens.
* Graph-only styles of the workflow graph (TasksGraph.tsx) — the two pieces
* the page sheet (tasks-graph.module.css) does not carry:
*
* Skin contract: every color is a `--dsw-*` token (no literal, no palette
* class), so the canvas follows the host light/dark theme like the rest of the
* page. Relations are 1px hairlines in the border ink — the KIND of a relation
* is its dash pattern and opacity, never a second hue.
* - the card title, clamped to TWO lines (the 68px card reserve in
* tasks-graph-layout.ts is sized for that second line: a single ellipsized
* line left too few CJK characters to tell two siblings apart), and
* - the hydration hint drawn over an empty canvas.
*
* Everything else the graph wears (the dotted canvas, the bezier edges, the
* node cards, the control cluster) stays in the page sheet — one source of
* truth per rule.
*
* Skin contract: colors resolve to `--dsw-alias-*`, type to `--dsw-font-*` —
* tokens only, no literal, no palette class, no shadow on a static panel.
*/
.canvas {
/* Card line 1 of an agent / run node. `-webkit-box` + `-webkit-line-clamp` is
* the only way to cap WRAPPED text with an ellipsis, and `overflow-wrap:
* anywhere` keeps an unbroken run id from forcing one wide line. The recipe
* mirrors the page sheet's node title (12px strong) so only the truncation
* differs; the untruncated text stays in the element's `title`. */
.nodeTitle {
flex: 1;
min-width: 0;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
overflow-wrap: anywhere;
font: var(--dsw-font-xxs-strong-12);
color: var(--dsw-alias-label-primary);
}
/* The fold aggregate carries a count, not a name: it recedes one rung in both
* weight and ink (the page sheet's plain title). */
.nodeTitlePlain {
font: var(--dsw-font-xxs-12);
color: var(--dsw-alias-label-secondary);
}
/* The graph twin of the tree's loading row: centred over the canvas and
* click-transparent, so pan / zoom / node clicks stay live underneath. It sits
* above the transformed node layer (z-index auto) and below the control
* cluster (z-index 6). */
.loading {
position: absolute;
inset: 0;
cursor: grab;
/* Panning must never turn into a text selection or a native scroll. */
touch-action: none;
user-select: none;
/* Graph paper: the dotted grid is part of the language. */
background-image: radial-gradient(circle, var(--dsw-alias-border-l1) 0.6px, transparent 0.6px);
background-size: 16px 16px;
background-position: 0 0;
}
.canvasDragging {
cursor: grabbing;
}
.canvasInner {
position: absolute;
top: 0;
left: 0;
transform-origin: 0 0;
}
.edges {
position: absolute;
top: 0;
left: 0;
overflow: visible;
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
pointer-events: none;
font: var(--dsw-font-xxs-12);
color: var(--dsw-alias-label-tertiary);
}
.edge {
fill: none;
stroke: var(--dsw-alias-border-l4);
stroke-width: 1;
opacity: 0.5;
}
/* Team membership: dashed. */
.edgeTeam {
stroke-dasharray: 3 3;
opacity: 0.8;
}
/* Workflow member: solid, one notch stronger than a plain lineage edge. */
.edgeWorkflow {
opacity: 0.75;
}
/* Collapsed aggregate: dotted and faint — it stands for many rows. */
.edgeFold {
stroke-dasharray: 1 4;
opacity: 0.4;
/* The hint's glyph is decoration: the copy line carries the message. */
.loadingGlyph {
display: inline-flex;
flex: none;
}