84 lines
2.3 KiB
TypeScript
84 lines
2.3 KiB
TypeScript
export const AETHERA_THEME_KEY = 'aethera-theme';
|
|
|
|
export type ThemeMode = 'light' | 'dark' | 'system';
|
|
|
|
export interface ThemeState {
|
|
mode: ThemeMode;
|
|
}
|
|
|
|
export function getSystemTheme(): 'light' | 'dark' {
|
|
if (typeof window !== 'undefined') {
|
|
return window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
? 'dark'
|
|
: 'light';
|
|
}
|
|
return 'light';
|
|
}
|
|
|
|
export function getEffectiveTheme(themeMode: ThemeMode): 'light' | 'dark' {
|
|
if (themeMode === 'system') {
|
|
return getSystemTheme();
|
|
}
|
|
return themeMode;
|
|
}
|
|
|
|
export function loadTheme(): ThemeState {
|
|
if (typeof localStorage === 'undefined') {
|
|
return { mode: 'system' };
|
|
}
|
|
|
|
const stored = localStorage.getItem(AETHERA_THEME_KEY);
|
|
if (stored === 'light' || stored === 'dark' || stored === 'system') {
|
|
return { mode: stored };
|
|
}
|
|
|
|
return { mode: 'system' };
|
|
}
|
|
|
|
export function saveThemeMode(mode: ThemeMode): void {
|
|
if (typeof localStorage !== 'undefined') {
|
|
localStorage.setItem(AETHERA_THEME_KEY, mode);
|
|
}
|
|
}
|
|
|
|
export function applyTheme(mode: ThemeMode): void {
|
|
const effectiveTheme = getEffectiveTheme(mode);
|
|
if (typeof document !== 'undefined') {
|
|
if (effectiveTheme === 'dark') {
|
|
document.documentElement.classList.add('dark');
|
|
} else {
|
|
document.documentElement.classList.remove('dark');
|
|
}
|
|
}
|
|
applySyntaxTheme(effectiveTheme);
|
|
}
|
|
|
|
export function applySyntaxTheme(theme: 'light' | 'dark'): void {
|
|
if (typeof document === 'undefined') return;
|
|
|
|
const linkId = 'hljs-theme';
|
|
let link = document.getElementById(linkId) as HTMLLinkElement;
|
|
|
|
const cssFile =
|
|
theme === 'dark'
|
|
? 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/stackoverflow-dark.css'
|
|
: 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.css';
|
|
|
|
if (!link) {
|
|
link = document.createElement('link');
|
|
link.id = linkId;
|
|
link.rel = 'stylesheet';
|
|
link.href = cssFile;
|
|
document.head.appendChild(link);
|
|
} else if (link.href !== cssFile) {
|
|
link.href = cssFile;
|
|
}
|
|
}
|
|
|
|
export function getNextThemeMode(currentMode: ThemeMode): ThemeMode {
|
|
const cycle: ThemeMode[] = ['light', 'dark', 'system'];
|
|
const currentIndex = cycle.indexOf(currentMode);
|
|
const nextIndex = (currentIndex + 1) % cycle.length;
|
|
return cycle[nextIndex];
|
|
}
|