Skip to content

Commit 42fd957

Browse files
authored
Merge pull request #9 from Doppp/codex/library-theme-responsive
Add responsive light and dark course themes
2 parents 33f7625 + 06f526a commit 42fd957

12 files changed

Lines changed: 587 additions & 87 deletions

File tree

apps/dev-preview/index.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@
55
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
66
<meta name="description" content="A local explorables course" />
77
<title>explorables course</title>
8+
<script>
9+
(() => {
10+
const storedTheme = localStorage.getItem("explorables:theme");
11+
const theme =
12+
storedTheme === "light" || storedTheme === "dark"
13+
? storedTheme
14+
: matchMedia("(prefers-color-scheme: dark)").matches
15+
? "dark"
16+
: "light";
17+
document.documentElement.dataset.theme = theme;
18+
document.documentElement.style.colorScheme = theme;
19+
})();
20+
</script>
821
</head>
922
<body>
1023
<nav aria-label="Skip links">

apps/dev-preview/src/styles.css

Lines changed: 127 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,28 +28,49 @@
2828
}
2929

3030
@media (prefers-color-scheme: dark) {
31-
:root {
31+
:root:not([data-theme]) {
3232
color-scheme: dark;
33-
--canvas: #19201c;
34-
--surface: #212a25;
35-
--surface-soft: #252e29;
36-
--sage: #27372e;
37-
--sage-strong: #30473a;
38-
--rose: #382b31;
39-
--blue: #27343b;
40-
--butter: #383323;
41-
--ink: #edf1ec;
42-
--muted: #b8c0ba;
43-
--primary: #a9d1b8;
44-
--primary-hover: #c0dfc9;
33+
--canvas: #171b20;
34+
--surface: #20262c;
35+
--surface-soft: #292f36;
36+
--sage: #25372f;
37+
--sage-strong: #345243;
38+
--rose: #3b292f;
39+
--blue: #263746;
40+
--butter: #3a3424;
41+
--ink: #f3f1ea;
42+
--muted: #bdc5bf;
43+
--primary: #b4d9c3;
44+
--primary-hover: #cde6d6;
4545
--on-primary: #173528;
46-
--focus: #8cb8f2;
47-
--border: #505b54;
48-
--border-strong: #7b8780;
49-
--danger: #f1a3aa;
46+
--focus: #9bc5ff;
47+
--border: #465049;
48+
--border-strong: #78847c;
49+
--danger: #ffb1b8;
5050
}
5151
}
5252

53+
:root[data-theme="dark"] {
54+
color-scheme: dark;
55+
--canvas: #171b20;
56+
--surface: #20262c;
57+
--surface-soft: #292f36;
58+
--sage: #25372f;
59+
--sage-strong: #345243;
60+
--rose: #3b292f;
61+
--blue: #263746;
62+
--butter: #3a3424;
63+
--ink: #f3f1ea;
64+
--muted: #bdc5bf;
65+
--primary: #b4d9c3;
66+
--primary-hover: #cde6d6;
67+
--on-primary: #173528;
68+
--focus: #9bc5ff;
69+
--border: #465049;
70+
--border-strong: #78847c;
71+
--danger: #ffb1b8;
72+
}
73+
5374
* {
5475
box-sizing: border-box;
5576
}
@@ -141,6 +162,64 @@ button {
141162
cursor: pointer;
142163
}
143164

165+
.theme-toggle {
166+
display: inline-flex;
167+
flex: 0 0 auto;
168+
align-items: center;
169+
gap: 0.5rem;
170+
min-height: 2.6rem;
171+
padding: 0.35rem 0.55rem 0.35rem 0.7rem;
172+
border: 1px solid var(--border-strong);
173+
border-radius: 999px;
174+
background: var(--surface);
175+
color: var(--ink);
176+
cursor: pointer;
177+
}
178+
179+
.theme-toggle:hover {
180+
background: var(--sage);
181+
}
182+
183+
.theme-toggle-label {
184+
font-size: 0.72rem;
185+
font-weight: 700;
186+
line-height: 1;
187+
white-space: nowrap;
188+
}
189+
190+
.theme-toggle-track {
191+
position: relative;
192+
width: 1.9rem;
193+
height: 1.1rem;
194+
border: 1px solid var(--border-strong);
195+
border-radius: 999px;
196+
background: var(--surface-soft);
197+
}
198+
199+
.theme-toggle-thumb {
200+
position: absolute;
201+
top: 0.17rem;
202+
left: 0.17rem;
203+
width: 0.65rem;
204+
height: 0.65rem;
205+
border-radius: 50%;
206+
background: var(--muted);
207+
}
208+
209+
.theme-toggle[aria-pressed="true"] {
210+
background: var(--sage);
211+
}
212+
213+
.theme-toggle[aria-pressed="true"] .theme-toggle-track {
214+
border-color: var(--primary);
215+
background: var(--sage-strong);
216+
}
217+
218+
.theme-toggle[aria-pressed="true"] .theme-toggle-thumb {
219+
background: var(--primary);
220+
transform: translateX(0.8rem);
221+
}
222+
144223
h1,
145224
h2,
146225
h3 {
@@ -170,6 +249,14 @@ h3 {
170249
border-bottom: 1px solid var(--border);
171250
}
172251

252+
.course-sidebar-masthead,
253+
.library-masthead {
254+
display: flex;
255+
align-items: center;
256+
justify-content: space-between;
257+
gap: 1rem;
258+
}
259+
173260
.course-title {
174261
margin: 0.85rem 0 0;
175262
font-family: ui-serif, "Iowan Old Style", "Palatino Linotype", Georgia, serif;
@@ -350,7 +437,7 @@ h3 {
350437
}
351438

352439
.library-hero {
353-
max-width: 47rem;
440+
width: 100%;
354441
margin-bottom: 3.5rem;
355442
}
356443

@@ -360,17 +447,20 @@ h3 {
360447

361448
.library-title {
362449
margin: 0;
450+
text-wrap: balance;
363451
}
364452

365-
.library-hero > p:not(.eyebrow) {
366-
max-width: 43rem;
453+
.library-summary {
454+
max-width: 68ch;
367455
font-size: 1.03rem;
368456
}
369457

370458
.library-hero > .local-note {
459+
width: 100%;
460+
max-width: none;
371461
margin: 1.5rem 0;
372462
padding: 0.9rem 1rem;
373-
border: 1px solid var(--border);
463+
border: 1px solid var(--border-strong);
374464
border-radius: var(--radius-sm);
375465
background: var(--blue);
376466
color: var(--muted);
@@ -437,7 +527,7 @@ h3 {
437527
min-width: 0;
438528
flex-direction: column;
439529
padding: 1.3rem;
440-
border: 1px solid var(--border);
530+
border: 1px solid var(--border-strong);
441531
border-radius: var(--radius-md);
442532
background: var(--surface);
443533
}
@@ -845,15 +935,20 @@ pre code {
845935
}
846936

847937
.course-sidebar-header {
848-
display: flex;
849-
align-items: baseline;
938+
display: grid;
939+
align-items: center;
850940
justify-content: space-between;
941+
grid-template-columns: minmax(0, 1fr) minmax(0, auto);
851942
gap: 1rem;
852943
margin: 0;
853944
padding: 0;
854945
border: 0;
855946
}
856947

948+
.course-sidebar-masthead {
949+
min-width: 0;
950+
}
951+
857952
.course-title {
858953
max-width: 65%;
859954
margin: 0;
@@ -948,6 +1043,10 @@ pre code {
9481043
display: block;
9491044
}
9501045

1046+
.course-sidebar-masthead {
1047+
width: 100%;
1048+
}
1049+
9511050
.course-title {
9521051
max-width: none;
9531052
margin-top: 0.45rem;
@@ -1013,6 +1112,10 @@ pre code {
10131112
border-color 160ms ease,
10141113
background-color 160ms ease;
10151114
}
1115+
1116+
.theme-toggle-thumb {
1117+
transition: transform 160ms ease;
1118+
}
10161119
}
10171120

10181121
@media (prefers-reduced-motion: reduce) {

docs/implementation-status.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,18 @@ Updated: 13 August 2026
6565
explicit navigation states, compact course contents below 992px, and visually
6666
consistent sandbox controls. The course shell now reflows at 320px without
6767
putting the full lesson list ahead of the active lesson.
68+
- Added an explicit, persistent light/dark theme control to the course library
69+
and lesson shell, including live theme synchronization into already-mounted
70+
sandboxed explorables. Retuned the dark pastel roles, restored the library
71+
hero and local-data notice to the full responsive content width, and corrected
72+
title casing while preserving the lowercase `explorables` wordmark.
6873

6974
## Current work
7075

7176
The v0.1 runtime MVP remains verified. `AI from First Principles`
7277
`0.3.0-guided.1`, Guided Course Mode, Agent Plugins v1 packaging, and the local
73-
course-library milestone are implemented. The course UI redesign is complete.
78+
course-library milestone are implemented. The course UI redesign and its
79+
responsive/theme follow-up are complete.
7480
The library presents the shared
7581
frontier core and DeepSeek, Kimi, Qwen, MiniMax, and GLM specializations as
7682
planned rather than runnable. The next implementation increment remains the
@@ -118,12 +124,12 @@ npm view pnpm@11 version latest 11.15.1
118124
official Node release status Node 24 is LTS
119125
official Claude Desktop preview docs launch schema version 0.0.1 confirmed
120126
Agent Skills validation pass (template and both first-party courses)
121-
pnpm check pass under Node 24 (format, lint, TS7, 23 suites/76 tests, collection/plugin/course validators)
127+
pnpm check pass under Node 24 (format, lint, TS7, 24 suites/78 tests, collection/plugin/course validators)
122128
pnpm course:test pass under Node 24 (14 model suites/47 tests; 14 starter/reference pairs)
123129
pnpm build pass under Node 24 (9 package entries, collection, standalone course, static site)
124-
pnpm test:browser pass under Node 24 (11 tests; light/dark roles, library, safe routes, guided flow, sandbox, persistence, breakpoint state, failures, axe, 720px, 320px)
130+
pnpm test:browser pass under Node 24 (12 tests; persisted light/dark themes, sandbox sync, library, safe routes, guided flow, failures, axe, 1427px, 1156px, 720px, 320px)
125131
pnpm site:test pass (content, no-tracking copy, axe, 720px)
126-
course UI visual QA pass (library and lesson at 1440px, 800px, 390px, and 320px; no console errors)
132+
course UI visual QA pass (light/dark library at 1156px, 720px, and 320px; full-width hero/note, no overflow)
127133
generated course smoke pass (Agent Plugin manifest/skill, validate, static build)
128134
pnpm audit --audit-level high pass (no known vulnerabilities)
129135
Pages workflow YAML parse pass

explorables.library.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"schemaVersion": 1,
3-
"title": "explorables model-learning path",
3+
"title": "explorables Model-Learning Path",
44
"summary": "Build a language model from first principles, learn to evaluate frontier-model evidence, then choose a model-family specialization.",
55
"tracks": [
66
{
@@ -17,7 +17,7 @@
1717
},
1818
{
1919
"id": "research-skills",
20-
"title": "Research skills",
20+
"title": "Research Skills",
2121
"summary": "Learn to inspect real releases and make controlled, source-grounded comparisons.",
2222
"courses": [
2323
{
@@ -32,7 +32,7 @@
3232
},
3333
{
3434
"id": "specializations",
35-
"title": "Model specializations",
35+
"title": "Model Specializations",
3636
"summary": "Reconstruct distinctive mechanisms from pinned model-family releases.",
3737
"courses": [
3838
{

0 commit comments

Comments
 (0)