|
51 | 51 | [frontend.handler.file-sync :as file-sync] |
52 | 52 | [frontend.handler.notification :as notification] |
53 | 53 | [frontend.handler.plugin :as plugin-handler] |
| 54 | + [frontend.handler.property :as property-handler] |
54 | 55 | [frontend.handler.property.file :as property-file] |
55 | 56 | [frontend.handler.property.util :as pu] |
56 | 57 | [frontend.handler.route :as route-handler] |
|
301 | 302 | [:span.handle-left.image-resize (assoc handle-props :ref *handle-left)] |
302 | 303 | [:span.handle-right.image-resize (assoc handle-props :ref *handle-right)]])) |
303 | 304 |
|
| 305 | +(defn measure-image! [url on-dimensions] |
| 306 | + (let [img (js/Image.)] |
| 307 | + (set! (.-onload img) |
| 308 | + (fn [] |
| 309 | + (on-dimensions (.-naturalWidth img) (.-naturalHeight img)))) |
| 310 | + (set! (.-src img) url))) |
| 311 | + |
304 | 312 | (defonce *resizing-image? (atom false)) |
305 | | -(rum/defc asset-container |
| 313 | +(rum/defc ^:large-vars/cleanup-todo asset-container |
306 | 314 | [asset-block src title metadata {:keys [breadcrumb? positioned? local? full-text]}] |
307 | | - (let [*el-ref (rum/use-ref nil) |
308 | | - image-src (fs/asset-path-normalize src) |
309 | | - src' (if (or (string/starts-with? src "/") |
310 | | - (string/starts-with? src "~")) |
311 | | - (str "file://" src) |
312 | | - src) |
313 | | - get-blockid #(some-> (rum/deref *el-ref) (.closest "[blockid]") (.getAttribute "blockid") (uuid))] |
314 | | - [:div.asset-container |
315 | | - {:key "resize-asset-container" |
316 | | - :on-pointer-down util/stop |
317 | | - :on-click (fn [e] |
318 | | - (util/stop e) |
319 | | - (when (= "IMG" (some-> (.-target e) (.-nodeName))) |
320 | | - (open-lightbox! e))) |
321 | | - :ref *el-ref} |
322 | | - [:img.rounded-sm.relative |
323 | | - (merge |
324 | | - {:loading "lazy" |
325 | | - :referrerPolicy "no-referrer" |
326 | | - :src src' |
327 | | - :title title} |
328 | | - metadata)] |
329 | | - (when (and (not breadcrumb?) |
330 | | - (not positioned?)) |
331 | | - [:<> |
332 | | - (let [handle-copy! |
333 | | - (fn [_e] |
334 | | - (-> (util/copy-image-to-clipboard image-src) |
335 | | - (p/then #(notification/show! "Copied!" :success)))) |
336 | | - handle-delete! |
337 | | - (fn [_e] |
338 | | - (when-let [block-id (get-blockid)] |
339 | | - (let [*local-selected? (atom local?)] |
340 | | - (-> (shui/dialog-confirm! |
341 | | - [:div.text-xs.opacity-60.-my-2 |
342 | | - (when (and local? (not= (:block/uuid asset-block) block-id)) |
343 | | - [:label.flex.gap-1.items-center |
344 | | - (shui/checkbox |
345 | | - {:default-checked @*local-selected? |
346 | | - :on-checked-change #(reset! *local-selected? %)}) |
347 | | - (t :asset/physical-delete)])] |
348 | | - {:title (t :asset/confirm-delete (.toLocaleLowerCase (t :text/image))) |
349 | | - :outside-cancel? true}) |
350 | | - (p/then (fn [] |
351 | | - (shui/dialog-close!) |
352 | | - (editor-handler/delete-asset-of-block! |
353 | | - {:block-id block-id |
354 | | - :asset-block asset-block |
355 | | - :local? local? |
356 | | - :delete-local? @*local-selected? |
357 | | - :repo (state/get-current-repo) |
358 | | - :href src |
359 | | - :title title |
360 | | - :full-text full-text})))))))] |
361 | | - [:.asset-action-bar {:aria-hidden "true"} |
362 | | - (shui/button-group |
363 | | - (shui/button |
364 | | - {:variant :outline |
365 | | - :size :icon |
366 | | - :class "h-7 w-7" |
367 | | - :on-pointer-down util/stop |
368 | | - :on-click (fn [e] |
369 | | - (shui/popup-show! (.closest (.-target e) ".asset-action-bar") |
370 | | - (fn [] |
371 | | - [:div |
372 | | - {:on-click #(shui/popup-hide!)} |
373 | | - (shui/dropdown-menu-item |
374 | | - {:on-click #(some-> (db/entity [:block/uuid (get-blockid)]) |
375 | | - (editor-handler/edit-block! :max {:container-id :unknown-container}))} |
376 | | - [:span.flex.items-center.gap-1 |
377 | | - (ui/icon "edit") (t :asset/edit-block)]) |
378 | | - (shui/dropdown-menu-item |
379 | | - {:on-click handle-copy!} |
380 | | - [:span.flex.items-center.gap-1 |
381 | | - (ui/icon "copy") (t :asset/copy)]) |
382 | | - (when (util/electron?) |
| 315 | + (let [asset-width (:logseq.property.asset/width asset-block) |
| 316 | + asset-height (:logseq.property.asset/height asset-block)] |
| 317 | + (hooks/use-effect! |
| 318 | + (fn [] |
| 319 | + (when-not (or asset-width asset-height) |
| 320 | + (measure-image! |
| 321 | + src |
| 322 | + (fn [width height] |
| 323 | + (when (nil? (:logseq.property.asset/width asset-block)) |
| 324 | + (property-handler/set-block-properties! (state/get-current-repo) |
| 325 | + (:block/uuid asset-block) |
| 326 | + {:logseq.property.asset/width width |
| 327 | + :logseq.property.asset/height height}))))) |
| 328 | + (fn [])) |
| 329 | + []) |
| 330 | + (let [*el-ref (rum/use-ref nil) |
| 331 | + image-src (fs/asset-path-normalize src) |
| 332 | + src' (if (or (string/starts-with? src "/") |
| 333 | + (string/starts-with? src "~")) |
| 334 | + (str "file://" src) |
| 335 | + src) |
| 336 | + get-blockid #(some-> (rum/deref *el-ref) (.closest "[blockid]") (.getAttribute "blockid") (uuid))] |
| 337 | + [:div.asset-container |
| 338 | + {:key "resize-asset-container" |
| 339 | + :on-pointer-down util/stop |
| 340 | + :on-click (fn [e] |
| 341 | + (util/stop e) |
| 342 | + (when (= "IMG" (some-> (.-target e) (.-nodeName))) |
| 343 | + (open-lightbox! e))) |
| 344 | + :ref *el-ref} |
| 345 | + [:img.rounded-sm.relative.fade-in.fade-in-faster |
| 346 | + (merge |
| 347 | + {:loading "lazy" |
| 348 | + :referrerPolicy "no-referrer" |
| 349 | + :src src' |
| 350 | + :title title} |
| 351 | + metadata)] |
| 352 | + (when (and (not breadcrumb?) |
| 353 | + (not positioned?)) |
| 354 | + [:<> |
| 355 | + (let [handle-copy! |
| 356 | + (fn [_e] |
| 357 | + (-> (util/copy-image-to-clipboard image-src) |
| 358 | + (p/then #(notification/show! "Copied!" :success)))) |
| 359 | + handle-delete! |
| 360 | + (fn [_e] |
| 361 | + (when-let [block-id (get-blockid)] |
| 362 | + (let [*local-selected? (atom local?)] |
| 363 | + (-> (shui/dialog-confirm! |
| 364 | + [:div.text-xs.opacity-60.-my-2 |
| 365 | + (when (and local? (not= (:block/uuid asset-block) block-id)) |
| 366 | + [:label.flex.gap-1.items-center |
| 367 | + (shui/checkbox |
| 368 | + {:default-checked @*local-selected? |
| 369 | + :on-checked-change #(reset! *local-selected? %)}) |
| 370 | + (t :asset/physical-delete)])] |
| 371 | + {:title (t :asset/confirm-delete (.toLocaleLowerCase (t :text/image))) |
| 372 | + :outside-cancel? true}) |
| 373 | + (p/then (fn [] |
| 374 | + (shui/dialog-close!) |
| 375 | + (editor-handler/delete-asset-of-block! |
| 376 | + {:block-id block-id |
| 377 | + :asset-block asset-block |
| 378 | + :local? local? |
| 379 | + :delete-local? @*local-selected? |
| 380 | + :repo (state/get-current-repo) |
| 381 | + :href src |
| 382 | + :title title |
| 383 | + :full-text full-text})))))))] |
| 384 | + [:.asset-action-bar {:aria-hidden "true"} |
| 385 | + (shui/button-group |
| 386 | + (shui/button |
| 387 | + {:variant :outline |
| 388 | + :size :icon |
| 389 | + :class "h-7 w-7" |
| 390 | + :on-pointer-down util/stop |
| 391 | + :on-click (fn [e] |
| 392 | + (shui/popup-show! (.closest (.-target e) ".asset-action-bar") |
| 393 | + (fn [] |
| 394 | + [:div |
| 395 | + {:on-click #(shui/popup-hide!)} |
383 | 396 | (shui/dropdown-menu-item |
384 | | - {:on-click (fn [e] |
385 | | - (util/stop e) |
386 | | - (if local? |
387 | | - (ipc/ipc "openFileInFolder" image-src) |
388 | | - (js/window.apis.openExternal image-src)))} |
| 397 | + {:on-click #(some-> (db/entity [:block/uuid (get-blockid)]) |
| 398 | + (editor-handler/edit-block! :max {:container-id :unknown-container}))} |
389 | 399 | [:span.flex.items-center.gap-1 |
390 | | - (ui/icon "folder-pin") (t (if local? :asset/show-in-folder :asset/open-in-browser))])) |
391 | | - |
392 | | - (when-not config/publishing? |
393 | | - [:<> |
394 | | - (shui/dropdown-menu-separator) |
395 | | - (shui/dropdown-menu-item |
396 | | - {:on-click handle-delete!} |
397 | | - [:span.flex.items-center.gap-1.text-red-700 |
398 | | - (ui/icon "trash") (t :asset/delete)])])]) |
399 | | - {:align :start |
400 | | - :dropdown-menu? true}))} |
401 | | - (shui/tabler-icon "dots-vertical")))])])])) |
402 | | - |
403 | | -;; TODO: store image height and width for better ux |
| 400 | + (ui/icon "edit") (t :asset/edit-block)]) |
| 401 | + (shui/dropdown-menu-item |
| 402 | + {:on-click handle-copy!} |
| 403 | + [:span.flex.items-center.gap-1 |
| 404 | + (ui/icon "copy") (t :asset/copy)]) |
| 405 | + (when (util/electron?) |
| 406 | + (shui/dropdown-menu-item |
| 407 | + {:on-click (fn [e] |
| 408 | + (util/stop e) |
| 409 | + (if local? |
| 410 | + (ipc/ipc "openFileInFolder" image-src) |
| 411 | + (js/window.apis.openExternal image-src)))} |
| 412 | + [:span.flex.items-center.gap-1 |
| 413 | + (ui/icon "folder-pin") (t (if local? :asset/show-in-folder :asset/open-in-browser))])) |
| 414 | + |
| 415 | + (when-not config/publishing? |
| 416 | + [:<> |
| 417 | + (shui/dropdown-menu-separator) |
| 418 | + (shui/dropdown-menu-item |
| 419 | + {:on-click handle-delete!} |
| 420 | + [:span.flex.items-center.gap-1.text-red-700 |
| 421 | + (ui/icon "trash") (t :asset/delete)])])]) |
| 422 | + {:align :start |
| 423 | + :dropdown-menu? true}))} |
| 424 | + (shui/tabler-icon "dots-vertical")))])])]))) |
| 425 | + |
404 | 426 | (rum/defcs ^:large-vars/cleanup-todo resizable-image < |
405 | 427 | (rum/local nil ::size) |
406 | 428 | {:will-unmount (fn [state] |
|
410 | 432 | (let [breadcrumb? (:breadcrumb? config) |
411 | 433 | positioned? (:property-position config) |
412 | 434 | asset-block (:asset-block config) |
413 | | - width (or (get-in asset-block [:logseq.property.asset/resize-metadata :width]) |
414 | | - (:width metadata)) |
| 435 | + width (:width metadata) |
415 | 436 | *width (get state ::size) |
416 | | - width (or @*width width 250) |
417 | | - metadata' (merge |
418 | | - (cond-> |
419 | | - {:height 125} |
420 | | - width |
421 | | - (assoc :width width)) |
422 | | - metadata) |
| 437 | + width (or @*width width) |
| 438 | + metadata' (assoc metadata :width width) |
423 | 439 | resizable? (and (not (mobile-util/native-platform?)) |
424 | 440 | (not breadcrumb?) |
425 | 441 | (not positioned?)) |
|
503 | 519 | repo (state/get-current-repo) |
504 | 520 | href (config/get-local-asset-absolute-path href) |
505 | 521 | db-based? (config/db-based-graph? repo)] |
506 | | - (when (and (or db-based? |
507 | | - (util/electron?) |
508 | | - (mobile-util/native-platform?)) |
509 | | - (nil? @src)) |
| 522 | + |
| 523 | + (when (nil? @src) |
510 | 524 | (p/then (assets-handler/<make-asset-url href) |
511 | 525 | #(reset! src (common-util/safe-decode-uri-component %)))) |
512 | | - |
513 | | - (when @src |
| 526 | + (:image-placeholder config) |
| 527 | + (if-not @src |
| 528 | + (:image-placeholder config) |
514 | 529 | (let [ext (keyword (or (util/get-file-ext @src) |
515 | 530 | (util/get-file-ext href))) |
516 | 531 | repo (state/get-current-repo) |
|
1074 | 1089 | file-exists? @(::file-exists? state) |
1075 | 1090 | repo (state/get-current-repo) |
1076 | 1091 | asset-file-write-finished? (state/sub :assets/asset-file-write-finish |
1077 | | - {:path-in-sub-atom [repo (str (:block/uuid block))]})] |
1078 | | - (when (or file-exists? asset-file-write-finished?) |
1079 | | - (asset-link (assoc config :asset-block block) |
| 1092 | + {:path-in-sub-atom [repo (str (:block/uuid block))]}) |
| 1093 | + asset-type (:logseq.property.asset/type block) |
| 1094 | + image? (contains? (common-config/img-formats) (keyword asset-type)) |
| 1095 | + width (get-in block [:logseq.property.asset/resize-metadata :width]) |
| 1096 | + asset-width (:logseq.property.asset/width block) |
| 1097 | + asset-height (:logseq.property.asset/height block) |
| 1098 | + img-metadata (when image? |
| 1099 | + (let [width (or width 250 asset-width) |
| 1100 | + aspect-ratio (when (and asset-width asset-height) |
| 1101 | + (/ asset-width asset-height))] |
| 1102 | + (merge |
| 1103 | + (when width |
| 1104 | + {:width width}) |
| 1105 | + (when (and width aspect-ratio) |
| 1106 | + {:height (/ width aspect-ratio)})))) |
| 1107 | + img-placeholder (when image? |
| 1108 | + [:div.img-placeholder.asset-container |
| 1109 | + {:style img-metadata}])] |
| 1110 | + (cond |
| 1111 | + (or file-exists? asset-file-write-finished?) |
| 1112 | + (asset-link (assoc config |
| 1113 | + :asset-block block |
| 1114 | + :image-placeholder img-placeholder) |
1080 | 1115 | (:block/title block) |
1081 | 1116 | (path/path-join (str "../" common-config/local-assets-dir) file) |
1082 | | - nil |
1083 | | - nil)))) |
| 1117 | + img-metadata |
| 1118 | + nil) |
| 1119 | + image? |
| 1120 | + img-placeholder))) |
1084 | 1121 |
|
1085 | 1122 | (defn- img-audio-video? |
1086 | 1123 | [block] |
|
0 commit comments