Skip to content

Commit e3eea2f

Browse files
committed
fit in ThemeInit.astro to set initial theme/body-unhide logic to now runs immediately if the DOM is already ready, instead of depending solely on DOMContentLoaded
1 parent 21a45a7 commit e3eea2f

3 files changed

Lines changed: 130 additions & 115 deletions

File tree

axe-results-incomplete.json

Lines changed: 1 addition & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1 @@
1-
[
2-
{
3-
"id": "identical-links-same-purpose",
4-
"impact": "minor",
5-
"tags": [
6-
"cat.semantics",
7-
"wcag2aaa",
8-
"wcag249"
9-
],
10-
"description": "Ensure that links with the same accessible name serve a similar purpose",
11-
"help": "Links with the same name must have a similar purpose",
12-
"helpUrl": "https://dequeuniversity.com/rules/axe/4.11/identical-links-same-purpose?application=playwright",
13-
"nodes": [
14-
{
15-
"any": [],
16-
"all": [
17-
{
18-
"id": "identical-links-same-purpose",
19-
"data": {
20-
"name": "contact",
21-
"urlProps": {
22-
"protocol": "http:",
23-
"hostname": "localhost",
24-
"port": "4321",
25-
"pathname": "/contact/",
26-
"search": {},
27-
"hash": "",
28-
"filename": ""
29-
}
30-
},
31-
"relatedNodes": [
32-
{
33-
"html": "<a href=\"#privacy-contact-us-title\" class=\"text-content-inverse hover:text-content-offset transition-colors no-underline\"> Contact </a>",
34-
"target": [
35-
".hover\\:text-content-offset.transition-colors[href$=\"#privacy-contact-us-title\"]"
36-
]
37-
}
38-
],
39-
"impact": "minor",
40-
"message": "Check that links have the same purpose, or are intentionally ambiguous."
41-
}
42-
],
43-
"none": [],
44-
"impact": "minor",
45-
"html": "<a href=\"/contact\" class=\"_mainNavLink_14gez_5...\">",
46-
"target": [
47-
"._mainNavLink_14gez_54.tracking-\\[5px\\][href$=\"contact\"]"
48-
],
49-
"failureSummary": "Fix all of the following:\n Check that links have the same purpose, or are intentionally ambiguous."
50-
}
51-
]
52-
}
53-
]
1+
[]

axe-results-violations.json

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,66 @@
1-
[]
1+
[
2+
{
3+
"id": "landmark-one-main",
4+
"impact": "moderate",
5+
"tags": [
6+
"cat.semantics",
7+
"best-practice"
8+
],
9+
"description": "Ensure the document has a main landmark",
10+
"help": "Document should have one main landmark",
11+
"helpUrl": "https://dequeuniversity.com/rules/axe/4.11/landmark-one-main?application=playwright",
12+
"nodes": [
13+
{
14+
"any": [],
15+
"all": [
16+
{
17+
"id": "page-has-main",
18+
"data": null,
19+
"relatedNodes": [],
20+
"impact": "moderate",
21+
"message": "Document does not have a main landmark"
22+
}
23+
],
24+
"none": [],
25+
"impact": "moderate",
26+
"html": "<html lang=\"en\" data-theme=\"light\">",
27+
"target": [
28+
"html"
29+
],
30+
"failureSummary": "Fix all of the following:\n Document does not have a main landmark"
31+
}
32+
]
33+
},
34+
{
35+
"id": "page-has-heading-one",
36+
"impact": "moderate",
37+
"tags": [
38+
"cat.semantics",
39+
"best-practice"
40+
],
41+
"description": "Ensure that the page, or at least one of its frames contains a level-one heading",
42+
"help": "Page should contain a level-one heading",
43+
"helpUrl": "https://dequeuniversity.com/rules/axe/4.11/page-has-heading-one?application=playwright",
44+
"nodes": [
45+
{
46+
"any": [],
47+
"all": [
48+
{
49+
"id": "page-has-heading-one",
50+
"data": null,
51+
"relatedNodes": [],
52+
"impact": "moderate",
53+
"message": "Page must have a level-one heading"
54+
}
55+
],
56+
"none": [],
57+
"impact": "moderate",
58+
"html": "<html lang=\"en\" data-theme=\"light\">",
59+
"target": [
60+
"html"
61+
],
62+
"failureSummary": "Fix all of the following:\n Page must have a level-one heading"
63+
}
64+
]
65+
}
66+
]

src/components/Head/ThemeInit.astro

