mirror of
https://github.com/penpot/penpot.git
synced 2026-04-25 11:18:36 +00:00
🎉 Add copy as image to clipboard menu option (#8364)
* ✨ Copy as image Function to copy a board directly to the clipboard. This is exposed on the Copy/Paste as... context menu. The image is always copied at 2x to work well with wireframes. I tried with and without Retina display and it is better in both scenarios. Signed-off-by: Dalai Felinto <dalai@blender.org> * ✨ Add minor adjustments on promise creation * 🔥 Remove prn from obj/reify macros --------- Signed-off-by: Dalai Felinto <dalai@blender.org>
This commit is contained in:
parent
a1cc016727
commit
a278d54429
@ -9,6 +9,7 @@
|
||||
### :heart: Community contributions (Thank you!)
|
||||
|
||||
- Option to download custom fonts (by @dfelinto) [Github #8320](https://github.com/penpot/penpot/issues/8320)
|
||||
- Add copy as image to clipboard option to workspace context menu (by @dfelinto) [Github #8313](https://github.com/penpot/penpot/pull/8313)
|
||||
|
||||
### :sparkles: New features & Enhancements
|
||||
|
||||
|
||||
@ -1434,6 +1434,7 @@
|
||||
(dm/export dwcp/paste-shapes)
|
||||
(dm/export dwcp/paste-data-valid?)
|
||||
(dm/export dwcp/copy-link-to-clipboard)
|
||||
(dm/export dwcp/copy-as-image)
|
||||
|
||||
;; Drawing
|
||||
(dm/export dwd/select-for-drawing)
|
||||
|
||||
@ -1039,3 +1039,55 @@
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(clipboard/to-clipboard (rt/get-current-href)))))
|
||||
|
||||
(defn copy-as-image
|
||||
[]
|
||||
(ptk/reify ::copy-as-image
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [file-id (:current-file-id state)
|
||||
page-id (:current-page-id state)
|
||||
selected (first (dsh/lookup-selected state))
|
||||
|
||||
export {:file-id file-id
|
||||
:page-id page-id
|
||||
:object-id selected
|
||||
;; webp would be preferrable, but PNG is the most supported image MIME type by clipboard APIs.
|
||||
:type :png
|
||||
;; Always use 2 to ensure good enough quality for wireframes.
|
||||
:scale 2
|
||||
:suffix ""
|
||||
:enabled true
|
||||
:name ""}
|
||||
|
||||
params {:exports [export]
|
||||
:profile-id (:profile-id state)
|
||||
:cmd :export-shapes
|
||||
:wait true}]
|
||||
|
||||
(rx/concat
|
||||
;; Ensure current state persisted before exporting.
|
||||
(rx/of ::dps/force-persist)
|
||||
(->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
|
||||
(rx/filter #(or (nil? %) (= :saved %)))
|
||||
(rx/first)
|
||||
(rx/timeout 400 (rx/empty)))
|
||||
|
||||
;; Exporting itself can time its time, better to notify that we are busy.
|
||||
(rx/of (ntf/info (tr "workspace.clipboard.copying")))
|
||||
|
||||
;; Call exporter to get image URI, then fetch and copy blob.
|
||||
(->> (rp/cmd! :export params)
|
||||
(rx/mapcat (fn [{:keys [uri]}]
|
||||
(http/send! {:method :get
|
||||
:uri uri
|
||||
:response-type :blob})))
|
||||
(rx/map :body)
|
||||
(rx/tap (fn [blob]
|
||||
(clipboard/to-clipboard-promise "image/png" (p/resolved blob))))
|
||||
(rx/map (fn [_]
|
||||
(ntf/success (tr "workspace.clipboard.image-copied"))))
|
||||
(rx/catch (fn [e]
|
||||
(js/console.error "clipboard blocked:" e)
|
||||
(ntf/error (tr "workspace.clipboard.image-copy-failed"))
|
||||
(rx/empty)))))))))
|
||||
|
||||
@ -150,7 +150,9 @@
|
||||
{::mf/props :obj
|
||||
::mf/private true}
|
||||
[{:keys [shapes]}]
|
||||
(let [do-copy #(st/emit! (dw/copy-selected))
|
||||
(let [multiple? (> (count shapes) 1)
|
||||
|
||||
do-copy #(st/emit! (dw/copy-selected))
|
||||
do-copy-link #(st/emit! (dw/copy-link-to-clipboard))
|
||||
|
||||
do-cut #(st/emit! (dw/copy-selected)
|
||||
@ -178,6 +180,9 @@
|
||||
handle-copy-text
|
||||
(mf/use-callback #(st/emit! (dw/copy-selected-text)))
|
||||
|
||||
handle-copy-as-image
|
||||
(mf/use-callback #(st/emit! (dw/copy-as-image)))
|
||||
|
||||
handle-hover-copy-paste
|
||||
(mf/use-callback
|
||||
(fn []
|
||||
@ -222,6 +227,11 @@
|
||||
[:> menu-entry* {:title (tr "workspace.shape.menu.copy-svg")
|
||||
:on-click handle-copy-svg}]
|
||||
|
||||
(when (some cfh/frame-shape? shapes)
|
||||
[:> menu-entry* {:title (tr "workspace.shape.menu.copy-as-image")
|
||||
:disabled multiple?
|
||||
:on-click handle-copy-as-image}])
|
||||
|
||||
[:> menu-separator* {}]
|
||||
|
||||
[:> menu-entry* {:title (tr "workspace.shape.menu.copy-text")
|
||||
@ -229,7 +239,7 @@
|
||||
|
||||
[:> menu-entry* {:title (tr "workspace.shape.menu.copy-props")
|
||||
:shortcut (sc/get-tooltip :copy-props)
|
||||
:disabled (> (count shapes) 1)
|
||||
:disabled multiple?
|
||||
:on-click handle-copy-props}]
|
||||
[:> menu-entry* {:title (tr "workspace.shape.menu.paste-props")
|
||||
:shortcut (sc/get-tooltip :paste-props)
|
||||
|
||||
@ -7600,6 +7600,18 @@ msgstr "Paste"
|
||||
msgid "workspace.shape.menu.paste-props"
|
||||
msgstr "Paste properties"
|
||||
|
||||
msgid "workspace.shape.menu.copy-as-image"
|
||||
msgstr "Copy as image"
|
||||
|
||||
msgid "workspace.clipboard.copying"
|
||||
msgstr "Copying image…"
|
||||
|
||||
msgid "workspace.clipboard.image-copied"
|
||||
msgstr "Image copied to the clipboard"
|
||||
|
||||
msgid "workspace.clipboard.image-copy-failed"
|
||||
msgstr "Error copying image"
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs:443
|
||||
msgid "workspace.shape.menu.path"
|
||||
msgstr "Path"
|
||||
|
||||
@ -7544,6 +7544,18 @@ msgstr "Pegar"
|
||||
msgid "workspace.shape.menu.paste-props"
|
||||
msgstr "Pegar propiedades"
|
||||
|
||||
msgid "workspace.shape.menu.copy-as-image"
|
||||
msgstr "Copiar como imagen"
|
||||
|
||||
msgid "workspace.clipboard.copying"
|
||||
msgstr "Copiando imagen…"
|
||||
|
||||
msgid "workspace.clipboard.image-copied"
|
||||
msgstr "Imagen copiada al portapapeles"
|
||||
|
||||
msgid "workspace.clipboard.image-copy-failed"
|
||||
msgstr "Error al copiar la imagen"
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs:443
|
||||
msgid "workspace.shape.menu.path"
|
||||
msgstr "Ruta"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user