core
core copied to clipboard
feat(theme-default): dynamically change theme-color with dark mode (close #215)
Description
Linked with this feature request issue #215
Note
For better user experience, the browser should get color hex before the page loaded, but it seems vuepress-next is not currently supported duplicated meta tags like this:
['meta', { name: 'theme-color', content: '#3eaf7c', media: '(prefers-color-scheme: light)' }],
['meta', { name: 'theme-color', content: '#22272e', media: '(prefers-color-scheme: dark)' }]
It means the theme-color was changed after the script executes if system side is dark mode by default, because I could not have different color scheme in duplicated meta tags currently, and due to some reason that #3eaf7c seems too bright that Safari will not use it for address bar color if system side is dark mode by default (darker would works).
Also it may not be the best or proper workaround, some further commit may should be added.
We are using following snippet to dedupe <meta> tag:
https://github.com/vuepress/vuepress-next/blob/33c9a2145eeaf53429f2ae784e393074d1a9edd5/packages/%40vuepress/shared/src/utils/resolveHeadIdentifier.ts#L11-L14
But I think that supporting multiple <meta name="theme-color"> tags should be another issue.
We are using following snippet to dedupe
<meta>tag:https://github.com/vuepress/vuepress-next/blob/33c9a2145eeaf53429f2ae784e393074d1a9edd5/packages/%40vuepress/shared/src/utils/resolveHeadIdentifier.ts#L11-L14
But I think that supporting multiple
<meta name="theme-color">tags should be another issue.
https://github.com/vuepress/vuepress-next/blob/b0a9815c9eeaa2ba623cc1a153139e85397d450e/packages/%40vuepress/shared/src/utils/resolveHeadIdentifier.ts#L11-L14
It seems little rude to allow duplicated meta name 'theme-color' in this way, but it simple. Or still avoid duplicated 'theme-color', but keep if they has a different hash.
The problem about site data could be handled in this PR. If you are not familiar with that, I'll update it later.
The problem about site data could be handled in this PR. If you are not familiar with that, I'll update it later.
I'm not familiar with that and now I may not have enough time to learn and handle that correctly during my term examination (maybe later I cloud have a try). You can also update it, thanks!
Another point:
Currently in this PR, we are using --c-bg and --c-brand as the theme color. But users could set different theme color in head config
Another point:
Currently in this PR, we are using
--c-bgand--c-brandas the theme color. But users could set different theme color inheadconfig
Do you think this workaround would be better? The theme-color now entirely depends on the user's configuration.
let themeColorLight: string
let themeColorDark: string
const updateThemeColor = (): void => {
const themeColorEl = window?.document.querySelectorAll('meta[name="theme-color"]')
if (!themeColorEl) return
// get current system appearance mode by `prefers-color-scheme`
const systemAppearanceMode = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
// iterate `theme-color` meta tags
themeColorEl.forEach((meta) => {
// get `media` attribute from this meta tag
const mediaAttr = meta.getAttribute('media')
// initial themeColorLight or themeColorDark if uninitialized by appearance mode
if (!themeColorLight && mediaAttr?.includes('light')) {
themeColorLight = meta.getAttribute('content')!
}
if (!themeColorDark && mediaAttr?.includes('dark')) {
themeColorDark = meta.getAttribute('content')!
}
// if themeColorLight and themeColorDark are initiated, change `content` attribute if the meta `media` attribute matches current system appearance mode
if (themeColorLight && themeColorLight && mediaAttr?.includes(systemAppearanceMode)) {
meta.setAttribute('content', isDark.value ? themeColorDark : themeColorLight)
}
})
}
But according to https://github.com/vuepress/vuepress-next/issues/221#issuecomment-861685833, multiple theme-color is currently non-standard in Safari 15, to support the feature described in the title in this way seems more acceptable:
themeConfig: {
...
themeColorLight: '#xxxxxx',
themeColorDark: '#xxxxxx',
....
}
Or we'd better wait new standard came out, thanks your patient advice : )!
Currently, we could use user config as the light mode theme-color, and use --c-bg as the dark mode theme-color implicitly.
Also, the themeConfig.themeColorLight / themeColorDark could be an alternative.
I've updated this PR with a force push to resolve some conflicts. You could help to check if it works as expected when you have time.
Thanks, it works as expected after fix a logic typo in commit https://github.com/vuepress/vuepress-next/pull/218/commits/5bd549845d8758c668b99d5cedace284aee96468. But has another problem you mentioned before:
There's another problem.
Meta tags set in user config will be injected to client with
useSiteData. So we also have to update the sitedata ref, or the tag will be reset once navigating to another page.
And for better dark mode theme-color user experience, some new standard like multiple theme-color tag would be still needed.
https://user-images.githubusercontent.com/15633984/122413967-5cef0600-cfb9-11eb-9f55-4bad71800d6c.mov
I changed this PR into draft again, may try to finish this later.
Considering that simply changing the meta tag of theme-color in siteData would cause themeColorHeadContent not find the original theme-color after repeatedly switching dark mode, and adding a temporary variable to store the original color would be an inelegant way.
I prefer to do this with a new option in themeConfig, which changes the value of the content of the theme-color meta tag in siteData and current value in <head> via the value of the themeColorLight / themeColorDark options in themeConfig, and a boolean variable called themeColor to control whether or not enable these options.
Tested on my laptop, Safari 15.0:
https://user-images.githubusercontent.com/15633984/124940765-d4eea000-e03c-11eb-94e2-9c0b52b61d8b.mov
Still have a lot to learn before I can write quality code.
@Unbinilium is attempting to deploy a commit to the VuePress Team on Vercel.
A member of the Team first needs to authorize it.
As a reference, this vuepress 1.x plugin might help:
https://github.com/tolking/vuepress-theme-default-prefers-color-scheme