feat: [US-047] - Live cursor positions on canvas
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
b6d85b1a47
commit
7fe10544a1
@@ -8,10 +8,23 @@ export type PresenceUser = {
|
||||
displayName: string
|
||||
}
|
||||
|
||||
export type CursorPosition = {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
|
||||
export type RemoteCursor = {
|
||||
userId: string
|
||||
displayName: string
|
||||
position: CursorPosition
|
||||
lastUpdated: number
|
||||
}
|
||||
|
||||
type RealtimeCallbacks = {
|
||||
onConnectionStateChange: (state: ConnectionState) => void
|
||||
onPresenceSync?: (users: PresenceUser[]) => void
|
||||
onChannelSubscribed?: (channel: RealtimeChannel) => void
|
||||
onCursorUpdate?: (cursor: RemoteCursor) => void
|
||||
}
|
||||
|
||||
const HEARTBEAT_INTERVAL_MS = 30_000
|
||||
@@ -63,6 +76,15 @@ export class RealtimeConnection {
|
||||
this.callbacks.onPresenceSync?.(users)
|
||||
}
|
||||
})
|
||||
.on('broadcast', { event: 'cursor' }, ({ payload }) => {
|
||||
if (payload.userId === this.userId) return
|
||||
this.callbacks.onCursorUpdate?.({
|
||||
userId: payload.userId,
|
||||
displayName: payload.displayName,
|
||||
position: { x: payload.x, y: payload.y },
|
||||
lastUpdated: Date.now(),
|
||||
})
|
||||
})
|
||||
.subscribe(async (status) => {
|
||||
if (this.isDestroyed) return
|
||||
|
||||
@@ -107,6 +129,20 @@ export class RealtimeConnection {
|
||||
return this.channel
|
||||
}
|
||||
|
||||
broadcastCursor(position: CursorPosition): void {
|
||||
if (!this.channel) return
|
||||
this.channel.send({
|
||||
type: 'broadcast',
|
||||
event: 'cursor',
|
||||
payload: {
|
||||
userId: this.userId,
|
||||
displayName: this.displayName,
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
private async createSession(): Promise<void> {
|
||||
try {
|
||||
await this.supabase.from('collaboration_sessions').upsert(
|
||||
|
||||
Reference in New Issue
Block a user