Simplify node library panel collapse behavior
This commit is contained in:
@@ -27,7 +27,6 @@ import {
|
|||||||
PanelLeftOpenIcon,
|
PanelLeftOpenIcon,
|
||||||
} from "lucide-react"
|
} from "lucide-react"
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
|
||||||
import type { PanelImperativeHandle } from "react-resizable-panels"
|
|
||||||
|
|
||||||
import { Badge } from "@/components/ui/badge"
|
import { Badge } from "@/components/ui/badge"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
@@ -167,7 +166,6 @@ export function WorkflowEditor({
|
|||||||
const [selectedNodeId, setSelectedNodeId] = useState<string | null>(null)
|
const [selectedNodeId, setSelectedNodeId] = useState<string | null>(null)
|
||||||
const [nodeLibraryCollapsed, setNodeLibraryCollapsed] = useState(false)
|
const [nodeLibraryCollapsed, setNodeLibraryCollapsed] = useState(false)
|
||||||
const [pendingNodeDrag, setPendingNodeDrag] = useState<PendingNodeDrag | null>(null)
|
const [pendingNodeDrag, setPendingNodeDrag] = useState<PendingNodeDrag | null>(null)
|
||||||
const nodeLibraryPanelRef = useRef<PanelImperativeHandle | null>(null)
|
|
||||||
const canvasRef = useRef<HTMLElement | null>(null)
|
const canvasRef = useRef<HTMLElement | null>(null)
|
||||||
const pendingNodeDragRef = useRef<PendingNodeDrag | null>(null)
|
const pendingNodeDragRef = useRef<PendingNodeDrag | null>(null)
|
||||||
const suppressNextClickRef = useRef(false)
|
const suppressNextClickRef = useRef(false)
|
||||||
@@ -256,23 +254,6 @@ export function WorkflowEditor({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleNodeLibrary = () => {
|
|
||||||
const panel = nodeLibraryPanelRef.current
|
|
||||||
if (!panel) {
|
|
||||||
setNodeLibraryCollapsed((current) => !current)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (panel.isCollapsed()) {
|
|
||||||
panel.expand()
|
|
||||||
setNodeLibraryCollapsed(false)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
panel.collapse()
|
|
||||||
setNodeLibraryCollapsed(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
const dropNodeOnCanvas = useCallback(
|
const dropNodeOnCanvas = useCallback(
|
||||||
(spec: AIWorkflowNodeSpec, x: number, y: number) => {
|
(spec: AIWorkflowNodeSpec, x: number, y: number) => {
|
||||||
if (!flowInstance || !canvasRef.current) {
|
if (!flowInstance || !canvasRef.current) {
|
||||||
@@ -357,70 +338,67 @@ export function WorkflowEditor({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ResizablePanelGroup orientation="horizontal" className="h-full min-h-0">
|
<ResizablePanelGroup orientation="horizontal" className="h-full min-h-0">
|
||||||
|
{!nodeLibraryCollapsed ? (
|
||||||
|
<>
|
||||||
|
<ResizablePanel defaultSize="18%" minSize="12%" maxSize="34%" className="min-h-0">
|
||||||
|
<aside className="h-full min-h-0 bg-muted/20">
|
||||||
|
<ScrollArea className="h-full min-h-0">
|
||||||
|
<div className="p-3">
|
||||||
|
<div className="mb-3 flex items-center justify-between gap-2">
|
||||||
|
<div className="min-w-0 truncate text-sm font-medium">节点库</div>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="size-7 shrink-0 text-muted-foreground hover:text-foreground"
|
||||||
|
onClick={() => setNodeLibraryCollapsed(true)}
|
||||||
|
aria-label="折叠节点库"
|
||||||
|
>
|
||||||
|
<PanelLeftCloseIcon className="size-3.5" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{nodeSpecs.map((spec) => (
|
||||||
|
<button
|
||||||
|
key={spec.type}
|
||||||
|
type="button"
|
||||||
|
onPointerDown={(event) => onNodePointerDown(event, spec)}
|
||||||
|
onClick={() => {
|
||||||
|
if (suppressNextClickRef.current) {
|
||||||
|
suppressNextClickRef.current = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
addNode(spec)
|
||||||
|
}}
|
||||||
|
className="flex w-full cursor-grab rounded-md border bg-background px-3 py-2 text-left text-sm hover:bg-muted active:cursor-grabbing"
|
||||||
|
>
|
||||||
|
<span className="min-w-0">
|
||||||
|
<span className="block truncate font-medium">{spec.title}</span>
|
||||||
|
<span className="mt-1 line-clamp-2 text-xs text-muted-foreground">
|
||||||
|
{spec.description}
|
||||||
|
</span>
|
||||||
|
<span className="mt-1 flex gap-2 text-[11px] text-muted-foreground">
|
||||||
|
<span>输入 {spec.inputSchema?.length ?? 0}</span>
|
||||||
|
<span>输出 {spec.outputSchema?.length ?? 0}</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ScrollArea>
|
||||||
|
</aside>
|
||||||
|
</ResizablePanel>
|
||||||
|
<ResizableHandle withHandle />
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
<ResizablePanel
|
<ResizablePanel
|
||||||
panelRef={nodeLibraryPanelRef}
|
defaultSize={
|
||||||
defaultSize="18%"
|
nodeLibraryCollapsed ? (selectedNode ? "74%" : "100%") : selectedNode ? "56%" : "82%"
|
||||||
minSize="12%"
|
}
|
||||||
maxSize="34%"
|
minSize="30%"
|
||||||
collapsedSize="0%"
|
|
||||||
collapsible
|
|
||||||
onResize={(panelSize: { asPercentage: number }) => {
|
|
||||||
setNodeLibraryCollapsed(panelSize.asPercentage <= 1)
|
|
||||||
}}
|
|
||||||
className="min-h-0"
|
className="min-h-0"
|
||||||
>
|
>
|
||||||
{nodeLibraryCollapsed ? null : (
|
|
||||||
<aside className="h-full min-h-0 bg-muted/20">
|
|
||||||
<ScrollArea className="h-full min-h-0">
|
|
||||||
<div className="p-3">
|
|
||||||
<div className="mb-3 flex items-center justify-between gap-2">
|
|
||||||
<div className="min-w-0 truncate text-sm font-medium">节点库</div>
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
variant="ghost"
|
|
||||||
size="icon"
|
|
||||||
className="size-7 shrink-0 text-muted-foreground hover:text-foreground"
|
|
||||||
onClick={toggleNodeLibrary}
|
|
||||||
aria-label="折叠节点库"
|
|
||||||
>
|
|
||||||
<PanelLeftCloseIcon className="size-3.5" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div className="space-y-2">
|
|
||||||
{nodeSpecs.map((spec) => (
|
|
||||||
<button
|
|
||||||
key={spec.type}
|
|
||||||
type="button"
|
|
||||||
onPointerDown={(event) => onNodePointerDown(event, spec)}
|
|
||||||
onClick={() => {
|
|
||||||
if (suppressNextClickRef.current) {
|
|
||||||
suppressNextClickRef.current = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
addNode(spec)
|
|
||||||
}}
|
|
||||||
className="flex w-full cursor-grab rounded-md border bg-background px-3 py-2 text-left text-sm hover:bg-muted active:cursor-grabbing"
|
|
||||||
>
|
|
||||||
<span className="min-w-0">
|
|
||||||
<span className="block truncate font-medium">{spec.title}</span>
|
|
||||||
<span className="mt-1 line-clamp-2 text-xs text-muted-foreground">
|
|
||||||
{spec.description}
|
|
||||||
</span>
|
|
||||||
<span className="mt-1 flex gap-2 text-[11px] text-muted-foreground">
|
|
||||||
<span>输入 {spec.inputSchema?.length ?? 0}</span>
|
|
||||||
<span>输出 {spec.outputSchema?.length ?? 0}</span>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ScrollArea>
|
|
||||||
</aside>
|
|
||||||
)}
|
|
||||||
</ResizablePanel>
|
|
||||||
<ResizableHandle withHandle />
|
|
||||||
<ResizablePanel defaultSize={selectedNode ? "56%" : "82%"} minSize="30%" className="min-h-0">
|
|
||||||
<section
|
<section
|
||||||
data-workflow-canvas
|
data-workflow-canvas
|
||||||
ref={canvasRef}
|
ref={canvasRef}
|
||||||
@@ -435,7 +413,7 @@ export function WorkflowEditor({
|
|||||||
variant="outline"
|
variant="outline"
|
||||||
size="icon"
|
size="icon"
|
||||||
className="absolute top-12 left-3 z-20 size-7 rounded-full bg-background/95 text-muted-foreground shadow-sm hover:text-foreground"
|
className="absolute top-12 left-3 z-20 size-7 rounded-full bg-background/95 text-muted-foreground shadow-sm hover:text-foreground"
|
||||||
onClick={toggleNodeLibrary}
|
onClick={() => setNodeLibraryCollapsed(false)}
|
||||||
aria-label="展开节点库"
|
aria-label="展开节点库"
|
||||||
>
|
>
|
||||||
<PanelLeftOpenIcon className="size-3.5" />
|
<PanelLeftOpenIcon className="size-3.5" />
|
||||||
|
|||||||
Reference in New Issue
Block a user