realtimecursor
Version:
Real-time collaboration system with cursor tracking and approval workflow
140 lines (124 loc) • 4.28 kB
JavaScript
import React, { useState, useRef, useEffect } from 'react';
import { useRealtimeCursor, CursorOverlay, CollaboratorsList } from 'realtimecursor-sdk-fixed';
import 'realtimecursor-sdk-fixed/dist/cursor.css';
function App() {
const [content, setContent] = useState('# Welcome to RealtimeCursor Demo\n\nThis is a collaborative editor using the fixed RealtimeCursor SDK.\n\nTry opening this page in multiple browser windows to see real-time collaboration in action!\n\n1. Your cursor position will be shared with others\n2. Content changes will be synchronized\n3. You\'ll see who else is editing this document');
const [userId, setUserId] = useState(`user-${Math.floor(Math.random() * 10000)}`);
const [userName, setUserName] = useState(`User ${Math.floor(Math.random() * 10000)}`);
const [userColor, setUserColor] = useState(getRandomColor());
const editorRef = useRef(null);
const {
cursors,
collaborators,
connected,
connect,
disconnect,
updateCursor,
updateContent
} = useRealtimeCursor({
apiUrl: 'http://localhost:3001',
projectId: 'demo-project',
user: {
id: userId,
name: userName,
color: userColor
}
});
// Connect on mount
useEffect(() => {
connect();
return () => disconnect();
}, [connect, disconnect, userId, userName, userColor]);
// Update cursor position on mouse move
const handleMouseMove = (e) => {
if (!editorRef.current) return;
const rect = editorRef.current.getBoundingClientRect();
updateCursor({
x: e.clientX,
y: e.clientY,
relativeX: e.clientX - rect.left,
relativeY: e.clientY - rect.top
});
};
// Update content when changed
const handleContentChange = (e) => {
const newContent = e.target.value;
setContent(newContent);
updateContent(newContent);
};
// Update user info
const handleUserUpdate = (e) => {
e.preventDefault();
// Disconnect and reconnect with new user info
disconnect();
setTimeout(() => connect(), 100);
};
// Generate random color
function getRandomColor() {
const colors = [
'#3b82f6', // blue
'#ef4444', // red
'#10b981', // green
'#f59e0b', // yellow
'#8b5cf6', // purple
'#ec4899', // pink
'#06b6d4', // cyan
'#f97316', // orange
];
return colors[Math.floor(Math.random() * colors.length)];
}
return (
<div className="app">
<div className="header">
<h1>RealtimeCursor Demo</h1>
<p>Fixed version (v1.1.0) with improved stability and performance</p>
</div>
<div className="user-info">
<h2>Your Information</h2>
<form className="user-form" onSubmit={handleUserUpdate}>
<input
type="text"
value={userName}
onChange={(e) => setUserName(e.target.value)}
placeholder="Your name"
/>
<input
type="color"
value={userColor}
onChange={(e) => setUserColor(e.target.value)}
title="Choose your cursor color"
/>
<button type="submit">Update</button>
</form>
<div className="connection-status">
<div className={`status-indicator ${connected ? 'connected' : 'disconnected'}`}></div>
<div className="status-text">
{connected ? 'Connected' : 'Disconnected'}
</div>
</div>
</div>
<div className="editor-container" ref={editorRef} onMouseMove={handleMouseMove}>
<textarea
className="editor"
value={content}
onChange={handleContentChange}
placeholder="Start typing..."
/>
<CursorOverlay cursors={cursors} />
</div>
<div className="collaborators-panel">
<h2>Active Collaborators ({collaborators.length})</h2>
<CollaboratorsList collaborators={collaborators} />
</div>
<div className="footer">
<p>
RealtimeCursor SDK - Fixed Version (v1.1.0) |
<a href="https://github.com/yourusername/realtimecursor" target="_blank" rel="noopener noreferrer">
GitHub
</a>
</p>
</div>
</div>
);
}
export default App;