浏览代码

wip onboarding template

Peng Xiao 3 年之前
父节点
当前提交
48cfa27552

文件差异内容过多而无法显示
+ 0 - 0
resources/whiteboard/onboarding.template


+ 11 - 84
tldraw/apps/tldraw-logseq/src/hooks/usePaste.ts

@@ -33,21 +33,6 @@ const isValidURL = (url: string) => {
   }
 }
 
-const safeParseJson = (json: string) => {
-  try {
-    return JSON.parse(json)
-  } catch {
-    return null
-  }
-}
-
-const getWhiteboardsTldrFromText = (text: string) => {
-  const innerText = text.match(/<whiteboard-tldr>(.*)<\/whiteboard-tldr>/)?.[1]
-  if (innerText) {
-    return safeParseJson(decodeURIComponent(innerText))
-  }
-}
-
 interface VideoImageAsset extends TLAsset {
   size?: number[]
 }
@@ -263,67 +248,12 @@ export function usePaste() {
       }
 
       function tryCreateClonedShapesFromJSON(rawText: string) {
-        const data = getWhiteboardsTldrFromText(rawText)
-        try {
-          if (data) {
-            const shapes = data.shapes as TLShapeModel[]
-            assetsToClone = data.assets as TLAsset[]
-            const commonBounds = BoundsUtils.getCommonBounds(
-              shapes.map(shape => ({
-                minX: shape.point?.[0] ?? point[0],
-                minY: shape.point?.[1] ?? point[1],
-                width: shape.size?.[0] ?? 4,
-                height: shape.size?.[1] ?? 4,
-                maxX: (shape.point?.[0] ?? point[0]) + (shape.size?.[0] ?? 4),
-                maxY: (shape.point?.[1] ?? point[1]) + (shape.size?.[1] ?? 4),
-              }))
-            )
-            const bindings = data.bindings as Record<string, TLBinding>
-            const shapesToCreate = shapes.map(shape => {
-              return {
-                ...shape,
-                id: uniqueId(),
-                point: [
-                  point[0] + shape.point![0] - commonBounds.minX,
-                  point[1] + shape.point![1] - commonBounds.minY,
-                ],
-              }
-            })
-
-            // Try to rebinding the shapes to the new assets
-            shapesToCreate
-              .flatMap(s => Object.values(s.handles ?? {}))
-              .forEach(h => {
-                if (!h.bindingId) {
-                  return
-                }
-                // try to bind the new shape
-                const binding = bindings[h.bindingId]
-                if (binding) {
-                  // if the copied binding from/to is in the source
-                  const oldFromIdx = shapes.findIndex(s => s.id === binding.fromId)
-                  const oldToIdx = shapes.findIndex(s => s.id === binding.toId)
-                  if (binding && oldFromIdx !== -1 && oldToIdx !== -1) {
-                    const newBinding: TLBinding = {
-                      ...binding,
-                      id: uniqueId(),
-                      fromId: shapesToCreate[oldFromIdx].id,
-                      toId: shapesToCreate[oldToIdx].id,
-                    }
-                    bindingsToCreate.push(newBinding)
-                    h.bindingId = newBinding.id
-                  } else {
-                    h.bindingId = undefined
-                  }
-                } else {
-                  console.warn('binding not found', h.bindingId)
-                }
-              })
-
-            return shapesToCreate as Shape['props'][]
-          }
-        } catch (err) {
-          console.error(err)
+        const result = app.api.getClonedShapesFromTldrString(rawText, point)
+        if (result) {
+          const { shapes, assets, bindings } = result
+          assetsToClone.push(...assets)
+          bindingsToCreate.push(...bindings)
+          return shapes
         }
         return null
       }
@@ -442,13 +372,11 @@ export function usePaste() {
       })
 
       app.wrapUpdate(() => {
-        const allAssets = [...imageAssetsToCreate, ...assetsToClone]
-        if (allAssets.length > 0) {
-          app.createAssets(allAssets)
-        }
-        if (allShapesToAdd.length > 0) {
-          app.createShapes(allShapesToAdd)
-        }
+        app.api.addClonedShapes(
+          allShapesToAdd,
+          [...imageAssetsToCreate, ...assetsToClone],
+          bindingsToCreate
+        )
 
         if (app.selectedShapesArray.length === 1 && allShapesToAdd.length === 1 && !fromDrop) {
           const source = app.selectedShapesArray[0]
@@ -456,7 +384,6 @@ export function usePaste() {
           app.createNewLineBinding(source, target)
         }
 
-        app.currentPage.updateBindings(Object.fromEntries(bindingsToCreate.map(b => [b.id, b])))
         app.setSelectedShapes(allShapesToAdd.map(s => s.id))
         app.selectedTool.transition('idle') // clears possible editing states
         app.cursors.setCursor(TLCursor.Default)

+ 1 - 1
tldraw/apps/tldraw-logseq/src/lib/shapes/ImageShape.tsx

@@ -48,7 +48,7 @@ export class ImageShape extends TLImageShape<ImageShapeProps> {
       <HTMLContainer {...events} opacity={isErasing ? 0.2 : opacity}>
         {isBinding && <BindingIndicator mode="html" strokeWidth={4} size={[w, h]} />}
 
-        <div className="tl-image-shape-container">
+        <div data-asset-loaded={!!asset} className="tl-image-shape-container">
           {asset ? (
             <img
               src={handlers ? handlers.makeAssetUrl(asset.src) : asset.src}

+ 4 - 8
tldraw/apps/tldraw-logseq/src/lib/shapes/TextShape.tsx

@@ -45,7 +45,7 @@ export class TextShape extends TLTextShape<TextShapeProps> {
     parentId: 'page',
     type: 'text',
     point: [0, 0],
-    size: [100, 100],
+    size: [0, 0],
     isSizeLocked: true,
     text: '',
     lineHeight: 1.2,
@@ -170,13 +170,9 @@ export class TextShape extends TLTextShape<TextShapeProps> {
     }, [isEditing, onEditingEnd])
 
     React.useLayoutEffect(() => {
-      const { fontFamily, fontSize, fontWeight, lineHeight, padding } = this.props
-      const [width, height] = getTextLabelSize(
-        text,
-        { fontFamily, fontSize, fontWeight, lineHeight },
-        padding
-      )
-      this.update({ size: [width, height] })
+      if (this.props.size[0] === 0 || this.props.size[1] === 0) {
+        this.onResetBounds()
+      }
     }, [])
 
     return (

+ 4 - 1
tldraw/apps/tldraw-logseq/src/styles.css

@@ -740,7 +740,10 @@ button.tl-select-input-trigger {
 
 .tl-image-shape-container {
   @apply h-full w-full overflow-hidden flex items-center justify-center pointer-events-auto;
-  background-color: var(--ls-secondary-background-color);
+
+  &[data-asset-loaded="false"] {
+    background-color: var(--ls-secondary-background-color);
+  }
 }
 
 .tl-html-container {

+ 107 - 2
tldraw/packages/core/src/lib/TLApi/TLApi.ts

@@ -1,6 +1,6 @@
 import Vec from '@tldraw/vec'
-import type { TLEventMap } from '../../types'
-import { BoundsUtils } from '../../utils'
+import type { TLAsset, TLBinding, TLEventMap } from '../../types'
+import { BoundsUtils, uniqueId } from '../../utils'
 import type { TLShape, TLShapeModel } from '../shapes'
 import type { TLApp } from '../TLApp'
 
@@ -195,4 +195,109 @@ export class TLApi<S extends TLShape = TLShape, K extends TLEventMap = TLEventMa
   createNewLineBinding = (source: S | string, target: S | string) => {
     return this.app.createNewLineBinding(source, target)
   }
+
+  getClonedShapesFromTldrString = (text: string, point: number[]) => {
+    const safeParseJson = (json: string) => {
+      try {
+        return JSON.parse(json)
+      } catch {
+        return null
+      }
+    }
+
+    const getWhiteboardsTldrFromText = (text: string) => {
+      const innerText = text.match(/<whiteboard-tldr>(.*)<\/whiteboard-tldr>/)?.[1]
+      if (innerText) {
+        return safeParseJson(decodeURIComponent(innerText))
+      }
+    }
+
+    try {
+      let assetsToClone: TLAsset[] = []
+      const bindingsToCreate: TLBinding[] = []
+      const data = getWhiteboardsTldrFromText(text)
+
+      const shapes = data.shapes as TLShapeModel[]
+      assetsToClone = data.assets as TLAsset[]
+      const commonBounds = BoundsUtils.getCommonBounds(
+        shapes.map(shape => ({
+          minX: shape.point?.[0] ?? point[0],
+          minY: shape.point?.[1] ?? point[1],
+          width: shape.size?.[0] ?? 4,
+          height: shape.size?.[1] ?? 4,
+          maxX: (shape.point?.[0] ?? point[0]) + (shape.size?.[0] ?? 4),
+          maxY: (shape.point?.[1] ?? point[1]) + (shape.size?.[1] ?? 4),
+        }))
+      )
+
+      const bindings = data.bindings as Record<string, TLBinding>
+      const shapesToCreate = shapes.map(shape => {
+        return {
+          ...shape,
+          id: uniqueId(),
+          point: [
+            point[0] + shape.point![0] - commonBounds.minX,
+            point[1] + shape.point![1] - commonBounds.minY,
+          ],
+        }
+      })
+
+      // Try to rebinding the shapes to the new assets
+      shapesToCreate
+        .flatMap(s => Object.values(s.handles ?? {}))
+        .forEach(h => {
+          if (!h.bindingId) {
+            return
+          }
+          // try to bind the new shape
+          const binding = bindings[h.bindingId]
+          if (binding) {
+            // if the copied binding from/to is in the source
+            const oldFromIdx = shapes.findIndex(s => s.id === binding.fromId)
+            const oldToIdx = shapes.findIndex(s => s.id === binding.toId)
+            if (binding && oldFromIdx !== -1 && oldToIdx !== -1) {
+              const newBinding: TLBinding = {
+                ...binding,
+                id: uniqueId(),
+                fromId: shapesToCreate[oldFromIdx].id,
+                toId: shapesToCreate[oldToIdx].id,
+              }
+              bindingsToCreate.push(newBinding)
+              h.bindingId = newBinding.id
+            } else {
+              h.bindingId = undefined
+            }
+          } else {
+            console.warn('binding not found', h.bindingId)
+          }
+        })
+
+      return {
+        shapes: shapesToCreate as S['props'][],
+        assets: assetsToClone,
+        bindings: bindingsToCreate,
+      }
+    } catch (err) {
+      console.log(err)
+    }
+    return null
+  }
+
+  addClonedShapes = (shapes: S[] | TLShapeModel[], assets: TLAsset[], bindings: TLBinding[]) => {
+    if (assets.length > 0) {
+      this.app.createAssets(assets)
+    }
+    if (shapes.length > 0) {
+      this.app.createShapes(shapes)
+    }
+    this.app.currentPage.updateBindings(Object.fromEntries(bindings.map(b => [b.id, b])))
+    this.app.selectedTool.transition('idle') // clears possible editing states
+  }
+
+  addClonedShapesFromTldrString = (text: string, point: number[]) => {
+    const data = this.getClonedShapesFromTldrString(text, point)
+    if (data) {
+      this.addClonedShapes(data.shapes, data.assets, data.bindings)
+    }
+  }
 }

+ 6 - 4
tldraw/packages/core/src/utils/getTextSize.ts

@@ -1,5 +1,5 @@
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
-let melm: any
+let melm: HTMLElement
 
 interface TLTextMeasureStyles {
   fontStyle?: string
@@ -88,15 +88,17 @@ export function getTextLabelSize(
       return [10, 10]
     }
 
-    if (!melm.parent) document.body.appendChild(melm)
+    if (!melm.parentNode) document.body.appendChild(melm)
 
     melm.innerHTML = `${text}&#8203;`
     melm.style.font = font
     melm.style.padding = padding + 'px'
 
+    const rect = melm.getBoundingClientRect();
+
     // In tests, offsetWidth and offsetHeight will be 0
-    const width = melm.offsetWidth || 1
-    const height = melm.offsetHeight || 1
+    const width = Math.ceil(rect.width || 1)
+    const height = Math.ceil(rect.height || 1)
 
     saveCached(text, font, padding, [width, height])
   }

部分文件因为文件数量过多而无法显示