Skip to content

Commit 6eede2d

Browse files
Implement enhanced dark mode synchronization for header theme attributes in VitePress
1 parent b9b7b89 commit 6eede2d

2 files changed

Lines changed: 42 additions & 0 deletions

File tree

docs/.vitepress/config.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,33 @@ const config = defineConfig({
193193
"project management, issue tracking, sprint management, agile, scrum, create projects, track sprints",
194194
},
195195
],
196+
/**
197+
* SSG inlines OSSHeader with data-theme from server isDark. Tailwind `dark:…`
198+
* keys off [data-theme*="dark"] on that wrapper, so the bar can stay dark
199+
* until Vue hydrates. The built-in "check-dark-mode" also only add()s
200+
* html.dark. Run in setTimeout(0) so it executes after that script, then
201+
* clear stale data-theme as soon as the bar exists.
202+
*/
203+
[
204+
"script",
205+
{},
206+
`!function(){setTimeout(function(){
207+
var k="vitepress-theme-appearance";
208+
var p=localStorage.getItem(k)||"dark";
209+
var m=matchMedia("(prefers-color-scheme: dark)").matches;
210+
var d=!p||p==="auto"?m:p==="dark";
211+
document.documentElement.classList.toggle("dark",d);
212+
function bar(n){
213+
var h=document.querySelector(".docs-layout header");
214+
if(h&&h.parentElement){
215+
var w=h.parentElement;
216+
if(d)w.setAttribute("data-theme","dark");else w.removeAttribute("data-theme");
217+
return;
218+
}
219+
if(n<200&&document.readyState==="loading")requestAnimationFrame(function(){bar(n+1)});
220+
}bar(0);
221+
},0);}();`,
222+
],
196223
],
197224

198225
themeConfig: {

docs/.vitepress/theme/index.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,14 +206,29 @@ export default {
206206
* until a theme toggle re-syncs. Keep `documentElement` in lockstep with
207207
* `isDark` (same source of truth as the toggle).
208208
*/
209+
const syncOssHeaderThemeAttr = (dark: boolean) => {
210+
const header = document.querySelector(
211+
".docs-layout header",
212+
) as HTMLElement | null;
213+
const bar = header?.parentElement;
214+
if (!bar) return;
215+
if (dark) bar.setAttribute("data-theme", "dark");
216+
else bar.removeAttribute("data-theme");
217+
};
218+
209219
watch(
210220
isDark,
211221
(dark) => {
212222
document.documentElement.classList.toggle("dark", dark);
223+
syncOssHeaderThemeAttr(dark);
213224
},
214225
{ immediate: true },
215226
);
216227

228+
onMounted(() => {
229+
syncOssHeaderThemeAttr(isDark.value);
230+
});
231+
217232
const zoom = mediumZoom(".vp-doc img", {
218233
background: "rgba(0, 0, 0, 0.8)",
219234
});

0 commit comments

Comments
 (0)