From ffbfce895c37e8e8306d426a2e59e73647ed6a86 Mon Sep 17 00:00:00 2001 From: 苏向夜 Date: Sun, 29 Mar 2026 02:46:51 +0800 Subject: refactor(ui): rewrite game store --- packages/ui/src/pages/home-view.tsx | 102 ------- packages/ui/src/pages/home.tsx | 102 +++++++ packages/ui/src/pages/index.tsx | 12 +- packages/ui/src/pages/instances-view.tsx | 457 ------------------------------- packages/ui/src/pages/routes.ts | 6 +- 5 files changed, 106 insertions(+), 573 deletions(-) delete mode 100644 packages/ui/src/pages/home-view.tsx create mode 100644 packages/ui/src/pages/home.tsx delete mode 100644 packages/ui/src/pages/instances-view.tsx (limited to 'packages/ui/src/pages') diff --git a/packages/ui/src/pages/home-view.tsx b/packages/ui/src/pages/home-view.tsx deleted file mode 100644 index da7238f..0000000 --- a/packages/ui/src/pages/home-view.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import { useState } from "react"; -import { BottomBar } from "@/components/bottom-bar"; -import { useSaturnEffect } from "@/components/particle-background"; - -export function HomeView() { - const [mouseX, setMouseX] = useState(0); - const [mouseY, setMouseY] = useState(0); - const saturn = useSaturnEffect(); - - const handleMouseMove = (e: React.MouseEvent) => { - const x = (e.clientX / window.innerWidth) * 2 - 1; - const y = (e.clientY / window.innerHeight) * 2 - 1; - setMouseX(x); - setMouseY(y); - - // Forward mouse move to SaturnEffect (if available) for parallax/rotation interactions - saturn?.handleMouseMove(e.clientX); - }; - - const handleSaturnMouseDown = (e: React.MouseEvent) => { - saturn?.handleMouseDown(e.clientX); - }; - - const handleSaturnMouseUp = () => { - saturn?.handleMouseUp(); - }; - - const handleSaturnMouseLeave = () => { - // Treat leaving the area as mouse-up for the effect - saturn?.handleMouseUp(); - }; - - const handleSaturnTouchStart = (e: React.TouchEvent) => { - if (e.touches && e.touches.length === 1) { - const clientX = e.touches[0].clientX; - saturn?.handleTouchStart(clientX); - } - }; - - const handleSaturnTouchMove = (e: React.TouchEvent) => { - if (e.touches && e.touches.length === 1) { - const clientX = e.touches[0].clientX; - saturn?.handleTouchMove(clientX); - } - }; - - const handleSaturnTouchEnd = () => { - saturn?.handleTouchEnd(); - }; - - return ( -
- {/* Hero Section (Full Height) - Interactive area */} -
- {/* 3D Floating Hero Text */} -
-
-
- - Launcher Active - -
- -

- MINECRAFT -

- -
-
- Java Edition -
-
-
- - {/* Action Area */} -
-
- > Ready to launch session. -
-
- - -
-
- ); -} diff --git a/packages/ui/src/pages/home.tsx b/packages/ui/src/pages/home.tsx new file mode 100644 index 0000000..dc1413d --- /dev/null +++ b/packages/ui/src/pages/home.tsx @@ -0,0 +1,102 @@ +import { useState } from "react"; +import { BottomBar } from "@/components/bottom-bar"; +import { useSaturnEffect } from "@/components/particle-background"; + +export function HomePage() { + const [mouseX, setMouseX] = useState(0); + const [mouseY, setMouseY] = useState(0); + const saturn = useSaturnEffect(); + + const handleMouseMove = (e: React.MouseEvent) => { + const x = (e.clientX / window.innerWidth) * 2 - 1; + const y = (e.clientY / window.innerHeight) * 2 - 1; + setMouseX(x); + setMouseY(y); + + // Forward mouse move to SaturnEffect (if available) for parallax/rotation interactions + saturn?.handleMouseMove(e.clientX); + }; + + const handleSaturnMouseDown = (e: React.MouseEvent) => { + saturn?.handleMouseDown(e.clientX); + }; + + const handleSaturnMouseUp = () => { + saturn?.handleMouseUp(); + }; + + const handleSaturnMouseLeave = () => { + // Treat leaving the area as mouse-up for the effect + saturn?.handleMouseUp(); + }; + + const handleSaturnTouchStart = (e: React.TouchEvent) => { + if (e.touches && e.touches.length === 1) { + const clientX = e.touches[0].clientX; + saturn?.handleTouchStart(clientX); + } + }; + + const handleSaturnTouchMove = (e: React.TouchEvent) => { + if (e.touches && e.touches.length === 1) { + const clientX = e.touches[0].clientX; + saturn?.handleTouchMove(clientX); + } + }; + + const handleSaturnTouchEnd = () => { + saturn?.handleTouchEnd(); + }; + + return ( +
+ {/* Hero Section (Full Height) - Interactive area */} +
+ {/* 3D Floating Hero Text */} +
+
+
+ + Launcher Active + +
+ +

+ MINECRAFT +

+ +
+
+ Java Edition +
+
+
+ + {/* Action Area */} +
+
+ > Ready to launch session. +
+
+ + +
+
+ ); +} diff --git a/packages/ui/src/pages/index.tsx b/packages/ui/src/pages/index.tsx index 2acd377..d12646b 100644 --- a/packages/ui/src/pages/index.tsx +++ b/packages/ui/src/pages/index.tsx @@ -5,13 +5,11 @@ import { Sidebar } from "@/components/sidebar"; import { useAuthStore } from "@/models/auth"; import { useInstanceStore } from "@/models/instance"; import { useSettingsStore } from "@/models/settings"; -import { useGameStore } from "@/stores/game-store"; export function IndexPage() { const authStore = useAuthStore(); const settingsStore = useSettingsStore(); const instanceStore = useInstanceStore(); - const initGameLifecycle = useGameStore((state) => state.initLifecycle); const location = useLocation(); @@ -19,15 +17,7 @@ export function IndexPage() { authStore.init(); settingsStore.refresh(); instanceStore.refresh(); - void initGameLifecycle().catch((error) => { - console.error("Failed to initialize game lifecycle:", error); - }); - }, [ - authStore.init, - settingsStore.refresh, - instanceStore.refresh, - initGameLifecycle, - ]); + }, [authStore.init, settingsStore.refresh, instanceStore.refresh]); return (
diff --git a/packages/ui/src/pages/instances-view.tsx b/packages/ui/src/pages/instances-view.tsx deleted file mode 100644 index 7bb3302..0000000 --- a/packages/ui/src/pages/instances-view.tsx +++ /dev/null @@ -1,457 +0,0 @@ -import { open, save } from "@tauri-apps/plugin-dialog"; -import { - CopyIcon, - EditIcon, - FolderOpenIcon, - Plus, - RocketIcon, - Trash2Icon, - XIcon, -} from "lucide-react"; -import { useEffect, useState } from "react"; -import { toast } from "sonner"; -import { openFileExplorer } from "@/client"; -import InstanceCreationModal from "@/components/instance-creation-modal"; -import InstanceEditorModal from "@/components/instance-editor-modal"; -import { Button } from "@/components/ui/button"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; -import { Input } from "@/components/ui/input"; -import { cn } from "@/lib/utils"; -import { useAuthStore } from "@/models/auth"; -import { useInstanceStore } from "@/models/instance"; -import { useGameStore } from "@/stores/game-store"; -import type { Instance } from "@/types"; - -export function InstancesView() { - const account = useAuthStore((state) => state.account); - const instancesStore = useInstanceStore(); - const startGame = useGameStore((state) => state.startGame); - const stopGame = useGameStore((state) => state.stopGame); - const runningInstanceId = useGameStore((state) => state.runningInstanceId); - const launchingInstanceId = useGameStore( - (state) => state.launchingInstanceId, - ); - const stoppingInstanceId = useGameStore((state) => state.stoppingInstanceId); - const [isImporting, setIsImporting] = useState(false); - const [repairing, setRepairing] = useState(false); - const [exportingId, setExportingId] = useState(null); - - // Modal / UI state - const [showCreateModal, setShowCreateModal] = useState(false); - const [showEditModal, setShowEditModal] = useState(false); - const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); - const [showDuplicateModal, setShowDuplicateModal] = useState(false); - - // Selected / editing instance state - const [selectedInstance, setSelectedInstance] = useState( - null, - ); - const [editingInstance, setEditingInstance] = useState(null); - - // Form fields - const [duplicateName, setDuplicateName] = useState(""); - - useEffect(() => { - instancesStore.refresh(); - }, [instancesStore.refresh]); - - // Handlers to open modals - const openCreate = () => { - setShowCreateModal(true); - }; - - const openEdit = (instance: Instance) => { - setEditingInstance({ ...instance }); - setShowEditModal(true); - }; - - const openDelete = (instance: Instance) => { - setSelectedInstance(instance); - setShowDeleteConfirm(true); - }; - - const openDuplicate = (instance: Instance) => { - setSelectedInstance(instance); - setDuplicateName(`${instance.name} (Copy)`); - setShowDuplicateModal(true); - }; - - const confirmDelete = async () => { - if (!selectedInstance) return; - await instancesStore.delete(selectedInstance.id); - setSelectedInstance(null); - setShowDeleteConfirm(false); - }; - - const confirmDuplicate = async () => { - if (!selectedInstance) return; - const name = duplicateName.trim(); - if (!name) return; - await instancesStore.duplicate(selectedInstance.id, name); - setSelectedInstance(null); - setDuplicateName(""); - setShowDuplicateModal(false); - }; - - const handleImport = async () => { - setIsImporting(true); - try { - const selected = await open({ - multiple: false, - filters: [{ name: "Zip Archive", extensions: ["zip"] }], - }); - - if (typeof selected !== "string") { - return; - } - - await instancesStore.importArchive(selected); - } finally { - setIsImporting(false); - } - }; - - const handleRepair = async () => { - setRepairing(true); - try { - await instancesStore.repair(); - } finally { - setRepairing(false); - } - }; - - const handleExport = async (instance: Instance) => { - setExportingId(instance.id); - try { - const filePath = await save({ - defaultPath: `${instance.name.replace(/[\\/:*?"<>|]/g, "_")}.zip`, - filters: [{ name: "Zip Archive", extensions: ["zip"] }], - }); - - if (!filePath) { - return; - } - - await instancesStore.exportArchive(instance.id, filePath); - } finally { - setExportingId(null); - } - }; - - return ( -
-
-

- Instances -

-
- - - -
-
- - {instancesStore.instances.length === 0 ? ( -
-
-

No instances yet

-

Create your first instance to get started

-
-
- ) : ( -
    - {instancesStore.instances.map((instance) => { - const isActive = instancesStore.activeInstance?.id === instance.id; - const isRunning = runningInstanceId === instance.id; - const isLaunching = launchingInstanceId === instance.id; - const isStopping = stoppingInstanceId === instance.id; - const otherInstanceRunning = - runningInstanceId !== null && !isRunning; - - return ( -
  • instancesStore.setActiveInstance(instance)} - onKeyDown={async (e) => { - if (e.key === "Enter") { - try { - await instancesStore.setActiveInstance(instance); - } catch (e) { - console.error("Failed to set active instance:", e); - toast.error("Error setting active instance"); - } - } - }} - className="cursor-pointer" - > -
    -
    - {instance.iconPath ? ( -
    - {instance.name} -
    - ) : ( -
    - - {instance.name.charAt(0).toUpperCase()} - -
    - )} - -
    -

    {instance.name}

    - {instance.versionId ? ( -

    - {instance.versionId} -

    - ) : ( -

    - No version selected -

    - )} -
    -
    - -
    -
    - - - - - - -
    -
    -
    -
  • - ); - })} -
- )} - - - - { - setShowEditModal(open); - if (!open) setEditingInstance(null); - }} - /> - - {/* Delete Confirmation */} - - - - Delete Instance - - Are you sure you want to delete "{selectedInstance?.name}"? This - action cannot be undone. - - - - - - - - - - - {/* Duplicate Modal */} - - - - Duplicate Instance - - Provide a name for the duplicated instance. - - - -
- setDuplicateName(e.target.value)} - placeholder="New instance name" - onKeyDown={(e) => e.key === "Enter" && confirmDuplicate()} - /> -
- - - - - -
-
-
- ); -} diff --git a/packages/ui/src/pages/routes.ts b/packages/ui/src/pages/routes.ts index 8d105d4..55eb8fd 100644 --- a/packages/ui/src/pages/routes.ts +++ b/packages/ui/src/pages/routes.ts @@ -1,6 +1,6 @@ import { createHashRouter } from "react-router"; -import { IndexPage } from "."; -import { HomeView } from "./home-view"; +import { HomePage } from "./home"; +import { IndexPage } from "./index"; import instanceRoute from "./instances/routes"; import { SettingsPage } from "./settings"; @@ -11,7 +11,7 @@ const router = createHashRouter([ children: [ { index: true, - Component: HomeView, + Component: HomePage, }, { path: "settings", -- cgit v1.2.3-70-g09d2