initial commit

This commit is contained in:
2025-12-31 15:33:16 -05:00
commit 4641e7d0ef
51 changed files with 4779 additions and 0 deletions

83
frontend/src/theme.ts Normal file
View File

@@ -0,0 +1,83 @@
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];
}