feat(theme): add dark mode#649
Conversation
eb79028 to
0d07496
Compare
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://lemon-wave-085522403-649.westeurope.1.azurestaticapps.net |
1 similar comment
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://lemon-wave-085522403-649.westeurope.1.azurestaticapps.net |
There was a problem hiding this comment.
Pull request overview
This PR introduces a site-wide dark/light/auto theme toggle (persisted via localStorage) and updates templates + styles to support Bootstrap color modes across most pages, including dark-mode syntax highlighting.
Changes:
- Adds theme-mode plumbing (inline head script + switcher bundle + navbar dropdown) and wires it into key layouts.
- Introduces a dark palette via Bootstrap dark-variable overrides and replaces many hard-coded light colors with CSS variables.
- Adds a dark Chroma syntax theme and updates blog/docs/release/404 styling for dark mode.
Reviewed changes
Copilot reviewed 42 out of 42 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| themes/flatcar/layouts/taxonomy/tag.html | Adds theme-mode + hero layout |
| themes/flatcar/layouts/section/releases.html | Removes white box-shadow hacks |
| themes/flatcar/layouts/section/blog.html | Refactors blog list template + theme-mode |
| themes/flatcar/layouts/partials/theme-mode.html | New partial: head/body theme-mode emits |
| themes/flatcar/layouts/partials/navbar.html | Adds theme selector dropdown |
| themes/flatcar/layouts/partials/hero.html | Adjusts hero description fallback logic |
| themes/flatcar/layouts/partials/head.html | Removes html/head/body wrappers; adds view-transition CSS |
| themes/flatcar/layouts/partials/footer.html | Switches to fingerprinted common.js asset |
| themes/flatcar/layouts/partials/article.html | Blog article layout updates for new hero usage |
| themes/flatcar/layouts/partials/announcement_banner.html | Moves banner bg to CSS variable + class |
| themes/flatcar/layouts/docs/docsportal_home.html | Adds theme-mode + html/head/body structure |
| themes/flatcar/layouts/docs/baseof.html | Adds theme-mode + docs body class |
| themes/flatcar/layouts/careers/single.html | Adds theme-mode + html/head/body structure |
| themes/flatcar/layouts/blog/single.html | Adds hero + authors header above article |
| themes/flatcar/layouts/blog/baseof.html | New blog base template with theme-mode |
| themes/flatcar/layouts/404.html | Refactors markup + theme-mode includes |
| themes/flatcar/layouts/_default/baseof.html | Adds theme-mode + home-page forced light attributes |
| themes/flatcar/assets/scss/sections/section-related-post.scss | Converts colors to Bootstrap CSS vars |
| themes/flatcar/assets/scss/sections/section-product.scss | Dark-mode variable-based styling, releases accent |
| themes/flatcar/assets/scss/sections/section-docs.scss | Docs theming + layout alignment tweaks |
| themes/flatcar/assets/scss/sections/section-contact-us.scss | Converts colors to Bootstrap CSS vars |
| themes/flatcar/assets/scss/search.scss | Makes search UI color-mode compatible |
| themes/flatcar/assets/scss/partials/navbar.scss | Adds theme-switcher styles + dropdown selector change |
| themes/flatcar/assets/scss/partials/hero.scss | Dark-mode hero border + z-index adjustments |
| themes/flatcar/assets/scss/partials/header.scss | Dark-mode scrolled header background |
| themes/flatcar/assets/scss/partials/grid-statements.scss | Converts card/surface colors to CSS vars |
| themes/flatcar/assets/scss/partials/footer.scss | Dark-mode footer/link colors |
| themes/flatcar/assets/scss/pages/blog-page.scss | Blog hero overlap + dark-friendly surfaces |
| themes/flatcar/assets/scss/pages/article.scss | Link/selection/related area dark-friendly updates |
| themes/flatcar/assets/scss/main.scss | Imports dark syntax stylesheet |
| themes/flatcar/assets/scss/layouts.scss | Dark-friendly muted text + 404 styling remains |
| themes/flatcar/assets/scss/buttons.scss | Makes .btn-black invert in dark mode |
| themes/flatcar/assets/scss/_syntax.scss | Updates comments to reflect new dark syntax |
| themes/flatcar/assets/scss/_syntax-dark.scss.parked | Removes parked dark syntax file |
| themes/flatcar/assets/scss/_syntax-dark.scss | Adds scoped dark Chroma theme |
| themes/flatcar/assets/scss/_styles.scss | Adds Flatcar CSS custom properties + dark pagination vars |
| themes/flatcar/assets/scss/_custom.scss | Adds Bootstrap dark-mode Sass variable overrides |
| themes/flatcar/assets/js/theme-switcher.js | New JS: persisted theme switching + a11y focus handling |
| themes/flatcar/assets/js/common.js | Updates mobile dropdown handling + code copy fix |
| static/js/common.js | Removes unused static common.js |
| content/blog/_index.md | Adds blog section front matter for hero config |
| config.yaml | Updates syntax theme docs + changes Docs menu URL |
Comments suppressed due to low confidence (1)
themes/flatcar/assets/scss/partials/navbar.scss:111
- The desktop hover/focus dropdown rule now relies on the
:has()selector (.nav-item.dropdown:not(:has(.theme-switcher__toggle))). In browsers that don't support:has(), this entire rule will be ignored, potentially breaking hover-to-open behavior for all dropdowns. Prefer excluding the theme switcher via an explicit class on the - (e.g.
theme-switcher) and use.nav-item.dropdown:not(.theme-switcher)instead.
.nav-item.dropdown:not(:has(.theme-switcher__toggle)) {
&:hover,&.focus {
@include media-breakpoint-up(md) {
> .dropdown-menu {
display: block;
}
}
}
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <head> | ||
| {{- partial "head.html" . -}} {{ partial "theme-mode.html" (dict "part" | ||
| "head" "page" .) }} | ||
| </head> |
There was a problem hiding this comment.
Addressed by centralizing the theme-init call in head.html before all stylesheet links. On themeable pages, data-bs-theme is now set before CSS loads; the home page remains explicitly forced to light mode.
| - name: Docs | ||
| url: /docs | ||
| url: /docs/latest | ||
| identifier: docs |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 42 out of 42 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (3)
themes/flatcar/layouts/partials/head.html:9
- The dark/light FOUC-prevention script is currently emitted by callers after this partial, but this partial already outputs multiple tags (Google Fonts, Bootstrap, main.scss). That means the inline theme script runs too late to prevent a flash of the wrong theme.
A robust fix is to emit the theme-mode "head" part from inside head.html before any stylesheet links (and then remove the per-template theme-mode "head" calls to avoid duplication).
config.yaml:103
- This PR is scoped to adding dark mode/theme toggling, but it also changes the main menu Docs URL from
/docsto/docs/latest. That’s a user-facing navigation change unrelated to theming and should either be justified in the PR description or reverted to keep scope focused.
identifier: releases
weight: -400
- name: Docs
url: /docs/latest
identifier: docs
weight: -200
themes/flatcar/layouts/404.html:12
- The 404 template no longer renders the
/images/404.svgillustration that was previously shown. The PR description mentions adding dark styles for the 404 page, but not removing the illustration; if this removal is intentional, it should be called out explicitly since it changes the 404 page content/layout.
<main class="main notfound row">
<div class="mx-auto my-auto content">
<h1>Whoops! Something's missing!</h1>
<h2>Not to worry, head back <a href="/">home</a>!</h2>
</div>
| var ICONS = { auto: "auto-icon", light: "sun-icon", dark: "moon-icon" }; | ||
|
|
||
| function stored() { | ||
| try { | ||
| return localStorage.getItem(KEY) || AUTO; | ||
| } catch (e) { | ||
| return AUTO; | ||
| } | ||
| } |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 42 out of 42 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (2)
themes/flatcar/layouts/partials/head.html:112
- The reduced-motion media query is invalid without a value, so the View Transition animations won’t be disabled for users who prefer reduced motion. Use the standard syntax
prefers-reduced-motion: reduce.
themes/flatcar/layouts/404.html:11 - The 404 page removed the previous illustration (404.svg). This is a visible content change not mentioned in the PR description; if it’s intentional, it should be called out in the PR, otherwise consider restoring the image (possibly with a dark-mode friendly asset).
<main class="main notfound row">
<div class="mx-auto my-auto content">
<h1>Whoops! Something's missing!</h1>
<h2>Not to worry, head back <a href="/">home</a>!</h2>
</div>
| } | ||
|
|
||
| .nav-item.dropdown { | ||
| .nav-item.dropdown:not(:has(.theme-switcher__toggle)) { |
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://lemon-wave-085522403-649.westeurope.1.azurestaticapps.net |
adds a dark/light toggle that remembers your choice, plus dark styles for most of the site. - theme switcher js + partial, wired into head/baseof - dark scss palette + dark syntax highlighting - dark styles for navbar, footer, search, blog, docs, product, careers, releases and 404 - a11y: focus/selected colors, contrast, mobile toggle focus - dropped an unused static/js/common.js and fixed a dropdown null check Signed-off-by: Ervin Rácz <ervin.racz@protonmail.com>
- move the theme script into head.html before the stylesheets so the right theme paints first, and drop the duplicate call from each layout head - set $link-color so body links aren't black in light mode, and remove the global a:hover override so the per-theme hover colors apply - use the theme link color for the docs toc and code-copy hover, which were low-contrast on the dark code background - add accessible light syntax-token variants that clear wcag aa - give navbar controls a visible focus ring in both themes - keep product cta text readable on hover - honor prefers-reduced-motion - drop an unused variable Signed-off-by: Ervin Rácz <ervin.racz@protonmail.com>
- releases: use --flatcar-accent for badge/hover/version colours so they meet contrast on the dark cards - search: dark-mode highlight now uses near-solid brand yellow with dark text instead of low-contrast translucent yellow - theme init: ignore invalid stored modes and keep following the system theme on pages without a switcher (e.g. 404) - reduced-motion: also cap animation iterations - switcher: options are radio buttons (role=menuitemradio, aria-checked), the toggle announces the active theme, and selection is delegated so extra switcher instances stay in sync - restore the "Posts Tagged #<tag>" heading on tag pages Signed-off-by: Ervin Rácz <ervin.racz@protonmail.com>
e0e001c to
6493df3
Compare
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://lemon-wave-085522403-649.westeurope.1.azurestaticapps.net |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 42 out of 42 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
themes/flatcar/layouts/partials/head.html:116
- The media query
@media (prefers-reduced-motion)is not a valid prefers-reduced-motion query in CSS; it should specify a value (e.g.reduce). As written, the rule will be ignored so view-transition animations won’t be disabled for reduced-motion users.
| var menu = (toggle.closest(".dropdown") || document).querySelector( | ||
| ".theme-switcher__menu", | ||
| ); | ||
| if (!menu) return; |
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://lemon-wave-085522403-649.westeurope.1.azurestaticapps.net |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 42 out of 42 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
themes/flatcar/layouts/partials/head.html:116
- The prefers-reduced-motion media query is invalid as written (
@media (prefers-reduced-motion)); it won’t match and the View Transition animations won’t be disabled for users who request reduced motion. Use the correct feature syntaxprefers-reduced-motion: reduce.
themes/flatcar/assets/js/theme-switcher.js:113 - There is an unnecessary trailing comma in the
querySelector()call argument list. Trailing commas in function calls can break parsing in older JS engines and aren’t needed here.
var menu = (toggle.closest(".dropdown") || document).querySelector(
".theme-switcher__menu",
);
Found during the dark-mode review; not part of the theme feature itself: - .navbar-toggler had `outline: none !important`, leaving the mobile menu button with no keyboard focus indicator; add a :focus-visible ring - pagination active/hover was white on cyan (3.09:1); use navy text (5.75:1) - docs body links (.td-content a) were cyan on white (3.09:1); use the theme link colour (5.85:1 light / 5.75:1 dark), consistent with site links Signed-off-by: Ervin Rácz <ervin.racz@protonmail.com>
4babd51 to
7e6b7a7
Compare
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://lemon-wave-085522403-649.westeurope.1.azurestaticapps.net |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 42 out of 42 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (2)
themes/flatcar/layouts/partials/head.html:112
- The media query uses an invalid prefers-reduced-motion syntax.
prefers-reduced-motionrequires a value (e.g.reduce), otherwise the rule won’t match and view-transition animations won’t be disabled for users who request reduced motion.
config.yaml:102 - The main menu Docs link was changed from
/docsto/docs/latest, which is unrelated to the dark-mode work described in the PR description. If this navigation change is intentional, it should be called out explicitly in the PR description (or moved to a separate PR) to avoid surprising reviewers/users.
identifier: releases
weight: -400
- name: Docs
url: /docs/latest
identifier: docs
| window | ||
| .matchMedia("(prefers-color-scheme: dark)") | ||
| .addEventListener("change", function () { | ||
| if (stored() === AUTO) updateUI(AUTO); | ||
| }); |
- Replace `addEventListener` with fallback to `addListener` for older browsers - Add `e.preventDefault()` to prevent default link behavior - Fix `prefers-reduced-motion` media query syntax - Update CSS selector for theme-switcher dropdown - Remove unused image max-width style Signed-off-by: Ervin Rácz <ervin.racz@protonmail.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://lemon-wave-085522403-649.westeurope.1.azurestaticapps.net |
| {{ if and (eq .Kind "term") (eq .Data.Singular "tag") }} | ||
| {{ $title = printf "Posts Tagged #%s" $title }} | ||
| {{ end }} | ||
| {{ $description := index $hero "description" }} | ||
| {{ if eq $description nil }} |
| if (t && window.bootstrap) { | ||
| var d = bootstrap.Dropdown.getInstance(t); | ||
| if (d) d.hide(); | ||
| } |
- Revert docs URL from /docs/latest to /docs Signed-off-by: Ervin Rácz <ervin.racz@protonmail.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://lemon-wave-085522403-649.westeurope.1.azurestaticapps.net |
|
|
||
| {{ if eq .part "head" }} | ||
| {{ if not .page.IsHome }} | ||
| <script>(function(){var m="auto";try{var s=localStorage.getItem("theme-mode");if(s==="light"||s==="dark")m=s}catch(e){}var t=m==="auto"?window.matchMedia("(prefers-color-scheme:dark)").matches?"dark":"light":m;document.documentElement.setAttribute("data-bs-theme",t)})()</script> |
| <div class="dropdown-menu dropdown-menu-end theme-switcher__menu" role="menu" aria-label="Theme"> | ||
| {{- range $themes }} | ||
| <button type="button" class="dropdown-item theme-switcher__option" role="menuitemradio" aria-checked="false" data-theme-mode="{{ .mode }}"> |
- Guard hero configuration with `with` block to prevent nil pointer errors - Simplify theme dropdown hide logic using `getOrCreateInstance` - Preserve existing inheritance behavior for hero section parameters Signed-off-by: Ervin Rácz <ervin.racz@protonmail.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://lemon-wave-085522403-649.westeurope.1.azurestaticapps.net |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 42 out of 42 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
themes/flatcar/layouts/docs/docsportal_home.html:86
- After closing the header
.container.main-containernear the top of the section, the</div>immediately before</section>becomes an extra unmatched closing tag. Remove it to keep the<div>nesting balanced.
| {{ $homeParams := .Params }} | ||
| <div class="container"> | ||
| <div class="row"> |
- Replace `aria-checked` with `aria-pressed` for theme toggle buttons - Add `role="button"` to theme switcher toggle link - Remove redundant `role="menu"` and `role="menuitemradio` attributes - Improve semantic HTML for dropdown menu structure Signed-off-by: Ervin Rácz <ervin.racz@protonmail.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://lemon-wave-085522403-649.westeurope.1.azurestaticapps.net |
adds a dark/light toggle that remembers your choice, plus dark styles for most of the site.
[Title: describe the change in one sentence]
[ describe the change in 1 - 3 paragraphs ]
How to use
[ describe what reviewers need to do in order to validate this PR ]
Testing done
[Describe the testing you have done before submitting this PR. Please include both the commands you issued as well as the output you got.]
changelog/directory (user-facing change, bug fix, security fix, update)/bootand/usrsize, packages, list files for any missing binaries, kernel modules, config files, kernel modules, etc.