diff options
| -rw-r--r-- | assets/image.jpg | bin | 172906 -> 161028 bytes | |||
| -rw-r--r-- | src-tauri/src/core/config.rs | 2 | ||||
| -rw-r--r-- | src-tauri/src/main.rs | 4 | ||||
| -rw-r--r-- | src-tauri/tauri.conf.json | 4 | ||||
| -rw-r--r-- | ui/src/App.svelte | 39 | ||||
| -rw-r--r-- | ui/src/components/BottomBar.svelte | 20 | ||||
| -rw-r--r-- | ui/src/components/HomeView.svelte | 10 | ||||
| -rw-r--r-- | ui/src/components/LoginModal.svelte | 30 | ||||
| -rw-r--r-- | ui/src/components/ModLoaderSelector.svelte | 40 | ||||
| -rw-r--r-- | ui/src/components/SettingsView.svelte | 60 | ||||
| -rw-r--r-- | ui/src/components/Sidebar.svelte | 8 | ||||
| -rw-r--r-- | ui/src/components/StatusToast.svelte | 10 | ||||
| -rw-r--r-- | ui/src/components/VersionsView.svelte | 48 | ||||
| -rw-r--r-- | ui/src/stores/settings.svelte.ts | 6 | ||||
| -rw-r--r-- | ui/src/types/index.ts | 1 |
15 files changed, 163 insertions, 119 deletions
diff --git a/assets/image.jpg b/assets/image.jpg Binary files differindex 28cffe1..ddda96f 100644 --- a/assets/image.jpg +++ b/assets/image.jpg diff --git a/src-tauri/src/core/config.rs b/src-tauri/src/core/config.rs index 27e0011..510b126 100644 --- a/src-tauri/src/core/config.rs +++ b/src-tauri/src/core/config.rs @@ -17,6 +17,7 @@ pub struct LauncherConfig { pub enable_gpu_acceleration: bool, pub enable_visual_effects: bool, pub active_effect: String, + pub theme: String, } impl Default for LauncherConfig { @@ -32,6 +33,7 @@ impl Default for LauncherConfig { enable_gpu_acceleration: false, enable_visual_effects: true, active_effect: "constellation".to_string(), + theme: "dark".to_string(), } } } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index f7a391a..8a955a5 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -854,8 +854,6 @@ async fn get_recommended_java( Ok(core::java::get_recommended_java(required_major_version)) } -// ==================== Fabric Loader Commands ==================== - /// Get Minecraft versions supported by Fabric #[tauri::command] async fn get_fabric_game_versions() -> Result<Vec<core::fabric::FabricGameVersion>, String> { @@ -949,8 +947,6 @@ async fn is_fabric_installed( )) } -// ==================== Forge Loader Commands ==================== - /// Get Minecraft versions supported by Forge #[tauri::command] async fn get_forge_game_versions() -> Result<Vec<String>, String> { diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 9145e1b..682acb0 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -14,8 +14,8 @@ "title": "Minecraft DropOut Launcher", "width": 1024, "height": 768, - "minWidth": 800, - "minHeight": 600, + "minWidth": 905, + "minHeight": 575, "resizable": true } ], diff --git a/ui/src/App.svelte b/ui/src/App.svelte index d93374e..2160b85 100644 --- a/ui/src/App.svelte +++ b/ui/src/App.svelte @@ -31,12 +31,22 @@ onMount(async () => { authState.checkAccount(); - settingsState.loadSettings(); + await settingsState.loadSettings(); gameState.loadVersions(); getVersion().then((v) => (uiState.appVersion = v)); window.addEventListener("mousemove", handleMouseMove); }); + $effect(() => { + if (settingsState.settings.theme === 'light') { + document.documentElement.classList.remove('dark'); + document.documentElement.setAttribute('data-theme', 'light'); + } else { + document.documentElement.classList.add('dark'); + document.documentElement.setAttribute('data-theme', 'dark'); + } + }); + onDestroy(() => { if (typeof window !== 'undefined') window.removeEventListener("mousemove", handleMouseMove); @@ -44,10 +54,10 @@ </script> <div - class="relative h-screen w-screen overflow-hidden text-white font-sans selection:bg-indigo-500/30" + class="relative h-screen w-screen overflow-hidden dark:text-white text-gray-900 font-sans selection:bg-indigo-500/30" > <!-- Modern Animated Background --> - <div class="absolute inset-0 z-0 bg-[#09090b] overflow-hidden"> + <div class="absolute inset-0 z-0 bg-[#09090b] dark:bg-[#09090b] bg-gray-100 overflow-hidden"> {#if settingsState.settings.custom_background_path} <img src={convertFileSrc(settingsState.settings.custom_background_path)} @@ -57,28 +67,35 @@ <!-- Dimming Overlay for readability --> <div class="absolute inset-0 bg-black/50 "></div> {:else if settingsState.settings.enable_visual_effects} - <!-- Original Gradient --> - <div - class="absolute inset-0 opacity-60 bg-gradient-to-br from-emerald-900 via-zinc-900 to-indigo-950" - ></div> + <!-- Original Gradient (Dark Only / or Adjusted for Light) --> + {#if settingsState.settings.theme === 'dark'} + <div + class="absolute inset-0 opacity-60 bg-gradient-to-br from-emerald-900 via-zinc-900 to-indigo-950" + ></div> + {:else} + <!-- Light Mode Gradient --> + <div + class="absolute inset-0 opacity-100 bg-gradient-to-br from-emerald-100 via-gray-100 to-indigo-100" + ></div> + {/if} {#if uiState.currentView === "home"} <ParticleBackground /> {/if} <div - class="absolute inset-0 bg-gradient-to-t from-zinc-900 via-transparent to-black/50" + class="absolute inset-0 bg-gradient-to-t from-zinc-900 via-transparent to-black/50 dark:from-zinc-900 dark:to-black/50 from-gray-100 to-transparent" ></div> {/if} <!-- Subtle Grid Overlay --> - <div class="absolute inset-0 z-0 opacity-10 pointer-events-none" - style="background-image: linear-gradient(#ffffff 1px, transparent 1px), linear-gradient(90deg, #ffffff 1px, transparent 1px); background-size: 40px 40px; mask-image: radial-gradient(circle at 50% 50%, black 30%, transparent 70%);"> + <div class="absolute inset-0 z-0 opacity-10 dark:opacity-10 opacity-30 pointer-events-none" + style="background-image: linear-gradient({settingsState.settings.theme === 'dark' ? '#ffffff' : '#000000'} 1px, transparent 1px), linear-gradient(90deg, {settingsState.settings.theme === 'dark' ? '#ffffff' : '#000000'} 1px, transparent 1px); background-size: 40px 40px; mask-image: radial-gradient(circle at 50% 50%, black 30%, transparent 70%);"> </div> </div> <!-- Content Wrapper --> - <div class="relative z-10 flex h-full p-4 gap-4"> + <div class="relative z-10 flex h-full p-4 gap-4 text-gray-900 dark:text-white"> <!-- Floating Sidebar --> <Sidebar /> diff --git a/ui/src/components/BottomBar.svelte b/ui/src/components/BottomBar.svelte index dd218f3..0178111 100644 --- a/ui/src/components/BottomBar.svelte +++ b/ui/src/components/BottomBar.svelte @@ -5,7 +5,7 @@ </script> <div - class="h-24 bg-gradient-to-t from-black/50 to-transparent border-t border-white/5 flex items-center px-8 justify-between z-20 backdrop-blur-md" + class="h-24 bg-gradient-to-t from-black/50 to-transparent dark:from-black/50 dark:to-transparent from-white/90 to-transparent border-t dark:border-white/5 border-black/5 flex items-center px-8 justify-between z-20 backdrop-blur-md" > <!-- Account Area --> <div class="flex items-center gap-6"> @@ -17,7 +17,7 @@ onkeydown={(e) => e.key === "Enter" && authState.openLoginModal()} > <div - class="w-12 h-12 rounded-xl bg-gradient-to-tr from-indigo-500 to-purple-500 shadow-lg shadow-indigo-500/20 flex items-center justify-center text-white font-bold text-xl overflow-hidden ring-2 ring-transparent group-hover:ring-white/20 transition-all" + class="w-12 h-12 rounded-xl bg-gradient-to-tr from-indigo-500 to-purple-500 shadow-lg shadow-indigo-500/20 flex items-center justify-center text-white font-bold text-xl overflow-hidden ring-2 ring-transparent dark:group-hover:ring-white/20 group-hover:ring-black/10 transition-all" > {#if authState.currentAccount} <img @@ -30,25 +30,25 @@ {/if} </div> <div> - <div class="font-bold text-white text-lg group-hover:text-indigo-300 transition-colors"> + <div class="font-bold dark:text-white text-gray-900 text-lg group-hover:text-indigo-500 dark:group-hover:text-indigo-300 transition-colors"> {authState.currentAccount ? authState.currentAccount.username : "Login"} </div> - <div class="text-xs text-zinc-400 flex items-center gap-1.5"> + <div class="text-xs dark:text-zinc-400 text-gray-500 flex items-center gap-1.5"> <span class="w-2 h-2 rounded-full {authState.currentAccount ? 'bg-emerald-500 shadow-[0_0_8px_rgba(16,185,129,0.5)]' - : 'bg-zinc-600'}" + : 'dark:bg-zinc-600 bg-gray-400'}" ></span> {authState.currentAccount ? "Ready to play" : "Guest Mode"} </div> </div> </div> - <div class="h-8 w-px bg-white/10"></div> + <div class="h-8 w-px dark:bg-white/10 bg-black/10"></div> <!-- Console Toggle --> <button - class="text-xs font-mono text-zinc-500 hover:text-white transition-colors flex items-center gap-2" + class="text-xs font-mono dark:text-zinc-500 text-gray-500 dark:hover:text-white hover:text-black transition-colors flex items-center gap-2" onclick={() => uiState.toggleConsole()} > <span class="text-lg">_</span> @@ -61,14 +61,14 @@ <div class="flex flex-col items-end mr-2"> <label for="version-select" - class="text-[10px] text-white/40 mb-1 uppercase font-bold tracking-wider" + class="text-[10px] dark:text-white/40 text-black/40 mb-1 uppercase font-bold tracking-wider" >Selected Version</label > <div class="relative group"> <select id="version-select" bind:value={gameState.selectedVersion} - class="appearance-none bg-black/40 text-white border border-white/10 rounded-xl pl-4 pr-10 py-2.5 hover:border-white/30 transition-all cursor-pointer outline-none focus:ring-2 focus:ring-indigo-500/50 w-56 text-sm font-mono backdrop-blur-sm shadow-inner" + class="appearance-none dark:bg-black/40 bg-white/60 dark:text-white text-gray-900 border dark:border-white/10 border-black/10 rounded-xl pl-4 pr-10 py-2.5 dark:hover:border-white/30 hover:border-black/30 transition-all cursor-pointer outline-none focus:ring-2 focus:ring-indigo-500/50 w-56 text-sm font-mono backdrop-blur-sm shadow-inner" > {#if gameState.versions.length === 0} <option>Loading...</option> @@ -78,7 +78,7 @@ {/each} {/if} </select> - <div class="absolute right-3 top-1/2 -translate-y-1/2 text-white/20 pointer-events-none group-hover:text-white/50 transition-colors">▼</div> + <div class="absolute right-3 top-1/2 -translate-y-1/2 dark:text-white/20 text-black/20 pointer-events-none dark:group-hover:text-white/50 group-hover:text-black/50 transition-colors">▼</div> </div> </div> diff --git a/ui/src/components/HomeView.svelte b/ui/src/components/HomeView.svelte index 036c03a..9cd8014 100644 --- a/ui/src/components/HomeView.svelte +++ b/ui/src/components/HomeView.svelte @@ -19,19 +19,19 @@ style:transform={`perspective(1000px) rotateX(${mouseY * -2}deg) rotateY(${mouseX * 2}deg)`} > <h1 - class="text-8xl font-black tracking-tighter text-white drop-shadow-2xl mb-4" - style="text-shadow: 0 10px 30px rgba(0,0,0,0.5);" + class="text-8xl font-black tracking-tighter dark:text-white text-gray-900 drop-shadow-2xl mb-4" + style:text-shadow="0 10px 30px rgba(0,0,0,0.5)" > MINECRAFT </h1> <div class="flex items-center gap-4"> <div - class="bg-white/10 backdrop-blur-md border border-white/10 px-4 py-1.5 rounded-full text-sm font-bold uppercase tracking-widest text-emerald-400 shadow-xl" + class="bg-white/10 dark:bg-white/10 bg-black/5 backdrop-blur-md border dark:border-white/10 border-black/10 px-4 py-1.5 rounded-full text-sm font-bold uppercase tracking-widest text-emerald-500 dark:text-emerald-400 shadow-xl" > Java Edition </div> - <div class="text-2xl font-light text-zinc-300"> + <div class="text-2xl font-light dark:text-zinc-300 text-gray-600"> Latest Release 1.21 </div> </div> @@ -40,7 +40,7 @@ <!-- Action Area --> <div class="mt-8 flex gap-4"> <!-- Quick Play Button (Visual only here, logic is in BottomBar usually) --> - <div class="text-zinc-400 text-sm italic"> + <div class="dark:text-zinc-400 text-gray-500 text-sm italic"> Ready to play. Select version below or hit Launch. </div> </div> diff --git a/ui/src/components/LoginModal.svelte b/ui/src/components/LoginModal.svelte index f1ac0d5..1886cd9 100644 --- a/ui/src/components/LoginModal.svelte +++ b/ui/src/components/LoginModal.svelte @@ -9,16 +9,16 @@ {#if authState.isLoginModalOpen} <div - class="fixed inset-0 z-[60] flex items-center justify-center bg-black/80 backdrop-blur-sm p-4" + class="fixed inset-0 z-[60] flex items-center justify-center bg-white/80 dark:bg-black/80 backdrop-blur-sm p-4" > <div - class="bg-zinc-900 border border-zinc-700 rounded-xl shadow-2xl p-6 w-full max-w-md animate-in fade-in zoom-in-0 duration-200" + class="bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-xl shadow-2xl p-6 w-full max-w-md animate-in fade-in zoom-in-0 duration-200" > <div class="flex justify-between items-center mb-6"> - <h2 class="text-2xl font-bold text-white">Login</h2> + <h2 class="text-2xl font-bold text-gray-900 dark:text-white">Login</h2> <button onclick={() => authState.closeLoginModal()} - class="text-zinc-500 hover:text-white transition group" + class="text-zinc-500 hover:text-black dark:hover:text-white transition group" > ✕ </button> @@ -28,7 +28,7 @@ <div class="space-y-4"> <button onclick={() => authState.startMicrosoftLogin()} - class="w-full flex items-center justify-center gap-3 bg-[#2F2F2F] hover:bg-[#3F3F3F] text-white p-4 rounded-lg font-bold border border-transparent hover:border-zinc-500 transition-all group" + class="w-full flex items-center justify-center gap-3 bg-gray-100 hover:bg-gray-200 dark:bg-[#2F2F2F] dark:hover:bg-[#3F3F3F] text-gray-900 dark:text-white p-4 rounded-lg font-bold border border-transparent hover:border-zinc-400 dark:hover:border-zinc-500 transition-all group" > <!-- Microsoft Logo SVG --> <svg @@ -49,10 +49,10 @@ <div class="relative py-2"> <div class="absolute inset-0 flex items-center"> - <div class="w-full border-t border-zinc-700"></div> + <div class="w-full border-t border-zinc-200 dark:border-zinc-700"></div> </div> <div class="relative flex justify-center text-xs uppercase"> - <span class="bg-zinc-900 px-2 text-zinc-500">OR</span> + <span class="bg-white dark:bg-zinc-900 px-2 text-zinc-400 dark:text-zinc-500">OR</span> </div> </div> @@ -61,12 +61,12 @@ type="text" bind:value={authState.offlineUsername} placeholder="Offline Username" - class="w-full bg-zinc-950 border border-zinc-700 rounded p-3 text-white focus:border-indigo-500 outline-none" + class="w-full bg-gray-50 border-zinc-200 dark:bg-zinc-950 dark:border-zinc-700 rounded p-3 text-gray-900 dark:text-white focus:border-indigo-500 outline-none" onkeydown={(e) => e.key === "Enter" && authState.performOfflineLogin()} /> <button onclick={() => authState.performOfflineLogin()} - class="w-full bg-zinc-800 hover:bg-zinc-700 text-zinc-300 p-3 rounded font-medium transition-colors" + class="w-full bg-gray-200 hover:bg-gray-300 dark:bg-zinc-800 dark:hover:bg-zinc-700 text-gray-700 dark:text-zinc-300 p-3 rounded font-medium transition-colors" > Offline Login </button> @@ -80,18 +80,18 @@ </div> {:else if authState.deviceCodeData} <div class="space-y-4"> - <p class="text-sm text-zinc-400">1. Go to this URL:</p> + <p class="text-sm text-gray-500 dark:text-zinc-400">1. Go to this URL:</p> <button onclick={() => authState.deviceCodeData && openLink(authState.deviceCodeData.verification_uri)} - class="text-indigo-400 hover:text-indigo-300 underline break-all font-mono text-sm" + class="text-indigo-600 dark:text-indigo-400 hover:text-indigo-500 dark:hover:text-indigo-300 underline break-all font-mono text-sm" > {authState.deviceCodeData.verification_uri} </button> - <p class="text-sm text-zinc-400 mt-2">2. Enter this code:</p> + <p class="text-sm text-gray-500 dark:text-zinc-400 mt-2">2. Enter this code:</p> <div - class="bg-zinc-950 p-4 rounded border border-zinc-700 font-mono text-2xl tracking-widest text-center select-all cursor-pointer hover:border-indigo-500 transition-colors" + class="bg-gray-50 dark:bg-zinc-950 p-4 rounded border border-zinc-200 dark:border-zinc-700 font-mono text-2xl tracking-widest text-center select-all cursor-pointer hover:border-indigo-500 transition-colors dark:text-white text-gray-900" role="button" tabindex="0" onkeydown={(e) => e.key === 'Enter' && navigator.clipboard.writeText(authState.deviceCodeData?.user_code || "")} @@ -106,8 +106,8 @@ <div class="pt-6 space-y-3"> <div class="flex flex-col items-center gap-3"> - <div class="animate-spin rounded-full h-6 w-6 border-2 border-zinc-600 border-t-indigo-500"></div> - <span class="text-sm text-zinc-400 font-medium break-all text-center">{authState.msLoginStatus}</span> + <div class="animate-spin rounded-full h-6 w-6 border-2 border-zinc-300 dark:border-zinc-600 border-t-indigo-500"></div> + <span class="text-sm text-gray-600 dark:text-zinc-400 font-medium break-all text-center">{authState.msLoginStatus}</span> </div> <p class="text-xs text-zinc-600">This window will update automatically.</p> </div> diff --git a/ui/src/components/ModLoaderSelector.svelte b/ui/src/components/ModLoaderSelector.svelte index 4a59916..fd26382 100644 --- a/ui/src/components/ModLoaderSelector.svelte +++ b/ui/src/components/ModLoaderSelector.svelte @@ -114,16 +114,16 @@ <div class="space-y-4"> <div class="flex items-center justify-between"> - <h3 class="text-xs font-bold uppercase tracking-widest text-white/40">Select Mod Loader</h3> + <h3 class="text-xs font-bold uppercase tracking-widest text-gray-500 dark:text-white/40">Select Mod Loader</h3> </div> <!-- Loader Type Tabs - Segmented Control --> - <div class="flex p-1 bg-black/40 rounded-xl border border-white/5 backdrop-blur-sm"> + <div class="flex p-1 bg-white/60 dark:bg-black/40 rounded-xl border border-black/5 dark:border-white/5 backdrop-blur-sm"> <button class="flex-1 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200 {selectedLoader === 'vanilla' - ? 'bg-white/10 text-white shadow-lg border border-white/10' - : 'text-zinc-500 hover:text-white hover:bg-white/5'}" + ? 'bg-white shadow-lg border border-black/5 text-black dark:bg-white/10 dark:text-white dark:border-white/10' + : 'text-gray-500 dark:text-zinc-500 hover:text-black dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5'}" onclick={() => onLoaderChange("vanilla")} > Vanilla @@ -131,8 +131,8 @@ <button class="flex-1 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200 {selectedLoader === 'fabric' - ? 'bg-indigo-500/20 text-indigo-300 shadow-lg border border-indigo-500/20' - : 'text-zinc-500 hover:text-white hover:bg-white/5'}" + ? 'bg-indigo-100 text-indigo-700 border border-indigo-200 dark:bg-indigo-500/20 dark:text-indigo-300 dark:shadow-lg dark:border-indigo-500/20' + : 'text-gray-500 dark:text-zinc-500 hover:text-black dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5'}" onclick={() => onLoaderChange("fabric")} > Fabric @@ -140,8 +140,8 @@ <button class="flex-1 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200 {selectedLoader === 'forge' - ? 'bg-orange-500/20 text-orange-300 shadow-lg border border-orange-500/20' - : 'text-zinc-500 hover:text-white hover:bg-white/5'}" + ? 'bg-orange-100 text-orange-700 border border-orange-200 dark:bg-orange-500/20 dark:text-orange-300 dark:shadow-lg dark:border-orange-500/20' + : 'text-gray-500 dark:text-zinc-500 hover:text-black dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5'}" onclick={() => onLoaderChange("forge")} > Forge @@ -151,36 +151,36 @@ <!-- Content Area --> <div class="min-h-[100px] flex flex-col justify-center"> {#if selectedLoader === "vanilla"} - <div class="text-center p-4 rounded-xl bg-white/5 border border-dashed border-white/10 text-white/40 text-sm"> + <div class="text-center p-4 rounded-xl bg-white/40 dark:bg-white/5 border border-dashed border-black/5 dark:border-white/10 text-gray-500 dark:text-white/40 text-sm"> No mod loader selected. <br> Pure vanilla experience. </div> {:else if !selectedGameVersion} - <div class="text-center p-4 rounded-xl bg-red-500/10 border border-red-500/20 text-red-300 text-sm"> + <div class="text-center p-4 rounded-xl bg-red-50 border border-red-200 text-red-700 dark:bg-red-500/10 dark:border-red-500/20 dark:text-red-300 text-sm"> ⚠️ Please select a base Minecraft version first. </div> {:else if isLoading} - <div class="flex flex-col items-center gap-2 text-sm text-white/50 py-4"> - <div class="w-6 h-6 border-2 border-white/20 border-t-white rounded-full animate-spin"></div> + <div class="flex flex-col items-center gap-2 text-sm text-gray-500 dark:text-white/50 py-4"> + <div class="w-6 h-6 border-2 border-gray-200 border-t-gray-500 dark:border-white/20 dark:border-t-white rounded-full animate-spin"></div> Loading {selectedLoader} versions... </div> {:else if error} - <div class="p-4 bg-red-500/10 border border-red-500/20 rounded-xl text-red-300 text-sm break-words"> + <div class="p-4 bg-red-50 border border-red-200 text-red-700 dark:bg-red-500/10 dark:border-red-500/20 dark:text-red-300 rounded-xl text-sm break-words"> {error} </div> {:else if selectedLoader === "fabric"} <div class="space-y-4 animate-in fade-in slide-in-from-bottom-2 duration-300"> <div> - <label for="fabric-loader-select" class="block text-xs text-white/40 mb-2 pl-1" + <label for="fabric-loader-select" class="block text-xs text-gray-500 dark:text-white/40 mb-2 pl-1" >Loader Version</label > <div class="relative"> <select id="fabric-loader-select" - class="w-full appearance-none bg-black/40 border border-white/10 rounded-xl px-4 py-3 text-sm focus:outline-none focus:border-indigo-500/50 text-white transition-colors" + class="w-full appearance-none bg-white/80 dark:bg-black/40 border border-black/10 dark:border-white/10 rounded-xl px-4 py-3 text-sm focus:outline-none focus:border-indigo-500/50 text-gray-900 dark:text-white transition-colors" bind:value={selectedFabricLoader} > {#each fabricLoaders as loader} @@ -189,7 +189,7 @@ </option> {/each} </select> - <div class="absolute right-4 top-1/2 -translate-y-1/2 text-white/20 pointer-events-none">▼</div> + <div class="absolute right-4 top-1/2 -translate-y-1/2 text-black/30 dark:text-white/20 pointer-events-none">▼</div> </div> </div> @@ -205,18 +205,18 @@ {:else if selectedLoader === "forge"} <div class="space-y-4 animate-in fade-in slide-in-from-bottom-2 duration-300"> {#if forgeVersions.length === 0} - <div class="text-center p-4 text-sm text-white/40 italic"> + <div class="text-center p-4 text-sm text-gray-500 dark:text-white/40 italic"> No Forge versions available for {selectedGameVersion} </div> {:else} <div> - <label for="forge-version-select" class="block text-xs text-white/40 mb-2 pl-1" + <label for="forge-version-select" class="block text-xs text-gray-500 dark:text-white/40 mb-2 pl-1" >Forge Version</label > <div class="relative"> <select id="forge-version-select" - class="w-full appearance-none bg-black/40 border border-white/10 rounded-xl px-4 py-3 text-sm focus:outline-none focus:border-orange-500/50 text-white transition-colors" + class="w-full appearance-none bg-white/80 dark:bg-black/40 border border-black/10 dark:border-white/10 rounded-xl px-4 py-3 text-sm focus:outline-none focus:border-orange-500/50 text-gray-900 dark:text-white transition-colors" bind:value={selectedForgeVersion} > {#each forgeVersions as version} @@ -227,7 +227,7 @@ </option> {/each} </select> - <div class="absolute right-4 top-1/2 -translate-y-1/2 text-white/20 pointer-events-none">▼</div> + <div class="absolute right-4 top-1/2 -translate-y-1/2 text-black/30 dark:text-white/20 pointer-events-none">▼</div> </div> </div> diff --git a/ui/src/components/SettingsView.svelte b/ui/src/components/SettingsView.svelte index 4c92220..86bcce1 100644 --- a/ui/src/components/SettingsView.svelte +++ b/ui/src/components/SettingsView.svelte @@ -32,24 +32,24 @@ <div class="h-full flex flex-col p-6 overflow-hidden"> <div class="flex items-center justify-between mb-6"> - <h2 class="text-3xl font-black bg-clip-text text-transparent bg-gradient-to-r from-white to-white/60">Settings</h2> + <h2 class="text-3xl font-black bg-clip-text text-transparent bg-gradient-to-r dark:from-white dark:to-white/60 from-gray-900 to-gray-600">Settings</h2> </div> <div class="flex-1 overflow-y-auto pr-2 space-y-6 custom-scrollbar pb-10"> <!-- Appearance / Background --> - <div class="bg-black/20 p-6 rounded-2xl border border-white/5 "> - <h3 class="text-xs font-bold uppercase tracking-widest text-white/40 mb-6 flex items-center gap-2"> + <div class="dark:bg-black/20 bg-white/60 p-6 rounded-2xl border dark:border-white/5 border-black/5 shadow-sm backdrop-blur-sm"> + <h3 class="text-xs font-bold uppercase tracking-widest dark:text-white/40 text-black/40 mb-6 flex items-center gap-2"> Appearance </h3> <div class="space-y-4"> <div> - <label class="block text-sm font-medium text-white/70 mb-3">Custom Background Image</label> + <label class="block text-sm font-medium dark:text-white/70 text-black/70 mb-3">Custom Background Image</label> <div class="flex items-center gap-6"> <!-- Preview --> - <div class="w-40 h-24 rounded-xl overflow-hidden bg-black/50 border border-white/10 relative group shadow-lg"> + <div class="w-40 h-24 rounded-xl overflow-hidden dark:bg-black/50 bg-gray-200 border dark:border-white/10 border-black/10 relative group shadow-lg"> {#if settingsState.settings.custom_background_path} <img src={convertFileSrc(settingsState.settings.custom_background_path)} @@ -66,7 +66,7 @@ <div class="flex flex-col gap-2"> <button onclick={selectBackground} - class="bg-white/10 hover:bg-white/20 text-white px-4 py-2 rounded-lg text-sm transition-colors border border-white/5" + class="dark:bg-white/10 dark:hover:bg-white/20 bg-black/5 hover:bg-black/10 dark:text-white text-black px-4 py-2 rounded-lg text-sm transition-colors border dark:border-white/5 border-black/5" > Select Image </button> @@ -81,39 +81,39 @@ {/if} </div> </div> - <p class="text-xs text-white/30 mt-3"> + <p class="text-xs dark:text-white/30 text-black/40 mt-3"> Select an image from your computer to replace the default gradient background. Supported formats: PNG, JPG, WEBP, GIF. </p> </div> <!-- Visual Settings --> - <div class="pt-4 border-t border-white/5 space-y-4"> + <div class="pt-4 border-t dark:border-white/5 border-black/5 space-y-4"> <div class="flex items-center justify-between"> <div> - <h4 class="text-sm font-medium text-white/90" id="visual-effects-label">Visual Effects</h4> - <p class="text-xs text-white/40 mt-1">Enable particle effects and animated gradients. (Default: On)</p> + <h4 class="text-sm font-medium dark:text-white/90 text-black/80" id="visual-effects-label">Visual Effects</h4> + <p class="text-xs dark:text-white/40 text-black/50 mt-1">Enable particle effects and animated gradients. (Default: On)</p> </div> <button aria-labelledby="visual-effects-label" onclick={() => { settingsState.settings.enable_visual_effects = !settingsState.settings.enable_visual_effects; settingsState.saveSettings(); }} - class="w-11 h-6 rounded-full transition-colors duration-200 ease-in-out relative focus:outline-none {settingsState.settings.enable_visual_effects ? 'bg-indigo-500' : 'bg-white/10'}" + class="w-11 h-6 rounded-full transition-colors duration-200 ease-in-out relative focus:outline-none {settingsState.settings.enable_visual_effects ? 'bg-indigo-500' : 'dark:bg-white/10 bg-black/10'}" > <div class="absolute top-1 left-1 bg-white w-4 h-4 rounded-full shadow-sm transition-transform duration-200 ease-in-out {settingsState.settings.enable_visual_effects ? 'translate-x-5' : 'translate-x-0'}"></div> </button> </div> {#if settingsState.settings.enable_visual_effects} - <div class="flex items-center justify-between pl-2 border-l-2 border-white/5 ml-1"> + <div class="flex items-center justify-between pl-2 border-l-2 dark:border-white/5 border-black/5 ml-1"> <div> - <h4 class="text-sm font-medium text-white/90" id="theme-effect-label">Theme Effect</h4> - <p class="text-xs text-white/40 mt-1">Select the active visual theme.</p> + <h4 class="text-sm font-medium dark:text-white/90 text-black/80" id="theme-effect-label">Theme Effect</h4> + <p class="text-xs dark:text-white/40 text-black/50 mt-1">Select the active visual theme.</p> </div> <select aria-labelledby="theme-effect-label" bind:value={settingsState.settings.active_effect} onchange={() => settingsState.saveSettings()} - class="bg-black/40 text-white text-xs px-3 py-2 rounded-lg border border-white/10 outline-none focus:border-indigo-500/50 appearance-none cursor-pointer hover:bg-white/5 transition-colors" + class="dark:bg-black/40 bg-white dark:text-white text-black text-xs px-3 py-2 rounded-lg border dark:border-white/10 border-black/10 outline-none focus:border-indigo-500/50 appearance-none cursor-pointer hover:bg-black/5 dark:hover:bg-white/5 transition-colors" > <option value="saturn">Saturn (Saturn)</option> <option value="constellation">Network (Constellation)</option> @@ -123,23 +123,45 @@ <div class="flex items-center justify-between"> <div> - <h4 class="text-sm font-medium text-white/90" id="gpu-acceleration-label">GPU Acceleration</h4> - <p class="text-xs text-white/40 mt-1">Enable GPU acceleration for the interface. (Default: Off, Requires Restart)</p> + <h4 class="text-sm font-medium dark:text-white/90 text-black/80" id="gpu-acceleration-label">GPU Acceleration</h4> + <p class="text-xs dark:text-white/40 text-black/50 mt-1">Enable GPU acceleration for the interface. (Default: Off, Requires Restart)</p> </div> <button aria-labelledby="gpu-acceleration-label" onclick={() => { settingsState.settings.enable_gpu_acceleration = !settingsState.settings.enable_gpu_acceleration; settingsState.saveSettings(); }} - class="w-11 h-6 rounded-full transition-colors duration-200 ease-in-out relative focus:outline-none {settingsState.settings.enable_gpu_acceleration ? 'bg-indigo-500' : 'bg-white/10'}" + class="w-11 h-6 rounded-full transition-colors duration-200 ease-in-out relative focus:outline-none {settingsState.settings.enable_gpu_acceleration ? 'bg-indigo-500' : 'dark:bg-white/10 bg-black/10'}" > <div class="absolute top-1 left-1 bg-white w-4 h-4 rounded-full shadow-sm transition-transform duration-200 ease-in-out {settingsState.settings.enable_gpu_acceleration ? 'translate-x-5' : 'translate-x-0'}"></div> </button> </div> + + <!-- Color Theme Switcher --> + <div class="flex items-center justify-between pt-4 border-t dark:border-white/5 border-black/5 opacity-50 cursor-not-allowed"> + <div> + <h4 class="text-sm font-medium dark:text-white/90 text-black/80" id="color-theme-label">Color Theme</h4> + <p class="text-xs dark:text-white/40 text-black/50 mt-1">Interface color mode. (Locked to Dark)</p> + </div> + <div class="flex items-center bg-black/5 dark:bg-white/5 rounded-lg p-1 pointer-events-none"> + <button + disabled + class="px-3 py-1 rounded-md text-xs font-medium transition-all text-gray-500 dark:text-gray-600" + > + Light + </button> + <button + disabled + class="px-3 py-1 rounded-md text-xs font-medium transition-all bg-indigo-500 text-white shadow-sm" + > + Dark + </button> + </div> + </div> </div> </div> </div> <!-- Java Path --> - <div class="bg-black/20 p-6 rounded-2xl border border-white/5 "> + <div class="dark:bg-black/20 bg-white/60 p-6 rounded-2xl border dark:border-white/5 border-black/5 shadow-sm backdrop-blur-sm"> <h3 class="text-xs font-bold uppercase tracking-widest text-white/40 mb-6 flex items-center gap-2"> Java Environment </h3> diff --git a/ui/src/components/Sidebar.svelte b/ui/src/components/Sidebar.svelte index 7976f6a..e6fbf43 100644 --- a/ui/src/components/Sidebar.svelte +++ b/ui/src/components/Sidebar.svelte @@ -3,7 +3,7 @@ </script> <aside - class="w-20 lg:w-64 bg-black flex flex-col items-center lg:items-start transition-all duration-300 shrink-0 py-6" + class="w-20 lg:w-64 dark:bg-black bg-white/80 border-r dark:border-white/5 border-gray-200/50 flex flex-col items-center lg:items-start transition-all duration-300 shrink-0 py-6 backdrop-blur-md" > <!-- Logo Area --> <div @@ -17,7 +17,7 @@ </div> <!-- Full Logo (Large) --> <div - class="hidden lg:block font-bold text-2xl tracking-wider text-white" + class="hidden lg:block font-bold text-2xl tracking-wider dark:text-white text-gray-900" > <span class="bg-clip-text text-transparent bg-gradient-to-r from-indigo-400 to-fuchsia-400">DROP</span>OUT </div> @@ -30,8 +30,8 @@ <button class="group flex items-center lg:gap-4 justify-center lg:justify-start w-full px-0 lg:px-5 py-3.5 rounded-xl transition-all duration-200 relative overflow-hidden {uiState.currentView === view - ? 'bg-gradient-to-r from-indigo-500/20 to-purple-500/20 text-white shadow-lg shadow-indigo-500/10 border border-white/10' - : 'text-zinc-400 hover:text-white hover:bg-white/5'}" + ? 'bg-gradient-to-r from-indigo-500/20 to-purple-500/20 dark:text-white text-indigo-900 shadow-lg shadow-indigo-500/10 dark:border border-white/10' + : 'dark:text-zinc-400 text-gray-500 hover:text-black dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5'}" onclick={() => uiState.setView(view)} > <span class="text-xl relative z-10 transition-transform group-hover:scale-110 duration-200">{icon}</span> diff --git a/ui/src/components/StatusToast.svelte b/ui/src/components/StatusToast.svelte index 0d68778..4c981c7 100644 --- a/ui/src/components/StatusToast.svelte +++ b/ui/src/components/StatusToast.svelte @@ -5,19 +5,19 @@ {#if uiState.status !== "Ready"} {#key uiState.status} <div - class="absolute top-12 right-12 bg-zinc-800/90 backdrop-blur border border-zinc-600 p-4 rounded-lg shadow-2xl max-w-sm animate-in fade-in slide-in-from-top-4 duration-300 z-50 group" + class="absolute top-12 right-12 bg-white/90 dark:bg-zinc-800/90 backdrop-blur border border-zinc-200 dark:border-zinc-600 p-4 rounded-lg shadow-2xl max-w-sm animate-in fade-in slide-in-from-top-4 duration-300 z-50 group" > <div class="flex justify-between items-start mb-1"> - <div class="text-xs text-zinc-400 uppercase font-bold">Status</div> + <div class="text-xs text-zinc-500 dark:text-zinc-400 uppercase font-bold">Status</div> <button onclick={() => uiState.setStatus("Ready")} - class="text-zinc-500 hover:text-white transition -mt-1 -mr-1 p-1" + class="text-zinc-400 hover:text-black dark:text-zinc-500 dark:hover:text-white transition -mt-1 -mr-1 p-1" > ✕ </button> </div> - <div class="font-mono text-sm whitespace-pre-wrap mb-2">{uiState.status}</div> - <div class="w-full bg-zinc-700/50 h-1 rounded-full overflow-hidden"> + <div class="font-mono text-sm whitespace-pre-wrap mb-2 text-gray-900 dark:text-gray-100">{uiState.status}</div> + <div class="w-full bg-gray-200 dark:bg-zinc-700/50 h-1 rounded-full overflow-hidden"> <div class="h-full bg-indigo-500 origin-left w-full progress-bar" ></div> diff --git a/ui/src/components/VersionsView.svelte b/ui/src/components/VersionsView.svelte index 00ac281..8f3a568 100644 --- a/ui/src/components/VersionsView.svelte +++ b/ui/src/components/VersionsView.svelte @@ -73,15 +73,15 @@ function getVersionBadge(type: string) { switch (type) { case "release": - return { text: "Release", class: "bg-emerald-500/20 text-emerald-300 border-emerald-500/30" }; + return { text: "Release", class: "bg-emerald-100 text-emerald-700 border-emerald-200 dark:bg-emerald-500/20 dark:text-emerald-300 dark:border-emerald-500/30" }; case "snapshot": - return { text: "Snapshot", class: "bg-amber-500/20 text-amber-300 border-amber-500/30" }; + return { text: "Snapshot", class: "bg-amber-100 text-amber-700 border-amber-200 dark:bg-amber-500/20 dark:text-amber-300 dark:border-amber-500/30" }; case "fabric": - return { text: "Fabric", class: "bg-indigo-500/20 text-indigo-300 border-indigo-500/30" }; + return { text: "Fabric", class: "bg-indigo-100 text-indigo-700 border-indigo-200 dark:bg-indigo-500/20 dark:text-indigo-300 dark:border-indigo-500/30" }; case "forge": - return { text: "Forge", class: "bg-orange-500/20 text-orange-300 border-orange-500/30" }; + return { text: "Forge", class: "bg-orange-100 text-orange-700 border-orange-200 dark:bg-orange-500/20 dark:text-orange-300 dark:border-orange-500/30" }; default: - return { text: type, class: "bg-zinc-500/20 text-zinc-300 border-zinc-500/30" }; + return { text: type, class: "bg-zinc-100 text-zinc-700 border-zinc-200 dark:bg-zinc-500/20 dark:text-zinc-300 dark:border-zinc-500/30" }; } } @@ -116,8 +116,8 @@ <div class="h-full flex flex-col p-6 overflow-hidden"> <div class="flex items-center justify-between mb-6"> - <h2 class="text-3xl font-black bg-clip-text text-transparent bg-gradient-to-r from-white to-white/60">Version Manager</h2> - <div class="text-sm text-white/40">Select a version to play or modify</div> + <h2 class="text-3xl font-black bg-clip-text text-transparent bg-gradient-to-r from-gray-900 to-gray-600 dark:from-white dark:to-white/60">Version Manager</h2> + <div class="text-sm dark:text-white/40 text-black/50">Select a version to play or modify</div> </div> <div class="flex-1 grid grid-cols-1 lg:grid-cols-3 gap-6 overflow-hidden"> @@ -126,24 +126,24 @@ <!-- Search and Filters (Glass Bar) --> <div class="flex gap-3"> <div class="relative flex-1"> - <span class="absolute left-3 top-1/2 -translate-y-1/2 text-white/30">🔍</span> + <span class="absolute left-3 top-1/2 -translate-y-1/2 dark:text-white/30 text-black/30">🔍</span> <input type="text" placeholder="Search versions..." - class="w-full pl-9 pr-4 py-3 bg-black/20 border border-white/10 rounded-xl text-white placeholder-white/30 focus:outline-none focus:border-indigo-500/50 focus:bg-black/40 transition-all backdrop-blur-sm" + class="w-full pl-9 pr-4 py-3 bg-white/60 dark:bg-black/20 border border-black/10 dark:border-white/10 rounded-xl dark:text-white text-gray-900 placeholder-black/30 dark:placeholder-white/30 focus:outline-none focus:border-indigo-500/50 dark:focus:bg-black/40 focus:bg-white/80 transition-all backdrop-blur-sm" bind:value={searchQuery} /> </div> </div> <!-- Type Filter Tabs (Glass Caps) --> - <div class="flex p-1 bg-black/20 rounded-xl border border-white/5"> + <div class="flex p-1 bg-white/60 dark:bg-black/20 rounded-xl border border-black/5 dark:border-white/5"> {#each ['all', 'release', 'snapshot', 'modded'] as filter} <button class="flex-1 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200 capitalize {typeFilter === filter - ? 'bg-white/10 text-white shadow-lg border border-white/10' - : 'text-white/40 hover:text-white hover:bg-white/5'}" + ? 'bg-white shadow-sm border border-black/5 dark:bg-white/10 dark:text-white dark:shadow-lg dark:border-white/10 text-black' + : 'text-black/40 dark:text-white/40 hover:text-black dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5'}" onclick={() => (typeFilter = filter as any)} > {filter} @@ -154,11 +154,11 @@ <!-- Version List SCROLL --> <div class="flex-1 overflow-y-auto pr-2 space-y-2 custom-scrollbar"> {#if gameState.versions.length === 0} - <div class="flex items-center justify-center h-40 text-white/30 italic animate-pulse"> + <div class="flex items-center justify-center h-40 dark:text-white/30 text-black/30 italic animate-pulse"> Fetching manifest... </div> {:else if filteredVersions().length === 0} - <div class="flex flex-col items-center justify-center -40 text-white/30 gap-2"> + <div class="flex flex-col items-center justify-center -40 dark:text-white/30 text-black/30 gap-2"> <span class="text-2xl">👻</span> <span>No matching versions found</span> </div> @@ -169,8 +169,8 @@ <button class="w-full group flex items-center justify-between p-4 rounded-xl text-left border transition-all duration-200 relative overflow-hidden {isSelected - ? 'bg-indigo-600/20 border-indigo-500/50 shadow-[0_0_20px_rgba(99,102,241,0.2)]' - : 'bg-white/5 border-white/5 hover:bg-white/10 hover:border-white/10 hover:translate-x-1'}" + ? 'bg-indigo-50 border-indigo-200 dark:bg-indigo-600/20 dark:border-indigo-500/50 shadow-[0_0_20px_rgba(99,102,241,0.2)]' + : 'bg-white/40 dark:bg-white/5 border-black/5 dark:border-white/5 hover:bg-white/60 dark:hover:bg-white/10 hover:border-black/10 dark:hover:border-white/10 hover:translate-x-1'}" onclick={() => (gameState.selectedVersion = version.id)} > <!-- Selection Glow --> @@ -185,11 +185,11 @@ {badge.text} </span> <div> - <div class="font-bold font-mono text-lg tracking-tight {isSelected ? 'text-white' : 'text-zinc-300 group-hover:text-white'}"> + <div class="font-bold font-mono text-lg tracking-tight {isSelected ? 'text-black dark:text-white' : 'text-gray-700 dark:text-zinc-300 group-hover:text-black dark:group-hover:text-white'}"> {version.id} </div> {#if version.releaseTime && version.type !== "fabric" && version.type !== "forge"} - <div class="text-xs text-white/30"> + <div class="text-xs dark:text-white/30 text-black/30"> {new Date(version.releaseTime).toLocaleDateString()} </div> {/if} @@ -197,7 +197,7 @@ </div> {#if isSelected} - <div class="relative z-10 text-indigo-400"> + <div class="relative z-10 text-indigo-500 dark:text-indigo-400"> <span class="text-lg">Selected</span> </div> {/if} @@ -210,21 +210,21 @@ <!-- Right: Mod Loader Panel --> <div class="flex flex-col gap-4"> <!-- Selected Version Info Card --> - <div class="bg-gradient-to-br from-white/10 to-white/5 p-6 rounded-2xl border border-white/10 backdrop-blur-md relative overflow-hidden group"> + <div class="bg-gradient-to-br from-white/40 to-white/20 dark:from-white/10 dark:to-white/5 p-6 rounded-2xl border border-black/5 dark:border-white/10 backdrop-blur-md relative overflow-hidden group"> <div class="absolute top-0 right-0 p-8 bg-indigo-500/20 blur-[60px] rounded-full group-hover:bg-indigo-500/30 transition-colors"></div> - <h3 class="text-xs font-bold uppercase tracking-widest text-white/40 mb-2 relative z-10">Current Selection</h3> + <h3 class="text-xs font-bold uppercase tracking-widest dark:text-white/40 text-black/40 mb-2 relative z-10">Current Selection</h3> {#if gameState.selectedVersion} - <p class="font-mono text-3xl font-black text-transparent bg-clip-text bg-gradient-to-r from-white to-white/70 relative z-10 truncate"> + <p class="font-mono text-3xl font-black text-transparent bg-clip-text bg-gradient-to-r from-gray-900 to-gray-600 dark:from-white dark:to-white/70 relative z-10 truncate"> {gameState.selectedVersion} </p> {:else} - <p class="text-white/20 italic relative z-10">None selected</p> + <p class="dark:text-white/20 text-black/20 italic relative z-10">None selected</p> {/if} </div> <!-- Mod Loader Selector Card --> - <div class="bg-black/20 p-4 rounded-2xl border border-white/5 backdrop-blur-sm flex-1 flex flex-col"> + <div class="bg-white/60 dark:bg-black/20 p-4 rounded-2xl border border-black/5 dark:border-white/5 backdrop-blur-sm flex-1 flex flex-col"> <ModLoaderSelector selectedGameVersion={selectedBaseVersion()} onInstall={handleModLoaderInstall} diff --git a/ui/src/stores/settings.svelte.ts b/ui/src/stores/settings.svelte.ts index c59bf3c..b67cdc3 100644 --- a/ui/src/stores/settings.svelte.ts +++ b/ui/src/stores/settings.svelte.ts @@ -13,6 +13,7 @@ export class SettingsState { enable_gpu_acceleration: false, enable_visual_effects: true, active_effect: "constellation", + theme: "dark", }); javaInstallations = $state<JavaInstallation[]>([]); isDetectingJava = $state(false); @@ -21,6 +22,11 @@ export class SettingsState { try { const result = await invoke<LauncherConfig>("get_settings"); this.settings = result; + // Force dark mode + if (this.settings.theme !== "dark") { + this.settings.theme = "dark"; + this.saveSettings(); + } } catch (e) { console.error("Failed to load settings:", e); } diff --git a/ui/src/types/index.ts b/ui/src/types/index.ts index fa48075..7e2cc67 100644 --- a/ui/src/types/index.ts +++ b/ui/src/types/index.ts @@ -34,6 +34,7 @@ export interface LauncherConfig { enable_gpu_acceleration: boolean; enable_visual_effects: boolean; active_effect: string; + theme: string; } export interface JavaInstallation { |