web/_includes/mode-toggle.html
2024-04-20 23:59:59 +08:00

145 lines
3.2 KiB
HTML

<!-- Switch the mode between dark and light. -->
<script type="text/javascript">
class ModeToggle {
static get MODE_KEY() {
return 'mode';
}
static get MODE_ATTR() {
return 'data-mode';
}
static get DARK_MODE() {
return 'dark';
}
static get LIGHT_MODE() {
return 'light';
}
static get ID() {
return 'mode-toggle';
}
constructor() {
if (this.hasMode) {
if (this.isDarkMode) {
if (!this.isSysDarkPrefer) {
this.setDark();
}
} else {
if (this.isSysDarkPrefer) {
this.setLight();
}
}
}
let self = this;
{%- comment -%} always follow the system prefers {%- endcomment -%}
this.sysDarkPrefers.addEventListener('change', () => {
if (self.hasMode) {
if (self.isDarkMode) {
if (!self.isSysDarkPrefer) {
self.setDark();
}
} else {
if (self.isSysDarkPrefer) {
self.setLight();
}
}
self.clearMode();
}
self.notify();
});
} {%- comment -%} constructor() {%- endcomment -%}
get sysDarkPrefers() {
return window.matchMedia('(prefers-color-scheme: dark)');
}
get isSysDarkPrefer() {
return this.sysDarkPrefers.matches;
}
get isDarkMode() {
return this.mode === ModeToggle.DARK_MODE;
}
get isLightMode() {
return this.mode === ModeToggle.LIGHT_MODE;
}
get hasMode() {
return this.mode != null;
}
get mode() {
return sessionStorage.getItem(ModeToggle.MODE_KEY);
}
{%- comment -%} get the current mode on screen {%- endcomment -%}
get modeStatus() {
if (this.isDarkMode || (!this.hasMode && this.isSysDarkPrefer)) {
return ModeToggle.DARK_MODE;
} else {
return ModeToggle.LIGHT_MODE;
}
}
setDark() {
document.documentElement.setAttribute(ModeToggle.MODE_ATTR, ModeToggle.DARK_MODE);
sessionStorage.setItem(ModeToggle.MODE_KEY, ModeToggle.DARK_MODE);
}
setLight() {
document.documentElement.setAttribute(ModeToggle.MODE_ATTR, ModeToggle.LIGHT_MODE);
sessionStorage.setItem(ModeToggle.MODE_KEY, ModeToggle.LIGHT_MODE);
}
clearMode() {
document.documentElement.removeAttribute(ModeToggle.MODE_ATTR);
sessionStorage.removeItem(ModeToggle.MODE_KEY);
}
{%- comment -%}
Notify another plugins that the theme mode has changed
{%- endcomment -%}
notify() {
window.postMessage(
{
direction: ModeToggle.ID,
message: this.modeStatus
},
'*'
);
}
flipMode() {
if (this.hasMode) {
if (this.isSysDarkPrefer) {
if (this.isLightMode) {
this.clearMode();
} else {
this.setLight();
}
} else {
if (this.isDarkMode) {
this.clearMode();
} else {
this.setDark();
}
}
} else {
if (this.isSysDarkPrefer) {
this.setLight();
} else {
this.setDark();
}
}
this.notify();
}
}
const modeToggle = new ModeToggle();
</script>