Browse Source

refactor: separate og and db version (#12276)

separate og and new version apps

remove file sync, tldraw, excalidraw and zotero
Tienson Qin 14 hours ago
parent
commit
bcc478b5f7
100 changed files with 105 additions and 6290 deletions
  1. 1 15
      .carve/ignore
  2. 1 2
      clj-e2e/test/logseq/e2e/plugins_basic_test.clj
  3. 3 4
      deps/cli/src/logseq/cli/common/graph.cljs
  4. 0 18
      deps/common/resources/templates/config.edn
  5. 1 1
      deps/common/src/logseq/common/config.cljs
  6. 1 1
      deps/common/src/logseq/common/graph.cljs
  7. 6 14
      deps/db/src/logseq/db/common/view.cljs
  8. 73 93
      deps/outliner/src/logseq/outliner/core.cljs
  9. 10 15
      deps/outliner/src/logseq/outliner/op.cljs
  10. 3 3
      deps/outliner/src/logseq/outliner/page.cljs
  11. 1 1
      deps/outliner/src/logseq/outliner/tree.cljs
  12. 2 2
      deps/outliner/test/logseq/outliner/core_test.cljs
  13. 1 1
      deps/publishing/src/logseq/publishing/export.cljs
  14. 0 4
      gulpfile.js
  15. 1 1
      ios/App/App/FsWatcher.swift
  16. 0 2
      libs/src/LSPlugin.ts
  17. 1 6
      package.json
  18. 0 19
      packages/tldraw/.editorconfig
  19. 0 3
      packages/tldraw/.eslintignore
  20. 0 19
      packages/tldraw/.eslintrc
  21. 0 2
      packages/tldraw/.gitattributes
  22. 0 17
      packages/tldraw/.gitignore
  23. 0 17
      packages/tldraw/.npmignore
  24. 0 11
      packages/tldraw/.prettierrc
  25. 0 21
      packages/tldraw/LICENSE.md
  26. 0 29
      packages/tldraw/README.md
  27. 0 3
      packages/tldraw/apps/tldraw-logseq/README.md
  28. 0 29
      packages/tldraw/apps/tldraw-logseq/build.mjs
  29. 0 42
      packages/tldraw/apps/tldraw-logseq/package.json
  30. 0 3
      packages/tldraw/apps/tldraw-logseq/postcss.config.js
  31. 0 148
      packages/tldraw/apps/tldraw-logseq/src/app.tsx
  32. 0 113
      packages/tldraw/apps/tldraw-logseq/src/components/ActionBar/ActionBar.tsx
  33. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/ActionBar/index.ts
  34. 0 20
      packages/tldraw/apps/tldraw-logseq/src/components/AppUI.tsx
  35. 0 71
      packages/tldraw/apps/tldraw-logseq/src/components/BlockLink/BlockLink.tsx
  36. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/BlockLink/index.ts
  37. 0 15
      packages/tldraw/apps/tldraw-logseq/src/components/Button/Button.tsx
  38. 0 26
      packages/tldraw/apps/tldraw-logseq/src/components/Button/CircleButton.tsx
  39. 0 2
      packages/tldraw/apps/tldraw-logseq/src/components/Button/index.ts
  40. 0 67
      packages/tldraw/apps/tldraw-logseq/src/components/ContextBar/ContextBar.tsx
  41. 0 560
      packages/tldraw/apps/tldraw-logseq/src/components/ContextBar/contextBarActionFactory.tsx
  42. 0 2
      packages/tldraw/apps/tldraw-logseq/src/components/ContextBar/index.ts
  43. 0 369
      packages/tldraw/apps/tldraw-logseq/src/components/ContextMenu/ContextMenu.tsx
  44. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/ContextMenu/index.ts
  45. 0 56
      packages/tldraw/apps/tldraw-logseq/src/components/Devtools/Devtools.tsx
  46. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/Devtools/index.ts
  47. 0 93
      packages/tldraw/apps/tldraw-logseq/src/components/GeometryTools/GeometryTools.tsx
  48. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/GeometryTools/index.ts
  49. 0 16
      packages/tldraw/apps/tldraw-logseq/src/components/KeyboardShortcut/KeyboardShortcut.tsx
  50. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/KeyboardShortcut/index.ts
  51. 0 55
      packages/tldraw/apps/tldraw-logseq/src/components/Minimap/Minimap.tsx
  52. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/Minimap/index.ts
  53. 0 39
      packages/tldraw/apps/tldraw-logseq/src/components/PopoverButton/PopoverButton.tsx
  54. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/PopoverButton/index.ts
  55. 0 103
      packages/tldraw/apps/tldraw-logseq/src/components/PrimaryTools/PrimaryTools.tsx
  56. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/PrimaryTools/index.ts
  57. 0 44
      packages/tldraw/apps/tldraw-logseq/src/components/QuickLinks/QuickLinks.tsx
  58. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/QuickLinks/index.ts
  59. 0 437
      packages/tldraw/apps/tldraw-logseq/src/components/QuickSearch/QuickSearch.tsx
  60. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/QuickSearch/index.ts
  61. 0 16
      packages/tldraw/apps/tldraw-logseq/src/components/StatusBar/StatusBar.tsx
  62. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/StatusBar/index.ts
  63. 0 50
      packages/tldraw/apps/tldraw-logseq/src/components/ToolButton/ToolButton.tsx
  64. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/ToolButton/index.ts
  65. 0 31
      packages/tldraw/apps/tldraw-logseq/src/components/Tooltip/Tooltip.tsx
  66. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/Tooltip/index.ts
  67. 0 65
      packages/tldraw/apps/tldraw-logseq/src/components/ZoomMenu/ZoomMenu.tsx
  68. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/ZoomMenu/index.ts
  69. 0 35
      packages/tldraw/apps/tldraw-logseq/src/components/icons/TablerIcon.tsx
  70. 0 1
      packages/tldraw/apps/tldraw-logseq/src/components/icons/index.ts
  71. 0 122
      packages/tldraw/apps/tldraw-logseq/src/components/inputs/ColorInput.tsx
  72. 0 12
      packages/tldraw/apps/tldraw-logseq/src/components/inputs/NumberInput.tsx
  73. 0 59
      packages/tldraw/apps/tldraw-logseq/src/components/inputs/ScaleInput.tsx
  74. 0 75
      packages/tldraw/apps/tldraw-logseq/src/components/inputs/SelectInput.tsx
  75. 0 162
      packages/tldraw/apps/tldraw-logseq/src/components/inputs/ShapeLinksInput.tsx
  76. 0 18
      packages/tldraw/apps/tldraw-logseq/src/components/inputs/TextInput.tsx
  77. 0 76
      packages/tldraw/apps/tldraw-logseq/src/components/inputs/ToggleGroupInput.tsx
  78. 0 34
      packages/tldraw/apps/tldraw-logseq/src/components/inputs/ToggleInput.tsx
  79. 0 6
      packages/tldraw/apps/tldraw-logseq/src/hooks/useCameraMoving.ts
  80. 0 11
      packages/tldraw/apps/tldraw-logseq/src/hooks/useCopy.ts
  81. 0 14
      packages/tldraw/apps/tldraw-logseq/src/hooks/useDrop.ts
  82. 0 515
      packages/tldraw/apps/tldraw-logseq/src/hooks/usePaste.ts
  83. 0 12
      packages/tldraw/apps/tldraw-logseq/src/hooks/useQuickAdd.ts
  84. 0 18
      packages/tldraw/apps/tldraw-logseq/src/index.ts
  85. 0 3
      packages/tldraw/apps/tldraw-logseq/src/lib/index.ts
  86. 0 70
      packages/tldraw/apps/tldraw-logseq/src/lib/logseq-context.ts
  87. 0 148
      packages/tldraw/apps/tldraw-logseq/src/lib/preview-manager.tsx
  88. 0 32
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/BindingIndicator.tsx
  89. 0 195
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/BoxShape.tsx
  90. 0 62
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/DotShape.tsx
  91. 0 223
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/EllipseShape.tsx
  92. 0 65
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/GroupShape.tsx
  93. 0 159
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/HTMLShape.tsx
  94. 0 116
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/HighlighterShape.tsx
  95. 0 100
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/IFrameShape.tsx
  96. 0 119
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/ImageShape.tsx
  97. 0 252
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/LineShape.tsx
  98. 0 605
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/LogseqPortalShape.tsx
  99. 0 83
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/PdfShape.tsx
  100. 0 77
      packages/tldraw/apps/tldraw-logseq/src/lib/shapes/PenShape.tsx

+ 1 - 15
.carve/ignore

@@ -11,29 +11,15 @@ frontend.debug/defn
 frontend.debug/print
 ;; Lazily loaded
 frontend.extensions.code/editor
-;; Lazily loaded
-frontend.extensions.age-encryption/keygen
-frontend.extensions.age-encryption/encrypt-with-x25519
-frontend.extensions.age-encryption/decrypt-with-x25519
-frontend.extensions.age-encryption/encrypt-with-user-passphrase
-frontend.extensions.age-encryption/decrypt-with-user-passphrase
-;; Lazily loaded
-frontend.extensions.excalidraw/draw
-;; Lazily loaded
-frontend.extensions.tldraw/tldraw-app
-frontend.extensions.tldraw/generate-preview
 ;; Referenced in commented TODO
 frontend.extensions.pdf.utils/get-page-bounding
 ;; For repl
-frontend.extensions.zotero.api/item
-;; For repl
-frontend.external.roam/reset-state!
-;; For repl
 logseq.graph-parser.mldoc/ast-export-markdown
 ;; Protocol fn wrapper that could be used
 frontend.fs/readdir
 ;; Referenced in TODO
 frontend.handler.metadata/update-properties!
+frontend.handler.user/<ensure-id&access-token
 ;; Referenced in comment
 frontend.image/get-orientation
 ;; For debugging

+ 1 - 2
clj-e2e/test/logseq/e2e/plugins_basic_test.clj

@@ -361,8 +361,7 @@
       (is (= (get tag1 ":logseq.property.class/extends") [id2]) "tag1 extends tag2 with db id")
       (let [_ (ls-api-call! :editor.addTagExtends id1 id3)
             tag1 (ls-api-call! :editor.getTag id1)]
-        (is (= (get tag1 ":logseq.property.class/extends") [id2 id3]) "tag1 extends tag2,tag3 with db ids"))
-      )))
+        (is (= (get tag1 ":logseq.property.class/extends") [id2 id3]) "tag1 extends tag2,tag3 with db ids")))))
 
 (deftest get-tags-by-name-test
   (testing "get tags by exact name"

+ 3 - 4
deps/cli/src/logseq/cli/common/graph.cljs

@@ -26,7 +26,6 @@
     (->> (common-graph/read-directories dir)
          (remove (fn [s] (= s common-config/unlinked-graphs-dir)))
          (map graph-name->path)
-         (map (fn [s]
-                (if (string/starts-with? s common-config/file-version-prefix)
-                  s
-                  (str common-config/db-version-prefix s)))))))
+         (keep (fn [s]
+                 (when-not (string/starts-with? s common-config/file-version-prefix)
+                   (str common-config/db-version-prefix s)))))))

