static-fire 0.0.0-stage → 0.44.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/LICENSE +21 -0
- package/README.md +230 -2
- package/bin/static-fire.js +46 -0
- package/package.json +29 -4
- package/pricing.yaml +20 -0
- package/src/adapters/index.ts +153 -0
- package/src/api.ts +218 -0
- package/src/cli.ts +297 -0
- package/src/core/apkit-install.ts +47 -0
- package/src/core/authored.ts +47 -0
- package/src/core/batch-state.ts +25 -0
- package/src/core/batch.ts +435 -0
- package/src/core/batches.ts +221 -0
- package/src/core/checks.ts +63 -0
- package/src/core/commands.ts +42 -0
- package/src/core/compare.ts +203 -0
- package/src/core/config.ts +25 -0
- package/src/core/copying.ts +18 -0
- package/src/core/db.ts +572 -0
- package/src/core/derived.ts +74 -0
- package/src/core/engine.ts +85 -0
- package/src/core/facets.ts +128 -0
- package/src/core/grade.ts +197 -0
- package/src/core/grading-versions.ts +281 -0
- package/src/core/identity.ts +263 -0
- package/src/core/init.ts +231 -0
- package/src/core/judge-schema.ts +37 -0
- package/src/core/judge.ts +166 -0
- package/src/core/label.ts +43 -0
- package/src/core/lock.ts +40 -0
- package/src/core/migrate.ts +288 -0
- package/src/core/new-task.ts +85 -0
- package/src/core/outside-tools.ts +129 -0
- package/src/core/profiles.ts +42 -0
- package/src/core/project.ts +54 -0
- package/src/core/regrade.ts +233 -0
- package/src/core/score.ts +148 -0
- package/src/core/settings.ts +44 -0
- package/src/core/task-file.ts +95 -0
- package/src/core/trial-detail.ts +73 -0
- package/src/core/types.ts +195 -0
- package/src/core/view-query.ts +85 -0
- package/src/core/view.ts +498 -0
- package/src/guide.md +547 -0
- package/src/server.ts +24 -0
- package/web/api.ts +6 -0
- package/web/app.tsx +1019 -0
- package/web/brand/offset-tokens.css +126 -0
- package/web/charts.tsx +190 -0
- package/web/compare.tsx +317 -0
- package/web/encoding.tsx +55 -0
- package/web/filter-menu.ts +164 -0
- package/web/index.html +17 -0
- package/web/pages.ts +16 -0
- package/web/run-status.ts +51 -0
- package/web/styles.css +333 -0
- package/web/suite-notes.ts +20 -0
- package/web/wording.ts +38 -0
package/web/styles.css
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/* Offset (The AI Launchpad visual system). Every colour, font, radius and shadow comes from
|
|
2
|
+
./brand/offset-tokens.css; nothing is defined here that is not a token or a token role.
|
|
3
|
+
Light scheme only: Offset's dark scheme is for packaging. */
|
|
4
|
+
@import url("./brand/offset-tokens.css");
|
|
5
|
+
|
|
6
|
+
* { box-sizing: border-box; }
|
|
7
|
+
html, body { margin: 0; background: var(--ground); color: var(--fg); font-family: var(--font-text); font-size: 15px; line-height: var(--leading-text); -webkit-font-smoothing: antialiased; }
|
|
8
|
+
button { font: inherit; color: inherit; cursor: pointer; }
|
|
9
|
+
code { font-family: var(--font-mono); font-size: 0.9em; }
|
|
10
|
+
.app { max-width: 1240px; margin: 0 auto; padding: var(--spacing-24) var(--spacing-16) var(--spacing-64); }
|
|
11
|
+
.muted { color: var(--fg-3); }
|
|
12
|
+
.error { color: var(--fg); background: var(--color-blush); border: var(--outline-width) solid var(--outline); border-radius: var(--radius-xs); padding: var(--spacing-8) var(--spacing-12); font-size: var(--text-sm); }
|
|
13
|
+
.kicker { font-family: var(--font-kicker); font-weight: var(--weight-kicker); font-size: var(--text-sm); letter-spacing: var(--tracking-kicker); text-transform: uppercase; color: var(--fg-3); display: flex; align-items: center; gap: var(--spacing-8); }
|
|
14
|
+
|
|
15
|
+
/* top bar */
|
|
16
|
+
.topbar { display: flex; align-items: center; flex-wrap: wrap; gap: var(--spacing-12); margin-bottom: var(--spacing-32); }
|
|
17
|
+
.brand { font-family: var(--font-display); font-weight: var(--weight-display); letter-spacing: var(--tracking-display); font-size: var(--text-xl); display: flex; align-items: center; gap: var(--spacing-8); }
|
|
18
|
+
.brand::before { content: ""; width: 22px; height: 22px; border-radius: var(--radius-xs); background: var(--accent); border: var(--outline-width) solid var(--outline); }
|
|
19
|
+
.spacer { flex: 1; }
|
|
20
|
+
|
|
21
|
+
/* page navigation (#24): one pill per page, the current one filled */
|
|
22
|
+
.nav { display: flex; gap: var(--spacing-4, 4px); }
|
|
23
|
+
.nav a { font-weight: 800; color: var(--fg-3); text-decoration: none; border: var(--outline-width) solid transparent; border-radius: var(--radius-pill); padding: 4px var(--spacing-16); }
|
|
24
|
+
.nav a:hover { color: var(--fg); }
|
|
25
|
+
.nav a.on { color: var(--fg); background: var(--accent); border-color: var(--outline); }
|
|
26
|
+
.page-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: var(--spacing-16); }
|
|
27
|
+
.page-head .sub { color: var(--fg-3); margin: 0; max-width: 72ch; }
|
|
28
|
+
select, .btn, input[type="number"] { border: var(--outline-width) solid var(--outline); background: var(--raised); border-radius: var(--radius-sm); padding: var(--spacing-8) var(--spacing-12); font: inherit; color: var(--fg); max-width: 100%; }
|
|
29
|
+
.btn { font-weight: 700; box-shadow: var(--shadow-sm); transition: transform .08s, box-shadow .08s; }
|
|
30
|
+
.btn:hover:not(:disabled) { transform: translateY(var(--press-y)); box-shadow: var(--shadow-sm-pressed); }
|
|
31
|
+
.btn-primary { background: var(--accent); }
|
|
32
|
+
.btn-quiet { box-shadow: none; background: var(--surface); margin-top: var(--spacing-16); font-size: var(--text-sm); }
|
|
33
|
+
.btn-quiet:hover:not(:disabled) { transform: none; box-shadow: none; background: var(--color-cream); }
|
|
34
|
+
.btn:disabled { opacity: 0.5; cursor: default; }
|
|
35
|
+
|
|
36
|
+
/* hero */
|
|
37
|
+
.hero { margin-bottom: var(--spacing-24); }
|
|
38
|
+
.hero h1 { font-family: var(--font-display); font-weight: var(--weight-display); letter-spacing: var(--tracking-display); line-height: var(--leading-display); font-size: clamp(2rem, 5vw, var(--text-5xl)); margin: var(--spacing-8) 0 var(--spacing-12); }
|
|
39
|
+
.meta { display: flex; flex-wrap: wrap; gap: var(--spacing-8) var(--spacing-24); color: var(--fg-3); font-size: var(--text-sm); margin-bottom: var(--spacing-16); }
|
|
40
|
+
.meta b { color: var(--fg); }
|
|
41
|
+
.progress { display: flex; align-items: center; gap: var(--spacing-12); }
|
|
42
|
+
.progress-track { flex: 1; height: 12px; border-radius: var(--radius-pill); background: var(--raised); border: var(--outline-width) solid var(--outline); overflow: hidden; }
|
|
43
|
+
.progress-fill { height: 100%; background: var(--accent); transition: width .4s ease; }
|
|
44
|
+
.pill { font-size: var(--text-sm); font-weight: 700; padding: 2px var(--spacing-12); border-radius: var(--radius-pill); border: var(--outline-width) solid var(--outline); background: var(--raised); white-space: nowrap; }
|
|
45
|
+
.pill.live { background: var(--color-mint); }
|
|
46
|
+
.pill.live::before { content: ""; display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--outline); margin-right: 6px; animation: pulse 1.4s infinite; }
|
|
47
|
+
@keyframes pulse { 50% { opacity: 0.25; } }
|
|
48
|
+
|
|
49
|
+
/* view chips */
|
|
50
|
+
.chips { display: flex; flex-wrap: wrap; gap: var(--spacing-8); margin-bottom: var(--spacing-16); }
|
|
51
|
+
.chip { border: var(--outline-width) solid var(--outline); background: var(--raised); border-radius: var(--radius-pill); padding: 4px var(--spacing-16); font-weight: 700; font-size: var(--text-sm); }
|
|
52
|
+
.chip.on { background: var(--accent); box-shadow: var(--shadow-sm-pressed); }
|
|
53
|
+
|
|
54
|
+
/* filter bar */
|
|
55
|
+
.filters { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--spacing-8) var(--spacing-12); margin-bottom: var(--spacing-24); }
|
|
56
|
+
.filters label { display: flex; flex-direction: column; gap: 4px; font-size: var(--text-sm); font-weight: 700; color: var(--fg-3); min-width: 0; }
|
|
57
|
+
.filters select, .filters input[type="date"] { border: var(--outline-width) solid var(--outline); background: var(--raised); border-radius: var(--radius-sm); padding: 6px var(--spacing-8); font: inherit; font-weight: 500; color: var(--fg); max-width: 260px; }
|
|
58
|
+
.filters .btn-quiet { margin-top: 0; }
|
|
59
|
+
|
|
60
|
+
/* filter bar: one Filter button with a searchable menu, and a tag per active filter (#26) */
|
|
61
|
+
.filter-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-8); margin-bottom: var(--spacing-24); }
|
|
62
|
+
.filter-bar .pop { position: relative; }
|
|
63
|
+
.filter-btn { display: inline-flex; align-items: center; gap: 6px; padding: 4px var(--spacing-16); border-radius: var(--radius-pill); font-size: var(--text-sm); }
|
|
64
|
+
.filter-btn.on { background: var(--accent); }
|
|
65
|
+
.filter-bar .menu { position: absolute; z-index: 20; top: calc(100% + 8px); left: 0; width: min(340px, calc(100vw - 32px)); background: var(--raised); border: var(--outline-width) solid var(--outline); border-radius: var(--radius-sm); box-shadow: var(--shadow-md); padding: var(--spacing-8); }
|
|
66
|
+
.filter-bar .menu input[type="search"] { width: 100%; box-sizing: border-box; font: inherit; font-size: var(--text-sm); border: 1.5px solid var(--outline); border-radius: var(--radius-xs); padding: 6px var(--spacing-8); margin-bottom: 6px; background: var(--ground); color: var(--fg); }
|
|
67
|
+
.filter-bar .menu-list { max-height: 320px; overflow: auto; }
|
|
68
|
+
.filter-bar .sec, .filter-bar .opt { display: flex; width: 100%; justify-content: space-between; align-items: center; gap: var(--spacing-8); border: 0; background: none; font: inherit; color: var(--fg); text-align: left; cursor: pointer; border-radius: 6px; }
|
|
69
|
+
.filter-bar .sec { padding: 6px; font-weight: 700; font-size: var(--text-sm); }
|
|
70
|
+
.filter-bar .sec i { display: inline-block; width: 14px; font-style: normal; }
|
|
71
|
+
.filter-bar .sec span:last-child { color: var(--fg-3); font-weight: 400; font-size: 12px; text-align: right; }
|
|
72
|
+
.filter-bar .sec span.sec-on { color: var(--fg); font-weight: 700; }
|
|
73
|
+
.filter-bar .sec:hover, .filter-bar .opt:hover, .filter-bar .sec:focus-visible, .filter-bar .opt:focus-visible { background: var(--surface); }
|
|
74
|
+
.filter-bar .opt { padding: 4px 6px; font-size: var(--text-sm); }
|
|
75
|
+
.filter-bar .opt.on { font-weight: 700; }
|
|
76
|
+
.filter-bar .opt em, .filter-bar .menu-flat-dates em { font-style: normal; color: var(--fg-3); }
|
|
77
|
+
.filter-bar .opt small { display: block; color: var(--fg-3); font-weight: 400; font-size: 12px; }
|
|
78
|
+
.filter-bar .opt-count { color: var(--fg-3); font-family: var(--font-mono); font-size: 12px; }
|
|
79
|
+
.filter-bar .in { padding-left: 14px; }
|
|
80
|
+
.filter-bar .grp { font-weight: 800; font-size: var(--text-xs); letter-spacing: var(--tracking-kicker); text-transform: uppercase; color: var(--fg-3); padding: 6px 6px 2px; }
|
|
81
|
+
.filter-bar .menu-dates { display: flex; flex-wrap: wrap; gap: var(--spacing-8); padding: 4px 6px; }
|
|
82
|
+
.filter-bar .menu-dates label { display: flex; flex-direction: column; gap: 2px; font-size: 12px; font-weight: 700; color: var(--fg-3); }
|
|
83
|
+
.filter-bar .menu-dates input { border: 1.5px solid var(--outline); background: var(--raised); border-radius: var(--radius-xs); padding: 4px 6px; font: inherit; font-size: var(--text-sm); color: var(--fg); }
|
|
84
|
+
.filter-bar .menu-flat-dates { padding: 4px 6px; font-size: var(--text-sm); }
|
|
85
|
+
.filter-bar .menu-none { margin: 0; padding: 6px; font-size: var(--text-sm); }
|
|
86
|
+
.tag { display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-sm); background: var(--surface); border: 1.5px solid var(--outline); border-radius: var(--radius-xs); padding: 2px 4px 2px 8px; }
|
|
87
|
+
.tag em { font-style: normal; color: var(--fg-3); }
|
|
88
|
+
.tag.grading { background: var(--color-lavender); }
|
|
89
|
+
.tag button { font: inherit; border: 0; background: none; cursor: pointer; padding: 0 4px; font-weight: 800; color: var(--fg); }
|
|
90
|
+
.clear-all { padding: 3px var(--spacing-12); border-radius: var(--radius-pill); border-style: dashed; box-shadow: none; font-size: var(--text-sm); }
|
|
91
|
+
.clear-all:hover:not(:disabled) { transform: none; box-shadow: none; background: var(--surface); }
|
|
92
|
+
|
|
93
|
+
/* cards */
|
|
94
|
+
.card { background: var(--raised); border: var(--outline-width) solid var(--outline); border-radius: var(--radius-md); box-shadow: var(--shadow-md); padding: var(--spacing-24); margin-bottom: var(--spacing-32); min-width: 0; }
|
|
95
|
+
.card h2 { font-family: var(--font-heading); font-weight: var(--weight-heading); letter-spacing: var(--tracking-heading); line-height: var(--leading-heading); font-size: var(--text-2xl); margin: var(--spacing-4) 0 var(--spacing-8); }
|
|
96
|
+
.card h3 { font-family: var(--font-heading); font-weight: var(--weight-heading-card); letter-spacing: -0.02em; font-size: var(--text-lg); margin: 0 0 2px; }
|
|
97
|
+
.card .sub { color: var(--fg-3); font-size: var(--text-sm); margin: 0 0 var(--spacing-16); max-width: 72ch; }
|
|
98
|
+
.grid3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--spacing-24); margin-bottom: var(--spacing-32); }
|
|
99
|
+
.grid3 .card { margin-bottom: 0; }
|
|
100
|
+
@media (max-width: 900px) { .grid3 { grid-template-columns: 1fr; } }
|
|
101
|
+
.note { color: var(--fg-3); font-size: var(--text-sm); margin: var(--spacing-12) 0 0; }
|
|
102
|
+
.empty { text-align: center; padding: var(--spacing-64) var(--spacing-24); }
|
|
103
|
+
.empty .kicker { justify-content: center; }
|
|
104
|
+
.empty h1 { font-family: var(--font-display); font-weight: var(--weight-display); letter-spacing: var(--tracking-display); font-size: var(--text-4xl); margin: var(--spacing-8) 0; }
|
|
105
|
+
|
|
106
|
+
/* legend */
|
|
107
|
+
.legend { display: flex; flex-wrap: wrap; gap: var(--spacing-8) var(--spacing-16); font-size: var(--text-sm); color: var(--fg-2); margin-bottom: var(--spacing-8); }
|
|
108
|
+
.legend span { display: inline-flex; align-items: center; gap: 6px; }
|
|
109
|
+
.legend .sep { width: 2px; height: 16px; background: var(--line); }
|
|
110
|
+
.swatch { width: 14px; height: 14px; border-radius: 4px; border: var(--outline-width) solid var(--outline); display: inline-block; }
|
|
111
|
+
.marker { flex: none; overflow: visible; }
|
|
112
|
+
.quad-key { width: 18px; height: 12px; background: var(--color-mint); border: var(--outline-width) solid var(--color-mint-2); border-radius: 3px; }
|
|
113
|
+
.pareto-key { width: 20px; border-top: 2px dotted var(--fg); }
|
|
114
|
+
.human-key { width: 20px; border-top: 3px solid var(--color-ink); }
|
|
115
|
+
.chart .human-line { stroke: var(--color-ink); stroke-width: 3; stroke-linecap: round; }
|
|
116
|
+
.chart .human-label { fill: var(--fg); font-size: 12.5px; font-weight: 700; paint-order: stroke; stroke: var(--raised); stroke-width: 4px; stroke-linejoin: round; }
|
|
117
|
+
|
|
118
|
+
/* charts */
|
|
119
|
+
.chart-wrap { position: relative; }
|
|
120
|
+
.chart { width: 100%; display: block; overflow: visible; }
|
|
121
|
+
.chart text { font-family: var(--font-text); fill: var(--fg-3); font-size: 12px; }
|
|
122
|
+
.chart .axis-title { fill: var(--fg-2); font-size: 13px; font-weight: 700; }
|
|
123
|
+
.chart .gridline { stroke: var(--dataviz-grid); }
|
|
124
|
+
.chart .quadrant { fill: var(--color-mint); opacity: 0.55; }
|
|
125
|
+
.chart .pt-label { fill: var(--fg); font-size: 12.5px; font-weight: 500; paint-order: stroke; stroke: var(--raised); stroke-width: 4px; stroke-linejoin: round; }
|
|
126
|
+
.chart .muted { fill: var(--fg-3); }
|
|
127
|
+
.tooltip { position: absolute; pointer-events: none; background: var(--raised); color: var(--fg); border: var(--outline-width) solid var(--outline); box-shadow: var(--shadow-sm); padding: var(--spacing-12); border-radius: var(--radius-sm); font-size: var(--text-sm); line-height: 1.5; min-width: 220px; transform: translate(-50%, calc(-100% - 16px)); z-index: 5; }
|
|
128
|
+
.tooltip .tt-head { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; }
|
|
129
|
+
.tooltip .row { display: flex; justify-content: space-between; gap: var(--spacing-16); }
|
|
130
|
+
.tooltip .row span:first-child { color: var(--fg-3); }
|
|
131
|
+
|
|
132
|
+
/* bars */
|
|
133
|
+
.bars { display: flex; flex-direction: column; gap: 10px; }
|
|
134
|
+
.bar-row { display: grid; grid-template-columns: minmax(0, 170px) minmax(0, 1fr); gap: var(--spacing-8); align-items: center; font-size: var(--text-sm); }
|
|
135
|
+
.bar-label { display: flex; align-items: center; gap: 6px; line-height: 1.25; color: var(--fg-2); }
|
|
136
|
+
.bar-label .marker { flex: none; }
|
|
137
|
+
.bar-track { position: relative; height: 20px; }
|
|
138
|
+
.bar { position: absolute; left: 0; top: 0; bottom: 0; border: var(--outline-width) solid var(--outline); border-radius: 0 4px 4px 0; min-width: 4px; transition: width .5s ease; }
|
|
139
|
+
.bar-val { position: absolute; top: 50%; transform: translateY(-50%); font-variant-numeric: tabular-nums; font-weight: 700; padding-left: 6px; white-space: nowrap; }
|
|
140
|
+
|
|
141
|
+
/* tables */
|
|
142
|
+
.table-wrap { overflow-x: auto; }
|
|
143
|
+
table { width: 100%; border-collapse: separate; border-spacing: 3px; font-size: var(--text-sm); }
|
|
144
|
+
th { font-weight: 700; color: var(--fg-3); font-size: 12px; text-align: center; padding: 6px 4px; vertical-align: bottom; }
|
|
145
|
+
th:first-child, td:first-child { text-align: left; }
|
|
146
|
+
td { padding: var(--spacing-8) 6px; border-radius: var(--radius-xs); text-align: center; font-variant-numeric: tabular-nums; }
|
|
147
|
+
td.cfg, .cfg { white-space: nowrap; display: flex; align-items: center; gap: var(--spacing-8); }
|
|
148
|
+
td.strong, th.strong { font-weight: 800; }
|
|
149
|
+
td .ci { color: var(--fg-3); font-weight: 500; }
|
|
150
|
+
tr.group td { text-align: left; font-family: var(--font-kicker); font-weight: var(--weight-kicker); text-transform: uppercase; letter-spacing: var(--tracking-kicker); font-size: 12px; color: var(--fg-3); padding-top: var(--spacing-16); }
|
|
151
|
+
table.criteria td.q { font-family: var(--font-mono); font-size: 12px; white-space: nowrap; }
|
|
152
|
+
.tag { display: inline-block; font-size: 11px; font-weight: 700; padding: 0 6px; border-radius: var(--radius-pill); border: var(--outline-width) solid var(--outline); margin-left: 6px; }
|
|
153
|
+
.tag.floor { background: var(--color-cream); }
|
|
154
|
+
.tag.strong { background: var(--color-sky); }
|
|
155
|
+
.tag.ceiling { background: var(--color-lavender); }
|
|
156
|
+
.tag.warn { background: var(--color-blush); }
|
|
157
|
+
td > .tag:first-child { margin-left: 0; }
|
|
158
|
+
td.q .tag { margin-left: var(--spacing-8); }
|
|
159
|
+
|
|
160
|
+
/* trials */
|
|
161
|
+
.trial-task + .trial-task { margin-top: var(--spacing-24); }
|
|
162
|
+
.trial-rows { display: flex; flex-direction: column; gap: var(--spacing-8); margin-top: var(--spacing-8); }
|
|
163
|
+
.trial-row { display: grid; grid-template-columns: minmax(0, 300px) minmax(0, 1fr); gap: var(--spacing-12); align-items: center; font-size: var(--text-sm); }
|
|
164
|
+
@media (max-width: 700px) { .trial-row { grid-template-columns: 1fr; } }
|
|
165
|
+
.trial-cells { display: flex; gap: var(--spacing-8); flex-wrap: wrap; }
|
|
166
|
+
.cell { min-width: 96px; padding: 6px 10px; border-radius: var(--radius-xs); border: var(--outline-width) solid var(--outline); background: var(--raised); font-size: 12px; text-align: left; display: flex; flex-direction: column; }
|
|
167
|
+
.cell .k { color: var(--fg-3); font-size: 11px; }
|
|
168
|
+
.cell .v { font-weight: 800; font-variant-numeric: tabular-nums; }
|
|
169
|
+
.cell.done { box-shadow: var(--shadow-sm); }
|
|
170
|
+
.cell.done:hover { transform: translateY(var(--press-y)); box-shadow: var(--shadow-sm-pressed); }
|
|
171
|
+
.cell.running, .cell.grading { background: var(--color-butter); }
|
|
172
|
+
.cell.running .v, .cell.grading .v { animation: pulse 1.4s infinite; font-weight: 600; }
|
|
173
|
+
.cell.invalid { background: var(--color-sun-2); }
|
|
174
|
+
.cell.failed { background: var(--color-blush); }
|
|
175
|
+
.cell.queued { opacity: 0.5; }
|
|
176
|
+
|
|
177
|
+
/* drawer */
|
|
178
|
+
.scrim { position: fixed; inset: 0; background: color-mix(in srgb, var(--color-ink) 35%, transparent); z-index: 10; }
|
|
179
|
+
.drawer { position: fixed; top: 0; right: 0; bottom: 0; width: min(1120px, 100vw); background: var(--ground); border-left: var(--outline-width) solid var(--outline); z-index: 11; display: flex; flex-direction: column; }
|
|
180
|
+
.drawer-head { padding: var(--spacing-16) var(--spacing-24); border-bottom: var(--outline-width) solid var(--outline); display: flex; align-items: flex-start; gap: var(--spacing-12); background: var(--raised); }
|
|
181
|
+
.drawer-head h2 { font-family: var(--font-heading); font-weight: var(--weight-heading); letter-spacing: var(--tracking-heading); font-size: var(--text-2xl); margin: 4px 0 0; }
|
|
182
|
+
.drawer-body { flex: 1; overflow: hidden; display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); }
|
|
183
|
+
@media (max-width: 800px) { .drawer-body { grid-template-columns: 1fr; overflow-y: auto; } .drawer-body > div { overflow: visible !important; } }
|
|
184
|
+
.drawer-body > div { overflow-y: auto; padding: var(--spacing-24); }
|
|
185
|
+
.drawer-body > div + div { border-left: var(--outline-width) solid var(--line); background: var(--surface); }
|
|
186
|
+
.drawer-body h3 { font-family: var(--font-heading); font-weight: var(--weight-heading); letter-spacing: var(--tracking-heading); font-size: var(--text-xl); margin: 0 0 var(--spacing-12); }
|
|
187
|
+
.stats { display: flex; gap: var(--spacing-24); flex-wrap: wrap; margin-top: var(--spacing-8); }
|
|
188
|
+
.stat .k { color: var(--fg-3); font-size: 12px; }
|
|
189
|
+
.stat .v { font-size: var(--text-lg); font-weight: 800; font-variant-numeric: tabular-nums; }
|
|
190
|
+
.close { margin-left: auto; border: var(--outline-width) solid var(--outline); background: var(--raised); border-radius: var(--radius-pill); width: 36px; height: 36px; font-size: 20px; line-height: 1; }
|
|
191
|
+
.tabs { display: flex; gap: 6px; margin-bottom: var(--spacing-16); }
|
|
192
|
+
.tab { border: var(--outline-width) solid var(--outline); background: var(--raised); border-radius: var(--radius-pill); padding: 2px var(--spacing-12); font-size: var(--text-sm); font-weight: 700; }
|
|
193
|
+
.tab.on { background: var(--accent); }
|
|
194
|
+
.prose { line-height: 1.65; max-width: 680px; }
|
|
195
|
+
.prose h1, .prose h2, .prose h3 { font-family: var(--font-heading); font-weight: var(--weight-heading-card); letter-spacing: -0.02em; line-height: 1.15; }
|
|
196
|
+
.prose code { background: var(--surface); padding: 1px 5px; border-radius: 6px; }
|
|
197
|
+
.prose pre { background: var(--surface); border: var(--outline-width) solid var(--line); padding: var(--spacing-12); border-radius: var(--radius-xs); overflow-x: auto; }
|
|
198
|
+
.prose pre code { background: none; padding: 0; }
|
|
199
|
+
.prose blockquote { border-left: 4px solid var(--accent); margin: 0; padding-left: var(--spacing-16); color: var(--fg-2); }
|
|
200
|
+
.prose img { display: none; }
|
|
201
|
+
.prose table { font-size: var(--text-sm); }
|
|
202
|
+
.prose td, .prose th { border: 1px solid var(--line); }
|
|
203
|
+
/* An image output in the trial drawer: never wider than the drawer column. */
|
|
204
|
+
.output-image { display: block; max-width: 100%; height: auto; border: var(--outline-width) solid var(--outline); border-radius: var(--radius-xs); }
|
|
205
|
+
pre.raw { white-space: pre-wrap; font-family: var(--font-mono); font-size: 12.5px; }
|
|
206
|
+
.verdict-group { margin-bottom: var(--spacing-24); }
|
|
207
|
+
.verdict-group > .crit-head { display: flex; justify-content: space-between; font-size: var(--text-lg); margin-bottom: var(--spacing-8); }
|
|
208
|
+
.crit-score { font-weight: 800; font-variant-numeric: tabular-nums; }
|
|
209
|
+
.crit { background: var(--raised); border: var(--outline-width) solid var(--outline); border-radius: var(--radius-sm); padding: var(--spacing-12); margin-bottom: var(--spacing-8); }
|
|
210
|
+
.crit-top { display: flex; gap: var(--spacing-8); align-items: flex-start; }
|
|
211
|
+
.crit-top .q { font-size: var(--text-sm); font-weight: 600; }
|
|
212
|
+
.crit-meta { display: flex; gap: var(--spacing-8); align-items: center; margin: 6px 0 2px; font-size: 12px; }
|
|
213
|
+
.crit-meta .tag { margin-left: 0; }
|
|
214
|
+
.reason { margin: 4px 0 0; font-size: var(--text-sm); color: var(--fg-2); }
|
|
215
|
+
.badge { flex: none; font-size: 12px; font-weight: 800; padding: 0 8px; border-radius: var(--radius-pill); border: var(--outline-width) solid var(--outline); }
|
|
216
|
+
.badge.pass { background: var(--color-mint); }
|
|
217
|
+
.badge.fail { background: var(--color-blush); }
|
|
218
|
+
.badge.split { background: var(--color-sun-2); }
|
|
219
|
+
.badge.err { background: var(--color-cream); }
|
|
220
|
+
.conditions { color: var(--fg-3); font-size: 12px; font-weight: 400; }
|
|
221
|
+
.conditions-list, .gradings { margin-bottom: var(--spacing-24); }
|
|
222
|
+
.conditions-list dl { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 4px var(--spacing-12); margin: 0; font-size: var(--text-sm); }
|
|
223
|
+
.conditions-list dt { color: var(--fg-3); }
|
|
224
|
+
.conditions-list dd { margin: 0; overflow-wrap: anywhere; }
|
|
225
|
+
.gradings ul { list-style: none; margin: 0; padding: 0; }
|
|
226
|
+
.gradings li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px var(--spacing-12); padding: var(--spacing-8) var(--spacing-12); margin-bottom: 6px; background: var(--raised); border: var(--outline-width) solid var(--line); border-radius: var(--radius-sm); font-size: var(--text-sm); }
|
|
227
|
+
.gradings li.counted { border-color: var(--outline); box-shadow: inset 4px 0 0 var(--accent); }
|
|
228
|
+
.gradings .g-name { flex-basis: 100%; font-weight: 700; }
|
|
229
|
+
.gradings .g-score { font-weight: 800; font-variant-numeric: tabular-nums; }
|
|
230
|
+
.gradings .g-status.invalid { color: var(--fg-2); }
|
|
231
|
+
.gradings .g-counted { margin-left: auto; font-size: 12px; font-weight: 800; padding: 0 8px; border-radius: var(--radius-pill); border: var(--outline-width) solid var(--outline); background: var(--accent); }
|
|
232
|
+
|
|
233
|
+
/* modal */
|
|
234
|
+
.modal { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: min(560px, calc(100vw - 32px)); max-height: calc(100vh - 32px); overflow-y: auto; background: var(--raised); border: var(--outline-width) solid var(--outline); box-shadow: var(--shadow-lg); border-radius: var(--radius-md); padding: var(--spacing-24); z-index: 11; }
|
|
235
|
+
.modal h2 { font-family: var(--font-heading); font-weight: var(--weight-heading); letter-spacing: var(--tracking-heading); font-size: var(--text-2xl); margin: 0 0 var(--spacing-16); }
|
|
236
|
+
.modal fieldset { border: none; padding: 0; margin: 0 0 var(--spacing-16); }
|
|
237
|
+
.modal legend { font-family: var(--font-kicker); font-weight: var(--weight-kicker); text-transform: uppercase; letter-spacing: var(--tracking-kicker); font-size: 12px; color: var(--fg-3); margin-bottom: 4px; }
|
|
238
|
+
.modal label.opt { display: flex; align-items: center; gap: var(--spacing-8); padding: 6px 2px; border-bottom: 1px solid var(--line-soft); font-size: var(--text-sm); }
|
|
239
|
+
.modal label.opt .muted { margin-left: auto; font-size: 12px; }
|
|
240
|
+
.modal select { width: 100%; }
|
|
241
|
+
.modal .row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-16); margin-top: var(--spacing-12); font-size: var(--text-sm); }
|
|
242
|
+
.modal .row label { display: flex; align-items: center; gap: var(--spacing-8); }
|
|
243
|
+
.modal .row.end { justify-content: flex-end; }
|
|
244
|
+
.modal input[type="number"] { width: 72px; padding: 4px var(--spacing-8); }
|
|
245
|
+
.envelope { background: var(--surface); border: var(--outline-width) solid var(--outline); border-radius: var(--radius-sm); padding: var(--spacing-12) var(--spacing-16); margin-bottom: var(--spacing-16); font-size: var(--text-sm); }
|
|
246
|
+
.envelope .k { font-family: var(--font-kicker); font-weight: var(--weight-kicker); text-transform: uppercase; letter-spacing: var(--tracking-kicker); font-size: 11px; color: var(--fg-3); margin-top: 4px; }
|
|
247
|
+
.envelope .subject { font-weight: 800; font-size: var(--text-lg); }
|
|
248
|
+
.img-ph { display: inline-block; background: var(--color-sky); border: var(--outline-width) dashed var(--outline); border-radius: var(--radius-xs); padding: 2px var(--spacing-8); font-size: var(--text-sm); }
|
|
249
|
+
|
|
250
|
+
/* batches panel (#13) */
|
|
251
|
+
.batches { margin-bottom: var(--spacing-24); }
|
|
252
|
+
.batch-list { list-style: none; margin: var(--spacing-12) 0 0; padding: 0; display: grid; gap: var(--spacing-12); }
|
|
253
|
+
.batch { border: var(--outline-width) solid var(--outline); border-radius: var(--radius-sm); padding: var(--spacing-12); background: var(--raised); }
|
|
254
|
+
/* one row per batch, in the columns of .batch-cols; stacked on narrow screens */
|
|
255
|
+
.batch-cols, .batch-head { display: grid; grid-template-columns: minmax(10em, 1fr) minmax(0, 2fr) minmax(150px, 1.5fr) 7.5em; gap: var(--spacing-8) var(--spacing-16); align-items: center; }
|
|
256
|
+
.batch-cols { margin: var(--spacing-12) 0 0; padding: 0 calc(var(--spacing-12) + var(--outline-width)); font-family: var(--font-kicker); font-weight: var(--weight-kicker); font-size: 12px; letter-spacing: var(--tracking-kicker); text-transform: uppercase; color: var(--fg-3); }
|
|
257
|
+
.batch-head { width: 100%; text-align: left; background: none; border: 0; padding: 0; }
|
|
258
|
+
.batch-id { display: flex; flex-direction: column; min-width: 0; }
|
|
259
|
+
.batch-id code { color: var(--fg-3); font-size: 12px; }
|
|
260
|
+
.batch-asked { color: var(--fg-3); font-size: var(--text-sm); min-width: 0; }
|
|
261
|
+
.batch-progress { display: flex; flex-direction: column; min-width: 0; }
|
|
262
|
+
.batch-head .batch-state { justify-self: start; }
|
|
263
|
+
@media (max-width: 720px) { .batch-cols { display: none; } .batch-head { grid-template-columns: 1fr; } }
|
|
264
|
+
.batch-state { font-size: var(--text-sm); font-weight: 700; padding: 2px var(--spacing-12); border-radius: var(--radius-pill); border: var(--outline-width) solid var(--outline); background: var(--surface); white-space: nowrap; }
|
|
265
|
+
.batch-state.running { background: var(--color-mint); }
|
|
266
|
+
.batch-state.stalled { background: var(--color-sun-2); }
|
|
267
|
+
.batch-bar { display: flex; height: 10px; margin: 0 0 var(--spacing-4, 4px); border-radius: var(--radius-pill); border: var(--outline-width) solid var(--outline); overflow: hidden; background: var(--surface); }
|
|
268
|
+
.batch-bar .seg { flex-basis: 0; transition: flex-grow .4s ease; }
|
|
269
|
+
.batch-bar .seg.done { background: var(--color-mint); }
|
|
270
|
+
.batch-bar .seg.failed { background: var(--color-blush); }
|
|
271
|
+
.batch-bar .seg.invalid { background: var(--color-sun-2); }
|
|
272
|
+
.batch-bar .seg.running { background: var(--color-butter); }
|
|
273
|
+
.batch-bar .seg.queued { background: var(--surface); }
|
|
274
|
+
.batch-line { font-size: var(--text-sm); }
|
|
275
|
+
.batch-trials { width: 100%; border-collapse: collapse; margin-top: var(--spacing-8); font-size: var(--text-sm); }
|
|
276
|
+
.batch-trials th, .batch-trials td { text-align: left; padding: 2px var(--spacing-8); border-top: 1px solid var(--dataviz-grid); }
|
|
277
|
+
.status.done { color: var(--fg); }
|
|
278
|
+
.status.failed, .status.invalid { font-weight: 700; }
|
|
279
|
+
|
|
280
|
+
/* left-out notice (under the chart) */
|
|
281
|
+
.left-out { margin-top: var(--spacing-12); }
|
|
282
|
+
.left-out .btn-quiet { margin-top: var(--spacing-8); }
|
|
283
|
+
.left-out .error { margin-top: var(--spacing-8); }
|
|
284
|
+
.empty .left-out { text-align: left; max-width: 72ch; margin: var(--spacing-24) auto 0; }
|
|
285
|
+
.linkish { background: none; border: 0; padding: 0; font: inherit; color: var(--fg); text-decoration: underline; cursor: pointer; }
|
|
286
|
+
|
|
287
|
+
/* chart card: Chart / Table toggle and the config table */
|
|
288
|
+
.card-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--spacing-8) var(--spacing-16); }
|
|
289
|
+
.view-toggle { display: inline-flex; border: var(--outline-width) solid var(--outline); border-radius: var(--radius-pill); overflow: hidden; background: var(--raised); }
|
|
290
|
+
.view-toggle button { font: inherit; font-weight: 700; font-size: var(--text-sm); color: var(--fg); border: 0; background: transparent; padding: 4px var(--spacing-16); cursor: pointer; }
|
|
291
|
+
.view-toggle button + button { border-left: var(--outline-width) solid var(--outline); }
|
|
292
|
+
.view-toggle button.on { background: var(--accent); }
|
|
293
|
+
table.configs th.num, table.configs td.num { text-align: right; white-space: nowrap; }
|
|
294
|
+
table.configs th:last-child, table.configs td:last-child { text-align: left; white-space: nowrap; }
|
|
295
|
+
table.configs tbody tr { cursor: pointer; }
|
|
296
|
+
table.configs tbody tr:hover td { background: var(--ground); }
|
|
297
|
+
table.configs .why { color: var(--fg-3); font-size: 12px; margin-top: 2px; }
|
|
298
|
+
|
|
299
|
+
/* Compare page (#27): the two picked versions, what changed between them, and the moved criteria */
|
|
300
|
+
.compare-picks { margin-bottom: var(--spacing-16); }
|
|
301
|
+
.compare-picks select { max-width: 420px; }
|
|
302
|
+
.two { display: grid; grid-template-columns: 1fr 1fr; gap: var(--spacing-12); }
|
|
303
|
+
@media (max-width: 720px) { .two { grid-template-columns: 1fr; } }
|
|
304
|
+
.ver { border: var(--outline-width) solid var(--outline); border-radius: var(--radius-sm); padding: var(--spacing-12); background: var(--color-lavender); min-width: 0; }
|
|
305
|
+
.ver .ver-name { display: block; font-size: var(--text-lg); margin: 2px 0; }
|
|
306
|
+
.ver .muted { font-size: var(--text-sm); }
|
|
307
|
+
.pill.current { background: var(--accent); font-size: 11px; padding: 0 var(--spacing-8); letter-spacing: 0; text-transform: none; }
|
|
308
|
+
.changes { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--spacing-12); }
|
|
309
|
+
.change { min-width: 0; }
|
|
310
|
+
.diff { font-family: var(--font-mono); font-size: var(--text-sm); background: var(--ground); border: var(--outline-width) solid var(--outline); border-radius: var(--radius-xs); padding: var(--spacing-8) var(--spacing-12); margin-top: 6px; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
311
|
+
.diff del { background: var(--color-blush); text-decoration: line-through; }
|
|
312
|
+
.diff ins { background: var(--color-mint); text-decoration: none; }
|
|
313
|
+
.diff .field { color: var(--fg-3); font-weight: 700; }
|
|
314
|
+
.pill.mark { font-size: 11px; padding: 0 var(--spacing-8); }
|
|
315
|
+
.pill.mark.changed, .pill.mark.added, .pill.mark.removed { background: var(--color-lavender); }
|
|
316
|
+
.pill.mark.same { background: var(--color-cream); }
|
|
317
|
+
.delta { font-weight: 700; padding: 1px 6px; border-radius: var(--radius-xs); }
|
|
318
|
+
.delta.up { background: var(--color-mint); }
|
|
319
|
+
.delta.down { background: var(--color-blush); }
|
|
320
|
+
.moved-head { margin-top: var(--spacing-24) !important; }
|
|
321
|
+
.reading { background: var(--color-butter); border: var(--outline-width) solid var(--outline); border-radius: var(--radius-sm); padding: var(--spacing-8) var(--spacing-12); margin: var(--spacing-16) 0 0; font-weight: 600; }
|
|
322
|
+
/* run status indicator in the top bar (#25): a pill that opens the Runs page */
|
|
323
|
+
.run-status { display: flex; align-items: center; gap: var(--spacing-8); font-size: var(--text-sm); font-weight: 600; border: var(--outline-width) solid var(--outline); border-radius: var(--radius-pill); padding: 3px var(--spacing-12); background: var(--raised); max-width: 100%; text-align: left; }
|
|
324
|
+
.run-status:hover { background: var(--color-cream); }
|
|
325
|
+
.run-status .dot { flex: none; width: 9px; height: 9px; border-radius: 50%; border: 1.5px solid var(--outline); background: var(--color-mint-2); }
|
|
326
|
+
.run-status .dot.none { background: var(--surface); }
|
|
327
|
+
.run-status .dot.run { background: var(--color-sun); animation: run-pulse 1.2s infinite; }
|
|
328
|
+
.run-status .dot.stalled, .run-status .dot.unavailable { background: var(--color-blush-2); }
|
|
329
|
+
@keyframes run-pulse { 50% { opacity: .35; } }
|
|
330
|
+
@media (prefers-reduced-motion: reduce) { .run-status .dot.run { animation: none; } }
|
|
331
|
+
.run-status .mini { flex: none; width: 70px; height: 7px; border: 1.5px solid var(--outline); border-radius: 4px; overflow: hidden; background: var(--raised); }
|
|
332
|
+
.run-status .mini b { display: block; height: 100%; background: var(--color-sun); transition: width .4s ease; }
|
|
333
|
+
.run-status-count { white-space: nowrap; font-variant-numeric: tabular-nums; }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// The suite descriptions the Results page shows with a chart. A suite can state facts that must stand next to any
|
|
2
|
+
// chart of it (for example where its tasks and criteria come from), so every chart that draws a suite shows them.
|
|
3
|
+
import type { Suite } from "../src/core/types";
|
|
4
|
+
import type { Scope } from "../src/core/view-query";
|
|
5
|
+
|
|
6
|
+
export interface SuiteNote { title: string; description: string }
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The described suites a chart draws: the chosen suite, every suite in the view for the Workflow Index, or each
|
|
10
|
+
* suite that holds the chosen task (a task's view has no suites of its own). Suites without a description are left out.
|
|
11
|
+
*/
|
|
12
|
+
export function suiteNotes(sel: Scope, suiteIds: string[], suites: Map<string, Suite>): SuiteNote[] {
|
|
13
|
+
const ids = sel.kind === "suite" ? [sel.id]
|
|
14
|
+
: sel.kind === "index" ? suiteIds
|
|
15
|
+
: [...suites.keys()].filter((id) => suites.get(id)!.tasks.includes(sel.id));
|
|
16
|
+
return ids.flatMap((id) => {
|
|
17
|
+
const s = suites.get(id), description = s?.description?.trim();
|
|
18
|
+
return s && description ? [{ title: s.title, description }] : [];
|
|
19
|
+
});
|
|
20
|
+
}
|
package/web/wording.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// The changed words between two wordings of one text (a reworded question, a changed context), for the Compare
|
|
2
|
+
// page to mark. Display only: what changed between two grading versions comes from the server's difference.
|
|
3
|
+
|
|
4
|
+
export interface WordPart { kind: "same" | "added" | "removed"; text: string }
|
|
5
|
+
|
|
6
|
+
/** Words, runs of spaces and single punctuation marks, so "(the subject" and "(subject" share the "(". */
|
|
7
|
+
const tokens = (s: string) => s.match(/\w+|\s+|[^\w\s]/g) ?? [];
|
|
8
|
+
|
|
9
|
+
/** Above this many token pairs the texts are shown as one removed and one added part. */
|
|
10
|
+
const MAX_CELLS = 4_000_000;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The parts of `b` against `a`, in reading order: kept, removed (only in `a`) and added (only in `b`). In a run of
|
|
14
|
+
* changes the removed part comes first. Joined, the kept and removed parts give `a`; the kept and added parts give `b`.
|
|
15
|
+
*/
|
|
16
|
+
export function wordChanges(a: string, b: string): WordPart[] {
|
|
17
|
+
const x = tokens(a), y = tokens(b);
|
|
18
|
+
const parts: WordPart[] = [];
|
|
19
|
+
const push = (kind: WordPart["kind"], text: string) => {
|
|
20
|
+
const last = parts.at(-1);
|
|
21
|
+
if (last?.kind === kind) last.text += text; else if (text) parts.push({ kind, text });
|
|
22
|
+
};
|
|
23
|
+
if (x.length * y.length > MAX_CELLS) { push("removed", a); push("added", b); return parts; }
|
|
24
|
+
// lcs[i][j]: the longest common run of tokens of x from i and y from j.
|
|
25
|
+
const w = y.length + 1, lcs = new Uint32Array((x.length + 1) * w);
|
|
26
|
+
for (let i = x.length - 1; i >= 0; i--) {
|
|
27
|
+
for (let j = y.length - 1; j >= 0; j--) {
|
|
28
|
+
lcs[i * w + j] = x[i] === y[j] ? lcs[(i + 1) * w + j + 1]! + 1 : Math.max(lcs[(i + 1) * w + j]!, lcs[i * w + j + 1]!);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
let i = 0, j = 0;
|
|
32
|
+
while (i < x.length || j < y.length) {
|
|
33
|
+
if (i < x.length && j < y.length && x[i] === y[j]) { push("same", x[i]!); i++; j++; }
|
|
34
|
+
else if (j >= y.length || (i < x.length && lcs[(i + 1) * w + j]! >= lcs[i * w + j + 1]!)) { push("removed", x[i]!); i++; }
|
|
35
|
+
else { push("added", y[j]!); j++; }
|
|
36
|
+
}
|
|
37
|
+
return parts;
|
|
38
|
+
}
|