From 38207a1f304ebe596d7749f7ee58af5aae82c434 Mon Sep 17 00:00:00 2001 From: Kr4ight Date: Mon, 6 Apr 2026 21:52:33 +0200 Subject: [PATCH] Improved settings --- src/components/SettingsSection.tsx | 237 +++++++++++++++++------------ src/lib/types.ts | 3 + 2 files changed, 146 insertions(+), 94 deletions(-) diff --git a/src/components/SettingsSection.tsx b/src/components/SettingsSection.tsx index 5f40435..e076293 100644 --- a/src/components/SettingsSection.tsx +++ b/src/components/SettingsSection.tsx @@ -3,44 +3,168 @@ import { Save, RefreshCcw, Info } from "lucide-react"; import { getSettings, updateSettings } from "../lib/saturn"; import { LauncherSettings } from "@/lib/types"; -export type SettingType = "slider" | "toggle" | "input"; +export type SettingSchemaItem = + | SettingSchemaLeaf + | SettingSchemaGroup; -export interface SettingSchemaItem { - key: keyof LauncherSettings; +export interface SettingSchemaBase { label: string; description?: string; - type: SettingType; +} + +export interface SettingSchemaLeaf extends SettingSchemaBase { + type: "slider" | "toggle" | "input"; + + key: string; // leaf key (resolved in context) + default: any; - // Slider-specific min?: number; max?: number; step?: number; format?: (value: any) => string; ticks?: number[]; info?: string; +} - // Default value - default: any; +export interface SettingSchemaGroup extends SettingSchemaBase { + type: "group"; + children: SettingSchemaItem[]; } export const settingsSchema: SettingSchemaItem[] = [ { - key: "max_memory", - label: "Maximum Memory (RAM)", - type: "slider", - min: 1024, - max: 16384, - step: 512, - default: 2048, + type: "group", + label: "Performance", - format: (v) => `${(v / 1024).toFixed(1)} GB`, + children: [ + { + key: "max_memory", + label: "Maximum Memory (RAM)", + type: "slider", + min: 1024, + max: 16384, + step: 512, + default: 2048, - ticks: [1024, 4096, 8192, 12288, 16384], + format: (v) => `${(v / 1024).toFixed(1)} GB`, + }, + ], + }, - info: `Allocating too much memory can cause system instability, while too little can lead to performance issues or crashes. 2GB - 8GB is recommended for most users.`, + { + type: "group", + label: "Features", + + children: [ + { + key: "features.sync_options", + label: "Sync Options", + type: "toggle", + default: true, + }, + ], }, ]; +const getValue = (obj: any, path: string) => + path.split(".").reduce((acc, key) => acc?.[key], obj); + +const setValue = (obj: any, path: string, value: any) => { + const keys = path.split("."); + const last = keys.pop()!; + const clone = structuredClone(obj); + + let current = clone; + for (const key of keys) current = current[key]; + + current[last] = value; + return clone; +}; + +const SettingItem: React.FC<{ + item: SettingSchemaItem; + settings: LauncherSettings; + setSettings: React.Dispatch< + React.SetStateAction + >; +}> = ({ item, settings, setSettings }) => { + if (item.type === "group") { + return ( +
+
+ {item.label} +
+ + {item.children.map((child, i) => ( + + ))} +
+ ); + } + + const value = getValue(settings, item.key); + + return ( +
+ {item.type === "slider" && ( + <> + {item.label} + + setSettings((prev) => + prev + ? setValue(prev, item.key, parseInt(e.target.value)) + : prev + ) + } + className="w-full" + /> + + )} + + {item.type === "toggle" && ( +
+ + setSettings((prev) => + prev ? setValue(prev, item.key, e.target.checked) : prev + ) + } + /> + {item.label} +
+ )} +
+ ); +}; + +const buildDefaultSettings = (schema: SettingSchemaItem[]): any => { + const result: any = {}; + + for (const item of schema) { + if (item.type === "group") { + Object.assign(result, buildDefaultSettings(item.children)); + } else { + result[item.key] = item.default; + } + } + + return result; +}; + const SettingsSection: React.FC = () => { const [settings, setSettings] = useState(null); const [isSaving, setIsSaving] = useState(false); @@ -69,7 +193,7 @@ const SettingsSection: React.FC = () => { }; const handleReset = async () => { - setSettings(Object.fromEntries(settingsSchema.map((v) => [v.key, v.default])) as LauncherSettings); + setSettings(buildDefaultSettings(settingsSchema) as LauncherSettings); }; if (!settings) return null; @@ -103,82 +227,7 @@ const SettingsSection: React.FC = () => {
- {settingsSchema.map((item) => { - const value = settings[item.key]; - - return ( -
-
- {item.label} - {item.format && ( - - {item.format(value)} - - )} -
- - {item.type === "slider" && ( - <> - - setSettings({ - ...settings, - [item.key]: parseInt(e.target.value), - }) - } - className="w-full h-2 bg-saturn-border rounded-lg appearance-none cursor-pointer accent-saturn-accent" - /> - - {/* Tick labels */} - {item.ticks && ( -
- {item.ticks.map((tick) => { - const percent = - (((tick - item.min!) / (item.max! - item.min!)) * 100 - 50) * - 0.97 + - 50; - - return ( - - {tick / 1024} GB - - ); - })} -
- )} - - {/* Info box */} - {item.info && ( -
- -

- {item.info} -

-
- )} - - )} - - {item.description && ( -
- -

- {item.description} -

-
- )} -
- ); - })} + {settingsSchema.map((item) => ())}
); diff --git a/src/lib/types.ts b/src/lib/types.ts index 81fd836..ad6b013 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -17,4 +17,7 @@ export interface GameVersion { export interface LauncherSettings { max_memory: number; + features: { + sync_options: boolean + } }