Skip to content

Commit ed44dae

Browse files
clanker-loverclaude
andcommitted
Dark mode default with light/dark toggle
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 601c569 commit ed44dae

2 files changed

Lines changed: 333 additions & 79 deletions

File tree

codedocent/templates/base.html

Lines changed: 161 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,101 @@
44
<meta charset="utf-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1">
66
<title>codedocent — {{ root.name }}</title>
7+
<script>
8+
if (localStorage.getItem('cd-theme') === 'light')
9+
document.documentElement.classList.add('light-mode');
10+
</script>
711
<style>
12+
:root {
13+
--bg-body: #1a1a2e;
14+
--bg-header: #12122a;
15+
--bg-node: #222240;
16+
--bg-imports: #1e1e38;
17+
--bg-pseudocode: #1e2a38;
18+
--bg-source: #0d0d1a;
19+
--bg-badge: #2e2e50;
20+
--bg-btn: #2e2e50;
21+
--bg-btn-hover: #3a3a5a;
22+
--bg-btn-active: #4466aa;
23+
--bg-breadcrumb: #1e1e38;
24+
--bg-header-hover: #2a2a48;
25+
26+
--text-primary: #e0e0e0;
27+
--text-body: #e0e0e0;
28+
--text-name: #e0e0f0;
29+
--text-badge: #aaaacc;
30+
--text-lines: #8888aa;
31+
--text-range: #8888aa;
32+
--text-warning: #FFD700;
33+
--text-imports-label: #8888aa;
34+
--text-imports-item: #bbbbcc;
35+
--text-summary: #bbbbcc;
36+
--text-placeholder: #666688;
37+
--text-pseudocode-label: #8888aa;
38+
--text-pseudocode: #ccccdd;
39+
--text-btn: #bbbbcc;
40+
--text-link: #7799ee;
41+
--text-toggle: #8888aa;
42+
--text-analyzing: #8888aa;
43+
--text-breadcrumb-sep: #666688;
44+
--text-breadcrumb-current: #e0e0e0;
45+
--text-source: #D4D4D4;
46+
47+
--border-node: #3a3a5a;
48+
--border-imports: #3a3a5a;
49+
--border-pseudocode: #3a4a5a;
50+
--border-btn: #4a4a6a;
51+
--border-breadcrumb: #3a3a5a;
52+
--border-textarea: #555;
53+
54+
--shadow-node: rgba(0, 0, 0, 0.3);
55+
}
56+
57+
:root.light-mode {
58+
--bg-body: #F5F5F5;
59+
--bg-header: #1A1A2E;
60+
--bg-node: #FFFFFF;
61+
--bg-imports: #F9F9F9;
62+
--bg-pseudocode: #F0F4F8;
63+
--bg-source: #1E1E2E;
64+
--bg-badge: #EEEEEE;
65+
--bg-btn: #F5F5F5;
66+
--bg-btn-hover: #E8E8E8;
67+
--bg-btn-active: #1A1A2E;
68+
--bg-breadcrumb: #EDEDF0;
69+
--bg-header-hover: #FAFAFA;
70+
71+
--text-primary: #333;
72+
--text-body: #333;
73+
--text-name: #1A1A2E;
74+
--text-badge: #666666;
75+
--text-lines: #888888;
76+
--text-range: #AAAAAA;
77+
--text-warning: #B8860B;
78+
--text-imports-label: #999999;
79+
--text-imports-item: #555555;
80+
--text-summary: #555555;
81+
--text-placeholder: #AAAAAA;
82+
--text-pseudocode-label: #999999;
83+
--text-pseudocode: #444444;
84+
--text-btn: #555;
85+
--text-link: #5566DD;
86+
--text-toggle: #888;
87+
--text-analyzing: #888;
88+
--text-breadcrumb-sep: #999;
89+
--text-breadcrumb-current: #333;
90+
--text-source: #D4D4D4;
91+
92+
--border-node: #E0E0E0;
93+
--border-imports: #E8E8E8;
94+
--border-pseudocode: #D0D8E0;
95+
--border-btn: #D0D0D0;
96+
--border-breadcrumb: #D8D8DC;
97+
--border-textarea: #555;
98+
99+
--shadow-node: rgba(0, 0, 0, 0.06);
100+
}
101+
8102
*, *::before, *::after {
9103
box-sizing: border-box;
10104
}
@@ -13,16 +107,19 @@
13107
margin: 0;
14108
padding: 0;
15109
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
16-
background: #F5F5F5;
17-
color: #333;
110+
background: var(--bg-body);
111+
color: var(--text-body);
18112
line-height: 1.5;
19113
}
20114

