reviewzy 0.2.0 → 0.3.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.
@@ -2,17 +2,17 @@
2
2
  reviewzy — dashboard page styles
3
3
  ============================================================ */
4
4
 
5
- /* ---- Page shell (navbar shell per cloudy-ui) ---- */
5
+ /* The one override that retunes the column: the navbar's card and inner
6
+ column, the page width and this shell all read it. */
7
+ :root { --page-w: 1400px; }
8
+
9
+ /* ---- Page shell (navbar shell) ---- */
6
10
  .app-shell { min-height: 100vh; display: flex; flex-direction: column; }
7
- .main { padding: var(--space-10) var(--space-12); max-width: 1400px; margin: 0 auto; width: 100%; }
11
+ .main { padding: var(--space-10) var(--space-8); max-width: var(--page-w); margin: 0 auto; width: 100%; }
8
12
 
9
13
  /* ---- Page header: the eyebrow / title / lede triplet (login/editor pages) ---- */
10
- .page-header { margin-bottom: var(--space-8); padding-bottom: var(--space-5); border-bottom: 1px solid var(--line); }
11
- .page-eyebrow { color: var(--accent); margin-bottom: var(--space-2); }
12
- .page-title { font: 550 var(--text-2xl)/1.15 var(--font-sans); color: var(--text); letter-spacing: -0.02em; margin-bottom: var(--space-3); }
13
- .page-lede { font-size: var(--text-base); color: var(--text-dim); max-width: 540px; }
14
- /* The entries header is just the title plus the total count, no eyebrow or lede. */
15
- .page-count { font-size: var(--text-sm); color: var(--text-dim); }
14
+ .page-eyebrow { color: var(--accent-text); margin-bottom: var(--space-2); }
15
+ .page-lede { font-size: var(--t-3); color: var(--text-3); max-width: 540px; }
16
16
 
17
17
  /* ---- Filter form ---- */
18
18
  .filters { display: grid; grid-template-columns: minmax(0, 2fr) 200px 200px; gap: var(--space-3); align-items: end; margin-bottom: var(--space-8); }
@@ -21,43 +21,20 @@
21
21
  /* ---- Entries region ---- */
22
22
  /* The loading strip is hidden until htmx marks the request in flight (hx-indicator adds the
23
23
  .htmx-request class); it sits beside the swap target, so a swap never removes it. */
24
- #entries-loading { display: none; align-items: center; gap: var(--space-2); font-size: var(--text-sm); color: var(--text-dim); padding: var(--space-2) 0; }
24
+ #entries-loading { display: none; align-items: center; gap: var(--space-2); font-size: var(--t-2); color: var(--text-3); padding: var(--space-2) 0; }
25
25
  #entries-loading.htmx-request { display: flex; }
26
- /* The spinner reuses the @keyframes spin components.css ships for .btn-loading. */
27
- .spinner {
28
- width: 12px; height: 12px;
29
- border: 2px solid var(--line-strong);
30
- border-top-color: var(--accent);
31
- border-radius: 50%;
32
- animation: spin 0.6s linear infinite;
33
- flex-shrink: 0;
34
- }
35
26
 
36
27
  /* ---- Partial state ---- */
37
28
  .partial-header { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-4); }
38
- .partial-count { font-size: var(--text-sm); color: var(--text-dim); }
39
-
40
- /* ---- Screen-reader-only ---- */
41
- /* Present in the DOM and the accessibility tree, absent from layout, and never focusable. */
42
- .visually-hidden {
43
- position: absolute;
44
- width: 1px;
45
- height: 1px;
46
- margin: -1px;
47
- padding: 0;
48
- overflow: hidden;
49
- clip: rect(0 0 0 0);
50
- white-space: nowrap;
51
- border: 0;
52
- }
29
+ .partial-count { font-size: var(--t-2); color: var(--text-3); }
53
30
 
54
31
  /* ---- Project groups ---- */
55
32
  .project-group { margin-bottom: var(--space-10); }
56
33
  .project-header { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-4); }
