mirror of
https://github.com/docker/docs.git
synced 2026-04-03 17:59:01 +07:00
> 🤖 Generated with [Claude Code](https://claude.com/claude-code) ## Summary `theme.js` unconditionally wrote the resolved preference to `localStorage` on every page load, permanently locking in a concrete `"light"` or `"dark"` value even for first-time visitors — making it impossible to track OS preference changes after any site visit. Removed the unconditional `localStorage.setItem` from `theme.js` so the early script only reads (never writes); the Alpine.js toggle in `header.html` now cycles through three states (light → dark → auto), with "auto" removing the `theme-preference` key and resolving from `prefers-color-scheme` with a live `matchMedia` change listener so the theme updates immediately when the OS preference changes. A contrast icon indicates auto mode; all three icon spans are driven by Alpine `x-show` directives rather than pure CSS dark-mode classes. **Verified:** logic matches the standard three-state pattern; `prefers-color-scheme` media query and `matchMedia` change listener are the canonical browser APIs for system-preference tracking. **Checked:** no other files reference `theme-preference` or the theme toggle; no CSS changes required. Closes #23177 --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
118 lines
4.7 KiB
HTML
118 lines
4.7 KiB
HTML
<header class="sticky top-0 z-20 h-16 w-full bg-blue-600 text-white">
|
|
<div class="mx-auto flex h-full justify-between gap-2 px-4">
|
|
<div class="flex h-full items-center gap-2 lg:gap-8">
|
|
{{- if not .IsHome }}
|
|
<button
|
|
x-data
|
|
@click="$store.showSidebar = true"
|
|
class="icon-svg block h-full px-4 md:hidden"
|
|
aria-label="Menu"
|
|
>
|
|
{{ partialCached "icon" "menu" "menu" }}
|
|
</button>
|
|
{{- end }}
|
|
<div>
|
|
{{/* main logo */}}
|
|
<a title="Docker Docs home page" href="{{ site.BaseURL }}">
|
|
<div class="hidden sm:block">
|
|
{{- (resources.Get "images/docker-docs-white.svg").Content | safe.HTML -}}
|
|
</div>
|
|
<div class="block sm:hidden">
|
|
{{- (resources.Get "images/docker-docs-white-condensed.svg").Content | safe.HTML -}}
|
|
</div>
|
|
</a>
|
|
</div>
|
|
<nav class="mt-1 hidden md:flex lg:flex xl:flex 2xl:flex">
|
|
{{/* main menu */}}
|
|
<ul class="flex text-sm md:text-base lg:gap-4">
|
|
{{ range site.Menus.main }}
|
|
<li
|
|
{{- if or (eq page.Permalink .Page.Permalink) (page.IsDescendant .Page) }}
|
|
class="border-b-4"
|
|
{{- else }}
|
|
class="border-b-4 border-transparent hover:border-white/20"
|
|
{{- end }}
|
|
>
|
|
<a class="block px-2 py-1 whitespace-nowrap" href="{{ .URL }}"
|
|
>{{ .Name }}</a
|
|
>
|
|
</li>
|
|
{{ end }}
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
<div
|
|
id="buttons"
|
|
class="flex min-w-0 flex-shrink-0 items-center justify-end"
|
|
>
|
|
<div class="flex items-center gap-2">
|
|
<div data-tooltip-wrapper class="relative">
|
|
<button
|
|
x-data
|
|
@click="$store.gordon.toggle()"
|
|
aria-label="Ask Gordon, AI assistant"
|
|
aria-describedby="gordon-tooltip"
|
|
class="shimmer open-kapa-widget flex cursor-pointer items-center gap-2 rounded-lg border border-blue-500 bg-blue-700 p-2 text-white transition-colors focus:ring focus:ring-blue-400 focus:outline-none"
|
|
>
|
|
<span class="icon-svg">
|
|
{{ partial "utils/svg.html" "/icons/sparkle.svg" }}
|
|
</span>
|
|
<span class="hidden px-1 lg:inline">Gordon</span>
|
|
</button>
|
|
<div
|
|
id="gordon-tooltip"
|
|
data-tooltip-body
|
|
class="absolute top-0 left-0 hidden rounded-sm bg-gray-900 p-2 text-sm whitespace-nowrap text-white"
|
|
role="tooltip"
|
|
>
|
|
Ask Gordon — AI assistant for Docker docs
|
|
<div
|
|
data-tooltip-arrow
|
|
class="absolute h-2 w-2 rotate-45 bg-gray-900"
|
|
></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="search-bar-container">
|
|
{{ partialCached "search-bar.html" "-" }}
|
|
</div>
|
|
|
|
<button
|
|
aria-label="Theme switch"
|
|
id="theme-switch"
|
|
class="cursor-pointer rounded-lg border border-blue-500 bg-blue-700 p-2 transition-colors hover:border-blue-400 hover:bg-blue-800 focus:ring focus:ring-blue-400 focus:outline-none"
|
|
x-data="{ theme: localStorage.getItem('theme-preference') || 'auto' }"
|
|
x-init="
|
|
let mql = window.matchMedia('(prefers-color-scheme: dark)');
|
|
function applyTheme(val) {
|
|
if (val === 'auto') {
|
|
localStorage.removeItem('theme-preference');
|
|
document.firstElementChild.className = mql.matches ? 'dark' : 'light';
|
|
} else {
|
|
localStorage.setItem('theme-preference', val);
|
|
document.firstElementChild.className = val;
|
|
}
|
|
document.firstElementChild.dataset.themePreference = val;
|
|
}
|
|
let handler = e => { if (theme === 'auto') document.firstElementChild.className = e.matches ? 'dark' : 'light'; };
|
|
mql.addEventListener('change', handler);
|
|
$watch('theme', val => applyTheme(val));
|
|
return () => mql.removeEventListener('change', handler);
|
|
"
|
|
@click="theme = (theme === 'light' ? 'dark' : theme === 'dark' ? 'auto' : 'light')"
|
|
>
|
|
<span class="theme-icon-sun icon-svg" x-show="theme === 'light'"
|
|
>{{ partialCached "icon" "icons/sun.svg" "sun" }}
|
|
</span>
|
|
<span class="theme-icon-moon icon-svg" x-show="theme === 'dark'">
|
|
{{ partialCached "icon" "icons/moon.svg" "moon" }}
|
|
</span>
|
|
<span class="theme-icon-auto icon-svg" x-show="theme === 'auto'">
|
|
{{ partialCached "icon" "contrast" "contrast" }}
|
|
</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</header>
|