diff --git a/common/src/app/common/schema.cljc b/common/src/app/common/schema.cljc
index 322a3dd5fc..fc41156ca1 100644
--- a/common/src/app/common/schema.cljc
+++ b/common/src/app/common/schema.cljc
@@ -908,10 +908,6 @@
::oapi/format "password"}})
-;; FIXME: this should not be here
-(register! ::plugin-data
- [:map-of {:gen/max 5} :string :string])
-
;; ---- PREDICATES
(def valid-safe-number?
diff --git a/common/src/app/common/types/color.cljc b/common/src/app/common/types/color.cljc
index 64c8571612..5ab2dc6355 100644
--- a/common/src/app/common/types/color.cljc
+++ b/common/src/app/common/types/color.cljc
@@ -14,6 +14,7 @@
[app.common.types.color.generic :as-alias color-generic]
[app.common.types.color.gradient :as-alias color-gradient]
[app.common.types.color.gradient.stop :as-alias color-gradient-stop]
+ [app.common.types.plugins :as ctpg]
[app.common.uuid :as uuid]
[clojure.test.check.generators :as tgen]
[cuerdas.core :as str]))
@@ -88,7 +89,7 @@
[:gradient {:optional true} [:maybe ::gradient]]
[:image {:optional true} [:maybe ::image-color]]
[:plugin-data {:optional true}
- [:map-of {:gen/max 5} :keyword ::sm/plugin-data]]]
+ [:map-of {:gen/max 5} :keyword ::ctpg/plugin-data]]]
[::sm/contains-any {:strict true} [:color :gradient :image]]])
(sm/register! ::recent-color
diff --git a/common/src/app/common/types/container.cljc b/common/src/app/common/types/container.cljc
index d8aa12b938..aedf4ebc26 100644
--- a/common/src/app/common/types/container.cljc
+++ b/common/src/app/common/types/container.cljc
@@ -15,6 +15,7 @@
[app.common.types.component :as ctk]
[app.common.types.components-list :as ctkl]
[app.common.types.pages-list :as ctpl]
+ [app.common.types.plugins :as ctpg]
[app.common.types.shape-tree :as ctst]
[app.common.types.shape.layout :as ctl]
[app.common.uuid :as uuid]))
@@ -37,7 +38,7 @@
[:objects {:optional true}
[:map-of {:gen/max 10} ::sm/uuid :map]]
[:plugin-data {:optional true}
- [:map-of {:gen/max 5} :keyword ::sm/plugin-data]]])
+ [:map-of {:gen/max 5} :keyword ::ctpg/plugin-data]]])
(def check-container!
(sm/check-fn ::container))
diff --git a/common/src/app/common/types/file.cljc b/common/src/app/common/types/file.cljc
index b7f7acd7dc..1a411f594f 100644
--- a/common/src/app/common/types/file.cljc
+++ b/common/src/app/common/types/file.cljc
@@ -24,6 +24,7 @@
[app.common.types.container :as ctn]
[app.common.types.page :as ctp]
[app.common.types.pages-list :as ctpl]
+ [app.common.types.plugins :as ctpg]
[app.common.types.shape-tree :as ctst]
[app.common.types.typographies-list :as ctyl]
[app.common.types.typography :as cty]
@@ -59,7 +60,7 @@
[:media {:optional true}
[:map-of {:gen/max 5} ::sm/uuid ::media-object]]
[:plugin-data {:optional true}
- [:map-of {:gen/max 5} :keyword ::sm/plugin-data]]])
+ [:map-of {:gen/max 5} :keyword ::ctpg/plugin-data]]])
(def check-file-data!
(sm/check-fn ::data))
diff --git a/common/src/app/common/types/page.cljc b/common/src/app/common/types/page.cljc
index b8c9eb3de6..3b00643ce0 100644
--- a/common/src/app/common/types/page.cljc
+++ b/common/src/app/common/types/page.cljc
@@ -10,6 +10,7 @@
[app.common.schema :as sm]
[app.common.types.color :as-alias ctc]
[app.common.types.grid :as ctg]
+ [app.common.types.plugins :as ctpg]
[app.common.types.shape :as cts]
[app.common.uuid :as uuid]))
@@ -45,7 +46,7 @@
[:guides {:optional true}
[:map-of {:gen/max 2} ::sm/uuid ::guide]]
[:plugin-data {:optional true}
- [:map-of {:gen/max 5} :keyword ::sm/plugin-data]]]]])
+ [:map-of {:gen/max 5} :keyword ::ctpg/plugin-data]]]]])
(def check-page-guide!
(sm/check-fn ::guide))
diff --git a/common/src/app/common/types/plugins.cljc b/common/src/app/common/types/plugins.cljc
new file mode 100644
index 0000000000..49d31bf2d6
--- /dev/null
+++ b/common/src/app/common/types/plugins.cljc
@@ -0,0 +1,16 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) KALEIDOS INC
+
+(ns app.common.types.plugins
+ (:require
+ [app.common.schema :as sm]))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; SCHEMAS
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(sm/register! ::plugin-data
+ [:map-of {:gen/max 5} :string :string])
diff --git a/common/src/app/common/types/shape.cljc b/common/src/app/common/types/shape.cljc
index 71a1964d39..cbce60984c 100644
--- a/common/src/app/common/types/shape.cljc
+++ b/common/src/app/common/types/shape.cljc
@@ -20,6 +20,7 @@
[app.common.transit :as t]
[app.common.types.color :as ctc]
[app.common.types.grid :as ctg]
+ [app.common.types.plugins :as ctpg]
[app.common.types.shape.attrs :refer [default-color]]
[app.common.types.shape.blur :as ctsb]
[app.common.types.shape.export :as ctse]
@@ -188,7 +189,7 @@
[:grow-type {:optional true}
[::sm/one-of #{:auto-width :auto-height :fixed}]]
[:plugin-data {:optional true}
- [:map-of {:gen/max 5} :keyword ::sm/plugin-data]]])
+ [:map-of {:gen/max 5} :keyword ::ctpg/plugin-data]]])
(sm/register! ::group-attrs
[:map {:title "GroupAttrs"}
diff --git a/common/src/app/common/types/typography.cljc b/common/src/app/common/types/typography.cljc
index ba9eb12906..e143a2b8b7 100644
--- a/common/src/app/common/types/typography.cljc
+++ b/common/src/app/common/types/typography.cljc
@@ -9,6 +9,7 @@
[app.common.data :as d]
[app.common.schema :as sm]
[app.common.text :as txt]
+ [app.common.types.plugins :as ctpg]
[app.common.uuid :as uuid]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -31,7 +32,7 @@
[:modified-at {:optional true} ::sm/inst]
[:path {:optional true} [:maybe :string]]
[:plugin-data {:optional true}
- [:map-of {:gen/max 5} :keyword ::sm/plugin-data]]])
+ [:map-of {:gen/max 5} :keyword ::ctpg/plugin-data]]])
(def check-typography!
(sm/check-fn ::typography))
diff --git a/frontend/resources/images/icons/puzzle.svg b/frontend/resources/images/icons/puzzle.svg
index 6e978bac53..ceef3a54b4 100644
--- a/frontend/resources/images/icons/puzzle.svg
+++ b/frontend/resources/images/icons/puzzle.svg
@@ -1 +1 @@
-
+
diff --git a/frontend/resources/plugins-runtime/index.js b/frontend/resources/plugins-runtime/index.js
index 1d75c17b15..8b622aa539 100644
--- a/frontend/resources/plugins-runtime/index.js
+++ b/frontend/resources/plugins-runtime/index.js
@@ -7776,6 +7776,9 @@ function Ml(t, e) {
get selection() {
return o("content:read"), t.selection;
},
+ set selection(i) {
+ o("content:read"), t.selection = i;
+ },
get viewport() {
return t.viewport;
},
diff --git a/frontend/src/app/config.cljs b/frontend/src/app/config.cljs
index 286a179038..58d702f8b9 100644
--- a/frontend/src/app/config.cljs
+++ b/frontend/src/app/config.cljs
@@ -110,7 +110,7 @@
(def privacy-policy-uri (obj/get global "penpotPrivacyPolicyURI" "https://penpot.app/privacy"))
(def flex-help-uri (obj/get global "penpotGridHelpURI" "https://help.penpot.app/user-guide/flexible-layouts/"))
(def grid-help-uri (obj/get global "penpotGridHelpURI" "https://help.penpot.app/user-guide/flexible-layouts/"))
-(def plugins-list-uri (obj/get global "penpotPluginsListUri" "https://penpot-docs-plugins.netlify.app/technical-guide/plugins/getting-started/#examples"))
+(def plugins-list-uri (obj/get global "penpotPluginsListUri" "https://penpot-docs-plugins.pages.dev/technical-guide/plugins/getting-started/#examples"))
(defn- normalize-uri
[uri-str]
diff --git a/frontend/src/app/main/data/workspace/media.cljs b/frontend/src/app/main/data/workspace/media.cljs
index d97d0b8035..b3f5d48ec6 100644
--- a/frontend/src/app/main/data/workspace/media.cljs
+++ b/frontend/src/app/main/data/workspace/media.cljs
@@ -467,4 +467,5 @@
(watch [_ _ _]
(->> (svg->clj [name svg-string])
(rx/take 1)
- (rx/map #(svg/add-svg-shapes id % position {:change-selection? false}))))))
+ (rx/map #(svg/add-svg-shapes id % position {:ignore-selection? true
+ :change-selection? false}))))))
diff --git a/frontend/src/app/main/data/workspace/shortcuts.cljs b/frontend/src/app/main/data/workspace/shortcuts.cljs
index bd0071602e..87346de670 100644
--- a/frontend/src/app/main/data/workspace/shortcuts.cljs
+++ b/frontend/src/app/main/data/workspace/shortcuts.cljs
@@ -27,7 +27,8 @@
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.hooks.resize :as r]
- [app.util.dom :as dom]))
+ [app.util.dom :as dom]
+ [potok.v2.core :as ptk]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Shortcuts
@@ -563,7 +564,9 @@
:command (ds/c-mod "alt+p")
:subsections [:basics]
:fn #(when (features/active-feature? @st/state "plugins/runtime")
- (st/emit! (modal/show :plugin-management {})))}})
+ (st/emit!
+ (ptk/event ::ev/event {::ev/name "open-plugins-manager" ::ev/origin "workspace:shortcuts"})
+ (modal/show :plugin-management {})))}})
(def debug-shortcuts
;; PREVIEW
diff --git a/frontend/src/app/main/data/workspace/svg_upload.cljs b/frontend/src/app/main/data/workspace/svg_upload.cljs
index a11f8893bb..169e2dd3ed 100644
--- a/frontend/src/app/main/data/workspace/svg_upload.cljs
+++ b/frontend/src/app/main/data/workspace/svg_upload.cljs
@@ -64,7 +64,8 @@
([svg-data position]
(add-svg-shapes nil svg-data position nil))
- ([id svg-data position {:keys [change-selection?] :or {change-selection? false}}]
+ ([id svg-data position {:keys [change-selection? ignore-selection?]
+ :or {ignore-selection? false change-selection? true}}]
(ptk/reify ::add-svg-shapes
ptk/WatchEvent
(watch [it state _]
@@ -73,7 +74,7 @@
page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
frame-id (ctst/top-nested-frame objects position)
- selected (wsh/lookup-selected state)
+ selected (if ignore-selection? #{} (wsh/lookup-selected state))
base (cfh/get-base-shape objects selected)
selected-id (first selected)
diff --git a/frontend/src/app/main/ui/workspace/main_menu.cljs b/frontend/src/app/main/ui/workspace/main_menu.cljs
index 135cdc1b59..ea0fc54f41 100644
--- a/frontend/src/app/main/ui/workspace/main_menu.cljs
+++ b/frontend/src/app/main/ui/workspace/main_menu.cljs
@@ -630,13 +630,23 @@
(when (d/not-empty? plugins)
[:div {:class (stl/css :separator)}])
- (for [[idx {:keys [name] :as manifest}] (d/enumerate plugins)]
+ (for [[idx {:keys [name host] :as manifest}] (d/enumerate plugins)]
[:> dropdown-menu-item* {:key (dm/str "plugins-menu-" idx)
- :on-click #(uwp/open-plugin! manifest)
+ :on-click #(do
+ (st/emit! (ptk/event ::ev/event {::ev/name "start-plugin"
+ ::ev/origin "workspace:menu"
+ :name name
+ :host host}))
+ (uwp/open-plugin! manifest))
:class (stl/css :submenu-item)
:on-key-down (fn [event]
(when (kbd/enter? event)
- #(uwp/open-plugin! manifest)))}
+ #(do
+ (st/emit! (ptk/event ::ev/event {::ev/name "start-plugin"
+ ::ev/origin "workspace:menu"
+ :name name
+ :host host}))
+ (uwp/open-plugin! manifest))))}
[:span {:class (stl/css :item-name)} name]])])))
(mf/defc menu
@@ -699,7 +709,9 @@
(dom/stop-propagation event)
(reset! show-menu* false)
(reset! sub-menu* nil)
- (st/emit! (modal/show :plugin-management {}))))]
+ (st/emit!
+ (ptk/event ::ev/event {::ev/name "open-plugins-manager" ::ev/origin "workspace:menu"})
+ (modal/show :plugin-management {}))))]
[:*
diff --git a/frontend/src/app/main/ui/workspace/plugins.cljs b/frontend/src/app/main/ui/workspace/plugins.cljs
index d7db43950c..7a71cf4a00 100644
--- a/frontend/src/app/main/ui/workspace/plugins.cljs
+++ b/frontend/src/app/main/ui/workspace/plugins.cljs
@@ -10,6 +10,7 @@
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.config :as cf]
+ [app.main.data.events :as ev]
[app.main.data.modal :as modal]
[app.main.store :as st]
[app.main.ui.components.search-bar :refer [search-bar]]
@@ -21,6 +22,8 @@
[app.util.http :as http]
[app.util.i18n :as i18n :refer [tr]]
[beicon.v2.core :as rx]
+ [cuerdas.core :as str]
+ [potok.v2.core :as ptk]
[rumext.v2 :as mf]))
(def ^:private close-icon
@@ -111,6 +114,7 @@
(rx/subs!
(fn [body]
(let [plugin (plugins/parser-manifest plugin-url body)]
+ (st/emit! (ptk/event ::ev/event {::ev/name "install-plugin" :name (:name plugin) :url plugin-url}))
(modal/show!
:plugin-permissions
{:plugin plugin
@@ -126,6 +130,10 @@
handle-open-plugin
(mf/use-callback
(fn [manifest]
+ (st/emit! (ptk/event ::ev/event {::ev/name "start-plugin"
+ ::ev/origin "workspace:plugins"
+ :name (:name manifest)
+ :host (:host manifest)}))
(open-plugin! manifest)
(modal/hide!)))
@@ -134,6 +142,9 @@
(mf/deps plugins-state)
(fn [plugin-index]
(let [plugin (nth @plugins/pluginsdb plugin-index)]
+ (st/emit! (ptk/event ::ev/event {::ev/name "remove-plugin"
+ :name (:name plugin)
+ :host (:host plugin)}))
(plugins/remove-plugin! plugin)
(reset! plugins-state* @plugins/pluginsdb))))]
@@ -162,7 +173,10 @@
[:div {:class (stl/css :plugins-empty)}
[:div {:class (stl/css :plugins-empty-logo)} i/puzzle]
[:div {:class (stl/css :plugins-empty-text)} (tr "workspace.plugins.empty-plugins")]
- [:a {:class (stl/css :plugins-link) :href cf/plugins-list-uri :target "_blank"}
+ [:a {:class (stl/css :plugins-link)
+ :href cf/plugins-list-uri
+ :target "_blank"
+ :on-click #(st/emit! (ptk/event ::ev/event {::ev/name "open-plugins-list"}))}
(tr "workspace.plugins.plugin-list-link") i/external-link]]
[:*
@@ -182,7 +196,7 @@
::mf/register-as :plugin-permissions}
[{:keys [plugin on-accept]}]
- (let [{:keys [permissions]} plugin
+ (let [{:keys [host permissions]} plugin
permissions (set permissions)
handle-accept-dialog
@@ -190,12 +204,18 @@
(fn [event]
(dom/prevent-default event)
(st/emit! (modal/hide))
+ (ptk/event ::ev/event {::ev/name "allow-plugin-permissions"
+ :host host
+ :permissions (->> permissions (str/join ", "))})
(on-accept)))
handle-close-dialog
(mf/use-callback
(fn [event]
(dom/prevent-default event)
+ (ptk/event ::ev/event {::ev/name "reject-plugin-permissions"
+ :host host
+ :permissions (->> permissions (str/join ", "))})
(st/emit! (modal/hide))))]
[:div {:class (stl/css :modal-overlay)}
@@ -205,35 +225,38 @@
[:div {:class (stl/css :modal-content)}
[:div {:class (stl/css :permissions-list)}
- (when (contains? permissions "content:read")
+ (cond
+ (contains? permissions "content:write")
+ [:div {:class (stl/css :permissions-list-entry)}
+ i/oauth-1
+ [:p {:class (stl/css :permissions-list-text)}
+ (tr "workspace.plugins.permissions.content-write")]]
+
+ (contains? permissions "content:read")
[:div {:class (stl/css :permissions-list-entry)}
i/oauth-1
[:p {:class (stl/css :permissions-list-text)}
(tr "workspace.plugins.permissions.content-read")]])
- (when (contains? permissions "content:write")
- [:div {:class (stl/css :permissions-list-entry)}
- i/oauth-1
- [:p {:class (stl/css :permissions-list-text)}
- (tr "workspace.plugins.permissions.content-write")]])
-
- (when (contains? permissions "user:read")
+ (cond
+ (contains? permissions "user:read")
[:div {:class (stl/css :permissions-list-entry)}
i/oauth-2
[:p {:class (stl/css :permissions-list-text)}
(tr "workspace.plugins.permissions.user-read")]])
- (when (contains? permissions "library:read")
+ (cond
+ (contains? permissions "library:write")
[:div {:class (stl/css :permissions-list-entry)}
i/oauth-3
[:p {:class (stl/css :permissions-list-text)}
- (tr "workspace.plugins.permissions.library-read")]])
+ (tr "workspace.plugins.permissions.library-write")]]
- (when (contains? permissions "library:write")
+ (contains? permissions "library:read")
[:div {:class (stl/css :permissions-list-entry)}
i/oauth-3
[:p {:class (stl/css :permissions-list-text)}
- (tr "workspace.plugins.permissions.library-write")]])]
+ (tr "workspace.plugins.permissions.library-read")]])]
[:div {:class (stl/css :permissions-disclaimer)}
(tr "workspace.plugins.permissions.disclaimer")]]
diff --git a/frontend/src/app/main/ui/workspace/top_toolbar.cljs b/frontend/src/app/main/ui/workspace/top_toolbar.cljs
index dfbb3fe1ae..82e3444452 100644
--- a/frontend/src/app/main/ui/workspace/top_toolbar.cljs
+++ b/frontend/src/app/main/ui/workspace/top_toolbar.cljs
@@ -27,6 +27,7 @@
[app.util.i18n :as i18n :refer [tr]]
[app.util.timers :as ts]
[okulary.core :as l]
+ [potok.v2.core :as ptk]
[rumext.v2 :as mf]))
(mf/defc image-upload
@@ -200,7 +201,9 @@
{:title (tr "workspace.toolbar.plugins" (sc/get-tooltip :plugins))
:aria-label (tr "workspace.toolbar.plugins" (sc/get-tooltip :plugins))
:class (stl/css :main-toolbar-options-button)
- :on-click #(modal/show! :plugin-management {})
+ :on-click #(st/emit!
+ (ptk/event ::ev/event {::ev/name "open-plugins-manager" ::ev/origin "workspace:toolbar"})
+ (modal/show :plugin-management {}))
:data-tool "plugins"
:data-testid "plugins-btn"}
i/puzzle]])
diff --git a/frontend/src/app/plugins.cljs b/frontend/src/app/plugins.cljs
index 21e16d3c20..c66260e522 100644
--- a/frontend/src/app/plugins.cljs
+++ b/frontend/src/app/plugins.cljs
@@ -47,7 +47,16 @@
desc (obj/get manifest "description")
code (obj/get manifest "code")
icon (obj/get manifest "icon")
- permissions (obj/get manifest "permissions")
+
+ permissions (into #{} (obj/get manifest "permissions" []))
+ permissions
+ (cond-> permissions
+ (contains? permissions "content:write")
+ (conj "content:read")
+
+ (contains? permissions "library:write")
+ (conj "content:write"))
+
origin (obj/get (js/URL. plugin-url) "origin")
plugin-id (str (uuid/next))]
{:plugin-id plugin-id
diff --git a/frontend/src/app/plugins/api.cljs b/frontend/src/app/plugins/api.cljs
index 2cd3938a7f..076c9f0fa4 100644
--- a/frontend/src/app/plugins/api.cljs
+++ b/frontend/src/app/plugins/api.cljs
@@ -23,6 +23,7 @@
[app.main.data.workspace.colors :as dwc]
[app.main.data.workspace.groups :as dwg]
[app.main.data.workspace.media :as dwm]
+ [app.main.data.workspace.selection :as dws]
[app.main.store :as st]
[app.plugins.events :as events]
[app.plugins.file :as file]
@@ -356,7 +357,19 @@
{:name "root" :get #(.getRoot ^js %)}
{:name "currentFile" :get #(.getFile ^js %)}
{:name "currentPage" :get #(.getPage ^js %)}
- {:name "selection" :get #(.getSelectedShapes ^js %)}
+
+ {:name "selection"
+ :get #(.getSelectedShapes ^js %)
+ :set
+ (fn [_ shapes]
+ (cond
+ (or (not (array? shapes)) (not (every? shape/shape-proxy? shapes)))
+ (u/display-not-valid :selection shapes)
+
+ :else
+ (let [ids (into (d/ordered-set) (map #(obj/get % "$id")) shapes)]
+ (st/emit! (dws/select-shapes ids)))))}
+
{:name "viewport" :get #(.getViewport ^js %)}
{:name "currentUser" :get #(.getCurrentUser ^js %)}
{:name "activeUsers" :get #(.getActiveUsers ^js %)}
diff --git a/frontend/src/app/plugins/parser.cljs b/frontend/src/app/plugins/parser.cljs
index 3180a0e4b7..53092c5697 100644
--- a/frontend/src/app/plugins/parser.cljs
+++ b/frontend/src/app/plugins/parser.cljs
@@ -229,8 +229,8 @@
(when (some? export)
(d/without-nils
{:type (-> (obj/get export "type") parse-keyword)
- :scale (obj/get export "scale")
- :suffix (obj/get export "suffix")})))
+ :scale (obj/get export "scale" 1)
+ :suffix (obj/get export "suffix" "")})))
(defn parse-exports
[^js exports]
diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs
index 727b2c70c9..2ae9b0d399 100644
--- a/frontend/src/app/plugins/shape.cljs
+++ b/frontend/src/app/plugins/shape.cljs
@@ -36,6 +36,7 @@
[app.main.data.workspace.shape-layout :as dwsl]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.texts :as dwt]
+ [app.main.repo :as rp]
[app.main.store :as st]
[app.plugins.flex :as flex]
[app.plugins.format :as format]
@@ -46,7 +47,9 @@
[app.plugins.utils :as u]
[app.util.object :as obj]
[app.util.path.format :as upf]
- [cuerdas.core :as str]))
+ [beicon.v2.core :as rx]
+ [cuerdas.core :as str]
+ [promesa.core :as p]))
(def lib-typography-proxy? nil)
(def lib-component-proxy nil)
@@ -436,7 +439,34 @@
shape (u/proxy->shape self)]
(when (ctn/in-any-component? objects shape)
(let [[root component] (u/locate-component objects shape)]
- (lib-component-proxy $plugin (:component-file root) (:id component)))))))
+ (lib-component-proxy $plugin (:component-file root) (:id component))))))
+
+ (export
+ [self value]
+ (let [value (parser/parse-export value)]
+ (cond
+ (not (sm/validate ::ctse/export value))
+ (u/display-not-valid :export value)
+
+ :else
+ (let [payload
+ {:cmd :export-shapes
+ :profile-id (:profile-id @st/state)
+ :wait true
+ :exports [{:file-id $file
+ :page-id $page
+ :object-id $id
+ :name (obj/get self "name")
+ :type (:type value :png)
+ :suffix (:suffix value "")
+ :scale (:scale value 1)}]}]
+ (p/create
+ (fn [resolve reject]
+ (->> (rp/cmd! :export payload)
+ (rx/mapcat #(rp/cmd! :export {:cmd :get-resource :wait true :id (:id %) :blob? true}))
+ (rx/mapcat #(.arrayBuffer %))
+ (rx/map #(js/Uint8Array. %))
+ (rx/subs! resolve reject)))))))))
(defn shape-proxy? [p]
(instance? ShapeProxy p))
@@ -886,6 +916,12 @@
{:name "height"
:get #(-> % u/proxy->shape :height)}
+ {:name "bounds"
+ :get #(-> % u/proxy->shape :points grc/points->rect format/format-bounds)}
+
+ {:name "center"
+ :get #(-> % u/proxy->shape gsh/shape->center format/format-point)}
+
{:name "rotation"
:get #(-> % u/proxy->shape :rotation)
:set
diff --git a/frontend/test/frontend_tests/helpers/state.cljs b/frontend/test/frontend_tests/helpers/state.cljs
index 6c3c7cb2c7..37d245df5c 100644
--- a/frontend/test/frontend_tests/helpers/state.cljs
+++ b/frontend/test/frontend_tests/helpers/state.cljs
@@ -39,21 +39,25 @@
store))
(defn run-store
- [store done events completed-cb]
- (let [stream (ptk/input-stream store)]
- (->> stream
- (rx/take-until (rx/filter #(= :the/end %) stream))
- (rx/last)
- (rx/tap (fn []
- (completed-cb @store)))
- (rx/subs! (fn [_] (done))
- (fn [cause]
- (js/console.log "[error]:" cause))
- (fn [_]
- (js/console.log "[complete]"))))
- (doall (for [event events]
- (ptk/emit! store event)))
- (ptk/emit! store :the/end)))
+ ([store done events completed-cb]
+ (run-store store done events completed-cb nil))
+ ([store done events completed-cb stopper]
+ (let [stream (ptk/input-stream store)]
+ (->> stream
+ (rx/take-until (if stopper
+ (stopper stream)
+ (rx/filter #(= :the/end %) stream)))
+ (rx/last)
+ (rx/tap (fn []
+ (completed-cb @store)))
+ (rx/subs! (fn [_] (done))
+ (fn [cause]
+ (js/console.log "[error]:" cause))
+ (fn [_]
+ (js/console.log "[complete]"))))
+ (doall (for [event events]
+ (ptk/emit! store event)))
+ (ptk/emit! store :the/end))))
(defn get-file-from-store
[store]
diff --git a/frontend/translations/en.po b/frontend/translations/en.po
index b05464a4c9..5e90a19512 100644
--- a/frontend/translations/en.po
+++ b/frontend/translations/en.po
@@ -5281,6 +5281,9 @@ msgstr "Plugin correctly loaded."
msgid "workspace.plugins.menu.title"
msgstr "Plugins"
+msgid "workspace.toolbar.plugins"
+msgstr "Plugins"
+
msgid "workspace.plugins.menu.plugins-manager"
msgstr "Plugins manager"
diff --git a/frontend/translations/es.po b/frontend/translations/es.po
index c226af8922..407f37cd58 100644
--- a/frontend/translations/es.po
+++ b/frontend/translations/es.po
@@ -5361,6 +5361,9 @@ msgstr "Pulsar para cerrar la ruta"
msgid "workspace.plugins.title"
msgstr "Extensiones"
+msgid "workspace.toolbar.plugins"
+msgstr "Extensiones"
+
msgid "workspace.plugins.search-placeholder"
msgstr "Intruduzca URL de la extensión"