57
- .project-name { font: 500 var(--text-lg)/1.2 var(--font-mono); color: var(--text); letter-spacing: -0.01em; }
34
+ .project-name { font: 500 var(--t-5)/1.2 var(--font-mono); color: var(--text); letter-spacing: -0.01em; }
58
35
  .batch { margin-bottom: var(--space-6); }
59
36
  .batch-header { display: flex; align-items: baseline; gap: var(--space-3); margin-bottom: var(--space-2); }
60
- .batch-meta { font: 400 var(--text-xs)/1 var(--font-sans); color: var(--text-faint); }
37
+ .batch-meta { font: 400 var(--t-2)/1 var(--font-sans); color: var(--text-4); }
61
38
 
62
39
  /* ---- Entry table cells ----
63
40
  The table lays out fixed with a colgroup so the title column takes the remainder and the row
@@ -75,7 +52,7 @@
75
52
  .entry-title {
76
53
  flex: 1 1 auto;
77
54
  min-width: 0;
78
- font: 450 var(--text-base)/1.4 var(--font-sans);
55
+ font: 400 var(--t-3)/1.4 var(--font-sans);
79
56
  color: var(--text);
80
57
  white-space: nowrap;
81
58
  overflow: hidden;
@@ -83,14 +60,14 @@
83
60
  }
84
61
  .entry-filer {
85
62
  flex-shrink: 0;
86
- font-size: var(--text-xs);
87
- color: var(--text-faint);
63
+ font-size: var(--t-2);
64
+ color: var(--text-4);
88
65
  white-space: nowrap;
89
66
  }
90
67
  .cell-file {
91
68
  font-family: var(--font-mono);
92
- font-size: var(--text-xs);
93
- color: var(--text-faint);
69
+ font-size: var(--t-2);
70
+ color: var(--text-4);
94
71
  white-space: nowrap;
95
72
  overflow: hidden;
96
73
  text-overflow: ellipsis;
@@ -101,103 +78,53 @@
101
78
  .htmx-request while the request is in flight, and pointer-events drops the duplicate click a
102
79
  double-click would otherwise fire. */
103
80
  .htmx-request { pointer-events: none; }
104
- /* The cloudy-ui custom checkbox: an appearance:none box on the sunk plane, accent-filled with a
105
- clip-path check when checked. The select-all also takes a dash in its indeterminate state (a
106
- partially selected batch), which the native accent-color box could not express. */
107
- .cell-select input[type="checkbox"],
108
- .batch-header .select-all {
109
- width: 15px;
110
- height: 15px;
111
- appearance: none;
112
- background: var(--bg-sunken);
113
- border: 1px solid var(--line);
114
- border-radius: calc(var(--radius) * 0.5);
115
- cursor: pointer;
116
- flex-shrink: 0;
117
- position: relative;
118
- transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
119
- }
120
- .cell-select input[type="checkbox"]:hover,
121
- .batch-header .select-all:hover { border-color: var(--line-strong); }
122
- .cell-select input[type="checkbox"]:checked,
123
- .batch-header .select-all:checked,
124
- .cell-select input[type="checkbox"]:indeterminate,
125
- .batch-header .select-all:indeterminate {
126
- background: var(--accent);
127
- border-color: var(--accent);
128
- }
129
- .cell-select input[type="checkbox"]:checked::after,
130
- .batch-header .select-all:checked::after {
131
- content: '';
132
- position: absolute;
133
- inset: 3px;
134
- background: var(--text-on-accent);
135
- clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
136
- }
137
- .cell-select input[type="checkbox"]:indeterminate::after,
138
- .batch-header .select-all:indeterminate::after {
139
- content: '';
140
- position: absolute;
141
- left: 3px;
142
- right: 3px;
143
- top: 50%;
144
- height: 2px;
145
- transform: translateY(-50%);
146
- background: var(--text-on-accent);
147
- border-radius: 1px;
148
- }
149
- .cell-actions { white-space: nowrap; }
150
- .cell-actions .btn + .btn { margin-left: var(--space-2); }
81
+ .cell-actions { white-space: nowrap; display: inline-flex; align-items: center; gap: var(--space-1); }
151
82
  .table-wrap tbody td.cell-actions { padding-left: var(--space-1); padding-right: var(--space-1); }
