@vernikr/size-report 2.8.0 → 2.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,7 +10,7 @@ shows.
10
10
 
11
11
  ## Status
12
12
 
13
- **Release 2.8.0 (2026-09-18).** The tool lives as a package of its own: the registry name is
13
+ **Release 2.8.1 (2026-09-18).** The tool lives as a package of its own: the registry name is
14
14
  `@vernikr/size-report` (published by tag from CI, with no secret). A project may keep no settings at
15
15
  all: without a config file the tool derives them from the project itself and says so in one line,
16
16
  and `--init` pins what was derived into a file. The report is **one file**, the self-contained page
@@ -19,6 +19,22 @@ is installed and on the first run. The version is in the manifest, and every rel
19
19
  the journal — `worklog/` for today's entries, `worklog/archive/WORKLOG.md` for the earlier ones:
20
20
  what changes in the numbers is measured rather than retold.
21
21
 
22
+ 2.8.1 is the drawing of the page put right after its table became a window, and its figures are measured rather than
23
+ retold. **The panel and the table were sharing one class:** the table's rows were styled by a bare `.row` while the
24
+ panel's own rows are `.panel .row`, so the table's rule took the metrics row and the three method lines out of the flow
25
+ and painted them over one another — every rule of the shared part now hangs off `#grid`, and a check reads the selector
26
+ list of that sheet rather than a sample of the page. **The numbers were placed from the grid's left edge while the commit
27
+ column is pinned over it**, which hid the first column — the overall total — completely; they begin at the column's right
28
+ edge now, a 220px figure written in the script and in the styling and held together like the three beside it. **The order
29
+ of the columns comes from the numbers rather than from the commit's list of paths**: a commit can touch a file without
30
+ moving it — this package's own attachment to itself, 2.7.0 → 2.8.0, is one character for another — and a column of empty
31
+ cells standing in front of the table is what a reader calls a broken order, so a file's newest move decides its place;
32
+ the engine's mark `last` stays in `--data` while the page's block no longer carries it. **One border and one height:**
33
+ every line of the table is 1px of one colour (the header's two lines were 2px and another shade) and the header is two rows
34
+ of the table's own height, while a file's name is centred over its group. The artifact grows 351 B for it — 85 495 B
35
+ against 85 144 B of one history. The checks go 88 → **89** in the fast profile and 193 → **194** in the full one; the
36
+ figures and the reasoning stand in `worklog/0209-page-drawing-order.md`.
37
+
22
38
  2.8.0 is about what the report costs whoever opens it, and its figures are measured rather than retold.
23
39
  **The table is a window of itself:** every row and every column in sight is built, plus four beyond each edge so that
24
40
  the edge of the window is never seen empty, while the rest of the table exists as the extent of the scrolled box and
@@ -237,11 +253,10 @@ commits and installs hooks; the reason for each expensive file is named line by
237
253
 
238
254
  | Run | Command | Checks |
239
255
  |---|---|---|
240
- | Fast — every edit | `pnpm test` | **88 of 193** |
241
- | Full — release and CI | `pnpm test:all` | **193** |
256
+ | Fast — every edit | `pnpm test` | **89 of 194** |
257
+ | Full — release and CI | `pnpm test:all` | **194** |
242
258
 
243
- No check is lost or weakened: the full run starts all 186 with the same files, the fast one takes part
244
- of them. The default is the full run — a file becomes fast only explicitly and with a reason — so new
259
+ No check is lost or weakened: the full run starts every file, the fast one takes part of them. The default is the full run — a file becomes fast only explicitly and with a reason — so new
245
260
  expensive work cannot quietly move into the fast one. Two declarations guard that:
246
261
  `test/suites.test.js` (every file classified, and a reason for each) and the documentation guard
247
262
  `test/docs-numbers.test.js` (the numbers in the table above).
@@ -367,10 +382,14 @@ a *single* cell of this repository's report, 539 ms for 6 000 (`probes/step-12-c
367
382
  table is **2 460 nodes and 0.15 GB**, a hundredth of the nodes and a tenth of the memory, and the whole-table scroll
368
383
  pass that took 36 s of task time over 60 steps takes **1.1 s over 251** (`worklog/0208-table-window.md`). **The columns
369
384
  are one width and fixed, 70px each**: the numbers are short and of one kind, and a width that came out of the text is a
370
- measurement of every cell of the column — the very cost this step removed. A file's name over its group is cut with an
371
- ellipsis rather than wrapped (the header is one line high and the whole name stands in the tooltip). The geometry is
372
- three figures — a column, a row, the header written in the styling and in the script that counts the window's ordinals
373
- in them, and `test/page-grid.test.js` reads both and holds them together.
385
+ measurement of every cell of the column — the very cost this step removed. A file's name stands centred over its group
386
+ and is cut with an ellipsis rather than wrapped the whole name stays in the tooltip. The header is two lines of one
387
+ row each, the numbers begin at the
388
+ right edge of the pinned commit column rather than under it, and every line of the table under a row, under a header
389
+ cell, along a group's left edge — is one pixel of one colour: a heavier line would promise a hierarchy to work out
390
+ rather than read. The geometry is four figures — a column, a row, the header, the pinned column — written in the styling
391
+ and in the script that counts the window's ordinals in them, and `test/page-grid.test.js` reads both and holds them
392
+ together.
374
393
 
375
394
  **A click builds the window again, and that is cheap now.** A file switched off is simply not among the columns that
376
395
  are built, and a metric switched off not among the metrics: there is nothing to hide and nothing to carry, and the
@@ -387,15 +406,16 @@ virtualizes rows out of a string of all of them and knows nothing of columns —
387
406
  the artifact, whose bytes this very tool measures. What is left to write after any of them is what the chapter is: the
388
407
  window, the cells, the header and the pinned column.
389
408
 
390
- **The columns the last commit touched come first.** The report is rebuilt after every commit, and a
391
- reader's first question is what that edit brought. The mark comes from the history rather than from the
392
- numbers an edit that changed no size is an edit too and it is taken from the last commit that
393
- touched at least one column, counting back from the top: a commit that went past the columns, above all
394
- the report itself, which the hook commits, is skipped, or the mark would depend on the report's own
395
- commit, the same run would give different bytes and the hook would commit the report a second time.
396
- Inside each part the order stays as it comes from the settings (the sort is stable): the order of the
397
- columns is what the reader is used to, and his choice of files does not rearrange it
398
- (`test/page-grid.test.js`, the contract's `last` field).
409
+ **The columns whose numbers last moved come first.** The report is rebuilt after every commit, and a
410
+ reader's first question is what that edit brought. The mark is taken from the numbers rather than from
411
+ the commit's list of paths, and that is the whole of the difference: a commit can touch a column without
412
+ moving it a version bumped inside a line of the same length, this package's own attachment to itself is
413
+ one and a column of empty cells standing in front of the table is what a reader calls a broken order.
414
+ The rest follows in the settings' order (the sort is stable), so the order of the columns is what the
415
+ reader is used to, and his choice of files does not rearrange it (`src/page/table.js`; the rule is counted
416
+ from the contract's own rows in `test/page-grid.test.js`). The engine still answers with `last` the
417
+ columns the newest commit touched — in `--data`; the page no longer reads it, and the block it carries no
418
+ longer holds it.
399
419
 
400
420
  **On a wide window the panel stands to the left of the table and takes no room from the numbers** (from
401
421
  900px, `src/page/app.css`). That is not decoration: a desktop has much side room and little vertical
@@ -578,13 +598,13 @@ acceptance for each.
578
598
  | `src/size-table.js` | The package's entry point: a re-export of the public API (55 names) and no calculation of its own |
579
599
  | `src/derived.js` | The report's shared calculation: totals, deltas, a cell, a commit's caption — one for the engine and the page's program |
580
600
  | `src/css.js` | Reading the styling from disk: which sets of styles exist and what role each has |
581
- | `src/table.css` | The report's table: the geometry of the window — one width per column, one height per row, the header — the sticky header and commit column, a file's caption cut with an ellipsis, the colour of deltas |
601
+ | `src/table.css` | The report's table: the geometry of the window — one width per column, one height per row, the two lines of the header, the pinned commit column — the sticky header and commit column, one 1px line of one colour for every border, a file's caption centred over its group and cut with an ellipsis, the colour of deltas |
582
602
  | `src/page/app.css` | The page's styling on top of the shared part: the panel with the file tree and its sticky row of categories (a column on the left on a wide screen, the page fitting the window), the empty states, a narrow window |
583
603
  | `src/page/payload.js` | The page's block in sparse form, and the one place that unrolls it back: the history as changes (a file's appearance, its moves, its disappearance) turned into the snapshots the calculation and the table already speak — a value that did not move is one object shared by the rows that hold it |
584
604
  | `src/page/state.js` | The page's state: the report's data (the block unrolled by the payload chapter), the view of the checkboxes, the pointer "which path is which column", the unfolded folders, the record's passport, the browser's memory and the link that is read out of the address — a chapter of the page's program |
585
605
  | `src/page/dom.js` | The page's nodes: the small helpers of markup (`appEl`, `appBox`) — one set for the panel and the table alike |
586
606
  | `src/page/panel.js` | The panel of choices: the switches of metrics and files, the categories, the tree of the project's paths (files outside the report keep a checkbox off with a reason and stand after the rest, and a hidden name after every visible one; the tree opens folded and folders carry a sign that hides the subtree by a class rather than by a rebuild); built once, with the fields of the switches and of the folders and categories written where they stand |
587
- | `src/page/table.js` | The page's table as a window: the rows and the columns the reader can see (plus four beyond each edge), a cell, a commit's caption, the header, the empty states and the two figures of the window — markup over the shared calculation, with the totals counted per row from the choice, the geometry in pixels that the styling mirrors, and the reason a library was not taken |
607
+ | `src/page/table.js` | The page's table as a window: the rows and the columns the reader can see (plus four beyond each edge), a cell, a commit's caption, the header, the empty states and the order of the columns — markup over the shared calculation, with the totals counted per row from the choice, the geometry in pixels that the styling mirrors, and the reason a library was not taken |
588
608
  | `src/page/app.js` | Assembling and starting the page: the first drawing, then a switch that builds the window again and writes the fields it reached without making a node of the panel; an anchor change; pasted into the assembled page |
589
609
  | `src/page/build.js` | Assembling the page: data, styling and program in one file with no external references — the pasted text is **squeezed** on the way in (comments and indentation out, the same stripping the `min` metric counts) while the sources keep them, and the result is guarded by the stripper's own `assertCompilable` |
590
610
  | `src/git.js` | The only border where git is called: the pinned settings, blobs by the batch, the history, the comparison with the working tree |
@@ -633,7 +653,7 @@ acceptance for each.
633
653
  | `test/refusals-catalog.test.js` | The guard of the refusal catalogue: every refusal site in the sources has an entry, every entry declares its advice, and refusals handed to another check are really accepted by it (the named file and line are checked) |
634
654
  | `test/contract-data.test.js` | The data contract: the numbers against the reference, the set of fields against the derived quantities, the metric's method against the way the numbers were counted — and the round trip through the page's sparse block, which restores the contract whole and twice over the same bytes |
635
655
  | `test/contract-derived.test.js` | The derived quantities against the artifact's numbers: a row's totals, a cell's delta and the delta of a total — on the code that lies in the tree |
636
- | `test/page-grid.test.js` | The grid of the page as a window: what the reader sees is built and no more, the geometry of the styling against the script's, the rows and the columns that a scroll builds and drops, a number under its own caption, a file and a metric switched off, and every row of the window against the engine's own calculation |
656
+ | `test/page-grid.test.js` | The grid of the page as a window: what the reader sees is built and no more, the geometry of the styling against the script's, the rows and the columns that a scroll builds and drops, a number under its own caption, a file and a metric switched off, every row of the window against the engine's own calculation, and the drawing's own rules — the order of the columns by the numbers, one border, the header's rows of one height, and the panel out of the shared styling's reach |
637
657
  | `test/page-view.test.js` | The assembled page: pasted with no copy of the calculation, self-contained, the empty states, the styling, the switches, a click that makes no table and the carried totals against the engine's own sums — **deactivated** while the table is rebuilt, every check skipped with its reason in the file |
638
658
  | `test/page-tree.test.js` | The panel's file tree: folders by the project's paths, three states, the subtree, files and folders outside the report (a checkbox off, a place after the rest), the hidden names at the end of a level, the tree that opens folded and the unfolding the memory keeps, folding without a rebuild and a scroll a click does not touch — **deactivated** with the table, the checks skipped with their reason |
639
659
  | `test/page-choice.test.js` | The reader's choice and the work a click starts: the memory and a revisit, someone else's report, a foreign and a broken record, an address that stays clean, a link read at opening and on an open page, and the drawing of a long switch in a task of its own behind the stripe — **deactivated**: the choice and the link are the same, while the counts and the stripe are not |
@@ -717,7 +737,7 @@ The same release can be taken by a reference to the repository — installation
717
737
  registry, but stays tied to a revision:
718
738
 
719
739
  ```bash
720
- pnpm add -D github:vernikr/size-report#v2.8.0
740
+ pnpm add -D github:vernikr/size-report#v2.8.1
721
741
  ```
722
742
 
723
743
  With no network (or nothing to fetch from codeload) — the tarball: `pnpm pack` in the package clone, then
@@ -729,7 +749,7 @@ the branch moves on the installation fails with `Could not resolve <sha> to a co
729
749
  observation rather than reasoning: the short pin `6530237` installed while `main` stood on it and stopped
730
750
  working at the very next commit, while the same sha in full installed. A branch name (`#main`) and a tag
731
751
  are both accepted, but a branch is a moving target and a tag is constant: this release stands on the tag
732
- `v2.8.0`, which is also the one in the example (forty characters work as well, but they have to be copied
752
+ `v2.8.1`, which is also the one in the example (forty characters work as well, but they have to be copied
733
753
  out of the history by eye).
734
754
 
735
755
  The revision in the example is a part of the claim rather than decoration: what is described below is
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vernikr/size-report",
3
- "version": "2.8.0",
3
+ "version": "2.8.1",
4
4
  "author": "vernikr",
5
5
  "repository": {
6
6
  "type": "git",
@@ -65,7 +65,7 @@
65
65
  "report"
66
66
  ],
67
67
  "devDependencies": {
68
- "@vernikr/size-report": "2.7.0",
68
+ "@vernikr/size-report": "2.8.0",
69
69
  "c8": "10",
70
70
  "dependency-cruiser": "17",
71
71
  "eslint": "^9.18.0",
package/src/page/app.css CHANGED
@@ -14,7 +14,10 @@
14
14
  --pad: clamp(16px, 3vw, 34px);
15
15
  --radius: 10px;
16
16
  --muted: rgba(127, 127, 127, .85);
17
- --line: rgba(127, 127, 127, .32);
17
+ /* The same grey as the table's own lines (`--grid-line` of `src/table.css`): the frame around the numbers and the rows
18
+ * inside it are one drawing, and a second grey for the chrome is what makes a page look assembled from two. The two
19
+ * declarations are held together by the check that reads the borders of both sheets. */
20
+ --line: rgba(127, 127, 127, .25);
18
21
  --tint: rgba(127, 127, 127, .07);
19
22
  }
20
23
 
@@ -231,7 +234,8 @@ h1 { margin: 0 0 3px; font-size: 21px; font-weight: 650; letter-spacing: -.012em
231
234
  h1 { font-size: 18px; }
232
235
  #grid { font-size: 12px; }
233
236
  .shell { max-height: calc(100vh - 260px); }
234
- /* The commit column needs no rule of its own here any more: its width is the measure `--clip` of the shared part
235
- * (`src/table.css`), and on a narrow screen that measure stands as it is. A shorter one would be `--clip: 150px`
236
- * here — the adaptation the shared part cannot make for itself. */
237
+ /* The commit column keeps its width on a narrow screen, and that is deliberate rather than forgotten: the numbers
238
+ * are placed beside it by the script (`APP_COMMIT`), so a narrower column here would leave a band of empty grid
239
+ * between the two one number would have to be read from the styling by the script, which is a second copy of a
240
+ * geometry the check holds together (`test/page-grid.test.js`). */
237
241
  }
package/src/page/build.js CHANGED
@@ -126,11 +126,13 @@ function uiText(page, loc) {
126
126
  * one (`src/page/payload.js`, `appDecode`), so the two places it is read are the encoder here and the decoder there.
127
127
  * `test/contract-data.test.js` holds the round trip between them.
128
128
  *
129
- * What the block leaves out besides the sparse form is the list of skipped commits: it changes with the report's own
130
- * commit (one with nothing to say lands in the list), and the file would stop being a **fixed point** — a rebuild
131
- * after its own commit would yield different bytes and the hook would commit the report forever. The page has no use
132
- * for the list at all: it does not show it. It stays available to the reader `--data`, `--json` and `explain`
133
- * answer from the same run.
129
+ * What the block leaves out besides the sparse form are two facts the page does not read. The list of skipped commits
130
+ * changes with the report's own commit (one with nothing to say lands in the list), and the file would stop being a
131
+ * **fixed point** — a rebuild after its own commit would yield different bytes and the hook would commit the report
132
+ * forever; the page does not show it. The other is `last`, the columns the newest commit touched: the page orders the
133
+ * columns by the numbers themselves, which is a different fact (`src/page/table.js` says why), and the block would
134
+ * carry a list nothing asks for. Both stay available to the reader — `--data`, `--json` and `explain` answer from the
135
+ * same run.
134
136
  *
135
137
  * How much this is worth: the artifact of this repository carried 1 370 627 B of data as a snapshot per commit — 95 %
136
138
  * of the whole file — while nine tenths of the cells repeat the row above; the same history as changes is about 84 000
@@ -139,7 +141,7 @@ function uiText(page, loc) {
139
141
  /* The block's fields, in the order the encoder writes them. The shape is closed: a field added here has to be read in
140
142
  * the decoder, and the page's checks compare the block with this list rather than with a description of it. */
141
143
  export const PAGE_KEYS = ['schema', 'tool', 'report', 'hrefPrefix', 'strs', 'metrics', 'cats', 'files',
142
- 'catalog', 'rows', 'last', 'hist'];
144
+ 'catalog', 'rows', 'hist'];
143
145
 
144
146
  /* The texts of the block, each written once. The dictionary is extended in the order of the walk `pagePayload` makes
145
147
  * — files in the column order, rows in the history order — and the order of the first appearance is what decides an
@@ -227,10 +229,8 @@ export function pagePayload(data) {
227
229
  r.section === null ? null : dict.of(r.section.head),
228
230
  r.section !== null && r.section.added ? 1 : 0,
229
231
  r.href === null ? null : dict.of(r.href.slice(prefix.length))]),
230
- last: [],
231
232
  hist: history(keys, data.files, data.rows)
232
233
  };
233
- data.last.forEach((on, i) => { if (on) out.last.push(i); });
234
234
  return out;
235
235
  }
236
236
 
@@ -15,7 +15,9 @@
15
15
  * moved (deltas against its own previous record) or disappeared, and this chapter puts the snapshots back
16
16
  * together. The whole history walk is O(number of changes) rather than O(rows × files).
17
17
  *
18
- * The model after `appDecode` is exactly `--data`: the calculation (`rowModel`, `totalsOf`, `cellParts`,
18
+ * The model after `appDecode` is exactly `--data` but for one field: the history's mark `last` (the columns the
19
+ * newest commit touched) is not carried, because the page orders its columns by the numbers rather than by the
20
+ * commit's list of paths (`src/page/table.js`). The calculation (`rowModel`, `totalsOf`, `cellParts`,
19
21
  * `valueParts`), the table and the panel know nothing about the sparse form, so there is no second way to
20
22
  * count a row. A value that did not move is **one object shared by the rows that hold it** — the heap keeps
21
23
  * the distinct numbers rather than a copy per commit — and because every consumer reads `v[metric]` and
@@ -149,8 +151,6 @@ function appRowOf(p, r, values) {
149
151
  export function appDecode(p) {
150
152
  const keys = p.metrics.map((m) => appText(p, m[0]));
151
153
  const hist = appUnroll(p, keys);
152
- const last = p.files.map(() => false);
153
- p.last.forEach((i) => { last[i] = true; });
154
154
  return {
155
155
  schema: p.schema,
156
156
  tool: p.tool,
@@ -162,7 +162,6 @@ export function appDecode(p) {
162
162
  paths: f[2].map((i) => p.strs[i]), category: appText(p, f[3]), categoryBy: appText(p, f[4]) })),
163
163
  catalog: p.catalog.map((e) => ({ path: appText(p, e[0]), why: appText(p, e[1]) })),
164
164
  rows: p.rows.map((r, ri) => appRowOf(p, r, hist.rows[ri])),
165
- now: hist.now,
166
- last: last
165
+ now: hist.now
167
166
  };
168
167
  }
package/src/page/table.js CHANGED
@@ -13,7 +13,8 @@ import { appData, appUi, appView } from './state.js';
13
13
  * to build less rather than to promise the browser will skip it. A grid of `position: absolute` rows has no layout to
14
14
  * be redone: a row is placed by its `top`, a column by the `left` of the group of cells that starts it, and the
15
15
  * browser never measures a cell to decide a width — every column is `--col` wide (70px), which is what the numbers
16
- * need and no more (the counted widths this step replaced were 47–70px).
16
+ * need and no more (the counted widths this step replaced were 47–70px), and they begin at the right edge of the
17
+ * pinned commit column (`APP_COMMIT`) rather than under it.
17
18
  *
18
19
  * **Why not a library.** A virtualizer for two axes is not a solved problem for a page like this one — measured from
19
20
  * the tarballs, `@tanstack/virtual-core` is ~6.7 kB gzip and headless (the rows and columns are two virtualizers and
@@ -37,10 +38,12 @@ import { appData, appUi, appView } from './state.js';
37
38
  */
38
39
 
39
40
  /* The geometry in pixels: written here and read by the styling (`src/table.css`), which is one copy too many — hence
40
- * `test/page-grid.test.js` holds the two together, and the report says the same numbers in its journal. */
41
+ * `test/page-grid.test.js` holds the two together, and the report says the same numbers in its journal. The header is
42
+ * two lines of one row each, and the commit column is as wide as the styling pins it. */
41
43
  export const APP_COL = 70;
42
44
  export const APP_ROW = 25;
43
- export const APP_HEAD = 44;
45
+ export const APP_HEAD = APP_ROW * 2;
46
+ export const APP_COMMIT = 220;
44
47
 
45
48
  /* How much more than the visible window is built, in rows and in columns. A window that ends exactly at the edge of
46
49
  * the shell shows an empty band while the browser scrolls a notch; four rows and four columns of slack are cheaper
@@ -53,15 +56,41 @@ export const APP_OVER = 4;
53
56
  export const APP_MIN_ROWS = 24;
54
57
  export const APP_MIN_COLS = 10;
55
58
 
56
- /* The order of the columns: the files the last commit touched come first the report is rebuilt after every
57
- * commit, and a reader's first question is what that edit brought. Inside each part the order is the settings', and
58
- * it depends on the files rather than on the choice: that is what lets a column be switched off without moving the
59
- * others. */
59
+ /* The order of the columns: the files whose numbers last moved come first, and the older the move the further right the
60
+ * column stands. A reader opens the report after a commit, and what he looks for is what that edit brought while the
61
+ * rest may as well be ordered by the settings, which is the order of the ties.
62
+ *
63
+ * The mark is taken from the numbers rather than from the history's list of paths, and that is the whole of the
64
+ * difference: a commit can touch a column without moving it (a version bumped inside a line of the same length, this
65
+ * package's own attachment to itself is one), and a column of empty cells standing in front of the table is what a
66
+ * reader sees as a broken order. The list of paths is the engine's (`--data`), which is where a fact about a commit
67
+ * belongs; what stands here is a fact about the numbers.
68
+ *
69
+ * The order depends on the files rather than on the choice: that is what lets a column be switched off without moving
70
+ * the others. Counted once per document — the model does not change while the page is open — because every window the
71
+ * reader scrolls to asks for it. */
72
+ function appRank() {
73
+ const rank = appData.files.map(() => -1);
74
+ let was = null;
75
+ appData.rows.forEach((row, i) => {
76
+ /* The rows of a file are the same object until it moves (`src/page/payload.js`), so one comparison per file and
77
+ * row says whether the file appeared, moved or went away at this commit — the three cases a cell is not empty. */
78
+ row.values.forEach((v, j) => { if (was === null || was[j] !== v) rank[j] = i; });
79
+ was = row.values;
80
+ });
81
+ return rank;
82
+ }
83
+
84
+ let appOrderValue = null;
85
+
60
86
  export function appOrder() {
61
- const files = [];
62
- appData.files.forEach((_f, i) => files.push(i));
63
- files.sort((a, b) => (appData.last[a] === true ? 0 : 1) - (appData.last[b] === true ? 0 : 1));
64
- return files;
87
+ if (appOrderValue === null) {
88
+ const rank = appRank();
89
+ const files = [];
90
+ appData.files.forEach((_f, i) => files.push(i));
91
+ appOrderValue = files.sort((a, b) => rank[b] - rank[a]);
92
+ }
93
+ return appOrderValue;
65
94
  }
66
95
 
67
96
  /* The files whose columns are built, in the order of the columns: what is switched off is not among them, which is
@@ -141,7 +170,9 @@ function appRow(cache, r, span) {
141
170
  else commit.appendChild(appCommit(appData.rows[i]));
142
171
  row.appendChild(commit);
143
172
  const cells = appEl('div', 'cells');
144
- cells.style.left = (span.c0 * APP_COL) + 'px';
173
+ /* The numbers stand beside the commit column rather than under it: the column is pinned over the content, so what the
174
+ * grid holds begins where the column ends. */
175
+ cells.style.left = (APP_COMMIT + span.c0 * APP_COL) + 'px';
145
176
  for (let c = span.c0; c <= span.c1; c++) cells.appendChild(appCell(model, c, now, cache));
146
177
  row.appendChild(cells);
147
178
  return row;
@@ -173,7 +204,7 @@ function appHead(cache, span) {
173
204
  const count = cache.keys.length;
174
205
  const g0 = Math.floor(span.c0 / count);
175
206
  const g1 = Math.floor(span.c1 / count);
176
- const left = (g0 * count * APP_COL) + 'px';
207
+ const left = (APP_COMMIT + g0 * count * APP_COL) + 'px';
177
208
  const head = appEl('div', 'head');
178
209
  head.appendChild(appEl('div', 'c-commit', appUi.commit));
179
210
  const groups = appEl('div', 'hgroups');
@@ -214,7 +245,7 @@ export function appSpan(cache) {
214
245
  cache.slot = cache.list.map((i) => cache.rank[i]);
215
246
  const cols = count * (cache.list.length + 1);
216
247
  const rows = appData.rows.length + 1;
217
- cache.grid.style.width = (cols * APP_COL) + 'px';
248
+ cache.grid.style.width = (APP_COMMIT + cols * APP_COL) + 'px';
218
249
  cache.grid.style.height = (APP_HEAD + rows * APP_ROW) + 'px';
219
250
  if (count === 0) return { r0: 0, r1: -1, c0: 0, c1: -1 };
220
251
  const high = shell.clientHeight || APP_MIN_ROWS * APP_ROW;
package/src/table.css CHANGED
@@ -1,25 +1,29 @@
1
1
  /* The report's table: a grid of plain elements rather than a `<table>`, and only the part of it the reader looks at is
2
2
  * built (`src/page/table.js` says why, and what was measured).
3
3
  *
4
- * Three figures are the whole geometry a metric column, a row and the header and they are written twice, here and
5
- * in the script that counts the window's ordinals in them. Two copies of a number are two answers waiting to happen,
6
- * hence `test/page-grid.test.js` reads these three declarations and holds the script to them. The fourth, the commit
7
- * column's width, is the styling's alone: the script places the numbers from the left edge of the grid, and the caption
8
- * is pinned over them.
4
+ * Everything here hangs off `#grid`, and that is not a habit: this sheet is the package's **shared** part (`src/css.js`)
5
+ * while the page brings a `.panel .row` of its own, and an unscoped rule for the table's rows took that row out of the
6
+ * flow with it (the panel's switches stood on top of one another until the rules were scoped).
7
+ *
8
+ * Four figures are the whole geometry — a metric column, a row, the header and the commit column — and they are written
9
+ * twice, here and in the script that counts the window's ordinals in them. Two copies of a number are two answers waiting
10
+ * to happen, hence `test/page-grid.test.js` reads these four declarations and holds the script to them.
11
+ *
12
+ * One border: 1px of one colour — a row's bottom edge, a group's left edge, the lines of the header. A heavier line or a
13
+ * second colour would promise a hierarchy to be worked out rather than read.
9
14
  *
10
15
  * One type face for the whole table; numbers line up by their digits thanks to tabular-nums rather than through a
11
- * monospaced font. Every column is the same width and fixed: the numbers are short and of one kind, and a width that
12
- * came out of the text would have to be measured over every cell of the column — the very cost this step removed.
13
- * A file's caption over its group is cut with an ellipsis rather than wrapped (`appCaption`), because the header is one
14
- * line high and the grid is built of rows of one height.
16
+ * monospaced font. Every column is the same width and fixed: the numbers are short and of one kind, and a width that came
17
+ * out of the text would have to be measured over every cell of the column — the very cost this step removed. The header is
18
+ * two lines of one row each — `--head` is exactly two `--row` and a name too long for its group is cut with an ellipsis
19
+ * rather than wrapped (`appCaption`) or run over its neighbour.
15
20
  */
16
21
  #grid {
17
22
  --col: 70px;
18
23
  --row: 25px;
19
- --head: 44px;
24
+ --head: 50px;
20
25
  --commit: 220px;
21
26
  --grid-line: rgba(127, 127, 127, .25);
22
- --grid-edge: rgba(127, 127, 127, .35);
23
27
  position: relative;
24
28
  font-variant-numeric: tabular-nums;
25
29
  }
@@ -28,8 +32,8 @@
28
32
  * painting — no layout and no script — while the width of the content gives the scrollbar its length and the script its
29
33
  * ordinals. The cells of a row are one grid of fixed tracks (`grid-auto-columns`): a cell cannot change the width of a
30
34
  * column, and it cannot push its neighbour. */
31
- .row { position: absolute; left: 0; width: 100%; height: var(--row); }
32
- .cells {
35
+ #grid .row { position: absolute; left: 0; width: 100%; height: var(--row); }
36
+ #grid .cells {
33
37
  position: absolute;
34
38
  top: 0;
35
39
  display: grid;
@@ -37,32 +41,42 @@
37
41
  grid-auto-columns: var(--col);
38
42
  height: var(--row);
39
43
  }
40
- .cells > span, .hgroups > span, .hmetrics > span { box-sizing: border-box; white-space: nowrap; }
41
- .cells > span { padding: 2px 4px; line-height: 20px; border-bottom: 1px solid var(--grid-line); }
42
- .num { text-align: right; }
44
+ #grid .cells > span, #grid .hgroups > span, #grid .hmetrics > span { box-sizing: border-box; white-space: nowrap; }
45
+ /* Two pixels of padding and a line of twenty: with the border, a cell is one `--row` high — the same for the header's
46
+ * cells as for the numbers, or the header would be a band of another rhythm. */
47
+ #grid .cells > span {
48
+ padding: 2px 4px;
49
+ line-height: 20px;
50
+ border-bottom: 1px solid var(--grid-line);
51
+ }
52
+ #grid .num { text-align: right; }
43
53
  /* The left edge of a group — the total, and every file — is carried by the group's first metric. One class instead of
44
54
  * the four rules of "which metric is switched on": the window is built out of the files that are on, so which column
45
55
  * stands first in a group is the page's own answer rather than something the styling has to work out. */
46
- .cells > .g, .hmetrics > .g, .hgroups > .gh { border-left: 1px solid var(--grid-edge); }
56
+ #grid .cells > .g, #grid .hmetrics > .g, #grid .hgroups > .gh { border-left: 1px solid var(--grid-line); }
47
57
 
48
58
  /* The header: one row of groups (the total and the files) over one row of metrics, stuck to the top edge of the shell,
49
59
  * and the commit column stuck to its left edge. Both carry an opaque background (Canvas), or the numbers would show
50
- * through them while the reader scrolls. */
51
- .head { position: sticky; top: 0; left: 0; z-index: 3; height: var(--head); background: Canvas; }
52
- .hgroups, .hmetrics { position: absolute; display: grid; grid-auto-flow: column; grid-auto-columns: var(--col); }
53
- .hgroups { top: 0; height: 22px; }
54
- .hmetrics { top: 22px; height: 22px; }
55
- .hgroups > span, .hmetrics > span { padding: 0 4px; line-height: 20px; border-bottom: 2px solid var(--grid-edge); }
56
- .hgroups > span { text-align: left; }
57
- /* A file's name is one line of a fixed room: a name that does not fit is cut with an ellipsis (`appCaption` puts the
58
- * whole of it into the tooltip) rather than wrapped — the grid is rows of one height — or run over its neighbour. */
59
- .hgroups > span { overflow: hidden; text-overflow: ellipsis; }
60
- .hmetrics > span { text-align: center; color: CanvasText; }
60
+ * through them while the reader scrolls. The two lines are placed by `top` and are one row high each, so the header
61
+ * aligns with the table below it rather than standing a size of its own. */
62
+ #grid .head { position: sticky; top: 0; left: 0; z-index: 3; height: var(--head); background: Canvas; }
63
+ #grid .hgroups, #grid .hmetrics { position: absolute; display: grid; grid-auto-flow: column; grid-auto-columns: var(--col); }
64
+ #grid .hgroups { top: 0; height: var(--row); }
65
+ #grid .hmetrics { top: var(--row); height: var(--row); }
66
+ #grid .hgroups > span, #grid .hmetrics > span {
67
+ padding: 2px 4px;
68
+ line-height: 20px;
69
+ border-bottom: 1px solid var(--grid-line);
70
+ }
71
+ /* A file's name stands over its group of metrics and is centred on it: the group is a column of numbers, and a caption
72
+ * that began at its left edge would carry the eye to the wrong place. */
73
+ #grid .hgroups > span { text-align: center; overflow: hidden; text-overflow: ellipsis; }
74
+ #grid .hmetrics > span { text-align: center; color: CanvasText; }
61
75
 
62
- /* The commit column: a sticky cell of every row, so the commit a number belongs to is in sight while the reader
63
- * scrolls sideways. Its width is fixed, and a caption longer than it is clipped — the whole subject stands in the
64
- * tooltip. */
65
- .c-commit {
76
+ /* The commit column: a sticky cell of every row, so the commit a number belongs to is in sight while the reader scrolls
77
+ * sideways. Its width is fixed and is the script's `APP_COMMIT` as well — the numbers are placed from the left edge of
78
+ * the grid *beside* the column, and a caption longer than it is clipped (the whole subject stands in the tooltip). */
79
+ #grid .c-commit {
66
80
  position: sticky;
67
81
  left: 0;
68
82
  z-index: 2;
@@ -79,24 +93,24 @@
79
93
  white-space: nowrap;
80
94
  border-bottom: 1px solid var(--grid-line);
81
95
  }
82
- .c-commit a { color: inherit; }
83
- .head .c-commit { z-index: 6; height: var(--head); line-height: var(--head); border-bottom-width: 2px; }
96
+ #grid .c-commit a { color: inherit; }
97
+ #grid .head .c-commit { z-index: 6; height: var(--head); line-height: var(--head); }
84
98
  /* This block fills the commit column: the cell clips what does not fit, and the subject is what gives way (the flex
85
99
  * item of `flex: 1 1 auto`), while the date and the journal mark keep their own width. */
86
- .clip { display: flex; align-items: baseline; gap: 6px; width: 100%; }
87
- .when { flex: none; opacity: .7; }
88
- .subj { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; display: block; }
89
- .subj.plain { opacity: .7; }
90
- .sect { flex: none; opacity: .7; font-size: 11px; text-decoration: none; border-bottom: 1px dotted currentColor; }
100
+ #grid .clip { display: flex; align-items: baseline; gap: 6px; width: 100%; }
101
+ #grid .when { flex: none; opacity: .7; }
102
+ #grid .subj { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; display: block; }
103
+ #grid .subj.plain { opacity: .7; }
104
+ #grid .sect { flex: none; opacity: .7; font-size: 11px; text-decoration: none; border-bottom: 1px dotted currentColor; }
91
105
  /* Growth green, fall red — by agreement with whoever asked for the report (growth is "more logic" rather than alarm). */
92
- .up { color: #1e8449; }
93
- .down { color: #c0392b; }
94
- .miss { opacity: .5; }
95
- /* The top row holds the current sizes: it is also what explains what the deltas below refer to. */
96
- .row.now > .c-commit { font-weight: 600; }
97
- .row.now > .c-commit, .row.now > .cells > span { border-bottom-width: 2px; }
106
+ #grid .up { color: #1e8449; }
107
+ #grid .down { color: #c0392b; }
108
+ #grid .miss { opacity: .5; }
109
+ /* The top row holds the current sizes: it is also what explains what the deltas below refer to — by its weight rather
110
+ * than by a heavier line, which would be a second border among the rows. */
111
+ #grid .row.now > .c-commit { font-weight: 600; }
98
112
  /* A row's highlight is laid over rather than swapped in: the sticky column has to stay opaque, or numbers show through
99
113
  * it while the reader scrolls sideways. */
100
- .row:hover > .c-commit, .row:hover > .cells > span {
114
+ #grid .row:hover > .c-commit, #grid .row:hover > .cells > span {
101
115
  background-image: linear-gradient(rgba(127, 127, 127, .08), rgba(127, 127, 127, .08));
102
116
  }