@vernikr/size-report 2.7.0 → 2.8.0
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 +65 -44
- package/package.json +2 -2
- package/src/css.js +2 -2
- package/src/locales.js +0 -6
- package/src/page/app.css +7 -29
- package/src/page/app.js +29 -57
- package/src/page/build.js +6 -9
- package/src/page/table.js +221 -294
- package/src/table.css +89 -57
- package/src/page/work.js +0 -55
package/src/table.css
CHANGED
|
@@ -1,58 +1,88 @@
|
|
|
1
|
-
/*
|
|
2
|
-
*
|
|
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
|
+
* built (`src/page/table.js` says why, and what was measured).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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.
|
|
7
9
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
10
|
+
* 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.
|
|
15
|
+
*/
|
|
16
|
+
#grid {
|
|
17
|
+
--col: 70px;
|
|
18
|
+
--row: 25px;
|
|
19
|
+
--head: 44px;
|
|
20
|
+
--commit: 220px;
|
|
21
|
+
--grid-line: rgba(127, 127, 127, .25);
|
|
22
|
+
--grid-edge: rgba(127, 127, 127, .35);
|
|
23
|
+
position: relative;
|
|
24
|
+
font-variant-numeric: tabular-nums;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* The window: the rows stand at their own `top` inside the scrolled content, so scrolling costs the browser nothing but
|
|
28
|
+
* painting — no layout and no script — while the width of the content gives the scrollbar its length and the script its
|
|
29
|
+
* ordinals. The cells of a row are one grid of fixed tracks (`grid-auto-columns`): a cell cannot change the width of a
|
|
30
|
+
* column, and it cannot push its neighbour. */
|
|
31
|
+
.row { position: absolute; left: 0; width: 100%; height: var(--row); }
|
|
32
|
+
.cells {
|
|
33
|
+
position: absolute;
|
|
34
|
+
top: 0;
|
|
35
|
+
display: grid;
|
|
36
|
+
grid-auto-flow: column;
|
|
37
|
+
grid-auto-columns: var(--col);
|
|
38
|
+
height: var(--row);
|
|
39
|
+
}
|
|
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); }
|
|
29
42
|
.num { text-align: right; }
|
|
30
|
-
/* The group
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
/* A file's
|
|
45
|
-
*
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
.
|
|
43
|
+
/* The left edge of a group — the total, and every file — is carried by the group's first metric. One class instead of
|
|
44
|
+
* the four rules of "which metric is switched on": the window is built out of the files that are on, so which column
|
|
45
|
+
* 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); }
|
|
47
|
+
|
|
48
|
+
/* 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
|
+
* 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; }
|
|
61
|
+
|
|
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 {
|
|
66
|
+
position: sticky;
|
|
67
|
+
left: 0;
|
|
68
|
+
z-index: 2;
|
|
69
|
+
box-sizing: border-box;
|
|
70
|
+
width: var(--commit);
|
|
71
|
+
height: var(--row);
|
|
72
|
+
line-height: var(--row);
|
|
73
|
+
padding: 0 4px;
|
|
74
|
+
background: Canvas;
|
|
75
|
+
text-align: left;
|
|
76
|
+
font-weight: 400;
|
|
77
|
+
overflow: hidden;
|
|
78
|
+
text-overflow: ellipsis;
|
|
79
|
+
white-space: nowrap;
|
|
80
|
+
border-bottom: 1px solid var(--grid-line);
|
|
81
|
+
}
|
|
51
82
|
.c-commit a { color: inherit; }
|
|
52
|
-
|
|
53
|
-
/* This block fills the commit column
|
|
54
|
-
*
|
|
55
|
-
* numbers, because a table cell clips nothing. */
|
|
83
|
+
.head .c-commit { z-index: 6; height: var(--head); line-height: var(--head); border-bottom-width: 2px; }
|
|
84
|
+
/* This block fills the commit column: the cell clips what does not fit, and the subject is what gives way (the flex
|
|
85
|
+
* item of `flex: 1 1 auto`), while the date and the journal mark keep their own width. */
|
|
56
86
|
.clip { display: flex; align-items: baseline; gap: 6px; width: 100%; }
|
|
57
87
|
.when { flex: none; opacity: .7; }
|
|
58
88
|
.subj { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; display: block; }
|
|
@@ -62,9 +92,11 @@ thead .c-commit { z-index: 6; }
|
|
|
62
92
|
.up { color: #1e8449; }
|
|
63
93
|
.down { color: #c0392b; }
|
|
64
94
|
.miss { opacity: .5; }
|
|
65
|
-
/* The top row holds the current sizes: it is also what explains what the deltas refer to. */
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
/* A row's highlight is laid over rather than swapped in: the sticky column has to stay opaque, or numbers show through
|
|
69
|
-
*
|
|
70
|
-
|
|
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; }
|
|
98
|
+
/* A row's highlight is laid over rather than swapped in: the sticky column has to stay opaque, or numbers show through
|
|
99
|
+
* it while the reader scrolls sideways. */
|
|
100
|
+
.row:hover > .c-commit, .row:hover > .cells > span {
|
|
101
|
+
background-image: linear-gradient(rgba(127, 127, 127, .08), rgba(127, 127, 127, .08));
|
|
102
|
+
}
|
package/src/page/work.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/* The page's long work, and the stripe that says it is going on.
|
|
2
|
-
*
|
|
3
|
-
* A switch on a file's box changes a class on every node of that file's column, and a folder or a category is that same
|
|
4
|
-
* work over every file below it. That alone is cheap — measured at about 2 µs a node, so a whole category of this
|
|
5
|
-
* repository's report (73 columns, 55 042 nodes) is 120 ms of it — but it is not the price. **The browser lays this
|
|
6
|
-
* table out again for any change of a column's visibility, and that is close to a second on a table of a few hundred
|
|
7
|
-
* thousand cells** (`probes/step-12-columns.mjs`: 1 cell toggled 234 ms of layout, 750 cells 287 ms, 6 000 cells
|
|
8
|
-
* 539 ms, and the whole click on the shipped page 867 ms blocked with a 742 ms task).
|
|
9
|
-
*
|
|
10
|
-
* Hence the shape of this chapter, and it is a decision rather than a default. The drawing of a switch is **one task**:
|
|
11
|
-
* what is queued is drawn in a single go, one layout, one repaint. Slicing it — a queue worked off between timeouts —
|
|
12
|
-
* was written first and measured (Chrome 153, this repository's report): 37 slices of two columns each paid the table's
|
|
13
|
-
* relayout 37 times, 2.5–4 s a slice, 95 frames and 169 layouts of 151.9 s of pure layout time against 1.04 s for the
|
|
14
|
-
* same click when it is not sliced, with the tab growing to several gigabytes of repaint. The slice is the thing that
|
|
15
|
-
* freezes the page, only more often, so there is none.
|
|
16
|
-
*
|
|
17
|
-
* What is left is honesty about it: work short enough to be over before the browser could paint a stripe is done on the
|
|
18
|
-
* click itself, and above that the stripe appears, the drawing happens in the next task, and the stripe goes away —
|
|
19
|
-
* so a reader sees that the page is working rather than wondering whether it hung. The stripe carries no share: within
|
|
20
|
-
* one task the browser cannot repaint, so a bar that filled would be a bar that lies, and the page already knows the
|
|
21
|
-
* one thing that is true about it (the work is going on).
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
/* Above this much node work the drawing is one task with a stripe rather than a task on the click: a stripe that
|
|
25
|
-
* appears and disappears within the same frame is worse than none, and the figure is one file's column of a report of
|
|
26
|
-
* this repository's size (754 nodes). */
|
|
27
|
-
export const APP_LONG = 2000;
|
|
28
|
-
|
|
29
|
-
/* The stripe: on while a switch is being drawn, off when it is done. There is nothing to count here, and the length is
|
|
30
|
-
* carried by the styling (an indeterminate stripe), which is why this function takes a switch rather than a share. */
|
|
31
|
-
export function appBar(shown) {
|
|
32
|
-
const bar = document.getElementById('bar');
|
|
33
|
-
if (bar !== null) bar.hidden = !shown;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/* What a switch asks for: `items` are the columns that have to be drawn (`{i, units}` — the file's index and the nodes
|
|
37
|
-
* of its column), `step` draws one of them from the view, and the total decides whether the drawing is the reader's own
|
|
38
|
-
* click or the next task with the stripe over it. Only the columns out of step with the view are asked for at all
|
|
39
|
-
* (`appColumnStale`), so a report opened with everything switched on has nothing to draw here. */
|
|
40
|
-
export function appDraw(step, items) {
|
|
41
|
-
/* Counted by a plain walk rather than by `reduce`: the page's shell is held to a rule that it counts no totals of the
|
|
42
|
-
* table itself, and a guard that has to tell a sum of nodes from a sum of numbers is a guard that will be argued with
|
|
43
|
-
* one day. The count of nodes is not one of the report's numbers. */
|
|
44
|
-
let units = 0;
|
|
45
|
-
items.forEach((item) => { units += item.units; });
|
|
46
|
-
if (units <= APP_LONG) {
|
|
47
|
-
items.forEach((item) => step(item.i));
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
appBar(true);
|
|
51
|
-
setTimeout(() => {
|
|
52
|
-
items.forEach((item) => step(item.i));
|
|
53
|
-
appBar(false);
|
|
54
|
-
}, 0);
|
|
55
|
-
}
|