1diff --git a/scss/main.scss b/scss/main.scss
2index e0fecf162da0f98f0f1ef6e3405d05c9664fdf81..a98c0a2e43b6cfb15bafd82109dd1a64f4295ec2 100644
3--- a/scss/main.scss
4+++ b/scss/main.scss
5@@ -12,7 +12,7 @@
6 // basic functionality
7 @import "bootstrap/scss/_functions.scss";
8 @import "bootstrap/scss/_variables.scss";
9-@import "bootstrap/scss/_variables-dark.scss";
10+//@import "bootstrap/scss/_variables-dark.scss";
11 @import "bootstrap/scss/_maps.scss";
12 @import "bootstrap/scss/_mixins.scss";
13 @import "bootstrap/scss/_utilities.scss";
14@@ -27,6 +27,7 @@ @import "bootstrap/scss/_navbar.scss";
15 @import "bootstrap/scss/_grid.scss";
16 @import "bootstrap/scss/_forms.scss";
17 @import "bootstrap/scss/_buttons.scss";
18+@import "bootstrap/scss/mixins/_color-mode.scss";
19 @import "tree.scss";
20
21 // overwrite to reduce the ammount of css generated by loading all utilities
22@@ -80,6 +81,12 @@ font-size: $base-font-size;
23 margin: 0;
24 }
25
26+@include color-mode(dark) {
27+ body {
28+ background: #212529;
29+ }
30+}
31+
32 // prevert wierd input overflowing 100%
33 input {
34 width: 100%;
35@@ -116,6 +123,12 @@ margin: 0.5rem 0;
36 background: #f8f9fa;
37 }
38
39+@include color-mode(dark) {
40+ .event {
41+ background: #131618;
42+ }
43+}
44+
45 .event-commit {
46 background: #dadada;
47 padding: 5px;
48@@ -132,6 +145,13 @@ text-align: end;
49
50 @include media-breakpoint-down(xl) {
51 text-align: start;
52+ }
53+}
54+
55+
56+@include color-mode(dark) {
57+ .event-commit {
58+ background: #000;
59 }
60 }
61
62diff --git a/scss/tree.scss b/scss/tree.scss
63index 05828dc61747425bebb694e5ce3743b975e94aa7..58258bd921e2dc2f06d0339233fdbbf957f54952 100644
64--- a/scss/tree.scss
65+++ b/scss/tree.scss
66@@ -53,6 +53,20 @@ .size {
67 color: $gray-700;
68 }
69
70+ @media(prefers-color-scheme: dark) {
71+ .name.blob a {
72+ color: inherit;
73+ }
74+
75+ .mode,
76+ .commit,
77+ .commit a,
78+ .date,
79+ .size {
80+ color: inherit;
81+ }
82+ }
83+
84 .name.blob {
85 text-overflow: ellipsis;
86 white-space: nowrap;
87@@ -85,7 +99,392 @@
88 // Striped rows
89 &:nth-child(10n+#{$i}) {
90 background: rgba(0, 0, 0, .05);
91+
92+ @media(prefers-color-scheme: dark) {
93+ background: lighten($gray-900, 5);
94+ }
95 }
96 }
97 }
98 }
99+
100+.code-view {
101+ display: grid;
102+ grid-template-columns: auto auto auto 1fr;
103+ grid-template-rows: auto;
104+
105+ .blame-user {
106+ grid-column-start: 1;
107+ grid-row-start: 1;
108+ background: #ddd;
109+
110+ @media(prefers-color-scheme: dark) {
111+ background: $gray-900;
112+ }
113+
114+ .hunk {
115+ padding-left: 0.5rem;
116+ }
117+ }
118+
119+ .blame-time {
120+ grid-column-start: 2;
121+ grid-row-start: 1;
122+ background: #ddd;
123+ border-right: 1px solid #444;
124+ text-align: right;
125+
126+ @media(prefers-color-scheme: dark) {
127+ background: $gray-900;
128+ }
129+
130+ .hunk {
131+ padding-right: 0.5rem;
132+ }
133+ }
134+
135+ .hunk:nth-child(2n) {
136+ background: #eee;
137+
138+ @media(prefers-color-scheme: dark) {
139+ background: lighten($gray-900, 5);
140+ }
141+ }
142+
143+ .lines {
144+ grid-column-start: 3;
145+ grid-row-start: 1;
146+ text-align: right;
147+ padding-left: 0.5rem;
148+ padding-right: 0.5rem;
149+
150+ background: #eee;
151+ border-right: 1px solid #444;
152+
153+ @media(prefers-color-scheme: dark) {
154+ background: lighten($gray-900, 5);
155+ }
156+
157+ a:target::before,
158+ a.selected::before {
159+ display: block;
160+ content: "";
161+ // +6px to connect multiple selected lines
162+ height: calc(1rem + 6px);
163+ width: 100%;
164+ z-index: -1;
165+ position: absolute;
166+ left: 0;
167+ background: lighten($blue, 35);
168+
169+ @media(prefers-color-scheme: dark) {
170+ background: $black;
171+ }
172+ }
173+ }
174+
175+ .highlight {
176+ grid-column-start: 4;
177+ grid-row-start: 1;
178+ padding-left: 1rem;
179+ background: transparent;
180+ overflow-x: hidden;
181+
182+ pre {
183+ background: transparent;
184+ }
185+ }
186+
187+ .ruler {
188+ background: transparent;
189+ grid-column-start: 4;
190+ grid-row-start: 1;
191+ display: block;
192+ padding-left: calc(1rem + 4px);
193+ height: 100%;
194+ pointer-events: none;
195+ overflow-x: hidden;
196+
197+ pre {
198+ background: transparent;
199+ }
200+
201+ &>span {
202+ height: 100%;
203+ display: inline-block;
204+ border-right: 1px solid $gray-200;
205+
206+ @media(prefers-color-scheme: dark) {
207+ border-right: 1px solid #343a40;
208+ }
209+ }
210+ }
211+}
212+
213+.ref {
214+ border-width: 1px;
215+ border-style: solid;
216+ padding: 0.1rem 0.2rem;
217+
218+ &.branch {
219+ border-color: darken($info, 20);
220+ background: $info;
221+ color: $white !important;
222+ }
223+
224+ &.tag {
225+ border-color: darken($primary, 20);
226+ background: $primary;
227+ color: $white;
228+ }
229+
230+ &.tag.annotated {
231+ border-color: darken($success, 20);
232+ background: $success;
233+ color: $white;
234+ }
235+}
236+
237+.diff {
238+ .lineno {
239+ text-decoration: none;
240+ }
241+
242+ .text-success {
243+ color: color_adjust_contrast_AERT(darken($success, 10), white) !important;
244+ }
245+
246+ .text-danger {
247+ color: color_adjust_contrast_AERT(darken($danger, 10), white) !important;
248+ }
249+
250+ pre {
251+ background: transparent;
252+ }
253+
254+ @media(prefers-color-scheme: dark) {
255+ $success-dark: #2bb34b;
256+ $danger-dark: #ff3e3e;
257+
258+ .text-success {
259+ color: $success-dark !important;
260+ }
261+
262+ .text-danger {
263+ color: $danger-dark !important;
264+ }
265+ }
266+}
267+
268+img {
269+ max-width: 100%;
270+}
271+
272+.prepare-patchset {
273+ legend {
274+ font-weight: bold;
275+ }
276+
277+ label {
278+ margin-right: 1rem;
279+ cursor: pointer;
280+ }
281+
282+ details {
283+ display: inline;
284+ color: $gray-600;
285+
286+ &[open] {
287+ display: block;
288+ color: $black;
289+
290+ summary {
291+ color: $black;
292+ }
293+ }
294+
295+ ul {
296+ list-style: none;
297+ padding-left: 0;
298+ }
299+
300+ li {
301+ margin-top: 1rem;
302+ }
303+
304+ @media(prefers-color-scheme: dark) {
305+ color: $gray-500;
306+
307+ &[open] {
308+ color: $gray-100;
309+
310+ summary {
311+ color: $gray-100;
312+ }
313+ }
314+ }
315+ }
316+
317+ .event-list {
318+ display: flex;
319+ flex-direction: column;
320+
321+ &.reverse {
322+ flex-direction: column-reverse;
323+ }
324+
325+ input[type="radio"] {
326+ display: none;
327+ }
328+
329+ &>.commit-diff {
330+ margin-top: 1rem;
331+ order: -2;
332+ }
333+
334+ &>.form-controls {
335+ order: -1;
336+ margin-top: 1rem;
337+ align-self: flex-end;
338+
339+ &.last {
340+ order: -3;
341+ }
342+ }
343+
344+ &>details {
345+ order: 0;
346+ }
347+
348+ &>.event {
349+ order: 1;
350+ display: block;
351+ margin: 0.25rem 0;
352+
353+ // Because the order is reversed
354+ &:last-child {
355+ margin: 0.25rem 0;
356+ }
357+
358+ &:first-child {
359+ margin: 0;
360+ }
361+ }
362+
363+ input[type="radio"]:checked~.event {
364+ background: lighten($info, 50) !important;
365+ }
366+
367+ input[type="radio"]:checked+.event {
368+ background: lighten($info, 45) !important;
369+ }
370+
371+ @media(prefers-color-scheme: dark) {
372+ input[type="radio"]:checked~.event {
373+ background: #131a3c !important;
374+ }
375+
376+ input[type="radio"]:checked+.event {
377+ background: #003038 !important;
378+ }
379+ }
380+ }
381+}
382+
383+.markdown-nav {
384+ padding-left: 0;
385+ padding-right: 0;
386+
387+ .nav-tabs {
388+ padding-left: 0;
389+ margin-bottom: 0;
390+ border-left: 1rem #ddd solid;
391+ }
392+}
393+
394+.blob-nav {
395+ display: inline-block;
396+ padding-left: 0;
397+ padding-right: 0;
398+
399+ .nav-item:hover {
400+ background: #fff;
401+ }
402+
403+ @media(prefers-color-scheme: dark) {
404+ .nav-item:hover {
405+ background: inherit;
406+ }
407+ }
408+
409+ .nav-tabs {
410+ padding-left: 0;
411+ margin-bottom: -3px;
412+ border-bottom: 3px transparent solid;
413+
414+ .nav-link {
415+ padding: 0 0.5rem;
416+
417+ &:hover {
418+ color: black;
419+ }
420+
421+ &.active {
422+ border-bottom: 3px #fff solid;
423+ background: #fff;
424+ }
425+
426+ @media(prefers-color-scheme: dark) {
427+ color: $gray-400;
428+
429+ &.active,
430+ &:hover {
431+ border-bottom: 3px $gray-900 solid;
432+ background: $gray-900;
433+ color: $white;
434+ }
435+ }
436+ }
437+ }
438+}
439+
440+.tree-header {
441+ display: flex;
442+
443+ .breadcrumb {
444+ flex-grow: 1;
445+ width: 100%;
446+ }
447+
448+ .commit-info {
449+ margin-left: 1rem;
450+ white-space: nowrap;
451+ text-overflow: ellipsis;
452+ overflow: hidden;
453+ min-width: 0;
454+ }
455+}
456+
457+dl {
458+ dd {
459+ text-overflow: ellipsis;
460+ overflow-x: hidden;
461+ }
462+}
463+
464+@include media-breakpoint-up(md) {
465+ .blob {
466+ padding-left: 2rem;
467+
468+ .commit {
469+ float: right;
470+ }
471+ }
472+}
473+
474+.code-viewport {
475+ display: flex;
476+ flex: 1 0 auto;
477+ padding-left: 0;
478+ padding-right: 0;
479+}
480diff --git a/templates/base.qtpl b/templates/base.qtpl
481index db9deeed4f226872ce7a32728f8c5d9db0898b5f..b3df94a5b8b51f047b1403ddea94a376122fd844 100644
482--- a/templates/base.qtpl
483+++ b/templates/base.qtpl
484@@ -54,12 +54,13 @@
485 Page prints a page implementing Page interface.
486 {% func PageTemplate(p Page, ctx context.Context) %}
487 <!DOCTYPE html>
488-<html lang="en">
489+<html lang="en" data-bs-theme="light">
490 <head>
491 <meta charset="utf-8">
492 <link rel="icon" href="data:,">
493 <title>{%= p.Title(ctx) %}</title>
494 <link rel="stylesheet" href="/static/main{%s Slug %}.css">
495+ <html data-bs-theme="dark">
496 <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
497 <meta name="viewport" content="width=device-width, initial-scale=1" />
498 </head>
499@@ -70,5 +71,8 @@ {%= p.Content(ctx) %}
500 </div>
501 </body>
502 {%= p.Script(ctx) %}
503+ <script>
504+ function a(){const e=window.matchMedia("(prefers-color-scheme: dark)").matches;document.documentElement.setAttribute("data-bs-theme",e?"dark":"light")}a(),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",a);
505+ </script>
506 </html>
507 {% endfunc %}
508diff --git a/templates/base.qtpl.go b/templates/base.qtpl.go
509index 796538ee9e81af6a386f75a825c5c8c13bbd27e6..dce4cbcf1c80f70254c7a2dc5bcbc3794414fc2d 100644
510--- a/templates/base.qtpl.go
511+++ b/templates/base.qtpl.go
512@@ -98,7 +98,7 @@ func StreamPageTemplate(qw422016 *qt422016.Writer, p Page, ctx context.Context) {
513 //line templates/base.qtpl:55
514 qw422016.N().S(`
515 <!DOCTYPE html>
516-<html lang="en">
517+<html lang="en" data-bs-theme="light">
518 <head>
519 <meta charset="utf-8">
520 <link rel="icon" href="data:,">
521@@ -112,55 +112,59 @@ //line templates/base.qtpl:62
522 qw422016.E().S(Slug)
523 //line templates/base.qtpl:62
524 qw422016.N().S(`.css">
525+ <html data-bs-theme="dark">
526 <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
527 <meta name="viewport" content="width=device-width, initial-scale=1" />
528 </head>
529 <body>
530 `)
531-//line templates/base.qtpl:67
532+//line templates/base.qtpl:68
533 p.StreamNavbar(qw422016, ctx)
534-//line templates/base.qtpl:67
535+//line templates/base.qtpl:68
536 qw422016.N().S(`
537 <div class="container">
538 `)
539-//line templates/base.qtpl:69
540+//line templates/base.qtpl:70
541 p.StreamContent(qw422016, ctx)
542-//line templates/base.qtpl:69
543+//line templates/base.qtpl:70
544 qw422016.N().S(`
545 </div>
546 </body>
547 `)
548-//line templates/base.qtpl:72
549+//line templates/base.qtpl:73
550 p.StreamScript(qw422016, ctx)
551-//line templates/base.qtpl:72
552+//line templates/base.qtpl:73
553 qw422016.N().S(`
554+ <script>
555+ function a(){const e=window.matchMedia("(prefers-color-scheme: dark)").matches;document.documentElement.setAttribute("data-bs-theme",e?"dark":"light")}a(),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",a);
556+ </script>
557 </html>
558 `)
559-//line templates/base.qtpl:74
560+//line templates/base.qtpl:78
561 }
562
563-//line templates/base.qtpl:74
564+//line templates/base.qtpl:78
565 func WritePageTemplate(qq422016 qtio422016.Writer, p Page, ctx context.Context) {
566-//line templates/base.qtpl:74
567+//line templates/base.qtpl:78
568 qw422016 := qt422016.AcquireWriter(qq422016)
569-//line templates/base.qtpl:74
570+//line templates/base.qtpl:78
571 StreamPageTemplate(qw422016, p, ctx)
572-//line templates/base.qtpl:74
573+//line templates/base.qtpl:78
574 qt422016.ReleaseWriter(qw422016)
575-//line templates/base.qtpl:74
576+//line templates/base.qtpl:78
577 }
578
579-//line templates/base.qtpl:74
580+//line templates/base.qtpl:78
581 func PageTemplate(p Page, ctx context.Context) string {
582-//line templates/base.qtpl:74
583+//line templates/base.qtpl:78
584 qb422016 := qt422016.AcquireByteBuffer()
585-//line templates/base.qtpl:74
586+//line templates/base.qtpl:78
587 WritePageTemplate(qb422016, p, ctx)
588-//line templates/base.qtpl:74
589+//line templates/base.qtpl:78
590 qs422016 := string(qb422016.B)
591-//line templates/base.qtpl:74
592+//line templates/base.qtpl:78
593 qt422016.ReleaseByteBuffer(qb422016)
594-//line templates/base.qtpl:74
595+//line templates/base.qtpl:78
596 return qs422016
597-//line templates/base.qtpl:74
598+//line templates/base.qtpl:78
599 }