+ 0 - 18
deps/common/resources/templates/config.edn

@@ -116,11 +116,6 @@
  ;;  :enabled-in-timestamped-blocks false ;don't display logbook at all
  ;; }
 
- ;; File sync options
- ;; Ignore these files when syncing, regexp is supported.
- ;; This is _only_ for file graphs.
- ;; :file-sync/ignore-files []
-
  ;; Configure the escaping method for special characters in page titles.
  ;; This is _only_ for file graphs.
  ;; Warning:
@@ -391,17 +386,4 @@
  ;;  :redirect-page? false          ;; Default value: false
  ;;  :default-page "quick capture"} ;; Default page: "quick capture"
 
- ;; Configure the Enter key behavior for
- ;; context-aware editing with DWIM (Do What I Mean).
- ;; context-aware Enter key behavior implies that pressing Enter will
- ;; have different outcomes based on the context.
- ;; For instance, pressing Enter within a list generates a new list item,
- ;; whereas pressing Enter in a block reference opens the referenced block.
- ;; :dwim/settings
- ;; {:admonition&src?  true        ;; Default value: true
- ;;  :markup?          false       ;; Default value: false
- ;;  :block-ref?       true        ;; Default value: true
- ;;  :page-ref?        true        ;; Default value: true
- ;;  :properties?      true        ;; Default value: true
- ;;  :list?            false}      ;; Default value: false
  }

