feat(page-controller): enhance dark mode detection
Resolve the @TODO in checkDarkMode.ts by adding 3 new detection strategies and expanding data-attribute coverage: - Check data-color-mode, data-bs-theme, data-color-scheme attributes - Read CSS color-scheme property and <meta name="color-scheme"> tag - Inspect background of SPA containers (#app, #root, #__next, etc.) - Detect light text color as a dark-theme signal
This commit is contained in:
@@ -15,11 +15,14 @@ function hasDarkModeClass() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some sites use data attributes
|
// Some sites use data attributes (data-theme, data-color-mode, data-bs-theme, etc.)
|
||||||
const darkThemeAttribute = htmlElement.getAttribute('data-theme')
|
const dataAttrs = ['data-theme', 'data-color-mode', 'data-bs-theme', 'data-color-scheme']
|
||||||
if (darkThemeAttribute?.toLowerCase().includes('dark')) {
|
for (const attr of dataAttrs) {
|
||||||
|
const value = htmlElement.getAttribute(attr) || bodyElement?.getAttribute(attr)
|
||||||
|
if (value?.toLowerCase().includes('dark')) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -87,6 +90,65 @@ function isBackgroundDark() {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the CSS `color-scheme` property and `<meta name="color-scheme">` tag.
|
||||||
|
* @returns {boolean | null} - True/false if deterministic, null if inconclusive.
|
||||||
|
*/
|
||||||
|
function getColorSchemePreference(): boolean | null {
|
||||||
|
// Check <meta name="color-scheme" content="dark">
|
||||||
|
const meta = document.querySelector<HTMLMetaElement>('meta[name="color-scheme"]')
|
||||||
|
if (meta) {
|
||||||
|
const content = meta.content.toLowerCase()
|
||||||
|
// "dark" or "only dark" → dark; "light dark" is ambiguous so skip
|
||||||
|
if (content === 'dark' || content === 'only dark') return true
|
||||||
|
if (content === 'light' || content === 'only light') return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the computed color-scheme CSS property on :root
|
||||||
|
const rootStyle = window.getComputedStyle(document.documentElement)
|
||||||
|
const colorScheme = rootStyle.getPropertyValue('color-scheme').trim().toLowerCase()
|
||||||
|
if (colorScheme === 'dark' || colorScheme === 'only dark') return true
|
||||||
|
if (colorScheme === 'light' || colorScheme === 'only light') return false
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the text color on the body is light, which implies a dark background.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
function isTextColorLight() {
|
||||||
|
const bodyStyle = window.getComputedStyle(document.body || document.documentElement)
|
||||||
|
const textColor = bodyStyle.color
|
||||||
|
|
||||||
|
const rgb = parseRgbColor(textColor)
|
||||||
|
if (!rgb) return false
|
||||||
|
|
||||||
|
// Light text has high luminance (e.g. white text on dark bg)
|
||||||
|
const luminance = 0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b
|
||||||
|
return luminance > 180
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the background color of major layout elements (<main>, #app, #root, etc.).
|
||||||
|
* Many SPAs render into a container that may have its own dark background while
|
||||||
|
* <body> remains transparent.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
function isMainContentDark() {
|
||||||
|
const selectors = ['main', '#app', '#root', '#__next', '[role="main"]']
|
||||||
|
for (const selector of selectors) {
|
||||||
|
const el = document.querySelector(selector)
|
||||||
|
if (!el) continue
|
||||||
|
|
||||||
|
const style = window.getComputedStyle(el)
|
||||||
|
if (isColorDark(style.backgroundColor)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A comprehensive function to determine if the page is currently in a dark theme.
|
* A comprehensive function to determine if the page is currently in a dark theme.
|
||||||
* It combines class checking and background color analysis.
|
* It combines class checking and background color analysis.
|
||||||
@@ -94,18 +156,31 @@ function isBackgroundDark() {
|
|||||||
*/
|
*/
|
||||||
export function isPageDark() {
|
export function isPageDark() {
|
||||||
try {
|
try {
|
||||||
// Strategy 1: Check for common dark mode classes
|
// Strategy 1: Check for common dark mode classes and data attributes
|
||||||
if (hasDarkModeClass()) {
|
if (hasDarkModeClass()) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strategy 2: Analyze the computed background color
|
// Strategy 2: Check CSS color-scheme property and meta tag
|
||||||
|
const colorScheme = getColorSchemePreference()
|
||||||
|
if (colorScheme !== null) {
|
||||||
|
return colorScheme
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy 3: Analyze the computed background color of <html>/<body>
|
||||||
if (isBackgroundDark()) {
|
if (isBackgroundDark()) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// @TODO add more checks here, e.g., analyzing text color,
|
// Strategy 4: Check background of major layout containers (<main>, #app, etc.)
|
||||||
// or checking the background of major layout elements like <main> or #app.
|
if (isMainContentDark()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy 5: Check if text color is light (implies dark background)
|
||||||
|
if (isTextColorLight()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user