152
83
  .batch-bar {
153
84
  display: flex;
154
85
  align-items: center;
155
86
  margin-bottom: var(--space-4);
156
- /* Sticks just below the 56px navbar so the approve button stays reachable while rows scroll
87
+ /* Sticks just below the navbar so the approve button stays reachable while rows scroll
157
88
  under it; the background and z-index stop table rows from showing through the bar. */
158
89
  position: sticky;
159
- top: 56px;
90
+ top: var(--navbar-h);
160
91
  z-index: 10;
161
92
  padding: var(--space-2) 0;
162
93
  background: var(--bg);
163
94
  }
164
- .batch-header .select-all { align-self: center; }
95
+ .batch-header .checkbox-label { align-self: center; }
165
96
  /* ---- Collapsible project sections and batches ----
166
97
  The chevron points down expanded and turns when collapsed; the state is applied by dashboard.js
167
98
  from localStorage, so the server ships everything open and the viewer's choice re-applies. */
168
99
  .collapse-toggle { align-self: center; }
169
- .collapse-toggle svg { transition: transform var(--dur-fast) var(--ease); }
100
+ .collapse-toggle svg { transition: transform var(--dur-tint) var(--ease); }
170
101
  .collapse-toggle[aria-expanded="false"] svg { transform: rotate(-90deg); }
171
102
  .project-header .collapse-toggle, .batch-header .collapse-toggle { margin-left: auto; }
172
103
  .notice-list { margin: 0; padding-left: var(--space-5); display: flex; flex-direction: column; gap: var(--space-1); }
173
104
 
174
- /* ---- Diff view: the anchored snippet vs the entry's text, mono on sunken, anchor distinct ---- */
105
+ /* ---- Diff view: the anchored snippet vs the entry's text, mono on the well, anchor distinct ---- */
175
106
  .diff-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); margin-bottom: var(--space-8); }
176
107
  @media (max-width: 900px) { .diff-grid { grid-template-columns: 1fr; } }
177
108
  .diff-code {
178
- font: 400 var(--text-sm)/1.6 var(--font-mono);
179
- background: var(--bg-sunken);
109
+ font: 400 var(--t-2)/1.6 var(--font-mono);
110
+ background: var(--well);
180
111
  border: 1px solid var(--line);
181
- border-radius: var(--radius);
112
+ border-radius: var(--r-1);
182
113
  padding: var(--space-4);
183
114
  white-space: pre-wrap;
184
115
  word-break: break-word;
185
- color: var(--text-muted);
116
+ color: var(--text-2);
186
117
  margin: 0;
187
118
  }
188
119
  .diff-line { display: block; }
189
120
  .diff-anchor {
190
- background: var(--accent-soft);
121
+ background: var(--accent-quiet);
191
122
  border-left: 2px solid var(--accent);
192
123
  color: var(--text);
193
124
  padding-left: var(--space-2);
194
125
  }
195
126
 
196
- /* ---- Empty states ---- */
197
- .empty-state { text-align: center; padding: var(--space-12) var(--space-6); }
198
- .empty-icon { margin: 0 auto var(--space-4); width: 32px; height: 32px; color: var(--text-faint); display: flex; align-items: center; justify-content: center; }
199
- .empty-state h3 { font: 500 var(--text-lg)/1.3 var(--font-sans); color: var(--text); margin-bottom: var(--space-2); }
200
- .empty-state p { font-size: var(--text-sm); color: var(--text-dim); max-width: 420px; margin: 0 auto var(--space-4); }
127
+ /* ---- Empty state actions: the shipped .empty-state lays out one button, this row holds two ---- */
201
128
  .empty-actions { display: flex; gap: var(--space-2); justify-content: center; }
202
129
 
203
130
  /* ---- Error box (cloned from #error-box by dashboard.js) ---- */
@@ -205,7 +132,7 @@
205
132
  .callout-actions { margin-top: var(--space-2); }
206
133
 