+ 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]

+ 6 - 14
deps/db/src/logseq/db/common/view.cljs

@@ -290,16 +290,12 @@
    (map :e)
    set))
 
-(defn- get-entities-for-all-pages [db sorting property-ident {:keys [db-based?]}]
+(defn- get-entities-for-all-pages [db sorting property-ident]
   (let [refs-count? (and (coll? sorting) (some (fn [m] (= (:id m) :block.temp/refs-count)) sorting))
-        exclude-ids (when db-based? (get-exclude-page-ids db))]
+        exclude-ids (get-exclude-page-ids db)]
     (keep (fn [d]
             (let [e (entity-plus/unsafe->Entity db (:e d))]
-              (when-not (if db-based?
-                          (exclude-ids (:db/id e))
-                          (or (ldb/hidden-or-internal-tag? e)
-                              (entity-util/property? e)
-                              (entity-util/built-in? e)))
+              (when-not (exclude-ids (:db/id e))
                 (cond-> e
                   refs-count?
                   (assoc :block.temp/refs-count (common-initial-data/get-block-refs-count db (:e d)))))))
@@ -311,11 +307,10 @@
         view-for-id (or (:db/id view-for) view-for-id*)
         non-hidden-e (fn [id] (let [e (d/entity db id)]
                                 (when-not (entity-util/hidden? e)
-                                  e)))
-        db-based? (entity-plus/db-based-graph? db)]
+                                  e)))]
     (case feat-type
       :all-pages
-      (get-entities-for-all-pages db sorting property-ident {:db-based? db-based?})
+      (get-entities-for-all-pages db sorting property-ident)
 
       :class-objects
       (db-class/get-class-objects db view-for-id)
@@ -443,10 +438,7 @@
     :else
     (let [view (d/entity db view-id)
           group-by-property (:logseq.property.view/group-by-property view)
-          db-based? (entity-plus/db-based-graph? db)
-          list-view? (or (= :logseq.property.view/type.list (:db/ident (:logseq.property.view/type view)))
-                         (and (not db-based?)
-                              (contains? #{:linked-references :unlinked-references} view-feature-type)))
+          list-view? (= :logseq.property.view/type.list (:db/ident (:logseq.property.view/type view)))
           group-by-property-ident (or (:db/ident group-by-property) group-by-property-ident)
           group-by-closed-values? (some? (:property/closed-values group-by-property))
           ref-property? (= (:db/valueType group-by-property) :db.type/ref)

+ 73 - 93
deps/outliner/src/logseq/outliner/core.cljs

@@ -12,14 +12,12 @@
             [logseq.db :as ldb]
             [logseq.db.common.entity-plus :as entity-plus]
             [logseq.db.common.order :as db-order]
-            [logseq.db.file-based.schema :as file-schema]
             [logseq.db.frontend.class :as db-class]
             [logseq.db.frontend.schema :as db-schema]
             [logseq.db.sqlite.create-graph :as sqlite-create-graph]
             [logseq.db.sqlite.util :as sqlite-util]
             [logseq.graph-parser.block :as gp-block]
             [logseq.graph-parser.db :as gp-db]
-            [logseq.graph-parser.property :as gp-property]
             [logseq.outliner.batch-tx :include-macros true :as batch-tx]
             [logseq.outliner.datascript :as ds]
             [logseq.outliner.pipeline :as outliner-pipeline]
@@ -28,8 +26,6 @@
             [malli.core :as m]
             [malli.util :as mu]))
 
-;; TODO: remove `repo` usage, use db to check `entity-plus/db-based-graph?`
-
 (def ^:private block-map
   (mu/optional-keys
    [:map
@@ -299,25 +295,23 @@
 
 (extend-type Entity
   otree/INode
-  (-save [this *txs-state db repo _date-formatter {:keys [retract-attributes? retract-attributes outliner-op]
-                                                   :or {retract-attributes? true}}]
+  (-save [this *txs-state db {:keys [retract-attributes? retract-attributes outliner-op]
+                              :or {retract-attributes? true}}]
     (assert (ds/outliner-txs-state? *txs-state)
             "db should be satisfied outliner-tx-state?")
-    (let [db-based? (sqlite-util/db-based-graph? repo)
+    (let [db-graph? (entity-plus/db-based-graph? db)
           data (if (de/entity? this)
                  (assoc (.-kv ^js this) :db/id (:db/id this))
                  this)
-          data' (if db-based?
-                  (->> (dissoc data :block/properties)
-                       (remove-disallowed-inline-classes db))
-                  data)
+          data' (->> (dissoc data :block/properties)
+                     (remove-disallowed-inline-classes db))
           collapse-or-expand? (= outliner-op :collapse-expand-blocks)
           m* (cond->
               (-> data'
                   (dissoc :block/children :block/meta :block/unordered
                           :block.temp/ast-title :block.temp/ast-body :block/level :block.temp/load-status
                           :block.temp/has-children?)
-                  (fix-tag-ids db {:db-graph? db-based?}))
+                  (fix-tag-ids db {:db-graph? db-graph?}))
                (not collapse-or-expand?)
                block-with-updated-at)
           db-id (:db/id this)
@@ -325,28 +319,27 @@
           eid (or db-id (when block-uuid [:block/uuid block-uuid]))
           block-entity (d/entity db eid)
           page? (ldb/page? block-entity)
-          m* (if (and db-based? (:block/title m*)
+          m* (if (and (:block/title m*)
                       (not (:logseq.property.node/display-type block-entity)))
                (update m* :block/title common-util/clear-markdown-heading)
                m*)
           block-title (:block/title m*)
           page-title-changed? (and page? block-title
                                    (not= block-title (:block/title block-entity)))
-          _ (when (and db-based? page? block-title)
+          _ (when (and page? block-title)
               (outliner-validate/validate-page-title-characters block-title {:node m*}))
-          m* (if (and db-based? page-title-changed?)
+          m* (if page-title-changed?
                (let [_ (outliner-validate/validate-page-title (:block/title m*) {:node m*})
                      page-name (common-util/page-name-sanity-lc (:block/title m*))]
                  (assoc m* :block/name page-name))
                m*)
-          _ (when (and db-based?
-                       ;; page or object changed?
-                       (or (ldb/page? block-entity) (ldb/object? block-entity))
-                       (:block/title m*)
-                       (not= (:block/title m*) (:block/title block-entity)))
+          _ (when (and ;; page or object changed?
+                   (or (ldb/page? block-entity) (ldb/object? block-entity))
+                   (:block/title m*)
+                   (not= (:block/title m*) (:block/title block-entity)))
               (outliner-validate/validate-block-title db (:block/title m*) block-entity))
           m (cond-> m*
-              db-based?
+              true
               (dissoc :block/format :block/pre-block? :block/priority :block/marker :block/properties-order))]
       ;; Ensure block UUID never changes
       (let [e (d/entity db db-id)]
@@ -361,9 +354,7 @@
         (when (or (and retract-attributes? (:block/title m))
                   (seq retract-attributes))
           (let [retract-attributes (concat
-                                    (if db-based?
-                                      db-schema/retract-attributes
-                                      file-schema/retract-attributes)
+                                    db-schema/retract-attributes
                                     retract-attributes)]
             (swap! *txs-state (fn [txs]
                                 (vec
@@ -377,7 +368,7 @@
           (update-page-when-save-block *txs-state block-entity m))
         ;; Remove orphaned refs from block
         (when (and (:block/title m) (not= (:block/title m) (:block/title block-entity)))
-          (remove-orphaned-refs-when-save db *txs-state block-entity m {:db-graph? db-based?})))
+          (remove-orphaned-refs-when-save db *txs-state block-entity m {:db-graph? db-graph?})))
 
       ;; handle others txs
       (let [other-tx (:db/other-tx m)]
@@ -387,16 +378,15 @@
         (swap! *txs-state conj
                (dissoc m :db/other-tx)))
 
-      (when (and db-based? (:block/tags block-entity) block-entity)
+      (when (and (:block/tags block-entity) block-entity)
         (let [;; delete tags when title changed
               tx-data (remove-tags-when-title-changed block-entity (:block/title m))]
           (when (seq tx-data)
             (swap! *txs-state (fn [txs] (concat txs tx-data))))))
 
-      (when db-based?
-        (let [tx-data (add-missing-tag-idents db (:block/tags m))]
-          (when (seq tx-data)
-            (swap! *txs-state (fn [txs] (concat txs tx-data))))))
+      (let [tx-data (add-missing-tag-idents db (:block/tags m))]
+        (when (seq tx-data)
+          (swap! *txs-state (fn [txs] (concat txs tx-data)))))
 
       this))
 
@@ -519,7 +509,7 @@
 
 (defn ^:api save-block
   "Save the `block`."
-  [repo db date-formatter block opts]
+  [db block opts]
   {:pre [(map? block)]}
   (let [*txs-state (atom [])
         block' (if (de/entity? block)
@@ -530,7 +520,7 @@
                      (let [ent (d/entity db eid)]
                        (assert (some? ent) "save-block entity not exists")
                        (merge ent block)))))]
-    (otree/-save block' *txs-state db repo date-formatter opts)
+    (otree/-save block' *txs-state db opts)
     {:tx-data @*txs-state}))
 
 (defn- get-right-siblings
@@ -543,28 +533,19 @@
            rest))))
 
 (defn- blocks-with-ordered-list-props
-  [repo blocks target-block sibling?]
+  [blocks target-block sibling?]
   (let [target-block (if sibling? target-block (when target-block (ldb/get-down target-block)))
         list-type-fn (fn [block]
-                       (if (sqlite-util/db-based-graph? repo)
-                         ;; Get raw id since insert-blocks doesn't auto-handle raw property values
-                         (:db/id (:logseq.property/order-list-type block))
-                         (get (:block/properties block) :logseq.order-list-type)))
-        db-based? (sqlite-util/db-based-graph? repo)]
+                       (:db/id (:logseq.property/order-list-type block)))]
     (if-let [list-type (and target-block (list-type-fn target-block))]
       (mapv
-       (fn [{:block/keys [title format] :as block}]
+       (fn [block]
          (let [list?' (and (some? (:block/uuid block))
                            (nil? (list-type-fn block)))]
            (cond-> block
              list?'
              ((fn [b]
-                (if db-based?
-                  (assoc b :logseq.property/order-list-type list-type)
-                  (update b :block/properties assoc :logseq.order-list-type list-type))))
-
-             (not db-based?)
-             (assoc :block/title (gp-property/insert-property repo format title :logseq.order-list-type list-type)))))
+                (assoc b :logseq.property/order-list-type list-type))))))
        blocks)
       blocks)))
 
@@ -615,13 +596,12 @@
 
 (defn- build-insert-blocks-tx
   [db target-block blocks uuids get-new-id {:keys [sibling? outliner-op replace-empty-target? insert-template? keep-block-order?]}]
-  (let [db-based? (entity-plus/db-based-graph? db)
-        block-ids (set (map :block/uuid blocks))
+  (let [block-ids (set (map :block/uuid blocks))
         target-page (get-target-block-page target-block sibling?)
         orders (get-block-orders blocks target-block sibling? keep-block-order?)]
     (map-indexed (fn [idx {:block/keys [parent] :as block}]
                    (when-let [uuid' (get uuids (:block/uuid block))]
-                     (let [block (if db-based? (remove-disallowed-inline-classes db block) block)
+                     (let [block (remove-disallowed-inline-classes db block)
                            top-level? (= (:block/level block) 1)
                            parent (compute-block-parent block parent target-block top-level? sibling? get-new-id outliner-op replace-empty-target? idx)
 
@@ -790,11 +770,11 @@
                                to replace it, it defaults to be `false`.
       `update-timestamps?`: whether to update `blocks` timestamps.
     ``"
-  [repo db blocks target-block {:keys [_sibling? keep-uuid? keep-block-order?
-                                       outliner-op outliner-real-op replace-empty-target? update-timestamps?
-                                       insert-template?]
-                                :as opts
-                                :or {update-timestamps? true}}]
+  [db blocks target-block {:keys [_sibling? keep-uuid? keep-block-order?
+                                  outliner-op outliner-real-op replace-empty-target? update-timestamps?
+                                  insert-template?]
+                           :as opts
+                           :or {update-timestamps? true}}]
   {:pre [(seq blocks)
          (m/validate block-map-or-entity target-block)]}
   (let [blocks (cond->>
@@ -828,16 +808,15 @@
                                 (and sibling?
                                      (:block/title target-block)
                                      (string/blank? (:block/title target-block))
-                                     (> (count blocks) 1)))
-        db-based? (sqlite-util/db-based-graph? repo)]
+                                     (> (count blocks) 1)))]
     (when (seq blocks)
       (let [blocks' (let [blocks' (blocks-with-level blocks)]
-                      (cond->> (blocks-with-ordered-list-props repo blocks' target-block sibling?)
+                      (cond->> (blocks-with-ordered-list-props blocks' target-block sibling?)
                         update-timestamps?
                         (mapv #(dissoc % :block/created-at :block/updated-at))
                         true
                         (mapv block-with-timestamps)
-                        db-based?
+                        true
                         (mapv #(-> % (dissoc :block/properties)))))
             insert-opts {:sibling? sibling?
                          :replace-empty-target? replace-empty-target?
@@ -999,8 +978,8 @@
 
 (defn- move-blocks
   "Move `blocks` to `target-block` as siblings or children."
-  [_repo conn blocks target-block {:keys [_sibling? _top? _bottom? _up? outliner-op _indent?]
-                                   :as opts}]
+  [conn blocks target-block {:keys [_sibling? _top? _bottom? _up? outliner-op _indent?]
+                             :as opts}]
   {:pre [(seq blocks)
          (m/validate block-map-or-entity target-block)]}
   (let [db @conn
@@ -1039,7 +1018,7 @@
 
 (defn- move-blocks-up-down
   "Move blocks up/down."
-  [repo conn blocks up?]
+  [conn blocks up?]
   {:pre [(seq blocks) (boolean? up?)]}
   (let [db @conn
         top-level-blocks (filter-top-level-blocks db blocks)
@@ -1058,8 +1037,8 @@
                          (:db/id left-left))
                    (not (and (:logseq.property/created-from-property first-block)
                              (nil? first-block-left-sibling))))
-          (move-blocks repo conn top-level-blocks left-left (merge opts {:sibling? sibling?
-                                                                         :up? up?}))))
+          (move-blocks conn top-level-blocks left-left (merge opts {:sibling? sibling?
+                                                                    :up? up?}))))
 
       (let [last-top-block (last top-level-blocks)
             last-top-block-right (ldb/get-right-sibling last-top-block)
@@ -1072,12 +1051,12 @@
         (when (and right
                    (not (and (:logseq.property/created-from-property last-top-block)
                              (nil? last-top-block-right))))
-          (move-blocks repo conn blocks right (merge opts {:sibling? sibling?
-                                                           :up? up?})))))))
+          (move-blocks conn blocks right (merge opts {:sibling? sibling?
+                                                      :up? up?})))))))
 
 (defn- ^:large-vars/cleanup-todo indent-outdent-blocks
   "Indent or outdent `blocks`."
-  [repo conn blocks indent? & {:keys [parent-original logical-outdenting?]}]
+  [conn blocks indent? & {:keys [parent-original logical-outdenting?]}]
   {:pre [(seq blocks) (boolean? indent?)]}
   (let [db @conn
         top-level-blocks (filter-top-level-blocks db blocks)
@@ -1105,30 +1084,30 @@
               (when (seq blocks')
                 (if last-direct-child-id
                   (let [last-direct-child (d/entity db last-direct-child-id)
-                        result (move-blocks repo conn blocks' last-direct-child (merge opts {:sibling? true
-                                                                                             :indent? true}))
+                        result (move-blocks conn blocks' last-direct-child (merge opts {:sibling? true
+                                                                                        :indent? true}))
                         ;; expand `left` if it's collapsed
                         collapsed-tx (when (:block/collapsed? left)
                                        {:tx-data [{:db/id (:db/id left)
                                                    :block/collapsed? false}]})]
                     (concat-tx-fn result collapsed-tx))
-                  (move-blocks repo conn blocks' left (merge opts {:sibling? false
-                                                                   :indent? true}))))))
+                  (move-blocks conn blocks' left (merge opts {:sibling? false
+                                                              :indent? true}))))))
           (if parent-original
             (let [blocks' (take-while (fn [b]
                                         (not= (:db/id (:block/parent b))
                                               (:db/id (:block/parent parent))))
                                       top-level-blocks)]
-              (move-blocks repo conn blocks' parent-original (merge opts {:outliner-op :indent-outdent-blocks
-                                                                          :sibling? true
-                                                                          :indent? false})))
+              (move-blocks conn blocks' parent-original (merge opts {:outliner-op :indent-outdent-blocks
+                                                                     :sibling? true
+                                                                     :indent? false})))
 
             (when parent
               (let [blocks' (take-while (fn [b]
                                           (not= (:db/id (:block/parent b))
                                                 (:db/id (:block/parent parent))))
                                         top-level-blocks)
-                    result (move-blocks repo conn blocks' parent (merge opts {:sibling? true}))]
+                    result (move-blocks conn blocks' parent (merge opts {:sibling? true}))]
                 (if logical-outdenting?
                   result
                   ;; direct outdenting (default behavior)
@@ -1136,8 +1115,8 @@
                         right-siblings (get-right-siblings last-top-block)]
                     (if (seq right-siblings)
                       (if-let [last-direct-child-id (ldb/get-block-last-direct-child-id db (:db/id last-top-block))]
-                        (move-blocks repo conn right-siblings (d/entity db last-direct-child-id) (merge opts {:sibling? true}))
-                        (move-blocks repo conn right-siblings last-top-block (merge opts {:sibling? false})))
+                        (move-blocks conn right-siblings (d/entity db last-direct-child-id) (merge opts {:sibling? true}))
+                        (move-blocks conn right-siblings last-top-block (merge opts {:sibling? false})))
                       result)))))))))))
 
 ;;; ### write-operations have side-effects (do transactions) ;;;;;;;;;;;;;;;;
