diff --git a/src/components/Board.tsx b/src/components/Board.tsx index 4408973..445e6f8 100644 --- a/src/components/Board.tsx +++ b/src/components/Board.tsx @@ -40,43 +40,84 @@ import { usePersistentBoard } from '@/hooks/usePersistentBoard'; export function Board() { const { slug } = useParams<{ slug: string }>(); const roomId = slug || 'default-room'; - const { store } = usePersistentBoard(roomId); + const store = usePersistentBoard(roomId); const [editor, setEditor] = useState(null) - const { zoomToFrame, copyFrameLink, copyLocationLink } = useCameraControls(editor) + const { zoomToFrame, copyFrameLink, copyLocationLink, revertCamera } = useCameraControls(editor) return (
({ - ...baseTools, - frame: { - ...baseTools.frame, - contextMenu: (shape: TLFrameShape) => [ - { - id: 'copy-frame-link', - label: 'Copy Frame Link', - onSelect: () => copyFrameLink(shape.id), - }, - { - id: 'zoom-to-frame', - label: 'Zoom to Frame', - onSelect: () => zoomToFrame(shape.id), - }, - { - id: 'copy-location-link', - label: 'Copy Location Link', - onSelect: () => copyLocationLink(), - } - ] - }, - }) - }} - components={components} tools={tools} + components={components} + overrides={{ + tools: (editor, baseTools) => ({ + ...baseTools, + ChatBox: { + id: 'ChatBox', + icon: 'chat', + label: 'Chat', + kbd: 'c', + readonlyOk: true, + onSelect: () => { + editor.setCurrentTool('ChatBox') + }, + }, + VideoChat: { + id: 'VideoChat', + icon: 'video', + label: 'Video Chat', + kbd: 'v', + readonlyOk: true, + onSelect: () => { + editor.setCurrentTool('VideoChat') + }, + }, + Embed: { + id: 'Embed', + icon: 'embed', + label: 'Embed', + kbd: 'e', + readonlyOk: true, + onSelect: () => { + editor.setCurrentTool('Embed') + }, + }, + }), + actions: (editor, actions) => ({ + ...actions, + 'zoomToShape': { + id: 'zoom-to-shape', + label: 'Zoom to Selection', + kbd: 'z', + onSelect: () => { + if (editor.getSelectedShapeIds().length > 0) { + zoomToFrame(editor.getSelectedShapeIds()[0]); + } + }, + readonlyOk: true, + }, + 'copyLinkToCurrentView': { + id: 'copy-link-to-current-view', + label: 'Copy Link to Current View', + kbd: 'c', + onSelect: () => { + copyLocationLink(); + }, + readonlyOk: true, + }, + 'revertCamera': { + id: 'revert-camera', + label: 'Revert Camera', + kbd: 'b', + onSelect: () => { + revertCamera(); + }, + readonlyOk: true, + }, + }), + }} onMount={(editor) => { setEditor(editor) editor.registerExternalAssetHandler('url', unfurlBookmarkUrl) diff --git a/src/hooks/useCameraControls.ts b/src/hooks/useCameraControls.ts index e7970dc..ebf09af 100644 --- a/src/hooks/useCameraControls.ts +++ b/src/hooks/useCameraControls.ts @@ -2,6 +2,8 @@ import { useEffect } from 'react'; import { Editor, TLFrameShape, TLParentId } from 'tldraw'; import { useSearchParams } from 'react-router-dom'; +const initialCamera = { x: 0, y: 0, z: 1 }; + export function useCameraControls(editor: Editor | null) { const [searchParams] = useSearchParams(); @@ -85,6 +87,10 @@ export function useCameraControls(editor: Editor | null) { return { zoomToFrame, copyFrameLink, - copyLocationLink + copyLocationLink, + revertCamera: () => { + if (!editor) return + editor.setCamera(initialCamera) + } }; } \ No newline at end of file diff --git a/src/ui-overrides.tsx b/src/ui-overrides.tsx index d29607c..8c69fda 100644 --- a/src/ui-overrides.tsx +++ b/src/ui-overrides.tsx @@ -87,7 +87,7 @@ const copyFrameLink = async (editor: Editor, frameId: string) => { } }; -const zoomToShape = (editor: Editor) => { +const zoomToSelection = (editor: Editor) => { // Store camera position before zooming storeCameraPosition(editor); @@ -248,7 +248,7 @@ function CustomContextMenu(props: TLUiContextMenuProps) { }} /> { console.log('Zoom to Selection clicked'); - zoomToShape(editor); + zoomToSelection(editor); }} /> { console.log('Copy Link to Current View clicked'); @@ -278,37 +278,33 @@ function CustomContextMenu(props: TLUiContextMenuProps) { export const uiOverrides: TLUiOverrides = { tools(editor, tools) { - tools.VideoChat = { - id: 'VideoChat', - icon: 'color', - label: 'Video', - kbd: 'x', - meta: {}, - onSelect: () => { - editor.setCurrentTool('VideoChat') + return { + ...tools, + VideoChat: { + id: 'VideoChat', + icon: 'video', + label: 'Video Chat', + kbd: 'v', + readonlyOk: true, + onSelect: () => editor.setCurrentTool('VideoChat'), + }, + ChatBox: { + id: 'ChatBox', + icon: 'chat', + label: 'Chat', + kbd: 'c', + readonlyOk: true, + onSelect: () => editor.setCurrentTool('ChatBox'), + }, + Embed: { + id: 'Embed', + icon: 'embed', + label: 'Embed', + kbd: 'e', + readonlyOk: true, + onSelect: () => editor.setCurrentTool('Embed'), }, } - tools.ChatBox = { - id: 'ChatBox', - icon: 'color', - label: 'Chat', - kbd: 'x', - meta: {}, - onSelect: () => { - editor.setCurrentTool('ChatBox') - }, - } - tools.Embed = { - id: 'Embed', - icon: 'embed', - label: 'Embed', - kbd: 'e', - meta: {}, - onSelect: () => { - editor.setCurrentTool('Embed') - }, - } - return tools }, actions(editor, actions) { actions['copyFrameLink'] = { @@ -329,7 +325,7 @@ export const uiOverrides: TLUiOverrides = { onSelect: () => { const shape = editor.getSelectedShapes()[0] if (shape && shape.type === 'frame') { - zoomToShape(editor) + zoomToSelection(editor) } }, readonlyOk: true, @@ -353,7 +349,7 @@ export const uiOverrides: TLUiOverrides = { onSelect: () => { if (editor.getSelectedShapeIds().length > 0) { console.log('Zooming to selection'); - zoomToShape(editor); + zoomToSelection(editor); } }, readonlyOk: true, @@ -380,30 +376,71 @@ export const components: TLComponents = { const tools = useTools() return ( + {tools['VideoChat'] && ( )} {tools['ChatBox'] && ( )} {tools['Embed'] && ( )} - ) }, MainMenu: CustomMainMenu, - ContextMenu: CustomContextMenu, + ContextMenu: function CustomContextMenu({ ...rest }) { + const editor = useEditor() + const hasSelection = editor.getSelectedShapeIds().length > 0 + const hasCameraHistory = cameraHistory.length > 0 + + return ( + + + + zoomToSelection(editor)} + /> + copyLinkToCurrentView(editor)} + /> + revertCamera(editor)} + /> + + + ) + }, } const handleInitialShapeLoad = (editor: Editor) => {