enhance(ux): align for the image asset block container (#12425)

* feat(asset): add alignment options for images
* enhance(ux): select block for the action of double click in the image asset container
* enhance(asset): change alignment property type from string to keyword and normalize alignment handling
This commit is contained in:
Charlie
2026-03-12 11:18:51 +08:00
committed by GitHub
parent b1ceaa1216
commit 1b0db68098
7 changed files with 112 additions and 28 deletions

View File

@@ -510,7 +510,8 @@
[:logseq.property.asset/checksum :string]
[:logseq.property.asset/size :int]
[:logseq.property.asset/width {:optional true} :int]
[:logseq.property.asset/height {:optional true} :int]]
[:logseq.property.asset/height {:optional true} :int]
[:logseq.property.asset/align {:optional true} :keyword]]
block-attrs
page-or-block-attrs)))

View File

@@ -567,6 +567,11 @@
:schema {:type :map
:hide? true
:public? false}}
:logseq.property.asset/align {:title "Asset alignment"
:schema {:type :keyword
:hide? true
:public? false}
:queryable? false}
:logseq.property.fsrs/due {:title "Due"
:schema
{:type :datetime

View File

@@ -30,7 +30,7 @@
(map (juxt :major :minor)
[(parse-schema-version x) (parse-schema-version y)])))
(def version (parse-schema-version "65.22"))
(def version (parse-schema-version "65.23"))
(defn major-version
"Return a number.

View File

@@ -202,11 +202,24 @@
(on-dimensions (.-naturalWidth img) (.-naturalHeight img))))
(set! (.-src img) url)))
(defn- normalize-asset-align
[asset-align]
(cond
(keyword? asset-align) asset-align
(string? asset-align) (case asset-align
"left" :left
"center" :center
"right" :right
nil)
:else nil))
(defonce *resizing-image? (atom false))
(rum/defc ^:large-vars/cleanup-todo asset-container
[asset-block src title metadata {:keys [breadcrumb? positioned? local? full-text]}]
(let [asset-width (:logseq.property.asset/width asset-block)
asset-height (:logseq.property.asset/height asset-block)]
asset-height (:logseq.property.asset/height asset-block)
asset-align (normalize-asset-align (:logseq.property.asset/align asset-block))]
(hooks/use-effect!
(fn []
(when (:block/uuid asset-block)
@@ -275,7 +288,13 @@
:repo (state/get-current-repo)
:href src
:title title
:full-text full-text})))))))]
:full-text full-text})))))))
handle-set-align!
(fn [align]
(when-let [asset-id (:block/uuid asset-block)]
(property-handler/set-block-property! asset-id
:logseq.property.asset/align
align)))]
(when asset-block
[:.asset-action-bar {:aria-hidden "true"}
(shui/dropdown-menu
@@ -288,6 +307,33 @@
:class "h-6 w-6"}
(shui/tabler-icon "dots-vertical")))
(shui/dropdown-menu-content
(shui/dropdown-menu-sub
(shui/dropdown-menu-sub-trigger
[:span.flex.items-center.gap-1
(ui/icon "layout-align-left") (t :asset/align)])
(shui/dropdown-menu-sub-content
(shui/dropdown-menu-item
{:on-click #(handle-set-align! :left)}
[:span.flex.items-center.gap-2
(ui/icon "layout-align-left")
(t :asset/align-left)
(when (or (nil? asset-align) (= asset-align :left))
(ui/icon "check"))])
(shui/dropdown-menu-item
{:on-click #(handle-set-align! :center)}
[:span.flex.items-center.gap-2
(ui/icon "layout-align-center")
(t :asset/align-center)
(when (= asset-align :center)
(ui/icon "check"))])
(shui/dropdown-menu-item
{:on-click #(handle-set-align! :right)}
[:span.flex.items-center.gap-2
(ui/icon "layout-align-right")
(t :asset/align-right)
(when (= asset-align :right)
(ui/icon "check"))])))
(shui/dropdown-menu-item
{:on-click handle-copy!}
[:span.flex.items-center.gap-1
@@ -301,6 +347,7 @@
(js/window.apis.openExternal image-src)))}
[:span.flex.items-center.gap-1
(ui/icon "folder-pin") (t (if local? :asset/show-in-folder :asset/open-in-browser))]))
(when-not config/publishing?
[:<>
(shui/dropdown-menu-separator)
@@ -318,6 +365,7 @@
(let [breadcrumb? (:breadcrumb? config)
positioned? (:property-position config)
asset-block (:asset-block config)
asset-align (normalize-asset-align (:logseq.property.asset/align asset-block))
width (:width metadata)
*width (get state ::size)
width (or @*width width)
@@ -334,30 +382,42 @@
(:table-view? config)
(not resizable?))
asset-container-cp
[:div.ls-resize-image.rounded-md
asset-container-cp
(resize-image-handles
(fn [k ^js event]
(let [dx (.-dx event)
^js target (.-target event)]
[:div.ls-resize-inner.w-full.select-none
{:on-double-click (fn [^js e]
(let [^js target (.-target e)
^js container (.closest target ".ls-resize-inner")]
(when (or container (= target container))
(when-let [block-uuid (or (:block/uuid config)
(some-> config :block :block/uuid))]
(editor-handler/select-block! block-uuid)))))}
[:div.ls-resize-image.rounded-md
{:class (case asset-align
:center "align-center"
:right "align-right"
"align-left")}
asset-container-cp
(resize-image-handles
(fn [k ^js event]
(let [dx (.-dx event)
^js target (.-target event)]
(case k
:start
(let [c (.closest target ".ls-resize-image")]
(reset! *width (.-offsetWidth c))
(reset! *resizing-image? true))
:move
(let [width' (+ @*width dx)]
(when (or (> width' 60)
(not (neg? dx)))
(reset! *width width')))
:end
(let [width' @*width]
(when (and width' @*resizing-image?)
(when-let [block-id (or (:block/uuid config)
(some-> config :block (:block/uuid)))]
(editor-handler/resize-image! config block-id metadata full-text {:width width'})))
(reset! *resizing-image? false))))))])))
(case k
:start
(let [c (.closest target ".ls-resize-image")]
(reset! *width (.-offsetWidth c))
(reset! *resizing-image? true))
:move
(let [width' (+ @*width dx)]
(when (or (> width' 60)
(not (neg? dx)))
(reset! *width width')))
:end
(let [width' @*width]
(when (and width' @*resizing-image?)
(when-let [block-id (or (:block/uuid config)
(some-> config :block (:block/uuid)))]
(editor-handler/resize-image! config block-id metadata full-text {:width width'})))
(reset! *resizing-image? false))))))]])))
(rum/defc audio-cp
([src] (audio-cp src nil))

View File

@@ -1194,6 +1194,19 @@ html.is-mac {
.ls-resize-image {
@apply flex relative w-fit cursor-pointer;
&.align-left {
margin-right: auto;
}
&.align-center {
margin-left: auto;
margin-right: auto;
}
&.align-right {
margin-left: auto;
}
.handle-left, .handle-right {
@apply absolute w-[6px] h-[15%] min-h-[30px] bg-black/30 hover:bg-black/70
top-[50%] left-[5px] rounded-full cursor-col-resize select-none

View File

@@ -75,7 +75,8 @@
["65.20" {:properties [:logseq.property.class/bidirectional-property-title :logseq.property.class/enable-bidirectional?]}]
["65.21" {:properties [:logseq.property.sync/large-title-object]}]
["65.22" {:properties [:logseq.property.reaction/emoji-id
:logseq.property.reaction/target]}]])
:logseq.property.reaction/target]}]
["65.23" {:properties [:logseq.property.asset/align]}]])
(let [[major minor] (last (sort (map (comp (juxt :major :minor) db-schema/parse-schema-version first)
schema-version->updates)))]

View File

@@ -135,6 +135,10 @@
:asset/ref-block "Asset ref block"
:asset/confirm-delete "Are you sure you want to delete this {1}?"
:asset/physical-delete "Remove the file too (notice it can't be restored)"
:asset/align "Align"
:asset/align-left "Align left"
:asset/align-center "Align center"
:asset/align-right "Align right"
:color/gray "Gray"
:color/red "Red"
:color/yellow "Yellow"