21115
.cd-header {
22-
background: #1A1A2E;
116+
background: var(--bg-header);
23117
color: #FFFFFF;
24118
padding: 16px 24px;
25119
margin-bottom: 24px;
120+
display: flex;
121+
justify-content: space-between;
122+
align-items: center;
26123
}
27124

28125
.cd-header__title {
@@ -39,20 +136,36 @@
39136
font-family: "SF Mono", "Fira Code", "Consolas", monospace;
40137
}
41138

139+
.cd-theme-toggle {
140+
background: none;
141+
border: 1px solid rgba(255,255,255,0.3);
142+
border-radius: 8px;
143+
font-size: 20px;
144+
cursor: pointer;
145+
padding: 4px 8px;
146+
color: #FFF;
147+
line-height: 1;
148+
}
149+
150+
.cd-theme-toggle:hover {
151+
border-color: rgba(255,255,255,0.6);
152+
}
153+
42154
.cd-main {
43155
max-width: 960px;
44156
margin: 0 auto;
45157
padding: 0 16px 48px;
46158
}
47159

48160
.cd-node {
49-
background: #FFFFFF;
50-
border: 1px solid #E0E0E0;
161+
background: var(--bg-node);
162+
border: 1px solid var(--border-node);
51163
border-radius: 8px;
52-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
164+
box-shadow: 0 1px 3px var(--shadow-node);
53165
margin-bottom: 12px;
54166
border-left-width: 5px;
55167
border-left-style: solid;
168+
border-left-color: var(--node-color, #CCCCCC);
56169
}
57170

58171
.cd-node__header {
@@ -72,7 +185,7 @@
72185
font-family: "SF Mono", "Fira Code", "Consolas", monospace;
73186
font-weight: 700;
74187
font-size: 14px;
75-
color: #1A1A2E;
188+
color: var(--text-name);
76189
}
77190

78191
.cd-node__badge {
@@ -83,18 +196,18 @@
83196
letter-spacing: 0.05em;
84197
padding: 2px 8px;
85198
border-radius: 10px;
86-
background: #EEEEEE;
87-
color: #666666;
199+
background: var(--bg-badge);
200+
color: var(--text-badge);
88201
}
89202

90203
.cd-node__lines {
91204
font-size: 12px;
92-
color: #888888;
205+
color: var(--text-lines);
93206
}
94207

95208
.cd-node__range {
96209
font-size: 12px;
97-
color: #AAAAAA;
210+
color: var(--text-range);
98211
font-family: "SF Mono", "Fira Code", "Consolas", monospace;
99212
}
100213

@@ -105,7 +218,7 @@
105218

106219
.cd-node__warning-text {
107220
font-size: 11px;
108-
color: #B8860B;
221+
color: var(--text-warning);
109222
font-style: italic;
110223
}
111224

@@ -114,8 +227,8 @@
114227
}
115228

116229
.cd-imports {
117-
background: #F9F9F9;
118-
border: 1px solid #E8E8E8;
230+
background: var(--bg-imports);
231+
border: 1px solid var(--border-imports);
119232
border-radius: 6px;
120233
padding: 8px 12px;
121234
margin-bottom: 8px;
@@ -126,31 +239,31 @@
126239
font-weight: 700;
127240
text-transform: uppercase;
128241
letter-spacing: 0.08em;
129-
color: #999999;
242+
color: var(--text-imports-label);
130243
margin-bottom: 4px;
131244
}
132245

133246
.cd-imports__item {
134247
font-family: "SF Mono", "Fira Code", "Consolas", monospace;
135248
font-size: 13px;
136-
color: #555555;
249+
color: var(--text-imports-item);
137250
padding: 1px 0;
138251
}
139252

140253
.cd-summary {
141-
color: #555555;
254+
color: var(--text-summary);
142255
font-size: 13px;
143256
margin-bottom: 8px;
144257
}
145258

146259
.cd-summary--placeholder {
147260
font-style: italic;
148-
color: #AAAAAA;
261+
color: var(--text-placeholder);
149262
}
150263

