Feat: Build out server shell

This commit is contained in:
MangoPig
2026-06-16 13:11:14 +01:00
parent 35586729ba
commit 829d7b3d8f
28 changed files with 1990 additions and 149 deletions

View File

@@ -1,11 +1,12 @@
// Path: Frontend/src/theme/runtime.ts
import { defaultThemePresetPath } from "./presets";
import { defaultThemePresetMeta, defaultThemePresetPath, resolveThemePresetPath } from "./presets";
import { createCssVariableMap, isThemeModeName, validateThemeDefinition, type ThemeDefinition, type ThemeModeName } from "./schema";
export type Theme = ThemeModeName;
export const THEME_STORAGE_KEY = "theme";
export const THEME_PRESET_STORAGE_KEY = "theme-preset";
export const DEFAULT_THEME: Theme = "light";
let activeThemeDefinition: ThemeDefinition | null = null;
@@ -21,6 +22,14 @@ const getRootElement = (): HTMLElement | null => {
return canUseDom() ? document.documentElement : null;
};
const persistThemePreset = (themeDefinition: ThemeDefinition): void => {
if (!canUseStorage()) {
return;
}
localStorage.setItem(THEME_PRESET_STORAGE_KEY, themeDefinition.id);
};
const setDocumentThemeMode = (theme: Theme): void => {
const rootElement = getRootElement();
@@ -71,10 +80,31 @@ export const getDocumentTheme = (): Theme => {
export const applyThemeDefinition = (themeDefinition: ThemeDefinition, theme: Theme): void => {
activeThemeDefinition = themeDefinition;
persistThemePreset(themeDefinition);
setDocumentThemeMode(theme);
applyThemeVariables(themeDefinition, theme);
};
export const resolvePreferredThemePresetId = (): string => {
if (!canUseStorage()) {
return defaultThemePresetMeta.id;
}
const stored = localStorage.getItem(THEME_PRESET_STORAGE_KEY);
if (stored && resolveThemePresetPath(stored)) {
return stored;
}
return defaultThemePresetMeta.id;
};
export const resolvePreferredThemePresetPath = (): string => {
const presetId = resolvePreferredThemePresetId();
return resolveThemePresetPath(presetId) ?? defaultThemePresetPath;
};
export const initializeThemeRuntime = async (): Promise<ThemeDefinition | null> => {
if (typeof window === "undefined") {
return null;
@@ -88,7 +118,7 @@ export const initializeThemeRuntime = async (): Promise<ThemeDefinition | null>
if (!themeInitializationPromise) {
themeInitializationPromise = (async (): Promise<ThemeDefinition | null> => {
try {
const response = await fetch(defaultThemePresetPath, {
const response = await fetch(resolvePreferredThemePresetPath(), {
headers: {
Accept: "application/json",
},