add node-control

This commit is contained in:
StyleZhang
2024-02-20 16:58:02 +08:00
parent 92219b5aad
commit f14a5c7346
16 changed files with 276 additions and 2 deletions

View File

@@ -0,0 +1,5 @@
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="plus">
<path id="Icon" d="M5.00004 2.08325V7.91659M2.08337 4.99992H7.91671" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 274 B

View File

@@ -0,0 +1,5 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Icon">
<path id="Icon_2" d="M2.5 2.49482C2.5 2.00924 2.5 1.76644 2.60125 1.63261C2.68945 1.51601 2.82426 1.44386 2.9702 1.43515C3.13772 1.42515 3.33973 1.55982 3.74376 1.82918L9.00154 5.33436C9.33538 5.55693 9.5023 5.66821 9.56047 5.80847C9.61133 5.9311 9.61133 6.06891 9.56047 6.19154C9.5023 6.3318 9.33538 6.44308 9.00154 6.66564L3.74376 10.1708C3.33973 10.4402 3.13772 10.5749 2.9702 10.5649C2.82426 10.5561 2.68945 10.484 2.60125 10.3674C2.5 10.2336 2.5 9.99077 2.5 9.50519V2.49482Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 689 B

View File

@@ -0,0 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Icon" clip-path="url(#clip0_467_1645)">
<path id="Icon_2" d="M1.5 3.9C1.5 3.05992 1.5 2.63988 1.66349 2.31901C1.8073 2.03677 2.03677 1.8073 2.31901 1.66349C2.63988 1.5 3.05992 1.5 3.9 1.5H8.1C8.94008 1.5 9.36012 1.5 9.68099 1.66349C9.96323 1.8073 10.1927 2.03677 10.3365 2.31901C10.5 2.63988 10.5 3.05992 10.5 3.9V8.1C10.5 8.94008 10.5 9.36012 10.3365 9.68099C10.1927 9.96323 9.96323 10.1927 9.68099 10.3365C9.36012 10.5 8.94008 10.5 8.1 10.5H3.9C3.05992 10.5 2.63988 10.5 2.31901 10.3365C2.03677 10.1927 1.8073 9.96323 1.66349 9.68099C1.5 9.36012 1.5 8.94008 1.5 8.1V3.9Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_467_1645">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 877 B

View File

@@ -0,0 +1,39 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "10",
"height": "10",
"viewBox": "0 0 10 10",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "g",
"attributes": {
"id": "plus"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"id": "Icon",
"d": "M5.00004 2.08325V7.91659M2.08337 4.99992H7.91671",
"stroke": "currentColor",
"stroke-width": "1.5",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
}
]
}
]
},
"name": "Plus02"
}

View File

@@ -0,0 +1,16 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './Plus02.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
props,
ref,
) => <IconBase {...props} ref={ref} data={data as IconData} />)
Icon.displayName = 'Plus02'
export default Icon

View File

@@ -19,6 +19,7 @@ export { default as LogOut04 } from './LogOut04'
export { default as Menu01 } from './Menu01'
export { default as Pin01 } from './Pin01'
export { default as Pin02 } from './Pin02'
export { default as Plus02 } from './Plus02'
export { default as Plus } from './Plus'
export { default as SearchLg } from './SearchLg'
export { default as Settings01 } from './Settings01'

View File

@@ -0,0 +1,39 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "12",
"height": "12",
"viewBox": "0 0 12 12",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "g",
"attributes": {
"id": "Icon"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"id": "Icon_2",
"d": "M2.5 2.49482C2.5 2.00924 2.5 1.76644 2.60125 1.63261C2.68945 1.51601 2.82426 1.44386 2.9702 1.43515C3.13772 1.42515 3.33973 1.55982 3.74376 1.82918L9.00154 5.33436C9.33538 5.55693 9.5023 5.66821 9.56047 5.80847C9.61133 5.9311 9.61133 6.06891 9.56047 6.19154C9.5023 6.3318 9.33538 6.44308 9.00154 6.66564L3.74376 10.1708C3.33973 10.4402 3.13772 10.5749 2.9702 10.5649C2.82426 10.5561 2.68945 10.484 2.60125 10.3674C2.5 10.2336 2.5 9.99077 2.5 9.50519V2.49482Z",
"stroke": "currentColor",
"stroke-width": "1.25",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
}
]
}
]
},
"name": "Play"
}

View File

@@ -0,0 +1,16 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './Play.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
props,
ref,
) => <IconBase {...props} ref={ref} data={data as IconData} />)
Icon.displayName = 'Play'
export default Icon

View File