Lines changed: 63 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -26,74 +26,76 @@ const { defaultThemeIdJson, darkThemeIdJson, metaColorsJson } = themeData()
2626
}}
2727
>
2828
// @ts-nocheck
29-
document.addEventListener(
30-
'DOMContentLoaded',
31-
() => {
32-
/**
33-
* This code is only for initial page load from the site. DOMContentLoaded does
34-
* not fire when using the Astro View Transitions API for page navigation, so
35-
* the themes store defines a side effect to set up an event listener for the
36-
* "astro:before-swap" event.
37-
*/
38-
try {
39-
const defaultThemeId = JSON.parse(defaultThemeIdJson)
40-
const darkThemeId = JSON.parse(darkThemeIdJson)
41-
const themeMetaColors = JSON.parse(metaColorsJson)
29+
const runThemeInit = () => {
30+
/**
31+
* This code is only for initial page load from the site. DOMContentLoaded does
32+
* not fire when using the Astro View Transitions API for page navigation, so
33+
* the themes store defines a side effect to set up an event listener for the
34+
* "astro:before-swap" event.
35+
*/
36+
try {
37+
const defaultThemeId = JSON.parse(defaultThemeIdJson)
38+
const darkThemeId = JSON.parse(darkThemeIdJson)
39+
const themeMetaColors = JSON.parse(metaColorsJson)
40+
41+
/** 1. Read theme preference from localStorage (set by user's previous selection) */
42+
const stored = localStorage.getItem('theme')
4243

43-
/** 1. Read theme preference from localStorage (set by user's previous selection) */
44-
const stored = localStorage.getItem('theme')
44+
if (stored && stored !== defaultThemeId) {
45+
/** User explicitly chose a theme - apply it immediately */
46+
/** <html> element */
47+
document.documentElement.dataset['theme'] = stored
48+
} else if (!stored) {
49+
/** No stored preference - use system preference */
50+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
51+
/** <html> element */
52+
document.documentElement.dataset['theme'] = prefersDark ? darkThemeId : defaultThemeId
53+
}
4554

46-
if (stored && stored !== defaultThemeId) {
47-
/** User explicitly chose a theme - apply it immediately */
48-
/** <html> element */
49-
document.documentElement.dataset['theme'] = stored
50-
} else if (!stored) {
51-
/** No stored preference - use system preference */
52-
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
53-
/** <html> element */
54-
document.documentElement.dataset['theme'] = prefersDark ? darkThemeId : defaultThemeId
55-
}
55+
/** 2. Turn <body> visible. It's set to hidden in BaseLayout.astro to avoid FOUC. Do
56+
* here to make sure it gets turned on, in case the <meta> element selector throws.
57+
*/
58+
document.body.classList.remove('invisible')
5659

57-
/** 2. Turn <body> visible. It's set to hidden in BaseLayout.astro to avoid FOUC. Do
58-
* here to make sure it gets turned on, in case the <meta> element selector throws.
59-
*/
60-
document.body.classList.remove('invisible')
60+
/** 3. Add theme entries from src/content/themes.json to the window.metaColors object */
61+
window.metaColors = window.metaColors || {}
62+
Object.assign(window.metaColors, themeMetaColors)
6163

62-
/** 3. Add theme entries from src/content/themes.json to the window.metaColors object */
63-
window.metaColors = window.metaColors || {}
64-
Object.assign(window.metaColors, themeMetaColors)
64+
/** 4. Update meta theme-color used for PWAs */
65+
const metaElement = document.querySelector('meta[name="theme-color"]')
66+
if (stored && stored !== defaultThemeId && metaElement && window.metaColors) {
67+
/** User explicitly chose a theme - apply it immediately */
68+
metaElement.setAttribute('content', window.metaColors[stored] || '')
69+
} else if (!stored && metaElement && window.metaColors) {
70+
/** No stored preference - use system preference */
71+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
72+
metaElement.setAttribute(
73+
'content',
74+
window.metaColors[prefersDark ? darkThemeId : defaultThemeId] || ''
75+
)
76+
}
6577

66-
/** 4. Update meta theme-color used for PWAs */
67-
const metaElement = document.querySelector('meta[name="theme-color"]')
68-
if (stored && stored !== defaultThemeId && metaElement && window.metaColors) {
69-
/** User explicitly chose a theme - apply it immediately */
70-
metaElement.setAttribute('content', window.metaColors[stored] || '')
71-
} else if (!stored && metaElement && window.metaColors) {
72-
/** No stored preference - use system preference */
73-
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
74-
metaElement.setAttribute(
75-
'content',
76-
window.metaColors[prefersDark ? darkThemeId : defaultThemeId] || ''
77-
)
78-
}
78+
/**
79+
* 5. If stored === defaultThemeId, BaseLayout.astro already set it
80+
* on <html> data-theme attribute and Meta.astro already set it on
81+
* <meta name="theme-color">, so nothing to do
82+
*/
7983

80-
/**
81-
* 5. If stored === defaultThemeId, BaseLayout.astro already set it
82-
* on <html> data-theme attribute and Meta.astro already set it on
83-
* <meta name="theme-color">, so nothing to do
84-
*/
84+
/** 6. Success! */
85+
console.log('🎨 Theme init on initial load executed')
86+
} catch (error) {
87+
/** localStorage access can fail (privacy mode, etc.) */
88+
/** Fall back to BaseLayout's data-theme="light", make sure the page is visible */
89+
document.body.classList.remove('invisible')
90+
console.error('❌ Theme init on initial load failed with errors:', error)
91+
}
92+
}
8593

86-
/** 6. Success! */
87-
console.log('🎨 Theme init on "DOMContentLoaded" executed')
88-
} catch (error) {
89-
/** localStorage access can fail (privacy mode, etc.) */
90-
/** Fall back to BaseLayout's data-theme="light", make sure the page is visible */
91-
document.body.classList.remove('invisible')
92-
console.error('❌ Theme init on "DOMContentLoaded" failed with errors:', error)
93-
}
94-
},
95-
{ once: true }
96-
)
94+
if (document.readyState === 'loading') {
95+
document.addEventListener('DOMContentLoaded', runThemeInit, { once: true })
96+
} else {
97+
runThemeInit()
98+
}
9799

98100
/**
99101
* Add the fast theme setting logic for Astro View Transition API navigation events.

0 commit comments

Comments
 (0)