From 9430bee86fbf943283eb5a6f63bd750b875ff433 Mon Sep 17 00:00:00 2001 From: 苏向夜 Date: Fri, 23 Jan 2026 20:51:28 +0800 Subject: feat(ui): add new ui project --- packages/ui-new/src/components/bottom-bar.tsx | 269 ++++++++++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100644 packages/ui-new/src/components/bottom-bar.tsx (limited to 'packages/ui-new/src/components/bottom-bar.tsx') diff --git a/packages/ui-new/src/components/bottom-bar.tsx b/packages/ui-new/src/components/bottom-bar.tsx new file mode 100644 index 0000000..a0c2c00 --- /dev/null +++ b/packages/ui-new/src/components/bottom-bar.tsx @@ -0,0 +1,269 @@ +import { invoke } from "@tauri-apps/api/core"; +import { listen, type UnlistenFn } from "@tauri-apps/api/event"; +import { Check, ChevronDown, Play, Terminal, User } from "lucide-react"; +import { useCallback, useEffect, useRef, useState } from "react"; +import { useAuthStore } from "@/stores/auth-store"; +import { useGameStore } from "@/stores/game-store"; +import { useInstancesStore } from "@/stores/instances-store"; +import { useUIStore } from "@/stores/ui-store"; + +interface InstalledVersion { + id: string; + type: string; +} + +export function BottomBar() { + const authStore = useAuthStore(); + const gameStore = useGameStore(); + const instancesStore = useInstancesStore(); + const uiStore = useUIStore(); + + const [isVersionDropdownOpen, setIsVersionDropdownOpen] = useState(false); + const [installedVersions, setInstalledVersions] = useState< + InstalledVersion[] + >([]); + const [isLoadingVersions, setIsLoadingVersions] = useState(true); + + const dropdownRef = useRef(null); + + const loadInstalledVersions = useCallback(async () => { + if (!instancesStore.activeInstanceId) { + setInstalledVersions([]); + setIsLoadingVersions(false); + return; + } + + setIsLoadingVersions(true); + try { + const versions = await invoke( + "list_installed_versions", + { instanceId: instancesStore.activeInstanceId }, + ); + + const installed = versions || []; + setInstalledVersions(installed); + + // If no version is selected but we have installed versions, select the first one + if (!gameStore.selectedVersion && installed.length > 0) { + gameStore.setSelectedVersion(installed[0].id); + } + } catch (error) { + console.error("Failed to load installed versions:", error); + } finally { + setIsLoadingVersions(false); + } + }, [ + instancesStore.activeInstanceId, + gameStore.selectedVersion, + gameStore.setSelectedVersion, + ]); + + useEffect(() => { + loadInstalledVersions(); + + const handleClickOutside = (event: MouseEvent) => { + if ( + dropdownRef.current && + !dropdownRef.current.contains(event.target as Node) + ) { + setIsVersionDropdownOpen(false); + } + }; + + document.addEventListener("mousedown", handleClickOutside); + + // Listen for backend events that should refresh installed versions. + let unlistenDownload: UnlistenFn | null = null; + let unlistenVersionDeleted: UnlistenFn | null = null; + + (async () => { + try { + unlistenDownload = await listen("download-complete", () => { + loadInstalledVersions(); + }); + } catch (err) { + // best-effort: do not break UI if listening fails + // eslint-disable-next-line no-console + console.warn("Failed to attach download-complete listener:", err); + } + + try { + unlistenVersionDeleted = await listen("version-deleted", () => { + loadInstalledVersions(); + }); + } catch (err) { + // eslint-disable-next-line no-console + console.warn("Failed to attach version-deleted listener:", err); + } + })(); + + return () => { + document.removeEventListener("mousedown", handleClickOutside); + try { + if (unlistenDownload) unlistenDownload(); + } catch { + // ignore + } + try { + if (unlistenVersionDeleted) unlistenVersionDeleted(); + } catch { + // ignore + } + }; + }, [loadInstalledVersions]); + + const selectVersion = (id: string) => { + if (id !== "loading" && id !== "empty") { + gameStore.setSelectedVersion(id); + setIsVersionDropdownOpen(false); + } + }; + + const handleStartGame = async () => { + await gameStore.startGame( + authStore.currentAccount, + authStore.openLoginModal, + instancesStore.activeInstanceId, + uiStore.setView, + ); + }; + + const getVersionTypeColor = (type: string) => { + switch (type) { + case "release": + return "bg-emerald-500"; + case "snapshot": + return "bg-amber-500"; + case "old_beta": + return "bg-rose-500"; + case "old_alpha": + return "bg-violet-500"; + default: + return "bg-gray-500"; + } + }; + + const versionOptions = isLoadingVersions + ? [{ id: "loading", type: "loading", label: "Loading..." }] + : installedVersions.length === 0 + ? [{ id: "empty", type: "empty", label: "No versions installed" }] + : installedVersions.map((v) => ({ + ...v, + label: `${v.id}${v.type !== "release" ? ` (${v.type})` : ""}`, + })); + + return ( +
+
+
+ {/* Left: Instance Info */} +
+
+ + Active Instance + + + {instancesStore.activeInstance?.name || "No instance selected"} + +
+ + {/* Version Selector */} +
+ + + {/* Dropdown */} + {isVersionDropdownOpen && ( +
+
+ {versionOptions.map((option) => ( + + ))} +
+
+ )} +
+
+ + {/* Right: Action Buttons */} +
+ {/* Console Toggle */} + + + {/* User Login/Info */} + + + {/* Start Game */} + +
+
+
+
+ ); +} -- cgit v1.2.3-70-g09d2