@@ -1150,44 +1129,45 @@
       (when result
         (let [tx-meta (assoc (:tx-meta result)
                              :outliner-op outliner-op)]
-          (ldb/transact! (second args) (:tx-data result) tx-meta)))
+          (ldb/transact! (first args) (:tx-data result) tx-meta)))
       result)
     (catch :default e
+      (js/console.error e)
       (when-not (= "not-allowed-move-block-page" (ex-message e))
         (throw e)))))
 
-(let [f (fn [repo conn date-formatter block opts]
-          (save-block repo @conn date-formatter block opts))]
+(let [f (fn [conn block opts]
+          (save-block @conn block opts))]
   (defn save-block!
-    [repo conn date-formatter block & {:as opts}]
-    (op-transact! :save-block f repo conn date-formatter block opts)))
+    [conn block & {:as opts}]
+    (op-transact! :save-block f conn block opts)))
 
-(let [f (fn [repo conn blocks target-block opts]
-          (insert-blocks repo @conn blocks target-block opts))]
+(let [f (fn [conn blocks target-block opts]
+          (insert-blocks @conn blocks target-block opts))]
   (defn insert-blocks!
-    [repo conn blocks target-block opts]
-    (op-transact! :insert-blocks f repo conn blocks target-block
+    [conn blocks target-block opts]
+    (op-transact! :insert-blocks f conn blocks target-block
                   (if (:outliner-op opts)
                     opts
                     (assoc opts :outliner-op :insert-blocks)))))
 
-(let [f (fn [_repo conn blocks _opts]
+(let [f (fn [conn blocks _opts]
           (delete-blocks @conn blocks))]
   (defn delete-blocks!
-    [repo conn _date-formatter blocks opts]
-    (op-transact! :delete-blocks f repo conn blocks opts)))
+    [conn blocks opts]
+    (op-transact! :delete-blocks f conn blocks opts)))
 
 (defn move-blocks!
-  [repo conn blocks target-block opts]
-  (op-transact! :move-blocks move-blocks repo conn blocks target-block
+  [conn blocks target-block opts]
+  (op-transact! :move-blocks move-blocks conn blocks target-block
                 (if (:outliner-op opts)
                   opts
                   (assoc opts :outliner-op :move-blocks))))
 
 (defn move-blocks-up-down!
-  [repo conn blocks up?]
-  (op-transact! :move-blocks-up-down move-blocks-up-down repo conn blocks up?))
+  [conn blocks up?]
+  (op-transact! :move-blocks-up-down move-blocks-up-down conn blocks up?))
 
 (defn indent-outdent-blocks!
-  [repo conn blocks indent? & {:as opts}]
-  (op-transact! :indent-outdent-blocks indent-outdent-blocks repo conn blocks indent? opts))
+  [conn blocks indent? & {:as opts}]
+  (op-transact! :indent-outdent-blocks indent-outdent-blocks conn blocks indent? opts))

+ 10 - 15
deps/outliner/src/logseq/outliner/op.cljs

@@ -1,7 +1,6 @@
 (ns logseq.outliner.op
   "Transact outliner ops"
-  (:require [clojure.string :as string]
-            [datascript.core :as d]
+  (:require [datascript.core :as d]
             [logseq.db :as ldb]
             [logseq.db.sqlite.export :as sqlite-export]
             [logseq.outliner.core :as outliner-core]
@@ -169,53 +168,49 @@
           (reset! *result {:error (str "Unexpected Import EDN error: " (pr-str (ex-message e)))}))))))
 
 (defn ^:large-vars/cleanup-todo apply-ops!
-  [repo conn ops date-formatter opts]
+  [conn ops opts]
   (assert (ops-validator ops) ops)
   (let [opts' (assoc opts
                      :transact-opts {:conn conn}
                      :local-tx? true)
-        *result (atom nil)
-        db-based? (ldb/db-based-graph? @conn)]
+        *result (atom nil)]
     (outliner-tx/transact!
      opts'
      (doseq [[op args] ops]
-       (when-not db-based?
-         (assert (not (or (string/includes? (name op) "property") (string/includes? (name op) "closed-value")))
-                 (str "Property related ops are only for db based graphs, ops: " ops)))
        (case op
          ;; blocks
          :save-block
-         (apply outliner-core/save-block! repo conn date-formatter args)
+         (apply outliner-core/save-block! conn args)
 
          :insert-blocks
          (let [[blocks target-block-id opts] args]
            (when-let [target-block (d/entity @conn target-block-id)]
-             (let [result (outliner-core/insert-blocks! repo conn blocks target-block opts)]
+             (let [result (outliner-core/insert-blocks! conn blocks target-block opts)]
                (reset! *result result))))
 
          :delete-blocks
          (let [[block-ids opts] args
                blocks (keep #(d/entity @conn %) block-ids)]
-           (outliner-core/delete-blocks! repo conn date-formatter blocks (merge opts opts')))
+           (outliner-core/delete-blocks! conn blocks (merge opts opts')))
 
          :move-blocks
          (let [[block-ids target-block-id opts] args
                blocks (keep #(d/entity @conn %) block-ids)
                target-block (d/entity @conn target-block-id)]
            (when (and target-block (seq blocks))
-             (outliner-core/move-blocks! repo conn blocks target-block opts)))
+             (outliner-core/move-blocks! conn blocks target-block opts)))
 
          :move-blocks-up-down
          (let [[block-ids up?] args
                blocks (keep #(d/entity @conn %) block-ids)]
            (when (seq blocks)
-             (outliner-core/move-blocks-up-down! repo conn blocks up?)))
+             (outliner-core/move-blocks-up-down! conn blocks up?)))
 
          :indent-outdent-blocks
          (let [[block-ids indent? opts] args
                blocks (keep #(d/entity @conn %) block-ids)]
            (when (seq blocks)
-             (outliner-core/indent-outdent-blocks! repo conn blocks indent? opts)))
+             (outliner-core/indent-outdent-blocks! conn blocks indent? opts)))
 
          ;; properties
          :upsert-property
@@ -264,6 +259,6 @@
          (apply ldb/transact! conn args)
 
          (when-let [handler (get @*op-handlers op)]
-           (reset! *result (handler repo conn args))))))
+           (reset! *result (handler conn args))))))
 
     @*result))

+ 3 - 3
deps/outliner/src/logseq/outliner/page.cljs

@@ -313,9 +313,9 @@
                      page-txs)
                 tx-meta (cond-> {:persist-op? persist-op?
                                  :outliner-op :create-page}
-                                today-journal?
-                                (assoc :create-today-journal? true
-                                       :today-journal-name title))]
+                          today-journal?
+                          (assoc :create-today-journal? true
+                                 :today-journal-name title))]
             {:tx-meta tx-meta
              :tx-data txs
              :title title

+ 1 - 1
deps/outliner/src/logseq/outliner/tree.cljs

@@ -6,7 +6,7 @@
             [logseq.db.common.property-util :as db-property-util]))
 
 (defprotocol INode
-  (-save [this *txs-state conn repo date-formatter opts])
+  (-save [this *txs-state conn opts])
   (-del [this *txs-state db]))
 
 (defn- blocks->vec-tree-aux

+ 2 - 2
deps/outliner/test/logseq/outliner/core_test.cljs

@@ -13,7 +13,7 @@
           property-value (:user.property/default (db-test/find-block-by-content @conn "b1"))
           _ (assert (:db/id property-value))
           block (db-test/find-block-by-content @conn "b1")]
