Skip to content

Commit

Permalink
feat(workflow): support panel slots
Browse files Browse the repository at this point in the history
  • Loading branch information
qianmoQ committed Dec 8, 2024
1 parent 5b6c70f commit 126bc03
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 44 deletions.
16 changes: 13 additions & 3 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
<template>
Current Workflow: {{ workflowState }}

<ShadcnWorkflowEditor v-model="workflowState" :categories="categories" :nodes="nodes" :connections="[]"/>
<ShadcnWorkflowEditor v-model="workflowState"
:categories="categories"
:nodes="nodes"
:connections="[]"
:search-text="searchText">
<template #panel-search>
<div class="p-4 border-b border-gray-200">
<ShadcnInput v-model="searchText" placeholder="Search"/>
</div>
</template>
</ShadcnWorkflowEditor>
</template>

<script setup lang="ts">
import { ref } from 'vue'
const categories = ['Input Node', 'Transform Node', 'Output Node']
const searchText = ref('')
const workflowState = ref({
nodes: [],
connections: []
})
const nodes: [] = [
const nodes: any[] = [
{
id: 'start',
category: 'Input Node',
Expand Down
25 changes: 23 additions & 2 deletions src/ui/workflow/ShadcnWorkflowEditor.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
<template>
<div class="flex h-screen">
<ShadcnWorkflowPanel class="w-64 border-r" :categories="props.categories" :nodes="props.nodes"/>
<ShadcnWorkflowPanel :categories="props.categories"
:nodes="props.nodes"
:search-text="props.searchText"
class="w-64 border-r"
@update:search-text="(text: string) => emit('update:searchText', text)">
<template #search>
<slot name="panel-search"/>
</template>

<template #category-header="{ category }">
<slot :category="category" name="panel-category-header"/>
</template>

<template #node="{ node, onDragStart }">
<slot :node="node" :onDragStart="onDragStart" name="panel-node"/>
</template>

<template #bottom>
<slot name="panel-bottom"/>
</template>
</ShadcnWorkflowPanel>

<ShadcnWorkflowCanvas class="flex-1"
:nodes="localNodes"
Expand All @@ -27,7 +47,8 @@ const props = withDefaults(defineProps<WorkflowProps>(), {
nodes: () => [],
connections: () => [],
categories: () => [],
modelValue: () => ({ nodes: [], connections: [] })
modelValue: () => ({ nodes: [], connections: [] }),
searchText: ''
})
const emit = defineEmits<WorkflowEmits>()
Expand Down
90 changes: 52 additions & 38 deletions src/ui/workflow/components/ShadcnWorkflowPanel.vue
Original file line number Diff line number Diff line change
@@ -1,59 +1,81 @@
<template>
<div class="h-full flex flex-col">
<!-- 搜索框 -->
<!-- Search box -->
<div class="p-4 border-b border-gray-200">
<ShadcnInput v-model="searchText" :placeholder="String(t('workflow.placeholder.search'))"/>
</div>
<!-- 搜索框 slot -->
<!-- Search box slot -->
<slot name="search">
<div class="p-4 border-b border-gray-200">
<ShadcnInput v-model="searchText" :placeholder="String(t('workflow.placeholder.search'))"/>
</div>
</slot>

<!-- 分类列表 -->
<!-- Category list -->
<div class="flex-1 overflow-y-auto">
<div v-for="catagory in categories" :key="catagory" class="mb-4">
<div class="px-4 py-2 font-medium text-gray-600 bg-gray-50">{{ catagory }}</div>
<div v-for="category in categories" :key="category" class="mb-4">
<!-- 分类标题 slot -->
<!-- Category title slot -->
<slot :category="category" name="category-header">
<div class="px-4 py-2 font-medium text-gray-600 bg-gray-50">{{ category }}</div>
</slot>

<!-- 节点列表 -->
<!-- Node list -->
<div class="p-2">
<div v-for="node in filteredNodes(catagory)"
class="p-3 mb-2 border border-gray-200 rounded-lg shadow-sm cursor-move hover:border-blue-500"
draggable="true"
:key="node.id"
@dragstart="handleDragStart(node, $event)">
<div class="font-medium text-sm">{{ node.category }}</div>
<div v-for="node in filteredNodes(category)"
:key="node.id">
<!-- 节点内容 slot -->
<!-- Node content slot -->
<slot :node="node" :onDragStart="handleDragStart" name="node">
<div class="p-3 mb-2 border border-gray-200 rounded-lg shadow-sm cursor-move hover:border-blue-500"
draggable="true"
@dragstart="handleDragStart(node, $event)">
<div class="font-medium text-sm">{{ node.category }}</div>

<div class="text-xs text-gray-500 mt-1">
{{ node.description || '暂无描述' }}
</div>
<div class="text-xs text-gray-500 mt-1">
{{ node.description || '暂无描述' }}
</div>

<!-- 端口预览 -->
<!-- Port preview -->
<div class="mt-2 flex justify-between text-xs text-gray-400">
<div v-if="node.ports.some(p => p.type === WorkflowPortType.input)">
{{ t('workflow.text.input') }}: {{ node.ports.filter(p => p.type === WorkflowPortType.input).length }}
</div>
<div v-if="node.ports.some(p => p.type === WorkflowPortType.output)">
{{ t('workflow.text.output') }}: {{ node.ports.filter(p => p.type === WorkflowPortType.output).length }}
<!-- 端口预览 -->
<!-- Port preview -->
<div class="mt-2 flex justify-between text-xs text-gray-400">
<div v-if="node.ports.some(p => p.type === WorkflowPortType.input)">
{{ t('workflow.text.input') }}: {{ node.ports.filter(p => p.type === WorkflowPortType.input).length }}
</div>
<div v-if="node.ports.some(p => p.type === WorkflowPortType.output)">
{{ t('workflow.text.output') }}: {{ node.ports.filter(p => p.type === WorkflowPortType.output).length }}
</div>
</div>
</div>
</div>
</slot>
</div>
</div>
</div>
</div>

<!-- 底部 slot -->
<!-- Bottom slot -->
<slot name="bottom"></slot>
</div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { t } from '@/utils/locale'
import { WorkflowNode, WorkflowPanelEmits, WorkflowPanelProps, WorkflowPortType } from '../types'
import ShadcnInput from '@/ui/input'
import { randomUUID } from '@/utils/uuid.ts'
import { ref, watch } from 'vue'
const emit = defineEmits<WorkflowPanelEmits>()
const props = withDefaults(defineProps<WorkflowPanelProps>(), {
searchText: ''
})
const props = defineProps<WorkflowPanelProps>()
const emits = defineEmits<WorkflowPanelEmits>()
const searchText = ref(props.searchText)
const searchText = ref('')
watch(() => props.searchText, (value) => {
searchText.value = value
emit('update:searchText', value)
})
// 根据分类过滤节点
// Filter nodes by category
Expand All @@ -69,21 +91,15 @@ const filteredNodes = (currentCategory: string) => {
// Handle node dragging
const handleDragStart = (node: WorkflowNode, event: DragEvent) => {
if (event.dataTransfer) {
// 创建新的节点数据,确保id是唯一的
// Create a new node data, ensuring the id is unique
const newNode = {
...node,
id: randomUUID(),
position: { x: 0, y: 0 }
}
// 使用特定的 MIME 类型
// Use a specific MIME type
event.dataTransfer.setData('application/node', JSON.stringify(newNode))
event.dataTransfer.effectAllowed = 'copy'
// 创建拖拽预览
// Create drag preview
const preview = document.createElement('div')
preview.className = 'bg-white border border-gray-200 rounded-lg p-2 shadow-lg'
preview.textContent = node.category
Expand All @@ -92,13 +108,11 @@ const handleDragStart = (node: WorkflowNode, event: DragEvent) => {
document.body.appendChild(preview)
event.dataTransfer.setDragImage(preview, 0, 0)
// 清理预览元素
// Cleanup preview element
requestAnimationFrame(() => {
document.body.removeChild(preview)
})
emits('on-node-drag-start', node)
emit('on-node-drag-start', node)
}
}
</script>
6 changes: 5 additions & 1 deletion src/ui/workflow/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,11 @@ export interface WorkflowPanelProps
{
nodes: WorkflowNode[]
categories: string[]
searchText: string
}

export type WorkflowPanelEmits = {
(e: 'update:searchText', value: string): void
(e: 'on-node-drag-start', node: WorkflowNode): void
}

Expand Down Expand Up @@ -97,11 +99,13 @@ export interface WorkflowProps
}
nodes: WorkflowNode[]
connections: WorkflowConnection[]
categories: string[]
categories: string[],
searchText?: string
}

export type WorkflowEmits = {
(e: 'update:modelValue', value: { nodes: WorkflowNode[], connections: WorkflowConnection[] }): void
(e: 'update:searchText', value: string): void
(e: 'on-node-moved', node: WorkflowNode): void
(e: 'on-node-added', node: WorkflowNode): void
(e: 'on-node-selected', node: WorkflowNode): void
Expand Down

0 comments on commit 126bc03

Please sign in to comment.