111 lines
3.5 KiB
JavaScript
111 lines
3.5 KiB
JavaScript
import { LOCAL_STORAGE_KEYS } from '../config/constants';
|
|
import { Feature } from 'oak-frontend-base/es/types/Feature';
|
|
import { ETheme } from '../types/Theme';
|
|
const defaultTheme = ETheme.light;
|
|
const initialThemeState = {
|
|
setting: false,
|
|
themeMode: defaultTheme,
|
|
systemTheme: false,
|
|
color: '#0052d9',
|
|
};
|
|
export default class Theme extends Feature {
|
|
themeState;
|
|
storage;
|
|
async loadSavedState() {
|
|
const themeState = await this.storage.load(LOCAL_STORAGE_KEYS.themeState);
|
|
this.themeState = themeState;
|
|
}
|
|
constructor(storage) {
|
|
super();
|
|
this.storage = storage;
|
|
this.themeState = initialThemeState;
|
|
this.switchThemeMode(this.themeState.themeMode);
|
|
this.switchColor(this.themeState.color);
|
|
}
|
|
get() {
|
|
return this.themeState;
|
|
}
|
|
set(themeState) {
|
|
this.themeState = themeState;
|
|
this.storage.save(LOCAL_STORAGE_KEYS.themeState, themeState);
|
|
this.publish();
|
|
}
|
|
toggleSetting() {
|
|
const state = this.themeState;
|
|
state.setting = !state.setting;
|
|
this.set(state);
|
|
}
|
|
switchThemeMode(finalThemeMode) {
|
|
const state = this.themeState;
|
|
// 切换主题颜色
|
|
state.themeMode = finalThemeMode;
|
|
// 关闭跟随系统
|
|
state.systemTheme = false;
|
|
switch (process.env.OAK_PLATFORM) {
|
|
case 'web': {
|
|
document.documentElement.setAttribute('theme-mode', finalThemeMode);
|
|
break;
|
|
}
|
|
default: {
|
|
break;
|
|
}
|
|
}
|
|
this.set(state);
|
|
}
|
|
openSystemTheme() {
|
|
const state = this.themeState;
|
|
const media = window.matchMedia('(prefers-color-scheme:dark)');
|
|
if (media.matches) {
|
|
const finalThemeMode = media.matches ? ETheme.dark : ETheme.light;
|
|
// 切换黑暗主题
|
|
state.themeMode = finalThemeMode;
|
|
state.systemTheme = true;
|
|
switch (process.env.OAK_PLATFORM) {
|
|
case 'web': {
|
|
document.documentElement.setAttribute('theme-mode', finalThemeMode);
|
|
break;
|
|
}
|
|
default: {
|
|
break;
|
|
}
|
|
}
|
|
this.set(state);
|
|
}
|
|
}
|
|
getColor() {
|
|
const state = this.themeState;
|
|
return state.color;
|
|
}
|
|
switchColor(color, theme) {
|
|
const state = this.themeState;
|
|
if (color) {
|
|
state.color = color; // 某主题 主题色
|
|
switch (process.env.OAK_PLATFORM) {
|
|
case 'web': {
|
|
this.insertThemeStylesheet(color, state.themeMode, theme);
|
|
if (theme) {
|
|
document.documentElement.setAttribute('theme-color', theme);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
break;
|
|
}
|
|
}
|
|
this.set(state);
|
|
}
|
|
}
|
|
insertThemeStylesheet(color, mode, theme) {
|
|
const isDarkMode = mode === 'dark';
|
|
const root = !isDarkMode
|
|
? (theme ? `:root[theme-color='${theme}']` : `:root`)
|
|
: (theme ? `:root[theme-color='${theme}'][theme-mode='dark']` : `:root[theme-mode='dark']`);
|
|
const styleSheet = document.createElement('style');
|
|
styleSheet.type = 'text/css';
|
|
styleSheet.innerText = `${root}{
|
|
--oak-color-primary: ${color};
|
|
}`;
|
|
document.head.appendChild(styleSheet);
|
|
}
|
|
}
|