diff --git a/components/chain-table.tsx b/components/chain-table.tsx index 7ef8268..c79c171 100644 --- a/components/chain-table.tsx +++ b/components/chain-table.tsx @@ -114,6 +114,7 @@ export function ChainTableBody({ onClear, onDelete, onClose, + topBarExtra, selectMode, onSelect, }: { @@ -140,6 +141,11 @@ export function ChainTableBody({ * (graph rendering off, owner 2026-10-06): the table is the page, * there is nothing to close, and the X does not render. */ onClose?: () => void; + /** HOME VARIANT (owner, 2026-10-06 polish): extra controls injected + * into the shared TopBar, right cluster, LEFT of the search input — + * the chains home's Import-notes + cost pill live here instead of + * floating over the list (covering table content read badly). */ + topBarExtra?: React.ReactNode; /** PRACTICE SELECT (2026-10-04): the floating bar's confirm becomes * "Practice these" — no delete fence; the caller owns what the * selection becomes. */ @@ -245,12 +251,17 @@ export function ChainTableBody({ chat surface. NO TITLE (owner round 11, 2026-10-05): the serif title register is RESERVED — it always names a session; the chain table names nothing, so its bar carries counts + search + - close only. Search + close carve out with lh-no-drag (the mask - law: later in the DOM). */} + close only — plus, in the home variant, the injected + topBarExtra (import + cost, owner 2026-10-06). Search, close, + and the extra carve out with lh-no-drag (the mask law: later + in the DOM). */} {chains.length} {chains.length === 1 ? "chain" : "chains"} · {nodes.length} {nodes.length === 1 ? "node" : "nodes"} + {topBarExtra && ( +
{topBarExtra}
+ )}
+ {costs && costs.runs.length > 0 && } +
+ + + +
+ + } /> )} - {/* The chrome survivors, floating top-right BELOW the table's top - bar (h-15 = 60px + breathing room — owner, 2026-10-06): Import - ALWAYS — the entry point; the cost pill when any run exists. Node - search + the render gear are canvas things. */} - {!isEmpty && ( -
- {costs && costs.runs.length > 0 && } -
- - - -
-
- )} - {deleteOpen && ( ({ id: n.id, name: n.name }))} diff --git a/tests/render-chain-table.test.tsx b/tests/render-chain-table.test.tsx index dad71ab..a34014c 100644 --- a/tests/render-chain-table.test.tsx +++ b/tests/render-chain-table.test.tsx @@ -82,6 +82,7 @@ const BASE = { onGenerate: () => {}, onDelete: () => {}, onClose: () => {}, + topBarExtra: undefined as React.ReactNode, }; function render(props: Partial = {}) { @@ -96,6 +97,14 @@ describe("ChainTableBody — the HOME variant (graph rendering off, 2026-10-06)" assert.ok(html.includes("chain"), "the counts stay"); assert.ok(html.includes("lh-drag"), "the window-drag band stays (same bar as every surface)"); }); + + it("topBarExtra injects into the bar's right cluster — import + cost ride the TOP BAR (owner, 2026-10-06)", () => { + const html = render({ onClose: undefined, topBarExtra: React.createElement("b", { "data-testid": "tbx" }, "X") }); + assert.ok(html.includes('data-testid="tbx"'), "the extra renders inside the bar"); + assert.ok(html.includes("lh-no-drag"), "the cluster carves out of the drag band"); + const overlay = render(); + assert.ok(!overlay.includes('data-testid="tbx"'), "absent by default — the overlay variant injects nothing"); + }); }); describe("ChainTableBody — clusters (the outermost layer)", () => {