-
Notifications
You must be signed in to change notification settings - Fork 240
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: added theme switcher with match-system option
- Loading branch information
1 parent
a7003d0
commit 0cb9d71
Showing
3 changed files
with
116 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 icon="laptop" label="Выберите тему" 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)); | ||
|
||
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 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'; | ||
} | ||
|
||
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); | ||
} | ||
} | ||
}); | ||
} | ||
} | ||
|
||
|
||
class StarlightThemeSelect extends HTMLElement { | ||
themeProvider = new StarlightThemeProvider(); | ||
|
||
constructor() { | ||
super(); | ||
this.onThemeChange(loadTheme()); | ||
this.querySelector('select')?.addEventListener('change', (e) => { | ||
if (e.currentTarget instanceof HTMLSelectElement) { | ||
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,7 @@ import { | |
createFileInput, | ||
createMarkdownEditor, | ||
handleFormSubmissionShortcuts, | ||
imageUploadOptions | ||
imageUploadOptions, | ||
} from "./common/markdown-editor"; | ||
import { getCollapsedCommentThreadsSet } from "./common/comments"; | ||
|
||
|
@@ -38,39 +38,38 @@ const App = { | |
initializeEmojiForPoorPeople() { | ||
const isApple = /iPad|iPhone|iPod|OS X/.test(navigator.userAgent) && !window.MSStream; | ||
if (!isApple) { | ||
document.body = twemoji.parse( | ||
document.body, | ||
{ base: "https://cdn.jsdelivr.net/gh/twitter/[email protected]/assets/" } | ||
); | ||
document.body = twemoji.parse(document.body, { | ||
base: "https://cdn.jsdelivr.net/gh/twitter/[email protected]/assets/", | ||
}); | ||
} | ||
}, | ||
initializeThemeSwitcher() { | ||
const themeSwitch = document.querySelector('.theme-switcher input[type="checkbox"]'); | ||
// const themeSwitch = document.querySelector('.theme-switcher input[type="checkbox"]'); | ||
const mediaQueryList = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)"); | ||
|
||
themeSwitch.addEventListener( | ||
"change", | ||
function (e) { | ||
let theme = "light"; | ||
if (e.target.checked) { | ||
theme = "dark"; | ||
} | ||
document.documentElement.setAttribute("theme", theme); | ||
localStorage.setItem("theme", theme); | ||
}, | ||
false | ||
); | ||
|
||
const theme = localStorage.getItem("theme"); | ||
themeSwitch.checked = theme ? theme === "dark" : mediaQueryList.matches; | ||
// themeSwitch.addEventListener( | ||
// "change", | ||
// function (e) { | ||
// let theme = "light"; | ||
// if (e.target.checked) { | ||
// theme = "dark"; | ||
// } | ||
// document.documentElement.setAttribute("theme", theme); | ||
// localStorage.setItem("theme", theme); | ||
// }, | ||
// false | ||
// ); | ||
|
||
// const theme = localStorage.getItem("theme"); | ||
// themeSwitch.checked = theme ? theme === "dark" : mediaQueryList.matches; | ||
|
||
const setFaviconHref = (e) => { | ||
const svgFavicon = document.querySelector('link[type="image/svg+xml"]'); | ||
const isDark = e.matches; | ||
|
||
if (!theme) { | ||
themeSwitch.checked = isDark; | ||
} | ||
// if (!theme) { | ||
// themeSwitch.checked = isDark; | ||
// } | ||
|
||
svgFavicon.href = isDark ? "/static/images/favicon/favicon-dark.svg" : "/static/images/favicon/favicon.svg"; | ||
}; | ||
|
@@ -91,7 +90,7 @@ const App = { | |
|
||
const fullMarkdownEditors = [...document.querySelectorAll(".markdown-editor-full")].reduce( | ||
(editors, element) => { | ||
const fileInputEl = createFileInput({ allowedTypes: imageUploadOptions.allowedTypes }) | ||
const fileInputEl = createFileInput({ allowedTypes: imageUploadOptions.allowedTypes }); | ||
const editor = createMarkdownEditor(element, { | ||
autosave: { | ||
enabled: false, | ||
|
@@ -145,7 +144,7 @@ const App = { | |
{ | ||
name: "upload-file", | ||
action: () => { | ||
fileInputEl.click() | ||
fileInputEl.click(); | ||
}, | ||
className: "fa fa-paperclip", | ||
text: "Upload image", | ||
|