proctolog 0.1.1 → 0.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +77 -3
- data/README.md +15 -4
- data/app/controllers/proctolog/application_controller.rb +1 -1
- data/app/controllers/proctolog/bursts_controller.rb +1 -1
- data/app/controllers/proctolog/choices_controller.rb +3 -1
- data/app/controllers/proctolog/decisions_controller.rb +1 -1
- data/app/controllers/proctolog/notes_controller.rb +2 -2
- data/app/controllers/proctolog/prompts_controller.rb +1 -1
- data/app/controllers/proctolog/pull_requests_controller.rb +2 -4
- data/app/controllers/proctolog/review_data_controller.rb +3 -1
- data/app/controllers/proctolog/shares_controller.rb +27 -0
- data/app/helpers/proctolog/decisions_helper.rb +6 -2
- data/app/helpers/proctolog/desk_helper.rb +48 -8
- data/app/helpers/proctolog/rounds_helper.rb +4 -2
- data/app/helpers/proctolog/shares_helper.rb +11 -0
- data/app/helpers/proctolog/standings_helper.rb +5 -4
- data/app/models/proctolog/burst.rb +17 -8
- data/app/models/proctolog/choices.rb +8 -0
- data/app/models/proctolog/doctor.rb +9 -1
- data/app/models/proctolog/github.rb +1 -1
- data/app/models/proctolog/marks.rb +1 -1
- data/app/models/proctolog/note.rb +4 -0
- data/app/models/proctolog/owner.rb +3 -0
- data/app/models/proctolog/pick.rb +12 -0
- data/app/models/proctolog/rounds.rb +37 -0
- data/app/models/proctolog/share/ngrok.rb +120 -0
- data/app/models/proctolog/share/settings.rb +23 -0
- data/app/models/proctolog/share/tailscale.rb +103 -0
- data/app/models/proctolog/share.rb +101 -0
- data/app/models/proctolog/standing.rb +24 -7
- data/app/views/proctolog/bursts/_line.html.erb +2 -2
- data/app/views/proctolog/bursts/_side.html.erb +6 -5
- data/app/views/proctolog/bursts/_side_stop.html.erb +4 -4
- data/app/views/proctolog/notes/_card.html.erb +7 -3
- data/app/views/proctolog/open_pull_requests/_side.html.erb +4 -3
- data/app/views/proctolog/open_pull_requests/_start.html.erb +8 -0
- data/app/views/proctolog/open_pull_requests/index.html.erb +4 -5
- data/app/views/proctolog/open_pull_requests/start/_first_time.html.erb +3 -0
- data/app/views/proctolog/open_pull_requests/start/_nothing_open.html.erb +3 -0
- data/app/views/proctolog/open_pull_requests/start/_nothing_written.html.erb +3 -0
- data/app/views/proctolog/shares/_line.html.erb +5 -0
- data/app/views/proctolog/shares/show.html.erb +48 -0
- data/app/views/proctolog/shares/ways/_ngrok.html.erb +6 -0
- data/app/views/proctolog/shares/ways/_tailscale.html.erb +2 -0
- data/bin/proctolog +92 -6
- data/completions/_proctolog +28 -4
- data/config/application.rb +23 -4
- data/config/initializers/grouse.rb +1 -1
- data/config/routes.rb +3 -0
- data/docs/manual/bursts.md +7 -2
- data/docs/manual/deciding.md +4 -1
- data/docs/manual/handover.md +6 -0
- data/docs/manual/reading.md +54 -27
- data/docs/manual/sharing.md +77 -0
- data/lib/proctolog/changelog.rb +50 -0
- data/lib/proctolog/version.rb +1 -1
- data/public/asking.js +31 -4
- data/public/decisions.js +4 -4
- data/public/desk.js +10 -6
- data/public/keys.js +6 -0
- data/public/notes.js +164 -58
- data/public/pick.css +21 -0
- data/public/respond.css +6 -0
- data/public/respond.js +51 -7
- data/public/review-drafts.js +47 -9
- data/public/review-rounds.js +27 -3
- data/public/share.css +58 -0
- data/public/side.js +11 -20
- data/public/terminal.css +295 -34
- data/public/viewer.js +700 -173
- metadata +18 -1
data/public/review-rounds.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { helping, keyOf } from "./keys.js";
|
|
1
|
+
import { helping, keyOf, overThePage } from "./keys.js";
|
|
2
2
|
import { prNumber } from "./pr-number.js";
|
|
3
3
|
import {
|
|
4
4
|
announce,
|
|
5
5
|
handOver,
|
|
6
6
|
draftsState,
|
|
7
7
|
registerRounds,
|
|
8
|
+
settled,
|
|
8
9
|
stale,
|
|
9
10
|
updateDrafts,
|
|
10
11
|
} from "./review-drafts.js";
|
|
@@ -28,6 +29,25 @@ const reviewData = async () => {
|
|
|
28
29
|
if (!response.ok) throw new Error(`Desk returned ${response.status}`);
|
|
29
30
|
return response.json();
|
|
30
31
|
};
|
|
32
|
+
// The pane's ↩, on each pull request something came back on, in the words
|
|
33
|
+
// the desk gives (DeskHelper#side_mark).
|
|
34
|
+
const markThePane = (back = {}) => {
|
|
35
|
+
for (const row of document.querySelectorAll("[data-side-pr]")) {
|
|
36
|
+
const said = back[row.dataset.sidePr];
|
|
37
|
+
Object.assign(row.querySelector("[data-side-mark]"), {
|
|
38
|
+
textContent: said ? "↩" : "",
|
|
39
|
+
role: said ? "img" : null,
|
|
40
|
+
ariaLabel: said ?? null,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
// Once the desk has the owner's word on an answer, it has moved the notes the
|
|
45
|
+
// answer was to (Rounds#move_notes), and the pane is marked again from it. A
|
|
46
|
+
// desk that does not answer leaves the pane as the page drew it.
|
|
47
|
+
const followThePane = async () => {
|
|
48
|
+
await settled();
|
|
49
|
+
markThePane((await reviewData()).back);
|
|
50
|
+
};
|
|
31
51
|
// What GitHub draws of each piece of markdown, by its words, asked once while
|
|
32
52
|
// the page is open: returned work is laid out again at every change of the
|
|
33
53
|
// drafts, and must not fall back to markdown each time. A piece that cannot
|
|
@@ -589,6 +609,7 @@ const mark = (item, resolution, latest, kind, text) => {
|
|
|
589
609
|
},
|
|
590
610
|
};
|
|
591
611
|
});
|
|
612
|
+
followThePane().catch(() => {});
|
|
592
613
|
selectResponse(
|
|
593
614
|
visibleResponses().find((node) => node.dataset.request === next) ||
|
|
594
615
|
visibleResponses()[0],
|
|
@@ -1275,6 +1296,7 @@ registerRounds({
|
|
|
1275
1296
|
context = await reviewData();
|
|
1276
1297
|
importServerBatches();
|
|
1277
1298
|
importServerResponses();
|
|
1299
|
+
markThePane(context.back);
|
|
1278
1300
|
},
|
|
1279
1301
|
});
|
|
1280
1302
|
|
|
@@ -1290,6 +1312,7 @@ tools
|
|
|
1290
1312
|
? "Agent response imported. Confirm or reply to its existing requests."
|
|
1291
1313
|
: "The desk has this answer already.",
|
|
1292
1314
|
);
|
|
1315
|
+
followThePane().catch(() => {});
|
|
1293
1316
|
} catch (error) {
|
|
1294
1317
|
announce(`Response could not be imported: ${error.message}`);
|
|
1295
1318
|
} finally {
|
|
@@ -1361,8 +1384,9 @@ document
|
|
|
1361
1384
|
.querySelector("[data-enter-responses]")
|
|
1362
1385
|
?.addEventListener("click", enterResponses);
|
|
1363
1386
|
document.addEventListener("focusin", (event) => {
|
|
1364
|
-
// A picture looked at closely
|
|
1365
|
-
|
|
1387
|
+
// A picture looked at closely, or a note written in Grouse's overlay, leaves
|
|
1388
|
+
// the response marked: Esc comes back to it.
|
|
1389
|
+
if (overThePage(event.target)) return;
|
|
1366
1390
|
const node = event.target.closest("[data-request]");
|
|
1367
1391
|
if (node) markResponse(node);
|
|
1368
1392
|
else activeResponse?.removeAttribute("aria-current");
|
data/public/share.css
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/* Sharing the desk: where it is now, then each way to share it, in the
|
|
2
|
+
route's own frame, with what it needs first or its button under its words. */
|
|
3
|
+
|
|
4
|
+
.share .now {
|
|
5
|
+
margin-block: 0 0.5lh;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.share .ways {
|
|
9
|
+
border: 1px solid var(--rule);
|
|
10
|
+
border-top: 0;
|
|
11
|
+
background: var(--surface);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.share .way {
|
|
15
|
+
display: grid;
|
|
16
|
+
row-gap: 8px;
|
|
17
|
+
padding: var(--row-pad) 12px;
|
|
18
|
+
border-bottom: 1px solid var(--rule-soft);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.share .way:last-child {
|
|
22
|
+
border-bottom: 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.share .way h3 {
|
|
26
|
+
margin: 0;
|
|
27
|
+
font-size: 1rem;
|
|
28
|
+
color: var(--ink);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.share .way p {
|
|
32
|
+
margin: 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.share .way .facts {
|
|
36
|
+
color: var(--quiet);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.share .way form {
|
|
40
|
+
display: grid;
|
|
41
|
+
row-gap: 8px;
|
|
42
|
+
justify-items: start;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.share .allow {
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-wrap: wrap;
|
|
48
|
+
gap: 4px 2ch;
|
|
49
|
+
align-items: baseline;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.share .allow input {
|
|
53
|
+
width: min(40ch, 100%);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.share code {
|
|
57
|
+
white-space: nowrap;
|
|
58
|
+
}
|
data/public/side.js
CHANGED
|
@@ -14,32 +14,23 @@ const made = (name, properties = {}, ...children) => {
|
|
|
14
14
|
return element;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
// "3 of 19 decisions reviewed", from the row's "~" and "3/19".
|
|
18
|
-
const progressInWords = (mark, fraction) => {
|
|
19
|
-
if (!fraction) return "no decisions to review";
|
|
20
|
-
const [reviewed, total] = fraction.split("/").map(Number);
|
|
21
|
-
const decisions = total === 1 ? "decision" : "decisions";
|
|
22
|
-
if (mark === "x")
|
|
23
|
-
return total === 1
|
|
24
|
-
? "its one decision reviewed"
|
|
25
|
-
: `all ${total} decisions reviewed`;
|
|
26
|
-
if (!reviewed) return `none of ${total} ${decisions} reviewed yet`;
|
|
27
|
-
return `${reviewed} of ${total} ${decisions} reviewed`;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
17
|
const MOVED = {
|
|
31
18
|
changed: "changed on GitHub since it was read",
|
|
32
19
|
closed: "no longer open on GitHub",
|
|
33
20
|
};
|
|
34
21
|
|
|
22
|
+
// The row's marks said in words: what came back from the agent, then each
|
|
23
|
+
// grade's beads with what they count, in the words the server labelled them with.
|
|
35
24
|
const marksOf = (row) => {
|
|
36
|
-
const
|
|
37
|
-
const
|
|
25
|
+
const back = row.querySelector("[data-side-mark]");
|
|
26
|
+
const grades = row.querySelectorAll("[data-side-decisions] [role=img]");
|
|
38
27
|
return [
|
|
39
|
-
[
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
28
|
+
back.textContent && [back.textContent, back.ariaLabel],
|
|
29
|
+
...[...grades].map((grade) => [
|
|
30
|
+
made("span", { className: "beads" }, grade.cloneNode(true)),
|
|
31
|
+
grade.ariaLabel,
|
|
32
|
+
]),
|
|
33
|
+
!grades.length && ["", "no decisions to review"],
|
|
43
34
|
row.dataset.moved && ["*", MOVED[row.dataset.moved]],
|
|
44
35
|
].filter(Boolean);
|
|
45
36
|
};
|
|
@@ -62,7 +53,7 @@ const cardOf = (row) => {
|
|
|
62
53
|
made(
|
|
63
54
|
"div",
|
|
64
55
|
{},
|
|
65
|
-
made("dt", {
|
|
56
|
+
made("dt", {}, shown),
|
|
66
57
|
made("dd", { textContent: said }),
|
|
67
58
|
),
|
|
68
59
|
),
|
data/public/terminal.css
CHANGED
|
@@ -501,7 +501,10 @@ body.shell::before {
|
|
|
501
501
|
white-space: nowrap;
|
|
502
502
|
}
|
|
503
503
|
|
|
504
|
+
/* The ↩ of a pull request the agent's answers came back on asks for the owner. */
|
|
504
505
|
.side .stops .mark {
|
|
506
|
+
color: var(--ink);
|
|
507
|
+
font-weight: 700;
|
|
505
508
|
white-space: pre;
|
|
506
509
|
}
|
|
507
510
|
|
|
@@ -528,8 +531,7 @@ body.shell::before {
|
|
|
528
531
|
background: var(--rest);
|
|
529
532
|
}
|
|
530
533
|
|
|
531
|
-
.side .stops [aria-current] .number
|
|
532
|
-
.side .stops [aria-current] .mark {
|
|
534
|
+
.side .stops [aria-current] .number {
|
|
533
535
|
color: var(--ink);
|
|
534
536
|
}
|
|
535
537
|
|
|
@@ -539,11 +541,6 @@ body.shell::before {
|
|
|
539
541
|
white-space: normal;
|
|
540
542
|
}
|
|
541
543
|
|
|
542
|
-
.side .stops [aria-current] .fraction {
|
|
543
|
-
border-color: var(--rule-strong);
|
|
544
|
-
color: var(--ink);
|
|
545
|
-
}
|
|
546
|
-
|
|
547
544
|
/* The bars: how far, drawn square */
|
|
548
545
|
|
|
549
546
|
meter,
|
|
@@ -960,18 +957,33 @@ body.shell .foot {
|
|
|
960
957
|
color: var(--ink);
|
|
961
958
|
}
|
|
962
959
|
|
|
960
|
+
/* The stage, and beside it, for a pair, the panel of its views and regions;
|
|
961
|
+
under them the divider's slider, the caption and the keys, the width of
|
|
962
|
+
the window. */
|
|
963
963
|
.viewer[open] {
|
|
964
964
|
display: grid;
|
|
965
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
965
966
|
grid-template-rows: minmax(0, 1fr) auto auto auto;
|
|
966
967
|
}
|
|
967
968
|
|
|
968
969
|
.viewer .stage {
|
|
969
970
|
position: relative;
|
|
971
|
+
grid-column: 1;
|
|
972
|
+
grid-row: 1;
|
|
970
973
|
overflow: hidden;
|
|
971
974
|
cursor: crosshair;
|
|
972
975
|
touch-action: none;
|
|
973
976
|
}
|
|
974
977
|
|
|
978
|
+
.viewer .swipe {
|
|
979
|
+
grid-column: 1;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
.viewer .caption,
|
|
983
|
+
.viewer .keys {
|
|
984
|
+
grid-column: 1 / -1;
|
|
985
|
+
}
|
|
986
|
+
|
|
975
987
|
.viewer .stage[data-zoomed="true"] {
|
|
976
988
|
cursor: grab;
|
|
977
989
|
}
|
|
@@ -1011,7 +1023,9 @@ body.shell .foot {
|
|
|
1011
1023
|
}
|
|
1012
1024
|
|
|
1013
1025
|
/* The swipe's divider and the changed regions: as thin on the screen at any
|
|
1014
|
-
zoom, white
|
|
1026
|
+
zoom, white with black, so that they show on a light picture and a dark.
|
|
1027
|
+
A changed region is a black line dashed white, lighter than a note's solid
|
|
1028
|
+
frame, so the two are told apart at a glance. */
|
|
1015
1029
|
.viewer .divider,
|
|
1016
1030
|
.viewer .change {
|
|
1017
1031
|
position: absolute;
|
|
@@ -1038,24 +1052,211 @@ body.shell .foot {
|
|
|
1038
1052
|
}
|
|
1039
1053
|
|
|
1040
1054
|
.viewer .change {
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1055
|
+
--dash: calc(var(--line) * 2);
|
|
1056
|
+
margin: calc(var(--dash) * -1);
|
|
1057
|
+
border: var(--dash) solid #000;
|
|
1058
|
+
outline: var(--dash) dashed #fff;
|
|
1059
|
+
outline-offset: calc(var(--dash) * -1);
|
|
1044
1060
|
}
|
|
1045
1061
|
|
|
1046
1062
|
.viewer .change[data-current] {
|
|
1047
|
-
|
|
1063
|
+
--dash: calc(var(--line) * 3);
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
/* The region focused on says its number and its half, above it, as large on
|
|
1067
|
+
the screen at any zoom. */
|
|
1068
|
+
.viewer .change .tag {
|
|
1069
|
+
position: absolute;
|
|
1070
|
+
bottom: 100%;
|
|
1071
|
+
left: calc(var(--line) * -3);
|
|
1072
|
+
margin-bottom: calc(var(--line) * 3);
|
|
1073
|
+
padding: 0 calc(var(--line) * 5);
|
|
1074
|
+
background: #fff;
|
|
1075
|
+
color: #000;
|
|
1076
|
+
font-size: calc(var(--line) * 12);
|
|
1077
|
+
font-weight: 700;
|
|
1078
|
+
line-height: 1.5;
|
|
1079
|
+
white-space: nowrap;
|
|
1048
1080
|
}
|
|
1049
1081
|
|
|
1050
1082
|
.viewer .swipe {
|
|
1051
1083
|
margin: 0.3rem 1.1rem;
|
|
1052
1084
|
}
|
|
1053
1085
|
|
|
1054
|
-
|
|
1086
|
+
/* The map in the stage's corner, once the stage shows only part of the
|
|
1087
|
+
picture: the whole, small, its regions, and the part shown, framed. */
|
|
1088
|
+
.viewer .minimap {
|
|
1089
|
+
position: absolute;
|
|
1090
|
+
right: 12px;
|
|
1091
|
+
bottom: 12px;
|
|
1092
|
+
z-index: 1;
|
|
1093
|
+
padding: 4px;
|
|
1094
|
+
border: 1px solid var(--rule-strong);
|
|
1095
|
+
background: var(--paper);
|
|
1096
|
+
cursor: pointer;
|
|
1097
|
+
--line: 1px;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
.viewer .minimap[hidden] {
|
|
1101
|
+
display: none;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
.viewer .map-canvas {
|
|
1105
|
+
position: relative;
|
|
1106
|
+
overflow: hidden;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
.viewer .map-regions,
|
|
1110
|
+
.viewer .map-shown {
|
|
1111
|
+
pointer-events: none;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
.viewer .map-region {
|
|
1115
|
+
position: absolute;
|
|
1116
|
+
outline: 1px solid #000;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
.viewer .map-region[data-current] {
|
|
1120
|
+
outline: 2px solid #fff;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
.viewer .map-shown {
|
|
1124
|
+
position: absolute;
|
|
1125
|
+
border: 1px solid #fff;
|
|
1126
|
+
outline: 1px solid #000;
|
|
1127
|
+
box-shadow: 0 0 0 100vmax rgb(0 0 0 / 0.45);
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
/* The panel beside a pair, quiet: rows without boxes, the view looked at in
|
|
1131
|
+
reverse with a line on what it shows, the regions by number, and the one
|
|
1132
|
+
focused on as each half has it. It scrolls under the ✕'s corner. */
|
|
1133
|
+
.viewer .compare {
|
|
1134
|
+
grid-column: 2;
|
|
1135
|
+
grid-row: 1;
|
|
1136
|
+
box-sizing: border-box;
|
|
1137
|
+
width: 16rem;
|
|
1138
|
+
min-height: 0;
|
|
1139
|
+
margin-top: 3rem;
|
|
1140
|
+
padding: 0.6rem 0.8rem 1rem;
|
|
1141
|
+
overflow-y: auto;
|
|
1142
|
+
border-left: 1px solid var(--rule);
|
|
1143
|
+
background: var(--panel);
|
|
1144
|
+
font-size: 0.86rem;
|
|
1145
|
+
--line: 1px;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
.viewer .compare[hidden] {
|
|
1149
|
+
display: none;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
.viewer .compare h2 {
|
|
1153
|
+
margin: 0 0 0.4rem;
|
|
1154
|
+
color: var(--quiet);
|
|
1155
|
+
font-size: 0.8rem;
|
|
1156
|
+
font-weight: 600;
|
|
1157
|
+
letter-spacing: 0.025em;
|
|
1158
|
+
text-transform: uppercase;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
.viewer .compare h2 .count {
|
|
1055
1162
|
color: var(--ink);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
.viewer .compare section + section {
|
|
1166
|
+
margin-top: 1.4rem;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
.viewer .compare p {
|
|
1170
|
+
margin: 0.4rem 0;
|
|
1171
|
+
color: var(--quiet);
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
.viewer .compare button {
|
|
1175
|
+
border-color: transparent;
|
|
1176
|
+
cursor: pointer;
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
.viewer .compare .way {
|
|
1180
|
+
display: flex;
|
|
1181
|
+
flex-wrap: wrap;
|
|
1182
|
+
align-items: baseline;
|
|
1183
|
+
gap: 0 1ch;
|
|
1184
|
+
width: 100%;
|
|
1185
|
+
padding: 0.15rem 0.4rem;
|
|
1186
|
+
text-align: left;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
.viewer .compare .way .shows {
|
|
1190
|
+
display: flex;
|
|
1191
|
+
flex-wrap: wrap;
|
|
1192
|
+
gap: 0 1.2ch;
|
|
1193
|
+
width: 100%;
|
|
1194
|
+
padding-left: calc(1.7em + 1ch);
|
|
1195
|
+
font-size: 0.8rem;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
.viewer .compare [aria-pressed="true"] kbd {
|
|
1199
|
+
border-color: currentcolor;
|
|
1200
|
+
color: inherit;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
.viewer .compare .places {
|
|
1204
|
+
display: flex;
|
|
1205
|
+
flex-wrap: wrap;
|
|
1206
|
+
gap: 0.15rem;
|
|
1207
|
+
margin: 0;
|
|
1208
|
+
padding: 0;
|
|
1209
|
+
list-style: none;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
.viewer .compare .place {
|
|
1213
|
+
min-width: 2em;
|
|
1214
|
+
padding: 0 0.3rem;
|
|
1215
|
+
color: var(--quiet);
|
|
1216
|
+
font-size: 0.8rem;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
.viewer .compare .place[aria-current] {
|
|
1220
|
+
background: var(--ink);
|
|
1221
|
+
color: var(--paper);
|
|
1056
1222
|
font-weight: 700;
|
|
1057
1223
|
}
|
|
1058
1224
|
|
|
1225
|
+
.viewer .compare .going {
|
|
1226
|
+
display: flex;
|
|
1227
|
+
flex-wrap: wrap;
|
|
1228
|
+
gap: 0 1.2ch;
|
|
1229
|
+
font-size: 0.8rem;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
/* The region focused on, as the before has it and as the after does; a
|
|
1233
|
+
press on either writes a note on it there. */
|
|
1234
|
+
.viewer .compare .crop {
|
|
1235
|
+
display: block;
|
|
1236
|
+
width: 100%;
|
|
1237
|
+
margin-top: 0.4rem;
|
|
1238
|
+
padding: 0.3rem;
|
|
1239
|
+
text-align: left;
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
.viewer .compare .crop .frame {
|
|
1243
|
+
position: relative;
|
|
1244
|
+
display: block;
|
|
1245
|
+
overflow: hidden;
|
|
1246
|
+
background: #000;
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
.viewer .compare .crop .label {
|
|
1250
|
+
display: block;
|
|
1251
|
+
margin-top: 0.15rem;
|
|
1252
|
+
color: var(--quiet);
|
|
1253
|
+
font-size: 0.8rem;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
.viewer .compare .crop:hover:not(:disabled) .label {
|
|
1257
|
+
color: var(--ink);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1059
1260
|
/* A region being drawn, and the place a note is being written on: white
|
|
1060
1261
|
inside black, so that it shows on a light picture and a dark, with all
|
|
1061
1262
|
outside it dimmed. */
|
|
@@ -1071,8 +1272,10 @@ body.shell .foot {
|
|
|
1071
1272
|
display: none;
|
|
1072
1273
|
}
|
|
1073
1274
|
|
|
1074
|
-
/* The notes on a picture
|
|
1075
|
-
|
|
1275
|
+
/* The notes on a picture: a solid frame, black outside and white inside, so
|
|
1276
|
+
that one band shows on a light picture and the other on a dark; heavier
|
|
1277
|
+
than a changed region's dashes, and as heavy on the screen at any zoom. A
|
|
1278
|
+
pin is a small square of the same frame. */
|
|
1076
1279
|
.viewer .notes {
|
|
1077
1280
|
position: absolute;
|
|
1078
1281
|
inset: 0;
|
|
@@ -1080,17 +1283,18 @@ body.shell .foot {
|
|
|
1080
1283
|
}
|
|
1081
1284
|
|
|
1082
1285
|
.viewer .note {
|
|
1286
|
+
--frame: calc(var(--line) * 2);
|
|
1083
1287
|
position: absolute;
|
|
1084
|
-
margin: calc(var(--
|
|
1085
|
-
|
|
1086
|
-
|
|
1288
|
+
margin: calc(var(--frame) * -2);
|
|
1289
|
+
padding: var(--frame);
|
|
1290
|
+
border: var(--frame) solid #000;
|
|
1291
|
+
box-shadow: inset 0 0 0 var(--frame) #fff;
|
|
1087
1292
|
}
|
|
1088
1293
|
|
|
1089
1294
|
.viewer .note.pin {
|
|
1090
|
-
width: calc(var(--line) *
|
|
1091
|
-
height: calc(var(--line) *
|
|
1092
|
-
margin: calc(var(--line) * -
|
|
1093
|
-
border-radius: 50%;
|
|
1295
|
+
width: calc(var(--line) * 12);
|
|
1296
|
+
height: calc(var(--line) * 12);
|
|
1297
|
+
margin: calc(var(--line) * -6 - var(--frame) * 2);
|
|
1094
1298
|
}
|
|
1095
1299
|
|
|
1096
1300
|
/* A note saved opens at a click, and says so under the pointer. */
|
|
@@ -1099,19 +1303,21 @@ body.shell .foot {
|
|
|
1099
1303
|
cursor: pointer;
|
|
1100
1304
|
}
|
|
1101
1305
|
|
|
1102
|
-
.viewer[data-takes-notes] .note[data-note]:hover
|
|
1103
|
-
|
|
1306
|
+
.viewer[data-takes-notes] .note[data-note]:hover,
|
|
1307
|
+
.viewer .note.drafted {
|
|
1308
|
+
--frame: calc(var(--line) * 3);
|
|
1104
1309
|
}
|
|
1105
1310
|
|
|
1106
1311
|
.viewer .note.drafted {
|
|
1107
|
-
|
|
1108
|
-
|
|
1312
|
+
box-shadow:
|
|
1313
|
+
inset 0 0 0 var(--frame) #fff,
|
|
1314
|
+
0 0 0 calc(var(--line) * 100000) rgb(0 0 0 / 0.5);
|
|
1109
1315
|
}
|
|
1110
1316
|
|
|
1111
|
-
/* The note's form, beside the place it is about. */
|
|
1317
|
+
/* The note's form, beside the place it is about, over the map. */
|
|
1112
1318
|
.viewer .beside-note {
|
|
1113
1319
|
position: absolute;
|
|
1114
|
-
z-index:
|
|
1320
|
+
z-index: 2;
|
|
1115
1321
|
width: min(24rem, calc(100% - 24px));
|
|
1116
1322
|
cursor: auto;
|
|
1117
1323
|
}
|
|
@@ -1150,7 +1356,7 @@ body.shell .foot {
|
|
|
1150
1356
|
position: absolute;
|
|
1151
1357
|
top: 0.6rem;
|
|
1152
1358
|
right: 0.8rem;
|
|
1153
|
-
z-index:
|
|
1359
|
+
z-index: 3;
|
|
1154
1360
|
min-width: 2.2rem;
|
|
1155
1361
|
padding: 0.1rem 0.6ch;
|
|
1156
1362
|
border: 1px solid var(--rule-strong);
|
|
@@ -1300,15 +1506,60 @@ body[data-page="pull_requests"] .flash {
|
|
|
1300
1506
|
font-weight: 400;
|
|
1301
1507
|
}
|
|
1302
1508
|
|
|
1303
|
-
.side .stops .
|
|
1304
|
-
min-width: 4ch;
|
|
1509
|
+
.side .stops .decisions {
|
|
1305
1510
|
padding-left: 0.6ch;
|
|
1306
|
-
border-left: 1px solid var(--rule-soft);
|
|
1307
1511
|
color: var(--quiet);
|
|
1308
1512
|
font-size: 0.8rem;
|
|
1309
1513
|
text-align: right;
|
|
1310
1514
|
}
|
|
1311
1515
|
|
|
1516
|
+
/* Decisions counted as beads, the stepper's own (below): a bead to each
|
|
1517
|
+
blocking decision, a smaller one to each non-blocking, hollow while it
|
|
1518
|
+
waits for the owner and solid once reviewed. In the pane they are smaller
|
|
1519
|
+
again. */
|
|
1520
|
+
|
|
1521
|
+
.beads {
|
|
1522
|
+
display: inline-flex;
|
|
1523
|
+
gap: 1ch;
|
|
1524
|
+
align-items: center;
|
|
1525
|
+
vertical-align: middle;
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
.beads > span {
|
|
1529
|
+
display: inline-flex;
|
|
1530
|
+
gap: 3px;
|
|
1531
|
+
align-items: center;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
.beads .non-blocking .bead {
|
|
1535
|
+
width: 6px;
|
|
1536
|
+
height: 6px;
|
|
1537
|
+
border-color: var(--quiet);
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
.side .beads {
|
|
1541
|
+
gap: 0.8ch;
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
.side .beads > span {
|
|
1545
|
+
gap: 2px;
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
.side .beads .bead {
|
|
1549
|
+
width: 7px;
|
|
1550
|
+
height: 7px;
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
.side .beads .non-blocking .bead {
|
|
1554
|
+
width: 5px;
|
|
1555
|
+
height: 5px;
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
/* A burst's count: a hollow bead of the grade, then how many of it wait. */
|
|
1559
|
+
.side .beads .count {
|
|
1560
|
+
gap: 0.4ch;
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1312
1563
|
.pull-request .status {
|
|
1313
1564
|
display: block;
|
|
1314
1565
|
margin: 8px 0 var(--group-gap);
|
|
@@ -2496,17 +2747,23 @@ button.choice[hidden] {
|
|
|
2496
2747
|
}
|
|
2497
2748
|
|
|
2498
2749
|
.stepper .cell,
|
|
2499
|
-
.finish .bead
|
|
2750
|
+
.finish .bead,
|
|
2751
|
+
.beads .bead {
|
|
2500
2752
|
box-sizing: border-box;
|
|
2501
2753
|
width: 9px;
|
|
2502
2754
|
height: 9px;
|
|
2503
2755
|
border: 1px solid var(--ink);
|
|
2504
2756
|
border-radius: 50% !important;
|
|
2757
|
+
}
|
|
2758
|
+
|
|
2759
|
+
.stepper .cell,
|
|
2760
|
+
.finish .bead {
|
|
2505
2761
|
cursor: pointer;
|
|
2506
2762
|
}
|
|
2507
2763
|
|
|
2508
2764
|
.stepper .cell:not([data-state=""]),
|
|
2509
|
-
.finish [data-line-of]:not([data-state=""]) .bead
|
|
2765
|
+
.finish [data-line-of]:not([data-state=""]) .bead,
|
|
2766
|
+
.beads .bead.reviewed {
|
|
2510
2767
|
border-color: var(--quiet);
|
|
2511
2768
|
background: var(--quiet);
|
|
2512
2769
|
}
|
|
@@ -4002,6 +4259,10 @@ body[data-page="bursts"] > .main {
|
|
|
4002
4259
|
text-align: right;
|
|
4003
4260
|
}
|
|
4004
4261
|
|
|
4262
|
+
.lines .stands strong {
|
|
4263
|
+
color: var(--ink);
|
|
4264
|
+
}
|
|
4265
|
+
|
|
4005
4266
|
.lines .number {
|
|
4006
4267
|
margin: 0;
|
|
4007
4268
|
color: var(--quiet);
|