-      (outliner-core/delete-blocks! nil conn nil [block] {})
+      (outliner-core/delete-blocks! conn [block] {})
       (is (nil? (db-test/find-block-by-content @conn "b1")))
       (is (nil? (db-test/find-block-by-content @conn "test block"))))))
 
@@ -32,7 +32,7 @@
                                 :block/parent (:db/id page1)}])
           b3 (db-test/find-block-by-content @conn "b3")
           b4 (db-test/find-block-by-content @conn "b4")]
-      (outliner-core/delete-blocks! nil conn nil [b3 b4 page2] {})
+      (outliner-core/delete-blocks! conn [b3 b4 page2] {})
       (is (some? (db-test/find-block-by-content @conn "b3")))
       (is (some? (db-test/find-block-by-content @conn "b4")))
       (let [page2' (ldb/get-page @conn "page2")]

+ 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
         }

+ 0 - 2
libs/src/LSPlugin.ts

@@ -283,8 +283,6 @@ export type ExternalCommandType =
   | 'logseq.editor/up'
   | 'logseq.editor/expand-block-children'
   | 'logseq.editor/collapse-block-children'
-  | 'logseq.editor/open-file-in-default-app'
-  | 'logseq.editor/open-file-in-directory'
   | 'logseq.editor/select-all-blocks'
   | 'logseq.editor/toggle-open-blocks'
   | 'logseq.editor/zoom-in'

+ 1 - 6
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",
@@ -139,7 +137,6 @@
         "@js-joda/core": "3.2.0",
         "@js-joda/locale_en-us": "3.1.1",
         "@js-joda/timezone": "2.5.0",
-        "@logseq/diff-merge": "^0.2.2",
         "@logseq/react-tweet-embed": "1.3.1-1",
         "@logseq/simple-wave-record": "^0.0.3",
         "@radix-ui/colors": "^0.1.8",
@@ -150,13 +147,11 @@
         "@tabler/icons-webfont": "^2.47.0",
         "@tippyjs/react": "4.2.5",
         "bignumber.js": "^9.0.2",
-        "check-password-strength": "2.0.7",
         "chokidar": "3.5.1",
         "chrono-node": "2.2.4",
         "codemirror": "5.65.18",
         "comlink": "^4.4.1",
         "d3-force": "3.0.0",
-        "diff": "5.0.0",
         "dompurify": "2.4.0",
         "emoji-mart": "^5.5.2",
         "fs": "0.0.1-security",

+ 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
-  }
-}

Some files were not shown because too many files changed in this diff