207
134
  /* ---- Entry editor ---- */
208
- /* The one live region, kept out of sight by the shared .visually-hidden utility above. */
135
+ /* The one live region, kept out of sight by the shipped .sr-only utility. */
209
136
  .editor-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-8); align-items: start; }
210
137
  .editor-main { min-width: 0; }
211
138
  .editor-rail { display: flex; flex-direction: column; gap: var(--space-6); position: sticky; top: var(--space-8); }
@@ -221,32 +148,32 @@
221
148
  #editor-text { font-family: var(--font-mono); }
222
149
 
223
150
  /* ---- Editor prev/next rails ----
224
- One full-height fixed strip per side, below the 56px navbar, so the previous and next entries are
225
- a single click away while reading. The strip sits inside the 48px page padding, clear of content. */
151
+ One full-height fixed strip per side, below the navbar, so the previous and next entries are
152
+ a single click away while reading. The strip sits inside the page's inline padding, clear of content. */
226
153
  .editor-nav-btn {
227
154
  position: fixed;
228
- top: 56px;
155
+ top: var(--navbar-h);
229
156
  bottom: 0;
230
157
  width: 44px;
231
158
  display: flex;
232
159
  align-items: center;
233
160
  justify-content: center;
234
- color: var(--text-dim);
161
+ color: var(--text-3);
235
162
  text-decoration: none;
236
163
  z-index: 40;
237
- transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
164
+ transition: background var(--dur-tint) var(--ease), color var(--dur-tint) var(--ease);
238
165
  }
239
166
  .editor-nav-prev { left: 0; }
240
167
  .editor-nav-next { right: 0; }
241
- .editor-nav-btn:hover { background: var(--bg-hover); color: var(--text); }
242
- .editor-nav-btn.is-disabled { color: var(--text-faint); opacity: 0.4; pointer-events: none; }
168
+ .editor-nav-btn:hover { background: var(--surface-2); color: var(--text); }
169
+ .editor-nav-btn.is-disabled { color: var(--text-4); opacity: 0.4; pointer-events: none; }
243
170
  .editor-nav-btn svg { width: 18px; height: 18px; }
244
171
  @media (max-width: 900px) { .editor-nav { display: none; } }
245
172
  #editor-region > .callout { margin-bottom: var(--space-4); }
246
173
  #editor-region > .btn { margin-top: var(--space-4); }
247
174
  .editor-actions { margin-top: var(--space-4); display: flex; align-items: center; gap: var(--space-2); }
248
175
  /* The in-flight indicator for an approve or reject from the editor: htmx's own rules fade it in. */
249
- .editor-actions .htmx-indicator { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); color: var(--text-dim); }
176
+ .editor-actions .htmx-indicator { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--t-2); color: var(--text-3); }
250
177
 
251
178
  /* The notes card: the agent's row reuses the constraint row shape; the human's textarea and its
252
179
  save button sit below it. */
@@ -256,51 +183,51 @@
256
183
  /* Constraint panel: live count and placeholder checklist; the server owns the refusal. */
257
184
  .constraint-row { display: flex; gap: var(--space-3); padding: 6px 0; }
258
185
  .constraint-row + .constraint-row { border-top: 1px solid var(--line); }
259
- .constraint-label { flex-shrink: 0; font: 450 11px/1.4 var(--font-sans); letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-dim); width: 96px; padding-top: 2px; }
260
- .constraint-value { min-width: 0; color: var(--text-muted); font-size: var(--text-sm); }
261
- .char-count { color: var(--text-muted); font-size: var(--text-sm); }
186
+ .constraint-label { flex-shrink: 0; font: 500 11px/1.4 var(--font-sans); letter-spacing: var(--caps); text-transform: uppercase; color: var(--text-3); width: 96px; padding-top: 2px; }
187
+ .constraint-value { min-width: 0; color: var(--text-2); font-size: var(--t-2); }
188
+ .char-count { color: var(--text-2); font-size: var(--t-2); }
262
189
  .char-count.over { color: var(--danger); }
263
190
  .placeholder-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
