-
Notifications
You must be signed in to change notification settings - Fork 240
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: added theme switcher with match-system option #1273
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
<starlight-theme-select> | ||
<label style='width: 6.25em'> | ||
<span class="sr-only">Выберите тему</span> | ||
<select value="auto" width="6.25em"> | ||
<option value="dark">Темная тема</option> | ||
<option value="light">Светлая тема</option> | ||
<option value="auto">Системная тема</option> | ||
</select> | ||
</label> | ||
</starlight-theme-select> | ||
|
||
|
||
<script> | ||
const storageKey = 'theme'; | ||
|
||
const parseTheme = (theme) => | ||
theme === 'auto' || theme === 'dark' || theme === 'light' ? theme : 'auto'; | ||
|
||
const loadTheme = () => | ||
parseTheme(typeof localStorage !== 'undefined' && localStorage.getItem(storageKey)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Выше уже писал, предлагаю юзать
|
||
|
||
function storeTheme(theme) { | ||
if (typeof localStorage !== 'undefined') { | ||
localStorage.setItem(storageKey, theme === 'light' || theme === 'dark' ? theme : ''); | ||
} | ||
} | ||
Comment on lines
+22
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. зачем это в глобальной видимости? |
||
|
||
const getPreferredColorScheme = () => | ||
matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark'; | ||
|
||
matchMedia(`(prefers-color-scheme: light)`).addEventListener('change', () => { | ||
if (loadTheme() === 'auto') onThemeChange('auto'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}); | ||
|
||
class StarlightThemeProvider { | ||
storedTheme = loadTheme(); | ||
|
||
constructor() { | ||
const theme = this.storedTheme || | ||
(window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark'); | ||
document.documentElement.dataset.theme = theme === 'light' ? 'light' : 'dark'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
|
||
updatePickers(theme = this.storedTheme || 'auto') { | ||
document.querySelectorAll('starlight-theme-select').forEach((picker) => { | ||
console.log('picker', picker); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Надо бы кильнуть, пакер не убирает логи из продакшен-бандла |
||
const select = picker.querySelector('select'); | ||
if (select) select.value = theme; | ||
|
||
/** @type {HTMLTemplateElement | null} */ | ||
const tmpl = document.querySelector(`#theme-icons`); | ||
const newIcon = tmpl && tmpl.content.querySelector('.' + theme); | ||
if (newIcon) { | ||
const oldIcon = picker.querySelector('starlight-theme-select i.label-icon'); | ||
if (oldIcon) { | ||
oldIcon.replaceChildren(...newIcon.cloneNode(true).childNodes); | ||
} | ||
} | ||
Comment on lines
+51
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
}); | ||
} | ||
} | ||
|
||
|
||
class StarlightThemeSelect extends HTMLElement { | ||
themeProvider = new StarlightThemeProvider(); | ||
|
||
constructor() { | ||
super(); | ||
this.onThemeChange(loadTheme()); | ||
this.querySelector('select')?.addEventListener('change', (e) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Зачем тут nullsafe? |
||
if (e.currentTarget instanceof HTMLSelectElement) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. событие |
||
this.onThemeChange(parseTheme(e.currentTarget.value)); | ||
} | ||
}); | ||
|
||
this.themeProvider.updatePickers(loadTheme()); | ||
|
||
matchMedia(`(prefers-color-scheme: light)`).addEventListener('change', () => { | ||
if (loadTheme() === 'auto') this.onThemeChange('auto'); | ||
}); | ||
} | ||
|
||
onThemeChange(theme) { | ||
this.themeProvider.updatePickers(theme); | ||
document.documentElement.setAttribute("theme", theme === 'auto' ? getPreferredColorScheme() : theme); | ||
storeTheme(theme); | ||
} | ||
} | ||
customElements.define('starlight-theme-select', StarlightThemeSelect); | ||
</script> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
<template> | ||
<label style="width: 6.25em"> | ||
<span class="sr-only">Выберите тему</span> | ||
<select value="auto" width="6.25em" @input="setTheme"> | ||
<option value="dark">Темная тема</option> | ||
<option value="light">Светлая тема</option> | ||
<option value="auto">Системная тема</option> | ||
</select> | ||
</label> | ||
</template> | ||
|
||
<script> | ||
const storageKey = "theme"; | ||
|
||
const parseTheme = (theme) => (theme === "auto" || theme === "dark" || theme === "light" ? theme : "auto"); | ||
|
||
const loadTheme = () => parseTheme(typeof localStorage !== "undefined" && localStorage.getItem(storageKey)); | ||
|
||
function storeTheme(theme) { | ||
if (typeof localStorage !== "undefined") { | ||
localStorage.setItem(storageKey, theme === "light" || theme === "dark" ? theme : ""); | ||
} | ||
} | ||
|
||
const getPreferredColorScheme = () => (matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark"); | ||
|
||
matchMedia(`(prefers-color-scheme: light)`).addEventListener("change", () => { | ||
if (loadTheme() === "auto") onThemeChange("auto"); | ||
}); | ||
|
||
// class ThemeProvider { | ||
// storedTheme = loadTheme(); | ||
|
||
// constructor() { | ||
// const theme = | ||
// this.storedTheme || (window.matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark"); | ||
// document.documentElement.dataset.theme = theme === "light" ? "light" : "dark"; | ||
// } | ||
|
||
// updatePickers(theme = this.storedTheme || "auto") { | ||
// document.querySelectorAll("starlight-theme-select").forEach((picker) => { | ||
// console.log("picker", picker); | ||
// const select = picker.querySelector("select"); | ||
// if (select) select.value = theme; | ||
|
||
// /** @type {HTMLTemplateElement | null} */ | ||
// const tmpl = document.querySelector(`#theme-icons`); | ||
// const newIcon = tmpl && tmpl.content.querySelector("." + theme); | ||
// if (newIcon) { | ||
// const oldIcon = picker.querySelector("starlight-theme-select i.label-icon"); | ||
// if (oldIcon) { | ||
// oldIcon.replaceChildren(...newIcon.cloneNode(true).childNodes); | ||
// } | ||
// } | ||
// }); | ||
// } | ||
// } | ||
|
||
// const themeProvider = new ThemeProvider(); | ||
|
||
export default { | ||
name: "PostUpvote", | ||
props: {}, | ||
data() { | ||
const theme = loadTheme(); | ||
onThemeChange(theme); | ||
// themeProvider.updatePickers(theme); | ||
}, | ||
methods: { | ||
setTheme(option) { | ||
if (!option) { | ||
return; | ||
} | ||
|
||
const theme = parseTheme(option.value); | ||
|
||
onThemeChange(theme); | ||
// themeProvider.updatePickers(theme); | ||
document.documentElement.setAttribute("theme", theme === "auto" ? getPreferredColorScheme() : theme); | ||
storeTheme(theme); | ||
}, | ||
}, | ||
}; | ||
</script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
В некоторых местах далее проверяется
typeof localStorage !== 'undefined'
перед юзанием LS. Предлагаю что тут, что далее юзатьnullsafe
, т.е. вместо проверок и дерева изif
, просто юзать