151264
.cd-pseudocode {
152-
background: #F0F4F8;
153-
border: 1px solid #D0D8E0;
265+
background: var(--bg-pseudocode);
266+
border: 1px solid var(--border-pseudocode);
154267
border-radius: 6px;
155268
padding: 8px 12px;
156269
margin-bottom: 8px;
@@ -161,14 +274,14 @@
161274
font-weight: 700;
162275
text-transform: uppercase;
163276
letter-spacing: 0.08em;
164-
color: #999999;
277+
color: var(--text-pseudocode-label);
165278
margin-bottom: 4px;
166279
}
167280

168281
.cd-pseudocode__code {
169282
font-family: "SF Mono", "Fira Code", "Consolas", monospace;
170283
font-size: 13px;
171-
color: #444444;
284+
color: var(--text-pseudocode);
172285
margin: 0;
173286
white-space: pre-wrap;
174287
}
@@ -179,7 +292,7 @@
179292

180293
.cd-warnings__item {
181294
font-size: 13px;
182-
color: #B8860B;
295+
color: var(--text-warning);
183296
padding: 2px 0;
184297
}
185298

@@ -199,21 +312,21 @@
199312
font-weight: 600;
200313
padding: 4px 12px;
201314
border-radius: 14px;
202-
border: 1px solid #D0D0D0;
203-
background: #F5F5F5;
204-
color: #555;
315+
border: 1px solid var(--border-btn);
316+
background: var(--bg-btn);
317+
color: var(--text-btn);
205318
cursor: pointer;
206319
transition: background 0.15s, color 0.15s;
207320
}
208321

209322
.cd-code-btn:hover {
210-
background: #E8E8E8;
323+
background: var(--bg-btn-hover);
211324
}
212325

213326
.cd-code-btn--active {
214-
background: #1A1A2E;
327+
background: var(--bg-btn-active);
215328
color: #FFF;
216-
border-color: #1A1A2E;
329+
border-color: var(--bg-btn-active);
217330
}
218331

219332
.cd-code-btn--copied {
@@ -224,8 +337,8 @@
224337

225338
.cd-source-display {
226339
display: none;
227-
background: #1E1E2E;
228-
color: #D4D4D4;
340+
background: var(--bg-source);
341+
color: var(--text-source);
229342
border-radius: 6px;
230343
padding: 12px;
231344
margin-bottom: 8px;
@@ -263,7 +376,7 @@
263376
<body>
264377

265378
{% macro render_node(node) %}
266-
<div class="cd-node cd-node--{{ node.node_type }}" style="border-left-color: {{ get_color(node) }};">
379+
<div class="cd-node cd-node--{{ node.node_type }}" style="--node-color: {{ get_color(node) }};">
267380
<div class="cd-node__header">
268381
<span class="cd-node__icon">{{ NODE_ICONS.get(node.node_type, '') }}</span>
269382
<span class="cd-node__name">{{ node.name }}</span>
@@ -334,15 +447,29 @@
334447
{% endmacro %}
335448

336449
<header class="cd-header">
337-
<h1 class="cd-header__title">codedocent</h1>
338-
<p class="cd-header__path">{{ root.filepath or root.name }}</p>
450+
<div class="cd-header__text">
451+
<h1 class="cd-header__title">codedocent</h1>
452+
<p class="cd-header__path">{{ root.filepath or root.name }}</p>
453+
</div>
454+
<button class="cd-theme-toggle" id="cd-theme-toggle"
455+
onclick="cdToggleTheme()" aria-label="Toggle theme"></button>
339456
</header>
340457

341458
<main class="cd-main">
342459
{{ render_node(root) }}
343460
</main>
344461

345462
<script>
463+
function cdToggleTheme() {
464+
var isLight = document.documentElement.classList.toggle('light-mode');
465+
localStorage.setItem('cd-theme', isLight ? 'light' : 'dark');
466+
document.getElementById('cd-theme-toggle').textContent = isLight ? '\u{1F319}' : '\u2600\uFE0F';
467+
}
468+
(function() {
469+
var btn = document.getElementById('cd-theme-toggle');
470+
if (btn) btn.textContent = document.documentElement.classList.contains('light-mode') ? '\u{1F319}' : '\u2600\uFE0F';
471+
})();
472+
346473
function cdToggleSource(btn) {
347474
var pre = btn.closest('.cd-node__body').querySelector('.cd-source-display');
348475
var isOpen = pre.classList.contains('cd-source-display--open');

0 commit comments

Comments
 (0)