Light is the default theme (refs #74) d98a93c10a0d
With no theme cookie the hub is light: the script that sets the theme before first paint, the header toggle (light, dark, then the system) and Settings → Appearance all start from light. Dark and matching the system stay a click away.
- Author
- Andy McCall @andymccall <[email protected]>
- When
- · 2026-10-01 22:34 UTC
- Signature
- ✔ signed by Andy McCall
- Hash
d98a93c10a0d714c5c91e66f200cd08c5b28a9f81bf702bc8eb08a055ab8b8a4- Depends on
- 18e381ea88c2 19bb31ff1f5c 749d9a5fcd9f 93be9ce4653e b5668108487f c40c2d3edb51 d23464c0ac60 f6346d875ee5
- Depended on by
- a7aa76ac52d7 17ca6cddc534 070a7b64b368
- In bookmarks
- api-unknown-fields cancel-landed-runs clear-waiting close-proposal-140 diffusion-pin-bookmark draft-ready image-check job-waits main oh-comment-body-file proposal-list-fast run-one-job wiki-says-so
- In tags
- v0.3.0 v0.3.1 v0.4.0 v0.4.1 v0.4.2 v0.5.0 v0.5.1 v0.5.2 v0.6.0 v0.6.1 v0.7.0 v0.8.0 v0.9.0 v0.9.1 v0.9.11 v0.9.15 v0.9.16 v0.9.19 v0.9.2 v0.9.20 v0.9.21 v0.9.22 v0.9.23 v0.9.24 v0.9.3 v0.9.4 v0.9.5 v0.9.6 v0.9.7 v0.9.8 v0.9.9
- Edits
- 19 atoms, 0 tree operations, 6 files
Browse the tree at this change
modified CHANGELOG.md +1 −1
| … | 3 unchanged lines |
||
| 4 | 4 | ||
| 5 | 5 | ## Unreleased |
|
| 6 | 6 | ||
| 7 | - | - **A GitHub-like look, now the default (#74).** Primer colours in light and dark, system fonts, rounded boxes, underline navigation, grey and green buttons, sentence case and pill labels, for readability and familiarity. The RetroPlay look stays available: `?look=classic` on any page keeps it for that browser, and `?look=github` returns to the default. |
|
| 7 | + | - **A GitHub-like look, now the default (#74).** Primer colours in light and dark, system fonts, rounded boxes, underline navigation, grey and green buttons, sentence case and pill labels, for readability and familiarity, light by default (the theme toggle and Settings → Appearance still offer dark and matching the system). The RetroPlay look stays available: `?look=classic` on any page keeps it for that browser, and `?look=github` returns to the default. |
|
| 8 | 8 | ||
| 9 | 9 | ## 0.2.0 (2026-10-01) |
|
| 10 | 10 | ||
| … | 16 unchanged lines |
modified assets/hub.js +3 −3
| … | 30 unchanged lines |
||
| 31 | 31 | /* Theme switch in the header: dark, light, auto (follows the system); kept in the theme cookie. */ |
|
| 32 | 32 | var toggle = document.querySelector("[data-theme-toggle]"); |
|
| 33 | 33 | if (toggle) { |
|
| 34 | - | var root = document.documentElement, order = ["dark", "light", "auto"], glyph = { dark: "◐", light: "☀", auto: "◑" }; |
|
| 34 | + | var root = document.documentElement, order = ["light", "dark", "auto"], glyph = { dark: "◐", light: "☀", auto: "◑" }; |
|
| 35 | 35 | var show = function () { |
|
| 36 | - | var p = root.dataset.themePref || "dark"; |
|
| 36 | + | var p = root.dataset.themePref || "light"; |
|
| 37 | 37 | toggle.title = "Theme: " + p + " (click to change)"; |
|
| 38 | 38 | toggle.setAttribute("aria-label", toggle.title); |
|
| 39 | 39 | toggle.firstElementChild.textContent = glyph[p]; |
|
| 40 | 40 | }; |
|
| 41 | 41 | show(); |
|
| 42 | 42 | toggle.addEventListener("click", function () { |
|
| 43 | - | var p = order[(order.indexOf(root.dataset.themePref || "dark") + 1) % order.length]; |
|
| 43 | + | var p = order[(order.indexOf(root.dataset.themePref || "light") + 1) % order.length]; |
|
| 44 | 44 | document.cookie = "theme=" + p + "; path=/; max-age=31536000; samesite=lax"; |
|
| 45 | 45 | root.dataset.themePref = p; |
|
| 46 | 46 | root.dataset.theme = p === "auto" ? (window.matchMedia && matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark") : p; |
|
| … | 342 unchanged lines |
modified crates/hub/src/web/settings.rs +3 −3
| … | 50 unchanged lines |
||
| 51 | 51 | } |
|
| 52 | 52 | ||
| 53 | 53 | /// The themes (hub spec §6.1): the cookie value and its label. |
|
| 54 | - | const THEMES: &[(&str, &str)] = &[("dark", "Dark"), ("light", "Light"), ("auto", "Match the system")]; |
|
| 54 | + | const THEMES: &[(&str, &str)] = &[("light", "Light"), ("dark", "Dark"), ("auto", "Match the system")]; |
|
| 55 | 55 | ||
| 56 | - | /// The theme the request's cookie asks for; dark when unset or unknown. |
|
| 56 | + | /// The theme the request's cookie asks for; light when unset or unknown. |
|
| 57 | 57 | fn theme_of(headers: &HeaderMap) -> &'static str { |
|
| 58 | 58 | let v = auth::viewer::cookie(headers, "theme").unwrap_or_default(); |
|
| 59 | - | THEMES.iter().map(|(t, _)| *t).find(|t| *t == v).unwrap_or("dark") |
|
| 59 | + | THEMES.iter().map(|(t, _)| *t).find(|t| *t == v).unwrap_or("light") |
|
| 60 | 60 | } |
|
| 61 | 61 | ||
| 62 | 62 | impl SettingsPage { |
|
| … | 519 unchanged lines |
modified crates/hub/tests/issues.rs +5 −5
| … | 426 unchanged lines |
||
| 427 | 427 | let andy = register(app, "andy").await; |
|
| 428 | 428 | let page = get(app, "/settings", Some(&andy)).await; |
|
| 429 | 429 | assert!(page.body.contains("Appearance")); |
|
| 430 | - | assert!(page.body.contains(r#"value="dark" checked"#), "dark by default: {}", page.body); |
|
| 430 | + | assert!(page.body.contains(r#"value="light" checked"#), "light by default: {}", page.body); |
|
| 431 | 431 | assert!(page.body.contains("data-theme-toggle"), "the header has the switch"); |
|
| 432 | 432 | let csrf = csrf_of(&page.body); |
|
| 433 | - | let r = post(app, "/settings/appearance", Some(&andy), &format!("_csrf={csrf}&theme=light")).await; |
|
| 433 | + | let r = post(app, "/settings/appearance", Some(&andy), &format!("_csrf={csrf}&theme=dark")).await; |
|
| 434 | 434 | assert_eq!(r.status, StatusCode::SEE_OTHER); |
|
| 435 | - | assert_eq!(r.cookie.as_deref(), Some("light")); |
|
| 435 | + | assert_eq!(r.cookie.as_deref(), Some("dark")); |
|
| 436 | 436 | assert_eq!(r.location.as_deref(), Some("/settings")); |
|
| 437 | - | let page = send_with_theme(app, &andy, "light").await; |
|
| 438 | - | assert!(page.contains(r#"value="light" checked"#), "the form shows the cookie's theme"); |
|
| 437 | + | let page = send_with_theme(app, &andy, "dark").await; |
|
| 438 | + | assert!(page.contains(r#"value="dark" checked"#), "the form shows the cookie's theme"); |
|
| 439 | 439 | assert_eq!(post(app, "/settings/appearance", Some(&andy), &format!("_csrf={csrf}&theme=purple")).await.status, StatusCode::BAD_REQUEST); |
|
| 440 | 440 | assert_eq!(post(app, "/settings/appearance", Some(&andy), "_csrf=nope&theme=light").await.status, StatusCode::BAD_REQUEST); |
|
| 441 | 441 | } |
|
| … | 390 unchanged lines |
modified docs/spec.md +1 −1
| … | 208 unchanged lines |
||
| 209 | 209 | ||
| 210 | 210 | ### 6.1 Theme |
|
| 211 | 211 | ||
| 212 | - | The default look (since 2026-10-01, oxygenhub#74) is close to GitHub's, chosen for readability and familiarity: Primer colours in light and dark, the system font stack at 14px, rounded boxes with divided rows, the site band and repository tabs as underline navigation, grey buttons with green primary actions, sentence case throughout, and pill labels. It is `assets/github.css`, loaded over the stylesheet below with every rule scoped to `:root[data-look="github"]`, which the page sets unless the browser chose the classic look with `?look=classic` (a cookie keeps the choice; `?look=github` returns to the default). The Oxygen mark stays the logo, with the wordmark OxygenHub. |
|
| 212 | + | The default look (since 2026-10-01, oxygenhub#74) is close to GitHub's, chosen for readability and familiarity: Primer colours, light by default (a `theme` cookie of `dark` or `auto` changes it), the system font stack at 14px, rounded boxes with divided rows, the site band and repository tabs as underline navigation, grey buttons with green primary actions, sentence case throughout, and pill labels. It is `assets/github.css`, loaded over the stylesheet below with every rule scoped to `:root[data-look="github"]`, which the page sets unless the browser chose the classic look with `?look=classic` (a cookie keeps the choice; `?look=github` returns to the default). The Oxygen mark stays the logo, with the wordmark OxygenHub. |
|
| 213 | 213 | ||
| 214 | 214 | The classic look follows the RetroPlay Network's shape (dark by default, `Barlow` for text and `Press Start 2P` for the wordmark and first columns, square corners, thin `--line` rules, a `--panel` header and footer, a full-width `--band` navigation bar with the active tab underlined in `--acc`) with the palette taken from the Oxygen mark shared with the VS Code extension: the mark's cyan `#00F0FF` to blue `#0072FF` gradient on `#070c18`, so `--acc` is cyan, `--acc-2` blue, and the band a deep blue. The mark itself is the logo in the header, the footer and the favicon; the wordmark beside it reads OXYGEN**HUB**. The stylesheet starts from `retroplay-manager/templates/style.css` lines 1–171 (tokens, shell, band, tabs, main, tables, forms, footer) and adds forge components; the store, showcase and game components are not carried over. |
|
| 215 | 215 | ||
| … | 445 unchanged lines |
modified templates/base.html +1 −1
| … | 7 unchanged lines |
||
| 8 | 8 | <link rel="icon" href="/favicon.svg" type="image/svg+xml"> |
|
| 9 | 9 | <link rel="stylesheet" href="/static/github.css"> |
|
| 10 | 10 | <script>/* The look (oxygenhub#74): GitHub-like by default (assets/github.css, every rule scoped to data-look="github"); ?look=classic keeps the RetroPlay look for this browser, ?look=github returns to the default. */(function(){var q=new URLSearchParams(location.search).get("look");if(q==="classic")document.cookie="look=classic; path=/; max-age=31536000; SameSite=Lax";else if(q==="github"||q==="default")document.cookie="look=; path=/; max-age=0; SameSite=Lax";if(!/(?:^|; )look=classic/.test(document.cookie))document.documentElement.dataset.look="github";})();</script> |
|
| 11 | - | <script>/* Theme before first paint: the theme cookie (dark, light or auto; dark when unset), auto following the system. */(function(){var d=document.documentElement,m=document.cookie.match(/(?:^|; )theme=(light|dark|auto)/),p=m?m[1]:"dark",q=window.matchMedia&&matchMedia("(prefers-color-scheme: light)");function a(){d.dataset.theme=p==="auto"?(q&&q.matches?"light":"dark"):p;}d.dataset.themePref=p;a();if(q&&q.addEventListener)q.addEventListener("change",function(){if(d.dataset.themePref==="auto")d.dataset.theme=q.matches?"light":"dark";});})();</script> |
|
| 11 | + | <script>/* Theme before first paint: the theme cookie (light, dark or auto; light when unset), auto following the system. */(function(){var d=document.documentElement,m=document.cookie.match(/(?:^|; )theme=(light|dark|auto)/),p=m?m[1]:"light",q=window.matchMedia&&matchMedia("(prefers-color-scheme: light)");function a(){d.dataset.theme=p==="auto"?(q&&q.matches?"light":"dark"):p;}d.dataset.themePref=p;a();if(q&&q.addEventListener)q.addEventListener("change",function(){if(d.dataset.themePref==="auto")d.dataset.theme=q.matches?"light":"dark";});})();</script> |
|
| 12 | 12 | </head> |
|
| 13 | 13 | <body{% block bodyattrs %}{% endblock %}> |
|
| 14 | 14 | <a class="skip" href="#main">Skip to content</a> |
|
| … | 49 unchanged lines |