Răsfoiți Sursa

remove file sync, tldraw, excalidraw and zotero

Tienson Qin 1 săptămână în urmă
părinte
comite
b3813ade7c
100 a modificat fișierele cu 5 adăugiri și 7642 ștergeri
  1. 1 1
      deps/common/src/logseq/common/config.cljs
  2. 1 1
      deps/common/src/logseq/common/graph.cljs
  3. 1 1
      deps/publishing/src/logseq/publishing/export.cljs
  4. 0 4
      gulpfile.js
  5. 1 1
      ios/App/App/FsWatcher.swift
  6. 1 3
      package.json
  7. 0 19
      packages/tldraw/.editorconfig
  8. 0 3
      packages/tldraw/.eslintignore
  9. 0 19
      packages/tldraw/.eslintrc
  10. 0 2
      packages/tldraw/.gitattributes
  11. 0 17
      packages/tldraw/.gitignore
  12. 0 17
      packages/tldraw/.npmignore
  13. 0 11
      packages/tldraw/.prettierrc
  14. 0 21
      packages/tldraw/LICENSE.md
  15. 0 29
      packages/tldraw/README.md
  16. 0 3
      packages/tldraw/apps/tldraw-logseq/README.md
  17. 0 29
      packages/tldraw/apps/tldraw-logseq/build.mjs
  18. 0 42
      packages/tldraw/apps/tldraw-logseq/package.json
  19. 0 3
      packages/tldraw/apps/tldraw-logseq/postcss.config.js
  20. 0 148
      packages/tldraw/apps/tldraw-logseq/src/app.tsx
  21. 0 113
      packages/tldraw/apps/tldraw-logseq/src/components/ActionBar/ActionBar.tsx
  22. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/ActionBar/index.ts
  23. 0 20
      packages/tldraw/apps/tldraw-logseq/src/components/AppUI.tsx
  24. 0 71
      packages/tldraw/apps/tldraw-logseq/src/components/BlockLink/BlockLink.tsx
  25. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/BlockLink/index.ts
  26. 0 15
      packages/tldraw/apps/tldraw-logseq/src/components/Button/Button.tsx
  27. 0 26
      packages/tldraw/apps/tldraw-logseq/src/components/Button/CircleButton.tsx
  28. 0 2
      packages/tldraw/apps/tldraw-logseq/src/components/Button/index.ts
  29. 0 67
      packages/tldraw/apps/tldraw-logseq/src/components/ContextBar/ContextBar.tsx
  30. 0 560
      packages/tldraw/apps/tldraw-logseq/src/components/ContextBar/contextBarActionFactory.tsx
  31. 0 2
      packages/tldraw/apps/tldraw-logseq/src/components/ContextBar/index.ts
  32. 0 369
      packages/tldraw/apps/tldraw-logseq/src/components/ContextMenu/ContextMenu.tsx
  33. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/ContextMenu/index.ts
  34. 0 56
      packages/tldraw/apps/tldraw-logseq/src/components/Devtools/Devtools.tsx
  35. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/Devtools/index.ts
  36. 0 93
      packages/tldraw/apps/tldraw-logseq/src/components/GeometryTools/GeometryTools.tsx
  37. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/GeometryTools/index.ts
  38. 0 16
      packages/tldraw/apps/tldraw-logseq/src/components/KeyboardShortcut/KeyboardShortcut.tsx
  39. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/KeyboardShortcut/index.ts
  40. 0 55
      packages/tldraw/apps/tldraw-logseq/src/components/Minimap/Minimap.tsx
  41. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/Minimap/index.ts
  42. 0 39
      packages/tldraw/apps/tldraw-logseq/src/components/PopoverButton/PopoverButton.tsx
  43. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/PopoverButton/index.ts
  44. 0 103
      packages/tldraw/apps/tldraw-logseq/src/components/PrimaryTools/PrimaryTools.tsx
  45. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/PrimaryTools/index.ts
  46. 0 44
      packages/tldraw/apps/tldraw-logseq/src/components/QuickLinks/QuickLinks.tsx
  47. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/QuickLinks/index.ts
  48. 0 437
      packages/tldraw/apps/tldraw-logseq/src/components/QuickSearch/QuickSearch.tsx
  49. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/QuickSearch/index.ts
  50. 0 16
      packages/tldraw/apps/tldraw-logseq/src/components/StatusBar/StatusBar.tsx
  51. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/StatusBar/index.ts
  52. 0 50
      packages/tldraw/apps/tldraw-logseq/src/components/ToolButton/ToolButton.tsx
  53. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/ToolButton/index.ts
  54. 0 31
      packages/tldraw/apps/tldraw-logseq/src/components/Tooltip/Tooltip.tsx
  55. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/Tooltip/index.ts
  56. 0 65
      packages/tldraw/apps/tldraw-logseq/src/components/ZoomMenu/ZoomMenu.tsx
  57. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/ZoomMenu/index.ts
  58. 0 35
      packages/tldraw/apps/tldraw-logseq/src/components/icons/TablerIcon.tsx
  59. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/icons/index.ts
  60. 0 122
      packages/tldraw/apps/tldraw-logseq/src/components/inputs/ColorInput.tsx
  61. 0 12
      packages/tldraw/apps/tldraw-logseq/src/components/inputs/NumberInput.tsx
  62. 0 59
      packages/tldraw/apps/tldraw-logseq/src/components/inputs/ScaleInput.tsx
  63. 0 75
      packages/tldraw/apps/tldraw-logseq/src/components/inputs/SelectInput.tsx
  64. 0 162
      packages/tldraw/apps/tldraw-logseq/src/components/inputs/ShapeLinksInput.tsx
  65. 0 18
      packages/tldraw/apps/tldraw-logseq/src/components/inputs/TextInput.tsx
  66. 0 76
      packages/tldraw/apps/tldraw-logseq/src/components/inputs/ToggleGroupInput.tsx
  67. 0 34
      packages/tldraw/apps/tldraw-logseq/src/components/inputs/ToggleInput.tsx
  68. 0 6
      packages/tldraw/apps/tldraw-logseq/src/hooks/useCameraMoving.ts
  69. 0 11
      packages/tldraw/apps/tldraw-logseq/src/hooks/useCopy.ts
  70. 0 14
      packages/tldraw/apps/tldraw-logseq/src/hooks/useDrop.ts
  71. 0 515
      packages/tldraw/apps/tldraw-logseq/src/hooks/usePaste.ts
  72. 0 12
      packages/tldraw/apps/tldraw-logseq/src/hooks/useQuickAdd.ts
  73. 0 18
      packages/tldraw/apps/tldraw-logseq/src/index.ts
  74. 0 3
      packages/tldraw/apps/tldraw-logseq/src/lib/index.ts
  75. 0 70
      packages/tldraw/apps/tldraw-logseq/src/lib/logseq-context.ts
  76. 0 148
      packages/tldraw/apps/tldraw-logseq/src/lib/preview-manager.tsx
  77. 0 32
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/BindingIndicator.tsx
  78. 0 195
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/BoxShape.tsx
  79. 0 62
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/DotShape.tsx
  80. 0 223
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/EllipseShape.tsx
  81. 0 65
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/GroupShape.tsx
  82. 0 159
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/HTMLShape.tsx
  83. 0 116
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/HighlighterShape.tsx
  84. 0 100
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/IFrameShape.tsx
  85. 0 119
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/ImageShape.tsx
  86. 0 252
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/LineShape.tsx
  87. 0 605
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/LogseqPortalShape.tsx
  88. 0 83
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/PdfShape.tsx
  89. 0 77
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/PenShape.tsx
  90. 0 163
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/PencilShape.tsx
  91. 0 218
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/PolygonShape.tsx
  92. 0 334
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/TextShape.tsx
  93. 0 227
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/TweetShape.tsx
  94. 0 105
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/VideoShape.tsx
  95. 0 182
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/YouTubeShape.tsx
  96. 0 87
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/arrow/Arrow.tsx
  97. 0 24
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/arrow/ArrowHead.tsx
  98. 0 59
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/arrow/arrowHelpers.ts
  99. 0 49
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/arrow/constants.ts
  100. 0 76
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/index.ts

+ 1 - 1
deps/common/src/logseq/common/config.cljs