264
191
  .placeholder-item { display: flex; align-items: center; gap: var(--space-2); }
265
- .placeholder-state { font-size: var(--text-xs); color: var(--text-dim); min-width: 52px; }
192
+ .placeholder-state { font-size: var(--t-2); color: var(--text-3); min-width: 52px; }
266
193
  .placeholder-state.is-present { color: var(--success); }
267
194
 
268
195
  /* The context card's secondary block: the provenance rows (hash, filer, stale note) collapsed
269
196
  behind a summary, so the anchor and the agent-supplied context rows lead the card. */
270
197
  .context-secondary { margin-top: var(--space-3); }
271
- .context-secondary summary { cursor: pointer; font-size: var(--text-xs); color: var(--text-dim); }
198
+ .context-secondary summary { cursor: pointer; font-size: var(--t-2); color: var(--text-3); }
272
199
  .context-secondary .info-table { margin-top: var(--space-2); }
273
200
 
274
201
  /* Repo row link: the brand icon beside the shortened owner/repo path, linking out to the host. */
275
202
  .repo-link { display: inline-flex; align-items: center; gap: 6px; color: var(--text); text-decoration: none; }
276
- .repo-link:hover { color: var(--accent); }
277
- .repo-icon { width: 14px; height: 14px; flex-shrink: 0; fill: currentColor; opacity: 0.7; }
278
- .placeholder-token { font: 400 var(--text-sm)/1 var(--font-mono); color: var(--text); background: var(--bg-sunken); border: 1px solid var(--line); border-radius: var(--radius); padding: 2px 6px; }
203
+ .repo-link:hover { color: var(--accent-text); }
204
+ .repo-icon { width: 14px; height: 14px; flex-shrink: 0; fill: currentColor; opacity: var(--icon-dim); }
205
+ .placeholder-token { font: 400 var(--t-2)/1 var(--font-mono); color: var(--text); background: var(--well); border: 1px solid var(--line); border-radius: var(--r-1); padding: 2px 6px; }
279
206
 
280
207
  /* Entry images: one image per row at the card's width, a remove form below each, and the
281
208
  one-file upload form closing the card. The file input flexes to whatever width remains. */
282
209
  .image-list { list-style: none; margin: 0 0 var(--space-3); padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
283
- .entry-image { display: block; max-width: 100%; height: auto; border: 1px solid var(--line); border-radius: var(--radius); }
284
- .image-skip { margin: 0; font-size: var(--text-xs); color: var(--text-dim); }
210
+ .entry-image { display: block; max-width: 100%; height: auto; border: 1px solid var(--line); border-radius: var(--r-1); }
211
+ .image-skip { margin: 0; font-size: var(--t-2); color: var(--text-3); }
285
212
  .image-remove { margin-top: var(--space-1); }
286
213
  .image-upload { display: flex; gap: var(--space-2); align-items: center; }
287
214
  .image-upload .input { flex: 1; min-width: 0; }
288
215
 
289
216
  /* Revision history: newest first; the text clamps like the list's entry text. */
290
- .history-empty { font-size: var(--text-sm); color: var(--text-faint); padding: var(--space-2) 0; }
217
+ .history-empty { font-size: var(--t-2); color: var(--text-4); padding: var(--space-2) 0; }
291
218
  .revision-list { list-style: none; margin: 0; padding: 0; }
292
219
  .revision { padding: var(--space-3) 0; }
293
220
  .revision + .revision { border-top: 1px solid var(--line); }
294
221
  .revision-head { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-2); }
295
- .revision-time { font-size: var(--text-xs); color: var(--text-faint); }
222
+ .revision-time { font-size: var(--t-2); color: var(--text-4); }
296
223
  .revision-head .btn { margin-left: auto; }
297
224
  .revision-text {
298
225
  display: -webkit-box;
299
226
  -webkit-line-clamp: 2;
300
227
  -webkit-box-orient: vertical;
301
228
  overflow: hidden;
302
- font-size: var(--text-sm);
303
- color: var(--text-muted);
229
+ font-size: var(--t-2);
230
+ color: var(--text-2);
304
231
  }
