Public: anyone can read this; the crew can change it.

Design: the spend tables use the design system's table, and spend-table/spend-totals leave §5d #3935

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/3615-design-the-spend-tables-use-the-design-s → main 6 commits fork

  • Merged. scout/3615-design-the-spend-tables-use-the-design-s was merged into main as 5184c15.

Review

Sign in to review this change.
4 files changed +20 −15
docs/DESIGN.md +1 −1
@@ -392,7 +392,7 @@ gone, so this list only shrinks.
392392 - **`style/content.ts`, apps, runs, and the crew** — run pages, their logs and checks (a pull's look is §5's **look**): `.app-url` `.check-progress` `.check-steps` `.ln-forge` `.ln-pulse` `.ln-say` `.ln-tool` `.ln-you` `.log-tail-row` `.pinned-failures` `.pinned-slot` `.run-actions` `.run-jump` `.run-live` `.run-steer` `.run-summary` `.step-state` `.tests-bar` `.tests-words` `.txt` `.who`
393393 - **`style/content.ts`, the code browser: explorer beside content** — the explorer column's own parts: `.code-main` `.code-split` `.ex-empty` `.ex-find` `.ex-head` `.ex-list` `.ex-name` `.ex-ref` `.ex-twist` `.explorer-toggle`
394394 - **`style/content.ts`, search results** — search results, the inbox's ask cards, the client list and the claim link: `.ask-acts` `.ask-card` `.ask-group` `.ask-kind` `.ask-meta` `.ask-more-acts` `.ask-pick` `.ask-pick-hit` `.ask-short` `.ask-waiting` `.claim-link-box` `.forges-sent` `.live-toggle` `.needs-you` `.no-hits`
395 - **`pages/board.ts`** — the spend tables `spend.ts` draws, first on the board (the board itself is §5's **board**): `.spend-table` `.spend-totals`
395 - **`pages/board.ts`** — the board itself is §5's **board**; the spend tables `spend.ts` draws wear §5's `.table` and `.stack`, no class of their own
396396 - **`pages/map.ts`** — the map of what waits for what: `.map-ask` `.map-breath` `.map-canvas` `.map-card` `.map-counts` `.map-dot` `.map-edge` `.map-edge-crit` `.map-edge-done` `.map-empty` `.map-list` `.map-main` `.map-meta` `.map-node` `.map-pillars` `.map-rule` `.map-svg` `.map-title` `.map-tool` `.map-tools` `.map-who` `.map-who-i` `.map-who-n` `.map-word` `.map-wrap`
397397 - **`studio/feed_style.ts`** — the home feed's cards, its composer and the apps rail: `.composer` `.composer-bar` `.fcard-form` `.fcard-reason` `.fcard-reply` `.fcard-text` `.fcard-unblock` `.fcard-who` `.fcard-why` `.feed` `.feed-head` `.kpi` `.kpi-note` `.kpi-spark` `.kpi-value` `.kpis` `.home-app` `.home-apps` `.home-apps-verbs` `.home-pick` `.home-rail` `.home-tabs`
398398
src/web/pages/board.ts +1 −4
@@ -999,7 +999,7 @@ function today(ctx: Ctx, scope: BoardScope): Html {
999999 * one key to show one. Everything inside them is §5's: rows in a list card,
10001000 * badges, meters, kbd. Assembled into the served stylesheet by
10011001 * `web/style.ts`, last in the `components` layer. The spend tables
1002 * (`spend.ts`) are drawn on the board first and keep their two rules here.
1002 * (`spend.ts`) wear §5's table and stack, with no rules here.
10031003 */
10041004 export const boardCss = /* css */ `
10051005 @layer components {
@@ -1019,9 +1019,6 @@ export const boardCss = /* css */ `
10191019 .board-region .row-lead img { display: block; border: 1px solid var(--border); border-radius: 4px; object-fit: cover; object-position: top; }
10201020 .board-region .row-main > meter { margin-top: 4px; }
10211021 .board [data-window] > meter { width: 56px; }
1022 .spend-table { margin-top: 8px; }
1023 .spend-table caption { text-align: left; color: var(--muted-fg); }
1024 .spend-totals { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 8px 0 0; }
10251022
10261023 /* Wide: four regions fill the window, each list scrolling on its own. */
10271024 @media (min-width: 1100px) {
src/web/pages/spend.ts +12 −10
@@ -48,7 +48,8 @@ function table(spend: Spend, dim: Dimension, title: string): Html {
4848 // The week's order: most spent first.
4949 const week = (n: string): number => at.get(n)!.get("week")?.costUsd ?? 0;
5050 names.sort((a, b) => week(b) - week(a));
51 return html`<table class="table spend-table" data-by="${dim}">
51 return html`<div class="table-scroll">
52 <table class="table" data-dense data-by="${dim}" aria-label="${title}">
5253 <thead>
5354 <tr>
5455 <th scope="col">${title}</th>
@@ -82,16 +83,17 @@ function table(spend: Spend, dim: Dimension, title: string): Html {
8283 </tr>`;
8384 })}
8485 </tbody>
85 </table>`;
86 </table>
87 </div>`;
8688 }
8789
8890 /** The whole breakdown: totals, five tables, the top runs. */
8991 export function spendView(spend: Spend): Html {
90 return html`<div class="spend">
91 <p class="spend-totals num">
92 return html`<div class="spend stack">
93 <p class="num">
9294 ${spend.spans.map(
93 (s) =>
94 html`<span
95 (s, i) =>
96 html`${i > 0 ? " — " : null}<span
9597 ><b>${usd(s.total.costUsd)}</b> ${SPAN_WORDS[s.span]} ·
9698 ${String(s.total.units)} runs · ${tokens(s.total.tokensIn)} in /
9799 ${tokens(s.total.tokensOut)} out</span
@@ -99,10 +101,9 @@ export function spendView(spend: Spend): Html {
99101 )}
100102 </p>
101103 ${DIMENSIONS.map(([dim, title]) => table(spend, dim, title))}
102 <table class="table spend-table" data-by="top">
103 <caption>
104 The 10 costliest runs, 7 days
105 </caption>
104 <p class="muted" id="spend-top">The 10 costliest runs, 7 days</p>
105 <div class="table-scroll">
106 <table class="table" data-dense data-by="top" aria-labelledby="spend-top">
106107 <thead>
107108 <tr>
108109 <th scope="col">Run</th>
@@ -134,6 +135,7 @@ export function spendView(spend: Spend): Html {
134135 )}
135136 </tbody>
136137 </table>
138 </div>
137139 <p class="muted small">
138140 US dollars at list price, as Claude Code reports them; a running session's
139141 tokens count as they arrive, its cost when it reports one. "Last 5 h" is
test/credentials.test.ts +6
@@ -337,5 +337,11 @@ describe("the board", () => {
337337
338338 const spend = await (await fetch(`${servers.url}/settings/spend`, { headers: { cookie } })).text();
339339 expect(spend).toContain('data-by="byCredential"');
340 expect(spend).not.toContain("spend-table");
341 expect(spend).not.toContain("spend-totals");
342 expect(spend).toContain('class="table-scroll"');
343 expect(spend).toContain("data-dense");
344 expect(spend).toContain('data-by="top" aria-labelledby="spend-top"');
345 expect(spend).toContain('id="spend-top"');
340346 });
341347 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs