@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 +43 -23
- package/package.json +2 -2
- package/src/page/app.css +8 -4
- package/src/page/build.js +8 -8
- package/src/page/payload.js +4 -5
- package/src/page/table.js +45 -14
- package/src/table.css +60 -46
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ shows.
|
|
|
10
10
|
|
|
11
11
|
## Status
|
|
12
12
|
|
|
13
|
-
**Release 2.8.
|
|
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` | **
|
|
241
|
-
| Full — release and CI | `pnpm test:all` | **
|
|
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
|
|
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
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
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
|
|
391
|
-
reader's first question is what that edit brought. The mark
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
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
|
|
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,
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
|
235
|
-
* (`
|
|
236
|
-
*
|
|
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
|
|
130
|
-
* commit (one with nothing to say lands in the list), and the file would stop being a
|
|
131
|
-
* after its own commit would yield different bytes and the hook would commit the report
|
|
132
|
-
*
|
|
133
|
-
*
|
|
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', '
|
|
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
|
|
package/src/page/payload.js
CHANGED
|
@@ -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
|
|
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 =
|
|
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
|
|
57
|
-
* commit, and
|
|
58
|
-
*
|
|
59
|
-
*
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
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:
|
|
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
|
-
|
|
42
|
-
|
|
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-
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
.hgroups {
|
|
54
|
-
.
|
|
55
|
-
|
|
56
|
-
.hgroups > span
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
-
*
|
|
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);
|
|
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
|
-
|
|
97
|
-
.row.now > .c-commit
|
|
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
|
}
|