305
232
 
306
233
  /* ---- Login page: the navbar shell, then one centered card ---- */
@@ -1,35 +1,11 @@
1
- // reviewzy dashboard behaviors. Load after htmx.min.js.
1
+ // reviewzy dashboard behaviors. Loads as a module after htmx.min.js.
2
+ // The navbar's ink, its dock state and the table header label boxes come from ui.js;
3
+ // initTables is re-run after every htmx swap so a freshly rendered table head gets its boxes.
4
+ import { initTables } from "./ui.js";
5
+
2
6
  (() => {
3
7
  "use strict";
4
8
 
5
- // --- Navbar ink (cloudy-ui navbar component) ---
6
- // Positions the sliding underline under the active link; re-positions on resize without animating.
7
- const navbarNav = document.getElementById("navbar-nav");
8
- const navbarInk = document.getElementById("navbar-ink");
9
-
10
- function positionNavbarInk() {
11
- if (!navbarNav || !navbarInk) return;
12
- const active = navbarNav.querySelector(".navbar-link.active");
13
- if (!active) {
14
- navbarInk.style.opacity = "0";
15
- return;
16
- }
17
- const navRect = navbarNav.getBoundingClientRect();
18
- const linkRect = active.getBoundingClientRect();
19
- navbarInk.style.left = `${linkRect.left - navRect.left}px`;
20
- navbarInk.style.width = `${linkRect.width}px`;
21
- navbarInk.style.opacity = "1";
22
- }
23
-
24
- window.addEventListener("resize", () => {
25
- navbarInk.style.transition = "none";
26
- positionNavbarInk();
27
- requestAnimationFrame(() => {
28
- navbarInk.style.transition = "";
29
- });
30
- });
31
- requestAnimationFrame(positionNavbarInk);
32
-
33
9
  // --- Filter errors ---
34
10
  // A failed filter request (HTTP error or network error) replaces the list with the error box
35
11
  // from the page's #error-box template; the retry button re-submits the filter form.
@@ -307,4 +283,5 @@
307
283
 
308
284
  applyCollapseState();
309
285
  document.addEventListener("htmx:afterSwap", applyCollapseState);
286
+ document.addEventListener("htmx:afterSwap", initTables);
310
287
  })();