@@ -91,7 +91,7 @@
 (defn text-formats
   []
   #{:json :org :md :yml :dat :asciidoc :rst :txt :markdown :adoc :html :js :ts :edn :clj :ml :rb :ex :erl :java :php :c :css
-    :excalidraw :tldr :sh})
+    :tldr :sh})
 
 (defn img-formats
   []

+ 1 - 1
deps/common/src/logseq/common/graph.cljs

@@ -82,7 +82,7 @@ Rules:
            (re-find #"^\.[^.]+" rpath))))))
 
 (def ^:private allowed-formats
-  #{:org :markdown :md :edn :json :js :css :excalidraw :tldr})
+  #{:org :markdown :md :edn :json :js :css})
 
 (defn- get-ext
   [p]

+ 1 - 1
deps/publishing/src/logseq/publishing/export.cljs

@@ -8,7 +8,7 @@
 
 (def ^:api js-files
   "js files from publishing release build"
-  (->> ["main.js" "code-editor.js" "excalidraw.js" "tldraw.js"]
+  (->> ["main.js" "code-editor.js"]
        ;; Add source maps for all js files as it doesn't affect initial load time
        (mapcat #(vector % (str % ".map")))
        vec))

+ 0 - 4
gulpfile.js

@@ -65,10 +65,6 @@ const common = {
   // NOTE: All assets from node_modules are copied to the output directory
   syncAssetFiles (...params) {
     return gulp.series(
-      () => gulp.src([
-        './node_modules/@excalidraw/excalidraw/dist/excalidraw-assets/**',
-        '!**/*/i18n-*.js',
-      ]).pipe(gulp.dest(path.join(outputPath, 'js', 'excalidraw-assets'))),
       () => gulp.src([
         'node_modules/katex/dist/katex.min.js',
         'node_modules/katex/dist/contrib/mhchem.min.js',

+ 1 - 1
ios/App/App/FsWatcher.swift

@@ -98,7 +98,7 @@ extension URL {
     }
 
     func shouldNotifyWithContent() -> Bool {
-        let allowedPathExtensions: Set = ["md", "markdown", "org", "js", "edn", "css", "excalidraw"]
+        let allowedPathExtensions: Set = ["md", "markdown", "org", "js", "edn", "css"]
         if allowedPathExtensions.contains(self.pathExtension.lowercased()) {
             return true
         }

+ 1 - 3
package.json

@@ -102,10 +102,9 @@
         "cljs:lint": "clojure -M:clj-kondo --parallel --lint src --cache false",
         "ios:dev": "cross-env PLATFORM=ios gulp cap",
         "android:dev": "cross-env PLATFORM=android gulp cap",
-        "tldraw:build": "yarn --cwd packages/tldraw install",
         "amplify:build": "yarn --cwd packages/amplify install",
         "ui:build": "yarn --cwd packages/ui install",
-        "postinstall": "yarn tldraw:build && yarn ui:build"
+        "postinstall": "yarn ui:build"
     },
     "dependencies": {
         "@aparajita/capacitor-secure-storage": "^7.1.6",
@@ -131,7 +130,6 @@
         "@dnd-kit/sortable": "^7.0.2",
         "@emoji-mart/data": "^1.1.2",
         "@emoji-mart/react": "^1.1.1",
-        "@excalidraw/excalidraw": "0.16.1",
         "@glidejs/glide": "^3.6.0",
         "@highlightjs/cdn-assets": "10.4.1",
         "@huggingface/transformers": "^3.6.3",

+ 0 - 19
packages/tldraw/.editorconfig

@@ -1,19 +0,0 @@
-
-# https://editorconfig.org
-root = true
-
-[*]
-charset = utf-8
-end_of_line = lf
-indent_size = 2
-indent_style = space
-insert_final_newline = true
-max_line_length = 80
-trim_trailing_whitespace = true
-
-[*.md]
-max_line_length = 0
-trim_trailing_whitespace = false
-
-[COMMIT_EDITMSG]
-max_line_length = 0

+ 0 - 3
packages/tldraw/.eslintignore

@@ -1,3 +0,0 @@
-**/node_modules/*
-**/out/*
-**/.next/*

+ 0 - 19
packages/tldraw/.eslintrc

@@ -1,19 +0,0 @@
-{
-  "root": true,
-  "parser": "@typescript-eslint/parser",
-  "plugins": ["@typescript-eslint"],
-  "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
-  "ignorePatterns": ["*.js", "*.jsx"],
-  "overrides": [
-    {
-      // enable the rule specifically for TypeScript files
-      "files": ["*.ts", "*.tsx"],
-      "rules": {
-        "@typescript-eslint/explicit-module-boundary-types": "off",
-        "@typescript-eslint/explicit-function-return-type": "off",
-        "@typescript-eslint/no-explicit-any": "off",
-        "@typescript-eslint/camelcase": "off"
-      }
-    }
-  ]
-}

+ 0 - 2
packages/tldraw/.gitattributes

@@ -1,2 +0,0 @@
-# Auto detect text files and perform LF normalization
-* text=auto

+ 0 - 17
packages/tldraw/.gitignore

@@ -1,17 +0,0 @@
-node_modules/
-build/
-dist/
-docs/
-.idea/*
-
-.DS_Store
-coverage
-*.log
-
-.vercel
-.next
-apps/www/public/workbox-*
-apps/www/public/worker-*
-apps/www/public/sw.js
-apps/www/public/sw.js.map
-.env

+ 0 - 17
packages/tldraw/.npmignore

@@ -1,17 +0,0 @@
-/.github/
-/.vscode/
-/node_modules/
-/build/
-/tmp/
-.idea/*
-/docs/
-
-coverage
-*.log
-.gitlab-ci.yml
-
-package-lock.json
-/*.tgz
-/tmp*
-/mnt/
-/package/

+ 0 - 11
packages/tldraw/.prettierrc

@@ -1,11 +0,0 @@
-{
-  "trailingComma": "es5",
-  "singleQuote": true,
-  "semi": false,
-  "printWidth": 100,
-  "tabWidth": 2,
-  "useTabs": false,
-  "jsxSingleQuote": false,
-  "jsxBracketSameLine": false,
-  "arrowParens": "avoid"
-}

+ 0 - 21
packages/tldraw/LICENSE.md

@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2021 Stephen Ruiz Ltd
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.

+ 0 - 29
packages/tldraw/README.md

@@ -1,29 +0,0 @@
-# Developer Notes
-
-## Background
-
-This folder contains the JS codes for a custom build of Tldraw to fit the needs of Logseq, which originates from an abandoned next branch from the author of Tldraw.
-
-## Development
-
-### Prerequisites
-
-Modern JS eco tools like Node.js and yarn.
-
-### Run in dev mode
-
-- install dependencies with `yarn`
-- run dev mode with `yarn dev`, which will start a Vite server at http://127.0.0.1:3031/
-
-Note, the dev mode is a standalone web app running a demo Tldraw app in `tldraw/demo/src/App.jsx`. The Logseq component renderers and handlers are all mocked to make sure Tldraw only functions can be isolatedly developed.
-
-## Other useful commands
-
-- fixing styles: `yarn fix:style`
-- build: `yarn build`
-
-## How it works
-
-### Data flow between Tldraw & Logseq
-
-The data flow between Tldraw & Logseq can be found here: https://whimsical.com/9sdt5j7MabK6DVrxgTZw25

+ 0 - 3
packages/tldraw/apps/tldraw-logseq/README.md

@@ -1,3 +0,0 @@
-# @tldraw/core Simple Example
-
-A (relatively) simple example project for `@tldraw/core`.

+ 0 - 29
packages/tldraw/apps/tldraw-logseq/build.mjs

@@ -1,29 +0,0 @@
-#!/usr/bin/env zx
-/* eslint-disable no-undef */
-import 'zx/globals'
-import fs from 'fs'
-import path from 'path'
-
-if (process.platform === 'win32') {
-  defaults.shell = "cmd.exe";
-  defaults.prefix = "";
-}
-
-// Build with [tsup](https://tsup.egoist.sh)
-await $`npx tsup`
-
-
-// Prepare package.json file
-const packageJson = fs.readFileSync('package.json', 'utf8')
-const glob = JSON.parse(packageJson)
-Object.assign(glob, {
-  main: './index.js',
-  module: './index.mjs',
-})
-
-fs.writeFileSync('dist/package.json', JSON.stringify(glob, null, 2))
-
-const dest = path.join(__dirname, '/../../../../src/main/frontend/tldraw-logseq.js')
-
-if (fs.existsSync(dest)) fs.unlinkSync(dest)
-fs.linkSync(path.join(__dirname, '/dist/index.js'), dest)

+ 0 - 42
packages/tldraw/apps/tldraw-logseq/package.json

@@ -1,42 +0,0 @@
-{
-  "version": "0.0.0-dev",
-  "name": "@tldraw/logseq",
-  "license": "MIT",
-  "module": "./src/index.ts",
-  "scripts": {
-    "build": "zx build.mjs",
-    "build:packages": "yarn build",
-    "dev": "tsup --watch",
-    "dev:vite": "tsup --watch --sourcemap inline"
-  },
-  "devDependencies": {
-    "@radix-ui/react-context-menu": "^2.1.0",
-    "@tldraw/core": "2.0.0-alpha.1",
-    "@tldraw/react": "2.0.0-alpha.1",
-    "@tldraw/vec": "2.0.0-alpha.1",
-    "@types/node": "^18.13.0",
-    "@types/react": "^17.0.0",
-    "@types/react-dom": "^17.0.0",
-    "autoprefixer": "^10.4.13",
-    "concurrently": "^7.5.0",
-    "esbuild": "^0.15.14",
-    "mobx": "^6.7.0",
-    "mobx-react-lite": "^3.4.0",
-    "perfect-freehand": "^1.2.0",
-    "polished": "^4.0.0",
-    "postcss": "^8.4.19",
-    "lucide-react": "^0.292.0",
-    "react": "^17.0.0",
-    "react-dom": "^17.0.0",
-    "react-virtuoso": "^3.1.3",
-    "rimraf": "3.0.2",
-    "shadow-cljs": "^2.20.11",
-    "tsup": "^6.5.0",
-    "typescript": "^4.9.3",
-    "zx": "^7.2.2"
-  },
-  "peerDependencies": {
-    "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
-    "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
-  }
-}

+ 0 - 3
packages/tldraw/apps/tldraw-logseq/postcss.config.js

@@ -1,3 +0,0 @@
-module.exports = ctx => ({
-  plugins: [require('autoprefixer')()],
-})

+ 0 - 148
packages/tldraw/apps/tldraw-logseq/src/app.tsx

@@ -1,148 +0,0 @@
-/* eslint-disable @typescript-eslint/no-non-null-assertion */
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import type { TLDocumentModel } from '@tldraw/core'
-import {
-  AppCanvas,
-  AppProvider,
-  TLReactCallbacks,
-  TLReactToolConstructor,
-  useApp,
-} from '@tldraw/react'
-import * as React from 'react'
-import { AppUI } from './components/AppUI'
-import { ContextBar } from './components/ContextBar'
-import { ContextMenu } from './components/ContextMenu'
-import { QuickLinks } from './components/QuickLinks'
-import { useDrop } from './hooks/useDrop'
-import { usePaste } from './hooks/usePaste'
-import { useCopy } from './hooks/useCopy'
-import { useQuickAdd } from './hooks/useQuickAdd'
-import {
-  BoxTool,
-  EllipseTool,
-  HighlighterTool,
-  HTMLTool,
-  IFrameTool,
-  LineTool,
-  LogseqPortalTool,
-  NuEraseTool,
-  PencilTool,
-  PolygonTool,
-  shapes,
-  TextTool,
-  YouTubeTool,
-  type Shape,
-} from './lib'
-import { LogseqContext, type LogseqContextValue } from './lib/logseq-context'
-
-const tools: TLReactToolConstructor<Shape>[] = [
-  BoxTool,
-  EllipseTool,
-  PolygonTool,
-  NuEraseTool,
-  HighlighterTool,
-  LineTool,
-  PencilTool,
-  TextTool,
-  YouTubeTool,
-  IFrameTool,
-  HTMLTool,
-  LogseqPortalTool,
-]
-
-interface LogseqTldrawProps {
-  renderers: LogseqContextValue['renderers']
-  handlers: LogseqContextValue['handlers']
-  readOnly: boolean
-  model?: TLDocumentModel<Shape>
-  onMount?: TLReactCallbacks<Shape>['onMount']
-  onPersist?: TLReactCallbacks<Shape>['onPersist']
-}
-
-const BacklinksCount: LogseqContextValue['renderers']['BacklinksCount'] = props => {
-  const { renderers } = React.useContext(LogseqContext)
-
-  const options = { 'portal?': false }
-
-  return <renderers.BacklinksCount {...props} options={options} />
-}
-
-const AppImpl = () => {
-  const ref = React.useRef<HTMLDivElement>(null)
-  const app = useApp()
-
-  const components = React.useMemo(
-    () => ({
-      ContextBar,
-      BacklinksCount,
-      QuickLinks,
-    }),
-    []
-  )
-  return (
-    <ContextMenu collisionRef={ref}>
-      <div ref={ref} className="logseq-tldraw logseq-tldraw-wrapper" data-tlapp={app.uuid}>
-        <AppCanvas components={components}>
-          <AppUI />
-        </AppCanvas>
-      </div>
-    </ContextMenu>
-  )
-}
-
-const AppInner = ({
-  onPersist,
-  readOnly,
-  model,
-  ...rest
-}: Omit<LogseqTldrawProps, 'renderers' | 'handlers'>) => {
-  const onDrop = useDrop()
-  const onPaste = usePaste()
-  const onCopy = useCopy()
-  const onQuickAdd = readOnly ? null : useQuickAdd()
-
-  const onPersistOnDiff: TLReactCallbacks<Shape>['onPersist'] = React.useCallback(
-    (app, info) => {
-      onPersist?.(app, info)
-    },
-    [model]
-  )
-
-  return (
-    <AppProvider
-      Shapes={shapes}
-      Tools={tools}
-      onDrop={onDrop}
-      onPaste={onPaste}
-      onCopy={onCopy}
-      readOnly={readOnly}
-      onCanvasDBClick={onQuickAdd}
-      onPersist={onPersistOnDiff}
-      model={model}
-      {...rest}
-    >
-      <AppImpl />
-    </AppProvider>
-  )
-}
-
-export const App = function App({ renderers, handlers, ...rest }: LogseqTldrawProps): JSX.Element {
-  const memoRenders: any = React.useMemo(() => {
-    return Object.fromEntries(
-      Object.entries(renderers).map(([key, comp]) => {
-        return [key, React.memo(comp)]
-      })
-    )
-  }, [])
-
-  const contextValue = {
-    renderers: memoRenders,
-    handlers: handlers,
-  }
-
-  return (
-    <LogseqContext.Provider value={contextValue}>
-      <AppInner {...rest} />
-    </LogseqContext.Provider>
-  )
-}

+ 0 - 113
packages/tldraw/apps/tldraw-logseq/src/components/ActionBar/ActionBar.tsx

@@ -1,113 +0,0 @@
-/* eslint-disable @typescript-eslint/no-non-null-assertion */
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import { useApp } from '@tldraw/react'
-import { observer } from 'mobx-react-lite'
-import * as React from 'react'
-import type { Shape } from '../../lib'
-import { TablerIcon } from '../icons'
-import { Button } from '../Button'
-import { ToggleInput } from '../inputs/ToggleInput'
-import { ZoomMenu } from '../ZoomMenu'
-import { LogseqContext } from '../../lib/logseq-context'
-
-// @ts-ignore
-const LSUI = window.LSUI
-
-export const ActionBar = observer(function ActionBar(): JSX.Element {
-  const app = useApp<Shape>()
-  const {
-    handlers: { t },
-  } = React.useContext(LogseqContext)
-
-  const undo = React.useCallback(() => {
-    app.api.undo()
-  }, [app])
-
-  const redo = React.useCallback(() => {
-    app.api.redo()
-  }, [app])
-
-  const zoomIn = React.useCallback(() => {
-    app.api.zoomIn()
-  }, [app])
-
-  const zoomOut = React.useCallback(() => {
-    app.api.zoomOut()
-  }, [app])
-
-  const toggleGrid = React.useCallback(() => {
-    app.api.toggleGrid()
-  }, [app])
-
-  const toggleSnapToGrid = React.useCallback(() => {
-    app.api.toggleSnapToGrid()
-  }, [app])
-
-  const togglePenMode = React.useCallback(() => {
-    app.api.togglePenMode()
-  }, [app])
-
-  return (
-    <div className="tl-action-bar" data-html2canvas-ignore="true">
-      {!app.readOnly && (
-        <div className="tl-toolbar tl-history-bar mr-2 mb-2">
-          <Button tooltip={t('whiteboard/undo')} onClick={undo}>
-            <TablerIcon name="arrow-back-up" />
-          </Button>
-          <Button tooltip={t('whiteboard/redo')} onClick={redo}>
-            <TablerIcon name="arrow-forward-up" />
-          </Button>
-        </div>
-      )}
-
-      <div className={'tl-toolbar tl-zoom-bar mr-2 mb-2'}>
-        <Button tooltip={t('whiteboard/zoom-in')} onClick={zoomIn} id="tl-zoom-in">
-          <TablerIcon name="plus" />
-        </Button>
-        <Button tooltip={t('whiteboard/zoom-out')} onClick={zoomOut} id="tl-zoom-out">
-          <TablerIcon name="minus" />
-        </Button>
-        <LSUI.Separator orientation="vertical" />
-        <ZoomMenu />
-      </div>
-
-      <div className={'tl-toolbar tl-grid-bar mr-2 mb-2'}>
-        <ToggleInput
-            tooltip={t('whiteboard/toggle-grid')}
-            className="tl-button"
-            pressed={app.settings.showGrid}
-            id="tl-show-grid"
-            onPressedChange={toggleGrid}
-          >
-          <TablerIcon name="grid-dots" />
-        </ToggleInput>
-
-        {!app.readOnly && (
-          <ToggleInput
-              tooltip={t('whiteboard/snap-to-grid')}
-              className="tl-button"
-              pressed={app.settings.snapToGrid}
-              id="tl-snap-to-grid"
-              onPressedChange={toggleSnapToGrid}
-            >
-            <TablerIcon name={app.settings.snapToGrid ? "magnet" : "magnet-off"} />
-          </ToggleInput>
-        )}
-      </div>
-
-      {!app.readOnly && (
-        <div className="tl-toolbar tl-pen-mode-bar mb-2">
-          <ToggleInput
-            tooltip={t('whiteboard/toggle-pen-mode')}
-            className="tl-button"
-            pressed={app.settings.penMode}
-            id="tl-toggle-pen-mode"
-            onPressedChange={togglePenMode}
-          >
-          <TablerIcon name={app.settings.penMode ? "pencil" : "pencil-off"} />
-        </ToggleInput>
-        </div>
-      )}
-    </div>
-  )
-})

+ 0 - 1
packages/tldraw/apps/tldraw-logseq/src/components/ActionBar/index.ts

@@ -1 +0,0 @@
-export * from './ActionBar'

+ 0 - 20
packages/tldraw/apps/tldraw-logseq/src/components/AppUI.tsx

@@ -1,20 +0,0 @@
-import { observer } from 'mobx-react-lite'
-import { ActionBar } from './ActionBar'
-import { DevTools } from './Devtools'
-import { PrimaryTools } from './PrimaryTools'
-import { StatusBar } from './StatusBar'
-import { isDev } from '@tldraw/core'
-import { useApp } from '@tldraw/react'
-
-export const AppUI = observer(function AppUI() {
-  const app = useApp()
-
-  return (
-    <>
-      {isDev() && <StatusBar />}
-      {isDev() && <DevTools />}
-      {!app.readOnly && <PrimaryTools />}
-      <ActionBar />
-    </>
-  )
-})

+ 0 - 71
packages/tldraw/apps/tldraw-logseq/src/components/BlockLink/BlockLink.tsx

@@ -1,71 +0,0 @@
-import { validUUID } from '@tldraw/core'
-import React from 'react'
-import { LogseqContext } from '../../lib/logseq-context'
-import { TablerIcon } from '../icons'
-
-export const BlockLink = ({
-  id,
-  showReferenceContent = false,
-}: {
-  id: string
-  showReferenceContent?: boolean
-}) => {
-  const {
-    handlers: { isWhiteboardPage, redirectToPage, sidebarAddBlock, queryBlockByUUID },
-    renderers: { Breadcrumb, PageName },
-  } = React.useContext(LogseqContext)
-
-  let iconName = ''
-  let linkType = validUUID(id) ? 'B' : 'P'
-  let blockContent = ''
-
-  if (validUUID(id)) {
-    const block = queryBlockByUUID(id)
-    if (!block) {
-      return <span className="p-2">Invalid reference. Did you remove it?</span>
-    }
-
-    blockContent = block.title
-
-    if (block.properties?.['ls-type'] === 'whiteboard-shape') {
-      iconName = 'link-to-whiteboard'
-    } else {
-      iconName = 'link-to-block'
-    }
-  } else {
-    if (isWhiteboardPage(id)) {
-      iconName = 'link-to-whiteboard'
-    } else {
-      iconName = 'link-to-page'
-    }
-  }
-
-  const slicedContent =
-    blockContent && blockContent.length > 23 ? blockContent.slice(0, 20) + '...' : blockContent
-
-  return (
-    <button
-      className="inline-flex gap-1 items-center w-full"
-      onPointerDown={e => {
-        e.stopPropagation()
-        if (e.shiftKey) {
-          sidebarAddBlock(id, linkType === 'B' ? 'block' : 'page')
-        } else {
-          redirectToPage(id)
-        }
-      }}
-    >
-      <TablerIcon name={iconName} />
-      <span className="pointer-events-none block-link-reference-row">
-        {linkType === 'P' ? (
-          <PageName pageName={id} />
-        ) : (
-          <>
-            <Breadcrumb levelLimit={1} blockId={id} endSeparator={showReferenceContent} />
-            {showReferenceContent && slicedContent}
-          </>
-        )}
-      </span>
-    </button>
-  )
-}

+ 0 - 1
packages/tldraw/apps/tldraw-logseq/src/components/BlockLink/index.ts

@@ -1 +0,0 @@
-export * from './BlockLink'

+ 0 - 15
packages/tldraw/apps/tldraw-logseq/src/components/Button/Button.tsx

@@ -1,15 +0,0 @@
-import { Tooltip } from '../Tooltip'
-import type { Side } from '@radix-ui/react-popper'
-export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
-  children: React.ReactNode
-  tooltip?: React.ReactNode
-  tooltipSide?: Side
-}
-
-export function Button({ className, tooltip, tooltipSide, ...rest }: ButtonProps) {
-  return (
-    <Tooltip content={tooltip} side={tooltipSide}>
-      <button className={'tl-button ' + (className ?? '')} {...rest} />
-    </Tooltip>
-  )
-}

+ 0 - 26
packages/tldraw/apps/tldraw-logseq/src/components/Button/CircleButton.tsx

@@ -1,26 +0,0 @@
-import { TablerIcon } from '../icons'
-
-export const CircleButton = ({
-  style,
-  icon,
-  onClick,
-}: {
-  active?: boolean
-  style?: React.CSSProperties
-  icon: string
-  otherIcon?: string
-  onClick: () => void
-}) => {
-  return (
-    <button
-      data-html2canvas-ignore="true"
-      style={style}
-      className="tl-circle-button"
-      onPointerDown={onClick}
-    >
-      <div className="tl-circle-button-icons-wrapper">
-        <TablerIcon name={icon} />
-      </div>
-    </button>
-  )
-}

+ 0 - 2
packages/tldraw/apps/tldraw-logseq/src/components/Button/index.ts

@@ -1,2 +0,0 @@
-export * from './Button'
-export * from './CircleButton'

+ 0 - 67
packages/tldraw/apps/tldraw-logseq/src/components/ContextBar/ContextBar.tsx

@@ -1,67 +0,0 @@
-import {
-  getContextBarTranslation,
-  HTMLContainer,
-  TLContextBarComponent,
-  useApp,
-} from '@tldraw/react'
-import { observer } from 'mobx-react-lite'
-
-import * as React from 'react'
-import type { Shape } from '../../lib'
-import { getContextBarActionsForShapes } from './contextBarActionFactory'
-
-// @ts-ignore
-const LSUI = window.LSUI
-
-const _ContextBar: TLContextBarComponent<Shape> = ({ shapes, offsets, hidden }) => {
-  const app = useApp()
-  const rSize = React.useRef<[number, number] | null>(null)
-  const rContextBar = React.useRef<HTMLDivElement>(null)
-
-  React.useLayoutEffect(() => {
-    setTimeout(() => {
-      const elm = rContextBar.current
-      if (!elm) return
-      const { offsetWidth, offsetHeight } = elm
-      rSize.current = [offsetWidth, offsetHeight]
-    })
-  })
-
-  React.useLayoutEffect(() => {
-    const elm = rContextBar.current
-    if (!elm) return
-    const size = rSize.current ?? [0, 0]
-    const [x, y] = getContextBarTranslation(size, offsets)
-    elm.style.transform = `translateX(${x}px) translateY(${y}px)`
-  }, [offsets])
-
-  if (!app) return null
-
-  const Actions = getContextBarActionsForShapes(shapes)
-
-  return (
-    <HTMLContainer centered>
-      {Actions.length > 0 && (
-        <div
-          ref={rContextBar}
-          className="tl-toolbar tl-context-bar"
-          style={{
-            visibility: hidden ? 'hidden' : 'visible',
-            pointerEvents: hidden ? 'none' : 'all',
-          }}
-        >
-          {Actions.map((Action, idx) => (
-            <React.Fragment key={idx}>
-              <Action />
-              {idx < Actions.length - 1 && (
-                <LSUI.Separator className="tl-toolbar-separator" orientation="vertical" />
-              )}
-            </React.Fragment>
-          ))}
-        </div>
-      )}
-    </HTMLContainer>
-  )
-}
-
-export const ContextBar = observer(_ContextBar)

+ 0 - 560
packages/tldraw/apps/tldraw-logseq/src/components/ContextBar/contextBarActionFactory.tsx

@@ -1,560 +0,0 @@
-import { Decoration, isNonNullable } from '@tldraw/core'
-import { useApp } from '@tldraw/react'
-import { observer } from 'mobx-react-lite'
-import React from 'react'
-import type {
-  BoxShape,
-  EllipseShape,
-  HTMLShape,
-  IFrameShape,
-  LineShape,
-  LogseqPortalShape,
-  PencilShape,
-  PolygonShape,
-  Shape,
-  TextShape,
-  YouTubeShape,
-  TweetShape,
-} from '../../lib'
-import { Button } from '../Button'
-import { TablerIcon } from '../icons'
-import { ColorInput } from '../inputs/ColorInput'
-import { ScaleInput } from '../inputs/ScaleInput'
-import { ShapeLinksInput } from '../inputs/ShapeLinksInput'
-import { TextInput } from '../inputs/TextInput'
-import {
-  ToggleGroupInput,
-  ToggleGroupMultipleInput,
-  type ToggleGroupInputOption,
-} from '../inputs/ToggleGroupInput'
-import { ToggleInput } from '../inputs/ToggleInput'
-import { GeometryTools } from '../GeometryTools'
-import { LogseqContext } from '../../lib/logseq-context'
-import { KeyboardShortcut } from '../KeyboardShortcut'
-
-export const contextBarActionTypes = [
-  // Order matters
-  'EditPdf',
-  'LogseqPortalViewMode',
-  'Geometry',
-  'AutoResizing',
-  'Swatch',
-  'NoFill',
-  'StrokeType',
-  'ScaleLevel',
-  'TextStyle',
-  'YoutubeLink',
-  'TwitterLink',
-  'IFrameSource',
-  'ArrowMode',
-  'Links',
-] as const
-
-type ContextBarActionType = typeof contextBarActionTypes[number]
-const singleShapeActions: ContextBarActionType[] = [
-  'YoutubeLink',
-  'TwitterLink',
-  'IFrameSource',
-  'Links',
-  'EditPdf',
-]
-
-const contextBarActionMapping = new Map<ContextBarActionType, React.FC>()
-
-type ShapeType = Shape['props']['type']
-
-export const shapeMapping: Record<ShapeType, ContextBarActionType[]> = {
-  'logseq-portal': ['Swatch', 'LogseqPortalViewMode', 'ScaleLevel', 'AutoResizing', 'Links'],
-  youtube: ['YoutubeLink', 'Links'],
-  tweet: ['TwitterLink', 'Links'],
-  iframe: ['IFrameSource', 'Links'],
-  box: ['Geometry', 'TextStyle', 'Swatch', 'ScaleLevel', 'NoFill', 'StrokeType', 'Links'],
-  ellipse: ['Geometry', 'TextStyle', 'Swatch', 'ScaleLevel', 'NoFill', 'StrokeType', 'Links'],
-  polygon: ['Geometry', 'TextStyle', 'Swatch', 'ScaleLevel', 'NoFill', 'StrokeType', 'Links'],
-  line: ['TextStyle', 'Swatch', 'ScaleLevel', 'ArrowMode', 'Links'],
-  pencil: ['Swatch', 'Links', 'ScaleLevel'],
-  highlighter: ['Swatch', 'Links', 'ScaleLevel'],
-  text: ['TextStyle', 'Swatch', 'ScaleLevel', 'AutoResizing', 'Links'],
-  html: ['ScaleLevel', 'AutoResizing', 'Links'],
-  image: ['Links'],
-  video: ['Links'],
-  pdf: ['EditPdf', 'Links'],
-}
-
-export const withFillShapes = Object.entries(shapeMapping)
-  .filter(([key, types]) => {
-    return types.includes('NoFill') && types.includes('Swatch')
-  })
-  .map(([key]) => key) as ShapeType[]
-
-function filterShapeByAction<S extends Shape>(type: ContextBarActionType) {
-  const app = useApp<Shape>()
-  const unlockedSelectedShapes = app.selectedShapesArray.filter(s => !s.props.isLocked)
-  return unlockedSelectedShapes.filter(shape => shapeMapping[shape.props.type]?.includes(type))
-}
-
-const AutoResizingAction = observer(() => {
-  const app = useApp<Shape>()
-  const {
-    handlers: { t },
-  } = React.useContext(LogseqContext)
-  const shapes = filterShapeByAction<LogseqPortalShape | TextShape | HTMLShape>('AutoResizing')
-
-  const pressed = shapes.every(s => s.props.isAutoResizing)
-
-  return (
-    <ToggleInput
-      tooltip={t('whiteboard/auto-resize')}
-      toggle={shapes.every(s => s.props.type === 'logseq-portal')}
-      className="tl-button"
-      pressed={pressed}
-      onPressedChange={v => {
-        shapes.forEach(s => {
-          if (s.props.type === 'logseq-portal') {
-            s.update({
-              isAutoResizing: v,
-            })
-          } else {
-            s.onResetBounds({ zoom: app.viewport.camera.zoom })
-          }
-        })
-        app.persist()
-      }}
-    >
-      <TablerIcon name="dimensions" />
-    </ToggleInput>
-  )
-})
-
-const LogseqPortalViewModeAction = observer(() => {
-  const app = useApp<Shape>()
-  const {
-    handlers: { t },
-  } = React.useContext(LogseqContext)
-  const shapes = filterShapeByAction<LogseqPortalShape>('LogseqPortalViewMode')
-
-  const collapsed = shapes.every(s => s.collapsed)
-  if (!collapsed && !shapes.every(s => !s.collapsed)) {
-    return null
-  }
-
-  const tooltip = (
-    <div className="flex">
-      {collapsed ? t('whiteboard/expand') : t('whiteboard/collapse')}
-      <KeyboardShortcut
-        action={collapsed ? 'editor/expand-block-children' : 'editor/collapse-block-children'}
-      />
-    </div>
-  )
-
-  return (
-    <ToggleInput
-      tooltip={tooltip}
-      toggle={shapes.every(s => s.props.type === 'logseq-portal')}
-      className="tl-button"
-      pressed={collapsed}
-      onPressedChange={() => app.api.setCollapsed(!collapsed)}
-    >
-      <TablerIcon name={collapsed ? 'object-expanded' : 'object-compact'} />
-    </ToggleInput>
-  )
-})
-
-const ScaleLevelAction = observer(() => {
-  const {
-    handlers: { isMobile },
-  } = React.useContext(LogseqContext)
-
-  const shapes = filterShapeByAction<LogseqPortalShape>('ScaleLevel')
-  const scaleLevel = new Set(shapes.map(s => s.scaleLevel)).size > 1 ? '' : shapes[0].scaleLevel
-
-  return <ScaleInput scaleLevel={scaleLevel} compact={isMobile()} />
-})
-
-const IFrameSourceAction = observer(() => {
-  const app = useApp<Shape>()
-  const {
-    handlers: { t },
-  } = React.useContext(LogseqContext)
-  const shape = filterShapeByAction<IFrameShape>('IFrameSource')[0]
-
-  const handleChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
-    shape.onIFrameSourceChange(e.target.value.trim().toLowerCase())
-    app.persist()
-  }, [])
-
-  const handleReload = React.useCallback(() => {
-    shape.reload()
-  }, [])
-
-  return (
-    <span className="flex gap-3">
-      <Button tooltip={t('whiteboard/reload')} type="button" onClick={handleReload}>
-        <TablerIcon name="refresh" />
-      </Button>
-      <TextInput
-        title={t('whiteboard/website-url')}
-        className="tl-iframe-src"
-        value={`${shape.props.url}`}
-        onChange={handleChange}
-      />
-      <Button
-        tooltip={t('whiteboard/open-website-url')}
-        type="button"
-        onClick={() => window.open(shape.props.url)}
-      >
-        <TablerIcon name="external-link" />
-      </Button>
-    </span>
-  )
-})
-
-const YoutubeLinkAction = observer(() => {
-  const app = useApp<Shape>()
-  const {
-    handlers: { t },
-  } = React.useContext(LogseqContext)
-  const shape = filterShapeByAction<YouTubeShape>('YoutubeLink')[0]
-  const handleChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
-    shape.onYoutubeLinkChange(e.target.value)
-    app.persist()
-  }, [])
-
-  return (
-    <span className="flex gap-3">
-      <TextInput
-        title={t('whiteboard/youtube-url')}
-        className="tl-youtube-link"
-        value={`${shape.props.url}`}
-        onChange={handleChange}
-      />
-      <Button
-        tooltip={t('whiteboard/open-youtube-url')}
-        type="button"
-        onClick={() => window.logseq?.api?.open_external_link?.(shape.props.url)}
-      >
-        <TablerIcon name="external-link" />
-      </Button>
-    </span>
-  )
-})
-
-const TwitterLinkAction = observer(() => {
-  const app = useApp<Shape>()
-  const {
-    handlers: { t },
-  } = React.useContext(LogseqContext)
-  const shape = filterShapeByAction<TweetShape>('TwitterLink')[0]
-  const handleChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
-    shape.onTwitterLinkChange(e.target.value)
-    app.persist()
-  }, [])
-
-  return (
-    <span className="flex gap-3">
-      <TextInput
-        title={t('whiteboard/twitter-url')}
-        className="tl-twitter-link"
-        value={`${shape.props.url}`}
-        onChange={handleChange}
-      />
-      <Button
-        tooltip={t('whiteboard/open-twitter-url')}
-        type="button"
-        onClick={() => window.logseq?.api?.open_external_link?.(shape.props.url)}
-      >
-        <TablerIcon name="external-link" />
-      </Button>
-    </span>
-  )
-})
-
-const EditPdfAction = observer(() => {
-  const app = useApp<Shape>()
-  const {
-    handlers: { t, setCurrentPdf },
-  } = React.useContext(LogseqContext)
-  const shape = app.selectedShapesArray[0]
-
-  return (
-    <Button
-      tooltip={t('whiteboard/edit-pdf')}
-      type="button"
-      onClick={() => setCurrentPdf(app.assets[shape.props.assetId].src)}
-    >
-      <TablerIcon name="edit" />
-    </Button>
-  )
-})
-
-const NoFillAction = observer(() => {
-  const app = useApp<Shape>()
-  const {
-    handlers: { t },
-  } = React.useContext(LogseqContext)
-  const shapes = filterShapeByAction<BoxShape | PolygonShape | EllipseShape>('NoFill')
-  const handleChange = React.useCallback((v: boolean) => {
-    app.selectedShapesArray.forEach(s => s.update({ noFill: v }))
-    app.persist()
-  }, [])
-
-  const noFill = shapes.every(s => s.props.noFill)
-
-  return (
-    <ToggleInput
-      tooltip={t('whiteboard/fill')}
-      className="tl-button"
-      pressed={noFill}
-      onPressedChange={handleChange}
-    >
-      <TablerIcon name={noFill ? 'droplet-off' : 'droplet'} />
-    </ToggleInput>
-  )
-})
-
-const SwatchAction = observer(() => {
-  const app = useApp<Shape>()
-  // Placeholder
-  const shapes = filterShapeByAction<
-    BoxShape | PolygonShape | EllipseShape | LineShape | PencilShape | TextShape
-  >('Swatch')
-
-  const handleSetColor = React.useCallback((color: string) => {
-    app.selectedShapesArray.forEach(s => {
-      s.update({ fill: color, stroke: color })
-    })
-    app.persist()
-  }, [])
-
-  const handleSetOpacity = React.useCallback((opacity: number) => {
-    app.selectedShapesArray.forEach(s => {
-      s.update({ opacity: opacity })
-    })
-    app.persist()
-  }, [])
-
-  const color = shapes[0].props.noFill ? shapes[0].props.stroke : shapes[0].props.fill
-  return (
-    <ColorInput
-      popoverSide="top"
-      color={color}
-      opacity={shapes[0].props.opacity}
-      setOpacity={handleSetOpacity}
-      setColor={handleSetColor}
-    />
-  )
-})
-
-const GeometryAction = observer(() => {
-  const app = useApp<Shape>()
-
-  const handleSetGeometry = React.useCallback((e: React.MouseEvent<HTMLButtonElement>) => {
-    const type = e.currentTarget.dataset.tool
-    app.api.convertShapes(type)
-  }, [])
-
-  return <GeometryTools popoverSide="top" chevron={false} setGeometry={handleSetGeometry} />
-})
-
-const StrokeTypeAction = observer(() => {
-  const app = useApp<Shape>()
-  const {
-    handlers: { t },
-  } = React.useContext(LogseqContext)
-  const shapes = filterShapeByAction<
-    BoxShape | PolygonShape | EllipseShape | LineShape | PencilShape
-  >('StrokeType')
-
-  const StrokeTypeOptions: ToggleGroupInputOption[] = [
-    {
-      value: 'line',
-      icon: 'circle',
-      tooltip: 'Solid',
-    },
-    {
-      value: 'dashed',
-      icon: 'circle-dashed',
-      tooltip: 'Dashed',
-    },
-  ]
-
-  const value = shapes.every(s => s.props.strokeType === 'dashed')
-    ? 'dashed'
-    : shapes.every(s => s.props.strokeType === 'line')
-    ? 'line'
-    : 'mixed'
-
-  return (
-    <ToggleGroupInput
-      title={t('whiteboard/stroke-type')}
-      options={StrokeTypeOptions}
-      value={value}
-      onValueChange={v => {
-        shapes.forEach(shape => {
-          shape.update({
-            strokeType: v,
-          })
-        })
-        app.persist()
-      }}
-    />
-  )
-})
-
-const ArrowModeAction = observer(() => {
-  const app = useApp<Shape>()
-  const {
-    handlers: { t },
-  } = React.useContext(LogseqContext)
-  const shapes = filterShapeByAction<LineShape>('ArrowMode')
-
-  const StrokeTypeOptions: ToggleGroupInputOption[] = [
-    {
-      value: 'start',
-      icon: 'arrow-narrow-left',
-    },
-    {
-      value: 'end',
-      icon: 'arrow-narrow-right',
-    },
-  ]
-
-  const startValue = shapes.every(s => s.props.decorations?.start === Decoration.Arrow)
-  const endValue = shapes.every(s => s.props.decorations?.end === Decoration.Arrow)
-
-  const value = [startValue ? 'start' : null, endValue ? 'end' : null].filter(isNonNullable)
-
-  const valueToDecorations = (value: string[]) => {
-    return {
-      start: value.includes('start') ? Decoration.Arrow : null,
-      end: value.includes('end') ? Decoration.Arrow : null,
-    }
-  }
-
-  return (
-    <ToggleGroupMultipleInput
-      title={t('whiteboard/arrow-head')}
-      options={StrokeTypeOptions}
-      value={value}
-      onValueChange={v => {
-        shapes.forEach(shape => {
-          shape.update({
-            decorations: valueToDecorations(v),
-          })
-        })
-        app.persist()
-      }}
-    />
-  )
-})
-
-const TextStyleAction = observer(() => {
-  const app = useApp<Shape>()
-  const {
-    handlers: { t },
-  } = React.useContext(LogseqContext)
-  const shapes = filterShapeByAction<TextShape>('TextStyle')
-
-  const bold = shapes.every(s => s.props.fontWeight > 500)
-  const italic = shapes.every(s => s.props.italic)
-
-  return (
-    <span className="flex gap-1">
-      <ToggleInput
-        tooltip={t('whiteboard/bold')}
-        className="tl-button"
-        pressed={bold}
-        onPressedChange={v => {
-          shapes.forEach(shape => {
-            shape.update({
-              fontWeight: v ? 700 : 400,
-            })
-            shape.onResetBounds()
-          })
-          app.persist()
-        }}
-      >
-        <TablerIcon name="bold" />
-      </ToggleInput>
-      <ToggleInput
-        tooltip={t('whiteboard/italic')}
-        className="tl-button"
-        pressed={italic}
-        onPressedChange={v => {
-          shapes.forEach(shape => {
-            shape.update({
-              italic: v,
-            })
-            shape.onResetBounds()
-          })
-          app.persist()
-        }}
-      >
-        <TablerIcon name="italic" />
-      </ToggleInput>
-    </span>
-  )
-})
-
-const LinksAction = observer(() => {
-  const app = useApp<Shape>()
-  const shape = app.selectedShapesArray[0]
-
-  const handleChange = (refs: string[]) => {
-    shape.update({ refs: refs })
-    app.persist()
-  }
-
-  return (
-    <ShapeLinksInput
-      onRefsChange={handleChange}
-      refs={shape.props.refs ?? []}
-      shapeType={shape.props.type}
-      side="right"
-      pageId={shape.props.type === 'logseq-portal' ? shape.props.pageId : undefined}
-      portalType={shape.props.type === 'logseq-portal' ? shape.props.blockType : undefined}
-    />
-  )
-})
-
-contextBarActionMapping.set('Geometry', GeometryAction)
-contextBarActionMapping.set('AutoResizing', AutoResizingAction)
-contextBarActionMapping.set('LogseqPortalViewMode', LogseqPortalViewModeAction)
-contextBarActionMapping.set('ScaleLevel', ScaleLevelAction)
-contextBarActionMapping.set('YoutubeLink', YoutubeLinkAction)
-contextBarActionMapping.set('TwitterLink', TwitterLinkAction)
-contextBarActionMapping.set('IFrameSource', IFrameSourceAction)
-contextBarActionMapping.set('NoFill', NoFillAction)
-contextBarActionMapping.set('Swatch', SwatchAction)
-contextBarActionMapping.set('StrokeType', StrokeTypeAction)
-contextBarActionMapping.set('ArrowMode', ArrowModeAction)
-contextBarActionMapping.set('TextStyle', TextStyleAction)
-contextBarActionMapping.set('Links', LinksAction)
-contextBarActionMapping.set('EditPdf', EditPdfAction)
-const getContextBarActionTypes = (type: ShapeType) => {
-  return (shapeMapping[type] ?? []).filter(isNonNullable)
-}
-
-export const getContextBarActionsForShapes = (shapes: Shape[]) => {
-  const types = shapes.map(s => s.props.type)
-  const actionTypes = new Set(shapes.length > 0 ? getContextBarActionTypes(types[0]) : [])
-  for (let i = 1; i < types.length && actionTypes.size > 0; i++) {
-    const otherActionTypes = getContextBarActionTypes(types[i])
-    actionTypes.forEach(action => {
-      if (!otherActionTypes.includes(action)) {
-        actionTypes.delete(action)
-      }
-    })
-  }
-  if (shapes.length > 1) {
-    singleShapeActions.forEach(action => {
-      if (actionTypes.has(action)) {
-        actionTypes.delete(action)
-      }
-    })
-  }
-
-  return Array.from(actionTypes)
-    .sort((a, b) => contextBarActionTypes.indexOf(a) - contextBarActionTypes.indexOf(b))
-    .map(action => contextBarActionMapping.get(action)!)
-}

+ 0 - 2
packages/tldraw/apps/tldraw-logseq/src/components/ContextBar/index.ts

@@ -1,2 +0,0 @@
-export * from './ContextBar'
-export * from './contextBarActionFactory'

+ 0 - 369
packages/tldraw/apps/tldraw-logseq/src/components/ContextMenu/ContextMenu.tsx

@@ -1,369 +0,0 @@
-import { useApp } from '@tldraw/react'
-import { LogseqContext } from '../../lib/logseq-context'
-import {
-  MOD_KEY,
-  AlignType,
-  DistributeType,
-  isDev,
-  EXPORT_PADDING
-} from '@tldraw/core'
-import { observer } from 'mobx-react-lite'
-import { TablerIcon } from '../icons'
-import { Button } from '../Button'
-import { KeyboardShortcut } from '../KeyboardShortcut'
-import * as React from 'react'
-import { toJS } from 'mobx'
-
-// @ts-ignore
-const LSUI = window.LSUI
-
-interface ContextMenuProps {
-  children: React.ReactNode
-  collisionRef: React.RefObject<HTMLDivElement>
-}
-
-export const ContextMenu = observer(function ContextMenu({
-  children,
-  collisionRef,
-}: ContextMenuProps) {
-  const app = useApp()
-  const { handlers } = React.useContext(LogseqContext)
-  const t = handlers.t
-  const rContent = React.useRef<HTMLDivElement>(null)
-
-  const runAndTransition = (f: Function) => {
-    f()
-    app.transition('select')
-  }
-
-  const developerMode = React.useMemo(() => {
-    return isDev()
-  }, [])
-
-  return (
-    <LSUI.ContextMenu
-      onOpenChange={(open: boolean) => {
-        if (open && !app.isIn('select.contextMenu')) {
-          app.transition('select').selectedTool.transition('contextMenu')
-        } else if (!open && app.isIn('select.contextMenu')) {
-          app.selectedTool.transition('idle')
-        }
-      }}
-    >
-      <LSUI.ContextMenuTrigger
-        disabled={app.editingShape && Object.keys(app.editingShape).length !== 0}
-      >
-        {children}
-      </LSUI.ContextMenuTrigger>
-      <LSUI.ContextMenuContent
-        className="tl-menu tl-context-menu"
-        ref={rContent}
-        onEscapeKeyDown={() => app.transition('select')}
-        collisionBoundary={collisionRef.current}
-        asChild
-        tabIndex={-1}
-      >
-        <div>
-          {app.selectedShapes?.size > 1 &&
-            !app.readOnly &&
-            app.selectedShapesArray?.some(s => !s.props.isLocked) && (
-              <>
-                <LSUI.ContextMenuItem className={'tl-menu-button-row-wrap'}>
-                  <div className="tl-menu-button-row pb-0">
-                    <Button
-                      tooltip={t('whiteboard/align-left')}
-                      onClick={() => runAndTransition(() => app.align(AlignType.Left))}
-                    >
-                      <TablerIcon name="layout-align-left"/>
-                    </Button>
-                    <Button
-                      tooltip={t('whiteboard/align-center-horizontally')}
-                      onClick={() => runAndTransition(() => app.align(AlignType.CenterHorizontal))}
-                    >
-                      <TablerIcon name="layout-align-center"/>
-                    </Button>
-                    <Button
-                      tooltip={t('whiteboard/align-right')}
-                      onClick={() => runAndTransition(() => app.align(AlignType.Right))}
-                    >
-                      <TablerIcon name="layout-align-right"/>
-                    </Button>
-                    <LSUI.Separator className="tl-toolbar-separator"
-                                    orientation="vertical"/>
-                    <Button
-                      tooltip={t('whiteboard/distribute-horizontally')}
-                      onClick={() =>
-                        runAndTransition(() => app.distribute(DistributeType.Horizontal))
-                      }
-                    >
-                      <TablerIcon name="layout-distribute-vertical"/>
-                    </Button>
-                  </div>
-                  <div className="tl-menu-button-row pt-0">
-                    <Button
-                      tooltip={t('whiteboard/align-top')}
-                      onClick={() => runAndTransition(() => app.align(AlignType.Top))}
-                    >
-                      <TablerIcon name="layout-align-top"/>
-                    </Button>
-                    <Button
-                      tooltip={t('whiteboard/align-center-vertically')}
-                      onClick={() => runAndTransition(() => app.align(AlignType.CenterVertical))}
-                    >
-                      <TablerIcon name="layout-align-middle"/>
-                    </Button>
-                    <Button
-                      tooltip={t('whiteboard/align-bottom')}
-                      onClick={() => runAndTransition(() => app.align(AlignType.Bottom))}
-                    >
-                      <TablerIcon name="layout-align-bottom"/>
-                    </Button>
-                    <LSUI.Separator className="tl-toolbar-separator"
-                                    orientation="vertical"/>
-                    <Button
-                      tooltip={t('whiteboard/distribute-vertically')}
-                      onClick={() =>
-                        runAndTransition(() => app.distribute(DistributeType.Vertical))
-                      }
-                    >
-                      <TablerIcon name="layout-distribute-horizontal"/>
-                    </Button>
-                  </div>
-                </LSUI.ContextMenuItem>
-                <LSUI.ContextMenuSeparator className="menu-separator"/>
-                <LSUI.ContextMenuItem
-                  className="tl-menu-item"
-                  onClick={() => runAndTransition(app.packIntoRectangle)}
-                >
-                  <TablerIcon className="tl-menu-icon" name="layout-grid"/>
-                  {t('whiteboard/pack-into-rectangle')}
-                </LSUI.ContextMenuItem>
-                <LSUI.ContextMenuSeparator className="menu-separator"/>
-              </>
-            )}
-          {app.selectedShapes?.size > 0 && (
-            <>
-              <LSUI.ContextMenuItem
-                className="tl-menu-item"
-                onClick={() => runAndTransition(app.api.zoomToSelection)}
-              >
-                <TablerIcon className="tl-menu-icon" name="circle-dotted"/>
-                {t('whiteboard/zoom-to-fit')}
-                <KeyboardShortcut action="whiteboard/zoom-to-fit"/>
-              </LSUI.ContextMenuItem>
-              <LSUI.ContextMenuSeparator className="menu-separator"/>
-            </>
-          )}
-          {(app.selectedShapesArray.some(s => s.type === 'group' || app.getParentGroup(s)) ||
-              app.selectedShapesArray.length > 1) &&
-            app.selectedShapesArray?.some(s => !s.props.isLocked) &&
-            !app.readOnly && (
-              <>
-                {app.selectedShapesArray.some(s => s.type === 'group' || app.getParentGroup(s)) && (
-                  <LSUI.ContextMenuItem
-                    className="tl-menu-item"
-                    onClick={() => runAndTransition(app.api.unGroup)}
-                  >
-                    <TablerIcon className="tl-menu-icon" name="ungroup"/>
-                    {t('whiteboard/ungroup')}
-                    <KeyboardShortcut action="whiteboard/ungroup"/>
-                  </LSUI.ContextMenuItem>
-                )}
-                {app.selectedShapesArray.length > 1 &&
-                  app.selectedShapesArray?.some(s => !s.props.isLocked) && (
-                    <LSUI.ContextMenuItem
-                      className="tl-menu-item"
-                      onClick={() => runAndTransition(app.api.doGroup)}
-                    >
-                      <TablerIcon className="tl-menu-icon" name="group"/>
-                      {t('whiteboard/group')}
-                      <KeyboardShortcut action="whiteboard/group"/>
-                    </LSUI.ContextMenuItem>
-                  )}
-                <LSUI.ContextMenuSeparator className="menu-separator"/>
-              </>
-            )}
-          {app.selectedShapes?.size > 0 && app.selectedShapesArray?.some(s => !s.props.isLocked) && (
-            <>
-              {!app.readOnly && (
-                <LSUI.ContextMenuItem
-                  className="tl-menu-item"
-                  onClick={() => runAndTransition(app.cut)}
-                >
-                  <TablerIcon className="tl-menu-icon" name="cut"/>
-                  {t('whiteboard/cut')}
-                </LSUI.ContextMenuItem>
-              )}
-              <LSUI.ContextMenuItem
-                className="tl-menu-item"
-                onClick={() => runAndTransition(app.copy)}
-              >
-                <TablerIcon className="tl-menu-icon" name="copy"/>
-                {t('whiteboard/copy')}
-                <KeyboardShortcut action="editor/copy"/>
-              </LSUI.ContextMenuItem>
-            </>
-          )}
-          {!app.readOnly && (
-            <LSUI.ContextMenuItem
-              className="tl-menu-item"
-              onClick={() => runAndTransition(app.paste)}
-            >
-              <TablerIcon className="tl-menu-icon" name="clipboard"/>
-              {t('whiteboard/paste')}
-              <KeyboardShortcut shortcut={`${MOD_KEY}+v`}/>
-            </LSUI.ContextMenuItem>
-          )}
-          {app.selectedShapes?.size === 1 && !app.readOnly && (
-            <LSUI.ContextMenuItem
-              className="tl-menu-item"
-              onClick={() => runAndTransition(() => app.paste(undefined, true))}
-            >
-              <TablerIcon className="tl-menu-icon" name="circle-dotted"/>
-              {t('whiteboard/paste-as-link')}
-              <KeyboardShortcut shortcut={`${MOD_KEY}+⇧+v`}/>
-            </LSUI.ContextMenuItem>
-          )}
-          {app.selectedShapes?.size > 0 && (
-            <>
-              <LSUI.ContextMenuSeparator className="menu-separator"/>
-              <LSUI.ContextMenuItem
-                className="tl-menu-item"
-                onClick={() =>
-                  runAndTransition(() =>
-                    handlers.exportToImage(app.currentPageId, {
-                      x: app.selectionBounds.minX + app.viewport.camera.point[0] - EXPORT_PADDING,
-                      y: app.selectionBounds.minY + app.viewport.camera.point[1] - EXPORT_PADDING,
-                      width: app.selectionBounds?.width + EXPORT_PADDING * 2,
-                      height: app.selectionBounds?.height + EXPORT_PADDING * 2,
-                      zoom: app.viewport.camera.zoom,
-                    })
-                  )
-                }
-              >
-                <TablerIcon className="tl-menu-icon" name="file-export"/>
-                {t('whiteboard/export')}
-                <div className="tl-menu-right-slot">
-                  <span className="keyboard-shortcut"></span>
-                </div>
-              </LSUI.ContextMenuItem>
-            </>
-          )}
-          <LSUI.ContextMenuSeparator className="menu-separator"/>
-          <LSUI.ContextMenuItem
-            className="tl-menu-item"
-            onClick={() => runAndTransition(app.api.selectAll)}
-          >
-            <TablerIcon className="tl-menu-icon" name="circle-dotted"/>
-            {t('whiteboard/select-all')}
-            <KeyboardShortcut action="editor/select-parent"/>
-          </LSUI.ContextMenuItem>
-          {app.selectedShapes?.size > 1 && (
-            <LSUI.ContextMenuItem
-              className="tl-menu-item"
-              onClick={() => runAndTransition(app.api.deselectAll)}
-            >
-              <TablerIcon className="tl-menu-icon" name="circle-dotted"/>
-              {t('whiteboard/deselect-all')}
-            </LSUI.ContextMenuItem>
-          )}
-          {!app.readOnly &&
-            app.selectedShapes?.size > 0 &&
-            app.selectedShapesArray?.some(s => !s.props.isLocked) && (
-              <LSUI.ContextMenuItem
-                className="tl-menu-item"
-                onClick={() => runAndTransition(() => app.setLocked(true))}
-              >
-                <TablerIcon className="tl-menu-icon" name="lock"/>
-                {t('whiteboard/lock')}
-                <KeyboardShortcut action="whiteboard/lock"/>
-              </LSUI.ContextMenuItem>
-            )}
-          {!app.readOnly &&
-            app.selectedShapes?.size > 0 &&
-            app.selectedShapesArray?.some(s => s.props.isLocked) && (
-              <LSUI.ContextMenuItem
-                className="tl-menu-item"
-                onClick={() => runAndTransition(() => app.setLocked(false))}
-              >
-                <TablerIcon className="tl-menu-icon" name="lock-open"/>
-                {t('whiteboard/unlock')}
-                <KeyboardShortcut action="whiteboard/unlock"/>
-              </LSUI.ContextMenuItem>
-            )}
-          {app.selectedShapes?.size > 0 &&
-            !app.readOnly &&
-            app.selectedShapesArray?.some(s => !s.props.isLocked) && (
-              <>
-                <LSUI.ContextMenuItem
-                  className="tl-menu-item"
-                  onClick={() => runAndTransition(app.api.deleteShapes)}
-                >
-                  <TablerIcon className="tl-menu-icon" name="backspace"/>
-                  {t('whiteboard/delete')}
-                  <KeyboardShortcut action="editor/delete"/>
-                </LSUI.ContextMenuItem>
-                {app.selectedShapes?.size > 1 && !app.readOnly && (
-                  <>
-                    <LSUI.ContextMenuSeparator className="menu-separator"/>
-                    <LSUI.ContextMenuItem
-                      className="tl-menu-item"
-                      onClick={() => runAndTransition(app.flipHorizontal)}
-                    >
-                      <TablerIcon className="tl-menu-icon"
-                                  name="flip-horizontal"/>
-                      {t('whiteboard/flip-horizontally')}
-                    </LSUI.ContextMenuItem>
-                    <LSUI.ContextMenuItem
-                      className="tl-menu-item"
-                      onClick={() => runAndTransition(app.flipVertical)}
-                    >
-                      <TablerIcon className="tl-menu-icon"
-                                  name="flip-vertical"/>
-                      {t('whiteboard/flip-vertically')}
-                    </LSUI.ContextMenuItem>
-                  </>
-                )}
-                {!app.readOnly && (
-                  <>
-                    <LSUI.ContextMenuSeparator className="menu-separator"/>
-                    <LSUI.ContextMenuItem
-                      className="tl-menu-item"
-                      onClick={() => runAndTransition(app.bringToFront)}
-                    >
-                      <TablerIcon className="tl-menu-icon" name="circle-dotted"/>
-                      {t('whiteboard/move-to-front')}
-                      <KeyboardShortcut action="whiteboard/bring-to-front"/>
-                    </LSUI.ContextMenuItem>
-                    <LSUI.ContextMenuItem
-                      className="tl-menu-item"
-                      onClick={() => runAndTransition(app.sendToBack)}
-                    >
-                      <TablerIcon className="tl-menu-icon" name="circle-dotted"/>
-                      {t('whiteboard/move-to-back')}
-                      <KeyboardShortcut action="whiteboard/send-to-back"/>
-                    </LSUI.ContextMenuItem>
-                  </>
-                )}
-
-                {developerMode && (
-                  <LSUI.ContextMenuItem
-                    className="tl-menu-item"
-                    onClick={() => {
-                      if (app.selectedShapesArray.length === 1) {
-                        console.log(toJS(app.selectedShapesArray[0].serialized))
-                      } else {
-                        console.log(app.selectedShapesArray.map(s => toJS(s.serialized)))
-                      }
-                    }}
-                  >
-                    {t('whiteboard/dev-print-shape-props')}
-                  </LSUI.ContextMenuItem>
-                )}
-              </>
-            )}
-        </div>
-      </LSUI.ContextMenuContent>
-    </LSUI.ContextMenu>
-  )
-})

+ 0 - 1
packages/tldraw/apps/tldraw-logseq/src/components/ContextMenu/index.ts

@@ -1 +0,0 @@
-export * from './ContextMenu'

+ 0 - 56
packages/tldraw/apps/tldraw-logseq/src/components/Devtools/Devtools.tsx

@@ -1,56 +0,0 @@
-import { useRendererContext } from '@tldraw/react'
-import { observer } from 'mobx-react-lite'
-import React from 'react'
-import ReactDOM from 'react-dom'
-
-const printPoint = (point: number[]) => {
-  return `[${point.map(d => d?.toFixed(2) ?? '-').join(', ')}]`
-}
-
-export const DevTools = observer(() => {
-  const {
-    viewport: {
-      bounds,
-      camera: { point, zoom },
-    },
-    inputs,
-  } = useRendererContext()
-
-  const statusbarAnchorRef = React.useRef<HTMLElement | null>()
-
-  React.useEffect(() => {
-    const statusbarAnchor = document.getElementById('tl-statusbar-anchor')
-    statusbarAnchorRef.current = statusbarAnchor
-  }, [])
-
-  const rendererStatusText = [
-    ['Z', zoom?.toFixed(2) ?? 'null'],
-    ['MP', printPoint(inputs.currentPoint)],
-    ['MS', printPoint(inputs.currentScreenPoint)],
-    ['VP', printPoint(point)],
-    ['VBR', printPoint([bounds.maxX, bounds.maxY])],
-  ]
-    .map(p => p.join(''))
-    .join('|')
-
-  const rendererStatus = statusbarAnchorRef.current
-    ? ReactDOM.createPortal(
-        <div
-          style={{
-            flex: 1,
-            display: 'flex',
-            alignItems: 'center',
-          }}
-        >
-          {rendererStatusText}
-        </div>,
-        statusbarAnchorRef.current
-      )
-    : null
-
-  return (
-    <>
-      {rendererStatus}
-    </>
-  )
-})

+ 0 - 1
packages/tldraw/apps/tldraw-logseq/src/components/Devtools/index.ts

@@ -1 +0,0 @@
-export * from './Devtools'

+ 0 - 93
packages/tldraw/apps/tldraw-logseq/src/components/GeometryTools/GeometryTools.tsx

@@ -1,93 +0,0 @@
-import { observer } from 'mobx-react-lite'
-import type { Side } from '@radix-ui/react-popper'
-import { ToolButton } from '../ToolButton'
-import { TablerIcon } from '../icons'
-import React from 'react'
-import { LogseqContext } from '../../lib/logseq-context'
-
-// @ts-ignore
-const LSUI = window.LSUI
-
-interface GeometryToolsProps extends React.HTMLAttributes<HTMLElement> {
-  popoverSide?: Side
-  activeGeometry?: string
-  setGeometry: (e: React.MouseEvent<HTMLButtonElement>) => void
-  chevron?: boolean
-}
-
-export const GeometryTools = observer(function GeometryTools({
-  popoverSide = 'left',
-  setGeometry,
-  activeGeometry,
-  chevron = true,
-  ...rest
-}: GeometryToolsProps) {
-  const {
-    handlers: { t },
-  } = React.useContext(LogseqContext)
-
-  const geometries = [
-    {
-      id: 'box',
-      icon: 'square',
-      tooltip: t('whiteboard/rectangle'),
-    },
-    {
-      id: 'ellipse',
-      icon: 'circle',
-      tooltip: t('whiteboard/circle'),
-    },
-    {
-      id: 'polygon',
-      icon: 'triangle',
-      tooltip: t('whiteboard/triangle'),
-    },
-  ]
-
-  const shapes = {
-    id: 'shapes',
-    icon: 'triangle-square-circle',
-    tooltip: t('whiteboard/shape'),
-  }
-
-  const activeTool = activeGeometry ? geometries.find(geo => geo.id === activeGeometry) : shapes
-
-  return (
-    <LSUI.Popover>
-      <LSUI.PopoverTrigger asChild>
-        <div {...rest} className="tl-geometry-tools-pane-anchor">
-          <ToolButton {...activeTool} tooltipSide={popoverSide} />
-          {chevron && (
-            <TablerIcon
-              data-selected={activeGeometry}
-              className="tl-popover-indicator"
-              name="chevron-down-left"
-            />
-          )}
-        </div>
-      </LSUI.PopoverTrigger>
-
-      <LSUI.PopoverContent
-        className="p-0 w-auto"
-        side={popoverSide}
-        sideOffset={15}
-        collisionBoundary={document.querySelector('.logseq-tldraw')}>
-        <div
-          className={`tl-toolbar tl-geometry-toolbar ${
-            ['left', 'right'].includes(popoverSide) ? 'flex-col' : 'flex-row'
-          }`}
-        >
-          {geometries.map(props => (
-            <ToolButton
-              key={props.id}
-              id={props.id}
-              icon={props.icon}
-              handleClick={setGeometry}
-              tooltipSide={popoverSide}
-            />
-          ))}
-        </div>
-      </LSUI.PopoverContent>
-    </LSUI.Popover>
-  )
-})

+ 0 - 1
packages/tldraw/apps/tldraw-logseq/src/components/GeometryTools/index.ts

@@ -1 +0,0 @@
-export * from './GeometryTools'

+ 0 - 16
packages/tldraw/apps/tldraw-logseq/src/components/KeyboardShortcut/KeyboardShortcut.tsx

@@ -1,16 +0,0 @@
-import { LogseqContext } from '../../lib/logseq-context'
-import * as React from 'react'
-
-export const KeyboardShortcut = ({
-  action, shortcut, opts,
-  ...props
-}: Partial<{ action: string, shortcut: string, opts: any }> & React.HTMLAttributes<HTMLElement>) => {
-  const { renderers } = React.useContext(LogseqContext)
-  const Shortcut = renderers?.KeyboardShortcut
-
-  return (
-    <div className="tl-menu-right-slot" {...props}>
-      <Shortcut action={action} shortcut={shortcut} opts={opts} />
-    </div>
-  )
-}

+ 0 - 1
packages/tldraw/apps/tldraw-logseq/src/components/KeyboardShortcut/index.ts

@@ -1 +0,0 @@
-export * from './KeyboardShortcut'

+ 0 - 55
packages/tldraw/apps/tldraw-logseq/src/components/Minimap/Minimap.tsx

@@ -1,55 +0,0 @@
-import { deepEqual } from '@tldraw/core'
-import { useApp, useMinimapEvents } from '@tldraw/react'
-import { reaction } from 'mobx'
-import { observer } from 'mobx-react-lite'
-import React from 'react'
-import { PreviewManager } from '../../lib'
-import { TablerIcon } from '../icons'
-
-export const Minimap = observer(function Minimap() {
-  const app = useApp()
-
-  const [whiteboardPreviewManager] = React.useState(() => new PreviewManager(app.serialized))
-  const [preview, setPreview] = React.useState(() =>
-    whiteboardPreviewManager.generatePreviewJsx(app.viewport)
-  )
-
-  const [active, setActive] = React.useState(false)
-
-  const events = useMinimapEvents()
-
-  React.useEffect(() => {
-    return reaction(
-      () => {
-        return {
-          serialized: app.serialized,
-          viewport: app.viewport,
-          cameraPoint: app.viewport.camera.point,
-        }
-      },
-      ({ serialized, viewport }, prev) => {
-        if (!deepEqual(prev.serialized, serialized)) {
-          whiteboardPreviewManager.load(serialized)
-        }
-        setPreview(whiteboardPreviewManager.generatePreviewJsx(viewport))
-      }
-    )
-  }, [app])
-
-  return (
-    <>
-      {active && (
-        <div className="tl-preview-minimap" {...events}>
-          {preview}
-        </div>
-      )}
-      <button
-        // className="tl-preview-minimap-toggle"
-        data-active={active}
-        onClick={() => setActive(a => !a)}
-      >
-        <TablerIcon name="crosshair2" />
-      </button>
-    </>
-  )
-})

+ 0 - 1
packages/tldraw/apps/tldraw-logseq/src/components/Minimap/index.ts

@@ -1 +0,0 @@
-export * from './Minimap'

+ 0 - 39
packages/tldraw/apps/tldraw-logseq/src/components/PopoverButton/PopoverButton.tsx

@@ -1,39 +0,0 @@
-import type { Side, Align } from '@radix-ui/react-popper'
-
-// @ts-ignore
-const LSUI = window.LSUI
-
-interface PopoverButton extends React.HTMLAttributes<HTMLButtonElement> {
-  side: Side // default side
-  align?: Align
-  alignOffset?: number
-  label: React.ReactNode
-  children: React.ReactNode
-  border?: boolean
-}
-
-export function PopoverButton({ side, align, alignOffset, label, children, border, ...rest }: PopoverButton) {
-  return (
-    <LSUI.Popover>
-      <LSUI.PopoverTrigger
-        {...rest}
-        data-border={border}
-        className="tl-button tl-popover-trigger-button"
-      >
-        {label}
-      </LSUI.PopoverTrigger>
-
-      <LSUI.PopoverContent
-        className="w-auto p-1"
-        align={align}
-        alignOffset={alignOffset}
-        side={side}
-        sideOffset={15}
-        collisionBoundary={document.querySelector('.logseq-tldraw')}
-      >
-        {children}
-        <LSUI.PopoverArrow className="popper-arrow" />
-      </LSUI.PopoverContent>
-    </LSUI.Popover>
-  )
-}

+ 0 - 1
packages/tldraw/apps/tldraw-logseq/src/components/PopoverButton/index.ts

@@ -1 +0,0 @@
-export * from './PopoverButton'

+ 0 - 103
packages/tldraw/apps/tldraw-logseq/src/components/PrimaryTools/PrimaryTools.tsx

@@ -1,103 +0,0 @@
-import { useApp } from '@tldraw/react'
-import { Geometry } from '@tldraw/core'
-import { observer } from 'mobx-react-lite'
-import * as React from 'react'
-import { ToolButton } from '../ToolButton'
-import { GeometryTools } from '../GeometryTools'
-import { ColorInput } from '../inputs/ColorInput'
-import { ScaleInput } from '../inputs/ScaleInput'
-import { LogseqContext } from '../../lib/logseq-context'
-
-// @ts-ignore
-const LSUI = window.LSUI
-
-export const PrimaryTools = observer(function PrimaryTools() {
-  const app = useApp()
-  const {
-    handlers: { t },
-  } = React.useContext(LogseqContext)
-
-  const handleSetColor = React.useCallback((color: string) => {
-    app.api.setColor(color)
-  }, [])
-
-  const handleToolClick = React.useCallback((e: React.MouseEvent<HTMLButtonElement>) => {
-    const tool = e.currentTarget.dataset.tool
-    if (tool) app.selectTool(tool)
-  }, [])
-
-  const [activeGeomId, setActiveGeomId] = React.useState(
-    () =>
-      Object.values(Geometry).find((geo: string) => geo === app.selectedTool.id) ??
-      Object.values(Geometry)[0]
-  )
-
-  React.useEffect(() => {
-    setActiveGeomId((prevId: Geometry) => {
-      return Object.values(Geometry).find((geo: string) => geo === app.selectedTool.id) ?? prevId
-    })
-  }, [app.selectedTool.id])
-
-  return (
-    <div className="tl-primary-tools" data-html2canvas-ignore="true">
-      <div className="tl-toolbar tl-tools-floating-panel">
-        <ToolButton
-          handleClick={() => app.selectTool('select')}
-          tooltip={t('whiteboard/select')}
-          id="select"
-          icon="select-cursor"
-        />
-        <ToolButton
-          handleClick={() => app.selectTool('move')}
-          tooltip={t('whiteboard/pan')}
-          id="move"
-          icon={app.isIn('move.panning') ? 'hand-grab' : 'hand-stop'}
-        />
-        <LSUI.Separator orientation="horizontal" />
-        <ToolButton
-          handleClick={() => app.selectTool('logseq-portal')}
-          tooltip={t('whiteboard/add-block-or-page')}
-          id="logseq-portal"
-          icon="circle-plus"
-        />
-        <ToolButton
-          handleClick={() => app.selectTool('pencil')}
-          tooltip={t('whiteboard/draw')}
-          id="pencil"
-          icon="ballpen"
-        />
-        <ToolButton
-          handleClick={() => app.selectTool('highlighter')}
-          tooltip={t('whiteboard/highlight')}
-          id="highlighter"
-          icon="highlight"
-        />
-        <ToolButton
-          handleClick={() => app.selectTool('erase')}
-          tooltip={t('whiteboard/eraser')}
-          id="erase"
-          icon="eraser"
-        />
-        <ToolButton
-          handleClick={() => app.selectTool('line')}
-          tooltip={t('whiteboard/connector')}
-          id="line"
-          icon="connector"
-        />
-        <ToolButton
-          handleClick={() => app.selectTool('text')}
-          tooltip={t('whiteboard/text')}
-          id="text"
-          icon="text"
-        />
-        <GeometryTools activeGeometry={activeGeomId} setGeometry={handleToolClick} />
-        <LSUI.Separator
-          orientation="horizontal"
-          style={{ margin: '0 -4px' }}
-        />
-        <ColorInput popoverSide="left" color={app.settings.color} setColor={handleSetColor} />
-        <ScaleInput scaleLevel={app.settings.scaleLevel} popoverSide="left" compact={true} />
-      </div>
-    </div>
-  )
-})

+ 0 - 1
packages/tldraw/apps/tldraw-logseq/src/components/PrimaryTools/index.ts

@@ -1 +0,0 @@
-export * from './PrimaryTools'

+ 0 - 44
packages/tldraw/apps/tldraw-logseq/src/components/QuickLinks/QuickLinks.tsx

@@ -1,44 +0,0 @@
-import { TLQuickLinksComponent, useApp } from '@tldraw/react'
-import { observer } from 'mobx-react-lite'
-import React from 'react'
-import type { Shape } from '../../lib'
-import { LogseqContext } from '../../lib/logseq-context'
-import { BlockLink } from '../BlockLink'
-
-export const QuickLinks: TLQuickLinksComponent<Shape> = observer(({ shape }) => {
-  const app = useApp()
-  const { handlers } = React.useContext(LogseqContext)
-  const t = handlers.t
-  const links = React.useMemo(() => {
-    const links = [...(shape.props.refs ?? [])].map<[ref: string, showReferenceContent: boolean]>(
-      // user added links should show the referenced block content
-      l => [l, true]
-    )
-
-    if (shape.props.type === 'logseq-portal' && shape.props.pageId) {
-      // portal reference should not show the block content
-      links.unshift([shape.props.pageId, false])
-    }
-
-    // do not show links for the current page
-    return links.filter(
-      link =>
-        link[0].toLowerCase() !== app.currentPage.id &&
-        link[0] !== shape.props.pageId
-    )
-  }, [shape.props.id, shape.props.type, shape.props.parentId, shape.props.refs])
-
-  if (links.length === 0) return null
-
-  return (
-    <div className="tl-quick-links" title={t('whiteboard/shape-quick-links')}>
-      {links.map(([ref, showReferenceContent]) => {
-        return (
-          <div key={ref} className="tl-quick-links-row">
-            <BlockLink id={ref} showReferenceContent={showReferenceContent} />
-          </div>
-        )
-      })}
-    </div>
-  )
-})

+ 0 - 1
packages/tldraw/apps/tldraw-logseq/src/components/QuickLinks/index.ts

@@ -1 +0,0 @@
-export * from './QuickLinks'

+ 0 - 437
packages/tldraw/apps/tldraw-logseq/src/components/QuickSearch/QuickSearch.tsx

@@ -1,437 +0,0 @@
-import { useDebouncedValue } from '@tldraw/react'
-import { observer } from 'mobx-react-lite'
-import React from 'react'
-import { Virtuoso } from 'react-virtuoso'
-import { LogseqPortalShape } from '../../lib'
-import { LogseqContext, SearchResult } from '../../lib/logseq-context'
-import { CircleButton } from '../Button'
-import { TablerIcon } from '../icons'
-import { TextInput } from '../inputs/TextInput'
-
-interface LogseqQuickSearchProps {
-  onChange: (id: string) => void
-  className?: string
-  placeholder?: string
-  style?: React.CSSProperties
-  onBlur?: () => void
-  onAddBlock?: (uuid: string) => void
-}
-
-const LogseqTypeTag = ({
-  type,
-  active,
-}: {
-  type: 'B' | 'P' | 'BA' | 'PA' | 'WA' | 'WP' | 'BS' | 'PS'
-  active?: boolean
-}) => {
-  const nameMapping = {
-    B: 'block',
-    P: 'page',
-    WP: 'whiteboard',
-    BA: 'new-block',
-    PA: 'new-page',
-    WA: 'new-whiteboard',
-    BS: 'block-search',
-    PS: 'page-search',
-  }
-  return (
-    <span className="tl-type-tag" data-active={active}>
-      <i className={`tie tie-${nameMapping[type]}`} />
-    </span>
-  )
-}
-
-function escapeRegExp(text: string) {
-  return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
-}
-
-const highlightedJSX = (input: string, keyword: string) => {
-  return (
-    <span>
-      {input
-        .split(new RegExp(`(${escapeRegExp(keyword)})`, 'gi'))
-        .map((part, index) => {
-          if (index % 2 === 1) {
-            return <mark className="tl-highlighted">{part}</mark>
-          }
-          return part
-        })
-        .map((frag, idx) => (
-          <React.Fragment key={idx}>{frag}</React.Fragment>
-        ))}
-    </span>
-  )
-}
-
-const useSearch = (q: string, searchFilter: 'B' | 'P' | null) => {
-  const { handlers } = React.useContext(LogseqContext)
-  const [results, setResults] = React.useState<SearchResult | null>(null)
-  const dq = useDebouncedValue(q, 200)
-
-  React.useEffect(() => {
-    let canceled = false
-    if (dq.length > 0) {
-      const filter = { 'pages?': true, 'blocks?': true, 'files?': false }
-      if (searchFilter === 'B') {
-        filter['pages?'] = false
-      } else if (searchFilter === 'P') {
-        filter['blocks?'] = false
-      }
-      handlers.search(dq, filter).then(_results => {
-        if (!canceled) {
-          setResults(_results)
-        }
-      })
-    } else {
-      setResults(null)
-    }
-    return () => {
-      canceled = true
-    }
-  }, [dq, handlers?.search])
-
-  return results
-}
-
-export const LogseqQuickSearch = observer(
-  ({ className, style, placeholder, onChange, onBlur, onAddBlock }: LogseqQuickSearchProps) => {
-    const [q, setQ] = React.useState(LogseqPortalShape.defaultSearchQuery)
-    const [searchFilter, setSearchFilter] = React.useState<'B' | 'P' | null>(
-      LogseqPortalShape.defaultSearchFilter
-    )
-    const rInput = React.useRef<HTMLInputElement>(null)
-    const { handlers, renderers } = React.useContext(LogseqContext)
-    const t = handlers.t
-
-    const finishSearching = React.useCallback((id: string, isPage: boolean) => {
-    console.log({id, isPage})
-      setTimeout(() => onChange(id, isPage))
-      rInput.current?.blur()
-      if (id) {
-        LogseqPortalShape.defaultSearchQuery = ''
-        LogseqPortalShape.defaultSearchFilter = null
-      }
-    }, [])
-
-    const handleAddBlock = React.useCallback(
-      async (content: string) => {
-        const uuid = await handlers?.addNewBlock(content)
-        if (uuid) {
-          finishSearching(uuid)
-          onAddBlock?.(uuid)
-        }
-        return uuid
-      },
-      [onAddBlock]
-    )
-
-    const optionsWrapperRef = React.useRef<HTMLDivElement>(null)
-
-    const [focusedOptionIdx, setFocusedOptionIdx] = React.useState<number>(0)
-
-    const searchResult = useSearch(q, searchFilter)
-
-    const [prefixIcon, setPrefixIcon] = React.useState<string>('circle-plus')
-
-    const [showPanel, setShowPanel] = React.useState<boolean>(false)
-
-    React.useEffect(() => {
-      // autofocus attr seems not to be working
-      setTimeout(() => {
-        rInput.current?.focus()
-      })
-    }, [searchFilter])
-
-    React.useEffect(() => {
-      LogseqPortalShape.defaultSearchQuery = q
-      LogseqPortalShape.defaultSearchFilter = searchFilter
-    }, [q, searchFilter])
-
-    type Option = {
-      actionIcon: 'search' | 'circle-plus'
-      onChosen: () => boolean // return true if the action was handled
-      element: React.ReactNode
-    }
-
-    const options: Option[] = React.useMemo(() => {
-      const options: Option[] = []
-
-      const Breadcrumb = renderers?.Breadcrumb
-
-      if (!Breadcrumb || !handlers) {
-        return []
-      }
-
-      if (onAddBlock) {
-        // New block option
-        options.push({
-          actionIcon: 'circle-plus',
-          onChosen: () => {
-            return !!handleAddBlock(q)
-          },
-          element: (
-            <div className="tl-quick-search-option-row">
-              <LogseqTypeTag active type="BA" />
-              {q.length > 0 ? (
-                <>
-                  <strong>{t('whiteboard/new-block')}</strong>
-                  {q}
-                </>
-              ) : (
-                <strong>{t('whiteboard/new-block-no-colon')}</strong>
-              )}
-            </div>
-          ),
-        })
-      }
-
-      // New page or whiteboard option when no exact match
-      if (!searchResult?.pages?.some(p => p.title.toLowerCase() === q.toLowerCase()) && q) {
-        options.push(
-          {
-            actionIcon: 'circle-plus',
-            onChosen: async () => {
-              let result = await handlers?.addNewPage(q)
-              finishSearching(result, true)
-              return true
-            },
-            element: (
-              <div className="tl-quick-search-option-row">
-                <LogseqTypeTag active type="PA" />
-                <strong>{t('whiteboard/new-page')}</strong>
-                {q}
-              </div>
-            ),
-          },
-          {
-            actionIcon: 'circle-plus',
-            onChosen: async () => {
-              let result = await handlers?.addNewWhiteboard(q)
-              finishSearching(result, true)
-              return true
-            },
-            element: (
-              <div className="tl-quick-search-option-row">
-                <LogseqTypeTag active type="WA" />
-                <strong>{t('whiteboard/new-whiteboard')}</strong>
-                {q}
-              </div>
-            ),
-          }
-        )
-      }
-
-      // search filters
-      if (q.length === 0 && searchFilter === null) {
-        options.push(
-          {
-            actionIcon: 'search',
-            onChosen: () => {
-              setSearchFilter('B')
-              return true
-            },
-            element: (
-              <div className="tl-quick-search-option-row">
-                <LogseqTypeTag type="BS" />
-                {t('whiteboard/search-only-blocks')}
-              </div>
-            ),
-          },
-          {
-            actionIcon: 'search',
-            onChosen: () => {
-              setSearchFilter('P')
-              return true
-            },
-            element: (
-              <div className="tl-quick-search-option-row">
-                <LogseqTypeTag type="PS" />
-                {t('whiteboard/search-only-pages')}
-              </div>
-            ),
-          }
-        )
-      }
-
-      // Page results
-      if ((!searchFilter || searchFilter === 'P') && searchResult && searchResult.pages) {
-        options.push(
-          ...searchResult.pages.map(page => {
-            return {
-              actionIcon: 'search' as 'search',
-              onChosen: () => {
-                finishSearching(page.id, true)
-                return true
-              },
-              element: (
-                <div className="tl-quick-search-option-row">
-                  <LogseqTypeTag type={handlers.isWhiteboardPage(page.id) ? 'WP' : 'P'} />
-                  {highlightedJSX(page.title, q)}
-                </div>
-              ),
-            }
-          })
-        )
-      }
-
-      // Block results
-      if ((!searchFilter || searchFilter === 'B') && searchResult && searchResult.blocks) {
-        options.push(
-          ...searchResult.blocks
-            .filter(block => block.title && block.uuid)
-            .map(({ title, uuid }) => {
-              const block = handlers.queryBlockByUUID(uuid)
-              return {
-                actionIcon: 'search' as 'search',
-                onChosen: () => {
-                  if (block) {
-                    finishSearching(uuid)
-                    window.logseq?.api?.set_blocks_id?.([uuid])
-                    return true
-                  }
-                  return false
-                },
-                // FIXME: breadcrumb not works here because of async loading
-                element: (
-                  <>
-                    <div className="tl-quick-search-option-row">
-                      <LogseqTypeTag type="B" />
-                      {highlightedJSX(title, q)}
-                    </div>
-                  </>
-                ),
-              }
-            })
-        )
-      }
-      return options
-    }, [q, searchFilter, searchResult, renderers?.Breadcrumb, handlers])
-
-    React.useEffect(() => {
-      const keydownListener = (e: KeyboardEvent) => {
-        let newIndex = focusedOptionIdx
-        if (e.key === 'ArrowDown') {
-          newIndex = Math.min(options.length - 1, focusedOptionIdx + 1)
-        } else if (e.key === 'ArrowUp') {
-          newIndex = Math.max(0, focusedOptionIdx - 1)
-        } else if (e.key === 'Enter') {
-          options[focusedOptionIdx]?.onChosen()
-          e.stopPropagation()
-          e.preventDefault()
-        } else if (e.key === 'Backspace' && q.length === 0) {
-          setSearchFilter(null)
-        } else if (e.key === 'Escape') {
-          finishSearching('')
-        }
-
-        if (newIndex !== focusedOptionIdx) {
-          const option = options[newIndex]
-          setFocusedOptionIdx(newIndex)
-          setPrefixIcon(option.actionIcon)
-          e.stopPropagation()
-          e.preventDefault()
-          const optionElement = optionsWrapperRef.current?.querySelector(
-            '.tl-quick-search-option:nth-child(' + (newIndex + 1) + ')'
-          )
-          if (optionElement) {
-            // @ts-expect-error we are using scrollIntoViewIfNeeded, which is not in standards
-            optionElement?.scrollIntoViewIfNeeded(false)
-          }
-        }
-      }
-      document.addEventListener('keydown', keydownListener, true)
-      return () => {
-        document.removeEventListener('keydown', keydownListener, true)
-      }
-    }, [options, focusedOptionIdx, q])
-
-    return (
-      <div className={'tl-quick-search ' + (className ?? '')} style={style}>
-        <CircleButton
-          icon={prefixIcon}
-          onClick={() => {
-            options[focusedOptionIdx]?.onChosen()
-          }}
-        />
-        <div className="tl-quick-search-input-container">
-          {searchFilter && (
-            <div className="tl-quick-search-input-filter">
-              <LogseqTypeTag type={searchFilter} />
-              {searchFilter === 'B' ? 'Search blocks' : 'Search pages'}
-              <div
-                className="tl-quick-search-input-filter-remove"
-                onClick={() => setSearchFilter(null)}
-              >
-                <TablerIcon name="x" />
-              </div>
-            </div>
-          )}
-          <TextInput
-            ref={rInput}
-            type="text"
-            value={q}
-            className="tl-quick-search-input"
-            placeholder={placeholder ?? 'Create or search your graph...'}
-            onChange={q => setQ(q.target.value)}
-            onKeyDown={e => {
-              if (e.key === 'Enter') {
-                finishSearching(q)
-              }
-              e.stopPropagation()
-            }}
-            onFocus={() => {
-              setShowPanel(true)
-            }}
-            onBlur={() => {
-              setShowPanel(false)
-              onBlur?.()
-            }}
-          />
-        </div>
-        {/* TODO: refactor to radix-ui popover */}
-        {options.length > 0 && (
-          <div
-            onWheelCapture={e => e.stopPropagation()}
-            className="tl-quick-search-options"
-            ref={optionsWrapperRef}
-            style={{
-              // not using display: none so we can persist the scroll position
-              visibility: showPanel ? 'visible' : 'hidden',
-              pointerEvents: showPanel ? 'all' : 'none',
-            }}
-          >
-            <Virtuoso
-              style={{ height: Math.min(Math.max(1, options.length), 12) * 40 }}
-              totalCount={options.length}
-              itemContent={index => {
-                const { actionIcon, onChosen, element } = options[index]
-                return (
-                  <div
-                    key={index}
-                    data-focused={index === focusedOptionIdx}
-                    className="tl-quick-search-option"
-                    tabIndex={0}
-                    onMouseEnter={() => {
-                      setPrefixIcon(actionIcon)
-                      setFocusedOptionIdx(index)
-                    }}
-                    // we have to use mousedown && stop propagation EARLY, otherwise some
-                    // default behavior of clicking the rendered elements will happen
-                    onPointerDownCapture={e => {
-                      if (onChosen()) {
-                        e.stopPropagation()
-                        e.preventDefault()
-                      }
-                    }}
-                  >
-                    {element}
-                  </div>
-                )
-              }}
-            />
-          </div>
-        )}
-      </div>
-    )
-  }
-)

+ 0 - 1
packages/tldraw/apps/tldraw-logseq/src/components/QuickSearch/index.ts

@@ -1 +0,0 @@
-export * from './QuickSearch'

+ 0 - 16
packages/tldraw/apps/tldraw-logseq/src/components/StatusBar/StatusBar.tsx

@@ -1,16 +0,0 @@
-/* eslint-disable @typescript-eslint/no-non-null-assertion */
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import { useApp } from '@tldraw/react'
-import { observer } from 'mobx-react-lite'
-import type { Shape } from '../../lib'
-
-export const StatusBar = observer(function StatusBar() {
-  const app = useApp<Shape>()
-  return (
-    <div className="tl-statusbar" data-html2canvas-ignore="true">
-      {app.selectedTool.id} | {app.selectedTool.currentState.id}
-      <div style={{ flex: 1 }} />
-      <div id="tl-statusbar-anchor" className="flex gap-1" />
-    </div>
-  )
-})

+ 0 - 1
packages/tldraw/apps/tldraw-logseq/src/components/StatusBar/index.ts

@@ -1 +0,0 @@
-export * from './StatusBar'

+ 0 - 50
packages/tldraw/apps/tldraw-logseq/src/components/ToolButton/ToolButton.tsx

@@ -1,50 +0,0 @@
-import { TLMoveTool, TLSelectTool } from '@tldraw/core'
-import { useApp } from '@tldraw/react'
-import type { Side } from '@radix-ui/react-popper'
-import { observer } from 'mobx-react-lite'
-import type * as React from 'react'
-import { Button } from '../Button'
-import { TablerIcon } from '../icons'
-import { KeyboardShortcut } from '../KeyboardShortcut'
-
-export interface ToolButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
-  id: string
-  icon: string | React.ReactNode
-  tooltip: string
-  tooltipSide?: Side
-  handleClick: (e: React.MouseEvent<HTMLButtonElement>) => void
-}
-
-export const ToolButton = observer(
-  ({ id, icon, tooltip, tooltipSide = 'left', handleClick, ...props }: ToolButtonProps) => {
-    const app = useApp()
-
-    // Tool must exist
-    const Tool = [...app.Tools, TLSelectTool, TLMoveTool]?.find(T => T.id === id)
-
-    const shortcut = (Tool as any)?.['shortcut']
-
-    const tooltipContent =
-      shortcut && tooltip ? (
-        <div className="flex">
-          {tooltip}
-          <KeyboardShortcut action={shortcut} />
-        </div>
-      ) : (
-        tooltip
-      )
-
-    return (
-      <Button
-        {...props}
-        tooltipSide={tooltipSide}
-        tooltip={tooltipContent}
-        data-tool={id}
-        data-selected={id === app.selectedTool.id}
-        onClick={handleClick}
-      >
-        {typeof icon === 'string' ? <TablerIcon name={icon} /> : icon}
-      </Button>
-    )
-  }
-)

+ 0 - 1
packages/tldraw/apps/tldraw-logseq/src/components/ToolButton/index.ts

@@ -1 +0,0 @@
-export * from './ToolButton'

+ 0 - 31
packages/tldraw/apps/tldraw-logseq/src/components/Tooltip/Tooltip.tsx

@@ -1,31 +0,0 @@
-import type { Side } from '@radix-ui/react-popper'
-
-// @ts-ignore
-const LSUI = window.LSUI
-
-export interface TooltipProps {
-  children: React.ReactNode
-  side?: Side
-  sideOffset?: number
-  content?: React.ReactNode
-}
-
-export function Tooltip({ side, content, sideOffset = 10, ...rest }: TooltipProps) {
-  return content ? (
-    <LSUI.TooltipProvider delayDuration={300}>
-      <LSUI.Tooltip>
-        <LSUI.TooltipTrigger asChild>{rest.children}</LSUI.TooltipTrigger>
-          <LSUI.TooltipContent
-            sideOffset={sideOffset}
-            side={side}
-            {...rest}
-          >
-            {content}
-            <LSUI.TooltipArrow className="popper-arrow" />
-          </LSUI.TooltipContent>
-      </LSUI.Tooltip>
-    </LSUI.TooltipProvider>
-  ) : (
-    <>{rest.children}</>
-  )
-}

+ 0 - 1
packages/tldraw/apps/tldraw-logseq/src/components/Tooltip/index.ts

@@ -1 +0,0 @@
-export * from './Tooltip'

+ 0 - 65
packages/tldraw/apps/tldraw-logseq/src/components/ZoomMenu/ZoomMenu.tsx

@@ -1,65 +0,0 @@
-import { useApp } from '@tldraw/react'
-import { KeyboardShortcut } from '../KeyboardShortcut'
-import { observer } from 'mobx-react-lite'
-
-// @ts-ignore
-const LSUI = window.LSUI
-
-export const ZoomMenu = observer(function ZoomMenu(): JSX.Element {
-  const app = useApp()
-  const preventEvent = (e: Event) => {
-    e.preventDefault()
-  }
-
-  return (
-    <LSUI.DropdownMenu>
-      <LSUI.DropdownMenuTrigger className="tl-button text-sm px-2 important" id="tl-zoom">
-        {(app.viewport.camera.zoom * 100).toFixed(0) + '%'}
-      </LSUI.DropdownMenuTrigger>
-      <LSUI.DropdownMenuContent
-        onCloseAutoFocus={e => e.preventDefault()}
-        id="zoomPopup"
-        sideOffset={12}
-      >
-        <LSUI.DropdownMenuItem
-          onSelect={preventEvent}
-          onClick={app.api.zoomToFit}
-        >
-          Zoom to drawing
-          <KeyboardShortcut action="whiteboard/zoom-to-fit" />
-        </LSUI.DropdownMenuItem>
-        <LSUI.DropdownMenuItem
-          onSelect={preventEvent}
-          onClick={app.api.zoomToSelection}
-          disabled={app.selectedShapesArray.length === 0}
-        >
-          Zoom to fit selection
-          <KeyboardShortcut action="whiteboard/zoom-to-selection" />
-        </LSUI.DropdownMenuItem>
-        <LSUI.DropdownMenuItem
-          onSelect={preventEvent}
-          onClick={app.api.zoomIn}
-        >
-          Zoom in
-          <KeyboardShortcut action="whiteboard/zoom-in" />
-        </LSUI.DropdownMenuItem>
-        <LSUI.DropdownMenuItem
-          onSelect={preventEvent}
-          onClick={app.api.zoomOut}
-        >
-          Zoom out
-          <KeyboardShortcut action="whiteboard/zoom-out" />
-        </LSUI.DropdownMenuItem>
-        <LSUI.DropdownMenuItem
-          onSelect={preventEvent}
-          onClick={app.api.resetZoom}
-        >
-          Reset zoom
-          <KeyboardShortcut action="whiteboard/reset-zoom" />
-        </LSUI.DropdownMenuItem>
-      </LSUI.DropdownMenuContent>
-    </LSUI.DropdownMenu>
-  )
-})
-
-export default ZoomMenu

+ 0 - 1
packages/tldraw/apps/tldraw-logseq/src/components/ZoomMenu/index.ts

@@ -1 +0,0 @@
-export * from './ZoomMenu'

+ 0 - 35
packages/tldraw/apps/tldraw-logseq/src/components/icons/TablerIcon.tsx

@@ -1,35 +0,0 @@
-const extendedIcons = [
-  'add-link',
-  'block-search',
-  'block',
-  'connector',
-  'group',
-  'internal-link',
-  'link-to-block',
-  'link-to-page',
-  'link-to-whiteboard',
-  'move-to-sidebar-right',
-  'object-compact',
-  'object-expanded',
-  'open-as-page',
-  'page-search',
-  'page',
-  'references-hide',
-  'references-show',
-  'select-cursor',
-  'text',
-  'ungroup',
-  'whiteboard-element',
-  'whiteboard',
-]
-
-const cx = (...args: (string | undefined)[]) => args.join(' ')
-
-export const TablerIcon = ({
-  name,
-  className,
-  ...props
-}: { name: string } & React.HTMLAttributes<HTMLElement>) => {
-  const classNamePrefix = extendedIcons.includes(name) ? `tie tie-` : `ti ti-`
-  return <i className={cx(classNamePrefix + name, className)} {...props} />
-}

+ 0 - 1
packages/tldraw/apps/tldraw-logseq/src/components/icons/index.ts

@@ -1 +0,0 @@
-export * from './TablerIcon'

+ 0 - 122
packages/tldraw/apps/tldraw-logseq/src/components/inputs/ColorInput.tsx

@@ -1,122 +0,0 @@
-import type { Side } from '@radix-ui/react-popper'
-import { Color, isBuiltInColor, debounce } from '@tldraw/core'
-import { TablerIcon } from '../icons'
-import { PopoverButton } from '../PopoverButton'
-import { Tooltip } from '../Tooltip'
-import React from 'react'
-import { LogseqContext } from '../../lib/logseq-context'
-// @ts-ignore
-const LSUI = window.LSUI
-
-interface ColorInputProps extends React.HTMLAttributes<HTMLButtonElement> {
-  color?: string
-  opacity?: number
-  popoverSide: Side
-  setColor: (value: string) => void
-  setOpacity?: (value: number) => void
-}
-
-export function ColorInput({
-  color,
-  opacity,
-  popoverSide,
-  setColor,
-  setOpacity,
-  ...rest
-}: ColorInputProps) {
-  const {
-    handlers: { t },
-  } = React.useContext(LogseqContext)
-
-  function renderColor(color?: string) {
-    return color ? (
-      <div className="tl-color-bg" style={{ backgroundColor: color }}>
-        <div className={`w-full h-full bg-${color}-500`}></div>
-      </div>
-    ) : (
-      <div className={'tl-color-bg'}>
-        <TablerIcon name="color-swatch" />
-      </div>
-    )
-  }
-
-  function isHexColor(color: string) {
-    return /^#(?:[0-9a-f]{3}){1,2}$/i.test(color)
-  }
-
-  const handleChangeDebounced = React.useMemo(() => {
-    let latestValue = ''
-
-    const handler: React.ChangeEventHandler<HTMLInputElement> = e => {
-      setColor(latestValue)
-    }
-
-    return debounce(handler, 100, e => {
-      latestValue = e.target.value
-    })
-  }, [])
-
-  return (
-    <PopoverButton
-      {...rest}
-      border
-      side={popoverSide}
-      label={
-        <Tooltip content={t('whiteboard/color')} side={popoverSide} sideOffset={14}>
-          {renderColor(color)}
-        </Tooltip>
-      }
-    >
-      <div className="p-1">
-        <div className={'tl-color-palette'}>
-          {Object.values(Color).map(value => (
-            <button
-              key={value}
-              className={`tl-color-drip m-1${value === color ? ' active' : ''}`}
-              onClick={() => setColor(value)}
-            >
-              {renderColor(value)}
-            </button>
-          ))}
-        </div>
-
-        <div className="flex items-center tl-custom-color">
-          <div className={`tl-color-drip m-1 mr-3 ${!isBuiltInColor(color) ? 'active' : ''}`}>
-            <div className="color-input-wrapper tl-color-bg">
-              <input
-                className="color-input cursor-pointer"
-                id="tl-custom-color-input"
-                type="color"
-                value={isHexColor(color) ? color : '#000000'}
-                onChange={handleChangeDebounced}
-                style={{ opacity: isBuiltInColor(color) ? 0 : 1 }}
-                {...rest}
-              />
-            </div>
-          </div>
-          <label htmlFor="tl-custom-color-input" className="text-xs cursor-pointer">
-            {t('whiteboard/select-custom-color')}
-          </label>
-        </div>
-
-        {setOpacity && (
-          <div className="mx-1 my-2">
-            <LSUI.Slider
-              defaultValue={[opacity ?? 0]}
-              onValueCommit={value => setOpacity(value[0])}
-              max={1}
-              step={0.1}
-              aria-label={t('whiteboard/opacity')}
-              className="tl-slider-root"
-            >
-              <LSUI.SliderTrack className="tl-slider-track">
-                <LSUI.SliderRange className="tl-slider-range" />
-              </LSUI.SliderTrack>
-              <LSUI.SliderThumb className="tl-slider-thumb" />
-            </LSUI.Slider>
-          </div>
-        )}
-      </div>
-    </PopoverButton>
-  )
-}

+ 0 - 12
packages/tldraw/apps/tldraw-logseq/src/components/inputs/NumberInput.tsx

@@ -1,12 +0,0 @@
-interface NumberInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
-  label: string
-}
-
-export function NumberInput({ label, ...rest }: NumberInputProps) {
-  return (
-    <div className="input">
-      <label htmlFor={`number-${label}`}>{label}</label>
-      <input className="number-input" name={`number-${label}`} type="number" {...rest} />
-    </div>
-  )
-}

+ 0 - 59
packages/tldraw/apps/tldraw-logseq/src/components/inputs/ScaleInput.tsx

@@ -1,59 +0,0 @@
-import { SelectInput, type SelectOption } from '../inputs/SelectInput'
-import type { Side } from '@radix-ui/react-popper'
-import type { SizeLevel } from '../../lib'
-import { useApp } from '@tldraw/react'
-import React from 'react'
-import { LogseqContext } from '../../lib/logseq-context'
-
-interface ScaleInputProps extends React.HTMLAttributes<HTMLButtonElement> {
-  scaleLevel?: SizeLevel
-  compact?: boolean
-  popoverSide?: Side
-}
-
-export function ScaleInput({ scaleLevel, compact, popoverSide, ...rest }: ScaleInputProps) {
-  const app = useApp<Shape>()
-  const {
-    handlers: { t },
-  } = React.useContext(LogseqContext)
-
-  const sizeOptions: SelectOption[] = [
-    {
-      label: compact ? 'XS' : t('whiteboard/extra-small'),
-      value: 'xs',
-    },
-    {
-      label: compact ? 'SM' : t('whiteboard/small'),
-      value: 'sm',
-    },
-    {
-      label: compact ? 'MD' : t('whiteboard/medium'),
-      value: 'md',
-    },
-    {
-      label: compact ? 'LG' : t('whiteboard/large'),
-      value: 'lg',
-    },
-    {
-      label: compact ? 'XL' : t('whiteboard/extra-large'),
-      value: 'xl',
-    },
-    {
-      label: compact ? 'XXL' : t('whiteboard/huge'),
-      value: 'xxl',
-    },
-  ]
-
-  return (
-    <SelectInput
-      tooltip={t('whiteboard/scale-level')}
-      options={sizeOptions}
-      value={scaleLevel}
-      popoverSide={popoverSide}
-      compact={compact}
-      onValueChange={v => {
-        app.api.setScaleLevel(v)
-      }}
-    />
-  )
-}

+ 0 - 75
packages/tldraw/apps/tldraw-logseq/src/components/inputs/SelectInput.tsx

@@ -1,75 +0,0 @@
-import * as React from 'react'
-import { Tooltip } from '../Tooltip'
-import { ChevronDown } from 'lucide-react'
-import type { Side } from '@radix-ui/react-popper'
-
-// @ts-ignore
-const LSUI = window.LSUI
-
-export interface SelectOption {
-  value: string
-  label: React.ReactNode
-}
-
-interface SelectInputProps extends React.HTMLAttributes<HTMLElement> {
-  options: SelectOption[]
-  value: string
-  tooltip?: React.ReactNode
-  popoverSide?: Side
-  compact?: boolean
-  onValueChange: (value: string) => void
-}
-
-export function SelectInput({
-  options,
-  tooltip,
-  popoverSide,
-  compact = false,
-  value,
-  onValueChange,
-  ...rest
-}: SelectInputProps) {
-  const [isOpen, setIsOpen] = React.useState(false)
-  return (
-    <div {...rest}>
-      <LSUI.Select
-        open={isOpen}
-        onOpenChange={setIsOpen}
-        value={value}
-        onValueChange={onValueChange}
-      >
-        <Tooltip content={tooltip} side={popoverSide}>
-          <LSUI.SelectTrigger
-            className={`tl-select-trigger ${compact ? "compact" : ""}`}>
-            <LSUI.SelectValue />
-            {!compact && (
-              <LSUI.SelectIcon asChild>
-                <ChevronDown className="h-4 w-4 opacity-50"/>
-              </LSUI.SelectIcon>
-            )}
-          </LSUI.SelectTrigger>
-        </Tooltip>
-
-        <LSUI.SelectContent
-          className="min-w-min"
-          side={popoverSide}
-          position="popper"
-          sideOffset={14}
-          align="center"
-          onKeyDown={e => e.stopPropagation()}
-        >
-          {options.map(option => {
-            return (
-              <LSUI.SelectItem
-                key={option.value}
-                value={option.value}
-              >
-                {option.label}
-              </LSUI.SelectItem>
-            )
-          })}
-        </LSUI.SelectContent>
-      </LSUI.Select>
-    </div>
-  )
-}

+ 0 - 162
packages/tldraw/apps/tldraw-logseq/src/components/inputs/ShapeLinksInput.tsx

@@ -1,162 +0,0 @@
-import type { Side } from '@radix-ui/react-popper'
-import { validUUID } from '@tldraw/core'
-import { useApp } from '@tldraw/react'
-import React from 'react'
-
-import { observer } from 'mobx-react-lite'
-import { LogseqContext } from '../../lib/logseq-context'
-import { BlockLink } from '../BlockLink'
-import { Button } from '../Button'
-import { Tooltip } from '../Tooltip'
-import { TablerIcon } from '../icons'
-import { PopoverButton } from '../PopoverButton'
-import { LogseqQuickSearch } from '../QuickSearch'
-
-interface ShapeLinksInputProps extends React.HTMLAttributes<HTMLButtonElement> {
-  shapeType: string
-  side: Side
-  refs: string[]
-  pageId?: string // the portal referenced block id or page name
-  portalType?: 'B' | 'P'
-  onRefsChange: (value: string[]) => void
-}
-
-function ShapeLinkItem({
-  id,
-  type,
-  onRemove,
-  showContent,
-}: {
-  id: string
-  type: 'B' | 'P'
-  onRemove?: () => void
-  showContent?: boolean
-}) {
-  const app = useApp<Shape>()
-  const { handlers } = React.useContext(LogseqContext)
-  const t = handlers.t
-
-  return (
-    <div className="tl-shape-links-panel-item color-level relative">
-      <div className="whitespace-pre break-all overflow-hidden text-ellipsis inline-flex">
-        <BlockLink id={id} showReferenceContent={showContent} />
-      </div>
-      <div className="flex-1" />
-      {handlers.getBlockPageName(id) !== app.currentPage.name && (
-        <Button
-          tooltip={t('whiteboard/open-page')}
-          type="button"
-          onClick={() => handlers?.redirectToPage(id)}
-        >
-          <TablerIcon name="open-as-page" />
-        </Button>
-      )}
-      <Button
-        tooltip={t('whiteboard/open-page-in-sidebar')}
-        type="button"
-        onClick={() => handlers?.sidebarAddBlock(id, type === 'B' ? 'block' : 'page')}
-      >
-        <TablerIcon name="move-to-sidebar-right" />
-      </Button>
-      {onRemove && (
-        <Button
-          className="tl-shape-links-panel-item-remove-button"
-          tooltip={t('whiteboard/remove-link')}
-          type="button"
-          onClick={onRemove}
-        >
-          <TablerIcon name="x" className="!translate-y-0" />
-        </Button>
-      )}
-    </div>
-  )
-}
-
-export const ShapeLinksInput = observer(function ShapeLinksInput({
-  pageId,
-  portalType,
-  shapeType,
-  refs,
-  side,
-  onRefsChange,
-  ...rest
-}: ShapeLinksInputProps) {
-  const {
-    handlers: { t },
-  } = React.useContext(LogseqContext)
-
-  const noOfLinks = refs.length + (pageId ? 1 : 0)
-  const canAddLink = refs.length === 0
-
-  const addNewRef = (value?: string) => {
-    if (value && !refs.includes(value) && canAddLink) {
-      onRefsChange([...refs, value])
-    }
-  }
-
-  const showReferencePanel = !!(pageId && portalType)
-
-  return (
-    <PopoverButton
-      {...rest}
-      side={side}
-      align="start"
-      alignOffset={-6}
-      label={
-        <Tooltip content={t('whiteboard/link')} sideOffset={14}>
-          <div className="flex gap-1 relative items-center justify-center px-1">
-            <TablerIcon name={noOfLinks > 0 ? 'link' : 'add-link'} />
-            {noOfLinks > 0 && <div className="tl-shape-links-count">{noOfLinks}</div>}
-          </div>
-        </Tooltip>
-      }
-    >
-      <div className="color-level rounded-lg" data-show-reference-panel={showReferencePanel}>
-        {showReferencePanel && (
-          <div className="tl-shape-links-reference-panel">
-            <div className="text-base inline-flex gap-1 items-center">
-              <TablerIcon className="opacity-50" name="internal-link" />
-              {t('whiteboard/references')}
-            </div>
-            <ShapeLinkItem type={portalType} id={pageId} />
-          </div>
-        )}
-        <div className="tl-shape-links-panel color-level">
-          <div className="text-base inline-flex gap-1 items-center">
-            <TablerIcon className="opacity-50" name="add-link" />
-            {t('whiteboard/link-to-any-page-or-block')}
-          </div>
-
-          {canAddLink && (
-            <LogseqQuickSearch
-              style={{
-                width: 'calc(100% - 46px)',
-                marginLeft: '46px',
-              }}
-              placeholder={t('whiteboard/start-typing-to-search')}
-              onChange={addNewRef}
-            />
-          )}
-
-          {refs.length > 0 && (
-            <div className="flex flex-col items-stretch gap-2">
-              {refs.map((ref, i) => {
-                return (
-                  <ShapeLinkItem
-                    key={ref}
-                    id={ref}
-                    type={validUUID(ref) ? 'B' : 'P'}
-                    onRemove={() => {
-                      onRefsChange(refs.filter((_, j) => i !== j))
-                    }}
-                    showContent
-                  />
-                )
-              })}
-            </div>
-          )}
-        </div>
-      </div>
-    </PopoverButton>
-  )
-})

+ 0 - 18
packages/tldraw/apps/tldraw-logseq/src/components/inputs/TextInput.tsx

@@ -1,18 +0,0 @@
-import * as React from 'react'
-
-interface TextInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
-  autoResize?: boolean
-}
-
-export const TextInput = React.forwardRef<HTMLInputElement, TextInputProps>(
-  ({ autoResize = true, value, className, ...rest }, ref) => {
-    return (
-      <div className={'tl-input' + (className ? ' ' + className : '')}>
-        <div className="tl-input-sizer">
-          <div className="tl-input-hidden">{value}</div>
-          <input ref={ref} value={value} className="tl-text-input" type="text" {...rest} />
-        </div>
-      </div>
-    )
-  }
-)

+ 0 - 76
packages/tldraw/apps/tldraw-logseq/src/components/inputs/ToggleGroupInput.tsx

@@ -1,76 +0,0 @@
-import { TablerIcon } from '../icons'
-import { Tooltip } from '../Tooltip'
-
-// @ts-ignore
-const LSUI = window.LSUI
-
-export interface ToggleGroupInputOption {
-  value: string
-  icon: string
-  tooltip?: string
-}
-
-interface ToggleGroupInputProps extends React.HTMLAttributes<HTMLElement> {
-  options: ToggleGroupInputOption[]
-  value: string
-  onValueChange: (value: string) => void
-}
-
-interface ToggleGroupMultipleInputProps extends React.HTMLAttributes<HTMLElement> {
-  options: ToggleGroupInputOption[]
-  value: string[]
-  onValueChange: (value: string[]) => void
-}
-
-export function ToggleGroupInput({ options, value, onValueChange }: ToggleGroupInputProps) {
-  return (
-    <LSUI.ToggleGroup
-      type="single"
-      value={value}
-      onValueChange={onValueChange}
-    >
-      {options.map(option => {
-        return (
-          <Tooltip content={option.tooltip} key={option.value}>
-            <div className="inline-flex">
-              <LSUI.ToggleGroupItem
-                className="tl-button"
-                value={option.value}
-                disabled={option.value === value}
-              >
-                <TablerIcon name={option.icon} />
-              </LSUI.ToggleGroupItem>
-            </div>
-          </Tooltip>
-        )
-      })}
-    </LSUI.ToggleGroup>
-  )
-}
-
-export function ToggleGroupMultipleInput({
-  options,
-  value,
-  onValueChange,
-}: ToggleGroupMultipleInputProps) {
-  return (
-    <LSUI.ToggleGroup
-      className="inline-flex"
-      type="multiple"
-      value={value}
-      onValueChange={onValueChange}
-    >
-      {options.map(option => {
-        return (
-          <LSUI.ToggleGroupItem
-            className="tl-button"
-            key={option.value}
-            value={option.value}
-          >
-            <TablerIcon name={option.icon} />
-          </LSUI.ToggleGroupItem>
-        )
-      })}
-    </LSUI.ToggleGroup>
-  )
-}

+ 0 - 34
packages/tldraw/apps/tldraw-logseq/src/components/inputs/ToggleInput.tsx

@@ -1,34 +0,0 @@
-import { Tooltip } from '../Tooltip'
-
-// @ts-ignore
-const LSUI = window.LSUI
-
-interface ToggleInputProps extends React.HTMLAttributes<HTMLElement> {
-  toggle?: boolean
-  pressed: boolean
-  tooltip?: React.ReactNode
-  onPressedChange: (value: boolean) => void
-}
-
-export function ToggleInput({
-  toggle = true,
-  pressed,
-  onPressedChange,
-  className,
-  tooltip,
-  ...rest
-}: ToggleInputProps) {
-  return (
-    <Tooltip content={tooltip}>
-      <div className="inline-flex">
-        <LSUI.Toggle
-          {...rest}
-          data-toggle={toggle}
-          className={'tl-button' + (className ? ' ' + className : '')}
-          pressed={pressed}
-          onPressedChange={onPressedChange}
-        />
-      </div>
-    </Tooltip>
-  )
-}

+ 0 - 6
packages/tldraw/apps/tldraw-logseq/src/hooks/useCameraMoving.ts

@@ -1,6 +0,0 @@
-import { useApp } from '@tldraw/react'
-
-export function useCameraMovingRef() {
-  const app = useApp()
-  return app.inputs.state === 'panning' || app.inputs.state === 'pinching'
-}

+ 0 - 11
packages/tldraw/apps/tldraw-logseq/src/hooks/useCopy.ts

@@ -1,11 +0,0 @@
-import type { TLReactCallbacks } from '@tldraw/react'
-import * as React from 'react'
-import { LogseqContext } from '../lib/logseq-context'
-
-export function useCopy() {
-  const { handlers } = React.useContext(LogseqContext)
-
-  return React.useCallback<TLReactCallbacks['onCopy']>((app, { text, html }) => {
-    handlers.copyToClipboard(text, html)
-  }, [])
-}

+ 0 - 14
packages/tldraw/apps/tldraw-logseq/src/hooks/useDrop.ts

@@ -1,14 +0,0 @@
-import type { TLReactCallbacks } from '@tldraw/react'
-import * as React from 'react'
-import type { Shape } from '../lib'
-import { usePaste } from './usePaste'
-
-export function useDrop() {
-  const handlePaste = usePaste()
-  return React.useCallback<TLReactCallbacks<Shape>['onDrop']>(
-    async (app, { dataTransfer, point }) => {
-      handlePaste(app, { point, shiftKey: false, dataTransfer, fromDrop: true })
-    },
-    []
-  )
-}

+ 0 - 515
packages/tldraw/apps/tldraw-logseq/src/hooks/usePaste.ts

@@ -1,515 +0,0 @@
-import {
-  getSizeFromSrc,
-  isNonNullable,
-  TLAsset,
-  TLBinding,
-  TLCursor,
-  TLPasteEventInfo,
-  TLShapeModel,
-  uniqueId,
-  validUUID,
-} from '@tldraw/core'
-import type { TLReactApp, TLReactCallbacks } from '@tldraw/react'
-import Vec from '@tldraw/vec'
-import * as React from 'react'
-import { NIL as NIL_UUID } from 'uuid'
-import {
-  HTMLShape,
-  IFrameShape,
-  ImageShape,
-  PdfShape,
-  LogseqPortalShape,
-  VideoShape,
-  YouTubeShape,
-  YOUTUBE_REGEX,
-  TweetShape,
-  X_OR_TWITTER_REGEX,
-  type Shape,
-} from '../lib'
-import { LogseqContext, LogseqContextValue } from '../lib/logseq-context'
-
-const isValidURL = (url: string) => {
-  try {
-    const parsedUrl = new URL(url)
-    return parsedUrl.host && ['http:', 'https:'].includes(parsedUrl.protocol)
-  } catch {
-    return false
-  }
-}
-
-interface Asset extends TLAsset {
-  size?: number[]
-}
-
-const assetExtensions = {
-  image: ['.png', '.svg', '.jpg', '.jpeg', '.gif'],
-  video: ['.mp4', '.webm', '.ogg'],
-  pdf: ['.pdf'],
-}
-
-function getFileType(filename: string) {
-  // Get extension, verify that it's an image
-  const extensionMatch = filename.match(/\.[0-9a-z]+$/i)
-  if (!extensionMatch) return 'unknown'
-  const extension = extensionMatch[0].toLowerCase()
-
-  const [type, _extensions] = Object.entries(assetExtensions).find(([_type, extensions]) =>
-    extensions.includes(extension)
-  ) ?? ['unknown', null]
-
-  return type
-}
-
-type MaybeShapes = TLShapeModel[] | null | undefined
-
-type CreateShapeFN<Args extends any[]> = (...args: Args) => Promise<MaybeShapes> | MaybeShapes
-
-/**
- * Try create a shape from a list of create shape functions. If one of the functions returns a
- * shape, return it, otherwise try again for the next one until all have been tried.
- */
-function tryCreateShapeHelper<Args extends any[]>(...fns: CreateShapeFN<Args>[]) {
-  return async (...args: Args) => {
-    for (const fn of fns) {
-      const result = await fn(...(args as any))
-      if (result && result.length > 0) {
-        return result
-      }
-    }
-    return null
-  }
-}
-
-// TODO: support file types
-async function getDataFromType(item: DataTransfer | ClipboardItem, type: `text/${string}`) {
-  if (!item.types.includes(type)) {
-    return null
-  }
-  if (item instanceof DataTransfer) {
-    return item.getData(type)
-  }
-  const blob = await item.getType(type)
-  return await blob.text()
-}
-
-const handleCreatingShapes = async (
-  app: TLReactApp<Shape>,
-  { point, shiftKey, dataTransfer, fromDrop }: TLPasteEventInfo,
-  handlers: LogseqContextValue['handlers']
-) => {
-  let imageAssetsToCreate: Asset[] = []
-  let assetsToClone: TLAsset[] = []
-  const bindingsToCreate: TLBinding[] = []
-
-  async function createAssetsFromURL(url: string, type: string): Promise<Asset> {
-    // Do we already have an asset for this image?
-    const existingAsset = Object.values(app.assets).find(asset => asset.src === url)
-    if (existingAsset) {
-      return existingAsset as Asset
-    }
-
-    // Create a new asset for this image
-    const asset: Asset = {
-      id: uniqueId(),
-      type: type,
-      src: url,
-      size: await getSizeFromSrc(handlers.makeAssetUrl(url), type),
-    }
-    return asset
-  }
-
-  async function createAssetsFromFiles(files: File[]) {
-    const tasks = files
-      .filter(file => getFileType(file.name) !== 'unknown')
-      .map(async file => {
-        try {
-          const dataurl = await handlers.saveAsset(file)
-          return await createAssetsFromURL(dataurl, getFileType(file.name))
-        } catch (err) {
-          console.error(err)
-        }
-        return null
-      })
-    return (await Promise.all(tasks)).filter(isNonNullable)
-  }
-
-  function createHTMLShape(text: string) {
-    return [
-      {
-        ...HTMLShape.defaultProps,
-        html: text,
-        point: [point[0], point[1]],
-      },
-    ]
-  }
-
-  async function tryCreateShapesFromDataTransfer(dataTransfer: DataTransfer) {
-    return tryCreateShapeHelper(
-      tryCreateShapeFromFilePath,
-      tryCreateShapeFromFiles,
-      tryCreateShapeFromPageName,
-      tryCreateShapeFromBlockUUID,
-      tryCreateShapeFromTextPlain,
-      tryCreateShapeFromTextHTML,
-      tryCreateLogseqPortalShapesFromString
-    )(dataTransfer)
-  }
-
-  async function tryCreateShapesFromClipboard() {
-    const items = await navigator.clipboard.read()
-    const createShapesFn = tryCreateShapeHelper(
-      tryCreateShapeFromTextPlain,
-      tryCreateShapeFromTextHTML,
-      tryCreateLogseqPortalShapesFromString
-    )
-    const allShapes = (await Promise.all(items.map(item => createShapesFn(item))))
-      .flat()
-      .filter(isNonNullable)
-
-    return allShapes
-  }
-
-  async function tryCreateShapeFromFilePath(item: DataTransfer) {
-    const file = item.getData('file')
-    if (!file) return null
-
-    const asset = await createAssetsFromURL(file, 'pdf')
-    app.addAssets([asset])
-
-    const newShape = {
-      ...PdfShape.defaultProps,
-      id: uniqueId(),
-      assetId: asset.id,
-      url: file,
-      opacity: 1,
-    }
-
-    if (asset.size) {
-      Object.assign(newShape, {
-        point: [point[0] - asset.size[0] / 4 + 16, point[1] - asset.size[1] / 4 + 16],
-        size: Vec.div(asset.size, 2),
-      })
-    }
-    return [newShape]
-  }
-
-  async function tryCreateShapeFromFiles(item: DataTransfer) {
-    const files = Array.from(item.files)
-    if (files.length > 0) {
-      const assets = await createAssetsFromFiles(files)
-      // ? could we get rid of this side effect?
-      imageAssetsToCreate = assets
-
-      return assets.map((asset, i) => {
-        let defaultProps = null
-
-        switch (asset.type) {
-          case 'video':
-            defaultProps = VideoShape.defaultProps
-            break
-          case 'image':
-            defaultProps = ImageShape.defaultProps
-            break
-          case 'pdf':
-            defaultProps = PdfShape.defaultProps
-            break
-          default:
-            return null
-        }
-
-        const newShape = {
-          ...defaultProps,
-          id: uniqueId(),
-          // TODO: Should be place near the last edited shape
-          assetId: asset.id,
-          opacity: 1,
-        }
-
-        if (asset.size) {
-          Object.assign(newShape, {
-            point: [point[0] - asset.size[0] / 4 + i * 16, point[1] - asset.size[1] / 4 + i * 16],
-            size: Vec.div(asset.size, 2),
-          })
-        }
-
-        return newShape
-      })
-    }
-    return null
-  }
-
-  async function tryCreateShapeFromTextHTML(item: DataTransfer | ClipboardItem) {
-    // skips if it's a drop event or using shift key
-    if (item.types.includes('text/plain') && (shiftKey || fromDrop)) {
-      return null
-    }
-    const rawText = await getDataFromType(item, 'text/html')
-    if (rawText) {
-      return tryCreateShapeHelper(tryCreateClonedShapesFromJSON, createHTMLShape)(rawText)
-    }
-    return null
-  }
-
-  async function tryCreateShapeFromBlockUUID(dataTransfer: DataTransfer) {
-    // This is a Logseq custom data type defined in frontend.components.block
-    const rawText = dataTransfer.getData('block-uuid')
-    if (rawText) {
-      const text = rawText.trim()
-      const allSelectedBlocks = window.logseq?.api?.get_selected_blocks?.()
-      const blockUUIDs =
-        allSelectedBlocks && allSelectedBlocks?.length > 1
-          ? allSelectedBlocks.map(b => b.uuid)
-          : [text]
-      // ensure all uuid in blockUUIDs is persisted
-      window.logseq?.api?.set_blocks_id?.(blockUUIDs)
-      const tasks = blockUUIDs.map(uuid => tryCreateLogseqPortalShapesFromUUID(`((${uuid}))`))
-      const newShapes = (await Promise.all(tasks)).flat().filter(isNonNullable)
-      return newShapes.map((s, idx) => {
-        // if there are multiple shapes, shift them to the right
-        return {
-          ...s,
-          // TODO: use better alignment?
-          point: [point[0] + (LogseqPortalShape.defaultProps.size[0] + 16) * idx, point[1]],
-        }
-      })
-    }
-    return null
-  }
-
-  async function tryCreateShapeFromPageName(dataTransfer: DataTransfer) {
-    // This is a Logseq custom data type defined in frontend.components.block
-    const rawText = dataTransfer.getData('page-name')
-    if (rawText) {
-      const text = rawText.trim()
-
-      return tryCreateLogseqPortalShapesFromUUID(`[[${text}]]`)
-    }
-    return null
-  }
-
-  async function tryCreateShapeFromTextPlain(item: DataTransfer | ClipboardItem) {
-    const rawText = await getDataFromType(item, 'text/plain')
-    if (rawText) {
-      const text = rawText.trim()
-      return tryCreateShapeHelper(tryCreateShapeFromURL, tryCreateShapeFromIframeString)(text)
-    }
-
-    return null
-  }
-
-  function tryCreateClonedShapesFromJSON(rawText: string) {
-    const result = app.api.getClonedShapesFromTldrString(decodeURIComponent(rawText), point)
-    if (result) {
-      const { shapes, assets, bindings } = result
-      assetsToClone.push(...assets)
-      bindingsToCreate.push(...bindings)
-      return shapes
-    }
-    return null
-  }
-
-  async function tryCreateShapeFromURL(rawText: string) {
-    if (isValidURL(rawText) && !shiftKey) {
-      if (YOUTUBE_REGEX.test(rawText)) {
-        return [
-          {
-            ...YouTubeShape.defaultProps,
-            url: rawText,
-            point: [point[0], point[1]],
-          },
-        ]
-      }
-
-      if (X_OR_TWITTER_REGEX.test(rawText)) {
-        return [
-          {
-            ...TweetShape.defaultProps,
-            url: rawText,
-            point: [point[0], point[1]],
-          },
-        ]
-      }
-
-      return [
-        {
-          ...IFrameShape.defaultProps,
-          url: rawText,
-          point: [point[0], point[1]],
-        },
-      ]
-    }
-    return null
-  }
-
-  function tryCreateShapeFromIframeString(rawText: string) {
-    // if rawText is iframe text
-    if (rawText.startsWith('<iframe')) {
-      return [
-        {
-          ...HTMLShape.defaultProps,
-          html: rawText,
-          point: [point[0], point[1]],
-        },
-      ]
-    }
-    return null
-  }
-
-  async function tryCreateLogseqPortalShapesFromUUID(rawText: string) {
-    if (/^\(\(.*\)\)$/.test(rawText) && rawText.length === NIL_UUID.length + 4) {
-      const blockRef = rawText.slice(2, -2)
-      if (validUUID(blockRef)) {
-        return [
-          {
-            ...LogseqPortalShape.defaultProps,
-            point: [point[0], point[1]],
-            size: [400, 0], // use 0 here to enable auto-resize
-            pageId: blockRef,
-            fill: app.settings.color,
-            stroke: app.settings.color,
-            scaleLevel: app.settings.scaleLevel,
-            blockType: 'B' as 'B',
-          },
-        ]
-      }
-    }
-    // [[page name]] ?
-    else if (/^\[\[.*\]\]$/.test(rawText)) {
-      const pageName = rawText.slice(2, -2)
-      return [
-        {
-          ...LogseqPortalShape.defaultProps,
-          point: [point[0], point[1]],
-          size: [400, 0], // use 0 here to enable auto-resize
-          pageId: pageName,
-          fill: app.settings.color,
-          stroke: app.settings.color,
-          scaleLevel: app.settings.scaleLevel,
-          blockType: 'P' as 'P',
-        },
-      ]
-    }
-
-    return null
-  }
-
-  async function tryCreateLogseqPortalShapesFromString(item: DataTransfer | ClipboardItem) {
-    const rawText = await getDataFromType(item, 'text/plain')
-    if (rawText) {
-      const text = rawText.trim()
-      // Create a new block that belongs to the current whiteboard
-      const uuid = await handlers?.addNewBlock(text)
-      if (uuid) {
-        // create text shape
-        return [
-          {
-            ...LogseqPortalShape.defaultProps,
-            size: [400, 0], // use 0 here to enable auto-resize
-            point: [point[0], point[1]],
-            pageId: uuid,
-            fill: app.settings.color,
-            stroke: app.settings.color,
-            scaleLevel: app.settings.scaleLevel,
-            blockType: 'B' as 'B',
-            compact: true,
-          },
-        ]
-      }
-    }
-
-    return null
-  }
-
-  app.cursors.setCursor(TLCursor.Progress)
-
-  let newShapes: TLShapeModel[] = []
-  try {
-    if (dataTransfer) {
-      newShapes.push(...((await tryCreateShapesFromDataTransfer(dataTransfer)) ?? []))
-    } else {
-      // from Clipboard app or Shift copy etc
-      // in this case, we do not have the dataTransfer object
-      newShapes.push(...((await tryCreateShapesFromClipboard()) ?? []))
-    }
-  } catch (error) {
-    console.error(error)
-  }
-
-  const allShapesToAdd: TLShapeModel<Shape['props']>[] = newShapes.map(shape => {
-    return {
-      ...shape,
-      parentId: app.currentPageId,
-      isLocked: false,
-      id: validUUID(shape.id) ? shape.id : uniqueId(),
-    }
-  })
-
-  const filesOnly = dataTransfer?.types.every(t => t === 'Files')
-
-  app.wrapUpdate(() => {
-    const allAssets = [...imageAssetsToCreate, ...assetsToClone]
-    if (allAssets.length > 0) {
-      app.createAssets(allAssets)
-    }
-    if (allShapesToAdd.length > 0) {
-      app.createShapes(allShapesToAdd)
-    }
-    app.currentPage.updateBindings(Object.fromEntries(bindingsToCreate.map(b => [b.id, b])))
-
-    if (app.selectedShapesArray.length === 1 && allShapesToAdd.length === 1 && fromDrop) {
-      const source = app.selectedShapesArray[0]
-      const target = app.getShapeById(allShapesToAdd[0].id!)!
-      app.createNewLineBinding(source, target)
-    }
-
-    app.setSelectedShapes(allShapesToAdd.map(s => s.id))
-    app.selectedTool.transition('idle') // clears possible editing states
-    app.cursors.setCursor(TLCursor.Default)
-
-    if (fromDrop || filesOnly) {
-      app.packIntoRectangle()
-    }
-  })
-}
-
-// FIXME: for assets, we should prompt the user a loading spinner
-export function usePaste() {
-  const { handlers } = React.useContext(LogseqContext)
-
-  return React.useCallback<TLReactCallbacks<Shape>['onPaste']>(async (app, info) => {
-    // there is a special case for SHIFT+PASTE
-    // it will set the link to the current selected shape
-
-    if (info.shiftKey && app.selectedShapesArray.length === 1) {
-      // TODO: thinking about how to make this more generic with usePaste hook
-      // TODO: handle whiteboard shapes?
-      const items = await navigator.clipboard.read()
-      let newRef: string | undefined
-      if (items.length > 0) {
-        const blob = await items[0].getType('text/plain')
-        const rawText = (await blob.text()).trim()
-
-        if (rawText) {
-          if (/^\(\(.*\)\)$/.test(rawText) && rawText.length === NIL_UUID.length + 4) {
-            const blockRef = rawText.slice(2, -2)
-            if (validUUID(blockRef)) {
-              newRef = blockRef
-            }
-          } else if (/^\[\[.*\]\]$/.test(rawText)) {
-            newRef = rawText.slice(2, -2)
-          }
-        }
-      }
-      if (newRef) {
-        app.selectedShapesArray[0].update({
-          refs: [newRef],
-        })
-        app.persist()
-        return
-      }
-      // fall through to creating shapes
-    }
-
-    handleCreatingShapes(app, info, handlers)
-  }, [])
-}

+ 0 - 12
packages/tldraw/apps/tldraw-logseq/src/hooks/useQuickAdd.ts

@@ -1,12 +0,0 @@
-import type { TLReactCallbacks } from '@tldraw/react'
-import React from 'react'
-import type { Shape } from '../lib'
-
-export function useQuickAdd() {
-  return React.useCallback<TLReactCallbacks<Shape>['onCanvasDBClick']>(async app => {
-    // Give a timeout so that the quick add input will not be blurred too soon
-    setTimeout(() => {
-      app.transition('logseq-portal').selectedTool.transition('creating')
-    }, 100)
-  }, [])
-}

+ 0 - 18
packages/tldraw/apps/tldraw-logseq/src/index.ts

@@ -1,18 +0,0 @@
-export * from './app'
-export * from './lib/preview-manager'
-
-declare global {
-  interface Window {
-    logseq?: {
-      api?: {
-        make_asset_url?: (url: string) => string
-        get_page_blocks_tree?: (pageName: string) => any[]
-        edit_block?: (uuid: string) => void
-        set_blocks_id?: (uuids: string[]) => void
-        open_external_link?: (url: string) => void
-        get_selected_blocks?: () => { uuid: string }[]
-        get_state_from_store?: (path: string) => any
-      }
-    }
-  }
-}

+ 0 - 3
packages/tldraw/apps/tldraw-logseq/src/lib/index.ts

@@ -1,3 +0,0 @@
-export * from './shapes'
-export * from './tools'
-export * from './preview-manager'

+ 0 - 70
packages/tldraw/apps/tldraw-logseq/src/lib/logseq-context.ts

@@ -1,70 +0,0 @@
-import React from 'react'
-
-export interface SearchResult {
-  pages?: string[]
-  blocks?: { content: string; page: number; uuid: string }[]
-  files?: string[]
-}
-
-export interface LogseqContextValue {
-  renderers: {
-    Page: React.FC<{
-      pageName: string
-    }>
-    Block: React.FC<{
-      blockId: string
-    }>
-    Breadcrumb: React.FC<{
-      blockId: string
-      levelLimit?: number
-      endSeparator?: boolean
-    }>
-    Tweet: React.FC<{
-      tweetId: string
-    }>
-    PageName: React.FC<{
-      pageName: string
-    }>
-    BlockReference: React.FC<{
-      blockId: string
-    }>
-    BacklinksCount: React.FC<{
-      id: string
-      className?: string
-      options?: {
-        'portal?'?: boolean
-        'hover?'?: boolean
-        renderFn?: (open?: boolean, count?: number) => React.ReactNode
-      }
-    }>
-    KeyboardShortcut: React.FC<{
-      action?: string,
-      shortcut?: string,
-      opts?: any
-    }>
-  }
-  handlers: {
-    t: (key: string) => any
-    search: (
-      query: string,
-      filters: { 'pages?': boolean; 'blocks?': boolean; 'files?': boolean }
-    ) => Promise<SearchResult>
-    addNewWhiteboard: (pageName: string) => void
-    exportToImage: (pageName: string, options: object) => void
-    addNewBlock: (content: string) => string // returns the new block uuid
-    queryBlockByUUID: (uuid: string) => any
-    getBlockPageName: (uuid: string) => string
-    getRedirectPageName: (uuidOrPageName: string) => string
-    isWhiteboardPage: (pageName: string) => boolean
-    isMobile: () => boolean
-    saveAsset: (file: File) => Promise<string>
-    makeAssetUrl: (relativeUrl: string | null) => string
-    inflateAsset: (src: string) => object
-    setCurrentPdf: (src: string | null) => void
-    sidebarAddBlock: (uuid: string, type: 'block' | 'page') => void
-    redirectToPage: (uuidOrPageName: string) => void
-    copyToClipboard: (text: string, html: string) => void
-  }
-}
-
-export const LogseqContext = React.createContext<LogseqContextValue>({} as LogseqContextValue)

+ 0 - 148
packages/tldraw/apps/tldraw-logseq/src/lib/preview-manager.tsx

@@ -1,148 +0,0 @@
-import { BoundsUtils, TLAsset, TLDocumentModel, TLShapeConstructor, TLViewport } from '@tldraw/core'
-import ReactDOMServer from 'react-dom/server'
-import { Shape, shapes } from './shapes'
-
-const SVG_EXPORT_PADDING = 16
-
-const ShapesMap = new Map(shapes.map(shape => [shape.id, shape]))
-
-const getShapeClass = (type: string): TLShapeConstructor<Shape> => {
-  if (!type) throw Error('No shape type provided.')
-  const Shape = ShapesMap.get(type)
-  if (!Shape) throw Error(`Could not find shape class for ${type}`)
-  return Shape
-}
-
-export class PreviewManager {
-  shapes: Shape[] | undefined
-  pageId: string | undefined
-  assets: TLAsset[] | undefined
-  constructor(serializedApp?: TLDocumentModel<Shape>) {
-    if (serializedApp) {
-      this.load(serializedApp)
-    }
-  }
-
-  load(snapshot: TLDocumentModel) {
-    const page = snapshot?.pages?.[0]
-    this.pageId = page?.id
-    this.assets = snapshot.assets
-    this.shapes = page?.shapes
-      .map(s => {
-        const ShapeClass = getShapeClass(s.type)
-        return new ShapeClass(s)
-      })
-      // do not need to render group shape because it is invisible in preview
-      .filter(s => s.type !== 'group')
-  }
-
-  generatePreviewJsx(viewport?: TLViewport, ratio?: number) {
-    const allBounds = [...(this.shapes ?? []).map(s => s.getRotatedBounds())]
-    const vBounds = viewport?.currentView
-    if (vBounds) {
-      allBounds.push(vBounds)
-    }
-    let commonBounds = BoundsUtils.getCommonBounds(allBounds)
-    if (!commonBounds) {
-      return null
-    }
-
-    commonBounds = BoundsUtils.expandBounds(commonBounds, SVG_EXPORT_PADDING)
-
-    // make sure commonBounds is of ratio 4/3 (should we have another ratio setting?)
-    commonBounds = ratio ? BoundsUtils.ensureRatio(commonBounds, ratio) : commonBounds
-
-    const translatePoint = (p: [number, number]): [string, string] => {
-      return [(p[0] - commonBounds.minX).toFixed(2), (p[1] - commonBounds.minY).toFixed(2)]
-    }
-
-    const [vx, vy] = vBounds ? translatePoint([vBounds.minX, vBounds.minY]) : [0, 0]
-
-    const svgElement = commonBounds && (
-      <svg
-        xmlns="http://www.w3.org/2000/svg"
-        data-common-bound-x={commonBounds.minX.toFixed(2)}
-        data-common-bound-y={commonBounds.minY.toFixed(2)}
-        data-common-bound-width={commonBounds.width.toFixed(2)}
-        data-common-bound-height={commonBounds.height.toFixed(2)}
-        viewBox={[0, 0, commonBounds.width, commonBounds.height].join(' ')}
-      >
-        <defs>
-          {vBounds && (
-            <>
-              <rect
-                id={this.pageId + '-camera-rect'}
-                transform={`translate(${vx}, ${vy})`}
-                width={vBounds.width}
-                height={vBounds.height}
-              />
-              <mask id={this.pageId + '-camera-mask'}>
-                <rect width={commonBounds.width} height={commonBounds.height} fill="white" />
-                <use href={`#${this.pageId}-camera-rect`} fill="black" />
-              </mask>
-            </>
-          )}
-        </defs>
-        <g id={this.pageId + '-preview-shapes'}>
-          {this.shapes?.map(s => {
-            const {
-              bounds,
-              props: { rotation },
-            } = s
-            const [tx, ty] = translatePoint([bounds.minX, bounds.minY])
-            const r = +((((rotation ?? 0) + (bounds.rotation ?? 0)) * 180) / Math.PI).toFixed(2)
-            const [rdx, rdy] = [(bounds.width / 2).toFixed(2), (bounds.height / 2).toFixed(2)]
-            const transformArr = [`translate(${tx}, ${ty})`, `rotate(${r}, ${rdx}, ${rdy})`]
-            return (
-              <g transform={transformArr.join(' ')} key={s.id}>
-                {s.getShapeSVGJsx({
-                  assets: this.assets ?? [],
-                })}
-              </g>
-            )
-          })}
-        </g>
-        <rect
-          mask={vBounds ? `url(#${this.pageId}-camera-mask)` : ''}
-          width={commonBounds.width}
-          height={commonBounds.height}
-          fill="transparent"
-        />
-        {vBounds && (
-          <use
-            id="minimap-camera-rect"
-            data-x={vx}
-            data-y={vy}
-            data-width={vBounds.width}
-            data-height={vBounds.height}
-            href={`#${this.pageId}-camera-rect`}
-            fill="transparent"
-            stroke="red"
-            strokeWidth={4 / viewport.camera.zoom}
-          />
-        )}
-      </svg>
-    )
-    return svgElement
-  }
-
-  exportAsSVG(ratio: number) {
-    const svgElement = this.generatePreviewJsx(undefined, ratio)
-    return svgElement ? ReactDOMServer.renderToString(svgElement) : ''
-  }
-}
-
-/**
- * One off helper to generate tldraw preview
- *
- * @param serializedApp
- */
-export function generateSVGFromModel(serializedApp: TLDocumentModel<Shape>, ratio = 4 / 3) {
-  const preview = new PreviewManager(serializedApp)
-  return preview.exportAsSVG(ratio)
-}
-
-export function generateJSXFromModel(serializedApp: TLDocumentModel<Shape>, ratio = 4 / 3) {
-  const preview = new PreviewManager(serializedApp)
-  return preview.generatePreviewJsx(undefined, ratio)
-}

+ 0 - 32
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/BindingIndicator.tsx

@@ -1,32 +0,0 @@
-interface BindingIndicatorProps {
-  strokeWidth: number
-  size: number[]
-  mode: 'svg' | 'html'
-}
-export function BindingIndicator({ strokeWidth, size, mode }: BindingIndicatorProps) {
-  return mode === 'svg' ? (
-    <rect
-      className="tl-binding-indicator"
-      x={strokeWidth}
-      y={strokeWidth}
-      rx={2}
-      ry={2}
-      width={Math.max(0, size[0] - strokeWidth * 2)}
-      height={Math.max(0, size[1] - strokeWidth * 2)}
-      strokeWidth={strokeWidth * 4}
-    />
-  ) : (
-    <div
-      className="tl-binding-indicator"
-      style={{
-        position: 'absolute',
-        left: 0,
-        top: 0,
-        right: 0,
-        bottom: 0,
-        boxShadow: '0 0 0 4px var(--tl-binding)',
-        borderRadius: 4,
-      }}
-    />
-  )
-}

+ 0 - 195
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/BoxShape.tsx

@@ -1,195 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import { SVGContainer, TLComponentProps } from '@tldraw/react'
-import { TLBoxShape, TLBoxShapeProps, getComputedColor, getTextLabelSize } from '@tldraw/core'
-import Vec from '@tldraw/vec'
-import * as React from 'react'
-import { observer } from 'mobx-react-lite'
-import { CustomStyleProps, withClampedStyles } from './style-props'
-import { BindingIndicator } from './BindingIndicator'
-import { TextLabel } from './text/TextLabel'
-import type { SizeLevel } from '.'
-import { action, computed } from 'mobx'
-
-export interface BoxShapeProps extends TLBoxShapeProps, CustomStyleProps {
-  borderRadius: number
-  type: 'box'
-  label: string
-  fontSize: number
-  fontWeight: number
-  italic: boolean
-  scaleLevel?: SizeLevel
-}
-
-const font = '20px / 1 var(--ls-font-family)'
-
-const levelToScale = {
-  xs: 10,
-  sm: 16,
-  md: 20,
-  lg: 32,
-  xl: 48,
-  xxl: 60,
-}
-
-export class BoxShape extends TLBoxShape<BoxShapeProps> {
-  static id = 'box'
-
-  static defaultProps: BoxShapeProps = {
-    id: 'box',
-    parentId: 'page',
-    type: 'box',
-    point: [0, 0],
-    size: [100, 100],
-    borderRadius: 2,
-    stroke: '',
-    fill: '',
-    noFill: false,
-    fontWeight: 400,
-    fontSize: 20,
-    italic: false,
-    strokeType: 'line',
-    strokeWidth: 2,
-    opacity: 1,
-    label: '',
-  }
-
-  canEdit = true
-
-  ReactComponent = observer(
-    ({ events, isErasing, isBinding, isSelected, isEditing, onEditingEnd }: TLComponentProps) => {
-      const {
-        props: {
-          size: [w, h],
-          stroke,
-          fill,
-          noFill,
-          strokeWidth,
-          strokeType,
-          borderRadius,
-          opacity,
-          label,
-          italic,
-          fontWeight,
-          fontSize,
-        },
-      } = this
-
-      const labelSize =
-        label || isEditing
-          ? getTextLabelSize(
-              label,
-              { fontFamily: 'var(--ls-font-family)', fontSize, lineHeight: 1, fontWeight },
-              4
-            )
-          : [0, 0]
-      const midPoint = Vec.mul(this.props.size, 0.5)
-      const scale = Math.max(0.5, Math.min(1, w / labelSize[0], h / labelSize[1]))
-      const bounds = this.getBounds()
-
-      const offset = React.useMemo(() => {
-        return Vec.sub(midPoint, Vec.toFixed([bounds.width / 2, bounds.height / 2]))
-      }, [bounds, scale, midPoint])
-
-      const handleLabelChange = React.useCallback(
-        (label: string) => {
-          this.update?.({ label })
-        },
-        [label]
-      )
-
-      return (
-        <div
-          {...events}
-          style={{ width: '100%', height: '100%', overflow: 'hidden' }}
-          className="tl-box-container"
-        >
-          <TextLabel
-            font={font}
-            text={label}
-            color={getComputedColor(stroke, 'text')}
-            offsetX={offset[0]}
-            offsetY={offset[1]}
-            fontSize={fontSize}
-            scale={scale}
-            isEditing={isEditing}
-            onChange={handleLabelChange}
-            onBlur={onEditingEnd}
-            fontStyle={italic ? 'italic' : 'normal'}
-            fontWeight={fontWeight}
-            pointerEvents={!!label}
-          />
-          <SVGContainer opacity={isErasing ? 0.2 : opacity}>
-            {isBinding && <BindingIndicator mode="svg" strokeWidth={strokeWidth} size={[w, h]} />}
-            <rect
-              className={isSelected || !noFill ? 'tl-hitarea-fill' : 'tl-hitarea-stroke'}
-              x={strokeWidth / 2}
-              y={strokeWidth / 2}
-              rx={borderRadius}
-              ry={borderRadius}
-              width={Math.max(0.01, w - strokeWidth)}
-              height={Math.max(0.01, h - strokeWidth)}
-              pointerEvents="all"
-            />
-            <rect
-              x={strokeWidth / 2}
-              y={strokeWidth / 2}
-              rx={borderRadius}
-              ry={borderRadius}
-              width={Math.max(0.01, w - strokeWidth)}
-              height={Math.max(0.01, h - strokeWidth)}
-              strokeWidth={strokeWidth}
-              stroke={getComputedColor(stroke, 'stroke')}
-              strokeDasharray={strokeType === 'dashed' ? '8 2' : undefined}
-              fill={noFill ? 'none' : getComputedColor(fill, 'background')}
-            />
-          </SVGContainer>
-        </div>
-      )
-    }
-  )
-
-  @computed get scaleLevel() {
-    return this.props.scaleLevel ?? 'md'
-  }
-
-  @action setScaleLevel = async (v?: SizeLevel) => {
-    this.update({
-      scaleLevel: v,
-      fontSize: levelToScale[v ?? 'md'],
-      strokeWidth: levelToScale[v ?? 'md'] / 10,
-    })
-    this.onResetBounds()
-  }
-
-  ReactIndicator = observer(() => {
-    const {
-      props: {
-        size: [w, h],
-        borderRadius,
-        isLocked,
-      },
-    } = this
-
-    return (
-      <g>
-        <rect
-          width={w}
-          height={h}
-          rx={borderRadius}
-          ry={borderRadius}
-          fill="transparent"
-          strokeDasharray={isLocked ? '8 2' : undefined}
-        />
-      </g>
-    )
-  })
-
-  validateProps = (props: Partial<BoxShapeProps>) => {
-    if (props.size !== undefined) {
-      props.size[0] = Math.max(props.size[0], 1)
-      props.size[1] = Math.max(props.size[1], 1)
-    }
-    if (props.borderRadius !== undefined) props.borderRadius = Math.max(0, props.borderRadius)
-    return withClampedStyles(this, props)
-  }
-}

+ 0 - 62
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/DotShape.tsx

@@ -1,62 +0,0 @@
-import { TLDotShape, TLDotShapeProps } from '@tldraw/core'
-import { SVGContainer, TLComponentProps } from '@tldraw/react'
-import { observer } from 'mobx-react-lite'
-import { CustomStyleProps, withClampedStyles } from './style-props'
-
-export interface DotShapeProps extends TLDotShapeProps, CustomStyleProps {
-  type: 'dot'
-}
-
-export class DotShape extends TLDotShape<DotShapeProps> {
-  static id = 'dot'
-
-  static defaultProps: DotShapeProps = {
-    id: 'dot',
-    parentId: 'page',
-    type: 'dot',
-    point: [0, 0],
-    radius: 4,
-    stroke: '#000000',
-    fill: 'var(--ls-secondary-background-color)',
-    noFill: false,
-    strokeType: 'line',
-    strokeWidth: 2,
-    opacity: 1,
-  }
-
-  ReactComponent = observer(({ events, isErasing }: TLComponentProps) => {
-    const { radius, stroke, fill, strokeWidth, opacity } = this.props
-    return (
-      <SVGContainer {...events} opacity={isErasing ? 0.2 : opacity}>
-        <circle className="tl-hitarea-fill" cx={radius} cy={radius} r={radius} />
-        <circle
-          cx={radius}
-          cy={radius}
-          r={radius}
-          stroke={stroke}
-          fill={fill}
-          strokeWidth={strokeWidth}
-          pointerEvents="none"
-        />
-      </SVGContainer>
-    )
-  })
-
-  ReactIndicator = observer(() => {
-    const { radius, isLocked } = this.props
-    return (
-      <circle
-        cx={radius}
-        cy={radius}
-        r={radius}
-        pointerEvents="all"
-        strokeDasharray={isLocked ? '8 2' : 'undefined'}
-      />
-    )
-  })
-
-  validateProps = (props: Partial<DotShapeProps>) => {
-    if (props.radius !== undefined) props.radius = Math.max(props.radius, 1)
-    return withClampedStyles(this, props)
-  }
-}

+ 0 - 223
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/EllipseShape.tsx

@@ -1,223 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import {
-  TLEllipseShapeProps,
-  TLEllipseShape,
-  getComputedColor,
-  getTextLabelSize,
-} from '@tldraw/core'
-import { SVGContainer, TLComponentProps } from '@tldraw/react'
-import Vec from '@tldraw/vec'
-import * as React from 'react'
-import { observer } from 'mobx-react-lite'
-import { CustomStyleProps, withClampedStyles } from './style-props'
-import { TextLabel } from './text/TextLabel'
-import type { SizeLevel } from '.'
-import { action, computed } from 'mobx'
-
-export interface EllipseShapeProps extends TLEllipseShapeProps, CustomStyleProps {
-  type: 'ellipse'
-  size: number[]
-  label: string
-  fontSize: number
-  fontWeight: number
-  italic: boolean
-  scaleLevel?: SizeLevel
-}
-
-const font = '18px / 1 var(--ls-font-family)'
-
-const levelToScale = {
-  xs: 10,
-  sm: 16,
-  md: 20,
-  lg: 32,
-  xl: 48,
-  xxl: 60,
-}
-
-export class EllipseShape extends TLEllipseShape<EllipseShapeProps> {
-  static id = 'ellipse'
-
-  static defaultProps: EllipseShapeProps = {
-    id: 'ellipse',
-    parentId: 'page',
-    type: 'ellipse',
-    point: [0, 0],
-    size: [100, 100],
-    stroke: '',
-    fill: '',
-    noFill: false,
-    fontWeight: 400,
-    fontSize: 20,
-    italic: false,
-    strokeType: 'line',
-    strokeWidth: 2,
-    opacity: 1,
-    label: '',
-  }
-
-  canEdit = true
-
-  ReactComponent = observer(
-    ({ isSelected, isErasing, events, isEditing, onEditingEnd }: TLComponentProps) => {
-      const {
-        size: [w, h],
-        stroke,
-        fill,
-        noFill,
-        strokeWidth,
-        strokeType,
-        opacity,
-        label,
-        italic,
-        fontWeight,
-        fontSize,
-      } = this.props
-
-      const labelSize =
-        label || isEditing
-          ? getTextLabelSize(
-              label,
-              { fontFamily: 'var(--ls-font-family)', fontSize, lineHeight: 1, fontWeight },
-              4
-            )
-          : [0, 0]
-      const midPoint = Vec.mul(this.props.size, 0.5)
-      const scale = Math.max(0.5, Math.min(1, w / labelSize[0], h / labelSize[1]))
-      const bounds = this.getBounds()
-
-      const offset = React.useMemo(() => {
-        return Vec.sub(midPoint, Vec.toFixed([bounds.width / 2, bounds.height / 2]))
-      }, [bounds, scale, midPoint])
-
-      const handleLabelChange = React.useCallback(
-        (label: string) => {
-          this.update?.({ label })
-        },
-        [label]
-      )
-
-      return (
-        <div
-          {...events}
-          style={{ width: '100%', height: '100%', overflow: 'hidden' }}
-          className="tl-ellipse-container"
-        >
-          <TextLabel
-            font={font}
-            text={label}
-            color={getComputedColor(stroke, 'text')}
-            offsetX={offset[0]}
-            offsetY={offset[1]}
-            scale={scale}
-            isEditing={isEditing}
-            onChange={handleLabelChange}
-            onBlur={onEditingEnd}
-            fontStyle={italic ? 'italic' : 'normal'}
-            fontSize={fontSize}
-            fontWeight={fontWeight}
-            pointerEvents={!!label}
-          />
-          <SVGContainer {...events} opacity={isErasing ? 0.2 : opacity}>
-            <ellipse
-              className={isSelected || !noFill ? 'tl-hitarea-fill' : 'tl-hitarea-stroke'}
-              cx={w / 2}
-              cy={h / 2}
-              rx={Math.max(0.01, (w - strokeWidth) / 2)}
-              ry={Math.max(0.01, (h - strokeWidth) / 2)}
-            />
-            <ellipse
-              cx={w / 2}
-              cy={h / 2}
-              rx={Math.max(0.01, (w - strokeWidth) / 2)}
-              ry={Math.max(0.01, (h - strokeWidth) / 2)}
-              strokeWidth={strokeWidth}
-              stroke={getComputedColor(stroke, 'stroke')}
-              strokeDasharray={strokeType === 'dashed' ? '8 2' : undefined}
-              fill={noFill ? 'none' : getComputedColor(fill, 'background')}
-            />
-          </SVGContainer>
-        </div>
-      )
-    }
-  )
-
-  @computed get scaleLevel() {
-    return this.props.scaleLevel ?? 'md'
-  }
-
-  @action setScaleLevel = async (v?: SizeLevel) => {
-    this.update({
-      scaleLevel: v,
-      fontSize: levelToScale[v ?? 'md'],
-      strokeWidth: levelToScale[v ?? 'md'] / 10,
-    })
-    this.onResetBounds()
-  }
-
-  ReactIndicator = observer(() => {
-    const {
-      size: [w, h],
-      isLocked,
-    } = this.props
-
-    return (
-      <g>
-        <ellipse
-          cx={w / 2}
-          cy={h / 2}
-          rx={w / 2}
-          ry={h / 2}
-          strokeWidth={2}
-          fill="transparent"
-          strokeDasharray={isLocked ? '8 2' : 'undefined'}
-        />
-      </g>
-    )
-  })
-
-  validateProps = (props: Partial<EllipseShapeProps>) => {
-    if (props.size !== undefined) {
-      props.size[0] = Math.max(props.size[0], 1)
-      props.size[1] = Math.max(props.size[1], 1)
-    }
-    return withClampedStyles(this, props)
-  }
-
-  /**
-   * Get a svg group element that can be used to render the shape with only the props data. In the
-   * base, draw any shape as a box. Can be overridden by subclasses.
-   */
-  getShapeSVGJsx(opts: any) {
-    const {
-      size: [w, h],
-      stroke,
-      fill,
-      noFill,
-      strokeWidth,
-      strokeType,
-      opacity,
-    } = this.props
-    return (
-      <g opacity={opacity}>
-        <ellipse
-          className={!noFill ? 'tl-hitarea-fill' : 'tl-hitarea-stroke'}
-          cx={w / 2}
-          cy={h / 2}
-          rx={Math.max(0.01, (w - strokeWidth) / 2)}
-          ry={Math.max(0.01, (h - strokeWidth) / 2)}
-        />
-        <ellipse
-          cx={w / 2}
-          cy={h / 2}
-          rx={Math.max(0.01, (w - strokeWidth) / 2)}
-          ry={Math.max(0.01, (h - strokeWidth) / 2)}
-          strokeWidth={strokeWidth}
-          stroke={getComputedColor(stroke, 'stroke')}
-          strokeDasharray={strokeType === 'dashed' ? '8 2' : undefined}
-          fill={noFill ? 'none' : getComputedColor(fill, 'background')}
-        />
-      </g>
-    )
-  }
-}

+ 0 - 65
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/GroupShape.tsx

@@ -1,65 +0,0 @@
-import { GROUP_PADDING, TLGroupShape, TLGroupShapeProps } from '@tldraw/core'
-import { SVGContainer, TLComponentProps, useApp } from '@tldraw/react'
-import { observer } from 'mobx-react-lite'
-
-export interface GroupShapeProps extends TLGroupShapeProps {}
-
-export class GroupShape extends TLGroupShape<GroupShapeProps> {
-  static id = 'group'
-
-  static defaultProps: GroupShapeProps = {
-    id: 'group',
-    type: 'group',
-    parentId: 'page',
-    point: [0, 0],
-    size: [0, 0],
-    children: [],
-  }
-
-  // TODO: add styles for arrow binding states
-  ReactComponent = observer(({ events }: TLComponentProps) => {
-    const strokeWidth = 2
-    const bounds = this.getBounds()
-    const app = useApp()
-
-    const childSelected = app.selectedShapesArray.some(s => {
-      return app.shapesInGroups([this]).includes(s)
-    })
-
-    const Indicator = this.ReactIndicator
-
-    return (
-      <SVGContainer {...events} className="tl-group-container">
-        <rect
-          className={'tl-hitarea-fill'}
-          x={strokeWidth / 2}
-          y={strokeWidth / 2}
-          width={Math.max(0.01, bounds.width - strokeWidth)}
-          height={Math.max(0.01, bounds.height - strokeWidth)}
-          pointerEvents="all"
-        />
-        {childSelected && (
-          <g stroke="var(--color-selectedFill)">
-            <Indicator />
-          </g>
-        )}
-      </SVGContainer>
-    )
-  })
-
-  ReactIndicator = observer(() => {
-    const bounds = this.getBounds()
-    return (
-      <rect
-        strokeDasharray="8 2"
-        x={-GROUP_PADDING}
-        y={-GROUP_PADDING}
-        rx={GROUP_PADDING / 2}
-        ry={GROUP_PADDING / 2}
-        width={bounds.width + GROUP_PADDING * 2}
-        height={bounds.height + GROUP_PADDING * 2}
-        fill="transparent"
-      />
-    )
-  })
-}

+ 0 - 159
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/HTMLShape.tsx

@@ -1,159 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import { delay, TLBoxShape, TLBoxShapeProps, TLResetBoundsInfo } from '@tldraw/core'
-import { HTMLContainer, TLComponentProps, useApp } from '@tldraw/react'
-import Vec from '@tldraw/vec'
-import { action, computed } from 'mobx'
-import { observer } from 'mobx-react-lite'
-import * as React from 'react'
-import type { SizeLevel, Shape } from '.'
-import { useCameraMovingRef } from '../../hooks/useCameraMoving'
-import { withClampedStyles } from './style-props'
-
-export interface HTMLShapeProps extends TLBoxShapeProps {
-  type: 'html'
-  html: string
-  scaleLevel?: SizeLevel
-}
-
-const levelToScale = {
-  xs: 0.5,
-  sm: 0.8,
-  md: 1,
-  lg: 1.5,
-  xl: 2,
-  xxl: 3,
-}
-
-export class HTMLShape extends TLBoxShape<HTMLShapeProps> {
-  static id = 'html'
-
-  static defaultProps: HTMLShapeProps = {
-    id: 'html',
-    type: 'html',
-    parentId: 'page',
-    point: [0, 0],
-    size: [600, 0],
-    html: '',
-  }
-
-  canChangeAspectRatio = true
-  canFlip = false
-  canEdit = true
-  htmlAnchorRef = React.createRef<HTMLDivElement>()
-
-  @computed get scaleLevel() {
-    return this.props.scaleLevel ?? 'md'
-  }
-
-  @action setScaleLevel = async (v?: SizeLevel) => {
-    const newSize = Vec.mul(
-      this.props.size,
-      levelToScale[(v as SizeLevel) ?? 'md'] / levelToScale[this.props.scaleLevel ?? 'md']
-    )
-    this.update({
-      scaleLevel: v,
-    })
-    await delay()
-    this.update({
-      size: newSize,
-    })
-  }
-
-  onResetBounds = (info?: TLResetBoundsInfo) => {
-    if (this.htmlAnchorRef.current) {
-      const rect = this.htmlAnchorRef.current.getBoundingClientRect()
-      const [w, h] = Vec.div([rect.width, rect.height], info?.zoom ?? 1)
-      const clamp = (v: number) => Math.max(Math.min(v || 400, 1400), 10)
-      this.update({
-        size: [clamp(w), clamp(h)],
-      })
-    }
-    return this
-  }
-
-  ReactComponent = observer(({ events, isErasing, isEditing }: TLComponentProps) => {
-    const {
-      props: { html, scaleLevel },
-    } = this
-    const isMoving = useCameraMovingRef()
-    const app = useApp<Shape>()
-    const isSelected = app.selectedIds.has(this.id)
-
-    const tlEventsEnabled =
-      isMoving || (isSelected && !isEditing) || app.selectedTool.id !== 'select'
-    const stop = React.useCallback(
-      e => {
-        if (!tlEventsEnabled) {
-          // TODO: pinching inside Logseq Shape issue
-          e.stopPropagation()
-        }
-      },
-      [tlEventsEnabled]
-    )
-
-    const scaleRatio = levelToScale[scaleLevel ?? 'md']
-
-    React.useEffect(() => {
-      if (this.props.size[1] === 0) {
-        this.onResetBounds({ zoom: app.viewport.camera.zoom })
-        app.persist()
-      }
-    }, [])
-
-    return (
-      <HTMLContainer
-        style={{
-          overflow: 'hidden',
-          pointerEvents: 'all',
-          opacity: isErasing ? 0.2 : 1,
-        }}
-        {...events}
-      >
-        <div
-          onWheelCapture={stop}
-          onPointerDown={stop}
-          onPointerUp={stop}
-          className="tl-html-container"
-          style={{
-            pointerEvents: !isMoving && (isEditing || isSelected) ? 'all' : 'none',
-            overflow: isEditing ? 'auto' : 'hidden',
-            width: `calc(100% / ${scaleRatio})`,
-            height: `calc(100% / ${scaleRatio})`,
-            transform: `scale(${scaleRatio})`,
-          }}
-        >
-          <div
-            ref={this.htmlAnchorRef}
-            className="tl-html-anchor"
-            dangerouslySetInnerHTML={{ __html: html.trim() }}
-          />
-        </div>
-      </HTMLContainer>
-    )
-  })
-
-  ReactIndicator = observer(() => {
-    const {
-      props: {
-        size: [w, h],
-        isLocked,
-      },
-    } = this
-    return (
-      <rect
-        width={w}
-        height={h}
-        fill="transparent"
-        strokeDasharray={isLocked ? '8 2' : 'undefined'}
-      />
-    )
-  })
-
-  validateProps = (props: Partial<HTMLShapeProps>) => {
-    if (props.size !== undefined) {
-      props.size[0] = Math.max(props.size[0], 1)
-      props.size[1] = Math.max(props.size[1], 1)
-    }
-    return withClampedStyles(this, props)
-  }
-}

+ 0 - 116
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/HighlighterShape.tsx

@@ -1,116 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import { SvgPathUtils, TLDrawShape, TLDrawShapeProps, getComputedColor } from '@tldraw/core'
-import { SVGContainer, TLComponentProps } from '@tldraw/react'
-import { observer } from 'mobx-react-lite'
-import { action, computed, makeObservable } from 'mobx'
-import type { SizeLevel } from '.'
-import { CustomStyleProps, withClampedStyles } from './style-props'
-
-export interface HighlighterShapeProps extends TLDrawShapeProps, CustomStyleProps {
-  type: 'highlighter'
-  scaleLevel?: SizeLevel
-}
-
-const levelToScale = {
-  xs: 1,
-  sm: 1.6,
-  md: 2,
-  lg: 3.2,
-  xl: 4.8,
-  xxl: 6,
-}
-
-export class HighlighterShape extends TLDrawShape<HighlighterShapeProps> {
-  constructor(props = {} as Partial<HighlighterShapeProps>) {
-    super(props)
-    makeObservable(this)
-  }
-
-  static id = 'highlighter'
-
-  static defaultProps: HighlighterShapeProps = {
-    id: 'highlighter',
-    parentId: 'page',
-    type: 'highlighter',
-    point: [0, 0],
-    points: [],
-    isComplete: false,
-    stroke: '',
-    fill: '',
-    noFill: true,
-    strokeType: 'line',
-    strokeWidth: 2,
-    opacity: 0.5,
-  }
-
-  @computed get pointsPath() {
-    const { points } = this.props
-    return SvgPathUtils.getCurvedPathForPoints(points)
-  }
-
-  ReactComponent = observer(({ events, isErasing }: TLComponentProps) => {
-    const {
-      pointsPath,
-      props: { stroke, strokeWidth, opacity },
-    } = this
-
-    return (
-      <SVGContainer {...events} opacity={isErasing ? 0.2 : 1}>
-        <path
-          d={pointsPath}
-          strokeWidth={strokeWidth * 16}
-          stroke={getComputedColor(stroke, 'stroke')}
-          fill="none"
-          pointerEvents="all"
-          strokeLinejoin="round"
-          strokeLinecap="round"
-          opacity={opacity}
-        />
-      </SVGContainer>
-    )
-  })
-
-  @computed get scaleLevel() {
-    return this.props.scaleLevel ?? 'md'
-  }
-
-  @action setScaleLevel = async (v?: SizeLevel) => {
-    this.update({
-      scaleLevel: v,
-      strokeWidth: levelToScale[v ?? 'md'],
-    })
-    this.onResetBounds()
-  }
-
-  ReactIndicator = observer(() => {
-    const { pointsPath, props } = this
-    return (
-      <path d={pointsPath} fill="none" strokeDasharray={props.isLocked ? '8 2' : 'undefined'} />
-    )
-  })
-
-  validateProps = (props: Partial<HighlighterShapeProps>) => {
-    props = withClampedStyles(this, props)
-    if (props.strokeWidth !== undefined) props.strokeWidth = Math.max(props.strokeWidth, 1)
-    return props
-  }
-
-  getShapeSVGJsx() {
-    const {
-      pointsPath,
-      props: { stroke, strokeWidth, opacity },
-    } = this
-    return (
-      <path
-        d={pointsPath}
-        strokeWidth={strokeWidth * 16}
-        stroke={getComputedColor(stroke, 'stroke')}
-        fill="none"
-        pointerEvents="all"
-        strokeLinejoin="round"
-        strokeLinecap="round"
-        opacity={opacity}
-      />
-    )
-  }
-}

+ 0 - 100
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/IFrameShape.tsx

@@ -1,100 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import * as React from 'react'
-import { TLBoxShape, TLBoxShapeProps } from '@tldraw/core'
-import { HTMLContainer, TLComponentProps, useApp } from '@tldraw/react'
-import { action } from 'mobx'
-import { observer } from 'mobx-react-lite'
-
-export interface IFrameShapeProps extends TLBoxShapeProps {
-  type: 'iframe'
-  url: string
-}
-
-export class IFrameShape extends TLBoxShape<IFrameShapeProps> {
-  static id = 'iframe'
-  frameRef = React.createRef<HTMLIFrameElement>()
-
-  static defaultProps: IFrameShapeProps = {
-    id: 'iframe',
-    type: 'iframe',
-    parentId: 'page',
-    point: [0, 0],
-    size: [853, 480],
-    url: '',
-  }
-
-  canEdit = true
-
-  @action onIFrameSourceChange = (url: string) => {
-    this.update({ url })
-  }
-
-  @action reload = () => {
-    if (this.frameRef.current) {
-      this.frameRef.current.src = this.frameRef?.current?.src
-    }
-  }
-
-  ReactComponent = observer(({ events, isErasing, isEditing }: TLComponentProps) => {
-    const ref = React.useRef<HTMLIFrameElement>(null)
-    const app = useApp<Shape>()
-
-    return (
-      <HTMLContainer
-        style={{
-          overflow: 'hidden',
-          pointerEvents: 'all',
-          opacity: isErasing ? 0.2 : 1,
-        }}
-        {...events}
-      >
-        <div
-          className="tl-iframe-container"
-          style={{
-            pointerEvents: isEditing || app.readOnly ? 'all' : 'none',
-            userSelect: 'none',
-          }}
-        >
-          {this.props.url && (
-            <div
-              style={{
-                overflow: 'hidden',
-                position: 'relative',
-                height: '100%',
-              }}
-            >
-              <iframe
-                ref={this.frameRef}
-                className="absolute inset-0 w-full h-full m-0"
-                width="100%"
-                height="100%"
-                src={`${this.props.url}`}
-                frameBorder="0"
-                sandbox="allow-scripts allow-same-origin allow-presentation"
-              />
-            </div>
-          )}
-        </div>
-      </HTMLContainer>
-    )
-  })
-
-  ReactIndicator = observer(() => {
-    const {
-      props: {
-        size: [w, h],
-        isLocked,
-      },
-    } = this
-    return (
-      <rect
-        width={w}
-        height={h}
-        fill="transparent"
-        rx={8}
-        ry={8}
-        strokeDasharray={isLocked ? '8 2' : 'undefined'}
-      />
-    )
-  })
-}

+ 0 - 119
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/ImageShape.tsx

@@ -1,119 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import { TLAsset, TLImageShape, TLImageShapeProps } from '@tldraw/core'
-import { HTMLContainer, TLComponentProps } from '@tldraw/react'
-import { observer } from 'mobx-react-lite'
-import * as React from 'react'
-import { LogseqContext } from '../logseq-context'
-import { BindingIndicator } from './BindingIndicator'
-
-export interface ImageShapeProps extends TLImageShapeProps {
-  type: 'image'
-  assetId: string
-  opacity: number
-}
-
-export class ImageShape extends TLImageShape<ImageShapeProps> {
-  static id = 'image'
-
-  static defaultProps: ImageShapeProps = {
-    id: 'image1',
-    parentId: 'page',
-    type: 'image',
-    point: [0, 0],
-    size: [100, 100],
-    opacity: 1,
-    assetId: '',
-    clipping: 0,
-    objectFit: 'fill',
-    isAspectRatioLocked: true,
-  }
-
-  ReactComponent = observer(({ events, isErasing, isBinding, asset }: TLComponentProps) => {
-    const {
-      props: {
-        opacity,
-        objectFit,
-        clipping,
-        size: [w, h],
-      },
-    } = this
-
-    const [t, r, b, l] = Array.isArray(clipping)
-      ? clipping
-      : [clipping, clipping, clipping, clipping]
-
-    const { handlers } = React.useContext(LogseqContext)
-
-    return (
-      <HTMLContainer {...events} opacity={isErasing ? 0.2 : opacity}>
-        {isBinding && <BindingIndicator mode="html" strokeWidth={4} size={[w, h]} />}
-
-        <div data-asset-loaded={!!asset} className="tl-image-shape-container">
-          {asset ? (
-            <img
-              src={handlers ? handlers.makeAssetUrl(asset.src) : asset.src}
-              draggable={false}
-              style={{
-                position: 'relative',
-                top: -t,
-                left: -l,
-                width: w + (l - r),
-                height: h + (t - b),
-                objectFit,
-              }}
-            />
-          ) : (
-            'Asset is missing'
-          )}
-        </div>
-      </HTMLContainer>
-    )
-  })
-
-  ReactIndicator = observer(() => {
-    const {
-      props: {
-        size: [w, h],
-        isLocked,
-      },
-    } = this
-    return (
-      <rect
-        width={w}
-        height={h}
-        fill="transparent"
-        strokeDasharray={isLocked ? '8 2' : 'undefined'}
-      />
-    )
-  })
-
-  getShapeSVGJsx({ assets }: { assets: TLAsset[] }) {
-    // Do not need to consider the original point here
-    const bounds = this.getBounds()
-    const {
-      assetId,
-      clipping,
-      size: [w, h],
-    } = this.props
-    const asset = assets.find(ass => ass.id === assetId)
-
-    if (asset) {
-      // TODO: add clipping
-      const [t, r, b, l] = Array.isArray(clipping)
-        ? clipping
-        : [clipping, clipping, clipping, clipping]
-
-      const make_asset_url = window.logseq?.api?.make_asset_url
-
-      return (
-        <image
-          width={bounds.width}
-          height={bounds.height}
-          href={make_asset_url ? make_asset_url(asset.src) : asset.src}
-        />
-      )
-    } else {
-      return super.getShapeSVGJsx({})
-    }
-  }
-}

+ 0 - 252
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/LineShape.tsx

@@ -1,252 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import { Decoration, TLLineShape, TLLineShapeProps, getComputedColor } from '@tldraw/core'
-import { SVGContainer, TLComponentProps } from '@tldraw/react'
-import Vec from '@tldraw/vec'
-import { observer } from 'mobx-react-lite'
-import * as React from 'react'
-import { Arrow } from './arrow/Arrow'
-import { getArrowPath } from './arrow/arrowHelpers'
-import { CustomStyleProps, withClampedStyles } from './style-props'
-import { getTextLabelSize } from '@tldraw/core'
-import { LabelMask } from './text/LabelMask'
-import { TextLabel } from './text/TextLabel'
-import type { SizeLevel } from '.'
-import { action, computed } from 'mobx'
-
-interface LineShapeProps extends CustomStyleProps, TLLineShapeProps {
-  type: 'line'
-  label: string
-  fontSize: number
-  fontWeight: number
-  italic: boolean
-  scaleLevel?: SizeLevel
-}
-
-const font = '20px / 1 var(--ls-font-family)'
-
-const levelToScale = {
-  xs: 10,
-  sm: 16,
-  md: 20,
-  lg: 32,
-  xl: 48,
-  xxl: 60,
-}
-
-export class LineShape extends TLLineShape<LineShapeProps> {
-  static id = 'line'
-
-  static defaultProps: LineShapeProps = {
-    id: 'line',
-    parentId: 'page',
-    type: 'line',
-    point: [0, 0],
-    handles: {
-      start: { id: 'start', canBind: true, point: [0, 0] },
-      end: { id: 'end', canBind: true, point: [1, 1] },
-    },
-    stroke: '',
-    fill: '',
-    noFill: true,
-    fontWeight: 400,
-    fontSize: 20,
-    italic: false,
-    strokeType: 'line',
-    strokeWidth: 1,
-    opacity: 1,
-    decorations: {
-      end: Decoration.Arrow,
-    },
-    label: '',
-  }
-
-  hideSelection = true
-  canEdit = true
-
-  ReactComponent = observer(({ events, isErasing, isEditing, onEditingEnd }: TLComponentProps) => {
-    const {
-      stroke,
-      handles: { start, end },
-      opacity,
-      label,
-      italic,
-      fontWeight,
-      fontSize,
-      id,
-    } = this.props
-    const labelSize =
-      label || isEditing
-        ? getTextLabelSize(
-            label || 'Enter text',
-            { fontFamily: 'var(--ls-font-family)', fontSize, lineHeight: 1, fontWeight },
-            6
-          )
-        : [0, 0]
-    const midPoint = Vec.med(start.point, end.point)
-    const dist = Vec.dist(start.point, end.point)
-    const scale = Math.max(
-      0.5,
-      Math.min(1, Math.max(dist / (labelSize[1] + 128), dist / (labelSize[0] + 128)))
-    )
-    const bounds = this.getBounds()
-    const offset = React.useMemo(() => {
-      return Vec.sub(midPoint, Vec.toFixed([bounds.width / 2, bounds.height / 2]))
-    }, [bounds, scale, midPoint])
-    const handleLabelChange = React.useCallback(
-      (label: string) => {
-        this.update?.({ label })
-      },
-      [label]
-    )
-    return (
-      <div
-        {...events}
-        style={{ width: '100%', height: '100%', overflow: 'hidden' }}
-        className="tl-line-container"
-      >
-        <TextLabel
-          font={font}
-          text={label}
-          fontSize={fontSize}
-          color={getComputedColor(stroke, 'text')}
-          offsetX={offset[0]}
-          offsetY={offset[1]}
-          scale={scale}
-          isEditing={isEditing}
-          onChange={handleLabelChange}
-          onBlur={onEditingEnd}
-          fontStyle={italic ? 'italic' : 'normal'}
-          fontWeight={fontWeight}
-          pointerEvents={!!label}
-        />
-        <SVGContainer opacity={isErasing ? 0.2 : opacity} id={id + '_svg'}>
-          <LabelMask id={id} bounds={bounds} labelSize={labelSize} offset={offset} scale={scale} />
-          <g pointerEvents="none" mask={label || isEditing ? `url(#${id}_clip)` : ``}>
-            {this.getShapeSVGJsx({ preview: false })}
-          </g>
-        </SVGContainer>
-      </div>
-    )
-  })
-
-  @computed get scaleLevel() {
-    return this.props.scaleLevel ?? 'md'
-  }
-
-  @action setScaleLevel = async (v?: SizeLevel) => {
-    this.update({
-      scaleLevel: v,
-      fontSize: levelToScale[v ?? 'md'],
-    })
-    this.onResetBounds()
-  }
-
-  ReactIndicator = observer(({ isEditing }: TLComponentProps) => {
-    const {
-      id,
-      decorations,
-      label,
-      strokeWidth,
-      fontSize,
-      fontWeight,
-      handles: { start, end },
-      isLocked,
-    } = this.props
-    const bounds = this.getBounds()
-    const labelSize =
-      label || isEditing
-        ? getTextLabelSize(
-            label,
-            { fontFamily: 'var(--ls-font-family)', fontSize, lineHeight: 1, fontWeight },
-            6
-          )
-        : [0, 0]
-    const midPoint = Vec.med(start.point, end.point)
-    const dist = Vec.dist(start.point, end.point)
-    const scale = Math.max(
-      0.5,
-      Math.min(1, Math.max(dist / (labelSize[1] + 128), dist / (labelSize[0] + 128)))
-    )
-    const offset = React.useMemo(() => {
-      return Vec.sub(midPoint, Vec.toFixed([bounds.width / 2, bounds.height / 2]))
-    }, [bounds, scale, midPoint])
-    return (
-      <g>
-        <path
-          mask={label ? `url(#${id}_clip)` : ``}
-          d={getArrowPath(
-            { strokeWidth },
-            start.point,
-            end.point,
-            decorations?.start,
-            decorations?.end
-          )}
-          strokeDasharray={isLocked ? '8 2' : 'undefined'}
-        />
-        {label && !isEditing && (
-          <rect
-            x={bounds.width / 2 - (labelSize[0] / 2) * scale + offset[0]}
-            y={bounds.height / 2 - (labelSize[1] / 2) * scale + offset[1]}
-            width={labelSize[0] * scale}
-            height={labelSize[1] * scale}
-            rx={4 * scale}
-            ry={4 * scale}
-            fill="transparent"
-          />
-        )}
-      </g>
-    )
-  })
-
-  validateProps = (props: Partial<LineShapeProps>) => {
-    return withClampedStyles(this, props)
-  }
-
-  getShapeSVGJsx({ preview }: any) {
-    const {
-      stroke,
-      fill,
-      strokeWidth,
-      strokeType,
-      decorations,
-      label,
-      scaleLevel,
-      handles: { start, end },
-    } = this.props
-    const midPoint = Vec.med(start.point, end.point)
-    return (
-      <>
-        <Arrow
-          style={{
-            stroke: getComputedColor(stroke, 'text'),
-            fill,
-            strokeWidth,
-            strokeType,
-          }}
-          scaleLevel={scaleLevel}
-          start={start.point}
-          end={end.point}
-          decorationStart={decorations?.start}
-          decorationEnd={decorations?.end}
-        />
-        {preview && (
-          <>
-            <text
-              style={{
-                transformOrigin: 'top left',
-              }}
-              fontFamily="Inter"
-              fontSize={20}
-              transform={`translate(${midPoint[0]}, ${midPoint[1]})`}
-              textAnchor="middle"
-              fill={getComputedColor(stroke, 'text')}
-              stroke={getComputedColor(stroke, 'text')}
-            >
-              {label}
-            </text>
-          </>
-        )}
-      </>
-    )
-  }
-}

+ 0 - 605
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/LogseqPortalShape.tsx

@@ -1,605 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import {
-  delay,
-  getComputedColor,
-  TLBoxShape,
-  TLBoxShapeProps,
-  TLResetBoundsInfo,
-  TLResizeInfo,
-  validUUID,
-  isBuiltInColor,
-} from '@tldraw/core'
-import { HTMLContainer, TLComponentProps, useApp } from '@tldraw/react'
-import Vec from '@tldraw/vec'
-import { action, computed, makeObservable } from 'mobx'
-import { observer } from 'mobx-react-lite'
-import * as React from 'react'
-import type { Shape, SizeLevel } from '.'
-import { LogseqQuickSearch } from '../../components/QuickSearch'
-import { useCameraMovingRef } from '../../hooks/useCameraMoving'
-import { LogseqContext } from '../logseq-context'
-import { BindingIndicator } from './BindingIndicator'
-import { CustomStyleProps, withClampedStyles } from './style-props'
-
-const HEADER_HEIGHT = 40
-const AUTO_RESIZE_THRESHOLD = 1
-
-export interface LogseqPortalShapeProps extends TLBoxShapeProps, CustomStyleProps {
-  type: 'logseq-portal'
-  pageId: string // page name or UUID
-  blockType?: 'P' | 'B'
-  collapsed?: boolean
-  compact?: boolean
-  borderRadius?: number
-  collapsedHeight?: number
-  scaleLevel?: SizeLevel
-}
-
-const levelToScale = {
-  xs: 0.5,
-  sm: 0.8,
-  md: 1,
-  lg: 1.5,
-  xl: 2,
-  xxl: 3,
-}
-
-const LogseqPortalShapeHeader = observer(
-  ({
-    type,
-    fill,
-    opacity,
-    children,
-  }: {
-    type: 'P' | 'B'
-    fill?: string
-    opacity: number
-    children: React.ReactNode
-  }) => {
-    const bgColor =
-      fill !== 'var(--ls-secondary-background-color)'
-        ? getComputedColor(fill, 'background')
-        : 'var(--ls-tertiary-background-color)'
-
-    const fillGradient =
-      fill && fill !== 'var(--ls-secondary-background-color)'
-        ? isBuiltInColor(fill)
-          ? `var(--ls-highlight-color-${fill})`
-          : fill
-        : 'var(--ls-secondary-background-color)'
-
-    return (
-      <div
-        className={`tl-logseq-portal-header tl-logseq-portal-header-${
-          type === 'P' ? 'page' : 'block'
-        }`}
-      >
-        <div
-          className="absolute inset-0 tl-logseq-portal-header-bg"
-          style={{
-            opacity,
-            background:
-              type === 'P' ? bgColor : `linear-gradient(0deg, ${fillGradient}, ${bgColor})`,
-          }}
-        ></div>
-        <div className="relative">{children}</div>
-      </div>
-    )
-  }
-)
-
-export class LogseqPortalShape extends TLBoxShape<LogseqPortalShapeProps> {
-  static id = 'logseq-portal'
-  static defaultSearchQuery = ''
-  static defaultSearchFilter: 'B' | 'P' | null = null
-
-  static defaultProps: LogseqPortalShapeProps = {
-    id: 'logseq-portal',
-    type: 'logseq-portal',
-    parentId: 'page',
-    point: [0, 0],
-    size: [400, 50],
-    // collapsedHeight is the height before collapsing
-    collapsedHeight: 0,
-    stroke: '',
-    fill: '',
-    noFill: false,
-    borderRadius: 8,
-    strokeWidth: 2,
-    strokeType: 'line',
-    opacity: 1,
-    pageId: '',
-    collapsed: false,
-    compact: false,
-    scaleLevel: 'md',
-    isAutoResizing: true,
-  }
-
-  hideRotateHandle = true
-  canChangeAspectRatio = true
-  canFlip = true
-  canEdit = true
-
-  persist: ((replace?: boolean) => void) | null = null
-  // For quick add shapes, we want to calculate the page height dynamically
-  initialHeightCalculated = true
-  getInnerHeight: (() => number) | null = null // will be overridden in the hook
-
-  constructor(props = {} as Partial<LogseqPortalShapeProps>) {
-    super(props)
-    makeObservable(this)
-    if (props.collapsed) {
-      Object.assign(this.canResize, [true, false])
-    }
-    if (props.size?.[1] === 0) {
-      this.initialHeightCalculated = false
-    }
-  }
-
-  static isPageOrBlock(id: string): 'P' | 'B' | false {
-    const blockRefEg = '((62af02d0-0443-42e8-a284-946c162b0f89))'
-    if (id) {
-      return /^\(\(.*\)\)$/.test(id) && id.length === blockRefEg.length ? 'B' : 'P'
-    }
-    return false
-  }
-
-  @computed get collapsed() {
-    return this.props.blockType === 'B' ? this.props.compact : this.props.collapsed
-  }
-
-  @action setCollapsed = async (collapsed: boolean) => {
-    if (this.props.blockType === 'B') {
-      this.update({ compact: collapsed })
-      this.canResize[1] = !collapsed
-      if (!collapsed) {
-        this.onResetBounds()
-      }
-    } else {
-      const originalHeight = this.props.size[1]
-      this.canResize[1] = !collapsed
-      this.update({
-        isAutoResizing: !collapsed,
-        collapsed: collapsed,
-        size: [this.props.size[0], collapsed ? this.getHeaderHeight() : this.props.collapsedHeight],
-        collapsedHeight: collapsed ? originalHeight : this.props.collapsedHeight,
-      })
-    }
-    this.persist?.()
-  }
-
-  @computed get scaleLevel() {
-    return this.props.scaleLevel ?? 'md'
-  }
-
-  @action setScaleLevel = async (v?: SizeLevel) => {
-    const newSize = Vec.mul(
-      this.props.size,
-      levelToScale[(v as SizeLevel) ?? 'md'] / levelToScale[this.props.scaleLevel ?? 'md']
-    )
-    this.update({
-      scaleLevel: v,
-    })
-    await delay()
-    this.update({
-      size: newSize,
-    })
-  }
-
-  useComponentSize<T extends HTMLElement>(ref: React.RefObject<T> | null, selector = '') {
-    const [size, setSize] = React.useState<[number, number]>([0, 0])
-    const app = useApp<Shape>()
-    React.useEffect(() => {
-      setTimeout(() => {
-        if (ref?.current) {
-          const el = selector ? ref.current.querySelector<HTMLElement>(selector) : ref.current
-          if (el) {
-            const updateSize = () => {
-              const { width, height } = el.getBoundingClientRect()
-              const bound = Vec.div([width, height], app.viewport.camera.zoom) as [number, number]
-              setSize(bound)
-              return bound
-            }
-            updateSize()
-            // Hacky, I know 🤨
-            this.getInnerHeight = () => updateSize()[1]
-            const resizeObserver = new ResizeObserver(() => {
-              updateSize()
-            })
-            resizeObserver.observe(el)
-            return () => {
-              resizeObserver.disconnect()
-            }
-          }
-        }
-        return () => {}
-      }, 10);
-    }, [ref, selector])
-    return size
-  }
-
-  getHeaderHeight() {
-    const scale = levelToScale[this.props.scaleLevel ?? 'md']
-    return this.props.compact ? 0 : HEADER_HEIGHT * scale
-  }
-
-  getAutoResizeHeight() {
-    if (this.getInnerHeight) {
-      return this.getHeaderHeight() + this.getInnerHeight()
-    }
-    return null
-  }
-
-  onResetBounds = (info?: TLResetBoundsInfo) => {
-    const height = this.getAutoResizeHeight()
-    if (height !== null && Math.abs(height - this.props.size[1]) > AUTO_RESIZE_THRESHOLD) {
-      this.update({
-        size: [this.props.size[0], height],
-      })
-      this.initialHeightCalculated = true
-    }
-    return this
-  }
-
-  onResize = (initialProps: any, info: TLResizeInfo): this => {
-    const {
-      bounds,
-      rotation,
-      scale: [scaleX, scaleY],
-    } = info
-    const nextScale = [...this.scale]
-    if (scaleX < 0) nextScale[0] *= -1
-    if (scaleY < 0) nextScale[1] *= -1
-
-    let height = bounds.height
-
-    if (this.props.isAutoResizing) {
-      height = this.getAutoResizeHeight() ?? height
-    }
-
-    return this.update({
-      point: [bounds.minX, bounds.minY],
-      size: [Math.max(1, bounds.width), Math.max(1, height)],
-      scale: nextScale,
-      rotation,
-    })
-  }
-
-  PortalComponent = observer(({}: TLComponentProps) => {
-    const {
-      props: { pageId, fill, opacity },
-    } = this
-    const { renderers } = React.useContext(LogseqContext)
-    const app = useApp<Shape>()
-
-    const cpRefContainer = React.useRef<HTMLDivElement>(null)
-
-    const [, innerHeight] = this.useComponentSize(
-      cpRefContainer,
-      this.props.compact
-        ? '.tl-logseq-cp-container > .single-block'
-        : '.tl-logseq-cp-container > .page'
-    )
-
-    if (!renderers?.Page) {
-      return null // not being correctly configured
-    }
-    const { Page, Block } = renderers
-    const [loaded, setLoaded] = React.useState(false)
-
-    React.useEffect(() => {
-      if (this.props.isAutoResizing) {
-        const latestInnerHeight = this.getInnerHeight?.() ?? innerHeight
-        const newHeight = latestInnerHeight + this.getHeaderHeight()
-        if (innerHeight && Math.abs(newHeight - this.props.size[1]) > AUTO_RESIZE_THRESHOLD) {
-          this.update({
-            size: [this.props.size[0], newHeight],
-          })
-
-          if (loaded) app.persist({})
-        }
-      }
-    }, [innerHeight, this.props.isAutoResizing])
-
-    React.useEffect(() => {
-      if (!this.initialHeightCalculated) {
-        setTimeout(() => {
-          this.onResetBounds()
-          app.persist({})
-        })
-      }
-    }, [this.initialHeightCalculated])
-
-    React.useEffect(() => {
-      setTimeout(function () {
-        setLoaded(true)
-      })
-    }, [])
-
-    return (
-      <>
-        <div
-          className="absolute inset-0 tl-logseq-cp-container-bg"
-          style={{
-            textRendering: app.viewport.camera.zoom < 0.5 ? 'optimizeSpeed' : 'auto',
-            background:
-              fill && fill !== 'var(--ls-secondary-background-color)'
-                ? isBuiltInColor(fill)
-                  ? `var(--ls-highlight-color-${fill})`
-                  : fill
-                : 'var(--ls-secondary-background-color)',
-            opacity,
-          }}
-        ></div>
-        <div
-          ref={cpRefContainer}
-          className="relative tl-logseq-cp-container"
-          style={{ overflow: this.props.isAutoResizing ? 'visible' : 'auto' }}
-        >
-          {(loaded || !this.initialHeightCalculated) &&
-            (this.props.blockType === 'B' && this.props.compact ? (
-              <Block blockId={pageId} />
-            ) : (
-              <Page pageName={pageId} />
-            ))}
-        </div>
-      </>
-    )
-  })
-
-  ReactComponent = observer((componentProps: TLComponentProps) => {
-    const { events, isErasing, isEditing, isBinding } = componentProps
-    const {
-      props: { opacity, pageId, fill, scaleLevel, strokeWidth, size, isLocked },
-    } = this
-
-    const app = useApp<Shape>()
-    const { renderers, handlers } = React.useContext(LogseqContext)
-
-    this.persist = () => app.persist()
-    const isMoving = useCameraMovingRef()
-    const isSelected = app.selectedIds.has(this.id) && app.selectedIds.size === 1
-
-    const isCreating = app.isIn('logseq-portal.creating') && !pageId
-    const tlEventsEnabled =
-      (isMoving || (isSelected && !isEditing) || app.selectedTool.id !== 'select') && !isCreating
-    const stop = React.useCallback(
-      e => {
-        if (!tlEventsEnabled) {
-          // TODO: pinching inside Logseq Shape issue
-          e.stopPropagation()
-        }
-      },
-      [tlEventsEnabled]
-    )
-
-    // There are some other portal sharing the same page id are selected
-    const portalSelected =
-      app.selectedShapesArray.length === 1 &&
-      app.selectedShapesArray.some(
-        shape =>
-          shape.type === 'logseq-portal' &&
-          shape.props.id !== this.props.id &&
-          pageId &&
-          (shape as LogseqPortalShape).props['pageId'] === pageId
-      )
-
-    const scaleRatio = levelToScale[scaleLevel ?? 'md']
-
-    // It is a bit weird to update shapes here. Is there a better place?
-    React.useEffect(() => {
-      if (this.props.collapsed && isEditing) {
-        // Should temporarily disable collapsing
-        this.update({
-          size: [this.props.size[0], this.props.collapsedHeight],
-        })
-        return () => {
-          this.update({
-            size: [this.props.size[0], this.getHeaderHeight()],
-          })
-        }
-      }
-      return () => {
-        // no-ops
-      }
-    }, [isEditing, this.props.collapsed])
-
-    React.useEffect(() => {
-      if (isCreating) {
-        const screenSize = [app.viewport.bounds.width, app.viewport.bounds.height]
-        const boundScreenCenter = app.viewport.getScreenPoint([this.bounds.minX, this.bounds.minY])
-
-        if (
-          boundScreenCenter[0] > screenSize[0] - 400 ||
-          boundScreenCenter[1] > screenSize[1] - 240 ||
-          app.viewport.camera.zoom > 1.5 ||
-          app.viewport.camera.zoom < 0.5
-        ) {
-          app.viewport.zoomToBounds({ ...this.bounds, minY: this.bounds.maxY + 25 })
-        }
-      }
-    }, [app.viewport.bounds.height.toFixed(2)])
-
-    const onPageNameChanged = React.useCallback((id: string, isPage: boolean) => {
-      this.initialHeightCalculated = false
-      const blockType = isPage ? 'P' : 'B'
-      const height = isPage ? 320 : 40
-      this.update({
-        pageId: id,
-        size: [400, height],
-        blockType: blockType,
-        compact: blockType === 'B',
-      })
-      app.selectTool('select')
-      app.history.resume()
-      app.history.persist()
-    }, [])
-
-    const PortalComponent = this.PortalComponent
-
-    const blockContent = React.useMemo(() => {
-      if (pageId && this.props.blockType === 'B') {
-        return handlers?.queryBlockByUUID(pageId)?.title
-      }
-    }, [handlers?.queryBlockByUUID, pageId])
-
-    const targetNotFound = this.props.blockType === 'B' && typeof blockContent !== 'string'
-    const showingPortal = (!this.props.collapsed || isEditing) && !targetNotFound
-
-    if (!renderers?.Page) {
-      return null // not being correctly configured
-    }
-
-    const { Breadcrumb, PageName } = renderers
-
-    const portalStyle: React.CSSProperties = {
-      width: `calc(100% / ${scaleRatio})`,
-      height: `calc(100% / ${scaleRatio})`,
-      opacity: isErasing ? 0.2 : 1,
-    }
-
-    // Reduce the chance of blurry text
-    if (scaleRatio !== 1) {
-      portalStyle.transform = `scale(${scaleRatio})`
-    }
-
-    return (
-      <HTMLContainer
-        style={{
-          pointerEvents: 'all',
-        }}
-        {...events}
-      >
-        {isBinding && <BindingIndicator mode="html" strokeWidth={strokeWidth} size={size} />}
-        <div
-          data-inner-events={!tlEventsEnabled}
-          onWheelCapture={stop}
-          onPointerDown={stop}
-          onPointerUp={stop}
-          style={{
-            width: '100%',
-            height: '100%',
-            pointerEvents: !isMoving && (isEditing || isSelected) ? 'all' : 'none',
-          }}
-        >
-          {isCreating ? (
-            <LogseqQuickSearch
-              onChange={onPageNameChanged}
-              onAddBlock={uuid => {
-                // wait until the editor is mounted
-                setTimeout(() => {
-                  app.api.editShape(this)
-                  window.logseq?.api?.edit_block?.(uuid)
-                }, 128)
-              }}
-              placeholder="Create or search your graph..."
-            />
-          ) : (
-            <div
-              className="tl-logseq-portal-container"
-              data-collapsed={this.collapsed}
-              data-page-id={pageId}
-              data-portal-selected={portalSelected}
-              data-editing={isEditing}
-              style={portalStyle}
-            >
-              {!this.props.compact && !targetNotFound && (
-                <LogseqPortalShapeHeader
-                  type={this.props.blockType ?? 'P'}
-                  fill={fill}
-                  opacity={opacity}
-                >
-                  {this.props.blockType === 'P' ? (
-                    <PageName pageName={pageId} />
-                  ) : (
-                    <Breadcrumb blockId={pageId} />
-                  )}
-                </LogseqPortalShapeHeader>
-              )}
-              {targetNotFound && <div className="tl-target-not-found">Target not found</div>}
-              {showingPortal && <PortalComponent {...componentProps} />}
-            </div>
-          )}
-        </div>
-      </HTMLContainer>
-    )
-  })
-
-  ReactIndicator = observer(() => {
-    const bounds = this.getBounds()
-    return (
-      <rect
-        width={bounds.width}
-        height={bounds.height}
-        fill="transparent"
-        rx={8}
-        ry={8}
-        strokeDasharray={this.props.isLocked ? '8 2' : 'undefined'}
-      />
-    )
-  })
-
-  validateProps = (props: Partial<LogseqPortalShapeProps>) => {
-    if (props.size !== undefined) {
-      const scale = levelToScale[this.props.scaleLevel ?? 'md']
-      props.size[0] = Math.max(props.size[0], 60 * scale)
-      props.size[1] = Math.max(props.size[1], HEADER_HEIGHT * scale)
-    }
-    return withClampedStyles(this, props)
-  }
-
-  getShapeSVGJsx({ preview }: any) {
-    // Do not need to consider the original point here
-    const bounds = this.getBounds()
-
-    return (
-      <>
-        <rect
-          fill={
-            this.props.fill && this.props.fill !== 'var(--ls-secondary-background-color)'
-              ? isBuiltInColor(this.props.fill)
-                ? `var(--ls-highlight-color-${this.props.fill})`
-                : this.props.fill
-              : 'var(--ls-secondary-background-color)'
-          }
-          stroke={getComputedColor(this.props.fill, 'background')}
-          strokeWidth={this.props.strokeWidth ?? 2}
-          fillOpacity={this.props.opacity ?? 0.2}
-          width={bounds.width}
-          rx={8}
-          ry={8}
-          height={bounds.height}
-        />
-        {!this.props.compact && (
-          <rect
-            fill={
-              this.props.fill && this.props.fill !== 'var(--ls-secondary-background-color)'
-                ? getComputedColor(this.props.fill, 'background')
-                : 'var(--ls-tertiary-background-color)'
-            }
-            fillOpacity={this.props.opacity ?? 0.2}
-            x={1}
-            y={1}
-            width={bounds.width - 2}
-            height={HEADER_HEIGHT - 2}
-            rx={8}
-            ry={8}
-          />
-        )}
-        <text
-          style={{
-            transformOrigin: 'top left',
-          }}
-          transform={`translate(${bounds.width / 2}, ${10 + bounds.height / 2})`}
-          textAnchor="middle"
-          fontFamily="var(--ls-font-family)"
-          fontSize="32"
-          fill="var(--ls-secondary-text-color)"
-          stroke="var(--ls-secondary-text-color)"
-        >
-          {this.props.blockType === 'P' ? this.props.pageName : ''}
-        </text>
-      </>
-    )
-  }
-}

+ 0 - 83
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/PdfShape.tsx

@@ -1,83 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import * as React from 'react'
-import { TLBoxShape, TLBoxShapeProps } from '@tldraw/core'
-import { HTMLContainer, TLComponentProps, useApp } from '@tldraw/react'
-import { observer } from 'mobx-react-lite'
-import { LogseqContext } from '../logseq-context'
-import { useCameraMovingRef } from '../../hooks/useCameraMoving'
-
-export interface PdfShapeProps extends TLBoxShapeProps {
-  type: 'pdf'
-  assetId: string
-}
-
-export class PdfShape extends TLBoxShape<PdfShapeProps> {
-  static id = 'pdf'
-  frameRef = React.createRef<HTMLElement>()
-
-  static defaultProps: PdfShapeProps = {
-    id: 'pdf',
-    type: 'pdf',
-    parentId: 'page',
-    point: [0, 0],
-    size: [595, 842],
-    assetId: '',
-  }
-
-  canChangeAspectRatio = true
-  canFlip = true
-  canEdit = true
-
-  ReactComponent = observer(({ events, asset, isErasing, isEditing }: TLComponentProps) => {
-    const ref = React.useRef<HTMLElement>(null)
-    const { handlers } = React.useContext(LogseqContext)
-    const app = useApp<Shape>()
-
-    const isMoving = useCameraMovingRef()
-
-    return (
-      <HTMLContainer
-        style={{
-          overflow: 'hidden',
-          pointerEvents: 'all',
-          opacity: isErasing ? 0.2 : 1,
-        }}
-        {...events}
-      >
-        {asset ? (
-          <embed
-            src={handlers ? handlers.inflateAsset(asset.src).url : asset.src}
-            className="relative tl-pdf-container"
-            onWheelCapture={stop}
-            onPointerDown={stop}
-            onPointerUp={stop}
-            style={{
-              width: '100%',
-              height: '100%',
-              pointerEvents: !isMoving && isEditing ? 'all' : 'none',
-            }}
-          />
-        ) : null}
-      </HTMLContainer>
-    )
-  })
-
-  ReactIndicator = observer(() => {
-    const {
-      props: {
-        size: [w, h],
-        isLocked,
-      },
-    } = this
-    return (
-      <rect
-        width={w}
-        height={h}
-        fill="transparent"
-        rx={8}
-        ry={8}
-        strokeDasharray={isLocked ? '8 2' : 'undefined'}
-      />
-    )
-  })
-}

+ 0 - 77
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/PenShape.tsx

@@ -1,77 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import { getStroke } from 'perfect-freehand'
-import { SvgPathUtils, TLDrawShape, TLDrawShapeProps, getComputedColor } from '@tldraw/core'
-import { SVGContainer, TLComponentProps } from '@tldraw/react'
-import { observer } from 'mobx-react-lite'
-import { computed, makeObservable } from 'mobx'
-import { CustomStyleProps, withClampedStyles } from './style-props'
-
-export interface PenShapeProps extends TLDrawShapeProps, CustomStyleProps {
-  type: 'pen'
-}
-
-export class PenShape extends TLDrawShape<PenShapeProps> {
-  constructor(props = {} as Partial<PenShapeProps>) {
-    super(props)
-    makeObservable(this)
-  }
-
-  static id = 'pen'
-
-  static defaultProps: PenShapeProps = {
-    id: 'pen',
-    parentId: 'page',
-    type: 'pen',
-    point: [0, 0],
-    points: [],
-    isComplete: false,
-    stroke: '',
-    fill: '',
-    noFill: false,
-    strokeType: 'line',
-    strokeWidth: 2,
-    opacity: 1,
-  }
-
-  @computed get pointsPath() {
-    const {
-      props: { points, isComplete, strokeWidth },
-    } = this
-    if (points.length < 2) {
-      return `M -4, 0
-      a 4,4 0 1,0 8,0
-      a 4,4 0 1,0 -8,0`
-    }
-    const stroke = getStroke(points, { size: 4 + strokeWidth * 2, last: isComplete })
-    return SvgPathUtils.getCurvedPathForPolygon(stroke)
-  }
-
-  ReactComponent = observer(({ events, isErasing }: TLComponentProps) => {
-    const {
-      pointsPath,
-      props: { stroke, strokeWidth, opacity },
-    } = this
-    return (
-      <SVGContainer {...events} opacity={isErasing ? 0.2 : opacity}>
-        <path
-          d={pointsPath}
-          strokeWidth={strokeWidth}
-          stroke={getComputedColor(stroke, 'stroke')}
-          fill={getComputedColor(stroke, 'stroke')}
-          pointerEvents="all"
-        />
-      </SVGContainer>
-    )
-  })
-
-  ReactIndicator = observer(() => {
-    const { pointsPath } = this
-    return <path d={pointsPath} strokeDasharray={this.props.isLocked ? '8 2' : 'undefined'} />
-  })
-
-  validateProps = (props: Partial<PenShapeProps>) => {
-    props = withClampedStyles(this, props)
-    if (props.strokeWidth !== undefined) props.strokeWidth = Math.max(props.strokeWidth, 1)
-    return props
-  }
-}

+ 0 - 163
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/PencilShape.tsx

@@ -1,163 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import { SvgPathUtils, TLDrawShape, TLDrawShapeProps, getComputedColor } from '@tldraw/core'
-import { SVGContainer, TLComponentProps } from '@tldraw/react'
-import Vec from '@tldraw/vec'
-import { action, computed, makeObservable } from 'mobx'
-import { observer } from 'mobx-react-lite'
-import {
-  getStrokeOutlinePoints,
-  getStrokePoints,
-  StrokeOptions,
-  StrokePoint,
-} from 'perfect-freehand'
-import type { SizeLevel } from '.'
-import { CustomStyleProps, withClampedStyles } from './style-props'
-
-export interface PencilShapeProps extends TLDrawShapeProps, CustomStyleProps {
-  type: 'pencil'
-  scaleLevel?: SizeLevel
-}
-
-const levelToScale = {
-  xs: 1,
-  sm: 1.6,
-  md: 2,
-  lg: 3.2,
-  xl: 4.8,
-  xxl: 6,
-}
-
-const simulatePressureSettings: StrokeOptions = {
-  easing: t => Math.sin((t * Math.PI) / 2),
-  simulatePressure: true,
-}
-
-const realPressureSettings: StrokeOptions = {
-  easing: t => t * t,
-  simulatePressure: false,
-}
-
-function getFreehandOptions(shape: PencilShapeProps) {
-  const options: StrokeOptions = {
-    size: 1 + shape.strokeWidth * 1.5,
-    thinning: 0.65,
-    streamline: 0.65,
-    smoothing: 0.65,
-    ...(shape.points[1][2] === 0.5 ? simulatePressureSettings : realPressureSettings),
-    last: shape.isComplete,
-  }
-
-  return options
-}
-
-function getFillPath(shape: PencilShapeProps) {
-  if (shape.points.length < 2) return ''
-
-  return SvgPathUtils.getSvgPathFromStroke(
-    getStrokePoints(shape.points, getFreehandOptions(shape)).map(pt => pt.point)
-  )
-}
-
-function getDrawStrokePoints(shape: PencilShapeProps, options: StrokeOptions) {
-  return getStrokePoints(shape.points, options)
-}
-
-function getDrawStrokePathTDSnapshot(shape: PencilShapeProps) {
-  if (shape.points.length < 2) return ''
-  const options = getFreehandOptions(shape)
-  const strokePoints = getDrawStrokePoints(shape, options)
-  const path = SvgPathUtils.getSvgPathFromStroke(getStrokeOutlinePoints(strokePoints, options))
-  return path
-}
-
-function getSolidStrokePathTDSnapshot(shape: PencilShapeProps) {
-  const { points } = shape
-  if (points.length < 2) return 'M 0 0 L 0 0'
-  const options = getFreehandOptions(shape)
-  const strokePoints = getDrawStrokePoints(shape, options)
-  const last = points[points.length - 1]
-  if (!Vec.isEqual(strokePoints[0].point, last)) strokePoints.push({ point: last } as StrokePoint)
-  const path = SvgPathUtils.getSvgPathFromStrokePoints(strokePoints)
-  return path
-}
-
-export class PencilShape extends TLDrawShape<PencilShapeProps> {
-  constructor(props = {} as Partial<PencilShapeProps>) {
-    super(props)
-    makeObservable(this)
-  }
-
-  static id = 'pencil'
-
-  static defaultProps: PencilShapeProps = {
-    id: 'pencil',
-    parentId: 'page',
-    type: 'pencil',
-    point: [0, 0],
-    points: [],
-    isComplete: false,
-    stroke: '',
-    fill: '',
-    noFill: true,
-    strokeType: 'line',
-    strokeWidth: 2,
-    opacity: 1,
-  }
-
-  @computed get pointsPath() {
-    return getDrawStrokePathTDSnapshot(this.props)
-  }
-
-  ReactComponent = observer(({ events, isErasing }: TLComponentProps) => {
-    const {
-      props: { opacity },
-    } = this
-    return (
-      <SVGContainer {...events} opacity={isErasing ? 0.2 : opacity}>
-        {this.getShapeSVGJsx()}
-      </SVGContainer>
-    )
-  })
-
-  @computed get scaleLevel() {
-    return this.props.scaleLevel ?? 'md'
-  }
-
-  @action setScaleLevel = async (v?: SizeLevel) => {
-    this.update({
-      scaleLevel: v,
-      strokeWidth: levelToScale[v ?? 'md'],
-    })
-    this.onResetBounds()
-  }
-
-  ReactIndicator = observer(() => {
-    const { pointsPath } = this
-    return <path d={pointsPath} strokeDasharray={this.props.isLocked ? '8 2' : 'undefined'} />
-  })
-
-  validateProps = (props: Partial<PencilShapeProps>) => {
-    props = withClampedStyles(this, props)
-    if (props.strokeWidth !== undefined) props.strokeWidth = Math.max(props.strokeWidth, 1)
-    return props
-  }
-
-  getShapeSVGJsx() {
-    const {
-      pointsPath,
-      props: { stroke, strokeWidth, strokeType },
-    } = this
-    return (
-      <path
-        pointerEvents="all"
-        d={pointsPath}
-        strokeWidth={strokeWidth / 2}
-        strokeLinejoin="round"
-        strokeLinecap="round"
-        stroke={getComputedColor(stroke, 'text')}
-        fill={getComputedColor(stroke, 'text')}
-        strokeDasharray={strokeType === 'dashed' ? '12 4' : undefined}
-      />
-    )
-  }
-}

+ 0 - 218
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/PolygonShape.tsx

@@ -1,218 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import {
-  TLPolygonShape,
-  TLPolygonShapeProps,
-  getComputedColor,
-  getTextLabelSize,
-} from '@tldraw/core'
-import { SVGContainer, TLComponentProps } from '@tldraw/react'
-import Vec from '@tldraw/vec'
-import * as React from 'react'
-import { observer } from 'mobx-react-lite'
-import { CustomStyleProps, withClampedStyles } from './style-props'
-import { TextLabel } from './text/TextLabel'
-import type { SizeLevel } from '.'
-import { action, computed } from 'mobx'
-
-interface PolygonShapeProps extends TLPolygonShapeProps, CustomStyleProps {
-  type: 'polygon'
-  label: string
-  fontSize: number
-  fontWeight: number
-  italic: boolean
-  scaleLevel?: SizeLevel
-}
-
-const font = '20px / 1 var(--ls-font-family)'
-
-const levelToScale = {
-  xs: 10,
-  sm: 16,
-  md: 20,
-  lg: 32,
-  xl: 48,
-  xxl: 60,
-}
-
-export class PolygonShape extends TLPolygonShape<PolygonShapeProps> {
-  static id = 'polygon'
-
-  static defaultProps: PolygonShapeProps = {
-    id: 'polygon',
-    parentId: 'page',
-    type: 'polygon',
-    point: [0, 0],
-    size: [100, 100],
-    sides: 3,
-    ratio: 1,
-    isFlippedY: false,
-    stroke: '',
-    fill: '',
-    fontWeight: 400,
-    fontSize: 20,
-    italic: false,
-    noFill: false,
-    strokeType: 'line',
-    strokeWidth: 2,
-    opacity: 1,
-    label: '',
-  }
-
-  canEdit = true
-
-  ReactComponent = observer(
-    ({ events, isErasing, isSelected, isEditing, onEditingEnd }: TLComponentProps) => {
-      const {
-        offset: [x, y],
-        props: {
-          stroke,
-          fill,
-          noFill,
-          strokeWidth,
-          opacity,
-          strokeType,
-          label,
-          italic,
-          fontWeight,
-          fontSize,
-        },
-      } = this
-
-      const path = this.getVertices(strokeWidth / 2).join()
-
-      const labelSize =
-        label || isEditing
-          ? getTextLabelSize(
-              label,
-              { fontFamily: 'var(--ls-font-family)', fontSize, lineHeight: 1, fontWeight },
-              4
-            )
-          : [0, 0]
-      // Using the centroid of the polygon as the label position is preferable in this case
-      // This shape is an isosceles triangle at the time of writing this comment
-      const midPoint = [this.props.size[0] / 2, (this.props.size[1] * 2) / 3]
-      const scale = Math.max(
-        0.5,
-        Math.min(
-          1,
-          this.props.size[0] / (labelSize[0] * 2),
-          this.props.size[1] / (labelSize[1] * 2)
-        )
-      )
-      const bounds = this.getBounds()
-
-      const offset = React.useMemo(() => {
-        return Vec.sub(midPoint, Vec.toFixed([bounds.width / 2, bounds.height / 2]))
-      }, [bounds, scale, midPoint])
-
-      const handleLabelChange = React.useCallback(
-        (label: string) => {
-          this.update?.({ label })
-        },
-        [label]
-      )
-
-      return (
-        <div {...events} style={{ width: '100%', height: '100%', overflow: 'hidden' }}>
-          <TextLabel
-            font={font}
-            text={label}
-            fontSize={fontSize}
-            color={getComputedColor(stroke, 'text')}
-            offsetX={offset[0]}
-            offsetY={offset[1] / scale}
-            scale={scale}
-            isEditing={isEditing}
-            onChange={handleLabelChange}
-            onBlur={onEditingEnd}
-            fontStyle={italic ? 'italic' : 'normal'}
-            fontWeight={fontWeight}
-            pointerEvents={!!label}
-          />
-          <SVGContainer opacity={isErasing ? 0.2 : opacity}>
-            <g transform={`translate(${x}, ${y})`}>
-              <polygon
-                className={isSelected || !noFill ? 'tl-hitarea-fill' : 'tl-hitarea-stroke'}
-                points={path}
-              />
-              <polygon
-                points={path}
-                stroke={getComputedColor(stroke, 'stroke')}
-                fill={noFill ? 'none' : getComputedColor(fill, 'background')}
-                strokeWidth={strokeWidth}
-                rx={2}
-                ry={2}
-                strokeLinejoin="round"
-                strokeDasharray={strokeType === 'dashed' ? '8 2' : undefined}
-              />
-            </g>
-          </SVGContainer>
-        </div>
-      )
-    }
-  )
-
-  @computed get scaleLevel() {
-    return this.props.scaleLevel ?? 'md'
-  }
-
-  @action setScaleLevel = async (v?: SizeLevel) => {
-    this.update({
-      scaleLevel: v,
-      fontSize: levelToScale[v ?? 'md'],
-      strokeWidth: levelToScale[v ?? 'md'] / 10,
-    })
-    this.onResetBounds()
-  }
-
-  ReactIndicator = observer(() => {
-    const {
-      offset: [x, y],
-      props: { strokeWidth, isLocked },
-    } = this
-
-    return (
-      <g>
-        <polygon
-          transform={`translate(${x}, ${y})`}
-          points={this.getVertices(strokeWidth / 2).join()}
-          strokeDasharray={isLocked ? '8 2' : 'undefined'}
-        />
-      </g>
-    )
-  })
-
-  validateProps = (props: Partial<PolygonShapeProps>) => {
-    if (props.sides !== undefined) props.sides = Math.max(props.sides, 3)
-    return withClampedStyles(this, props)
-  }
-
-  /**
-   * Get a svg group element that can be used to render the shape with only the props data. In the
-   * base, draw any shape as a box. Can be overridden by subclasses.
-   */
-  getShapeSVGJsx(opts: any) {
-    // Do not need to consider the original point here
-    const {
-      offset: [x, y],
-      props: { stroke, fill, noFill, strokeWidth, opacity, strokeType },
-    } = this
-    const path = this.getVertices(strokeWidth / 2).join()
-
-    return (
-      <g transform={`translate(${x}, ${y})`} opacity={opacity}>
-        <polygon className={!noFill ? 'tl-hitarea-fill' : 'tl-hitarea-stroke'} points={path} />
-        <polygon
-          points={path}
-          stroke={getComputedColor(stroke, 'stroke')}
-          fill={noFill ? 'none' : getComputedColor(fill, 'background')}
-          strokeWidth={strokeWidth}
-          rx={2}
-          ry={2}
-          strokeLinejoin="round"
-          strokeDasharray={strokeType === 'dashed' ? '8 2' : undefined}
-        />
-      </g>
-    )
-  }
-}

+ 0 - 334
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/TextShape.tsx

@@ -1,334 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import {
-  getTextLabelSize,
-  TextUtils,
-  TLBounds,
-  TLResizeStartInfo,
-  TLTextShape,
-  TLTextShapeProps,
-  getComputedColor,
-  isSafari,
-} from '@tldraw/core'
-import { HTMLContainer, TLComponentProps } from '@tldraw/react'
-import { action, computed } from 'mobx'
-import { observer } from 'mobx-react-lite'
-import * as React from 'react'
-import type { SizeLevel } from '.'
-import { CustomStyleProps, withClampedStyles } from './style-props'
-import { TextAreaUtils } from './text/TextAreaUtils'
-
-export interface TextShapeProps extends TLTextShapeProps, CustomStyleProps {
-  borderRadius: number
-  fontFamily: string
-  fontSize: number
-  fontWeight: number
-  italic: boolean
-  lineHeight: number
-  padding: number
-  type: 'text'
-  scaleLevel?: SizeLevel
-}
-
-const levelToScale = {
-  xs: 10,
-  sm: 16,
-  md: 20,
-  lg: 32,
-  xl: 48,
-  xxl: 60,
-}
-
-export class TextShape extends TLTextShape<TextShapeProps> {
-  static id = 'text'
-
-  static defaultProps: TextShapeProps = {
-    id: 'box',
-    parentId: 'page',
-    type: 'text',
-    point: [0, 0],
-    size: [0, 0],
-    isSizeLocked: true,
-    text: '',
-    lineHeight: 1.2,
-    fontSize: 20,
-    fontWeight: 400,
-    italic: false,
-    padding: 4,
-    fontFamily: 'var(--ls-font-family)',
-    borderRadius: 0,
-    stroke: '',
-    fill: '',
-    noFill: true,
-    strokeType: 'line',
-    strokeWidth: 2,
-    opacity: 1,
-  }
-
-  ReactComponent = observer(({ events, isErasing, isEditing, onEditingEnd }: TLComponentProps) => {
-    const {
-      props: {
-        opacity,
-        fontFamily,
-        fontSize,
-        fontWeight,
-        italic,
-        lineHeight,
-        text,
-        stroke,
-        padding,
-      },
-    } = this
-    const rInput = React.useRef<HTMLTextAreaElement>(null)
-
-    const rIsMounted = React.useRef(false)
-
-    const rInnerWrapper = React.useRef<HTMLDivElement>(null)
-
-    // When the text changes, update the text—and,
-    const handleChange = React.useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => {
-      const { isSizeLocked } = this.props
-      const text = TextUtils.normalizeText(e.currentTarget.value)
-      if (isSizeLocked) {
-        this.update({ text, size: this.getAutoSizedBoundingBox({ text }) })
-        return
-      }
-      // If not autosizing, update just the text
-      this.update({ text })
-    }, [])
-
-    const handleKeyDown = React.useCallback((e: React.KeyboardEvent<HTMLTextAreaElement>) => {
-      if (e.key === 'Escape') return
-
-      if (e.key === 'Tab' && text.length === 0) {
-        e.preventDefault()
-        return
-      }
-
-      if (!(e.key === 'Meta' || e.metaKey)) {
-        e.stopPropagation()
-      } else if (e.key === 'z' && e.metaKey) {
-        if (e.shiftKey) {
-          document.execCommand('redo', false)
-        } else {
-          document.execCommand('undo', false)
-        }
-        e.stopPropagation()
-        e.preventDefault()
-        return
-      }
-
-      if (e.key === 'Tab') {
-        e.preventDefault()
-        if (e.shiftKey) {
-          TextAreaUtils.unindent(e.currentTarget)
-        } else {
-          TextAreaUtils.indent(e.currentTarget)
-        }
-
-        this.update({ text: TextUtils.normalizeText(e.currentTarget.value) })
-      }
-    }, [])
-
-    const handleBlur = React.useCallback(
-      (e: React.FocusEvent<HTMLTextAreaElement>) => {
-        if (!isEditing) return
-        onEditingEnd?.()
-      },
-      [onEditingEnd]
-    )
-
-    const handleFocus = React.useCallback(
-      (e: React.FocusEvent<HTMLTextAreaElement>) => {
-        if (!isEditing) return
-        if (!rIsMounted.current) return
-        if (document.activeElement === e.currentTarget) {
-          e.currentTarget.select()
-        }
-      },
-      [isEditing]
-    )
-
-    const handlePointerDown = React.useCallback(
-      e => {
-        if (isEditing) e.stopPropagation()
-      },
-      [isEditing]
-    )
-
-    React.useEffect(() => {
-      if (isEditing) {
-        requestAnimationFrame(() => {
-          rIsMounted.current = true
-          const elm = rInput.current
-          if (elm) {
-            elm.focus()
-            elm.select()
-          }
-        })
-      }
-    }, [isEditing, onEditingEnd])
-
-    React.useLayoutEffect(() => {
-      if (this.props.size[0] === 0 || this.props.size[1] === 0) {
-        this.onResetBounds()
-      }
-    }, [])
-
-    return (
-      <HTMLContainer {...events} opacity={isErasing ? 0.2 : opacity}>
-        <div
-          ref={rInnerWrapper}
-          className="tl-text-shape-wrapper"
-          data-hastext={!!text}
-          data-isediting={isEditing}
-          style={{
-            fontFamily,
-            fontStyle: italic ? 'italic' : 'normal',
-            fontSize,
-            fontWeight,
-            padding,
-            lineHeight,
-            color: getComputedColor(stroke, 'text'),
-          }}
-        >
-          {isEditing ? (
-            <textarea
-              ref={rInput}
-              className="tl-text-shape-input"
-              name="text"
-              tabIndex={-1}
-              autoComplete="false"
-              autoCapitalize="false"
-              autoCorrect="false"
-              autoSave="false"
-              // autoFocus
-              placeholder=""
-              spellCheck="true"
-              wrap="off"
-              dir="auto"
-              datatype="wysiwyg"
-              defaultValue={text}
-              onFocus={handleFocus}
-              onChange={handleChange}
-              onKeyDown={handleKeyDown}
-              onBlur={handleBlur}
-              onPointerDown={handlePointerDown}
-              // onContextMenu={stopPropagation}
-            />
-          ) : (
-            <>{text}&#8203;</>
-          )}
-        </div>
-      </HTMLContainer>
-    )
-  })
-
-  @computed get scaleLevel() {
-    return this.props.scaleLevel ?? 'md'
-  }
-
-  @action setScaleLevel = async (v?: SizeLevel) => {
-    this.update({
-      scaleLevel: v,
-      fontSize: levelToScale[v ?? 'md'],
-    })
-    this.onResetBounds()
-  }
-
-  ReactIndicator = observer(({ isEditing }: TLComponentProps) => {
-    const {
-      props: { borderRadius, isLocked },
-      bounds,
-    } = this
-    return isEditing ? null : (
-      <rect
-        width={bounds.width}
-        height={bounds.height}
-        rx={borderRadius}
-        ry={borderRadius}
-        fill="transparent"
-        strokeDasharray={isLocked ? '8 2' : 'undefined'}
-      />
-    )
-  })
-
-  validateProps = (props: Partial<TextShapeProps>) => {
-    if (props.isSizeLocked || this.props.isSizeLocked) {
-      // props.size = this.getAutoSizedBoundingBox(props)
-    }
-    return withClampedStyles(this, props)
-  }
-
-  getAutoSizedBoundingBox(props = {} as Partial<TextShapeProps>) {
-    const {
-      text = this.props.text,
-      fontFamily = this.props.fontFamily,
-      fontSize = this.props.fontSize,
-      fontWeight = this.props.fontWeight,
-      lineHeight = this.props.lineHeight,
-      padding = this.props.padding,
-    } = props
-    const [width, height] = getTextLabelSize(
-      text,
-      { fontFamily, fontSize, lineHeight, fontWeight },
-      padding
-    )
-    return [width, height]
-  }
-
-  getBounds = (): TLBounds => {
-    const [x, y] = this.props.point
-    const [width, height] = this.props.size
-    return {
-      minX: x,
-      minY: y,
-      maxX: x + width,
-      maxY: y + height,
-      width,
-      height,
-    }
-  }
-
-  onResizeStart = ({ isSingle }: TLResizeStartInfo) => {
-    if (!isSingle) return this
-    this.scale = [...(this.props.scale ?? [1, 1])]
-    return this.update({
-      isSizeLocked: false,
-    })
-  }
-
-  onResetBounds = () => {
-    this.update({
-      size: this.getAutoSizedBoundingBox(),
-      isSizeLocked: true,
-    })
-    return this
-  }
-
-  getShapeSVGJsx() {
-    if (isSafari()) {
-      // Safari doesn't support foreignObject well
-      return super.getShapeSVGJsx(null)
-    }
-    const {
-      props: { text, stroke, fontSize, fontFamily },
-    } = this
-    // Stretch to the bound size
-    const bounds = this.getBounds()
-
-    return (
-      <foreignObject width={bounds.width} height={bounds.height}>
-        <div
-          style={{
-            color: getComputedColor(stroke, 'text'),
-            fontSize,
-            fontFamily,
-            display: 'contents',
-          }}
-        >
-          {text}
-        </div>
-      </foreignObject>
-    )
-  }
-}

+ 0 - 227
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/TweetShape.tsx

@@ -1,227 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import { TLBoxShape, TLBoxShapeProps, TLResizeInfo, TLResetBoundsInfo } from '@tldraw/core'
-import { HTMLContainer, TLComponentProps, useApp } from '@tldraw/react'
-import Vec from '@tldraw/vec'
-import { action, computed } from 'mobx'
-import { observer } from 'mobx-react-lite'
-import { withClampedStyles } from './style-props'
-import { LogseqContext } from '../logseq-context'
-import * as React from 'react'
-
-// https://regex101.com/r/cazpoJ/2
-export const X_OR_TWITTER_REGEX = /https?:\/\/(x|twitter).com\/[0-9a-zA-Z_]{1,20}\/status\/([0-9]*)/
-
-export interface TweetShapeProps extends TLBoxShapeProps {
-  type: 'tweet'
-  url: string
-}
-
-export class TweetShape extends TLBoxShape<TweetShapeProps> {
-  static id = 'tweet'
-
-  static defaultProps: TweetShapeProps = {
-    id: 'tweet',
-    type: 'tweet',
-    parentId: 'page',
-    point: [0, 0],
-    size: [331, 290],
-    url: '',
-  }
-
-  canFlip = false
-  canEdit = true
-  initialHeightCalculated = true
-  getInnerHeight: (() => number) | null = null // will be overridden in the hook
-
-  @computed get embedId() {
-    const url = this.props.url
-    const match = url.match(X_OR_TWITTER_REGEX)
-    const embedId = match?.[1] ?? url ?? ''
-    return embedId
-  }
-
-  @action onTwitterLinkChange = (url: string) => {
-    this.update({ url, size: TweetShape.defaultProps.size })
-  }
-
-  ReactComponent = observer(({ events, isErasing, isEditing, isSelected }: TLComponentProps) => {
-    const {
-      renderers: { Tweet },
-    } = React.useContext(LogseqContext)
-    const app = useApp<Shape>()
-
-    const cpRefContainer = React.useRef<HTMLDivElement>(null)
-
-    const [, innerHeight] = this.useComponentSize(cpRefContainer)
-
-    React.useEffect(() => {
-      const latestInnerHeight = this.getInnerHeight?.() ?? innerHeight
-      const newHeight = latestInnerHeight
-      if (innerHeight && Math.abs(newHeight - this.props.size[1]) > 1) {
-        this.update({
-          size: [this.props.size[0], newHeight],
-        })
-        app.persist()
-      }
-    }, [innerHeight])
-
-    React.useEffect(() => {
-      if (!this.initialHeightCalculated) {
-        setTimeout(() => {
-          this.onResetBounds()
-          app.persist()
-        })
-      }
-    }, [this.initialHeightCalculated])
-
-    return (
-      <HTMLContainer
-        style={{
-          overflow: 'hidden',
-          pointerEvents: 'all',
-          opacity: isErasing ? 0.2 : 1,
-        }}
-        {...events}
-      >
-        <div
-          className="rounded-xl w-full h-full relative shadow-xl tl-tweet-container"
-          style={{
-            pointerEvents: isEditing || app.readOnly ? 'all' : 'none',
-            userSelect: 'none',
-          }}
-        >
-          {this.embedId ? (
-            <div ref={cpRefContainer}>
-              <Tweet tweetId={this.embedId} />
-            </div>
-          ) : null}
-        </div>
-      </HTMLContainer>
-    )
-  })
-
-  ReactIndicator = observer(() => {
-    const {
-      props: {
-        size: [w, h],
-        isLocked,
-      },
-    } = this
-    return (
-      <rect
-        width={w}
-        height={h}
-        fill="transparent"
-        rx={8}
-        ry={8}
-        strokeDasharray={isLocked ? '8 2' : 'undefined'}
-      />
-    )
-  })
-
-  useComponentSize<T extends HTMLElement>(ref: React.RefObject<T> | null, selector = '') {
-    const [size, setSize] = React.useState<[number, number]>([0, 0])
-    const app = useApp<Shape>()
-    React.useEffect(() => {
-      if (ref?.current) {
-        const el = selector ? ref.current.querySelector<HTMLElement>(selector) : ref.current
-        if (el) {
-          const updateSize = () => {
-            const { width, height } = el.getBoundingClientRect()
-            const bound = Vec.div([width, height], app.viewport.camera.zoom) as [number, number]
-            setSize(bound)
-            return bound
-          }
-          updateSize()
-          this.getInnerHeight = () => updateSize()[1]
-          const resizeObserver = new ResizeObserver(() => {
-            updateSize()
-          })
-          resizeObserver.observe(el)
-          return () => {
-            resizeObserver.disconnect()
-          }
-        }
-      }
-      return () => {}
-    }, [ref, selector])
-    return size
-  }
-
-  getAutoResizeHeight() {
-    if (this.getInnerHeight) {
-      return this.getInnerHeight()
-    }
-    return null
-  }
-
-  onResetBounds = (info?: TLResetBoundsInfo) => {
-    const height = this.getAutoResizeHeight()
-    if (height !== null && Math.abs(height - this.props.size[1]) > 1) {
-      this.update({
-        size: [this.props.size[0], height],
-      })
-      this.initialHeightCalculated = true
-    }
-    return this
-  }
-
-  onResize = (initialProps: any, info: TLResizeInfo): this => {
-    const {
-      bounds,
-      rotation,
-      scale: [scaleX, scaleY],
-    } = info
-    const nextScale = [...this.scale]
-    if (scaleX < 0) nextScale[0] *= -1
-    if (scaleY < 0) nextScale[1] *= -1
-
-    const height = this.getAutoResizeHeight() ?? bounds.height
-
-    return this.update({
-      point: [bounds.minX, bounds.minY],
-      size: [Math.max(1, bounds.width), Math.max(1, height)],
-      scale: nextScale,
-      rotation,
-    })
-  }
-
-  validateProps = (props: Partial<TweetShapeProps>) => {
-    if (props.size !== undefined) {
-      props.size[0] = Math.min(Math.max(props.size[0], 300), 550)
-      props.size[1] = Math.max(props.size[1], 1)
-    }
-    return withClampedStyles(this, props)
-  }
-
-  getShapeSVGJsx() {
-    // Do not need to consider the original point here
-    const bounds = this.getBounds()
-    const embedId = this.embedId
-
-    if (embedId) {
-      return (
-        <g>
-          <rect width={bounds.width} height={bounds.height} fill="#15202b" rx={8} ry={8} />
-          <svg
-            x={bounds.width / 4}
-            y={bounds.height / 4}
-            width={bounds.width / 2}
-            height={bounds.height / 2}
-            viewBox="0 0 15 15"
-            fill="none"
-            xmlns="http://www.w3.org/2000/svg"
-          >
-            <path
-              d="m13.464 4.4401c0.0091 0.13224 0.0091 0.26447 0.0091 0.39793 0 4.0664-3.0957 8.7562-8.7562 8.7562v-0.0024c-1.6721 0.0024-3.3095-0.47658-4.7172-1.3797 0.24314 0.02925 0.48751 0.04387 0.73248 0.04448 1.3857 0.0013 2.7319-0.46374 3.8221-1.3199-1.3169-0.024981-2.4717-0.8836-2.8751-2.1371 0.4613 0.08897 0.93662 0.070688 1.3894-0.053016-1.4357-0.29007-2.4686-1.5515-2.4686-3.0165v-0.039001c0.42779 0.23827 0.90676 0.37051 1.3967 0.38513-1.3522-0.90372-1.769-2.7026-0.95247-4.1091 1.5625 1.9226 3.8678 3.0914 6.3425 3.2151-0.24802-1.0689 0.090798-2.1889 0.89031-2.9403 1.2395-1.1651 3.1889-1.1054 4.3541 0.13346 0.68921-0.13589 1.3498-0.38879 1.9543-0.74711-0.22974 0.71237-0.71054 1.3175-1.3528 1.702 0.60999-0.071907 1.206-0.23522 1.7672-0.48446-0.41316 0.61913-0.93358 1.1584-1.5356 1.5942z"
-              fill="#1d9bf0"
-              fillRule="evenodd"
-              clipRule="evenodd"
-            ></path>
-          </svg>
-        </g>
-      )
-    }
-    return super.getShapeSVGJsx({})
-  }
-}

+ 0 - 105
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/VideoShape.tsx

@@ -1,105 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import { TLBoxShape, TLBoxShapeProps } from '@tldraw/core'
-import { HTMLContainer, TLComponentProps, useApp } from '@tldraw/react'
-import { observer } from 'mobx-react-lite'
-import * as React from 'react'
-import type { Shape } from '.'
-import { useCameraMovingRef } from '../../hooks/useCameraMoving'
-import { LogseqContext } from '../logseq-context'
-
-export interface VideoShapeProps extends TLBoxShapeProps {
-  type: 'video'
-  assetId: string
-  opacity: number
-}
-
-export class VideoShape extends TLBoxShape<VideoShapeProps> {
-  static id = 'video'
-
-  static defaultProps: VideoShapeProps = {
-    id: 'video1',
-    parentId: 'page',
-    type: 'video',
-    point: [0, 0],
-    size: [100, 100],
-    opacity: 1,
-    assetId: '',
-    clipping: 0,
-    isAspectRatioLocked: true,
-  }
-
-  canFlip = false
-  canEdit = true
-  canChangeAspectRatio = false
-
-  ReactComponent = observer(({ events, isErasing, asset, isEditing }: TLComponentProps) => {
-    const {
-      props: {
-        opacity,
-        size: [w, h],
-      },
-    } = this
-
-    const isMoving = useCameraMovingRef()
-    const app = useApp<Shape>()
-
-    const isSelected = app.selectedIds.has(this.id)
-
-    const tlEventsEnabled =
-      isMoving || (isSelected && !isEditing) || app.selectedTool.id !== 'select'
-    const stop = React.useCallback(
-      e => {
-        if (!tlEventsEnabled) {
-          // TODO: pinching inside Logseq Shape issue
-          e.stopPropagation()
-        }
-      },
-      [tlEventsEnabled]
-    )
-
-    const { handlers } = React.useContext(LogseqContext)
-
-    return (
-      <HTMLContainer
-        style={{
-          overflow: 'hidden',
-          pointerEvents: 'all',
-          opacity: isErasing ? 0.2 : opacity,
-        }}
-        {...events}
-      >
-        <div
-          onWheelCapture={stop}
-          onPointerDown={stop}
-          onPointerUp={stop}
-          className="tl-video-container"
-          style={{
-            pointerEvents: !isMoving && (isEditing || isSelected) ? 'all' : 'none',
-            overflow: isEditing ? 'auto' : 'hidden',
-          }}
-        >
-          {asset && (
-            <video controls src={handlers ? handlers.makeAssetUrl(asset.src) : asset.src} />
-          )}
-        </div>
-      </HTMLContainer>
-    )
-  })
-
-  ReactIndicator = observer(() => {
-    const {
-      props: {
-        size: [w, h],
-        isLocked,
-      },
-    } = this
-    return (
-      <rect
-        width={w}
-        height={h}
-        fill="transparent"
-        strokeDasharray={isLocked ? '8 2' : 'undefined'}
-      />
-    )
-  })
-}

+ 0 - 182
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/YouTubeShape.tsx

@@ -1,182 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import { TLBoxShape, TLBoxShapeProps } from '@tldraw/core'
-import { HTMLContainer, TLComponentProps, useApp} from '@tldraw/react'
-import { action, computed } from 'mobx'
-import { observer } from 'mobx-react-lite'
-import { withClampedStyles } from './style-props'
-
-export const YOUTUBE_REGEX =
-  /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/
-
-export interface YouTubeShapeProps extends TLBoxShapeProps {
-  type: 'youtube'
-  url: string
-}
-
-export class YouTubeShape extends TLBoxShape<YouTubeShapeProps> {
-  static id = 'youtube'
-
-  static defaultProps: YouTubeShapeProps = {
-    id: 'youtube',
-    type: 'youtube',
-    parentId: 'page',
-    point: [0, 0],
-    size: [853, 480],
-    url: '',
-  }
-
-  aspectRatio = 480 / 853
-
-  canChangeAspectRatio = false
-
-  canFlip = false
-
-  canEdit = true
-
-  @computed get embedId() {
-    const url = this.props.url
-    const match = url.match(YOUTUBE_REGEX)
-    const embedId = match?.[1] ?? url ?? ''
-    return embedId
-  }
-
-  @action onYoutubeLinkChange = (url: string) => {
-    this.update({ url, size: YouTubeShape.defaultProps.size })
-  }
-
-  ReactComponent = observer(({ events, isErasing, isEditing, isSelected }: TLComponentProps) => {
-    const app = useApp<Shape>()
-
-    return (
-      <HTMLContainer
-        style={{
-          overflow: 'hidden',
-          pointerEvents: 'all',
-          opacity: isErasing ? 0.2 : 1,
-        }}
-        {...events}
-      >
-        <div
-          className="rounded-lg w-full h-full relative overflow-hidden shadow-xl tl-youtube-container"
-          style={{
-            pointerEvents: isEditing || app.readOnly ? 'all' : 'none',
-            userSelect: 'none',
-            background: `url('https://img.youtube.com/vi/${this.embedId}/mqdefault.jpg') no-repeat center/cover`,
-          }}
-        >
-          {this.embedId ? (
-            <div
-              style={{
-                overflow: 'hidden',
-                position: 'relative',
-                height: '100%',
-              }}
-            >
-              <iframe
-                className="absolute inset-0 w-full h-full m-0"
-                width="853"
-                height="480"
-                src={`https://www.youtube.com/embed/${this.embedId}`}
-                frameBorder="0"
-                allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
-                allowFullScreen
-                title="Embedded youtube"
-              />
-            </div>
-          ) : (
-            <div
-              className="w-full h-full flex items-center justify-center p-4"
-              style={{
-                backgroundColor: 'var(--ls-primary-background-color)',
-              }}
-            >
-              <svg
-                xmlns="http://www.w3.org/2000/svg"
-                viewBox="0 0 502 210.649"
-                height="210.65"
-                width="128"
-              >
-                <g>
-                  <path
-                    d="M498.333 45.7s-2.91-20.443-11.846-29.447C475.157 4.44 462.452 4.38 456.627 3.687c-41.7-3-104.25-3-104.25-3h-.13s-62.555 0-104.255 3c-5.826.693-18.523.753-29.86 12.566-8.933 9.004-11.84 29.447-11.84 29.447s-2.983 24.003-2.983 48.009v22.507c0 24.006 2.983 48.013 2.983 48.013s2.907 20.44 11.84 29.446c11.337 11.817 26.23 11.44 32.86 12.677 23.84 2.28 101.315 2.983 101.315 2.983s62.62-.094 104.32-3.093c5.824-.694 18.527-.75 29.857-12.567 8.936-9.006 11.846-29.446 11.846-29.446s2.98-24.007 2.98-48.013V93.709c0-24.006-2.98-48.01-2.98-48.01"
-                    fill="#cd201f"
-                  />
-                  <g>
-                    <path d="M187.934 169.537h-18.96V158.56c-7.19 8.24-13.284 12.4-19.927 12.4-5.826 0-9.876-2.747-11.9-7.717-1.23-3.02-2.103-7.736-2.103-14.663V68.744h18.957v81.833c.443 2.796 1.636 3.823 4.043 3.823 3.63 0 6.913-3.153 10.93-8.817V68.744h18.96v100.793zM102.109 139.597c.996 9.98-2.1 14.93-7.987 14.93s-8.98-4.95-7.98-14.93v-39.92c-1-9.98 2.093-14.657 7.98-14.657 5.89 0 8.993 4.677 7.996 14.657l-.01 39.92zm18.96-37.923c0-10.77-2.164-18.86-5.987-23.95-5.054-6.897-12.973-9.72-20.96-9.72-9.033 0-15.913 2.823-20.957 9.72-3.886 5.09-5.97 13.266-5.97 24.036l-.016 35.84c0 10.71 1.853 18.11 5.736 23.153 5.047 6.873 13.227 10.513 21.207 10.513 7.986 0 16.306-3.64 21.36-10.513 3.823-5.043 5.586-12.443 5.586-23.153v-35.926zM46.223 114.647v54.889h-19.96v-54.89S5.582 47.358 1.314 34.815H22.27L36.277 87.38l13.936-52.566H71.17l-24.947 79.833z" />
-                  </g>
-                  <g fill="#fff">
-                    <path d="M440.413 96.647c0-9.33 2.557-11.874 8.59-11.874 5.99 0 8.374 2.777 8.374 11.997v10.893l-16.964.02V96.647zm35.96 25.986l-.003-20.4c0-10.656-2.1-18.456-5.88-23.5-5.06-6.823-12.253-10.436-21.317-10.436-9.226 0-16.42 3.613-21.643 10.436-3.84 5.044-6.076 13.28-6.076 23.943v34.927c0 10.596 2.46 18.013 6.296 23.003 5.227 6.813 12.42 10.216 21.87 10.216 9.44 0 16.853-3.566 21.85-10.81 2.2-3.196 3.616-6.82 4.226-10.823.164-1.81.64-5.933.64-11.753v-2.827h-18.96c0 7.247.037 11.557-.133 12.54-1.033 4.834-3.623 7.25-8.07 7.25-6.203 0-8.826-4.636-8.76-13.843v-17.923h35.96zM390.513 140.597c0 9.98-2.353 13.806-7.563 13.806-2.973 0-6.4-1.53-9.423-4.553l.02-60.523c3.02-2.98 6.43-4.55 9.403-4.55 5.21 0 7.563 2.93 7.563 12.91v42.91zm2.104-72.453c-6.647 0-13.253 4.087-19.09 11.27l.02-43.603h-17.963V169.54h17.963l.027-10.05c6.036 7.47 12.62 11.333 19.043 11.333 7.193 0 12.45-3.85 14.863-11.267 1.203-4.226 1.993-10.733 1.993-19.956V99.684c0-9.447-1.21-15.907-2.416-19.917-2.41-7.466-7.247-11.623-14.44-11.623M340.618 169.537h-18.956V158.56c-7.193 8.24-13.283 12.4-19.926 12.4-5.827 0-9.877-2.747-11.9-7.717-1.234-3.02-2.107-7.736-2.107-14.663V69.744h18.96v80.833c.443 2.796 1.633 3.823 4.043 3.823 3.63 0 6.913-3.153 10.93-8.817V69.744h18.957v99.793z" />
-                    <path d="M268.763 169.537h-19.956V54.77h-20.956V35.835l62.869-.024v18.96h-21.957v114.766z" />
-                  </g>
-                </g>
-              </svg>
-            </div>
-          )}
-        </div>
-      </HTMLContainer>
-    )
-  })
-
-  ReactIndicator = observer(() => {
-    const {
-      props: {
-        size: [w, h],
-        isLocked,
-      },
-    } = this
-    return (
-      <rect
-        width={w}
-        height={h}
-        fill="transparent"
-        rx={8}
-        ry={8}
-        strokeDasharray={isLocked ? '8 2' : 'undefined'}
-      />
-    )
-  })
-
-  validateProps = (props: Partial<YouTubeShapeProps>) => {
-    if (props.size !== undefined) {
-      props.size[0] = Math.max(props.size[0], 1)
-      props.size[1] = Math.max(props.size[0] * this.aspectRatio, 1)
-    }
-    return withClampedStyles(this, props)
-  }
-
-  getShapeSVGJsx() {
-    // Do not need to consider the original point here
-    const bounds = this.getBounds()
-    const embedId = this.embedId
-
-    if (embedId) {
-      return (
-        <g>
-          <image
-            width={bounds.width}
-            height={bounds.height}
-            href={`https://img.youtube.com/vi/${embedId}/mqdefault.jpg`}
-            className="grayscale-[50%]"
-          />
-          <svg
-            x={bounds.width / 4}
-            y={bounds.height / 4}
-            width={bounds.width / 2}
-            height={bounds.height / 2}
-            viewBox="0 0 15 15"
-            fill="none"
-            xmlns="http://www.w3.org/2000/svg"
-          >
-            <path
-              d="M4.76447 3.12199C5.63151 3.04859 6.56082 3 7.5 3C8.43918 3 9.36849 3.04859 10.2355 3.12199C11.2796 3.21037 11.9553 3.27008 12.472 3.39203C12.9425 3.50304 13.2048 3.64976 13.4306 3.88086C13.4553 3.90618 13.4902 3.94414 13.5133 3.97092C13.7126 4.20149 13.8435 4.4887 13.918 5.03283C13.9978 5.6156 14 6.37644 14 7.52493C14 8.66026 13.9978 9.41019 13.9181 9.98538C13.8439 10.5206 13.7137 10.8061 13.5125 11.0387C13.4896 11.0651 13.4541 11.1038 13.4296 11.1287C13.2009 11.3625 12.9406 11.5076 12.4818 11.6164C11.9752 11.7365 11.3143 11.7942 10.2878 11.8797C9.41948 11.9521 8.47566 12 7.5 12C6.52434 12 5.58052 11.9521 4.7122 11.8797C3.68572 11.7942 3.02477 11.7365 2.51816 11.6164C2.05936 11.5076 1.7991 11.3625 1.57037 11.1287C1.54593 11.1038 1.51035 11.0651 1.48748 11.0387C1.28628 10.8061 1.15612 10.5206 1.08193 9.98538C1.00221 9.41019 1 8.66026 1 7.52493C1 6.37644 1.00216 5.6156 1.082 5.03283C1.15654 4.4887 1.28744 4.20149 1.48666 3.97092C1.5098 3.94414 1.54468 3.90618 1.56942 3.88086C1.7952 3.64976 2.05752 3.50304 2.52796 3.39203C3.04473 3.27008 3.7204 3.21037 4.76447 3.12199ZM0 7.52493C0 5.28296 0 4.16198 0.729985 3.31713C0.766457 3.27491 0.815139 3.22194 0.854123 3.18204C1.63439 2.38339 2.64963 2.29744 4.68012 2.12555C5.56923 2.05028 6.52724 2 7.5 2C8.47276 2 9.43077 2.05028 10.3199 2.12555C12.3504 2.29744 13.3656 2.38339 14.1459 3.18204C14.1849 3.22194 14.2335 3.27491 14.27 3.31713C15 4.16198 15 5.28296 15 7.52493C15 9.74012 15 10.8477 14.2688 11.6929C14.2326 11.7348 14.1832 11.7885 14.1444 11.8281C13.3629 12.6269 12.3655 12.71 10.3709 12.8763C9.47971 12.9505 8.50782 13 7.5 13C6.49218 13 5.52028 12.9505 4.62915 12.8763C2.63446 12.71 1.63712 12.6269 0.855558 11.8281C0.816844 11.7885 0.767442 11.7348 0.731221 11.6929C0 10.8477 0 9.74012 0 7.52493ZM5.25 5.38264C5.25 5.20225 5.43522 5.08124 5.60041 5.15369L10.428 7.27105C10.6274 7.35853 10.6274 7.64147 10.428 7.72895L5.60041 9.84631C5.43522 9.91876 5.25 9.79775 5.25 9.61736V5.38264Z"
-              fill="#D10014"
-              fillRule="evenodd"
-              clipRule="evenodd"
-            ></path>
-          </svg>
-        </g>
-      )
-    }
-    return super.getShapeSVGJsx({})
-  }
-}

+ 0 - 87
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/arrow/Arrow.tsx

@@ -1,87 +0,0 @@
-import type { Decoration } from '@tldraw/core'
-import Vec from '@tldraw/vec'
-import * as React from 'react'
-import { Arrowhead } from './ArrowHead'
-import { getStraightArrowHeadPoints } from './arrowHelpers'
-import type { SizeLevel } from '../'
-
-interface ShapeStyles {
-  stroke: string
-  strokeWidth: number
-  strokeType: 'line' | 'dashed'
-  fill?: string
-}
-
-interface ArrowSvgProps {
-  style: ShapeStyles
-  start: number[]
-  end: number[]
-  decorationStart: Decoration | undefined
-  decorationEnd: Decoration | undefined
-  scaleLevel?: SizeLevel
-}
-
-const levelToScale = {
-  xs: 10,
-  sm: 16,
-  md: 20,
-  lg: 32,
-  xl: 48,
-  xxl: 60,
-}
-
-export const Arrow = React.memo(function StraightArrow({
-  style,
-  start,
-  end,
-  decorationStart,
-  decorationEnd,
-  scaleLevel,
-}: ArrowSvgProps) {
-  const arrowDist = Vec.dist(start, end)
-  if (arrowDist < 2) return null
-  const { strokeWidth } = style
-  const sw = 1 + (strokeWidth * levelToScale[scaleLevel ?? 'md']) / 10
-  // Path between start and end points
-  const path = 'M' + Vec.toFixed(start) + 'L' + Vec.toFixed(end)
-  // Arrowheads
-  const arrowHeadLength = Math.min(arrowDist / 3, strokeWidth * levelToScale[scaleLevel ?? 'md'])
-  const startArrowHead = decorationStart
-    ? getStraightArrowHeadPoints(start, end, arrowHeadLength)
-    : null
-  const endArrowHead = decorationEnd
-    ? getStraightArrowHeadPoints(end, start, arrowHeadLength)
-    : null
-  return (
-    <>
-      <path className="tl-stroke-hitarea" d={path} />
-      <path
-        d={path}
-        strokeWidth={sw}
-        stroke={style.stroke}
-        strokeLinecap="round"
-        strokeLinejoin="round"
-        strokeDasharray={style.strokeType === 'dashed' ? '8 4' : undefined}
-        pointerEvents="stroke"
-      />
-      {startArrowHead && (
-        <Arrowhead
-          left={startArrowHead.left}
-          middle={start}
-          right={startArrowHead.right}
-          stroke={style.stroke}
-          strokeWidth={sw}
-        />
-      )}
-      {endArrowHead && (
-        <Arrowhead
-          left={endArrowHead.left}
-          middle={end}
-          right={endArrowHead.right}
-          stroke={style.stroke}
-          strokeWidth={sw}
-        />
-      )}
-    </>
-  )
-})

+ 0 - 24
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/arrow/ArrowHead.tsx

@@ -1,24 +0,0 @@
-export interface ArrowheadProps {
-  left: number[]
-  middle: number[]
-  right: number[]
-  stroke: string
-  strokeWidth: number
-}
-
-export function Arrowhead({ left, middle, right, stroke, strokeWidth }: ArrowheadProps) {
-  return (
-    <g>
-      <path className="tl-stroke-hitarea" d={`M ${left} L ${middle} ${right}`} />
-      <path
-        d={`M ${left} L ${middle} ${right}`}
-        fill="none"
-        stroke={stroke}
-        strokeWidth={strokeWidth}
-        strokeLinecap="round"
-        strokeLinejoin="round"
-        pointerEvents="none"
-      />
-    </g>
-  )
-}

+ 0 - 59
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/arrow/arrowHelpers.ts

@@ -1,59 +0,0 @@
-import type { Decoration } from '@tldraw/core'
-import { intersectCircleLineSegment } from '@tldraw/intersect'
-import Vec from '@tldraw/vec'
-
-export function getArrowArcPath(start: number[], end: number[], circle: number[], bend: number) {
-  return [
-    'M',
-    start[0],
-    start[1],
-    'A',
-    circle[2],
-    circle[2],
-    0,
-    0,
-    bend < 0 ? 0 : 1,
-    end[0],
-    end[1],
-  ].join(' ')
-}
-
-export function getStraightArrowHeadPoints(A: number[], B: number[], r: number) {
-  const ints = intersectCircleLineSegment(A, r, A, B).points
-  if (!ints) {
-    console.warn('Could not find an intersection for the arrow head.')
-    return { left: A, right: A }
-  }
-  const int = ints[0]
-  const left = int ? Vec.rotWith(int, A, Math.PI / 6) : A
-  const right = int ? Vec.rotWith(int, A, -Math.PI / 6) : A
-  return { left, right }
-}
-
-export function getStraightArrowHeadPath(A: number[], B: number[], r: number) {
-  const { left, right } = getStraightArrowHeadPoints(A, B, r)
-  return `M ${left} L ${A} ${right}`
-}
-
-export function getArrowPath(
-  style: {
-    strokeWidth: number
-  },
-  start: number[],
-  end: number[],
-  decorationStart: Decoration | undefined,
-  decorationEnd: Decoration | undefined
-) {
-  const strokeWidth = style.strokeWidth
-  const arrowDist = Vec.dist(start, end)
-  const arrowHeadLength = Math.min(arrowDist / 3, strokeWidth * 16)
-  const path: (string | number)[] = []
-  path.push(`M ${start} L ${end}`)
-  if (decorationStart) {
-    path.push(getStraightArrowHeadPath(start, end, arrowHeadLength))
-  }
-  if (decorationEnd) {
-    path.push(getStraightArrowHeadPath(end, start, arrowHeadLength))
-  }
-  return path.join(' ')
-}

+ 0 - 49
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/arrow/constants.ts

@@ -1,49 +0,0 @@
-export type Easing =
-  | 'linear'
-  | 'easeInQuad'
-  | 'easeOutQuad'
-  | 'easeInOutQuad'
-  | 'easeInCubic'
-  | 'easeOutCubic'
-  | 'easeInOutCubic'
-  | 'easeInQuart'
-  | 'easeOutQuart'
-  | 'easeInOutQuart'
-  | 'easeInQuint'
-  | 'easeOutQuint'
-  | 'easeInOutQuint'
-  | 'easeInSine'
-  | 'easeOutSine'
-  | 'easeInOutSine'
-  | 'easeInExpo'
-  | 'easeOutExpo'
-  | 'easeInOutExpo'
-
-export const EASINGS: Record<Easing, (t: number) => number> = {
-  linear: t => t,
-  easeInQuad: t => t * t,
-  easeOutQuad: t => t * (2 - t),
-  easeInOutQuad: t => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t),
-  easeInCubic: t => t * t * t,
-  easeOutCubic: t => --t * t * t + 1,
-  easeInOutCubic: t => (t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1),
-  easeInQuart: t => t * t * t * t,
-  easeOutQuart: t => 1 - --t * t * t * t,
-  easeInOutQuart: t => (t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t),
-  easeInQuint: t => t * t * t * t * t,
-  easeOutQuint: t => 1 + --t * t * t * t * t,
-  easeInOutQuint: t => (t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t),
-  easeInSine: t => 1 - Math.cos((t * Math.PI) / 2),
-  easeOutSine: t => Math.sin((t * Math.PI) / 2),
-  easeInOutSine: t => -(Math.cos(Math.PI * t) - 1) / 2,
-  easeInExpo: t => (t <= 0 ? 0 : Math.pow(2, 10 * t - 10)),
-  easeOutExpo: t => (t >= 1 ? 1 : 1 - Math.pow(2, -10 * t)),
-  easeInOutExpo: t =>
-    t <= 0
-      ? 0
-      : t >= 1
-      ? 1
-      : t < 0.5
-      ? Math.pow(2, 20 * t - 10) / 2
-      : (2 - Math.pow(2, -20 * t + 10)) / 2,
-}

