Skip to content

Commit 6c018c7

Browse files
rcosta358codex
andcommitted
Add polished dark mode to the docs
Co-authored-by: Codex <noreply@openai.com>
1 parent cd9f42b commit 6c018c7

5 files changed

Lines changed: 218 additions & 3 deletions

File tree

‎_includes/head_custom.html‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
33
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible:wght@400;700&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
44
<link rel="sitemap" type="application/xml" title="Sitemap" href="{{ '/sitemap.xml' | absolute_url }}">
5+
<script src="{{ '/assets/js/appearance.js' | relative_url }}"></script>

‎_includes/header_custom.html‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<div class="appearance-control">
2+
<button id="appearance" type="button" aria-label="Switch to dark mode" title="Switch to dark mode">
3+
<svg class="appearance-moon" viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
4+
<path d="M20.5 13.2A8.5 8.5 0 0 1 10.8 3.5a8.5 8.5 0 1 0 9.7 9.7Z" />
5+
</svg>
6+
<svg class="appearance-sun" viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round">
7+
<circle cx="12" cy="12" r="4" />
8+
<path d="M12 2v2m0 16v2M2 12h2m16 0h2M4.9 4.9l1.4 1.4m11.4 11.4 1.4 1.4m0-14.2-1.4 1.4M6.3 17.7l-1.4 1.4" />
9+
</svg>
10+
</button>
11+
</div>

