| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Freelance Platform Mind Map</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> |
| @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap'); |
| |
| body { |
| font-family: 'Poppins', sans-serif; |
| background-color: #f8fafc; |
| } |
| |
| .mindmap-container { |
| position: relative; |
| min-height: 100vh; |
| overflow-x: hidden; |
| } |
| |
| .node { |
| position: absolute; |
| border-radius: 12px; |
| padding: 1rem; |
| box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); |
| transition: all 0.3s ease; |
| cursor: pointer; |
| max-width: 300px; |
| z-index: 10; |
| } |
| |
| .node:hover { |
| transform: scale(1.05); |
| z-index: 20; |
| } |
| |
| .connector { |
| position: absolute; |
| height: 2px; |
| background-color: #cbd5e1; |
| transform-origin: left center; |
| z-index: 1; |
| } |
| |
| .node-icon { |
| font-size: 1.5rem; |
| margin-right: 0.5rem; |
| } |
| |
| .node-content { |
| margin-top: 0.5rem; |
| } |
| |
| .node-item { |
| margin-bottom: 0.25rem; |
| font-size: 0.9rem; |
| } |
| |
| .controls { |
| position: fixed; |
| bottom: 2rem; |
| right: 2rem; |
| z-index: 100; |
| } |
| |
| .zoom-buttons { |
| display: flex; |
| gap: 0.5rem; |
| } |
| |
| .legend { |
| position: fixed; |
| top: 2rem; |
| right: 2rem; |
| background: white; |
| padding: 1rem; |
| border-radius: 8px; |
| box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); |
| z-index: 100; |
| } |
| |
| .legend-item { |
| display: flex; |
| align-items: center; |
| margin-bottom: 0.5rem; |
| } |
| |
| .legend-color { |
| width: 20px; |
| height: 20px; |
| border-radius: 4px; |
| margin-right: 0.5rem; |
| } |
| |
| .search-container { |
| position: fixed; |
| top: 2rem; |
| left: 2rem; |
| z-index: 100; |
| } |
| |
| .highlight { |
| animation: pulse 1.5s infinite; |
| } |
| |
| @keyframes pulse { |
| 0% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4); } |
| 70% { box-shadow: 0 0 0 10px rgba(59, 130, 246, 0); } |
| 100% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0); } |
| } |
| </style> |
| </head> |
| <body class="bg-gray-50"> |
| <div class="mindmap-container" id="mindmap"> |
| |
| </div> |
| |
| <div class="legend"> |
| <h3 class="font-bold text-lg mb-2">Legend</h3> |
| <div class="legend-item"> |
| <div class="legend-color bg-blue-500"></div> |
| <span>Platform Overview</span> |
| </div> |
| <div class="legend-item"> |
| <div class="legend-color bg-green-500"></div> |
| <span>Actors</span> |
| </div> |
| <div class="legend-item"> |
| <div class="legend-color bg-purple-500"></div> |
| <span>Functional Areas</span> |
| </div> |
| <div class="legend-item"> |
| <div class="legend-color bg-yellow-500"></div> |
| <span>Data Model</span> |
| </div> |
| <div class="legend-item"> |
| <div class="legend-color bg-red-500"></div> |
| <span>Technical Architecture</span> |
| </div> |
| <div class="legend-item"> |
| <div class="legend-color bg-indigo-500"></div> |
| <span>UI/UX</span> |
| </div> |
| </div> |
| |
| <div class="search-container"> |
| <div class="relative"> |
| <input type="text" id="searchInput" placeholder="Search nodes..." |
| class="pl-10 pr-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"> |
| <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i> |
| </div> |
| </div> |
| |
| <div class="controls"> |
| <div class="zoom-buttons bg-white p-2 rounded-lg shadow-lg"> |
| <button id="zoomIn" class="p-2 rounded-full hover:bg-gray-100"> |
| <i class="fas fa-search-plus text-blue-500"></i> |
| </button> |
| <button id="zoomOut" class="p-2 rounded-full hover:bg-gray-100"> |
| <i class="fas fa-search-minus text-blue-500"></i> |
| </button> |
| <button id="resetZoom" class="p-2 rounded-full hover:bg-gray-100"> |
| <i class="fas fa-expand text-blue-500"></i> |
| </button> |
| </div> |
| </div> |
| |
| <script> |
| document.addEventListener('DOMContentLoaded', function() { |
| const mindmap = document.getElementById('mindmap'); |
| let scale = 1; |
| let offsetX = 0; |
| let offsetY = 0; |
| let isDragging = false; |
| let startX, startY; |
| |
| |
| const nodes = [ |
| { |
| id: 'platform-overview', |
| title: 'Platform Overview', |
| icon: 'fa-globe', |
| color: 'bg-blue-500', |
| content: [ |
| 'Digitize freelance workflow end-to-end', |
| 'Mobile-first UI', |
| 'Scope grooming per order', |
| 'Iterative delivery with reviews', |
| 'Transparent pricing & time tracking', |
| 'Messaging with attachments', |
| 'Email proposal tracking', |
| 'Microfrontend architecture' |
| ], |
| x: 50, |
| y: 50 |
| }, |
| { |
| id: 'actors', |
| title: 'Actors', |
| icon: 'fa-users', |
| color: 'bg-green-500', |
| content: [ |
| '<b>Freelancer</b>: Manages proposals, projects, time tracking', |
| '<b>Customer</b>: Requests work, manages scope, gives feedback', |
| '<b>System</b>: Notifications, email handling, auth' |
| ], |
| x: 50, |
| y: 250, |
| parent: 'platform-overview' |
| }, |
| { |
| id: 'functional-areas', |
| title: 'Functional Areas', |
| icon: 'fa-sitemap', |
| color: 'bg-purple-500', |
| content: [ |
| 'Request Intake', |
| 'Proposal Management', |
| 'Project & Iteration Management', |
| 'Messaging', |
| 'Time Tracking & Finance', |
| 'Reviews & Ratings', |
| 'Email & Proposal Tracking' |
| ], |
| x: 50, |
| y: 450, |
| parent: 'platform-overview' |
| }, |
| { |
| id: 'request-intake', |
| title: 'Request Intake', |
| icon: 'fa-inbox', |
| color: 'bg-purple-300', |
| content: [ |
| 'Customer submits request', |
| 'Optional scope grooming', |
| 'Budget preview', |
| 'Feature toggles' |
| ], |
| x: 300, |
| y: 350, |
| parent: 'functional-areas' |
| }, |
| { |
| id: 'proposal-management', |
| title: 'Proposal Management', |
| icon: 'fa-file-contract', |
| color: 'bg-purple-300', |
| content: [ |
| 'Generate proposal with price + scope', |
| 'Email-based response tracking', |
| 'Customer accepts/rejects', |
| 'Digital signature support', |
| 'Advance payment integration' |
| ], |
| x: 300, |
| y: 450, |
| parent: 'functional-areas' |
| }, |
| { |
| id: 'project-iteration', |
| title: 'Project & Iteration', |
| icon: 'fa-tasks', |
| color: 'bg-purple-300', |
| content: [ |
| 'Projects contain multiple iterations', |
| 'Markdown deliverable descriptions', |
| 'Downloadable attachments', |
| 'Linked customer feedback', |
| 'Review process with accept/changes' |
| ], |
| x: 300, |
| y: 550, |
| parent: 'functional-areas' |
| }, |
| { |
| id: 'messaging', |
| title: 'Messaging', |
| icon: 'fa-comments', |
| color: 'bg-purple-300', |
| content: [ |
| 'Tied to project and iteration', |
| 'File attachments support', |
| 'Threaded conversations', |
| 'Real-time notifications' |
| ], |
| x: 300, |
| y: 650, |
| parent: 'functional-areas' |
| }, |
| { |
| id: 'time-finance', |
| title: 'Time & Finance', |
| icon: 'fa-clock', |
| color: 'bg-purple-300', |
| content: [ |
| 'Hour logging per iteration', |
| 'Compare hours vs. budget', |
| 'Automatic rate application', |
| 'Payment tracking', |
| 'Invoicing' |
| ], |
| x: 300, |
| y: 750, |
| parent: 'functional-areas' |
| }, |
| { |
| id: 'data-model', |
| title: 'Data Model', |
| icon: 'fa-database', |
| color: 'bg-yellow-500', |
| content: [ |
| 'Users (freelancer, customer)', |
| 'Projects', |
| 'Proposals', |
| 'Iterations', |
| 'Deliverables', |
| 'Messages', |
| 'TimeLogs', |
| 'Payments', |
| 'Reviews', |
| 'EmailTrackers' |
| ], |
| x: 50, |
| y: 650, |
| parent: 'platform-overview' |
| }, |
| { |
| id: 'api-layer', |
| title: 'API Layer', |
| icon: 'fa-plug', |
| color: 'bg-red-500', |
| content: [ |
| 'RESTful API with domain services', |
| 'CRUD for all key entities', |
| 'JWT authentication', |
| 'Endpoint groups:', |
| '- /auth, /projects', |
| '- /proposals, /iterations', |
| '- /messages, /reviews', |
| '- /time-logs, /email-trackers', |
| 'File uploads for attachments' |
| ], |
| x: 50, |
| y: 850, |
| parent: 'platform-overview' |
| }, |
| { |
| id: 'backend-arch', |
| title: 'Backend Architecture', |
| icon: 'fa-server', |
| color: 'bg-red-500', |
| content: [ |
| 'Node.js + LowDB for prototyping', |
| 'Lightweight JSON DB', |
| 'Modular domain services', |
| 'Central config and error handling', |
| 'Scalable Microservices (Logical)', |
| 'Separated services per domain', |
| 'API gateway simulation' |
| ], |
| x: 300, |
| y: 850, |
| parent: 'api-layer' |
| }, |
| { |
| id: 'microfrontend', |
| title: 'Microfrontend Design', |
| icon: 'fa-window-maximize', |
| color: 'bg-red-500', |
| content: [ |
| 'Independent UI apps per domain:', |
| '- Project dashboard', |
| '- Proposal builder', |
| '- Iteration tracker', |
| '- Review system', |
| '- Messaging panel', |
| '- Time logging', |
| 'Deployed independently', |
| 'Talks to API gateway' |
| ], |
| x: 600, |
| y: 850, |
| parent: 'api-layer' |
| }, |
| { |
| id: 'ui-ux', |
| title: 'UI/UX Notes', |
| icon: 'fa-paint-brush', |
| color: 'bg-indigo-500', |
| content: [ |
| 'Mobile-first design', |
| 'Scope sliders or checkboxes', |
| 'Kanban board style dashboard', |
| 'Simple chat-style messaging', |
| 'Progress meters for time/budget', |
| 'Email timeline and interactions', |
| 'Deliverable previews' |
| ], |
| x: 50, |
| y: 1050, |
| parent: 'platform-overview' |
| } |
| ]; |
| |
| |
| function renderMindmap() { |
| mindmap.innerHTML = ''; |
| |
| |
| nodes.forEach(node => { |
| if (node.parent) { |
| const parentNode = nodes.find(n => n.id === node.parent); |
| if (parentNode) { |
| createConnector(parentNode, node); |
| } |
| } |
| }); |
| |
| |
| nodes.forEach(node => { |
| createNode(node); |
| }); |
| } |
| |
| function createNode(node) { |
| const nodeElement = document.createElement('div'); |
| nodeElement.className = `node ${node.color} text-white`; |
| nodeElement.id = `node-${node.id}`; |
| nodeElement.style.left = `${node.x}px`; |
| nodeElement.style.top = `${node.y}px`; |
| |
| nodeElement.innerHTML = ` |
| <div class="flex items-center"> |
| <i class="node-icon fas ${node.icon}"></i> |
| <h3 class="font-bold">${node.title}</h3> |
| </div> |
| <div class="node-content"> |
| ${node.content.map(item => `<div class="node-item">${item}</div>`).join('')} |
| </div> |
| `; |
| |
| |
| nodeElement.addEventListener('mousedown', startDrag); |
| |
| mindmap.appendChild(nodeElement); |
| } |
| |
| function createConnector(parentNode, childNode) { |
| const connector = document.createElement('div'); |
| connector.className = 'connector'; |
| |
| |
| const startX = parentNode.x + 150; |
| const startY = parentNode.y + 50; |
| const endX = childNode.x; |
| const endY = childNode.y + 50; |
| |
| const length = Math.sqrt(Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2)); |
| const angle = Math.atan2(endY - startY, endX - startX) * 180 / Math.PI; |
| |
| connector.style.width = `${length}px`; |
| connector.style.left = `${startX}px`; |
| connector.style.top = `${startY}px`; |
| connector.style.transform = `rotate(${angle}deg)`; |
| |
| mindmap.appendChild(connector); |
| } |
| |
| |
| document.getElementById('zoomIn').addEventListener('click', () => { |
| scale += 0.1; |
| updateTransform(); |
| }); |
| |
| document.getElementById('zoomOut').addEventListener('click', () => { |
| if (scale > 0.5) { |
| scale -= 0.1; |
| updateTransform(); |
| } |
| }); |
| |
| document.getElementById('resetZoom').addEventListener('click', () => { |
| scale = 1; |
| offsetX = 0; |
| offsetY = 0; |
| updateTransform(); |
| }); |
| |
| function updateTransform() { |
| mindmap.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(${scale})`; |
| } |
| |
| |
| function startDrag(e) { |
| if (e.button !== 0) return; |
| |
| const node = e.currentTarget; |
| const rect = node.getBoundingClientRect(); |
| |
| isDragging = true; |
| startX = e.clientX - offsetX; |
| startY = e.clientY - offsetY; |
| |
| document.addEventListener('mousemove', drag); |
| document.addEventListener('mouseup', stopDrag); |
| |
| e.preventDefault(); |
| } |
| |
| function drag(e) { |
| if (!isDragging) return; |
| |
| offsetX = e.clientX - startX; |
| offsetY = e.clientY - startY; |
| |
| updateTransform(); |
| } |
| |
| function stopDrag() { |
| isDragging = false; |
| document.removeEventListener('mousemove', drag); |
| document.removeEventListener('mouseup', stopDrag); |
| } |
| |
| |
| document.getElementById('searchInput').addEventListener('input', function(e) { |
| const searchTerm = e.target.value.toLowerCase(); |
| |
| |
| document.querySelectorAll('.node').forEach(node => { |
| node.classList.remove('highlight'); |
| }); |
| |
| if (searchTerm.trim() === '') return; |
| |
| |
| nodes.forEach(node => { |
| const nodeMatches = node.title.toLowerCase().includes(searchTerm) || |
| node.content.some(item => item.toLowerCase().includes(searchTerm)); |
| |
| if (nodeMatches) { |
| const nodeElement = document.getElementById(`node-${node.id}`); |
| if (nodeElement) { |
| nodeElement.classList.add('highlight'); |
| |
| |
| const x = node.x * scale + offsetX; |
| const y = node.y * scale + offsetY; |
| |
| window.scrollTo({ |
| left: x - window.innerWidth / 2, |
| top: y - window.innerHeight / 2, |
| behavior: 'smooth' |
| }); |
| } |
| } |
| }); |
| }); |
| |
| |
| renderMindmap(); |
| |
| |
| setTimeout(() => { |
| const centerX = (mindmap.scrollWidth - window.innerWidth) / 2; |
| const centerY = (mindmap.scrollHeight - window.innerHeight) / 2; |
| |
| offsetX = -centerX; |
| offsetY = -centerY; |
| updateTransform(); |
| }, 100); |
| }); |
| </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=LukasBe/mindmap" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |