UNPKG

realtimecursor

Version:

Real-time collaboration system with cursor tracking and approval workflow

169 lines (149 loc) 5.27 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>RealtimeCursor SDK Test</title> <link rel="stylesheet" href="../dist/cursor.css"> <style> body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; } .editor { width: 100%; height: 300px; padding: 16px; font-family: monospace; font-size: 16px; line-height: 1.5; border: 1px solid #ccc; border-radius: 8px; resize: none; } .collaborators { margin-top: 20px; padding: 10px; background-color: #f0f9ff; border-radius: 8px; border: 1px solid #bae6fd; } </style> </head> <body> <h1>RealtimeCursor SDK Test</h1> <div> <h2>Collaborative Editor</h2> <textarea id="editor" class="editor" placeholder="Start typing to collaborate..."></textarea> </div> <div class="collaborators"> <h3>Active Collaborators</h3> <div id="collaborators-list"></div> </div> <script src="../dist/index.js"></script> <script> // Initialize the cursor client const cursorClient = new RealtimeCursor({ apiUrl: 'http://localhost:3000', projectId: 'test-project', user: { id: 'user-' + Math.floor(Math.random() * 10000), name: 'Test User' }, autoConnect: true }); // Set up event handlers cursorClient.onCollaboratorsChange = (collaborators) => { const list = document.getElementById('collaborators-list'); list.innerHTML = ''; collaborators.forEach(collab => { const item = document.createElement('div'); item.style.display = 'flex'; item.style.alignItems = 'center'; item.style.gap = '8px'; item.style.padding = '4px 8px'; item.style.marginBottom = '4px'; const avatar = document.createElement('div'); avatar.style.width = '24px'; avatar.style.height = '24px'; avatar.style.borderRadius = '50%'; avatar.style.backgroundColor = collab.color; avatar.style.display = 'flex'; avatar.style.alignItems = 'center'; avatar.style.justifyContent = 'center'; avatar.style.color = 'white'; avatar.style.fontWeight = 'bold'; avatar.style.fontSize = '12px'; avatar.textContent = collab.name.charAt(0); const name = document.createElement('span'); name.textContent = collab.name; item.appendChild(avatar); item.appendChild(name); list.appendChild(item); }); }; cursorClient.onCursorUpdate = ({ socketId, user, x, y }) => { // Remove existing cursor const existingCursor = document.getElementById('cursor-' + socketId); if (existingCursor) { existingCursor.remove(); } // Create cursor element const cursor = document.createElement('div'); cursor.id = 'cursor-' + socketId; cursor.className = 'realtimecursor-cursor'; cursor.style.position = 'fixed'; cursor.style.left = x + 'px'; cursor.style.top = y + 'px'; cursor.style.transform = 'translate(-50%, -50%)'; cursor.style.zIndex = '9999'; cursor.style.pointerEvents = 'none'; const pointer = document.createElement('div'); pointer.className = 'realtimecursor-pointer'; pointer.style.width = '12px'; pointer.style.height = '12px'; pointer.style.borderRadius = '50%'; pointer.style.backgroundColor = user.color; pointer.style.boxShadow = '0 0 5px rgba(0,0,0,0.3)'; const nameLabel = document.createElement('div'); nameLabel.className = 'realtimecursor-name'; nameLabel.style.backgroundColor = user.color; nameLabel.style.color = '#fff'; nameLabel.style.padding = '2px 6px'; nameLabel.style.borderRadius = '4px'; nameLabel.style.fontSize = '12px'; nameLabel.style.marginTop = '4px'; nameLabel.style.whiteSpace = 'nowrap'; nameLabel.textContent = user.name; cursor.appendChild(pointer); cursor.appendChild(nameLabel); document.body.appendChild(cursor); }; cursorClient.onContentUpdate = ({ content }) => { const editor = document.getElementById('editor'); if (document.activeElement !== editor) { editor.value = content; } }; // Update cursor position on mouse move document.getElementById('editor').addEventListener('mousemove', (e) => { const rect = e.target.getBoundingClientRect(); cursorClient.updateCursor({ x: e.clientX, y: e.clientY, textPosition: e.target.selectionStart }); }); // Update content on change document.getElementById('editor').addEventListener('input', (e) => { cursorClient.updateContent(e.target.value, e.target.selectionStart); }); // Clean up on page unload window.addEventListener('beforeunload', () => { cursorClient.disconnect(); }); </script> </body> </html>