@@ -73,7 +73,7 @@ import {
7373 createNodeShapeTools ,
7474 createNodeShapeUtils ,
7575} from "./DiscourseNodeUtil" ;
76- import { hasRoamPersistedCanvasData , useRoamStore } from "./useRoamStore" ;
76+ import { useRoamStore } from "./useRoamStore" ;
7777import {
7878 TLDRAW_CLOUDFLARE_SYNC_ENABLED ,
7979 TLDRAW_CLOUDFLARE_SYNC_WS_BASE_URL ,
@@ -115,6 +115,12 @@ import { TLRecord } from "@tldraw/tlschema";
115115import { WHITE_LOGO_SVG } from "~/icons" ;
116116import { BLOCK_REF_REGEX } from "roamjs-components/dom" ;
117117import { defaultHandleExternalTextContent } from "./defaultHandleExternalTextContent" ;
118+ import {
119+ CanvasSyncMode ,
120+ ensureCanvasSyncMode ,
121+ getEffectiveCanvasSyncMode ,
122+ setCanvasSyncMode ,
123+ } from "./canvasSyncMode" ;
118124
119125declare global {
120126 // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
@@ -153,16 +159,48 @@ const TldrawCanvas = ({ title }: { title: string }) => {
153159 // In Roam, canvas identity is currently keyed by the page UID.
154160 // Room sync is graph/page encoded as an opaque base64url token.
155161 const pageUid = useMemo ( ( ) => getPageUidByPageTitle ( title ) , [ title ] ) ;
156- const useCloudflareSync =
162+ const [ canvasSyncMode , setCanvasSyncModeState ] = useState < CanvasSyncMode > (
163+ ( ) => getEffectiveCanvasSyncMode ( { pageUid } ) ,
164+ ) ;
165+ const isCloudflareSyncAvailable =
157166 TLDRAW_CLOUDFLARE_SYNC_ENABLED &&
158- ! ! TLDRAW_CLOUDFLARE_SYNC_WS_BASE_URL &&
159- ! hasRoamPersistedCanvasData ( pageUid ) ;
167+ ! ! TLDRAW_CLOUDFLARE_SYNC_WS_BASE_URL ;
168+ const useCloudflareSync =
169+ canvasSyncMode === "sync" && isCloudflareSyncAvailable ;
170+
171+ useEffect ( ( ) => {
172+ setCanvasSyncModeState ( ensureCanvasSyncMode ( { pageUid } ) ) ;
173+ } , [ pageUid ] ) ;
174+
175+ const onCanvasSyncModeChange = useCallback (
176+ ( mode : CanvasSyncMode ) => {
177+ setCanvasSyncMode ( { pageUid, mode } ) ;
178+ setCanvasSyncModeState ( mode ) ;
179+ } ,
180+ [ pageUid ] ,
181+ ) ;
160182
161183 if ( useCloudflareSync ) {
162- return < TldrawCanvasCloudflare title = { title } pageUid = { pageUid } /> ;
184+ return (
185+ < TldrawCanvasCloudflare
186+ title = { title }
187+ pageUid = { pageUid }
188+ canvasSyncMode = { canvasSyncMode }
189+ isCloudflareSyncAvailable = { isCloudflareSyncAvailable }
190+ onCanvasSyncModeChange = { onCanvasSyncModeChange }
191+ />
192+ ) ;
163193 }
164194
165- return < TldrawCanvasRoam title = { title } pageUid = { pageUid } /> ;
195+ return (
196+ < TldrawCanvasRoam
197+ title = { title }
198+ pageUid = { pageUid }
199+ canvasSyncMode = { canvasSyncMode }
200+ isCloudflareSyncAvailable = { isCloudflareSyncAvailable }
201+ onCanvasSyncModeChange = { onCanvasSyncModeChange }
202+ />
203+ ) ;
166204} ;
167205
168206type CanvasStoreAdapterArgs = {
@@ -232,33 +270,51 @@ const useCloudflareCanvasStore = ({
232270const TldrawCanvasRoam = ( {
233271 title,
234272 pageUid,
273+ canvasSyncMode,
274+ isCloudflareSyncAvailable,
275+ onCanvasSyncModeChange,
235276} : {
236277 title : string ;
237278 pageUid : string ;
279+ canvasSyncMode : CanvasSyncMode ;
280+ isCloudflareSyncAvailable : boolean ;
281+ onCanvasSyncModeChange : ( mode : CanvasSyncMode ) => void ;
238282} ) => {
239283 return (
240284 < TldrawCanvasShared
241285 title = { title }
242286 pageUid = { pageUid }
243287 useStoreAdapter = { useRoamCanvasStore }
244288 isCloudflareSync = { false }
289+ canvasSyncMode = { canvasSyncMode }
290+ isCloudflareSyncAvailable = { isCloudflareSyncAvailable }
291+ onCanvasSyncModeChange = { onCanvasSyncModeChange }
245292 />
246293 ) ;
247294} ;
248295
249296const TldrawCanvasCloudflare = ( {
250297 title,
251298 pageUid,
299+ canvasSyncMode,
300+ isCloudflareSyncAvailable,
301+ onCanvasSyncModeChange,
252302} : {
253303 title : string ;
254304 pageUid : string ;
305+ canvasSyncMode : CanvasSyncMode ;
306+ isCloudflareSyncAvailable : boolean ;
307+ onCanvasSyncModeChange : ( mode : CanvasSyncMode ) => void ;
255308} ) => {
256309 return (
257310 < TldrawCanvasShared
258311 title = { title }
259312 pageUid = { pageUid }
260313 useStoreAdapter = { useCloudflareCanvasStore }
261314 isCloudflareSync = { true }
315+ canvasSyncMode = { canvasSyncMode }
316+ isCloudflareSyncAvailable = { isCloudflareSyncAvailable }
317+ onCanvasSyncModeChange = { onCanvasSyncModeChange }
262318 />
263319 ) ;
264320} ;
@@ -268,11 +324,17 @@ const TldrawCanvasShared = ({
268324 pageUid,
269325 useStoreAdapter,
270326 isCloudflareSync,
327+ canvasSyncMode,
328+ isCloudflareSyncAvailable,
329+ onCanvasSyncModeChange,
271330} : {
272331 title : string ;
273332 pageUid : string ;
274333 useStoreAdapter : ( args : CanvasStoreAdapterArgs ) => CanvasStoreAdapterResult ;
275334 isCloudflareSync : boolean ;
335+ canvasSyncMode : CanvasSyncMode ;
336+ isCloudflareSyncAvailable : boolean ;
337+ onCanvasSyncModeChange : ( mode : CanvasSyncMode ) => void ;
276338} ) => {
277339 const appRef = useRef < Editor | null > ( null ) ;
278340 const lastInsertRef = useRef < VecModel > ( ) ;
@@ -591,8 +653,18 @@ const TldrawCanvasShared = ({
591653 allNodes,
592654 allRelationNames,
593655 allAddReferencedNodeActions,
656+ canvasSyncMode,
657+ isCloudflareSyncAvailable,
658+ onCanvasSyncModeChange,
594659 } ) ,
595- [ allNodes , allRelationNames , allAddReferencedNodeActions ] ,
660+ [
661+ allNodes ,
662+ allRelationNames ,
663+ allAddReferencedNodeActions ,
664+ canvasSyncMode ,
665+ isCloudflareSyncAvailable ,
666+ onCanvasSyncModeChange ,
667+ ] ,
596668 ) ;
597669
598670 // UTILS
@@ -859,12 +931,14 @@ const TldrawCanvasShared = ({
859931 onDrop = { handleDrop }
860932 >
861933 { isCloudflareSync && (
862- < div
863- className = "pointer-events-none absolute right-3 top-3 z-20 opacity-90 "
864- title = "Cloudflare Sync enabled"
934+ < Tooltip
935+ content = "Sync mode is enabled. Collaborators on older builds may still open this canvas in local mode. "
936+ hoverOpenDelay = { 100 }
865937 >
866- < Icon icon = "cloud" size = { 12 } className = "text-green-500" />
867- </ div >
938+ < div className = "absolute right-3 top-3 z-20 opacity-90" >
939+ < Icon icon = "cloud" size = { 12 } className = "text-green-500" />
940+ </ div >
941+ </ Tooltip >
868942 ) }
869943 < style > { tldrawStyles } </ style >
870944
0 commit comments