@@ -0,0 +1,184 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" hidden="" aria-hidden="true">
2
+ <!-- icon sprite. Paste this whole element into <body> as its first
3
+ child, then reach an icon with <use href="#i-name"/>.
4
+
5
+ Drawing contract, on every symbol: viewBox 0 0 16 16, fill none, stroke
6
+ currentColor, stroke-width 1.5, round caps, round joins. The round join
7
+ is the corner treatment: every corner in the set gets the same 0.75-unit
8
+ outer radius from it, so no path carries an rx of its own.
9
+
10
+ Grid: a closed shape bounds 2..14 (a circle container r 6.5 at 8,8), an
11
+ open stroke runs 3..13, a chevron arm is 5 on each axis, a dot is a
12
+ 0.01-long round-capped segment. -->
13
+
14
+ <!-- marks -->
15
+ <symbol id="i-minus" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
16
+ <path d="M3 8h10"/>
17
+ </symbol>
18
+ <symbol id="i-plus" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
19
+ <path d="M8 3v10M3 8h10"/>
20
+ </symbol>
21
+ <symbol id="i-check" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
22
+ <path d="M2.75 8.25L6.5 12L13.25 4"/>
23
+ </symbol>
24
+ <symbol id="i-x" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
25
+ <path d="M4 4L12 12M12 4L4 12"/>
26
+ </symbol>
27
+
28
+ <!-- chevrons: arm 5 on each axis, apex 2.5 off centre -->
29
+ <symbol id="i-chevron-down" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
30
+ <path d="M3 5.5L8 10.5L13 5.5"/>
31
+ </symbol>
32
+ <symbol id="i-chevron-up" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
33
+ <path d="M3 10.5L8 5.5L13 10.5"/>
34
+ </symbol>
35
+ <symbol id="i-chevron-right" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
36
+ <path d="M5.5 3L10.5 8L5.5 13"/>
37
+ </symbol>
38
+ <symbol id="i-chevron-left" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
39
+ <path d="M10.5 3L5.5 8L10.5 13"/>
40
+ </symbol>
41
+
42
+ <!-- arrows: shaft 3..13, head arm 4 -->
43
+ <symbol id="i-arrow-right" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
44
+ <path d="M3 8h10M9 4L13 8L9 12"/>
45
+ </symbol>
46
+ <symbol id="i-arrow-left" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
47
+ <path d="M13 8H3M7 4L3 8L7 12"/>
48
+ </symbol>
49
+ <symbol id="i-arrow-up" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
50
+ <path d="M8 13V3M4 7L8 3L12 7"/>
51
+ </symbol>
52
+ <symbol id="i-arrow-down" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
53
+ <path d="M8 3v10M4 9L8 13L12 9"/>
54
+ </symbol>
55
+
56
+ <!-- chrome -->
57
+ <symbol id="i-search" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
58
+ <circle cx="6.75" cy="6.75" r="4.75"/>
59
+ <path d="M10.5 10.5L14 14"/>
60
+ </symbol>
61
+ <symbol id="i-settings" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
62
+ <path d="M2.5 5.5H13.5M2.5 10.5H13.5"/>
63
+ <circle cx="6" cy="5.5" r="1.75"/>
64
+ <circle cx="10" cy="10.5" r="1.75"/>
65
+ </symbol>
66
+ <symbol id="i-bell" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
67
+ <path d="M4.5 7.5a3.5 3.5 0 0 1 7 0v3l1.5 2h-10l1.5-2z"/>
68
+ <path d="M6.5 12.5a1.5 1.5 0 0 0 3 0"/>
69
+ </symbol>
70
+ <symbol id="i-user" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
71
+ <circle cx="8" cy="5.25" r="2.5"/>
72
+ <path d="M3.25 13.75a4.75 4.75 0 0 1 9.5 0"/>
73
+ </symbol>
74
+ <symbol id="i-lock" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
75
+ <path d="M2.5 7h11v6.5h-11z"/>
76
+ <path d="M5 7V5.25a3 3 0 016 0V7"/>
77
+ </symbol>
78
+ <symbol id="i-menu" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
79
+ <path d="M2.5 4.5H13.5M2.5 8H13.5M2.5 11.5H13.5"/>
80
+ </symbol>
81
+ <symbol id="i-grid" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
82
+ <path d="M2 2h4v4H2zM10 2h4v4h-4zM2 10h4v4H2zM10 10h4v4h-4z"/>
83
+ </symbol>
84
+ <symbol id="i-chart" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
85
+ <path d="M2 13L5.5 8L8.5 11L14 3"/>
86
+ </symbol>
87
+ <symbol id="i-sun" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
88
+ <circle cx="8" cy="8" r="3"/>
89
+ <path d="M8 2v1.5M8 12.5V14M2 8h1.5M12.5 8H14M4.8 4.8L3.75 3.75M11.2 4.8L12.25 3.75M4.8 11.2L3.75 12.25M11.2 11.2L12.25 12.25"/>
90
+ </symbol>
91
+ <symbol id="i-moon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
92
+ <path d="M14 8.8A6 6 0 1 1 7.2 2a4.8 4.8 0 0 0 6.8 6.8z"/>
93
+ </symbol>
94
+
95
+ <!-- files and code -->
96
+ <symbol id="i-folder" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
97
+ <path d="M2 3.5h4l1.5 2H14v7H2z"/>
98
+ </symbol>
99
+ <symbol id="i-file" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
100
+ <path d="M9.5 2.5H4v11h8V5z"/>
101
+ <path d="M9.5 2.5V5H12"/>
102
+ </symbol>
103
+ <symbol id="i-code" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
104
+ <path d="M5.5 4.5L2.5 8L5.5 11.5M10.5 4.5L13.5 8L10.5 11.5"/>
105
+ </symbol>
106
+ <symbol id="i-terminal" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
107
+ <path d="M3 4.5L6.5 8L3 11.5M8.5 12H13"/>
108
+ </symbol>
109
+ <symbol id="i-console" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
110
+ <path d="M2.5 2.5h11v11h-11z"/>
111
+ <path d="M5 6l2 2-2 2"/>
112
+ <path d="M8.5 10h2.5"/>
113
+ </symbol>
114
+
115
+ <!-- row actions -->
116
+ <symbol id="i-copy" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
117
+ <path d="M5.5 5.5h8v8h-8z"/>
118
+ <path d="M10.5 5.5V2.5h-8v8h3"/>
119
+ </symbol>
120
+ <symbol id="i-trash" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
121
+ <path d="M3 4.5H13"/>
122
+ <path d="M6 4.5V2.5h4v2"/>
123
+ <path d="M4.5 4.5v9h7v-9"/>
124
+ </symbol>
125
+ <symbol id="i-edit" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
126
+ <path d="M11.5 2.5l2 2-8 8H3.5v-2z"/>
127
+ <path d="M9.5 4.5l2 2"/>
128
+ </symbol>
129
+ <symbol id="i-filter" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
130
+ <path d="M2.5 3.5h11l-4 5v4l-3 1.5V8.5z"/>
131
+ </symbol>
132
+ <symbol id="i-sort" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
133
+ <path d="M3 4H13M3 8H9.5M3 12H6"/>
134
+ </symbol>
135
+ <symbol id="i-more" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
136
+ <circle cx="8" cy="3.5" r="1"/><circle cx="8" cy="8" r="1"/><circle cx="8" cy="12.5" r="1"/>
137
+ </symbol>
138
+ <symbol id="i-refresh" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
139
+ <path d="M3.5 8A4.5 4.5 0 0 1 12.5 8"/>
140
+ <path d="M11 6.5L12.5 8L14 6.5"/>
141
+ <path d="M12.5 8A4.5 4.5 0 0 1 3.5 8"/>
142
+ <path d="M5 9.5L3.5 8L2 9.5"/>
143
+ </symbol>
144
+ <symbol id="i-undo" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
145
+ <path d="M2.5 8a5.5 5.5 0 1 0 9-4.2"/>
146
+ <path d="M11.5 2.25v1.55H9.2"/>
147
+ </symbol>
148
+ <symbol id="i-external" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
149
+ <path d="M13.5 9v4.5h-11v-11H7"/>
150
+ <path d="M9.5 2.5H13.5V6.5"/>
151
+ <path d="M7.5 8.5L13.5 2.5"/>
152
+ </symbol>
153
+ <symbol id="i-download" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
154
+ <path d="M8 2.5v8"/>
155
+ <path d="M4.5 7.5L8 11L11.5 7.5"/>
156
+ <path d="M2.5 13.5H13.5"/>
157
+ </symbol>
158
+ <symbol id="i-upload" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
159
+ <path d="M8 11V3"/>
160
+ <path d="M4.5 6.5L8 3L11.5 6.5"/>
161
+ <path d="M2.5 13.5H13.5"/>
162
+ </symbol>
163
+
164
+ <!-- status: the container carries the level, the mark carries the sense -->
165
+ <symbol id="i-info" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
166
+ <circle cx="8" cy="8" r="6.5"/>
167
+ <path d="M8 7.5v3.5"/>
168
+ <path d="M8 5h.01"/>
169
+ </symbol>
170
+ <symbol id="i-warning" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
171
+ <path d="M8 2.5L14 13.5H2z"/>
172
+ <path d="M8 6.5v3"/>
173
+ <path d="M8 11.5h.01"/>
174
+ </symbol>
175
+ <symbol id="i-error" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
176
+ <circle cx="8" cy="8" r="6.5"/>
177
+ <path d="M8 5v3.5"/>
178
+ <path d="M8 10.75h.01"/>
179
+ </symbol>
180
+ <symbol id="i-success" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
181
+ <circle cx="8" cy="8" r="6.5"/>
182
+ <path d="M5 8L7 10L11 6"/>
183
+ </symbol>
184
+ </svg>