From 6c6cd5052a157b658f50e04ca7c350a00c2dbd60 Mon Sep 17 00:00:00 2001 From: HsiangNianian Date: Fri, 16 Jan 2026 14:17:17 +0800 Subject: feat: add assistant view and configuration editor components Introduced a new AssistantView component for enhanced interaction with the AI assistant, allowing users to send messages and receive responses. Implemented a ConfigEditorModal for editing configuration files with JSON validation and history management. Updated the App component to integrate these new features, improving user experience and functionality in managing AI settings. --- ui/src/App.svelte | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'ui/src/App.svelte') diff --git a/ui/src/App.svelte b/ui/src/App.svelte index 760a15f..2b78892 100644 --- a/ui/src/App.svelte +++ b/ui/src/App.svelte @@ -10,6 +10,7 @@ import LoginModal from "./components/LoginModal.svelte"; import ParticleBackground from "./components/ParticleBackground.svelte"; import SettingsView from "./components/SettingsView.svelte"; + import AssistantView from "./components/AssistantView.svelte"; import Sidebar from "./components/Sidebar.svelte"; import StatusToast from "./components/StatusToast.svelte"; import VersionsView from "./components/VersionsView.svelte"; @@ -18,6 +19,7 @@ import { gameState } from "./stores/game.svelte"; import { settingsState } from "./stores/settings.svelte"; import { uiState } from "./stores/ui.svelte"; + import { logsState } from "./stores/logs.svelte"; import { convertFileSrc } from "@tauri-apps/api/core"; let mouseX = $state(0); @@ -29,24 +31,19 @@ } onMount(async () => { + // ENFORCE DARK MODE: Always add 'dark' class and attribute + document.documentElement.classList.add('dark'); + document.documentElement.setAttribute('data-theme', 'dark'); + document.documentElement.classList.remove('light'); + authState.checkAccount(); await settingsState.loadSettings(); + logsState.init(); await settingsState.detectJava(); gameState.loadVersions(); getVersion().then((v) => (uiState.appVersion = v)); window.addEventListener("mousemove", handleMouseMove); }); - - $effect(() => { - // ENFORCE DARK MODE: Always add 'dark' class and attribute - // This combined with the @variant dark in app.css ensures dark mode is always active - // regardless of system preference settings. - document.documentElement.classList.add('dark'); - document.documentElement.setAttribute('data-theme', 'dark'); - - // Ensure 'light' class is never present - document.documentElement.classList.remove('light'); - }); onDestroy(() => { if (typeof window !== 'undefined') @@ -120,6 +117,8 @@ {:else if uiState.currentView === "settings"} + {:else if uiState.currentView === "guide"} + {/if} -- cgit v1.2.3-70-g09d2 From 743401f15199a116b1777bced843c774c5a59fba Mon Sep 17 00:00:00 2001 From: HsiangNianian Date: Fri, 16 Jan 2026 20:20:19 +0800 Subject: feat: add InstancesView component and integrate instance management into the UI Introduced a new InstancesView component for managing game instances, allowing users to create, edit, delete, and duplicate instances. Updated the App.svelte to include the InstancesView and modified various components to ensure instance selection is handled correctly. Enhanced the ModLoaderSelector and VersionsView to check for active instances before performing actions. Updated the Sidebar to include navigation to the new InstancesView. --- ui/src/App.svelte | 5 + ui/src/components/BottomBar.svelte | 10 +- ui/src/components/InstancesView.svelte | 331 +++++++++++++++++++++++++++++ ui/src/components/ModLoaderSelector.svelte | 18 +- ui/src/components/Sidebar.svelte | 3 +- ui/src/components/VersionsView.svelte | 14 +- 6 files changed, 376 insertions(+), 5 deletions(-) create mode 100644 ui/src/components/InstancesView.svelte (limited to 'ui/src/App.svelte') diff --git a/ui/src/App.svelte b/ui/src/App.svelte index 2b78892..127bbea 100644 --- a/ui/src/App.svelte +++ b/ui/src/App.svelte @@ -11,12 +11,14 @@ import ParticleBackground from "./components/ParticleBackground.svelte"; import SettingsView from "./components/SettingsView.svelte"; import AssistantView from "./components/AssistantView.svelte"; + import InstancesView from "./components/InstancesView.svelte"; import Sidebar from "./components/Sidebar.svelte"; import StatusToast from "./components/StatusToast.svelte"; import VersionsView from "./components/VersionsView.svelte"; // Stores import { authState } from "./stores/auth.svelte"; import { gameState } from "./stores/game.svelte"; + import { instancesState } from "./stores/instances.svelte"; import { settingsState } from "./stores/settings.svelte"; import { uiState } from "./stores/ui.svelte"; import { logsState } from "./stores/logs.svelte"; @@ -40,6 +42,7 @@ await settingsState.loadSettings(); logsState.init(); await settingsState.detectJava(); + await instancesState.loadInstances(); gameState.loadVersions(); getVersion().then((v) => (uiState.appVersion = v)); window.addEventListener("mousemove", handleMouseMove); @@ -113,6 +116,8 @@
{#if uiState.currentView === "home"} + {:else if uiState.currentView === "instances"} + {:else if uiState.currentView === "versions"} {:else if uiState.currentView === "settings"} diff --git a/ui/src/components/BottomBar.svelte b/ui/src/components/BottomBar.svelte index 8a6b7ff..19cf35d 100644 --- a/ui/src/components/BottomBar.svelte +++ b/ui/src/components/BottomBar.svelte @@ -4,6 +4,7 @@ import { authState } from "../stores/auth.svelte"; import { gameState } from "../stores/game.svelte"; import { uiState } from "../stores/ui.svelte"; + import { instancesState } from "../stores/instances.svelte"; import { Terminal, ChevronDown, Play, User, Check } from 'lucide-svelte'; interface InstalledVersion { @@ -44,9 +45,16 @@ } async function loadInstalledVersions() { + if (!instancesState.activeInstanceId) { + installedVersions = []; + isLoadingVersions = false; + return; + } isLoadingVersions = true; try { - installedVersions = await invoke("list_installed_versions"); + installedVersions = await invoke("list_installed_versions", { + instanceId: instancesState.activeInstanceId, + }); // If no version is selected but we have installed versions, select the first one if (!gameState.selectedVersion && installedVersions.length > 0) { gameState.selectedVersion = installedVersions[0].id; diff --git a/ui/src/components/InstancesView.svelte b/ui/src/components/InstancesView.svelte new file mode 100644 index 0000000..a4881e6 --- /dev/null +++ b/ui/src/components/InstancesView.svelte @@ -0,0 +1,331 @@ + + +
+
+

Instances

+ +
+ + {#if instancesState.instances.length === 0} +
+
+

No instances yet

+

Create your first instance to get started

+
+
+ {:else} +
+ {#each instancesState.instances as instance (instance.id)} +
instancesState.setActiveInstance(instance.id)} + > + {#if instancesState.activeInstanceId === instance.id} +
+
+
+ {/if} + +
+

+ {instance.name} +

+
+ + + +
+
+ +
+ {#if instance.version_id} +

Version: {instance.version_id}

+ {:else} +

No version selected

+ {/if} + + {#if instance.mod_loader && instance.mod_loader !== "vanilla"} +

+ Mod Loader: {instance.mod_loader} + {#if instance.mod_loader_version} + ({instance.mod_loader_version}) + {/if} +

+ {/if} + +

Created: {formatDate(instance.created_at)}

+ + {#if instance.last_played} +

Last played: {formatLastPlayed(instance.last_played)}

+ {/if} +
+ + {#if instance.notes} +

+ {instance.notes} +

+ {/if} +
+ {/each} +
+ {/if} +
+ + +{#if showCreateModal} +
+
+

Create Instance

+ e.key === "Enter" && confirmCreate()} + autofocus + /> +
+ + +
+
+
+{/if} + + +{#if showEditModal && selectedInstance} +
+
+

Edit Instance

+ e.key === "Enter" && confirmEdit()} + autofocus + /> +
+ + +
+
+
+{/if} + + +{#if showDeleteConfirm && selectedInstance} +
+
+

Delete Instance

+

+ Are you sure you want to delete "{selectedInstance.name}"? This action cannot be undone and will delete all game data for this instance. +

+
+ + +
+
+
+{/if} + + +{#if showDuplicateModal && selectedInstance} +
+
+

Duplicate Instance

+ e.key === "Enter" && confirmDuplicate()} + autofocus + /> +
+ + +
+
+
+{/if} diff --git a/ui/src/components/ModLoaderSelector.svelte b/ui/src/components/ModLoaderSelector.svelte index 34f6f2e..50caa8c 100644 --- a/ui/src/components/ModLoaderSelector.svelte +++ b/ui/src/components/ModLoaderSelector.svelte @@ -9,6 +9,7 @@ } from "../types"; import { Loader2, Download, AlertCircle, Check, ChevronDown, CheckCircle } from 'lucide-svelte'; import { logsState } from "../stores/logs.svelte"; + import { instancesState } from "../stores/instances.svelte"; interface Props { selectedGameVersion: string; @@ -52,12 +53,13 @@ }); async function checkInstallStatus() { - if (!selectedGameVersion) { + if (!selectedGameVersion || !instancesState.activeInstanceId) { isVersionInstalled = false; return; } try { isVersionInstalled = await invoke("check_version_installed", { + instanceId: instancesState.activeInstanceId, versionId: selectedGameVersion, }); } catch (e) { @@ -112,8 +114,13 @@ error = null; logsState.addLog("info", "Installer", `Starting installation of ${selectedGameVersion}...`); + if (!instancesState.activeInstanceId) { + error = "Please select an instance first"; + return; + } try { await invoke("install_version", { + instanceId: instancesState.activeInstanceId, versionId: selectedGameVersion, }); logsState.addLog("info", "Installer", `Successfully installed ${selectedGameVersion}`); @@ -134,6 +141,12 @@ return; } + if (!instancesState.activeInstanceId) { + error = "Please select an instance first"; + isInstalling = false; + return; + } + isInstalling = true; error = null; @@ -142,6 +155,7 @@ if (!isVersionInstalled) { logsState.addLog("info", "Installer", `Installing base game ${selectedGameVersion} first...`); await invoke("install_version", { + instanceId: instancesState.activeInstanceId, versionId: selectedGameVersion, }); isVersionInstalled = true; @@ -151,6 +165,7 @@ if (selectedLoader === "fabric" && selectedFabricLoader) { logsState.addLog("info", "Installer", `Installing Fabric ${selectedFabricLoader} for ${selectedGameVersion}...`); const result = await invoke("install_fabric", { + instanceId: instancesState.activeInstanceId, gameVersion: selectedGameVersion, loaderVersion: selectedFabricLoader, }); @@ -159,6 +174,7 @@ } else if (selectedLoader === "forge" && selectedForgeVersion) { logsState.addLog("info", "Installer", `Installing Forge ${selectedForgeVersion} for ${selectedGameVersion}...`); const result = await invoke("install_forge", { + instanceId: instancesState.activeInstanceId, gameVersion: selectedGameVersion, forgeVersion: selectedForgeVersion, }); diff --git a/ui/src/components/Sidebar.svelte b/ui/src/components/Sidebar.svelte index 3d36f89..83f4ac6 100644 --- a/ui/src/components/Sidebar.svelte +++ b/ui/src/components/Sidebar.svelte @@ -1,6 +1,6 @@