Add copy-as-svg to contextual menu (#6510)

*  Add "copy as svg" to contextual menu

* 🌐 Add a few translations of the new string

* 📚 Document commit message format for translations

* 📎 Log SVG import errors to the console

* 📎 Update CHANGES.md (two PRs)

---------

Signed-off-by: Miguel de Benito Delgado <m.debenito.d@gmail.com>
This commit is contained in:
Miguel de Benito Delgado 2025-05-20 22:06:36 +02:00 committed by GitHub
parent 8f7c63d6e2
commit f36aa30525
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 75 additions and 5 deletions

View file

@ -77,8 +77,8 @@ A non exhaustive list of changes:
- Update base image for Docker Frontend to Nginx 1.28.0
- Allow multi file token import [Github #27](https://github.com/tokens-studio/penpot/issues/27)
- Create `input*` wrapper component, and `label*`, `input-field*` and `hint-message*` components [Taiga #10713](https://tree.taiga.io/project/penpot/us/10713)
- Add option for deselect layers with Ctrl+Shift+Drag [Github #2509](https://github.com/penpot/penpot/issues/2509)
- Deselect layers (and path nodes) with Ctrl+Shift+Drag [Github #2509](https://github.com/penpot/penpot/issues/2509)
- Copy to SVG from contextual menu [Github #838](https://github.com/penpot/penpot/issues/838)
### :bug: Bugs fixed

View file

@ -83,6 +83,8 @@ Where type is:
- :arrow_up: `:arrow_up:` a commit with dependency updates
- :arrow_down: `:arrow_down:` a commit with dependency downgrades
- :fire: `:fire:` a commit that removes files or code
- :globe_with_meridians: `:globe_with_meridians:` a commit that adds or updates
translations
More info:

View file

@ -1545,8 +1545,9 @@
(dm/export dwcp/paste-from-event)
(dm/export dwcp/copy-selected-css)
(dm/export dwcp/copy-selected-css-nested)
(dm/export dwcp/copy-selected-text)
(dm/export dwcp/copy-selected-props)
(dm/export dwcp/copy-selected-svg)
(dm/export dwcp/copy-selected-text)
(dm/export dwcp/paste-selected-props)
(dm/export dwcp/paste-shapes)
(dm/export dwcp/paste-data-valid?)

View file

@ -45,6 +45,7 @@
[app.main.repo :as rp]
[app.main.router :as rt]
[app.main.streams :as ms]
[app.util.code-gen.markup-svg :as svg]
[app.util.code-gen.style-css :as css]
[app.util.globals :as ug]
[app.util.http :as http]
@ -329,6 +330,25 @@
:else
(rx/empty))))))))
(defn copy-selected-svg
[]
(ptk/reify ::copy-selected-svg
ptk/EffectEvent
(effect [_ state _]
(let [objects (dsh/lookup-page-objects state)
selected (->> (dsh/lookup-selected state)
(ctst/sort-z-index objects)
(mapv (d/getf objects)))
parent-frame-id (cfh/common-parent-frame objects selected)
maybe-translate
#(if (= parent-frame-id uuid/zero) %
(gsh/translate-to-frame % (get objects parent-frame-id)))
shapes (mapv maybe-translate selected)
svg (svg/generate-markup objects shapes)]
(wapi/write-to-clipboard svg)))))
(defn copy-selected-css
[]
(ptk/reify ::copy-selected-css

View file

@ -8,6 +8,7 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.exceptions :as ex]
[app.common.files.changes-builder :as pcb]
[app.common.files.helpers :as cfh]
[app.common.files.shapes-builder :as sb]
@ -119,6 +120,7 @@
(dwu/commit-undo-transaction undo-id)))
(catch :default cause
(rx/throw {:type :svg-parser
:data cause})))))))
(js/console.error cause)
(rx/throw (ex/error :type :svg-parser
:hint (ex-message cause)))))))))

View file

@ -162,6 +162,9 @@
handle-paste-props
(mf/use-callback #(st/emit! (dw/paste-selected-props)))
handle-copy-svg
(mf/use-callback #(st/emit! (dw/copy-selected-svg)))
handle-copy-text
(mf/use-callback #(st/emit! (dw/copy-selected-text)))
@ -201,6 +204,8 @@
[:> menu-entry* {:title (tr "workspace.shape.menu.copy-paste-as")
:on-pointer-enter (when (cf/check-browser? :chrome) handle-hover-copy-paste)}
[:> menu-entry* {:title (tr "workspace.shape.menu.copy-svg")
:on-click handle-copy-svg}]
[:> menu-entry* {:title (tr "workspace.shape.menu.copy-css")
:on-click handle-copy-css}]
[:> menu-entry* {:title (tr "workspace.shape.menu.copy-css-nested")

View file

@ -6141,6 +6141,10 @@ msgstr "Eins nach hinten"
msgid "workspace.shape.menu.copy"
msgstr "Kopieren"
#: src/app/main/ui/workspace/context_menu.cljs
msgid "workspace.shape.menu.copy-svg"
msgstr "Als SVG kopieren"
#: src/app/main/ui/workspace/context_menu.cljs:204
msgid "workspace.shape.menu.copy-css"
msgstr "Als CSS kopieren"

View file

@ -6484,6 +6484,10 @@ msgstr "Send backward"
msgid "workspace.shape.menu.copy"
msgstr "Copy"
#: src/app/main/ui/workspace/context_menu.cljs
msgid "workspace.shape.menu.copy-svg"
msgstr "Copy as SVG"
#: src/app/main/ui/workspace/context_menu.cljs:204
msgid "workspace.shape.menu.copy-css"
msgstr "Copy as CSS"

View file

@ -6514,6 +6514,10 @@ msgstr "Enviar atrás"
msgid "workspace.shape.menu.copy"
msgstr "Copiar"
#: src/app/main/ui/workspace/context_menu.cljs
msgid "workspace.shape.menu.copy-svg"
msgstr "Copiar como SVG"
#: src/app/main/ui/workspace/context_menu.cljs:204
msgid "workspace.shape.menu.copy-css"
msgstr "Copiar como CSS"

View file

@ -5475,6 +5475,34 @@ msgstr "Éloigner"
msgid "workspace.shape.menu.copy"
msgstr "Copier"
#: src/app/main/ui/workspace/context_menu.cljs
msgid "workspace.shape.menu.copy-svg"
msgstr "Copier comme SVG"
#: src/app/main/ui/workspace/context_menu.cljs
msgid "workspace.shape.menu.copy-css"
msgstr "Copier comme CSS"
#: src/app/main/ui/workspace/context_menu.cljs
msgid "workspace.shape.menu.copy-css-nested"
msgstr "Copier comme CSS (calques imbriquées)"
#: src/app/main/ui/workspace/context_menu.cljs
msgid "workspace.shape.menu.copy-link"
msgstr "Copier le lien"
#: src/app/main/ui/workspace/context_menu.cljs
msgid "workspace.shape.menu.copy-paste-as"
msgstr "Copier/Coller comme ..."
#: src/app/main/ui/workspace/context_menu.cljs
msgid "workspace.shape.menu.copy-props"
msgstr "Copier les propriétés"
#: src/app/main/ui/workspace/context_menu.cljs
msgid "workspace.shape.menu.copy-text"
msgstr "Copier comme texte"
#: src/app/main/ui/workspace/sidebar/assets/common.cljs:454
msgid "workspace.shape.menu.create-annotation"
msgstr "Créer une note"