feat: full screen node
This commit is contained in:
@@ -51,6 +51,11 @@ import {
|
||||
EmptyTitle,
|
||||
} from '@/components/ui/empty'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog'
|
||||
import { ClipboardPaste, FolderOpen, FileStack, CircleDotDashed } from 'lucide-react'
|
||||
import { DEFAULT_NODE_STYLE, getDefaultDataForType, getNextNodeId } from '@/lib/flowUtils'
|
||||
import {
|
||||
@@ -58,6 +63,7 @@ import {
|
||||
getRegisteredNodeTypesGroupedByClassification,
|
||||
getRegisteredNodeTypeIds,
|
||||
getDefaultStyle,
|
||||
getNodeType,
|
||||
isConnectionAllowed,
|
||||
} from '@/lib/nodeRegistry'
|
||||
import type { AppNode, AppEdge } from '@/lib/nodeTypes'
|
||||
@@ -131,6 +137,70 @@ function FlowFitViewOnLoad() {
|
||||
return null
|
||||
}
|
||||
|
||||
type FullscreenNodeOverlayProps = {
|
||||
nodeId: string
|
||||
nodes: AppNode[]
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
function FullscreenNodeOverlay({ nodeId, nodes, onClose }: FullscreenNodeOverlayProps) {
|
||||
const open = nodeId != null
|
||||
const node = nodes.find((n) => n.id === nodeId)
|
||||
if (!nodeId) return null
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={(isOpen) => { if (!isOpen) onClose() }}>
|
||||
<DialogContent
|
||||
className="max-w-[94vw] w-[94vw] max-h-[90vh] h-[90vh] p-0 gap-0 overflow-hidden flex flex-col border rounded-lg shadow-xl bg-card"
|
||||
aria-describedby={undefined}
|
||||
hideCloseButton
|
||||
>
|
||||
<DialogTitle className="sr-only">Node: {node?.id ?? nodeId}</DialogTitle>
|
||||
{node && node.type && (
|
||||
<FullscreenNodeContent node={node} />
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
function FullscreenNodeContent({ node }: { node: AppNode }) {
|
||||
const descriptor = getNodeType(node.type ?? '')
|
||||
const NodeComponent = descriptor?.component as React.ComponentType<{
|
||||
id: string
|
||||
data: Record<string, unknown>
|
||||
type?: string
|
||||
selected?: boolean
|
||||
width?: number
|
||||
height?: number
|
||||
}> | undefined
|
||||
if (!NodeComponent) return null
|
||||
|
||||
const w = typeof window !== 'undefined' ? Math.round(window.innerWidth * 0.94) : 1200
|
||||
const h = typeof window !== 'undefined' ? Math.round(window.innerHeight * 0.9) : 800
|
||||
|
||||
const fullscreenNodeForStore: AppNode = {
|
||||
...node,
|
||||
position: node.position ?? { x: 0, y: 0 },
|
||||
style: { ...(node.style as object), width: w, height: h },
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex-1 min-h-0 overflow-hidden flex">
|
||||
<ReactFlowProvider initialNodes={[fullscreenNodeForStore]} initialEdges={[]}>
|
||||
<NodeComponent
|
||||
id={node.id}
|
||||
data={(node.data as Record<string, unknown>) ?? {}}
|
||||
type={node.type}
|
||||
selected={false}
|
||||
width={w}
|
||||
height={h}
|
||||
/>
|
||||
</ReactFlowProvider>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export type CanvasPageProps = {
|
||||
/** Optional project id for future per-project graph loading */
|
||||
projectId?: string
|
||||
@@ -193,6 +263,7 @@ export function CanvasPage({ projectId }: CanvasPageProps) {
|
||||
const [isPanning, setIsPanning] = React.useState(false)
|
||||
const [isSelecting, setIsSelecting] = React.useState(false)
|
||||
const [ariaAnnouncement, setAriaAnnouncement] = React.useState<string | null>(null)
|
||||
const [fullscreenNodeId, setFullscreenNodeId] = React.useState<string | null>(null)
|
||||
const nodesRef = useRef(nodes)
|
||||
nodesRef.current = nodes
|
||||
|
||||
@@ -412,6 +483,8 @@ export function CanvasPage({ projectId }: CanvasPageProps) {
|
||||
setConnectionFrom,
|
||||
isValidConnection,
|
||||
flowActionsRef,
|
||||
fullscreenNodeId,
|
||||
setFullscreenNodeId,
|
||||
}),
|
||||
[
|
||||
nodes,
|
||||
@@ -424,6 +497,8 @@ export function CanvasPage({ projectId }: CanvasPageProps) {
|
||||
setConnectionFrom,
|
||||
isValidConnection,
|
||||
flowActionsRef,
|
||||
fullscreenNodeId,
|
||||
setFullscreenNodeId,
|
||||
]
|
||||
)
|
||||
|
||||
@@ -707,6 +782,13 @@ export function CanvasPage({ projectId }: CanvasPageProps) {
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuContent>
|
||||
</ContextMenu>
|
||||
{fullscreenNodeId && (
|
||||
<FullscreenNodeOverlay
|
||||
nodeId={fullscreenNodeId}
|
||||
nodes={nodes}
|
||||
onClose={() => setFullscreenNodeId(null)}
|
||||
/>
|
||||
)}
|
||||
</FlowContext.Provider>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user