diff options
| author | 2026-03-29 00:54:21 +0800 | |
|---|---|---|
| committer | 2026-03-29 00:54:21 +0800 | |
| commit | 97fe5046f68b5e4ee5f750945bcc39a27f5eb37b (patch) | |
| tree | b5263ff32f888a0631fe4ae8a22bcbb7a80ed1f7 /packages/ui/src/components | |
| parent | 2412f7a3a626fc3b9e7b59ce1fc900468b792972 (diff) | |
| download | DropOut-97fe5046f68b5e4ee5f750945bcc39a27f5eb37b.tar.gz DropOut-97fe5046f68b5e4ee5f750945bcc39a27f5eb37b.zip | |
chore(ui): refactor effect instance check
Diffstat (limited to 'packages/ui/src/components')
| -rw-r--r-- | packages/ui/src/components/instance-editor-modal.tsx | 18 | ||||
| -rw-r--r-- | packages/ui/src/components/sidebar.tsx | 12 | ||||
| -rw-r--r-- | packages/ui/src/components/ui/alert-dialog.tsx | 186 |
3 files changed, 199 insertions, 17 deletions
diff --git a/packages/ui/src/components/instance-editor-modal.tsx b/packages/ui/src/components/instance-editor-modal.tsx index d964185..2a2bd7d 100644 --- a/packages/ui/src/components/instance-editor-modal.tsx +++ b/packages/ui/src/components/instance-editor-modal.tsx @@ -1,8 +1,8 @@ -import { invoke } from "@tauri-apps/api/core"; + +import { toNumber } from "es-toolkit/compat"; import { Folder, Loader2, Save, Trash2, X } from "lucide-react"; import { useCallback, useEffect, useState } from "react"; import { toast } from "sonner"; - import { Button } from "@/components/ui/button"; import { Dialog, @@ -14,12 +14,11 @@ import { } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; - -import { toNumber } from "@/lib/tsrs-utils"; import { useInstanceStore } from "@/models/instance"; import { useSettingsStore } from "@/models/settings"; import type { FileInfo } from "../types/bindings/core"; import type { Instance } from "../types/bindings/instance"; +import { deleteInstanceFile, listInstanceDirectory, openFileExplorer } from "@/client"; type Props = { open: boolean; @@ -94,11 +93,8 @@ export function InstanceEditorModal({ open, instance, onOpenChange }: Props) { if (!instance) return; setLoadingFiles(true); try { - const files = await invoke<FileInfo[]>("list_instance_directory", { - instanceId: instance.id, - folder, - }); - setFileList(files || []); + const files = await listInstanceDirectory(instance.id, folder); + setFileList(files); } catch (err) { console.error("Failed to load files:", err); toast.error("Failed to load files: " + String(err)); @@ -135,7 +131,7 @@ export function InstanceEditorModal({ open, instance, onOpenChange }: Props) { } setDeletingPath(filePath); try { - await invoke("delete_instance_file", { path: filePath }); + await deleteInstanceFile(filePath); // refresh the currently selected folder await loadFileList(selectedFileFolder); toast.success("Deleted"); @@ -149,7 +145,7 @@ export function InstanceEditorModal({ open, instance, onOpenChange }: Props) { async function openInExplorer(filePath: string) { try { - await invoke("open_file_explorer", { path: filePath }); + await openFileExplorer(filePath); } catch (err) { console.error("Failed to open in explorer:", err); toast.error("Failed to open file explorer: " + String(err)); diff --git a/packages/ui/src/components/sidebar.tsx b/packages/ui/src/components/sidebar.tsx index d81156f..e615274 100644 --- a/packages/ui/src/components/sidebar.tsx +++ b/packages/ui/src/components/sidebar.tsx @@ -23,10 +23,6 @@ function NavItem({ Icon, label, to }: NavItemProps) { const location = useLocation(); const isActive = location.pathname === to; - const handleClick = () => { - navigate(to); - }; - return ( <Button variant="ghost" @@ -35,7 +31,7 @@ function NavItem({ Icon, label, to }: NavItemProps) { isActive && "relative bg-accent", )} size="lg" - onClick={handleClick} + onClick={() => navigate(to)} > <Icon className="size-5" strokeWidth={isActive ? 2.5 : 2} /> <span className="hidden lg:block text-sm relative z-10">{label}</span> @@ -185,7 +181,11 @@ export function Sidebar() { <div className="w-full lg:px-3 flex-1 flex flex-col justify-end"> <DropdownMenu> - <DropdownMenuTrigger render={renderUserAvatar()} className="w-full"> + <DropdownMenuTrigger + render={renderUserAvatar()} + nativeButton={false} + className="w-full" + > Open </DropdownMenuTrigger> <DropdownMenuContent align="end" side="right" sideOffset={20}> diff --git a/packages/ui/src/components/ui/alert-dialog.tsx b/packages/ui/src/components/ui/alert-dialog.tsx new file mode 100644 index 0000000..27c9f77 --- /dev/null +++ b/packages/ui/src/components/ui/alert-dialog.tsx @@ -0,0 +1,186 @@ +"use client"; + +import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog"; +import type * as React from "react"; +import { Button } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; + +function AlertDialog({ ...props }: AlertDialogPrimitive.Root.Props) { + return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />; +} + +function AlertDialogTrigger({ ...props }: AlertDialogPrimitive.Trigger.Props) { + return ( + <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} /> + ); +} + +function AlertDialogPortal({ ...props }: AlertDialogPrimitive.Portal.Props) { + return ( + <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} /> + ); +} + +function AlertDialogOverlay({ + className, + ...props +}: AlertDialogPrimitive.Backdrop.Props) { + return ( + <AlertDialogPrimitive.Backdrop + data-slot="alert-dialog-overlay" + className={cn( + "fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0", + className, + )} + {...props} + /> + ); +} + +function AlertDialogContent({ + className, + size = "default", + ...props +}: AlertDialogPrimitive.Popup.Props & { + size?: "default" | "sm"; +}) { + return ( + <AlertDialogPortal> + <AlertDialogOverlay /> + <AlertDialogPrimitive.Popup + data-slot="alert-dialog-content" + data-size={size} + className={cn( + "group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-4 rounded-none bg-background p-4 ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", + className, + )} + {...props} + /> + </AlertDialogPortal> + ); +} + +function AlertDialogHeader({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( + <div + data-slot="alert-dialog-header" + className={cn( + "grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]", + className, + )} + {...props} + /> + ); +} + +function AlertDialogFooter({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( + <div + data-slot="alert-dialog-footer" + className={cn( + "flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end", + className, + )} + {...props} + /> + ); +} + +function AlertDialogMedia({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( + <div + data-slot="alert-dialog-media" + className={cn( + "mb-2 inline-flex size-10 items-center justify-center rounded-none bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-6", + className, + )} + {...props} + /> + ); +} + +function AlertDialogTitle({ + className, + ...props +}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) { + return ( + <AlertDialogPrimitive.Title + data-slot="alert-dialog-title" + className={cn( + "text-sm font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2", + className, + )} + {...props} + /> + ); +} + +function AlertDialogDescription({ + className, + ...props +}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) { + return ( + <AlertDialogPrimitive.Description + data-slot="alert-dialog-description" + className={cn( + "text-xs/relaxed text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground", + className, + )} + {...props} + /> + ); +} + +function AlertDialogAction({ + className, + ...props +}: React.ComponentProps<typeof Button>) { + return ( + <Button + data-slot="alert-dialog-action" + className={cn(className)} + {...props} + /> + ); +} + +function AlertDialogCancel({ + className, + variant = "outline", + size = "default", + ...props +}: AlertDialogPrimitive.Close.Props & + Pick<React.ComponentProps<typeof Button>, "variant" | "size">) { + return ( + <AlertDialogPrimitive.Close + data-slot="alert-dialog-cancel" + className={cn(className)} + render={<Button variant={variant} size={size} />} + {...props} + /> + ); +} + +export { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogMedia, + AlertDialogOverlay, + AlertDialogPortal, + AlertDialogTitle, + AlertDialogTrigger, +}; |