+ 0 - 76
packages/tldraw/apps/tldraw-logseq/src/lib/shapes/index.ts

@@ -1,76 +0,0 @@
-import type { TLReactShapeConstructor } from '@tldraw/react'
-import { BoxShape } from './BoxShape'
-import { EllipseShape } from './EllipseShape'
-import { GroupShape } from './GroupShape'
-import { HighlighterShape } from './HighlighterShape'
-import { HTMLShape } from './HTMLShape'
-import { IFrameShape } from './IFrameShape'
-import { ImageShape } from './ImageShape'
-import { LineShape } from './LineShape'
-import { LogseqPortalShape } from './LogseqPortalShape'
-import { PencilShape } from './PencilShape'
-import { PolygonShape } from './PolygonShape'
-import { TextShape } from './TextShape'
-import { VideoShape } from './VideoShape'
-import { YouTubeShape } from './YouTubeShape'
-import { TweetShape } from './TweetShape'
-import { PdfShape } from './PdfShape'
-
-export type Shape =
-  // | PenShape
-  // | DotShape
-  | BoxShape
-  | EllipseShape
-  | HighlighterShape
-  | ImageShape
-  | VideoShape
-  | LineShape
-  | PencilShape
-  | PolygonShape
-  | TextShape
-  | YouTubeShape
-  | TweetShape
-  | IFrameShape
-  | PdfShape
-  | HTMLShape
-  | LogseqPortalShape
-  | GroupShape
-
-export * from './BoxShape'
-export * from './DotShape'
-export * from './EllipseShape'
-export * from './HighlighterShape'
-export * from './HTMLShape'
-export * from './IFrameShape'
-export * from './ImageShape'
-export * from './LineShape'
-export * from './LogseqPortalShape'
-export * from './PencilShape'
-export * from './PolygonShape'
-export * from './TextShape'
-export * from './VideoShape'
-export * from './YouTubeShape'
-export * from './TweetShape'
-export * from './PdfShape'
-
-export const shapes: TLReactShapeConstructor<Shape>[] = [
-  // DotShape,
-  BoxShape,
-  EllipseShape,
-  HighlighterShape,
-  ImageShape,
-  VideoShape,
-  LineShape,
-  PencilShape,
-  PolygonShape,
-  TextShape,
-  YouTubeShape,
-  TweetShape,
-  IFrameShape,
-  HTMLShape,
-  PdfShape,
-  LogseqPortalShape,
-  GroupShape,
-]
-
-export type SizeLevel = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff