implemented basic board text search function, added double click to zoom
This commit is contained in:
parent
7b1fe2b803
commit
e3e2c474ac
|
|
@ -18,6 +18,7 @@ import {
|
|||
import { useState, useEffect } from "react"
|
||||
import { saveToPdf } from "../utils/pdfUtils"
|
||||
import { TLFrameShape } from "tldraw"
|
||||
import { searchText } from "../utils/searchUtils"
|
||||
|
||||
const getAllFrames = (editor: Editor) => {
|
||||
return editor
|
||||
|
|
@ -217,6 +218,16 @@ export function CustomContextMenu(props: TLUiContextMenuProps) {
|
|||
}}
|
||||
/>
|
||||
</TldrawUiMenuGroup>
|
||||
|
||||
<TldrawUiMenuGroup id="search-controls">
|
||||
<TldrawUiMenuItem
|
||||
id="search-text"
|
||||
label="Search Text"
|
||||
icon="search"
|
||||
kbd="s"
|
||||
onSelect={() => searchText(editor)}
|
||||
/>
|
||||
</TldrawUiMenuGroup>
|
||||
</DefaultContextMenu>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
zoomToSelection,
|
||||
} from "./cameraUtils"
|
||||
import { saveToPdf } from "../utils/pdfUtils"
|
||||
import { searchText } from "../utils/searchUtils"
|
||||
|
||||
export const overrides: TLUiOverrides = {
|
||||
tools(editor, tools) {
|
||||
|
|
@ -38,6 +39,22 @@ export const overrides: TLUiOverrides = {
|
|||
// Otherwise, use default select tool behavior
|
||||
;(tools.select as any).onPointerDown?.(info)
|
||||
},
|
||||
|
||||
//TODO: Fix double click to zoom on selector tool later...
|
||||
onDoubleClick: (info: any) => {
|
||||
// Prevent default double-click behavior (which would start text editing)
|
||||
info.preventDefault?.()
|
||||
|
||||
// Handle all pointer types (mouse, touch, pen)
|
||||
const point = info.point || (info.touches && info.touches[0]) || info
|
||||
|
||||
// Zoom in at the clicked/touched point
|
||||
editor.zoomIn(point, { animation: { duration: 200 } })
|
||||
|
||||
// Stop event propagation and prevent default handling
|
||||
info.stopPropagation?.()
|
||||
return false
|
||||
},
|
||||
},
|
||||
VideoChat: {
|
||||
id: "VideoChat",
|
||||
|
|
@ -81,6 +98,12 @@ export const overrides: TLUiOverrides = {
|
|||
onSelect: () => editor.setCurrentTool("MycrozineTemplate"),
|
||||
},
|
||||
*/
|
||||
hand: {
|
||||
...tools.hand,
|
||||
onDoubleClick: (info: any) => {
|
||||
editor.zoomIn(info.point, { animation: { duration: 200 } })
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
actions(editor, actions) {
|
||||
|
|
@ -317,6 +340,13 @@ export const overrides: TLUiOverrides = {
|
|||
editor.stopFollowingUser()
|
||||
},
|
||||
},
|
||||
searchShapes: {
|
||||
id: "search-shapes",
|
||||
label: "Search Shapes",
|
||||
kbd: "s",
|
||||
readonlyOk: true,
|
||||
onSelect: () => searchText(editor),
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
import { Editor } from "tldraw"
|
||||
|
||||
export const searchText = (editor: Editor) => {
|
||||
// Switch to select tool first
|
||||
editor.setCurrentTool('select')
|
||||
|
||||
const searchTerm = prompt("Enter search text:")
|
||||
if (!searchTerm) return
|
||||
|
||||
const shapes = editor.getCurrentPageShapes()
|
||||
const matchingShapes = shapes.filter(shape => {
|
||||
if (!shape.props) return false
|
||||
|
||||
const textProperties = [
|
||||
(shape.props as any).text,
|
||||
(shape.props as any).name,
|
||||
(shape.props as any).value,
|
||||
(shape.props as any).url,
|
||||
(shape.props as any).description,
|
||||
(shape.props as any).content,
|
||||
]
|
||||
|
||||
const termLower = searchTerm.toLowerCase()
|
||||
return textProperties.some(prop =>
|
||||
typeof prop === 'string' &&
|
||||
prop.toLowerCase().includes(termLower)
|
||||
)
|
||||
})
|
||||
|
||||
if (matchingShapes.length > 0) {
|
||||
editor.selectNone()
|
||||
editor.setSelectedShapes(matchingShapes)
|
||||
|
||||
const commonBounds = editor.getSelectionPageBounds()
|
||||
if (!commonBounds) return
|
||||
|
||||
// Calculate viewport dimensions
|
||||
const viewportPageBounds = editor.getViewportPageBounds()
|
||||
|
||||
// Calculate the ratio of selection size to viewport size
|
||||
const widthRatio = commonBounds.width / viewportPageBounds.width
|
||||
const heightRatio = commonBounds.height / viewportPageBounds.height
|
||||
|
||||
// Calculate target zoom based on selection size
|
||||
let targetZoom
|
||||
if (widthRatio < 0.1 || heightRatio < 0.1) {
|
||||
targetZoom = Math.min(
|
||||
(viewportPageBounds.width * 0.8) / commonBounds.width,
|
||||
(viewportPageBounds.height * 0.8) / commonBounds.height,
|
||||
40
|
||||
)
|
||||
} else if (widthRatio > 1 || heightRatio > 1) {
|
||||
targetZoom = Math.min(
|
||||
(viewportPageBounds.width * 0.7) / commonBounds.width,
|
||||
(viewportPageBounds.height * 0.7) / commonBounds.height,
|
||||
0.125
|
||||
)
|
||||
} else {
|
||||
targetZoom = Math.min(
|
||||
(viewportPageBounds.width * 0.8) / commonBounds.width,
|
||||
(viewportPageBounds.height * 0.8) / commonBounds.height,
|
||||
20
|
||||
)
|
||||
}
|
||||
|
||||
// Zoom to the common bounds
|
||||
editor.zoomToBounds(commonBounds, {
|
||||
targetZoom,
|
||||
inset: widthRatio > 1 || heightRatio > 1 ? 20 : 50,
|
||||
animation: {
|
||||
duration: 400,
|
||||
easing: (t) => t * (2 - t),
|
||||
},
|
||||
})
|
||||
|
||||
// Update URL with new camera position and first selected shape ID
|
||||
const newCamera = editor.getCamera()
|
||||
const url = new URL(window.location.href)
|
||||
url.searchParams.set("shapeId", matchingShapes[0].id)
|
||||
url.searchParams.set("x", newCamera.x.toString())
|
||||
url.searchParams.set("y", newCamera.y.toString())
|
||||
url.searchParams.set("zoom", newCamera.z.toString())
|
||||
window.history.replaceState(null, "", url.toString())
|
||||
} else {
|
||||
alert("No matches found")
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue