Team Ai
Apppublic

neyka/nodebase-explorer

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
database.html386 linesDownload Raw Back to root
1<!DOCTYPE html>2<html lang="en">3<head>4    <meta charset="UTF-8">5    <meta name="viewport" content="width=device-width, initial-scale=1.0">6    <title>Node Database</title>7    <script src="https://cdn.tailwindcss.com"></script>8    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>9    <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>10    <style>11        body {12            overflow: hidden;13            background: #0f172a;14            color: #e2e8f0;15        }16        #bg {17            position: fixed;18            top: 0;19            left: 0;20            z-index: -1;21            opacity: 0.4;22        }23        .node {24            width: 200px;25            border-radius: 8px;26            padding: 12px;27            position: absolute;28            cursor: move;29            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);30            transition: box-shadow 0.3s ease;31            user-select: none;32        }33        .node:hover {34            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);35        }36        .node-db {37            background: #1e40af;38            border: 2px solid #3b82f6;39        }40        .node-column {41            background: #4338ca;42            border: 2px solid #6366f1;43        }44        .node-data {45            background: #6b21a8;46            border: 2px solid #9333ea;47        }48        .connector {49            width: 12px;50            height: 12px;51            border-radius: 50%;52            position: absolute;53            cursor: pointer;54            z-index: 10;55        }56        .input-connector {57            background: #10b981;58            left: -6px;59            top: 50%;60            transform: translateY(-50%);61        }62        .output-connector {63            background: #f59e0b;64            right: -6px;65            top: 50%;66            transform: translateY(-50%);67        }68        .connection {69            position: absolute;70            background: rgba(255, 255, 255, 0.3);71            height: 2px;72            transform-origin: 0 0;73            z-index: 5;74        }75        .controls {76            position: fixed;77            bottom: 20px;78            left: 50%;79            transform: translateX(-50%);80            display: flex;81            gap: 10px;82        }83        .controls button {84            background: rgba(30, 41, 59, 0.8);85            border: 1px solid #334155;86            color: #e2e8f0;87            padding: 8px 16px;88            border-radius: 6px;89            cursor: pointer;90            display: flex;91            align-items: center;92            gap: 6px;93        }94        .controls button:hover {95            background: rgba(51, 65, 85, 0.8);96        }97    </style>98</head>99<body>100    <canvas id="bg"></canvas>101    <div id="workspace"></div>102    <div class="controls">103        <button id="create-db"><i data-feather="database"></i> Database</button>104        <button id="create-column"><i data-feather="columns"></i> Column</button>105        <button id="create-data"><i data-feather="file-text"></i> Data</button>106        <button id="clear-all"><i data-feather="trash-2"></i> Clear</button>107    </div>108 109    <script>110        // Mountain parallax shader111        const bgCanvas = document.getElementById('bg');112        const renderer = new THREE.WebGLRenderer({ 113            canvas: bgCanvas,114            alpha: true 115        });116        renderer.setSize(window.innerWidth, window.innerHeight);117 118        const scene = new THREE.Scene();119        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);120        camera.position.z = 15;121 122        // Create mountains123        const geometry = new THREE.PlaneGeometry(30, 30, 32, 32);124        const material = new THREE.MeshBasicMaterial({ 125            color: 0x1e3a8a,126            wireframe: true,127            transparent: true,128            opacity: 0.7129        });130        131        const mountains = [];132        for (let i = 0; i < 5; i++) {133            const mountain = new THREE.Mesh(geometry, material);134            mountain.position.z = -i * 5;135            mountain.scale.set(1 + i * 0.2, 1 + i * 0.2, 1);136            scene.add(mountain);137            mountains.push(mountain);138        }139 140        function animate() {141            requestAnimationFrame(animate);142            143            mountains.forEach((mountain, i) => {144                mountain.rotation.z += 0.0002 * (i + 1);145                mountain.rotation.x += 0.0001 * (i + 1);146            });147            148            renderer.render(scene, camera);149        }150        animate();151 152        window.addEventListener('resize', () => {153            camera.aspect = window.innerWidth / window.innerHeight;154            camera.updateProjectionMatrix();155            renderer.setSize(window.innerWidth, window.innerHeight);156        });157 158        // Node system159        const workspace = document.getElementById('workspace');160        let nodes = [];161        let connections = [];162        let draggingNode = null;163        let startPos = { x: 0, y: 0 };164        let selectedConnector = null;165 166        class Node {167            constructor(type, x, y) {168                this.id = Date.now() + Math.floor(Math.random() * 1000);169                this.type = type;170                this.x = x;171                this.y = y;172                this.element = null;173                this.inputConnector = null;174                this.outputConnector = null;175                this.create();176                nodes.push(this);177            }178 179            create() {180                this.element = document.createElement('div');181                this.element.className = `node node-${this.type}`;182                this.element.style.left = `${this.x}px`;183                this.element.style.top = `${this.y}px`;184                this.element.dataset.id = this.id;185 186                let title = '';187                let showInput = true;188                let showOutput = true;189 190                switch (this.type) {191                    case 'db':192                        title = 'Database';193                        showInput = false;194                        break;195                    case 'column':196                        title = 'Column';197                        break;198                    case 'data':199                        title = 'Data';200                        showOutput = false;201                        break;202                }203 204                this.element.innerHTML = `205                    <div class="font-bold mb-2">${title}</div>206                    <input type="text" placeholder="Name" class="w-full bg-transparent border-b border-gray-500 focus:border-blue-400 outline-none">207                `;208 209                if (showInput) {210                    this.inputConnector = document.createElement('div');211                    this.inputConnector.className = 'connector input-connector';212                    this.inputConnector.dataset.nodeId = this.id;213                    this.inputConnector.dataset.type = 'input';214                    this.element.appendChild(this.inputConnector);215                }216 217                if (showOutput) {218                    this.outputConnector = document.createElement('div');219                    this.outputConnector.className = 'connector output-connector';220                    this.outputConnector.dataset.nodeId = this.id;221                    this.outputConnector.dataset.type = 'output';222                    this.element.appendChild(this.outputConnector);223                }224 225                workspace.appendChild(this.element);226 227                // Add drag functionality228                this.element.addEventListener('mousedown', (e) => {229                    if (e.target === this.inputConnector || e.target === this.outputConnector) return;230                    231                    draggingNode = this;232                    startPos = {233                        x: e.clientX - this.x,234                        y: e.clientY - this.y235                    };236                });237            }238 239            updatePosition(x, y) {240                this.x = x;241                this.y = y;242                this.element.style.left = `${x}px`;243                this.element.style.top = `${y}px`;244 245                // Update connections246                this.updateConnections();247            }248 249            updateConnections() {250                connections.forEach(conn => {251                    if (conn.fromNode === this.id || conn.toNode === this.id) {252                        conn.update();253                    }254                });255            }256 257            remove() {258                // Remove connected connections259                connections = connections.filter(conn => {260                    if (conn.fromNode === this.id || conn.toNode === this.id) {261                        conn.element.remove();262                        return false;263                    }264                    return true;265                });266 267                this.element.remove();268                nodes = nodes.filter(n => n.id !== this.id);269            }270        }271 272        class Connection {273            constructor(fromNode, toNode) {274                this.fromNode = fromNode;275                this.toNode = toNode;276                this.element = document.createElement('div');277                this.element.className = 'connection';278                workspace.appendChild(this.element);279                this.update();280                connections.push(this);281            }282 283            update() {284                const fromNode = nodes.find(n => n.id === this.fromNode);285                const toNode = nodes.find(n => n.id === this.toNode);286 287                if (!fromNode || !toNode) {288                    this.element.remove();289                    connections = connections.filter(c => c !== this);290                    return;291                }292 293                const fromRect = fromNode.outputConnector.getBoundingClientRect();294                const toRect = toNode.inputConnector.getBoundingClientRect();295 296                const length = Math.sqrt(297                    Math.pow(toRect.left - fromRect.left, 2) + 298                    Math.pow(toRect.top - fromRect.top, 2)299                );300 301                const angle = Math.atan2(302                    toRect.top - fromRect.top,303                    toRect.left - fromRect.left304                );305 306                this.element.style.width = `${length}px`;307                this.element.style.left = `${fromRect.left - workspace.getBoundingClientRect().left + fromRect.width}px`;308                this.element.style.top = `${fromRect.top - workspace.getBoundingClientRect().top + fromRect.height / 2}px`;309                this.element.style.transform = `rotate(${angle}rad)`;310            }311        }312 313        // Event listeners314        document.addEventListener('mousemove', (e) => {315            if (draggingNode) {316                draggingNode.updatePosition(317                    e.clientX - startPos.x,318                    e.clientY - startPos.y319                );320            }321        });322 323        document.addEventListener('mouseup', () => {324            draggingNode = null;325        });326 327        workspace.addEventListener('click', (e) => {328            if (e.target.classList.contains('connector')) {329                if (!selectedConnector) {330                    selectedConnector = e.target;331                    e.target.style.transform = 'translateY(-50%) scale(1.5)';332                } else {333                    const fromType = selectedConnector.dataset.type;334                    const toType = e.target.dataset.type;335                    const fromNode = selectedConnector.dataset.nodeId;336                    const toNode = e.target.dataset.nodeId;337 338                    if (fromNode !== toNode && fromType !== toType) {339                        // Check if connection already exists340                        const exists = connections.some(conn => 341                            (conn.fromNode == fromNode && conn.toNode == toNode) ||342                            (conn.fromNode == toNode && conn.toNode == fromNode)343                        );344 345                        if (!exists) {346                            new Connection(347                                fromType === 'output' ? fromNode : toNode,348                                fromType === 'output' ? toNode : fromNode349                            );350                        }351                    }352 353                    selectedConnector.style.transform = 'translateY(-50%)';354                    selectedConnector = null;355                }356            } else if (selectedConnector) {357                selectedConnector.style.transform = 'translateY(-50%)';358                selectedConnector = null;359            }360        });361 362        // Control buttons363        document.getElementById('create-db').addEventListener('click', () => {364            new Node('db', 100, 100);365        });366 367        document.getElementById('create-column').addEventListener('click', () => {368            new Node('column', 300, 100);369        });370 371        document.getElementById('create-data').addEventListener('click', () => {372            new Node('data', 500, 100);373        });374 375        document.getElementById('clear-all').addEventListener('click', () => {376            nodes.forEach(node => node.remove());377            nodes = [];378            connections = [];379        });380 381        // Initialize feather icons382        feather.replace();383    </script>384</body>385</html>386```