/** * CanvasListPage — List of canvas documents. * * Shows all canvas documents (stored in RecordRoom) with * create and delete functionality. * * Navigates to /canvas/:docId when a canvas is selected. */ import { useState } from 'react' import { useNavigate } from 'react-router-dom' import { useUser } from 'deepspace' import { useQuery } from 'deepspace' import { useMutations } from 'deepspace' import { Button, Modal, EmptyState } from '@/components/ui' import { ROLES, type Role } from 'deepspace' // ============================================================================ // Types // ============================================================================ interface CanvasDocument { title: string ownerId: string } // ============================================================================ // Create Canvas Modal // ============================================================================ interface CreateCanvasModalProps { isOpen: boolean onClose: () => void onCreate: (title: string) => void } function CreateCanvasModal({ isOpen, onClose, onCreate }: CreateCanvasModalProps) { const [title, setTitle] = useState('') const handleSubmit = () => { if (title.trim()) { onCreate(title.trim()) setTitle('') onClose() } } return ( New Canvas Title setTitle(e.target.value)} placeholder="e.g., Wireframe Draft" className="w-full px-3 py-2 bg-transparent border border-border rounded-lg text-foreground placeholder-muted-foreground focus:outline-none focus:ring-ring" autoFocus onKeyDown={(e) => e.key === 'Enter' && handleSubmit()} /> Cancel Create ) } // ============================================================================ // Main Page // ============================================================================ export default function CanvasListPage() { const { user } = useUser() const navigate = useNavigate() const userRole = (user?.role ?? ROLES.VIEWER) as Role const canCreate = userRole === ROLES.MEMBER || userRole === ROLES.ADMIN const [showCreateModal, setShowCreateModal] = useState(false) const { records: canvases, status } = useQuery('canvases', { orderBy: 'createdAt', orderDir: 'desc', }) const { create, remove } = useMutations('canvases') const handleCreate = async (title: string) => { await create({ title, ownerId: user!.id }) } const handleDelete = async (canvasId: string) => { if (confirm('Delete this canvas?')) { await remove(canvasId) } } const isLoading = status === 'loading' return ( {/* Header */} Canvas Collaborative spatial editing {canCreate && ( setShowCreateModal(true)}> New Canvas )} {/* Canvas list */} {isLoading ? ( ) : canvases.length === 0 ? ( } /> ) : ( {canvases.map((canvas) => { const isOwner = canvas.data.ownerId === user?.id return ( navigate(`/canvas/${canvas.recordId}`)} > {canvas.data.title} {new Date(canvas.createdAt).toLocaleDateString()} {isOwner && ' · You'} {isOwner && ( { e.stopPropagation() handleDelete(canvas.recordId) }} className="p-2 text-muted-foreground hover:text-destructive hover:bg-destructive/20 rounded-lg transition-colors opacity-0 group-hover:opacity-100" title="Delete" > )} ) })} )} setShowCreateModal(false)} onCreate={handleCreate} /> ) }
Collaborative spatial editing
{new Date(canvas.createdAt).toLocaleDateString()} {isOwner && ' · You'}