insur-mcp / index.html
designfailure's picture
Add 2 files
05446d3 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Insur.MCP | Agent Workflow Canvas</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Custom styles for canvas elements */
.canvas-area {
background-color: #f8fafc;
border: 2px dashed #cbd5e1;
border-radius: 0.5rem;
min-height: 500px;
position: relative;
overflow: hidden;
}
.draggable-item {
cursor: grab;
user-select: none;
transition: all 0.2s ease;
}
.draggable-item:active {
cursor: grabbing;
}
.canvas-node {
position: absolute;
background: white;
border-radius: 0.5rem;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
min-width: 180px;
z-index: 10;
}
.canvas-node:hover {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
.node-header {
padding: 0.5rem 1rem;
border-bottom: 1px solid #e2e8f0;
font-weight: 600;
display: flex;
justify-content: space-between;
align-items: center;
}
.node-content {
padding: 1rem;
}
.node-connector {
width: 12px;
height: 12px;
border-radius: 50%;
background: #94a3b8;
position: absolute;
cursor: pointer;
}
.node-connector.input {
left: -6px;
top: 50%;
transform: translateY(-50%);
}
.node-connector.output {
right: -6px;
top: 50%;
transform: translateY(-50%);
}
.connection-line {
position: absolute;
height: 2px;
background: #64748b;
z-index: 5;
pointer-events: none;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
.tab-button.active {
background-color: #e2e8f0;
font-weight: 600;
}
/* Animation for empty canvas */
@keyframes pulse {
0%, 100% {
opacity: 0.5;
}
50% {
opacity: 0.2;
}
}
.empty-canvas {
animation: pulse 2s infinite;
}
</style>
</head>
<body class="font-sans antialiased text-gray-800 bg-white">
<!-- Navigation -->
<nav class="bg-white shadow-sm sticky top-0 z-50">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex items-center">
<div class="flex-shrink-0 flex items-center">
<a href="index.html" class="text-blue-600 font-bold text-xl">Insur.MCP</a>
</div>
</div>
<div class="hidden md:flex items-center space-x-8">
<a href="index.html" class="text-gray-500 hover:text-blue-600 font-medium px-1">Home</a>
<a href="index.html#features" class="text-gray-500 hover:text-blue-600 font-medium px-1">Features</a>
<a href="index.html#about" class="text-gray-500 hover:text-blue-600 font-medium px-1">About</a>
<a href="#" class="text-blue-600 font-medium border-b-2 border-blue-600 px-1">Canvas</a>
<button class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md font-medium transition duration-300">
Contact Us
</button>
</div>
<div class="md:hidden flex items-center">
<button id="mobile-menu-button" class="text-gray-500 hover:text-blue-600 focus:outline-none">
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
</button>
</div>
</div>
</div>
<div id="mobile-menu" class="mobile-menu md:hidden bg-white">
<div class="px-2 pt-2 pb-3 space-y-1 sm:px-3">
<a href="index.html" class="block px-3 py-2 rounded-md text-base font-medium text-gray-500 hover:text-blue-600 hover:bg-blue-50">Home</a>
<a href="index.html#features" class="block px-3 py-2 rounded-md text-base font-medium text-gray-500 hover:text-blue-600 hover:bg-blue-50">Features</a>
<a href="index.html#about" class="block px-3 py-2 rounded-md text-base font-medium text-gray-500 hover:text-blue-600 hover:bg-blue-50">About</a>
<a href="#" class="block px-3 py-2 rounded-md text-base font-medium text-blue-600 bg-blue-50">Canvas</a>
<button class="w-full text-left block px-3 py-2 rounded-md text-base font-medium text-white bg-blue-600 hover:bg-blue-700">
Contact Us
</button>
</div>
</div>
</nav>
<!-- Canvas Subpage Content -->
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div class="flex justify-between items-center mb-8">
<div>
<h1 class="text-3xl font-bold text-gray-900">Agent Workflow Canvas</h1>
<p class="text-gray-600 mt-2">Drag and drop components to create your AI agent workflow</p>
</div>
<div class="flex space-x-3">
<button id="clear-canvas" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50">
Clear Canvas
</button>
<button id="save-workflow" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">
Save Workflow
</button>
</div>
</div>
<div class="flex flex-col lg:flex-row gap-6">
<!-- Components Panel -->
<div class="lg:w-1/4 bg-gray-50 p-4 rounded-lg">
<div class="flex border-b border-gray-200 mb-4">
<button class="tab-button active px-4 py-2 rounded-t-lg" data-tab="agents">Agents</button>
<button class="tab-button px-4 py-2 rounded-t-lg" data-tab="tasks">Tasks</button>
<button class="tab-button px-4 py-2 rounded-t-lg" data-tab="tools">Tools</button>
<button class="tab-button px-4 py-2 rounded-t-lg" data-tab="data">Data</button>
</div>
<!-- Agents Tab -->
<div id="agents" class="tab-content active">
<div class="space-y-3">
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="agent" data-subtype="underwriting_agent">
<i class="fas fa-user-tie text-purple-500 mr-2"></i> Underwriting Agent
</div>
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="agent" data-subtype="sales_agent">
<i class="fas fa-handshake text-purple-500 mr-2"></i> Sales Agent
</div>
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="agent" data-subtype="fraud_agent">
<i class="fas fa-search-dollar text-purple-500 mr-2"></i> Fraud Agent
</div>
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="agent" data-subtype="claims_agent">
<i class="fas fa-file-invoice-dollar text-purple-500 mr-2"></i> Claims Agent
</div>
</div>
</div>
<!-- Tasks Tab -->
<div id="tasks" class="tab-content">
<div class="space-y-3">
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="task" data-subtype="risk_assessment">
<i class="fas fa-shield-alt text-blue-500 mr-2"></i> Risk Assessment
</div>
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="task" data-subtype="fraud_detection">
<i class="fas fa-search-dollar text-blue-500 mr-2"></i> Fraud Detection
</div>
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="task" data-subtype="sales_prospective">
<i class="fas fa-bullseye text-blue-500 mr-2"></i> Sales Prospective
</div>
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="task" data-subtype="appraisal">
<i class="fas fa-clipboard-check text-blue-500 mr-2"></i> Appraisal
</div>
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="task" data-subtype="estimation">
<i class="fas fa-calculator text-blue-500 mr-2"></i> Estimation
</div>
</div>
</div>
<!-- Tools Tab -->
<div id="tools" class="tab-content">
<div class="space-y-3">
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="tool" data-subtype="web_search">
<i class="fas fa-globe text-green-500 mr-2"></i> Web Search
</div>
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="tool" data-subtype="data_set">
<i class="fas fa-database text-green-500 mr-2"></i> Data Set
</div>
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="tool" data-subtype="analysis">
<i class="fas fa-chart-line text-green-500 mr-2"></i> Analysis
</div>
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="tool" data-subtype="delegation">
<i class="fas fa-users text-green-500 mr-2"></i> Delegation
</div>
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="tool" data-subtype="think">
<i class="fas fa-brain text-green-500 mr-2"></i> Think
</div>
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="tool" data-subtype="output_delivery">
<i class="fas fa-paper-plane text-green-500 mr-2"></i> Output Delivery
</div>
</div>
</div>
<!-- Data Tab -->
<div id="data" class="tab-content">
<div class="space-y-3">
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="data" data-subtype="customer_synt">
<i class="fas fa-users text-orange-500 mr-2"></i> Customer Synthetic
</div>
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="data" data-subtype="claim_synt">
<i class="fas fa-file-invoice text-orange-500 mr-2"></i> Claim Synthetic
</div>
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="data" data-subtype="process_synt">
<i class="fas fa-project-diagram text-orange-500 mr-2"></i> Process Synthetic
</div>
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="data" data-subtype="dataset">
<i class="fas fa-table text-orange-500 mr-2"></i> Dataset
</div>
<div class="draggable-item bg-white p-3 rounded border border-gray-200 cursor-move" draggable="true" data-type="data" data-subtype="sales">
<i class="fas fa-chart-bar text-orange-500 mr-2"></i> Sales Data
</div>
</div>
</div>
</div>
<!-- Canvas Area -->
<div class="lg:w-3/4">
<div id="workflow-canvas" class="canvas-area p-6">
<div class="empty-canvas text-center py-20 text-gray-400">
<i class="fas fa-arrows-alt text-4xl mb-4"></i>
<p class="text-xl">Drag components here to build your workflow</p>
<p class="text-sm mt-2">Connect nodes by dragging from output to input connectors</p>
</div>
</div>
<div class="mt-4 flex justify-between items-center">
<div class="text-sm text-gray-500">
<span id="node-count">0</span> nodes on canvas
</div>
<div class="flex space-x-3">
<button id="zoom-in" class="p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded">
<i class="fas fa-search-plus"></i>
</button>
<button id="zoom-out" class="p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded">
<i class="fas fa-search-minus"></i>
</button>
<button id="center-canvas" class="p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded">
<i class="fas fa-expand"></i>
</button>
</div>
</div>
</div>
</div>
</div>
<script>
// Mobile menu toggle
const mobileMenuButton = document.getElementById('mobile-menu-button');
const mobileMenu = document.getElementById('mobile-menu');
mobileMenuButton.addEventListener('click', () => {
mobileMenu.classList.toggle('open');
});
// Tab functionality
const tabButtons = document.querySelectorAll('.tab-button');
const tabContents = document.querySelectorAll('.tab-content');
tabButtons.forEach(button => {
button.addEventListener('click', () => {
// Remove active class from all buttons and contents
tabButtons.forEach(btn => btn.classList.remove('active'));
tabContents.forEach(content => content.classList.remove('active'));
// Add active class to clicked button and corresponding content
button.classList.add('active');
const tabId = button.getAttribute('data-tab');
document.getElementById(tabId).classList.add('active');
});
});
// Canvas functionality
const canvas = document.getElementById('workflow-canvas');
const draggableItems = document.querySelectorAll('.draggable-item');
const clearCanvasBtn = document.getElementById('clear-canvas');
const saveWorkflowBtn = document.getElementById('save-workflow');
const nodeCountElement = document.getElementById('node-count');
const emptyCanvasElement = document.querySelector('.empty-canvas');
let nodes = [];
let connections = [];
let isDragging = false;
let startConnector = null;
let tempLine = null;
let canvasScale = 1;
// Update node count
function updateNodeCount() {
const count = document.querySelectorAll('.canvas-node').length;
nodeCountElement.textContent = count;
if (count > 0) {
emptyCanvasElement.style.display = 'none';
} else {
emptyCanvasElement.style.display = 'block';
}
}
// Create a new node on canvas
function createNode(type, subtype, x, y) {
const nodeId = 'node-' + Date.now();
const node = document.createElement('div');
node.className = 'canvas-node';
node.id = nodeId;
node.style.left = `${x}px`;
node.style.top = `${y}px`;
// Set node color based on type
let icon, color, title;
switch(type) {
case 'agent':
icon = 'robot';
color = 'purple';
title = 'Agent: ' + subtype.replace('_', ' ');
break;
case 'task':
icon = 'tasks';
color = 'blue';
title = 'Task: ' + subtype.replace('_', ' ');
break;
case 'tool':
icon = 'tools';
color = 'green';
title = 'Tool: ' + subtype.replace('_', ' ');
break;
case 'data':
icon = 'database';
color = 'orange';
title = 'Data: ' + subtype.replace('_', ' ');
break;
}
// Create node HTML
node.innerHTML = `
<div class="node-header bg-${color}-50 text-${color}-700">
<div>
<i class="fas fa-${icon} mr-2"></i>
${title}
</div>
<button class="node-delete text-gray-400 hover:text-red-500">
<i class="fas fa-times"></i>
</button>
</div>
<div class="node-content">
<select class="w-full p-2 border border-gray-300 rounded text-sm">
${getOptionsForType(type)}
</select>
<div class="mt-2 text-xs text-gray-500">
<i class="fas fa-info-circle mr-1"></i>
${getDescriptionForSubtype(type, subtype)}
</div>
</div>
<div class="node-connector input" data-node="${nodeId}" data-type="input"></div>
<div class="node-connector output" data-node="${nodeId}" data-type="output"></div>
`;
// Add node to canvas
canvas.appendChild(node);
// Make node draggable
makeNodeDraggable(node);
// Add delete functionality
const deleteBtn = node.querySelector('.node-delete');
deleteBtn.addEventListener('click', () => {
// Remove any connections to this node
connections = connections.filter(conn => {
return conn.fromNode !== nodeId && conn.toNode !== nodeId;
});
// Remove connection lines from DOM
document.querySelectorAll('.connection-line').forEach(line => {
if (line.dataset.fromNode === nodeId || line.dataset.toNode === nodeId) {
line.remove();
}
});
// Remove the node
node.remove();
updateNodeCount();
});
// Store node in array
nodes.push({
id: nodeId,
type: type,
subtype: subtype,
element: node
});
updateNodeCount();
return node;
}
// Get options for select dropdown based on node type
function getOptionsForType(type) {
let options = '';
switch(type) {
case 'agent':
options = `
<option value="underwriting_agent">Underwriting Agent</option>
<option value="sales_agent">Sales Agent</option>
<option value="fraud_agent">Fraud Agent</option>
<option value="claims_agent">Claims Agent</option>
`;
break;
case 'task':
options = `
<option value="risk_assessment">Risk Assessment</option>
<option value="fraud_detection">Fraud Detection</option>
<option value="sales_prospective">Sales Prospective</option>
<option value="appraisal">Appraisal</option>
<option value="estimation">Estimation</option>
`;
break;
case 'tool':
options = `
<option value="web_search">Web Search</option>
<option value="data_set">Data Set</option>
<option value="analysis">Analysis</option>
<option value="delegation">Delegation</option>
<option value="think">Think</option>
<option value="output_delivery">Output Delivery</option>
`;
break;
case 'data':
options = `
<option value="customer_synt">Customer Synthetic</option>
<option value="claim_synt">Claim Synthetic</option>
<option value="process_synt">Process Synthetic</option>
<option value="dataset">Dataset</option>
<option value="sales">Sales Data</option>
`;
break;
}
return options;
}
// Get description for subtype
function getDescriptionForSubtype(type, subtype) {
const descriptions = {
agent: {
underwriting_agent: "Evaluates and assesses risks for insurance policies",
sales_agent: "Handles customer acquisition and policy sales",
fraud_agent: "Detects and investigates potential fraudulent claims",
claims_agent: "Manages and processes insurance claims"
},
task: {
risk_assessment: "Analyzes and evaluates potential risks",
fraud_detection: "Identifies suspicious patterns in claims",
sales_prospective: "Finds and qualifies potential customers",
appraisal: "Evaluates property or damage for claims",
estimation: "Calculates claim amounts or policy costs"
},
tool: {
web_search: "Searches the web for relevant information",
data_set: "Accesses structured data for analysis",
analysis: "Performs data analysis and interpretation",
delegation: "Assigns tasks to other agents",
think: "Processes information and makes decisions",
output_delivery: "Sends results to the next step"
},
data: {
customer_synt: "Synthetic customer profile data",
claim_synt: "Synthetic insurance claim data",
process_synt: "Synthetic process workflow data",
dataset: "General structured dataset",
sales: "Historical sales performance data"
}
};
return descriptions[type]?.[subtype] || "No description available";
}
// Make node draggable
function makeNodeDraggable(node) {
const header = node.querySelector('.node-header');
header.addEventListener('mousedown', (e) => {
if (e.target.classList.contains('node-delete') || e.target.closest('.node-delete')) {
return; // Don't drag if clicking delete button
}
const startX = e.clientX;
const startY = e.clientY;
const startLeft = parseInt(node.style.left);
const startTop = parseInt(node.style.top);
function moveNode(e) {
const dx = e.clientX - startX;
const dy = e.clientY - startY;
node.style.left = `${startLeft + dx}px`;
node.style.top = `${startTop + dy}px`;
// Update connection lines
updateConnectionLines();
}
function stopDrag() {
document.removeEventListener('mousemove', moveNode);
document.removeEventListener('mouseup', stopDrag);
}
document.addEventListener('mousemove', moveNode);
document.addEventListener('mouseup', stopDrag);
});
}
// Create a connection between two nodes
function createConnection(fromNodeId, toNodeId) {
// Check if connection already exists
const existingConnection = connections.find(conn =>
conn.fromNode === fromNodeId && conn.toNode === toNodeId
);
if (existingConnection) return;
// Add to connections array
connections.push({
fromNode: fromNodeId,
toNode: toNodeId
});
// Create connection line
updateConnectionLines();
}
// Update all connection lines
function updateConnectionLines() {
// Remove all existing connection lines
document.querySelectorAll('.connection-line').forEach(line => line.remove());
// Create new connection lines
connections.forEach(conn => {
const fromNode = document.getElementById(conn.fromNode);
const toNode = document.getElementById(conn.toNode);
if (fromNode && toNode) {
const fromConnector = fromNode.querySelector('.node-connector.output');
const toConnector = toNode.querySelector('.node-connector.input');
const fromRect = fromConnector.getBoundingClientRect();
const toRect = toConnector.getBoundingClientRect();
const canvasRect = canvas.getBoundingClientRect();
const fromX = fromRect.left + fromRect.width / 2 - canvasRect.left;
const fromY = fromRect.top + fromRect.height / 2 - canvasRect.top;
const toX = toRect.left + toRect.width / 2 - canvasRect.left;
const toY = toRect.top + toRect.height / 2 - canvasRect.top;
const length = Math.sqrt(Math.pow(toX - fromX, 2) + Math.pow(toY - fromY, 2));
const angle = Math.atan2(toY - fromY, toX - fromX) * 180 / Math.PI;
const line = document.createElement('div');
line.className = 'connection-line';
line.style.width = `${length}px`;
line.style.left = `${fromX}px`;
line.style.top = `${fromY}px`;
line.style.transform = `rotate(${angle}deg)`;
line.style.transformOrigin = '0 0';
line.dataset.fromNode = conn.fromNode;
line.dataset.toNode = conn.toNode;
canvas.appendChild(line);
}
});
}
// Handle drag and drop from components panel to canvas
draggableItems.forEach(item => {
item.addEventListener('dragstart', (e) => {
e.dataTransfer.setData('type', e.target.dataset.type);
e.dataTransfer.setData('subtype', e.target.dataset.subtype);
e.dataTransfer.effectAllowed = 'copy';
});
});
canvas.addEventListener('dragover', (e) => {
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
});
canvas.addEventListener('drop', (e) => {
e.preventDefault();
const type = e.dataTransfer.getData('type');
const subtype = e.dataTransfer.getData('subtype');
if (!type || !subtype) return;
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left - 90; // Center the node on cursor
const y = e.clientY - rect.top - 40;
createNode(type, subtype, x, y);
});
// Handle connector dragging for creating connections
canvas.addEventListener('mousedown', (e) => {
const connector = e.target.closest('.node-connector');
if (!connector) return;
e.preventDefault();
e.stopPropagation();
startConnector = {
node: connector.dataset.node,
type: connector.dataset.type,
x: e.clientX,
y: e.clientY
};
// Create temporary line
tempLine = document.createElement('div');
tempLine.className = 'connection-line';
tempLine.style.backgroundColor = '#6366f1';
canvas.appendChild(tempLine);
isDragging = true;
});
document.addEventListener('mousemove', (e) => {
if (!isDragging || !startConnector) return;
const fromNode = document.getElementById(startConnector.node);
if (!fromNode) return;
const fromConnector = fromNode.querySelector(`.node-connector.${startConnector.type}`);
const fromRect = fromConnector.getBoundingClientRect();
const canvasRect = canvas.getBoundingClientRect();
const fromX = fromRect.left + fromRect.width / 2 - canvasRect.left;
const fromY = fromRect.top + fromRect.height / 2 - canvasRect.top;
const toX = e.clientX - canvasRect.left;
const toY = e.clientY - canvasRect.top;
const length = Math.sqrt(Math.pow(toX - fromX, 2) + Math.pow(toY - fromY, 2));
const angle = Math.atan2(toY - fromY, toX - fromX) * 180 / Math.PI;
tempLine.style.width = `${length}px`;
tempLine.style.left = `${fromX}px`;
tempLine.style.top = `${fromY}px`;
tempLine.style.transform = `rotate(${angle}deg)`;
});
document.addEventListener('mouseup', (e) => {
if (!isDragging || !startConnector) {
isDragging = false;
startConnector = null;
return;
}
const connector = e.target.closest('.node-connector');
if (connector) {
const endConnector = {
node: connector.dataset.node,
type: connector.dataset.type
};
// Only connect output to input
if (startConnector.type === 'output' && endConnector.type === 'input') {
// Don't allow self-connections
if (startConnector.node !== endConnector.node) {
createConnection(startConnector.node, endConnector.node);
}
}
}
// Clean up
if (tempLine) {
tempLine.remove();
tempLine = null;
}
isDragging = false;
startConnector = null;
});
// Clear canvas
clearCanvasBtn.addEventListener('click', () => {
if (confirm('Are you sure you want to clear the canvas?')) {
document.querySelectorAll('.canvas-node').forEach(node => node.remove());
document.querySelectorAll('.connection-line').forEach(line => line.remove());
nodes = [];
connections = [];
updateNodeCount();
}
});
// Save workflow
saveWorkflowBtn.addEventListener('click', () => {
const workflow = {
nodes: nodes.map(node => ({
id: node.id,
type: node.type,
subtype: node.subtype,
position: {
x: parseInt(node.element.style.left),
y: parseInt(node.element.style.top)
}
})),
connections: connections
};
// In a real app, you would send this to a server
console.log('Workflow saved:', workflow);
alert('Workflow saved successfully!');
});
// Zoom functionality
document.getElementById('zoom-in').addEventListener('click', () => {
canvasScale = Math.min(canvasScale + 0.1, 2);
canvas.style.transform = `scale(${canvasScale})`;
});
document.getElementById('zoom-out').addEventListener('click', () => {
canvasScale = Math.max(canvasScale - 0.1, 0.5);
canvas.style.transform = `scale(${canvasScale})`;
});
document.getElementById('center-canvas').addEventListener('click', () => {
canvasScale = 1;
canvas.style.transform = `scale(${canvasScale})`;
canvas.scrollIntoView({ behavior: 'smooth', block: 'center' });
});
// Initialize
updateNodeCount();
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=designfailure/insur-mcp" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>