diff options
| author | 2026-02-25 02:06:07 +0800 | |
|---|---|---|
| committer | 2026-02-25 02:06:07 +0800 | |
| commit | 78ac61904d78d558d092eff08c9f261cbdb187e8 (patch) | |
| tree | 96f68d1f1554ee3a0532793afaaa52b0c73dcbec /packages/ui/src/models/settings.ts | |
| parent | 8ff3af6cb908fd824b512379dd21ed4f595ab6bb (diff) | |
| parent | 329734b23957b84cde2af459fa61c7385fb5b5f1 (diff) | |
| download | DropOut-78ac61904d78d558d092eff08c9f261cbdb187e8.tar.gz DropOut-78ac61904d78d558d092eff08c9f261cbdb187e8.zip | |
feat(ui): partial react rewrite (#77)
## Summary by Sourcery
Export backend data structures to TypeScript for the new React-based UI
and update CI to build additional targets.
New Features:
- Generate TypeScript definitions for core backend structs and enums
used by the UI.
- Now use our own Azure app(_DropOut_) to finish the authorize process.
Enhancements:
- Annotate existing Rust models with ts-rs metadata to control exported
TypeScript shapes, including tagged enums and opaque JSON fields.
Build:
- Add ts-rs as a dependency for generating TypeScript bindings from Rust
types.
CI:
- Extend the Semifold CI workflow to run on the dev branch and build
additional Linux musl and Windows GNU targets using cross where needed.
Diffstat (limited to 'packages/ui/src/models/settings.ts')
| -rw-r--r-- | packages/ui/src/models/settings.ts | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/packages/ui/src/models/settings.ts b/packages/ui/src/models/settings.ts new file mode 100644 index 0000000..9f4119c --- /dev/null +++ b/packages/ui/src/models/settings.ts @@ -0,0 +1,75 @@ +import { toast } from "sonner"; +import { create } from "zustand/react"; +import { getConfigPath, getSettings, saveSettings } from "@/client"; +import type { LauncherConfig } from "@/types"; + +export interface SettingsState { + config: LauncherConfig | null; + configPath: string | null; + + /* Theme getter */ + get theme(): string; + /* Apply theme to the document */ + applyTheme: (theme?: string) => void; + + /* Refresh settings from the backend */ + refresh: () => Promise<void>; + /* Save settings to the backend */ + save: () => Promise<void>; + /* Update settings in the backend */ + update: (config: LauncherConfig) => Promise<void>; + /* Merge settings with the current config without saving */ + merge: (config: Partial<LauncherConfig>) => void; +} + +export const useSettingsStore = create<SettingsState>((set, get) => ({ + config: null, + configPath: null, + + get theme() { + const { config } = get(); + return config?.theme || "dark"; + }, + applyTheme: (theme?: string) => { + const { config } = get(); + if (!config) return; + if (!theme) theme = config.theme; + let themeValue = theme; + if (theme === "system") { + themeValue = window.matchMedia("(prefers-color-scheme: dark)").matches + ? "dark" + : "light"; + } + document.documentElement.classList.remove("light", "dark"); + document.documentElement.setAttribute("data-theme", themeValue); + document.documentElement.classList.add(themeValue); + set({ config: { ...config, theme } }); + }, + + refresh: async () => { + const { applyTheme } = get(); + try { + const settings = await getSettings(); + const path = await getConfigPath(); + set({ config: settings, configPath: path }); + applyTheme(settings.theme); + } catch (error) { + console.error("Failed to load settings:", error); + toast.error("Failed to load settings"); + } + }, + save: async () => { + const { config } = get(); + if (!config) return; + await saveSettings(config); + }, + update: async (config) => { + await saveSettings(config); + set({ config }); + }, + merge: (config) => { + const { config: currentConfig } = get(); + if (!currentConfig) throw new Error("Settings not loaded"); + set({ config: { ...currentConfig, ...config } }); + }, +})); |