Add canvas sync bridge for rspace.online integration
PostMessage listener in CanvasEmbed receives shape updates from the embedded rspace canvas iframe. Canvas-sync utility provides type guards and API helpers for pushing shapes to rspace. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
8c13f6ad71
commit
cc88cdd0d8
|
|
@ -1,14 +1,31 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import { useEffect, useCallback } from 'react';
|
||||||
|
import { isCanvasMessage, CanvasShapeMessage } from '@/lib/canvas-sync';
|
||||||
|
|
||||||
interface CanvasEmbedProps {
|
interface CanvasEmbedProps {
|
||||||
canvasSlug: string;
|
canvasSlug: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
onShapeUpdate?: (message: CanvasShapeMessage) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CanvasEmbed({ canvasSlug, className = '' }: CanvasEmbedProps) {
|
export function CanvasEmbed({ canvasSlug, className = '', onShapeUpdate }: CanvasEmbedProps) {
|
||||||
const rspaceUrl = process.env.NEXT_PUBLIC_RSPACE_URL || 'https://rspace.online';
|
|
||||||
const canvasUrl = `https://${canvasSlug}.rspace.online`;
|
const canvasUrl = `https://${canvasSlug}.rspace.online`;
|
||||||
|
|
||||||
|
const handleMessage = useCallback(
|
||||||
|
(event: MessageEvent) => {
|
||||||
|
if (!isCanvasMessage(event)) return;
|
||||||
|
if (event.data.communitySlug !== canvasSlug) return;
|
||||||
|
onShapeUpdate?.(event.data);
|
||||||
|
},
|
||||||
|
[canvasSlug, onShapeUpdate]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.addEventListener('message', handleMessage);
|
||||||
|
return () => window.removeEventListener('message', handleMessage);
|
||||||
|
}, [handleMessage]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`relative bg-slate-900 rounded-xl overflow-hidden border border-slate-700/50 ${className}`}>
|
<div className={`relative bg-slate-900 rounded-xl overflow-hidden border border-slate-700/50 ${className}`}>
|
||||||
{/* Toolbar */}
|
{/* Toolbar */}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
/**
|
||||||
|
* Canvas sync utilities for rtrips.online <-> rspace.online integration
|
||||||
|
*
|
||||||
|
* Listens for postMessage events from the embedded rspace canvas iframe
|
||||||
|
* and provides methods to push structured data to the canvas.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface CanvasShapeMessage {
|
||||||
|
source: 'rspace-canvas';
|
||||||
|
type: 'shape-updated' | 'shape-deleted';
|
||||||
|
communitySlug: string;
|
||||||
|
shapeId: string;
|
||||||
|
data: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isCanvasMessage(event: MessageEvent): event is MessageEvent<CanvasShapeMessage> {
|
||||||
|
return event.data?.source === 'rspace-canvas';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push shapes to an rspace canvas community via the shapes API
|
||||||
|
*/
|
||||||
|
export async function pushShapesToCanvas(
|
||||||
|
canvasSlug: string,
|
||||||
|
shapes: Record<string, unknown>[],
|
||||||
|
rspaceUrl?: string
|
||||||
|
): Promise<void> {
|
||||||
|
const baseUrl = rspaceUrl || process.env.RSPACE_INTERNAL_URL || 'http://rspace-online:3000';
|
||||||
|
|
||||||
|
const response = await fetch(`${baseUrl}/api/communities/${canvasSlug}/shapes`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ shapes }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const text = await response.text();
|
||||||
|
throw new Error(`Failed to push shapes: ${response.status} ${text}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue