thunderbird-patch-review
Simple email patch review tool for Thunderbird
git clone git://mccd.space/thunderbird-patch-review| Log | Files | Refs | README | LICENSE | Mail | Artifacts |
review.css (11865B)
1 :root {
2 --bg: #ffffff;
3 --fg: #1f2328;
4 --muted: #656d76;
5 --border: #d1d9e0;
6 --surface: #f6f8fa;
7 --accent: #0969da;
8 --add-bg: #dafbe1;
9 --add-gutter: #aceebb;
10 --del-bg: #ffebe9;
11 --del-gutter: #ffcecb;
12 --hunk-bg: #ddf4ff;
13 --comment-bg: #fff8c5;
14 }
15
16 @media (prefers-color-scheme: dark) {
17 :root {
18 --bg: #0d1117;
19 --fg: #e6edf3;
20 --muted: #8d96a0;
21 --border: #30363d;
22 --surface: #161b22;
23 --accent: #4493f8;
24 --add-bg: #12261e;
25 --add-gutter: #1b4721;
26 --del-bg: #25171c;
27 --del-gutter: #542426;
28 --hunk-bg: #121d2f;
29 --comment-bg: #272115;
30 }
31 }
32
33 * { box-sizing: border-box; }
34
35 /* The hidden attribute must always win, even over display: flex rules. */
36 [hidden] { display: none !important; }
37
38 body {
39 margin: 0;
40 background: var(--bg);
41 color: var(--fg);
42 font: 13px/1.5 -apple-system, "Segoe UI", Cantarell, Ubuntu, sans-serif;
43 }
44
45 #topbar {
46 display: flex;
47 align-items: center;
48 justify-content: space-between;
49 gap: 1rem;
50 padding: 0.5rem 1rem;
51 border-bottom: 1px solid var(--border);
52 background: var(--surface);
53 position: sticky;
54 top: 0;
55 z-index: 2;
56 }
57
58 #series-nav {
59 display: flex;
60 align-items: center;
61 justify-content: flex-start;
62 gap: 0.4rem;
63 flex-wrap: wrap;
64 margin: 0.6rem 0;
65 }
66
67 #series-title {
68 font-weight: 600;
69 overflow: hidden;
70 text-overflow: ellipsis;
71 white-space: nowrap;
72 }
73
74 #actions {
75 display: flex;
76 align-items: center;
77 gap: 0.5rem;
78 flex-shrink: 0;
79 }
80
81
82 #repo-path {
83 max-width: 18rem;
84 padding: 0.3rem 0.6rem;
85 border: 1px solid var(--border);
86 border-radius: 6px;
87 background: var(--bg);
88 color: var(--fg);
89 font-family: ui-monospace, monospace;
90 white-space: nowrap;
91 overflow: hidden;
92 text-overflow: ellipsis;
93 user-select: none;
94 cursor: pointer;
95 text-align: left;
96 }
97
98 #repo-path .repo-branch { color: var(--muted); }
99 #repo-path.error .repo-sep,
100 #repo-path.error .repo-branch { color: inherit; }
101 #repo-path:hover { background: var(--hunk-bg); }
102 #repo-path.error { cursor: pointer; }
103 #repo-path.error {
104 border-color: #cf222e;
105 color: #cf222e;
106 }
107 @media (prefers-color-scheme: dark) {
108 #repo-path.error { border-color: #f85149; color: #f85149; }
109 }
110
111 /* A joined cluster: the repo chip and the Apply split read as one control.
112 The seam is drawn by Apply's left border alone; the repo chip's right
113 border goes transparent (this outranks the .error red by declaration
114 order), so an error chip doesn't butt a red edge against Apply's. */
115 .cluster {
116 display: flex;
117 align-items: stretch;
118 }
119 .cluster > #repo-path {
120 border-top-right-radius: 0;
121 border-bottom-right-radius: 0;
122 border-right-color: transparent;
123 }
124 .cluster > .split {
125 border-top-left-radius: 0;
126 border-bottom-left-radius: 0;
127 }
128 .cluster > .split > button:first-child {
129 border-top-left-radius: 0;
130 border-bottom-left-radius: 0;
131 }
132
133 button {
134 padding: 0.3rem 0.8rem;
135 border: 1px solid var(--border);
136 border-radius: 6px;
137 background: var(--surface);
138 color: var(--fg);
139 cursor: pointer;
140 }
141
142 button:hover { background: var(--hunk-bg); }
143 button:disabled { opacity: 0.5; cursor: not-allowed; }
144 button:disabled:hover { background: inherit; opacity: 0.5; }
145 button.primary:disabled { background: var(--accent); border-color: var(--accent); color: #fff; }
146 button.primary:disabled:hover { opacity: 0.5; }
147
148 .split .menu button.danger {
149 color: #cf222e;
150 }
151 .split .menu button.danger:hover {
152 background: #cf222e;
153 color: #fff;
154 }
155 @media (prefers-color-scheme: dark) {
156 .split .menu button.danger { color: #f85149; }
157 .split .menu button.danger:hover { background: #f85149; color: #0d1117; }
158 }
159 button.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
160 button.primary:hover { color: #fff; opacity: 0.9; }
161
162 /* Apply-button states from the pre-check (patchHost.check): the button
163 turns green with a checkmark when the series is already in HEAD, red
164 when it won't apply, yellow with a warning when the working tree is
165 dirty (git am would refuse before reading the patches) — disabled in
166 all three. State-checking is the transient "querying git" phase. The
167 menu-toggle plants itself in the same split, so it shares the deafened
168 look. */
169 #btn-apply.state-checking { cursor: progress; opacity: 0.85; }
170
171 #btn-apply.state-applied,
172 #btn-apply.state-applied:hover {
173 background: #dcfce7;
174 border-color: #1a7f37;
175 color: #1a7f37;
176 }
177
178 #btn-apply.state-conflict,
179 #btn-apply.state-conflict:hover {
180 background: #ffebe9;
181 border-color: #cf222e;
182 color: #cf222e;
183 }
184
185 #btn-apply.state-dirty,
186 #btn-apply.state-dirty:hover {
187 background: #fff8c5;
188 border-color: #bf8700;
189 color: #7d4e00;
190 }
191
192 @media (prefers-color-scheme: dark) {
193 #btn-apply.state-applied,
194 #btn-apply.state-applied:hover {
195 background: #0d2818;
196 border-color: #2ea043;
197 color: #3fb950;
198 }
199 #btn-apply.state-conflict,
200 #btn-apply.state-conflict:hover {
201 background: #2d1216;
202 border-color: #f85149;
203 color: #ff7b72;
204 }
205 #btn-apply.state-dirty,
206 #btn-apply.state-dirty:hover {
207 background: #2a2306;
208 border-color: #d29922;
209 color: #e3b341;
210 }
211 }
212
213 .split {
214 position: relative;
215 display: flex;
216 }
217
218 .split > button:first-child {
219 border-top-right-radius: 0;
220 border-bottom-right-radius: 0;
221 }
222
223 .split > .menu-toggle {
224 border-top-left-radius: 0;
225 border-bottom-left-radius: 0;
226 border-left-color: rgba(255, 255, 255, 0.35);
227 padding: 0.3rem 0.45rem;
228 }
229
230 .split .menu {
231 position: absolute;
232 top: calc(100% + 4px);
233 right: 0;
234 display: flex;
235 flex-direction: column;
236 min-width: 12rem;
237 border: 1px solid var(--border);
238 border-radius: 6px;
239 background: var(--surface);
240 box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
241 z-index: 4;
242 overflow: hidden;
243 }
244
245 .split .menu button {
246 border: 0;
247 border-radius: 0;
248 background: none;
249 text-align: left;
250 padding: 0.45rem 0.8rem;
251 }
252
253 .split .menu button:hover {
254 background: var(--hunk-bg);
255 color: var(--fg);
256 }
257
258 .patch-box {
259 margin: 0 0 1rem;
260 border: 1px solid var(--border);
261 border-radius: 6px;
262 background: var(--surface);
263 overflow: hidden;
264 }
265
266 #series-nav .pill {
267 padding: 0.2rem 0.7rem;
268 border: 1px solid var(--border);
269 border-radius: 999px;
270 cursor: pointer;
271 color: var(--muted);
272 }
273
274 #series-nav .pill.active {
275 border-color: var(--accent);
276 color: var(--accent);
277 font-weight: 600;
278 }
279
280 #series-nav .pill .badge {
281 display: inline-block;
282 min-width: 1.2em;
283 margin-left: 0.35em;
284 border-radius: 999px;
285 background: var(--accent);
286 color: #fff;
287 font-size: 11px;
288 text-align: center;
289 }
290
291 #content { padding: 0 1rem 4rem; max-width: 72rem; margin: 0 auto; }
292
293 .commit-message {
294 position: relative;
295 margin: 0;
296 padding: 0.8rem 1rem;
297 border: 0;
298 border-bottom: 1px solid var(--border);
299 border-radius: 0;
300 background: transparent;
301 white-space: pre-wrap;
302 font-family: ui-monospace, monospace;
303 }
304
305 .commit-message .btn-general {
306 display: block;
307 margin: 0.6rem 0 0;
308 }
309
310 .commit-message .patch-headers {
311 margin: 0 0 0.4rem;
312 font-family: ui-monospace, "Cascadia Mono", "Source Code Pro", monospace;
313 color: var(--fg);
314 }
315 .commit-message .patch-headers dt {
316 display: inline;
317 color: var(--fg);
318 margin-right: 0.3em;
319 }
320 .commit-message .patch-headers dd {
321 display: inline;
322 margin: 0;
323 color: var(--fg);
324 }
325 .commit-message .patch-headers code {
326 font-family: inherit;
327 color: var(--fg);
328 }
329 .commit-message .patch-headers > dt + dd::after { content: "\A"; white-space: pre; }
330
331 .file {
332 margin-bottom: 1rem;
333 border: 1px solid var(--border);
334 border-radius: 6px;
335 overflow: hidden;
336 }
337
338 .file > summary {
339 padding: 0.4rem 0.8rem;
340 background: var(--surface);
341 font-family: ui-monospace, monospace;
342 font-weight: 600;
343 cursor: pointer;
344 }
345
346 .file .file-note { padding: 0.4rem 0.8rem; color: var(--muted); }
347
348 .binary-note {
349 padding: 0.4rem 0.8rem 0.6rem;
350 color: var(--muted);
351 border-left: 3px solid #d1242f;
352 }
353 .binary-note .file-note { padding: 0; }
354 .binary-note button { margin-top: 0.4rem; }
355 .binary-note .binary-raw {
356 margin: 0.5rem 0 0;
357 padding: 0.5rem 0.7rem;
358 max-height: 16rem;
359 overflow: auto;
360 border: 1px solid var(--border);
361 border-radius: 6px;
362 background: var(--bg);
363 font: 11px/1.4 ui-monospace, monospace;
364 white-space: pre-wrap;
365 color: var(--muted);
366 }
367
368 table.diff {
369 width: 100%;
370 border-collapse: collapse;
371 font: 12px/1.45 ui-monospace, "Cascadia Mono", "Source Code Pro", monospace;
372 }
373
374 table.diff td { padding: 0 0.5em; vertical-align: top; }
375
376 td.gutter {
377 width: 3em;
378 min-width: 3em;
379 text-align: right;
380 color: var(--muted);
381 user-select: none;
382 border-right: 1px solid var(--border);
383 }
384
385 td.code { white-space: pre-wrap; word-break: break-all; width: 100%; }
386
387 tr.hunk-header td {
388 background: var(--hunk-bg);
389 color: var(--muted);
390 padding: 0.2em 0.5em;
391 }
392
393 tr.line { cursor: pointer; }
394 tr.line:hover td.code { box-shadow: inset 2px 0 0 var(--accent); }
395 tr.line.add td { background: var(--add-bg); }
396 tr.line.add td.gutter { background: var(--add-gutter); }
397 tr.line.del td { background: var(--del-bg); }
398 tr.line.del td.gutter { background: var(--del-gutter); }
399 tr.line.commented td.code { box-shadow: inset 3px 0 0 var(--accent); }
400
401 /* Intra-line highlight: the span that actually changed within a line. */
402 tr.line.add td.code .hl { background: var(--add-gutter); border-radius: 2px; }
403 tr.line.del td.code .hl { background: var(--del-gutter); border-radius: 2px; }
404
405 tr.comment-row td { padding: 0; }
406
407 .comment-box {
408 margin: 0.3rem 2rem 0.5rem 3.5rem;
409 border: 1px solid var(--border);
410 border-radius: 6px;
411 background: var(--comment-bg);
412 font-family: -apple-system, "Segoe UI", sans-serif;
413 }
414
415 .comment-box .comment-text { padding: 0.5rem 0.8rem; white-space: pre-wrap; }
416
417 .comment-box textarea {
418 display: block;
419 width: 100%;
420 min-height: 4.5em;
421 padding: 0.5rem 0.8rem;
422 border: 0;
423 border-bottom: 1px solid var(--border);
424 background: transparent;
425 color: var(--fg);
426 font: inherit;
427 resize: vertical;
428 }
429
430 .comment-box .comment-actions {
431 display: flex;
432 gap: 0.4rem;
433 justify-content: flex-end;
434 padding: 0.3rem 0.5rem;
435 /* The editor inherits the yellow comment-box bg; the action row should read
436 as a distinct footer, not blend into the yellow. */
437 background: var(--surface);
438 border-radius: 0 0 5px 5px;
439 }
440
441 #send-confirm {
442 position: fixed;
443 inset: 0;
444 display: flex;
445 align-items: center;
446 justify-content: center;
447 background: rgba(0, 0, 0, 0.4);
448 z-index: 5;
449 }
450
451 #send-confirm .modal-card {
452 width: min(32rem, 90vw);
453 border: 1px solid var(--border);
454 border-radius: 8px;
455 background: var(--bg);
456 box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
457 padding: 1.2rem 1.4rem;
458 }
459
460 #send-confirm h2 {
461 margin: 0 0 0.4rem;
462 font-size: 15px;
463 }
464
465 #send-confirm-summary {
466 margin: 0 0 0.8rem;
467 color: var(--muted);
468 font-size: 12px;
469 }
470
471 #send-confirm #srht-status {
472 display: flex;
473 align-items: center;
474 gap: 0.4rem;
475 margin: 0 0 0.8rem;
476 color: var(--muted);
477 }
478
479 #send-confirm #srht-status select {
480 padding: 0.2rem 0.3rem;
481 border: 1px solid var(--border);
482 border-radius: 6px;
483 background: var(--bg);
484 color: var(--fg);
485 font: inherit;
486 }
487
488 #send-confirm .modal-actions {
489 display: flex;
490 gap: 0.5rem;
491 justify-content: flex-end;
492 }
493
494 #status {
495 position: fixed;
496 inset: auto 1rem 1rem auto;
497 width: min(44rem, 90vw);
498 max-height: 60vh;
499 display: flex;
500 flex-direction: column;
501 border: 1px solid var(--border);
502 border-radius: 6px;
503 background: var(--surface);
504 box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
505 z-index: 3;
506 }
507
508 #status-text {
509 margin: 0;
510 padding: 0.8rem 1rem;
511 overflow: auto;
512 font: 12px/1.45 ui-monospace, monospace;
513 white-space: pre-wrap;
514 }
515
516 #status-buttons {
517 display: flex;
518 gap: 0.5rem;
519 justify-content: flex-end;
520 padding: 0.5rem;
521 border-top: 1px solid var(--border);
522 }
523
524 .error { color: #d1242f; }
525 @media (prefers-color-scheme: dark) { .error { color: #ff7b72; } }