Files
calctext/calcpad-web/src/collab/useWebSocketProvider.ts
C. Cassel ef302ebda9 feat: add auth, real-time collaboration, sharing, font control, and UI fixes
Phase 1 - Bug fixes:
- Fix color labels not showing on active line in format preview
- Replace eye emoji with SVG icon showing clear preview/raw state
- Replace // button with comment icon + better tooltip
- Fix ThemePicker accent colors when using system theme

Phase 2 - Font:
- Load JetBrains Mono via Google Fonts with offline fallback
- Add font size control (A-/A+) with keyboard shortcuts
- Persist font size preference in localStorage

Phase 3 - Auth:
- Supabase-based email/password authentication
- Device session management with configurable password renewal TTL
- AuthModal, UserMenu, SecuritySettings components

Phase 4 - Cloud sync:
- Document metadata sync to Supabase PostgreSQL
- Legacy localStorage migration on first login
- IndexedDB persistence via y-indexeddb

Phase 5 - Real-time collaboration:
- Y.js CRDT integration with CodeMirror 6
- Hocuspocus WebSocket server with JWT auth
- Collaborative cursor awareness
- CollabIndicator component

Phase 6 - Sharing:
- Share links with view/edit permissions
- ShareDialog component with copy-to-clipboard
- Minimal client-side router for /s/{token} URLs

Infrastructure:
- Docker Compose with PostgreSQL, GoTrue, PostgREST, Hocuspocus
- Nginx reverse proxy for all backend services
- SQL migrations with RLS policies
- Production-ready Dockerfile with build args

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 16:21:04 -04:00

87 lines
2.1 KiB
TypeScript

import { useRef, useEffect, useState } from 'react'
import * as Y from 'yjs'
import { WebsocketProvider } from 'y-websocket'
import type { Awareness } from 'y-protocols/awareness'
const COLLAB_WS_URL = import.meta.env.VITE_COLLAB_WS_URL as string || 'ws://localhost:4000'
interface UseWebSocketProviderOptions {
ydoc: Y.Doc | null
roomName: string | null
token: string | null
userName: string
userColor: string
}
/**
* Manages a Y.js WebSocket provider for real-time collaboration.
* Connects to the Hocuspocus server.
*/
export function useWebSocketProvider({
ydoc,
roomName,
token,
userName,
userColor,
}: UseWebSocketProviderOptions) {
const providerRef = useRef<WebsocketProvider | null>(null)
const [awareness, setAwareness] = useState<Awareness | null>(null)
const [connected, setConnected] = useState(false)
const [peerCount, setPeerCount] = useState(0)
useEffect(() => {
if (!ydoc || !roomName || !token) {
setAwareness(null)
setConnected(false)
setPeerCount(0)
return
}
const provider = new WebsocketProvider(
COLLAB_WS_URL,
roomName,
ydoc,
{
params: { token },
connect: true,
},
)
providerRef.current = provider
// Set local user awareness
provider.awareness.setLocalStateField('user', {
name: userName,
color: userColor,
})
setAwareness(provider.awareness)
// Track connection status
provider.on('status', (event: { status: string }) => {
setConnected(event.status === 'connected')
})
// Track peer count
const updatePeerCount = () => {
const states = provider.awareness.getStates()
setPeerCount(Math.max(0, states.size - 1)) // Exclude self
}
provider.awareness.on('change', updatePeerCount)
updatePeerCount()
return () => {
provider.awareness.off('change', updatePeerCount)
provider.disconnect()
provider.destroy()
providerRef.current = null
setAwareness(null)
setConnected(false)
setPeerCount(0)
}
}, [ydoc, roomName, token, userName, userColor])
return { awareness, connected, peerCount }
}