‎_sass/custom/appearance.scss‎

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
.search-input::placeholder, .search-icon { color: #66707b; }
2+
3+
.appearance-control {
4+
display: none;
5+
align-items: center;
6+
padding: .5rem 1rem;
7+
flex-shrink: 0;
8+
font-size: .75rem;
9+
10+
button {
11+
display: grid;
12+
place-items: center;
13+
width: 2.5rem;
14+
height: 2.5rem;
15+
padding: .5rem;
16+
border: 0;
17+
border-radius: .5rem;
18+
background: transparent;
19+
color: #2a2f36;
20+
font: inherit;
21+
cursor: pointer;
22+
}
23+
}
24+
25+
:root[data-theme] .appearance-control { display: flex; }
26+
.appearance-control button:hover { background: #e5e9ed; }
27+
.appearance-control svg { width: 1.25rem; height: 1.25rem; }
28+
.appearance-sun { display: none; }
29+
:root[data-theme="dark"] .appearance-moon { display: none; }
30+
:root[data-theme="dark"] .appearance-sun { display: block; }
31+
32+
.appearance-control button:focus-visible {
33+
outline: 2px solid #5f7ea1;
34+
outline-offset: 3px;
35+
}
36+
37+
// keep appearance available when the mobile navigation is collapsed
38+
@media (max-width: 49.99rem) {
39+
body .side-bar + .main .main-header,
40+
body .side-bar + .main .main-header.nav-open { display: flex; }
41+
.search { min-width: 0; }
42+
.appearance-control { padding-left: 0; }
43+
}
44+
45+
@mixin dark-appearance {
46+
color-scheme: dark;
47+
48+
body { color: #c9d2de; background: #141a23; }
49+
h1, h2, h3, h4, h5, h6, #toctitle { color: #edf2f8; }
50+
a, .main-content a { color: #9cc9ec; }
51+
a:not([class]) { text-decoration-color: #526b82; }
52+
a:not([class]):hover { text-decoration-color: #9cc9ec; }
53+
:focus-visible { outline-color: #9cc9ec; }
54+
hr { background: #303c4c; }
55+
56+
.side-bar {
57+
background: radial-gradient(ellipse at top left, rgba(104, 151, 194, .08), transparent 65%), #191f29;
58+
border-color: #303c4c;
59+
}
60+
.site-header, .main-header, .site-nav, .site-footer { border-color: #303c4c; }
61+
body .side-bar + .main .main-header { background: #141a23; }
62+
.site-title { color: #edf2f8 !important; }
63+
.site-title:hover, .site-button:hover { background: #242f3e; }
64+
.site-footer { color: #9baabc; }
65+
.icon, .site-button, .nav-list .nav-list-item .nav-list-expander { color: #9cc9ec; }
66+
.nav-list .nav-list-item > .nav-list .nav-list-item .nav-list-link,
67+
.nav-list .nav-list-item > .nav-list .nav-list-item .nav-list-expander { color: #b8c7d8; }
68+
.nav-list .nav-list-item .nav-list-link:hover,
69+
.nav-list .nav-list-item .nav-list-link.active,
70+
.nav-list .nav-list-item .nav-list-expander:hover {
71+
background: linear-gradient(90deg, rgba(104, 151, 194, .04), rgba(104, 151, 194, .16));
72+
color: #d1e9ff;
73+
}
74+
.nav-list-link.active { box-shadow: inset 3px 0 #8dbce2; }
75+
.breadcrumb-nav-list-item::after { color: #77889b; }
76+
77+
.search-input, .search-results, .search-result { color: #c9d2de; background: #191f29; }
78+
.search-input { background: #141a23; }
79+
.search-input::placeholder, .search-icon { color: #9baabc; }
80+
.search-result:hover, .search-result.active { background: #243244; }
81+
.search-result-title, .search-result-doc, .search-result-section { color: #d1e9ff; }
82+
.search-result-preview { color: #b8c7d8; }
83+
.search-result-previews { border-color: #405169; }
84+
.search-result-doc.search-result-doc-parent { opacity: 1; color: #9baabc; }
85+
.search-result-doc .search-result-icon { color: #9baabc; }
86+
.search-result-rel-url { color: #9baabc; }
87+
.search-result-highlight { color: #edf2f8; }
88+
.search-results { border: 1px solid #303c4c; box-shadow: 0 16px 40px #0006; }
89+
90+
.appearance-control { color: #9baabc; }
91+
.appearance-control button { color: #dce6f2; }
92+
.appearance-control button:hover { background: #29394c; }
93+
.appearance-control button:focus-visible { outline-color: #9cc9ec; }
94+
95+
.main-content :not(pre) > code { color: #d1e9ff; background: #253142; border-color: #35465b; }
96+
.main-content pre.highlight,
97+
.main-content div.highlighter-rouge,
98+
.main-content #lj-editor,
99+
.main-content .lj-output {
100+
background: #101620;
101+
border-color: #344256;
102+
box-shadow: none;
103+
}
104+
.main-content .highlight .c,
105+
.main-content .highlight .cm,
106+
.main-content .highlight .c1,
107+
.main-content .highlight .cs { color: #9baabc; }
108+
.main-content img:not(.home-banner img) { border-color: #344256; box-shadow: none; }
109+
.home-banner img { filter: brightness(.82) saturate(.9); }
110+
.home-banner { border: 1px solid #344256; background: #101620; }
111+
.main-content blockquote { background: #1d2836; border-color: #718da9; }
112+
113+
.card-panel, .page-nav-link {
114+
background: #1c2531;
115+
border-color: #334154;
116+
box-shadow: none;
117+
}
118+
.card-panel:hover, .page-nav-link:hover { background: #232f3e; border-color: #6383a2; box-shadow: none; }
119+
.page-nav-label { color: #9baabc; }
120+
.page-nav-title { color: #dce6f2; }
121+
.page-nav-link:focus-visible { outline: 2px solid #9cc9ec; outline-offset: 3px; box-shadow: none; }
122+
.main-content .home-button { background: #9cc9ec; color: #142332; box-shadow: none; }
123+
.main-content .home-button:hover { background: #bcdef7; color: #142332; }
124+
th, td { background: #1c2531; border-color: #334154; }
125+
thead th { background: #253142; border-color: #405169; color: #edf2f8; }
126+
.table-wrapper { border: 1px solid #334154; box-shadow: none; }
127+
128+
@each $name, $accent, $surface in (note, #9cc9ec, #1d2c3d), (tip, #a7d9b9, #1d302d), (warn, #e5c784, #322e23) {
129+
.main-content p.#{$name}, .main-content blockquote.#{$name} {
130+
background: $surface;
131+
border-color: $accent;
132+
box-shadow: none;
133+
&::before, > .#{$name}-title { color: $accent; }
134+
}
135+
}
136+
137+
.lj-toolbar label { color: #b8c7d8; }
138+
.lj-toolbar select { color: #dce6f2; background: #202b39; border-color: #405169; }
139+
.lj-toolbar select:hover { background: #29394c; border-color: #8dbce2; }
140+
.lj-toolbar button { color: #9cc9ec; border-color: #405169; }
141+
.lj-toolbar button:hover:not(:disabled) { background: #29394c; border-color: #8dbce2; }
142+
.lj-toolbar #lj-verify, .lj-toolbar #lj-reset { color: #142332; background: #9cc9ec; border-color: #9cc9ec; }
143+
.lj-toolbar #lj-verify:hover:not(:disabled), .lj-toolbar #lj-reset:hover { color: #142332; background: #bcdef7; border-color: #bcdef7; }
144+
.lj-toolbar #lj-verify[data-state="busy"] { color: #fff; background: #a8323d; border-color: #cb6871; }
145+
.lj-toolbar #lj-verify[data-state="busy"]:hover { background: #bd3d49; }
146+
.lj-toolbar button:disabled, .lj-toolbar #lj-verify:disabled { color: #9baabc; background: #293342; border-color: #405169; }
147+
}
148+
149+
:root[data-theme="dark"] { @include dark-appearance; }
150+
151+
// the system theme also works without JavaScript
152+
@media (prefers-color-scheme: dark) {
153+
:root:not([data-theme]) { @include dark-appearance; }
154+
}

‎_sass/custom/custom.scss‎

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
.site-header {
2-
border-bottom: 1px solid rgba(23, 26, 31, 0.08);
1+
.site-header,
2+
.main-header {
3+
border-bottom: 0;
4+
}
5+
6+
.main-content > hr {
7+
display: none;
38
}
49

510
.site-title {
@@ -248,6 +253,14 @@
248253
list-style: disc;
249254
}
250255

256+
.main-content ul > li::before {
257+
content: none;
258+
}
259+
260+
.main-content .task-list-item {
261+
list-style: none;
262+
}
263+
251264
.main-content li > ul,
252265
.main-content li > ol {
253266
margin-top: 0.35rem;
@@ -333,7 +346,6 @@
333346
gap: 0.75rem;
334347
margin: 2.25rem 0 0.25rem;
335348
padding-top: 1.25rem;
336-
border-top: 1px solid rgba(17, 24, 39, 0.08);
337349
}
338350

339351
.page-nav-link {
@@ -402,3 +414,5 @@
402414
grid-template-columns: repeat(2, minmax(0, 1fr));
403415
}
404416
}
417+
418+
@import "custom/appearance";

‎assets/js/appearance.js‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
(() => {
2+
const root = document.documentElement;
3+
const system = window.matchMedia('(prefers-color-scheme: dark)');
4+
const key = 'liquidjava-appearance';
5+
let preference = 'system';
6+
let button;
7+
try {
8+
const saved = localStorage.getItem(key);
9+
if (['light', 'dark'].includes(saved)) preference = saved;
10+
} catch (_) { /* appearance still works when storage is unavailable */ }
11+
12+
function apply() {
13+
root.dataset.theme = preference === 'system'
14+
? (system.matches ? 'dark' : 'light') : preference;
15+
if (button) {
16+
const label = root.dataset.theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode';
17+
button.setAttribute('aria-label', label);
18+
button.title = label;
19+
}
20+
}
21+
apply();
22+
system.addEventListener('change', apply);
23+
24+
document.addEventListener('DOMContentLoaded', () => {
25+
button = document.getElementById('appearance');
26+
apply();
27+
button.addEventListener('click', () => {
28+
preference = root.dataset.theme === 'dark' ? 'light' : 'dark';
29+
try {
30+
localStorage.setItem(key, preference);
31+
} catch (_) { /* keep the selection for this page */ }
32+
apply();
33+
});
34+
});
35+
})();

0 commit comments

Comments
 (0)