aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/packages/ui/src/components
diff options
context:
space:
mode:
author苏向夜 <fu050409@163.com>2026-03-29 00:54:21 +0800
committer苏向夜 <fu050409@163.com>2026-03-29 00:54:21 +0800
commit97fe5046f68b5e4ee5f750945bcc39a27f5eb37b (patch)
treeb5263ff32f888a0631fe4ae8a22bcbb7a80ed1f7 /packages/ui/src/components
parent2412f7a3a626fc3b9e7b59ce1fc900468b792972 (diff)
downloadDropOut-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.tsx18
-rw-r--r--packages/ui/src/components/sidebar.tsx12
-rw-r--r--packages/ui/src/components/ui/alert-dialog.tsx186
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,
+};