feat: draggable button

This commit is contained in:
scarqin
2024-12-23 18:36:12 +08:00
parent e6f6560f3a
commit 57cc9c9db7
4 changed files with 44 additions and 32 deletions
@@ -23,7 +23,10 @@ export const KeyStatusNode: React.FC<{ data: KeyStatusNodeData }> = ({ data }) =
const keyWidth = totalKeys > 5 ? `calc((100% - ${(totalKeys - 1) * 0.25}rem) / ${totalKeys})` : KEY_SIZE
return (
<div className="relative p-4 bg-white rounded-lg shadow-sm node-card">
<div
className="relative p-4 bg-white rounded-lg shadow-sm node-card nodrag"
style={{ border: '1px solid var(--border-color)' }}
>
<Handle type="target" position={Position.Left} />
<div className="flex flex-col gap-2">
<div className="text-sm text-gray-900">{title}</div>
@@ -39,33 +39,35 @@ export const ModelCardNode: React.FC<{ data: ModelCardNodeData }> = ({ data }) =
return (
<div
className="node-card bg-white rounded-lg shadow-sm p-4 min-w-[280px] relative group nodrag"
className="node-card bg-white rounded-lg shadow-sm p-4 min-w-[280px] relative group"
style={{ border: '1px solid var(--border-color)' }}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
<Handle type="target" position={Position.Left} />
<Handle type="source" position={Position.Right} />
<div>
<div className="flex justify-between items-center">
<div className="flex gap-2 items-center">
<Icon icon="mdi:robot" className="text-xl text-[--primary-color]" />
<span className="text-base text-gray-900">{title}</span>
<Icon
icon={status === 'success' ? 'mdi:check-circle' : 'mdi:close-circle'}
className={`text-xl ${status === 'success' ? 'text-green-500' : 'text-red-500'}`}
/>
</div>
<div className="flex justify-between items-center">
<div className="flex gap-2 items-center">
<Icon icon="mdi:robot" className="text-xl text-[--primary-color]" />
<span className="text-base text-gray-900">{title}</span>
<Icon
icon={status === 'success' ? 'mdi:check-circle' : 'mdi:close-circle'}
className={`text-xl ${status === 'success' ? 'text-green-500' : 'text-red-500'}`}
/>
</div>
{/* Action buttons */}
<div className="flex gap-2 transition-opacity duration-200">
<Icon
icon="mdi:cog"
className="text-xl text-gray-400 cursor-pointer hover:text-[--primary-color]"
onClick={() => console.log('Settings', data.id)}
/>
{/* Action buttons */}
<div className="flex gap-2 transition-opacity duration-200">
<Icon
icon="mdi:cog"
className="text-xl text-gray-400 cursor-pointer hover:text-[--primary-color]"
onClick={() => console.log('Settings', data.id)}
/>
</div>
</div>
<div className="mt-2 text-sm text-gray-500">{defaultModel}</div>
</div>
<div className="mt-2 text-sm text-gray-500">{defaultModel}</div>
</div>
)
}
@@ -4,7 +4,10 @@ import React from 'react'
export const ServiceCardNode: React.FC<NodeProps> = () => {
return (
<div className="node-card bg-white rounded-lg shadow-sm p-4 min-w-[150px] relative">
<div
className="node-card bg-white rounded-lg shadow-sm p-4 min-w-[150px] relative nodrag"
style={{ border: '1px solid var(--border-color)' }}
>
<Handle type="source" position={Position.Right} />
<div className="flex flex-col gap-2 items-center">
<Icon icon="mdi:robot" className="text-3xl text-[--primary-color]" />
@@ -35,7 +35,7 @@ const calculateNodePositions = (models: ModelData[], startY = 50, gap = 120) =>
const nodeTypes: NodeTypes = {
modelCard: ModelCardNode,
keyStatus: KeyStatusNode,
keyCard: KeyStatusNode,
serviceCard: ServiceCardNode
} as const
@@ -155,7 +155,7 @@ const initialEdges = [
source: 'service',
target: 'openai',
label: 'apis(12)',
style: { stroke: '#3d46f2', cursor: 'pointer' },
style: { stroke: '#ddd', cursor: 'pointer' },
labelStyle: { fill: '#3d46f2', fontSize: 12, cursor: 'pointer' }
},
{
@@ -163,7 +163,7 @@ const initialEdges = [
source: 'service',
target: 'anthropic',
label: 'apis(8)',
style: { stroke: '#3d46f2', cursor: 'pointer' },
style: { stroke: '#ddd', cursor: 'pointer' },
labelStyle: { fill: '#3d46f2', fontSize: 12, cursor: 'pointer' }
},
{
@@ -171,7 +171,7 @@ const initialEdges = [
source: 'service',
target: 'gemini',
label: 'apis(5)',
style: { stroke: '#3d46f2', cursor: 'pointer' },
style: { stroke: '#ddd', cursor: 'pointer' },
labelStyle: { fill: '#3d46f2', fontSize: 12, cursor: 'pointer' }
},
{
@@ -179,7 +179,7 @@ const initialEdges = [
source: 'service',
target: 'mistral',
label: 'apis(4)',
style: { stroke: '#3d46f2', cursor: 'pointer' },
style: { stroke: '#ddd', cursor: 'pointer' },
labelStyle: { fill: '#3d46f2', fontSize: 12, cursor: 'pointer' }
},
{
@@ -187,7 +187,7 @@ const initialEdges = [
source: 'service',
target: 'cohere',
label: 'apis(6)',
style: { stroke: '#3d46f2', cursor: 'pointer' },
style: { stroke: '#ddd', cursor: 'pointer' },
labelStyle: { fill: '#3d46f2', fontSize: 12, cursor: 'pointer' }
},
{
@@ -195,7 +195,7 @@ const initialEdges = [
source: 'service',
target: 'azure',
label: 'apis(10)',
style: { stroke: '#3d46f2', cursor: 'pointer' },
style: { stroke: '#ddd', cursor: 'pointer' },
labelStyle: { fill: '#3d46f2', fontSize: 12, cursor: 'pointer' }
},
...modelData.map((model) => ({
@@ -203,7 +203,7 @@ const initialEdges = [
source: model.id,
target: `${model.id}-keys`,
animated: true,
style: { stroke: '#3d46f2' }
style: { stroke: '#ddd' }
}))
]
@@ -215,6 +215,8 @@ const Playground = () => {
const onNodeDrag = useCallback(
(_: any, node: any) => {
if (node.type !== 'modelCard') return
// Update positions of connected nodes during drag
setNodes((nds) => {
return nds.map((n) => {
@@ -236,6 +238,8 @@ const Playground = () => {
const onNodeDragStop = useCallback(
(_: any, node: any) => {
if (node.type !== 'modelCard') return
// Reorder nodes based on vertical position
setNodes((nds) => {
const modelNodes = nds.filter((n) => n.type === 'modelCard')
@@ -274,7 +278,7 @@ const Playground = () => {
)
return (
<div className="w-full h-screen bg-gray-50">
<div className="w-full h-screen">
<ReactFlow
nodes={nodes}
edges={edges}
@@ -286,11 +290,11 @@ const Playground = () => {
nodeTypes={nodeTypes}
defaultEdgeOptions={{
type: 'step',
style: { stroke: '#3d46f2', strokeWidth: 2 },
style: { stroke: '#000', strokeWidth: 2 },
animated: true
}}
fitView
nodesDraggable={true}
nodesDraggable={(node) => node.type === 'modelCard'}
nodesConnectable={false}
zoomOnScroll={false}
zoomOnPinch={false}