realtimecursor
Version:
Real-time collaboration system with cursor tracking and approval workflow
169 lines (149 loc) • 5.27 kB
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>