@@ -0,0 +1,66 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "12",
"height": "12",
"viewBox": "0 0 12 12",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "g",
"attributes": {
"id": "Icon",
"clip-path": "url(#clip0_467_1645)"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"id": "Icon_2",
"d": "M1.5 3.9C1.5 3.05992 1.5 2.63988 1.66349 2.31901C1.8073 2.03677 2.03677 1.8073 2.31901 1.66349C2.63988 1.5 3.05992 1.5 3.9 1.5H8.1C8.94008 1.5 9.36012 1.5 9.68099 1.66349C9.96323 1.8073 10.1927 2.03677 10.3365 2.31901C10.5 2.63988 10.5 3.05992 10.5 3.9V8.1C10.5 8.94008 10.5 9.36012 10.3365 9.68099C10.1927 9.96323 9.96323 10.1927 9.68099 10.3365C9.36012 10.5 8.94008 10.5 8.1 10.5H3.9C3.05992 10.5 2.63988 10.5 2.31901 10.3365C2.03677 10.1927 1.8073 9.96323 1.66349 9.68099C1.5 9.36012 1.5 8.94008 1.5 8.1V3.9Z",
"stroke": "currentColor",
"stroke-width": "1.25",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
}
]
},
{
"type": "element",
"name": "defs",
"attributes": {},
"children": [
{
"type": "element",
"name": "clipPath",
"attributes": {
"id": "clip0_467_1645"
},
"children": [
{
"type": "element",
"name": "rect",
"attributes": {
"width": "12",
"height": "12",
"fill": "white"
},
"children": []
}
]
}
]
}
]
},
"name": "Stop"
}

View File

@@ -0,0 +1,16 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './Stop.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
props,
ref,
) => <IconBase {...props} ref={ref} data={data as IconData} />)
Icon.displayName = 'Stop'
export default Icon

View File

@@ -1,3 +1,5 @@
export { default as Microphone01 } from './Microphone01'
export { default as Play } from './Play'
export { default as SlidersH } from './SlidersH'
export { default as Speaker } from './Speaker'
export { default as Stop } from './Stop'

View File

@@ -18,6 +18,7 @@ export type WorkflowContextValue = {
handleSelectedNodeIdChange: (nodeId: string) => void
selectedNode?: Node
handleAddNextNode: (prevNode: Node, nextNodeType: BlockEnum) => void
handleUpdateNodeData: (nodeId: string, data: Node['data']) => void
}
export const WorkflowContext = createContext<WorkflowContextValue>({
@@ -26,5 +27,6 @@ export const WorkflowContext = createContext<WorkflowContextValue>({
edges: [],
handleSelectedNodeIdChange: () => {},
handleAddNextNode: () => {},
handleUpdateNodeData: () => {},
})
export const useWorkflowContext = () => useContext(WorkflowContext)

View File

@@ -60,10 +60,21 @@ export const useWorkflow = (
})
}, [setNodes, setEdges])
const handleUpdateNodeData = useCallback((nodeId: string, data: Node['data']) => {
setNodes((oldNodes) => {
return produce(oldNodes, (draft) => {
const node = draft.find(node => node.id === nodeId)
if (node)
node.data = data
})
})
}, [setNodes])
return {
selectedNodeId,
selectedNode,
handleSelectedNodeIdChange,
handleAddNextNode,
handleUpdateNodeData,
}
}

View File

@@ -73,6 +73,7 @@ const WorkflowWrap: FC<WorkflowWrapProps> = ({
handleSelectedNodeIdChange,
selectedNode,
handleAddNextNode,
handleUpdateNodeData,
} = useWorkflow(
nodes,
edges,
@@ -90,6 +91,7 @@ const WorkflowWrap: FC<WorkflowWrapProps> = ({
nodes,
edges,
handleAddNextNode,
handleUpdateNodeData,
}}>
<Workflow />
</WorkflowContext.Provider>

View File

@@ -0,0 +1,42 @@
import type { FC } from 'react'
import { memo } from 'react'
import {
DotsHorizontal,
Loading02,
} from '@/app/components/base/icons/src/vender/line/general'
import {
Play,
Stop,
} from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
type NodeControlProps = {
isRunning?: boolean
}
const NodeControl: FC<NodeControlProps> = ({
isRunning,
}) => {
return (
<div className='absolute left-0 -top-7 flex items-center px-0.5 h-6 bg-white rounded-lg border-[0.5px] border-gray-100 shadow-xs text-gray-500'>
{
isRunning && (
<div className='flex items-center px-1 h-5 rounded-md bg-primary-50 text-xs font-medium text-primary-600'>
<Loading02 className='mr-1 w-3 h-3 animate-spin' />
RUNNING
</div>
)
}
<div className='flex items-center justify-center w-5 h-5 cursor-pointer'>
{
isRunning
? <Stop className='w-3 h-3' />
: <Play className='w-3 h-3' />
}
</div>
<div className='flex items-center justify-center w-5 h-5 cursor-pointer'>
<DotsHorizontal className='w-3 h-3' />
</div>
</div>
)
}
export default memo(NodeControl)

View File

@@ -12,8 +12,9 @@ import type { NodeProps } from 'reactflow'
import { getOutgoers } from 'reactflow'
import { useWorkflowContext } from '../../context'
import BlockSelector from '../../block-selector'
import NodeControl from '../../node-control'
import BlockIcon from '../../block-icon'
import { Plus } from '@/app/components/base/icons/src/vender/line/general'
import { Plus02 } from '@/app/components/base/icons/src/vender/line/general'
type BaseNodeProps = {
children: ReactElement
@@ -48,7 +49,7 @@ const BaseNode: FC<BaseNodeProps> = ({
${open && '!flex'}
`}
>
<Plus className='w-2.5 h-2.5 text-white' />
<Plus02 className='w-2.5 h-2.5 text-white' />
</div>
</div>
)
@@ -63,6 +64,7 @@ const BaseNode: FC<BaseNodeProps> = ({
`}
onClick={() => handleSelectedNodeIdChange(nodeId || '')}
>
<NodeControl />
<div className='flex items-center px-3 pt-3 pb-2'>
<BlockIcon
className='mr-2'