diff options
| author | 2026-01-18 14:53:44 +0800 | |
|---|---|---|
| committer | 2026-01-18 14:53:44 +0800 | |
| commit | d4ea239d4477e9427b52994ea25d54941dfdba3f (patch) | |
| tree | e576bfda1a9b94e37c6b89fc8e3fa6397a3cbea2 /ui/src/components/InstancesView.svelte | |
| parent | 5d403b86833c23ff7974daa829a9cbb2f837f4ec (diff) | |
| download | DropOut-d4ea239d4477e9427b52994ea25d54941dfdba3f.tar.gz DropOut-d4ea239d4477e9427b52994ea25d54941dfdba3f.zip | |
feat(frontend): add instance editor modal with tabbed interface
- Create InstanceEditorModal.svelte with 4 tabs:
* Info: Instance name, notes, metadata (created date, last played)
* Version: Mod loader switcher and version display
* Files: File browser for mods/resourcepacks/shaderpacks/saves/screenshots
* Settings: Memory override and JVM arguments customization
- Wire InstanceEditorModal to InstancesView with Edit button
- Add FileInfo type definition to types/index.ts
- Fix accessibility issues: proper button roles, keyboard events
- All TypeScript and Svelte compilation errors resolved
- Enable comprehensive per-instance configuration management
Diffstat (limited to 'ui/src/components/InstancesView.svelte')
| -rw-r--r-- | ui/src/components/InstancesView.svelte | 67 |
1 files changed, 17 insertions, 50 deletions
diff --git a/ui/src/components/InstancesView.svelte b/ui/src/components/InstancesView.svelte index e42f813..5334f9e 100644 --- a/ui/src/components/InstancesView.svelte +++ b/ui/src/components/InstancesView.svelte @@ -4,12 +4,14 @@ import { Plus, Trash2, Edit2, Copy, Check, X } from "lucide-svelte"; import type { Instance } from "../types"; import InstanceCreationModal from "./InstanceCreationModal.svelte"; + import InstanceEditorModal from "./InstanceEditorModal.svelte"; let showCreateModal = $state(false); let showEditModal = $state(false); let showDeleteConfirm = $state(false); let showDuplicateModal = $state(false); let selectedInstance: Instance | null = $state(null); + let editingInstance: Instance | null = $state(null); let newInstanceName = $state(""); let duplicateName = $state(""); @@ -22,9 +24,7 @@ } function handleEdit(instance: Instance) { - selectedInstance = instance; - newInstanceName = instance.name; - showEditModal = true; + editingInstance = instance; } function handleDelete(instance: Instance) { @@ -38,17 +38,6 @@ showDuplicateModal = true; } - async function confirmEdit() { - if (!selectedInstance || !newInstanceName.trim()) return; - await instancesState.updateInstance({ - ...selectedInstance, - name: newInstanceName.trim(), - }); - showEditModal = false; - selectedInstance = null; - newInstanceName = ""; - } - async function confirmDelete() { if (!selectedInstance) return; await instancesState.deleteInstance(selectedInstance.id); @@ -104,10 +93,13 @@ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> {#each instancesState.instances as instance (instance.id)} <div + role="button" + tabindex="0" class="relative p-4 bg-gray-100 dark:bg-gray-800 rounded-lg border-2 transition-all cursor-pointer hover:border-blue-500 {instancesState.activeInstanceId === instance.id ? 'border-blue-500' : 'border-transparent'}" onclick={() => instancesState.setActiveInstance(instance.id)} + onkeydown={(e) => e.key === "Enter" && instancesState.setActiveInstance(instance.id)} > {#if instancesState.activeInstanceId === instance.id} <div class="absolute top-2 right-2"> @@ -121,6 +113,7 @@ </h3> <div class="flex gap-1"> <button + type="button" onclick={(e) => { e.stopPropagation(); handleEdit(instance); @@ -131,6 +124,7 @@ <Edit2 size={16} class="text-gray-600 dark:text-gray-400" /> </button> <button + type="button" onclick={(e) => { e.stopPropagation(); handleDuplicate(instance); @@ -141,6 +135,7 @@ <Copy size={16} class="text-gray-600 dark:text-gray-400" /> </button> <button + type="button" onclick={(e) => { e.stopPropagation(); handleDelete(instance); @@ -190,41 +185,14 @@ <!-- Create Modal --> <InstanceCreationModal isOpen={showCreateModal} onClose={() => (showCreateModal = false)} /> -<!-- Edit Modal --> -{#if showEditModal && selectedInstance} - <div class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> - <div class="bg-white dark:bg-gray-800 rounded-lg p-6 w-96"> - <h2 class="text-xl font-bold mb-4 text-gray-900 dark:text-white">Edit Instance</h2> - <input - type="text" - bind:value={newInstanceName} - placeholder="Instance name" - class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white mb-4" - onkeydown={(e) => e.key === "Enter" && confirmEdit()} - autofocus - /> - <div class="flex gap-2 justify-end"> - <button - onclick={() => { - showEditModal = false; - selectedInstance = null; - newInstanceName = ""; - }} - class="px-4 py-2 bg-gray-200 dark:bg-gray-700 text-gray-900 dark:text-white rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors" - > - Cancel - </button> - <button - onclick={confirmEdit} - disabled={!newInstanceName.trim()} - class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors" - > - Save - </button> - </div> - </div> - </div> -{/if} +<!-- Instance Editor Modal --> +<InstanceEditorModal + isOpen={editingInstance !== null} + instance={editingInstance} + onClose={() => { + editingInstance = null; + }} +/> <!-- Delete Confirmation --> {#if showDeleteConfirm && selectedInstance} @@ -266,7 +234,6 @@ placeholder="New instance name" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white mb-4" onkeydown={(e) => e.key === "Enter" && confirmDuplicate()} - autofocus /> <div class="flex gap-2 justify-end"> <button |