Download index.html from LukasBe/mindmap: direct link, hf CLI and curl.
- Browser
- Download file 22.1 kB
-
https://huggingface.co/spaces/LukasBe/mindmap/resolve/main/index.html
- Command line
-
hf download hf://spaces/LukasBe/mindmap/index.html
-
curl -L -o index.html https://huggingface.co/spaces/LukasBe/mindmap/resolve/main/index.html
22.1 kB
| <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"> | |
| <!-- Nodes will be added here by JavaScript --> | |
| </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; | |
| // Mind map data structure | |
| 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' | |
| } | |
| ]; | |
| // Create nodes and connectors | |
| function renderMindmap() { | |
| mindmap.innerHTML = ''; | |
| // Create connectors first (so they appear behind nodes) | |
| nodes.forEach(node => { | |
| if (node.parent) { | |
| const parentNode = nodes.find(n => n.id === node.parent); | |
| if (parentNode) { | |
| createConnector(parentNode, node); | |
| } | |
| } | |
| }); | |
| // Create nodes | |
| 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> | |
| `; | |
| // Make nodes draggable | |
| nodeElement.addEventListener('mousedown', startDrag); | |
| mindmap.appendChild(nodeElement); | |
| } | |
| function createConnector(parentNode, childNode) { | |
| const connector = document.createElement('div'); | |
| connector.className = 'connector'; | |
| // Calculate connector position and dimensions | |
| const startX = parentNode.x + 150; // Assuming node width ~300px | |
| const startY = parentNode.y + 50; // Middle of parent node | |
| const endX = childNode.x; | |
| const endY = childNode.y + 50; // Middle of child node | |
| 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); | |
| } | |
| // Zoom functionality | |
| 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})`; | |
| } | |
| // Dragging functionality for the mindmap | |
| function startDrag(e) { | |
| if (e.button !== 0) return; // Only left mouse button | |
| 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); | |
| } | |
| // Search functionality | |
| document.getElementById('searchInput').addEventListener('input', function(e) { | |
| const searchTerm = e.target.value.toLowerCase(); | |
| // Remove highlights from all nodes | |
| document.querySelectorAll('.node').forEach(node => { | |
| node.classList.remove('highlight'); | |
| }); | |
| if (searchTerm.trim() === '') return; | |
| // Highlight matching nodes | |
| 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'); | |
| // Scroll to the node (approximate) | |
| 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' | |
| }); | |
| } | |
| } | |
| }); | |
| }); | |
| // Initial render | |
| renderMindmap(); | |
| // Center the mindmap on load | |
| 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> |