mirror of
https://github.com/penpot/penpot.git
synced 2025-04-12 15:01:28 -05:00
Merge pull request #4816 from penpot/alotor-plugins-2
Improvements over plugins subsystem
This commit is contained in:
commit
62cea62356
35 changed files with 3316 additions and 1526 deletions
1
frontend/resources/images/icons/oauth-1.svg
Normal file
1
frontend/resources/images/icons/oauth-1.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M7.32 2.25H4.417A2.168 2.168 0 0 0 2.25 4.418v2.61M7.32 21.75H4.417c-1.197 0-2.167-1.263-2.167-2.46v-2.61m19.5-9.36V4.418a2.168 2.168 0 0 0-2.168-2.168H16.68m5.07 14.43v2.903a2.168 2.168 0 0 1-2.168 2.167H16.68M15.496 7.5H8.499a1.001 1.001 0 0 0-1.001 1.001V15.5a1 1 0 0 0 1.001 1h6.997a1 1 0 0 0 1.001-1V8.501A1 1 0 0 0 15.496 7.5Z" style="stroke-width: 1; stroke-linecap: round;"/></svg>
|
After Width: | Height: | Size: 462 B |
1
frontend/resources/images/icons/oauth-2.svg
Normal file
1
frontend/resources/images/icons/oauth-2.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M20.888 22v-2.222a4.444 4.444 0 0 0-4.443-4.444h-8.89a4.444 4.444 0 0 0-4.443 4.444V22M12 10.889a4.445 4.445 0 1 0 .172-8.888A4.445 4.445 0 0 0 12 10.889Z" style="stroke-width: 1; stroke-opacity: 1; stroke-linecap: round;"/></svg>
|
After Width: | Height: | Size: 303 B |
1
frontend/resources/images/icons/oauth-3.svg
Normal file
1
frontend/resources/images/icons/oauth-3.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M6.5 2H20v20H6.5a2.5 2.5 0 0 1-2.499-2.436L4 19.5v-15A2.5 2.5 0 0 1 6.5 2ZM20 17h0ZH6.5a2.5 2.5 0 0 0-2.499 2.436" style="stroke-width: 1; stroke-linecap: round;" /></svg>
|
After Width: | Height: | Size: 244 B |
1
frontend/resources/images/icons/puzzle.svg
Normal file
1
frontend/resources/images/icons/puzzle.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19.439 7.85c-.049.322.059.648.289.878l1.568 1.568c.47.47.706 1.087.706 1.704s-.235 1.233-.706 1.704l-1.611 1.611a.98.98 0 0 1-.837.276c-.47-.07-.802-.48-.968-.925a2.501 2.501 0 1 0-3.214 3.214c.446.166.855.497.925.968a.979.979 0 0 1-.276.837l-1.61 1.61a2.404 2.404 0 0 1-1.705.707 2.402 2.402 0 0 1-1.704-.706l-1.568-1.568a1.026 1.026 0 0 0-.877-.29c-.493.074-.84.504-1.02.968a2.5 2.5 0 1 1-3.237-3.237c.464-.18.894-.527.967-1.02a1.026 1.026 0 0 0-.289-.877l-1.568-1.568A2.402 2.402 0 0 1 1.998 12c0-.617.236-1.234.706-1.704L4.23 8.77c.24-.24.581-.353.917-.303.515.077.877.528 1.073 1.01a2.5 2.5 0 1 0 3.259-3.259c-.482-.196-.933-.558-1.01-1.073-.05-.336.062-.676.303-.917l1.525-1.525A2.402 2.402 0 0 1 12 1.998c.617 0 1.234.236 1.704.706l1.568 1.568c.23.23.556.338.877.29.493-.074.84-.504 1.02-.968a2.5 2.5 0 1 1 3.237 3.237c-.464.18-.894.527-.967 1.02Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
After Width: | Height: | Size: 1,021 B |
File diff suppressed because it is too large
Load diff
|
@ -110,6 +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"))
|
||||
|
||||
(defn- normalize-uri
|
||||
[uri-str]
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
[app.util.color :as uc]
|
||||
[app.util.storage :refer [storage]]
|
||||
[beicon.v2.core :as rx]
|
||||
[cuerdas.core :as str]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
||||
;; A set of keys that are used for shared state identifiers
|
||||
|
@ -377,7 +378,7 @@
|
|||
|
||||
(defn color-att->text
|
||||
[color]
|
||||
{:fill-color (:color color)
|
||||
{:fill-color (when (:color color) (str/lower (:color color)))
|
||||
:fill-opacity (:opacity color)
|
||||
:fill-color-ref-id (:id color)
|
||||
:fill-color-ref-file (:file-id color)
|
||||
|
|
|
@ -71,6 +71,13 @@
|
|||
(defn get-font-data [id]
|
||||
(get @fontsdb id))
|
||||
|
||||
(defn find-font-data [data]
|
||||
(d/seek
|
||||
(fn [font]
|
||||
(= (select-keys font (keys data))
|
||||
data))
|
||||
(vals @fontsdb)))
|
||||
|
||||
(defn resolve-variants
|
||||
[id]
|
||||
(get-in @fontsdb [id :variants]))
|
||||
|
@ -249,6 +256,11 @@
|
|||
(or (d/seek #(= (:id %) font-variant-id) variants)
|
||||
(get-default-variant font)))
|
||||
|
||||
(defn find-variant
|
||||
[{:keys [variants] :as font} variant-data]
|
||||
(let [props (keys variant-data)]
|
||||
(d/seek #(= (select-keys % props) variant-data) variants)))
|
||||
|
||||
;; Font embedding functions
|
||||
(defn get-node-fonts
|
||||
"Extracts the fonts used by some node"
|
||||
|
|
|
@ -178,6 +178,9 @@
|
|||
(def ^:icon msg-success (icon-xref :msg-success))
|
||||
(def ^:icon msg-warning (icon-xref :msg-warning))
|
||||
(def ^:icon open-link (icon-xref :open-link))
|
||||
(def ^:icon oauth-1 (icon-xref :oauth-1))
|
||||
(def ^:icon oauth-2 (icon-xref :oauth-2))
|
||||
(def ^:icon oauth-3 (icon-xref :oauth-3))
|
||||
(def ^:icon padding-bottom (icon-xref :padding-bottom))
|
||||
(def ^:icon padding-extended (icon-xref :padding-extended))
|
||||
(def ^:icon padding-left (icon-xref :padding-left))
|
||||
|
@ -190,6 +193,7 @@
|
|||
(def ^:icon picker (icon-xref :picker))
|
||||
(def ^:icon pin (icon-xref :pin))
|
||||
(def ^:icon play (icon-xref :play))
|
||||
(def ^:icon puzzle (icon-xref :puzzle))
|
||||
(def ^:icon rectangle (icon-xref :rectangle))
|
||||
(def ^:icon reload (icon-xref :reload))
|
||||
(def ^:icon remove-icon (icon-xref :remove))
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
[app.main.ui.hooks.resize :as r]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.main.ui.workspace.plugins :as uwp]
|
||||
[app.plugins :as plugins]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
|
@ -608,7 +609,7 @@
|
|||
::mf/wrap [mf/memo]}
|
||||
[{:keys [open-plugins on-close]}]
|
||||
(when (features/active-feature? @st/state "plugins/runtime")
|
||||
(let [plugins (uwp/load-from-store)]
|
||||
(let [plugins @plugins/pluginsdb]
|
||||
[:& dropdown-menu {:show true
|
||||
:list-class (stl/css-case :sub-menu true :plugins true)
|
||||
:on-close on-close}
|
||||
|
|
|
@ -9,22 +9,23 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.config :as cf]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.search-bar :refer [search-bar]]
|
||||
[app.main.ui.components.title-bar :refer [title-bar]]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.plugins :as plugins]
|
||||
[app.util.avatars :as avatars]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.http :as http]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.object :as obj]
|
||||
[beicon.v2.core :as rx]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private close-icon
|
||||
(i/icon-xref :close (stl/css :close-icon)))
|
||||
|
||||
|
||||
(mf/defc plugin-entry
|
||||
[{:keys [index manifest on-open-plugin on-remove-plugin]}]
|
||||
|
||||
|
@ -55,20 +56,6 @@
|
|||
[:button {:class (stl/css :trash-button)
|
||||
:on-click handle-delete-click} i/delete]]))
|
||||
|
||||
(defn load-from-store
|
||||
[]
|
||||
(let [ls (.-localStorage js/window)
|
||||
plugins-val (.getItem ls "plugins")]
|
||||
(when plugins-val
|
||||
(let [plugins-js (.parse js/JSON plugins-val)]
|
||||
(js->clj plugins-js {:keywordize-keys true})))))
|
||||
|
||||
(defn save-to-store
|
||||
[plugins]
|
||||
(let [ls (.-localStorage js/window)
|
||||
plugins-js (clj->js plugins)
|
||||
plugins-val (.stringify js/JSON plugins-js)]
|
||||
(.setItem ls "plugins" plugins-val)))
|
||||
|
||||
(defn open-plugin!
|
||||
[{:keys [plugin-id name description host code icon permissions]}]
|
||||
|
@ -90,7 +77,7 @@
|
|||
::mf/register-as :plugin-management}
|
||||
[]
|
||||
|
||||
(let [plugins-state* (mf/use-state [])
|
||||
(let [plugins-state* (mf/use-state @plugins/pluginsdb)
|
||||
plugins-state @plugins-state*
|
||||
|
||||
plugin-url* (mf/use-state "")
|
||||
|
@ -123,27 +110,16 @@
|
|||
(rx/map :body)
|
||||
(rx/subs!
|
||||
(fn [body]
|
||||
(let [name (obj/get body "name")
|
||||
desc (obj/get body "description")
|
||||
code (obj/get body "code")
|
||||
icon (obj/get body "icon")
|
||||
permissions (obj/get body "permissions")
|
||||
origin (obj/get (js/URL. plugin-url) "origin")
|
||||
plugin-id (str (uuid/next))
|
||||
|
||||
new-state
|
||||
(conj plugins-state
|
||||
{:plugin-id plugin-id
|
||||
:name name
|
||||
:description desc
|
||||
:host origin
|
||||
:code code
|
||||
:icon icon
|
||||
:permissions (->> permissions (mapv str))})]
|
||||
(let [plugin (plugins/parser-manifest plugin-url body)]
|
||||
(modal/show!
|
||||
:plugin-permissions
|
||||
{:plugin plugin
|
||||
:on-accept
|
||||
#(do
|
||||
(plugins/install-plugin! plugin)
|
||||
(modal/show! :plugin-management {}))})
|
||||
(reset! input-status* :success)
|
||||
(reset! plugin-url* "")
|
||||
(reset! plugins-state* new-state)
|
||||
(save-to-store new-state)))
|
||||
(reset! plugin-url* "")))
|
||||
(fn [_]
|
||||
(reset! input-status* :error-url))))))
|
||||
|
||||
|
@ -157,21 +133,12 @@
|
|||
(mf/use-callback
|
||||
(mf/deps plugins-state)
|
||||
(fn [plugin-index]
|
||||
(let [new-state
|
||||
(into []
|
||||
(keep-indexed (fn [idx item]
|
||||
(when (not= idx plugin-index) item)))
|
||||
plugins-state)]
|
||||
|
||||
(reset! plugins-state* new-state)
|
||||
(save-to-store new-state))))]
|
||||
|
||||
(mf/use-effect
|
||||
(fn []
|
||||
(reset! plugins-state* (d/nilv (load-from-store) []))))
|
||||
(let [plugin (nth @plugins/pluginsdb plugin-index)]
|
||||
(plugins/remove-plugin! plugin)
|
||||
(reset! plugins-state* @plugins/pluginsdb))))]
|
||||
|
||||
[:div {:class (stl/css :modal-overlay)}
|
||||
[:div {:class (stl/css :modal-dialog)}
|
||||
[:div {:class (stl/css :modal-dialog :plugin-management)}
|
||||
[:button {:class (stl/css :close-btn) :on-click handle-close-dialog} close-icon]
|
||||
[:div {:class (stl/css :modal-title)} (tr "workspace.plugins.title")]
|
||||
|
||||
|
@ -183,7 +150,6 @@
|
|||
:class (stl/css-case :input-error error?)}]
|
||||
|
||||
[:button {:class (stl/css :primary-button)
|
||||
:disabled (empty? plugin-url)
|
||||
:on-click handle-install-click} (tr "workspace.plugins.install")]]
|
||||
|
||||
(when error?
|
||||
|
@ -194,9 +160,9 @@
|
|||
|
||||
(if (empty? plugins-state)
|
||||
[:div {:class (stl/css :plugins-empty)}
|
||||
[:div {:class (stl/css :plugins-empty-logo)} i/rocket]
|
||||
[: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 "#"}
|
||||
[:a {:class (stl/css :plugins-link) :href cf/plugins-list-uri :target "_blank"}
|
||||
(tr "workspace.plugins.plugin-list-link") i/external-link]]
|
||||
|
||||
[:*
|
||||
|
@ -204,10 +170,84 @@
|
|||
:title (tr "workspace.plugins.installed-plugins")}]
|
||||
|
||||
[:div {:class (stl/css :plugins-list)}
|
||||
|
||||
(for [[idx manifest] (d/enumerate plugins-state)]
|
||||
[:& plugin-entry {:key (dm/str "plugin-" idx)
|
||||
:index idx
|
||||
:manifest manifest
|
||||
:on-open-plugin handle-open-plugin
|
||||
:on-remove-plugin handle-remove-plugin}])]])]]]))
|
||||
|
||||
(mf/defc plugins-permissions-dialog
|
||||
{::mf/register modal/components
|
||||
::mf/register-as :plugin-permissions}
|
||||
[{:keys [plugin on-accept]}]
|
||||
|
||||
(let [{:keys [permissions]} plugin
|
||||
permissions (set permissions)
|
||||
|
||||
handle-accept-dialog
|
||||
(mf/use-callback
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(st/emit! (modal/hide))
|
||||
(on-accept)))
|
||||
|
||||
handle-close-dialog
|
||||
(mf/use-callback
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(st/emit! (modal/hide))))]
|
||||
|
||||
[:div {:class (stl/css :modal-overlay)}
|
||||
[:div {:class (stl/css :modal-dialog :plugin-permissions)}
|
||||
[:button {:class (stl/css :close-btn) :on-click handle-close-dialog} close-icon]
|
||||
[:div {:class (stl/css :modal-title)} (tr "workspace.plugins.permissions.title")]
|
||||
|
||||
[:div {:class (stl/css :modal-content)}
|
||||
[:div {:class (stl/css :permissions-list)}
|
||||
(when (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.disclaimer")]])
|
||||
|
||||
(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-read")]])
|
||||
|
||||
(when (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.content-write")]])
|
||||
|
||||
(when (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.user-read")]])
|
||||
|
||||
(when (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")]])]
|
||||
|
||||
[:div {:class (stl/css :permissions-disclaimer)}
|
||||
(tr "workspace.plugins.permissions.library-write")]]
|
||||
|
||||
[:div {:class (stl/css :modal-footer)}
|
||||
[:div {:class (stl/css :action-buttons)}
|
||||
[:input
|
||||
{:class (stl/css :cancel-button :button-expand)
|
||||
:type "button"
|
||||
:value (tr "ds.confirm-cancel")
|
||||
:on-click handle-close-dialog}]
|
||||
|
||||
[:input
|
||||
{:class (stl/css :primary-button :button-expand)
|
||||
:type "button"
|
||||
:value (tr "ds.confirm-allow")
|
||||
:on-click handle-accept-dialog}]]]]]))
|
||||
|
|
|
@ -13,15 +13,27 @@
|
|||
.modal-dialog {
|
||||
@extend .modal-container-base;
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr;
|
||||
width: $s-472;
|
||||
max-width: $s-472;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
|
||||
&.plugin-permissions {
|
||||
width: $s-412;
|
||||
max-width: $s-412;
|
||||
}
|
||||
|
||||
&.plugin-management {
|
||||
width: $s-472;
|
||||
max-width: $s-472;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-color: $db-tertiary;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
@extend .modal-close-btn-base;
|
||||
}
|
||||
|
@ -40,8 +52,15 @@
|
|||
.modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: $s-380;
|
||||
max-height: $s-380;
|
||||
|
||||
.plugin-permissions & {
|
||||
gap: $s-20;
|
||||
}
|
||||
|
||||
.plugin-management & {
|
||||
height: $s-380;
|
||||
max-height: $s-380;
|
||||
}
|
||||
}
|
||||
|
||||
.primary-button {
|
||||
|
@ -50,6 +69,17 @@
|
|||
padding: $s-0 $s-16;
|
||||
}
|
||||
|
||||
.button-expand {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.cancel-button {
|
||||
@extend .button-secondary;
|
||||
@include headlineSmallTypography;
|
||||
padding: $s-0 $s-16;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
@include flexCenter;
|
||||
width: $s-20;
|
||||
|
@ -87,7 +117,7 @@
|
|||
.plugins-list {
|
||||
padding-top: $s-20;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -148,8 +178,8 @@
|
|||
svg {
|
||||
width: $s-16;
|
||||
height: $s-16;
|
||||
fill: $df-secondary;
|
||||
stroke-width: 0;
|
||||
stroke: $df-secondary;
|
||||
fill: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,3 +220,45 @@ div.input-error {
|
|||
fill: none;
|
||||
}
|
||||
}
|
||||
|
||||
.plugin-permissions {
|
||||
}
|
||||
|
||||
.permissions-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $s-24;
|
||||
}
|
||||
|
||||
.permissions-list-entry {
|
||||
display: grid;
|
||||
grid-template-columns: 24px 1fr;
|
||||
gap: $s-16;
|
||||
align-items: center;
|
||||
|
||||
svg {
|
||||
width: $s-24;
|
||||
height: $s-24;
|
||||
stroke: $da-primary;
|
||||
fill: none;
|
||||
}
|
||||
}
|
||||
|
||||
.permissions-list-text {
|
||||
@include bodySmallTypography;
|
||||
margin: 0;
|
||||
color: $df-secondary;
|
||||
}
|
||||
|
||||
.permissions-disclaimer {
|
||||
@include bodySmallTypography;
|
||||
padding: $s-16;
|
||||
background: $db-tertiary;
|
||||
color: $df-secondary;
|
||||
border-radius: $br-4;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: $s-12;
|
||||
}
|
||||
|
|
|
@ -11,11 +11,13 @@
|
|||
[app.common.geom.point :as gpt]
|
||||
[app.common.media :as cm]
|
||||
[app.main.data.events :as ev]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.data.workspace.media :as dwm]
|
||||
[app.main.data.workspace.path.state :as pst]
|
||||
[app.main.data.workspace.shortcuts :as sc]
|
||||
[app.main.features :as features]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
||||
|
@ -192,6 +194,17 @@
|
|||
:data-testid "path-btn"}
|
||||
i/path]]
|
||||
|
||||
(when (features/active-feature? @st/state "plugins/runtime")
|
||||
[:li
|
||||
[:button
|
||||
{: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 {})
|
||||
:data-tool "plugins"
|
||||
:data-testid "plugins-btn"}
|
||||
i/puzzle]])
|
||||
|
||||
(when *assert*
|
||||
[:li
|
||||
[:button
|
||||
|
|
|
@ -7,18 +7,25 @@
|
|||
(ns app.plugins
|
||||
"RPC for plugins runtime."
|
||||
(:require
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.features :as features]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.api :as api]
|
||||
[app.plugins.public-utils]
|
||||
[app.plugins.register :as register]
|
||||
[app.util.globals :refer [global]]
|
||||
[app.util.object :as obj]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
||||
(def pluginsdb register/pluginsdb)
|
||||
(def install-plugin! register/install-plugin!)
|
||||
(def remove-plugin! register/remove-plugin!)
|
||||
|
||||
(defn init-plugins-runtime!
|
||||
[]
|
||||
(when-let [init-runtime (obj/get global "initPluginsRuntime")]
|
||||
(register/init)
|
||||
(init-runtime (fn [plugin-id] (api/create-context plugin-id)))))
|
||||
|
||||
(defn initialize
|
||||
|
@ -33,3 +40,20 @@
|
|||
(rx/take 1)
|
||||
(rx/tap init-plugins-runtime!)
|
||||
(rx/ignore)))))
|
||||
|
||||
(defn parser-manifest
|
||||
[plugin-url ^js manifest]
|
||||
(let [name (obj/get manifest "name")
|
||||
desc (obj/get manifest "description")
|
||||
code (obj/get manifest "code")
|
||||
icon (obj/get manifest "icon")
|
||||
permissions (obj/get manifest "permissions")
|
||||
origin (obj/get (js/URL. plugin-url) "origin")
|
||||
plugin-id (str (uuid/next))]
|
||||
{:plugin-id plugin-id
|
||||
:name name
|
||||
:description desc
|
||||
:host origin
|
||||
:code code
|
||||
:icon icon
|
||||
:permissions (->> permissions (mapv str))}))
|
||||
|
|
|
@ -13,20 +13,24 @@
|
|||
[app.common.files.helpers :as cfh]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.record :as cr]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.text :as txt]
|
||||
[app.common.types.color :as ctc]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.changes :as ch]
|
||||
[app.main.data.workspace.bool :as dwb]
|
||||
[app.main.data.workspace.colors :as dwc]
|
||||
[app.main.data.workspace.groups :as dwg]
|
||||
[app.main.data.workspace.media :as dwm]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.events :as events]
|
||||
[app.plugins.file :as file]
|
||||
[app.plugins.fonts :as fonts]
|
||||
[app.plugins.format :as format]
|
||||
[app.plugins.library :as library]
|
||||
[app.plugins.page :as page]
|
||||
[app.plugins.parser :as parser]
|
||||
[app.plugins.shape :as shape]
|
||||
[app.plugins.user :as user]
|
||||
[app.plugins.utils :as u]
|
||||
|
@ -87,35 +91,52 @@
|
|||
(let [selection (get-in @st/state [:workspace-local :selected])]
|
||||
(apply array (sequence (map (partial shape/shape-proxy $plugin)) selection))))
|
||||
|
||||
(getColors
|
||||
(shapesColors
|
||||
[_ shapes]
|
||||
(let [objects (u/locate-objects)
|
||||
shapes (->> shapes
|
||||
(map #(obj/get % "$id"))
|
||||
(mapcat #(cfh/get-children-with-self objects %)))
|
||||
(cond
|
||||
(or (not (array? shapes)) (not (every? shape/shape-proxy? shapes)))
|
||||
(u/display-not-valid :shapesColors-shapes shapes)
|
||||
|
||||
file-id (:current-file-id @st/state)
|
||||
shared-libs (:workspace-libraries @st/state)
|
||||
:else
|
||||
(let [objects (u/locate-objects)
|
||||
shapes (->> shapes
|
||||
(map #(obj/get % "$id"))
|
||||
(mapcat #(cfh/get-children-with-self objects %)))
|
||||
file-id (:current-file-id @st/state)
|
||||
shared-libs (:workspace-libraries @st/state)]
|
||||
|
||||
colors
|
||||
(apply
|
||||
array
|
||||
(->> (ctc/extract-all-colors shapes file-id shared-libs)
|
||||
(group-by :attrs)
|
||||
(map (fn [[color attrs]]
|
||||
(let [shapes-info (apply array (map (fn [{:keys [prop shape-id index]}]
|
||||
#js {:property (d/name prop)
|
||||
:index index
|
||||
:shapeId (str shape-id)}) attrs))
|
||||
color (u/to-js color)]
|
||||
(obj/set! color "shapeInfo" shapes-info)
|
||||
color)))))]
|
||||
colors))
|
||||
(->> (ctc/extract-all-colors shapes file-id shared-libs)
|
||||
(group-by :attrs)
|
||||
(format/format-array format/format-color-result)))))
|
||||
|
||||
(changeColor
|
||||
[_ _shapes _old-color _new-color]
|
||||
;; TODO
|
||||
)
|
||||
(replaceColor
|
||||
[_ shapes old-color new-color]
|
||||
|
||||
(let [old-color (parser/parse-color old-color)
|
||||
new-color (parser/parse-color new-color)]
|
||||
(cond
|
||||
(or (not (array? shapes)) (not (every? shape/shape-proxy? shapes)))
|
||||
(u/display-not-valid :replaceColor-shapes shapes)
|
||||
|
||||
(not (sm/validate ::ctc/color old-color))
|
||||
(u/display-not-valid :replaceColor-oldColor old-color)
|
||||
|
||||
(not (sm/validate ::ctc/color new-color))
|
||||
(u/display-not-valid :replaceColor-newColor new-color)
|
||||
|
||||
:else
|
||||
(let [file-id (:current-file-id @st/state)
|
||||
shared-libs (:workspace-libraries @st/state)
|
||||
objects (u/locate-objects)
|
||||
shapes
|
||||
(->> shapes
|
||||
(map #(obj/get % "$id"))
|
||||
(mapcat #(cfh/get-children-with-self objects %)))
|
||||
|
||||
shapes-by-color
|
||||
(->> (ctc/extract-all-colors shapes file-id shared-libs)
|
||||
(group-by :attrs))]
|
||||
(st/emit! (dwc/change-color-in-selected new-color (get shapes-by-color old-color) old-color))))))
|
||||
|
||||
(getRoot
|
||||
[_]
|
||||
|
@ -154,8 +175,8 @@
|
|||
(p/create
|
||||
(fn [resolve reject]
|
||||
(->> (dwm/upload-media-url name file-id url)
|
||||
(rx/map u/to-js)
|
||||
(rx/take 1)
|
||||
(rx/map format/format-image)
|
||||
(rx/subs! resolve reject)))))))
|
||||
|
||||
(uploadMediaData
|
||||
|
@ -171,7 +192,7 @@
|
|||
:on-image identity
|
||||
:on-svg identity})
|
||||
(rx/take 1)
|
||||
(rx/map u/to-js)
|
||||
(rx/map format/format-image)
|
||||
(rx/subs! resolve reject))))))
|
||||
|
||||
(group
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
(ns app.plugins.events
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.file :as file]
|
||||
[app.plugins.page :as page]
|
||||
|
@ -24,25 +23,19 @@
|
|||
|
||||
(defmethod handle-state-change "filechange"
|
||||
[_ plugin-id old-val new-val]
|
||||
(let [old-file (:workspace-file old-val)
|
||||
new-file (:workspace-file new-val)
|
||||
old-data (:workspace-data old-val)
|
||||
new-data (:workspace-data new-val)]
|
||||
(if (and (identical? old-file new-file)
|
||||
(identical? old-data new-data))
|
||||
(let [old-file-id (:current-file-id old-val)
|
||||
new-file-id (:current-file-id new-val)]
|
||||
(if (identical? old-file-id new-file-id)
|
||||
::not-changed
|
||||
(file/file-proxy plugin-id (:id new-file)))))
|
||||
(file/file-proxy plugin-id new-file-id))))
|
||||
|
||||
(defmethod handle-state-change "pagechange"
|
||||
[_ plugin-id old-val new-val]
|
||||
(let [file-id (:current-file-id new-val)
|
||||
old-page-id (:current-page-id old-val)
|
||||
new-page-id (:current-page-id new-val)
|
||||
old-page (dm/get-in old-val [:workspace-data :pages-index old-page-id])
|
||||
new-page (dm/get-in new-val [:workspace-data :pages-index new-page-id])]
|
||||
(if (identical? old-page new-page)
|
||||
(let [old-page-id (:current-page-id old-val)
|
||||
new-page-id (:current-page-id new-val)]
|
||||
(if (identical? old-page-id new-page-id)
|
||||
::not-changed
|
||||
(page/page-proxy plugin-id file-id new-page-id))))
|
||||
(page/page-proxy plugin-id (:current-file-id new-val) new-page-id))))
|
||||
|
||||
(defmethod handle-state-change "selectionchange"
|
||||
[_ _ old-val new-val]
|
||||
|
@ -75,7 +68,10 @@
|
|||
(fn [_ _ old-val new-val]
|
||||
(let [result (handle-state-change type plugin-id old-val new-val)]
|
||||
(when (not= ::not-changed result)
|
||||
(callback result)))))
|
||||
(try
|
||||
(callback result)
|
||||
(catch :default cause
|
||||
(.error js/console cause)))))))
|
||||
|
||||
;; return the generated key
|
||||
key))
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
[app.main.data.workspace :as dw]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.page :as page]
|
||||
[app.plugins.register :as r]
|
||||
[app.plugins.utils :as u]
|
||||
[app.util.object :as obj]))
|
||||
|
||||
|
@ -26,7 +27,7 @@
|
|||
[self key]
|
||||
(cond
|
||||
(not (string? key))
|
||||
(u/display-not-valid :file-plugin-data-key key)
|
||||
(u/display-not-valid :getPluginData-key key)
|
||||
|
||||
:else
|
||||
(let [file (u/proxy->file self)]
|
||||
|
@ -36,10 +37,13 @@
|
|||
[_ key value]
|
||||
(cond
|
||||
(or (not (string? key)) (empty? key))
|
||||
(u/display-not-valid :file-plugin-data-key key)
|
||||
(u/display-not-valid :setPluginData-key key)
|
||||
|
||||
(and (some? value) (not (string? value)))
|
||||
(u/display-not-valid :file-plugin-data value)
|
||||
(u/display-not-valid :setPluginData-value value)
|
||||
|
||||
(not (r/check-permission $plugin "content:write"))
|
||||
(u/display-not-valid :setPluginData "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dw/set-plugin-data $id :file (keyword "plugin" (str $plugin)) key value))))
|
||||
|
@ -53,10 +57,10 @@
|
|||
[self namespace key]
|
||||
(cond
|
||||
(not (string? namespace))
|
||||
(u/display-not-valid :file-plugin-data-namespace namespace)
|
||||
(u/display-not-valid :getSharedPluginData-namespace namespace)
|
||||
|
||||
(not (string? key))
|
||||
(u/display-not-valid :file-plugin-data-key key)
|
||||
(u/display-not-valid :getSharedPluginData-key key)
|
||||
|
||||
:else
|
||||
(let [file (u/proxy->file self)]
|
||||
|
@ -67,13 +71,16 @@
|
|||
|
||||
(cond
|
||||
(or (not (string? namespace)) (empty? namespace))
|
||||
(u/display-not-valid :file-plugin-data-namespace namespace)
|
||||
(u/display-not-valid :setSharedPluginData-namespace namespace)
|
||||
|
||||
(or (not (string? key)) (empty? key))
|
||||
(u/display-not-valid :file-plugin-data-key key)
|
||||
(u/display-not-valid :setSharedPluginData-key key)
|
||||
|
||||
(and (some? value) (not (string? value)))
|
||||
(u/display-not-valid :file-plugin-data value)
|
||||
(u/display-not-valid :setSharedPluginData-value value)
|
||||
|
||||
(not (r/check-permission $plugin "content:write"))
|
||||
(u/display-not-valid :setSharedPluginData "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dw/set-plugin-data $id :file (keyword "shared" namespace) key value))))
|
||||
|
@ -82,7 +89,7 @@
|
|||
[self namespace]
|
||||
(cond
|
||||
(not (string? namespace))
|
||||
(u/display-not-valid :file-plugin-data-namespace namespace)
|
||||
(u/display-not-valid :getSharedPluginDataKeys namespace)
|
||||
|
||||
:else
|
||||
(let [file (u/proxy->file self)]
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
[app.main.data.workspace.shape-layout :as dwsl]
|
||||
[app.main.data.workspace.transforms :as dwt]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.register :as r]
|
||||
[app.plugins.utils :as u]
|
||||
[app.util.object :as obj]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
@ -58,6 +59,9 @@
|
|||
(not (contains? ctl/flex-direction-types value))
|
||||
(u/display-not-valid :dir value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :dir "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-flex-dir value}))))))}
|
||||
|
@ -71,6 +75,9 @@
|
|||
(not (contains? ctl/align-items-types value))
|
||||
(u/display-not-valid :alignItems value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :alignItems "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-align-items value}))))))}
|
||||
|
@ -84,6 +91,9 @@
|
|||
(not (contains? ctl/align-content-types value))
|
||||
(u/display-not-valid :alignContent value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :alignContent "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-align-content value}))))))}
|
||||
|
@ -97,6 +107,9 @@
|
|||
(not (contains? ctl/justify-items-types value))
|
||||
(u/display-not-valid :justifyItems value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :justifyItems "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-justify-items value}))))))}
|
||||
|
@ -110,6 +123,9 @@
|
|||
(not (contains? ctl/justify-content-types value))
|
||||
(u/display-not-valid :justifyContent value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :justifyContent "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-justify-content value}))))))}
|
||||
|
@ -122,6 +138,9 @@
|
|||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :rowGap value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :rowGap "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-gap {:row-gap value}})))))}
|
||||
|
@ -134,6 +153,9 @@
|
|||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :columnGap value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :columnGap "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-gap {:column-gap value}})))))}
|
||||
|
@ -146,6 +168,9 @@
|
|||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :verticalPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :verticalPadding "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p1 value :p3 value}})))))}
|
||||
|
@ -158,6 +183,9 @@
|
|||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :horizontalPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :horizontalPadding "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value :p4 value}})))))}
|
||||
|
@ -171,6 +199,9 @@
|
|||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :topPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :topPadding "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p1 value}})))))}
|
||||
|
@ -183,6 +214,9 @@
|
|||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :rightPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :rightPadding "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value}})))))}
|
||||
|
@ -195,6 +229,9 @@
|
|||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :bottomPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :bottomPadding "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p3 value}})))))}
|
||||
|
@ -207,6 +244,9 @@
|
|||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :leftPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :leftPadding "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p4 value}})))))})))
|
||||
|
@ -234,6 +274,9 @@
|
|||
(not (boolean? value))
|
||||
(u/display-not-valid :absolute value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :absolute "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-item-absolute value})))))}
|
||||
|
@ -246,6 +289,9 @@
|
|||
(us/safe-int? value)
|
||||
(u/display-not-valid :zIndex value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :zIndex "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-z-index value})))))}
|
||||
|
@ -259,6 +305,9 @@
|
|||
(not (contains? ctl/item-h-sizing-types value))
|
||||
(u/display-not-valid :horizontalPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :horizontalPadding "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-h-sizing value}))))))}
|
||||
|
@ -272,6 +321,9 @@
|
|||
(not (contains? ctl/item-v-sizing-types value))
|
||||
(u/display-not-valid :verticalSizing value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :verticalSizing "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-v-sizing value}))))))}
|
||||
|
@ -285,6 +337,9 @@
|
|||
(not (contains? ctl/item-align-self-types value))
|
||||
(u/display-not-valid :alignSelf value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :alignSelf "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-align-self value}))))))}
|
||||
|
@ -297,6 +352,9 @@
|
|||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :verticalMargin value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :verticalMargin "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-margin {:m1 value :m3 value}})))))}
|
||||
|
@ -309,6 +367,9 @@
|
|||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :horizontalMargin value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :horizontalMargin "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-margin {:m2 value :m4 value}})))))}
|
||||
|
@ -321,6 +382,9 @@
|
|||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :topMargin value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :topMargin "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-margin {:m1 value}})))))}
|
||||
|
@ -333,6 +397,9 @@
|
|||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :rightMargin value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :rightMargin "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-margin {:m2 value}})))))}
|
||||
|
@ -345,6 +412,9 @@
|
|||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :bottomMargin value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :bottomMargin "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-margin {:m3 value}})))))}
|
||||
|
@ -357,6 +427,9 @@
|
|||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :leftMargin value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :leftMargin "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-margin {:m4 value}})))))}
|
||||
|
@ -369,6 +442,9 @@
|
|||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :maxWidth value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :maxWidth "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-max-w value})))))}
|
||||
|
@ -381,6 +457,9 @@
|
|||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :minWidth value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :minWidth "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-min-w value})))))}
|
||||
|
@ -393,6 +472,9 @@
|
|||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :maxHeight value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :maxHeight "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-max-h value})))))}
|
||||
|
@ -405,6 +487,9 @@
|
|||
(not (us/safe-number? value))
|
||||
(u/display-not-valid :minHeight value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :minHeight "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-min-h value})))))})))
|
||||
|
|
|
@ -11,13 +11,18 @@
|
|||
[app.main.data.workspace.texts :as dwt]
|
||||
[app.main.fonts :as fonts]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.register :as r]
|
||||
[app.plugins.shape :as shape]
|
||||
[app.plugins.text :as text]
|
||||
[app.plugins.utils :as u]
|
||||
[app.util.object :as obj]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
(deftype PenpotFontVariant [name fontVariantId fontWeight fontStyle])
|
||||
|
||||
(defn variant-proxy? [p]
|
||||
(instance? PenpotFontVariant p))
|
||||
|
||||
(deftype PenpotFont [name fontId fontFamily fontStyle fontVariantId fontWeight variants]
|
||||
Object
|
||||
|
||||
|
@ -26,7 +31,8 @@
|
|||
(not (shape/shape-proxy? text))
|
||||
(u/display-not-valid :applyToText text)
|
||||
|
||||
;; TODO: Check variant inside font variants
|
||||
(not (r/check-permission (obj/get text "$plugin") "content:write"))
|
||||
(u/display-not-valid :applyToText "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get text "$id")
|
||||
|
@ -39,10 +45,11 @@
|
|||
|
||||
(applyToRange [_ range variant]
|
||||
(cond
|
||||
(not (shape/text-range? range))
|
||||
(not (text/text-range? range))
|
||||
(u/display-not-valid :applyToRange range)
|
||||
|
||||
;; TODO: Check variant inside font variants
|
||||
(not (r/check-permission (obj/get range "$plugin") "content:write"))
|
||||
(u/display-not-valid :applyToRange "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get range "$id")
|
||||
|
@ -59,13 +66,13 @@
|
|||
(instance? PenpotFont p))
|
||||
|
||||
(defn font-proxy
|
||||
[{:keys [id name variants] :as font}]
|
||||
[{:keys [id family name variants] :as font}]
|
||||
(when (some? font)
|
||||
(let [default-variant (fonts/get-default-variant font)]
|
||||
(PenpotFont.
|
||||
name
|
||||
id
|
||||
id
|
||||
family
|
||||
(:style default-variant)
|
||||
(:id default-variant)
|
||||
(:weight default-variant)
|
||||
|
|
424
frontend/src/app/plugins/format.cljs
Normal file
424
frontend/src/app/plugins/format.cljs
Normal file
|
@ -0,0 +1,424 @@
|
|||
;; 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.plugins.format
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.util.object :as obj]))
|
||||
|
||||
(defn format-id
|
||||
[id]
|
||||
(when id (dm/str id)))
|
||||
|
||||
(defn format-key
|
||||
[kw]
|
||||
(when kw (d/name kw)))
|
||||
|
||||
(defn format-array
|
||||
[format-fn coll]
|
||||
(when (some? coll)
|
||||
(apply array (keep format-fn coll))))
|
||||
|
||||
(defn format-mixed
|
||||
[value]
|
||||
(if (= value :multiple)
|
||||
"mixed"
|
||||
value))
|
||||
|
||||
;; export type PenpotPoint = { x: number; y: number };
|
||||
(defn format-point
|
||||
[{:keys [x y] :as point}]
|
||||
(when (some? point)
|
||||
(obj/clear-empty
|
||||
#js {:x x :y y})))
|
||||
|
||||
;;export type PenpotBounds = {
|
||||
;; x: number;
|
||||
;; y: number;
|
||||
;; width: number;
|
||||
;; height: number;
|
||||
;;};
|
||||
(defn format-bounds
|
||||
[{:keys [x y width height] :as bounds}]
|
||||
(when (some? bounds)
|
||||
(obj/clear-empty
|
||||
#js {:x x :y y :width width :height height})))
|
||||
|
||||
;; export interface PenpotColorShapeInfoEntry {
|
||||
;; readonly property: string;
|
||||
;; readonly index?: number;
|
||||
;; readonly shapeId: string;
|
||||
;; }
|
||||
(defn format-shape-info
|
||||
[{:keys [prop shape-id index] :as info}]
|
||||
(when (some? info)
|
||||
(obj/clear-empty
|
||||
#js {:property (d/name prop)
|
||||
:index index
|
||||
:shapeId (dm/str shape-id)})))
|
||||
|
||||
;; export type PenpotGradient = {
|
||||
;; type: 'linear' | 'radial';
|
||||
;; startX: number;
|
||||
;; startY: number;
|
||||
;; endX: number;
|
||||
;; endY: number;
|
||||
;; width: number;
|
||||
;; stops: Array<{ color: string; opacity?: number; offset: number }>;
|
||||
;; };
|
||||
(defn format-stop
|
||||
[{:keys [color opacity offset] :as stop}]
|
||||
(when (some? stop)
|
||||
(obj/clear-empty #js {:color color :opacity opacity :offset offset})))
|
||||
|
||||
(defn format-gradient
|
||||
[{:keys [type start-x start-y end-x end-y width stops] :as gradient}]
|
||||
(when (some? gradient)
|
||||
(obj/clear-empty
|
||||
#js {:type (format-key type)
|
||||
:startX start-x
|
||||
:startY start-y
|
||||
:endX end-x
|
||||
:endY end-y
|
||||
:width width
|
||||
:stops (format-array format-stop stops)})))
|
||||
|
||||
;; export type PenpotImageData = {
|
||||
;; name?: string;
|
||||
;; width: number;
|
||||
;; height: number;
|
||||
;; mtype?: string;
|
||||
;; id: string;
|
||||
;; keepApectRatio?: boolean;
|
||||
;; };
|
||||
(defn format-image
|
||||
[{:keys [name width height mtype id keep-aspect-ratio] :as image}]
|
||||
(when (some? image)
|
||||
(obj/clear-empty
|
||||
#js {:name name
|
||||
:width width
|
||||
:height height
|
||||
:mtype mtype
|
||||
:id (format-id id)
|
||||
:keepAspectRatio keep-aspect-ratio})))
|
||||
|
||||
;; export interface PenpotColor {
|
||||
;; id?: string;
|
||||
;; name?: string;
|
||||
;; path?: string;
|
||||
;; color?: string;
|
||||
;; opacity?: number;
|
||||
;; refId?: string;
|
||||
;; refFile?: string;
|
||||
;; gradient?: PenpotGradient;
|
||||
;; image?: PenpotImageData;
|
||||
;; }
|
||||
(defn format-color
|
||||
[{:keys [id name path color opacity ref-id ref-file gradient image] :as color-data}]
|
||||
(when (some? color-data)
|
||||
(obj/clear-empty
|
||||
#js {:id (format-id id)
|
||||
:name name
|
||||
:path path
|
||||
:color color
|
||||
:opacity opacity
|
||||
:refId (format-id ref-id)
|
||||
:refFile (format-id ref-file)
|
||||
:gradient (format-gradient gradient)
|
||||
:image (format-image image)})))
|
||||
|
||||
;; PenpotColor & PenpotColorShapeInfo
|
||||
(defn format-color-result
|
||||
[[color attrs]]
|
||||
(let [shapes-info (apply array (map format-shape-info attrs))
|
||||
color (format-color color)]
|
||||
(obj/set! color "shapeInfo" shapes-info)
|
||||
color))
|
||||
|
||||
|
||||
;; export interface PenpotShadow {
|
||||
;; id?: string;
|
||||
;; style?: 'drop-shadow' | 'inner-shadow';
|
||||
;; offsetX?: number;
|
||||
;; offsetY?: number;
|
||||
;; blur?: number;
|
||||
;; spread?: number;
|
||||
;; hidden?: boolean;
|
||||
;; color?: PenpotColor;
|
||||
;; }
|
||||
(defn format-shadow
|
||||
[{:keys [id style offset-x offset-y blur spread hidden color] :as shadow}]
|
||||
(when (some? shadow)
|
||||
(obj/clear-empty
|
||||
#js {:id (-> id format-id)
|
||||
:style (-> style format-key)
|
||||
:offsetX offset-x
|
||||
:offsetY offset-y
|
||||
:blur blur
|
||||
:spread spread
|
||||
:hidden hidden
|
||||
:color (format-color color)})))
|
||||
|
||||
(defn format-shadows
|
||||
[shadows]
|
||||
(when (some? shadows)
|
||||
(format-array format-shadow shadows)))
|
||||
|
||||
;;export interface PenpotFill {
|
||||
;; fillColor?: string;
|
||||
;; fillOpacity?: number;
|
||||
;; fillColorGradient?: PenpotGradient;
|
||||
;; fillColorRefFile?: string;
|
||||
;; fillColorRefId?: string;
|
||||
;; fillImage?: PenpotImageData;
|
||||
;;}
|
||||
(defn format-fill
|
||||
[{:keys [fill-color fill-opacity fill-color-gradient fill-color-ref-file fill-color-ref-id fill-image] :as fill}]
|
||||
(when (some? fill)
|
||||
(obj/clear-empty
|
||||
#js {:fillColor fill-color
|
||||
:fillOpacity fill-opacity
|
||||
:fillColorGradient (format-gradient fill-color-gradient)
|
||||
:fillColorRefFile (format-id fill-color-ref-file)
|
||||
:fillColorRefId (format-id fill-color-ref-id)
|
||||
:fillImage (format-image fill-image)})))
|
||||
|
||||
(defn format-fills
|
||||
[fills]
|
||||
(cond
|
||||
(= fills :multiple)
|
||||
"mixed"
|
||||
|
||||
(= fills "mixed")
|
||||
"mixed"
|
||||
|
||||
(some? fills)
|
||||
(format-array format-fill fills)))
|
||||
|
||||
;; export interface PenpotStroke {
|
||||
;; strokeColor?: string;
|
||||
;; strokeColorRefFile?: string;
|
||||
;; strokeColorRefId?: string;
|
||||
;; strokeOpacity?: number;
|
||||
;; strokeStyle?: 'solid' | 'dotted' | 'dashed' | 'mixed' | 'none' | 'svg';
|
||||
;; strokeWidth?: number;
|
||||
;; strokeAlignment?: 'center' | 'inner' | 'outer';
|
||||
;; strokeCapStart?: PenpotStrokeCap;
|
||||
;; strokeCapEnd?: PenpotStrokeCap;
|
||||
;; strokeColorGradient?: PenpotGradient;
|
||||
;; }
|
||||
(defn format-stroke
|
||||
[{:keys [stroke-color stroke-color-ref-file stroke-color-ref-id
|
||||
stroke-opacity stroke-style stroke-width stroke-alignment
|
||||
stroke-cap-start stroke-cap-end stroke-color-gradient] :as stroke}]
|
||||
|
||||
(when (some? stroke)
|
||||
(obj/clear-empty
|
||||
#js {:strokeColor stroke-color
|
||||
:strokeColorRefFile (format-id stroke-color-ref-file)
|
||||
:strokeColorRefId (format-id stroke-color-ref-id)
|
||||
:strokeOpacity stroke-opacity
|
||||
:strokeStyle (format-key stroke-style)
|
||||
:strokeWidth stroke-width
|
||||
:strokeAlignment (format-key stroke-alignment)
|
||||
:strokeCapStart (format-key stroke-cap-start)
|
||||
:strokeCapEnd (format-key stroke-cap-end)
|
||||
:strokeColorGradient (format-gradient stroke-color-gradient)})))
|
||||
|
||||
(defn format-strokes
|
||||
[strokes]
|
||||
(when (some? strokes)
|
||||
(format-array format-stroke strokes)))
|
||||
|
||||
;; export interface PenpotBlur {
|
||||
;; id?: string;
|
||||
;; type?: 'layer-blur';
|
||||
;; value?: number;
|
||||
;; hidden?: boolean;
|
||||
;; }
|
||||
(defn format-blur
|
||||
[{:keys [id type value hidden] :as blur}]
|
||||
(when (some? blur)
|
||||
(obj/clear-empty
|
||||
#js {:id (format-id id)
|
||||
:type (format-key type)
|
||||
:value value
|
||||
:hidden hidden})))
|
||||
|
||||
;; export interface PenpotExport {
|
||||
;; type: 'png' | 'jpeg' | 'svg' | 'pdf';
|
||||
;; scale: number;
|
||||
;; suffix: string;
|
||||
;; }
|
||||
(defn format-export
|
||||
[{:keys [type scale suffix] :as export}]
|
||||
(when (some? export)
|
||||
(obj/clear-empty
|
||||
#js {:type (format-key type)
|
||||
:scale scale
|
||||
:suffix suffix})))
|
||||
|
||||
(defn format-exports
|
||||
[exports]
|
||||
(when (some? exports)
|
||||
(format-array format-export exports)))
|
||||
|
||||
;; export interface PenpotFrameGuideColumnParams {
|
||||
;; color: { color: string; opacity: number };
|
||||
;; type?: 'stretch' | 'left' | 'center' | 'right';
|
||||
;; size?: number;
|
||||
;; margin?: number;
|
||||
;; itemLength?: number;
|
||||
;; gutter?: number;
|
||||
;; }
|
||||
(defn format-frame-guide-column-params
|
||||
[{:keys [color type size margin item-length gutter] :as params}]
|
||||
(when (some? params)
|
||||
(obj/clear-empty
|
||||
#js {:color (format-color color)
|
||||
:type (format-key type)
|
||||
:size size
|
||||
:margin margin
|
||||
:itemLength item-length
|
||||
:gutter gutter})))
|
||||
|
||||
;; export interface PenpotFrameGuideColumn {
|
||||
;; type: 'column';
|
||||
;; display: boolean;
|
||||
;; params: PenpotFrameGuideColumnParams;
|
||||
;; }
|
||||
(defn format-frame-guide-column
|
||||
[{:keys [type display params] :as guide}]
|
||||
(when (some? guide)
|
||||
(obj/clear-empty
|
||||
#js {:type (format-key type)
|
||||
:display display
|
||||
:params (format-frame-guide-column-params params)})))
|
||||
|
||||
;; export interface PenpotFrameGuideRow {
|
||||
;; type: 'row';
|
||||
;; display: boolean;
|
||||
;; params: PenpotFrameGuideColumnParams;
|
||||
;; }
|
||||
(defn format-frame-guide-row
|
||||
[{:keys [type display params] :as guide}]
|
||||
(when (some? guide)
|
||||
(obj/clear-empty
|
||||
#js {:type (format-key type)
|
||||
:display display
|
||||
:params (format-frame-guide-column-params params)})))
|
||||
|
||||
;;export interface PenpotFrameGuideSquareParams {
|
||||
;; color: { color: string; opacity: number };
|
||||
;; size?: number;
|
||||
;;}
|
||||
(defn format-frame-guide-square-params
|
||||
[{:keys [color size] :as params}]
|
||||
(when (some? params)
|
||||
(obj/clear-empty
|
||||
#js {:color (format-color color)
|
||||
:size size})))
|
||||
|
||||
;; export interface PenpotFrameGuideSquare {
|
||||
;; type: 'square';
|
||||
;; display: boolean;
|
||||
;; params: PenpotFrameGuideSquareParams;
|
||||
;; }
|
||||
|
||||
(defn format-frame-guide-square
|
||||
[{:keys [type display params] :as guide}]
|
||||
(when (some? guide)
|
||||
(obj/clear-empty
|
||||
#js {:type (format-key type)
|
||||
:display display
|
||||
:params (format-frame-guide-column-params params)})))
|
||||
|
||||
(defn format-frame-guide
|
||||
[{:keys [type] :as guide}]
|
||||
(when (some? guide)
|
||||
(case type
|
||||
:column (format-frame-guide-column guide)
|
||||
:row (format-frame-guide-row guide)
|
||||
:square (format-frame-guide-square guide))))
|
||||
|
||||
(defn format-frame-guides
|
||||
[guides]
|
||||
(when (some? guides)
|
||||
(format-array format-frame-guide guides)))
|
||||
|
||||
;;interface PenpotPathCommand {
|
||||
;; command:
|
||||
;; | 'M' | 'move-to'
|
||||
;; | 'Z' | 'close-path'
|
||||
;; | 'L' | 'line-to'
|
||||
;; | 'H' | 'line-to-horizontal'
|
||||
;; | 'V' | 'line-to-vertical'
|
||||
;; | 'C' | 'curve-to'
|
||||
;; | 'S' | 'smooth-curve-to'
|
||||
;; | 'Q' | 'quadratic-bezier-curve-to'
|
||||
;; | 'T' | 'smooth-quadratic-bezier-curve-to'
|
||||
;; | 'A' | 'elliptical-arc';
|
||||
;;
|
||||
;; params?: {
|
||||
;; x?: number;
|
||||
;; y?: number;
|
||||
;; c1x: number;
|
||||
;; c1y: number;
|
||||
;; c2x: number;
|
||||
;; c2y: number;
|
||||
;; rx?: number;
|
||||
;; ry?: number;
|
||||
;; xAxisRotation?: number;
|
||||
;; largeArcFlag?: boolean;
|
||||
;; sweepFlag?: boolean;
|
||||
;; };
|
||||
;;}
|
||||
(defn format-command-params
|
||||
[{:keys [x y c1x c1y c2x c2y rx ry x-axis-rotation large-arc-flag sweep-flag] :as props}]
|
||||
(when (some? props)
|
||||
(obj/clear-empty
|
||||
#js {:x x
|
||||
:y y
|
||||
:c1x c1x
|
||||
:c1y c1y
|
||||
:c2x c2x
|
||||
:c2y c2y
|
||||
:rx rx
|
||||
:ry ry
|
||||
:xAxisRotation x-axis-rotation
|
||||
:largeArcFlag large-arc-flag
|
||||
:sweepFlag sweep-flag})))
|
||||
|
||||
(defn format-command
|
||||
[{:keys [command params] :as props}]
|
||||
(when (some? props)
|
||||
(obj/clear-empty
|
||||
#js {:command (format-key command)
|
||||
:params (format-command-params params)})))
|
||||
|
||||
(defn format-path-content
|
||||
[content]
|
||||
(when (some? content)
|
||||
(format-array format-command content)))
|
||||
|
||||
;; export type PenpotTrackType = 'flex' | 'fixed' | 'percent' | 'auto';
|
||||
;;
|
||||
;; export interface PenpotTrack {
|
||||
;; type: PenpotTrackType;
|
||||
;; value: number | null;
|
||||
;; }
|
||||
(defn format-track
|
||||
[{:keys [type value] :as track}]
|
||||
(when (some? track)
|
||||
(obj/clear-empty
|
||||
#js {:type (-> type format-key)
|
||||
:value value})))
|
||||
|
||||
(defn format-tracks
|
||||
[tracks]
|
||||
(when (some? tracks)
|
||||
(format-array format-track tracks)))
|
|
@ -13,6 +13,8 @@
|
|||
[app.main.data.workspace.shape-layout :as dwsl]
|
||||
[app.main.data.workspace.transforms :as dwt]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.format :as format]
|
||||
[app.plugins.register :as r]
|
||||
[app.plugins.utils :as u]
|
||||
[app.util.object :as obj]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
@ -20,12 +22,6 @@
|
|||
;; Define in `app.plugins.shape` we do this way to prevent circular dependency
|
||||
(def shape-proxy? nil)
|
||||
|
||||
(defn- make-tracks
|
||||
[tracks]
|
||||
(.freeze
|
||||
js/Object
|
||||
(apply array (->> tracks (map u/to-js)))))
|
||||
|
||||
(deftype GridLayout [$plugin $file $page $id]
|
||||
Object
|
||||
|
||||
|
@ -40,6 +36,9 @@
|
|||
(not (us/safe-number? value)))
|
||||
(u/display-not-valid :addRow-value value)
|
||||
|
||||
(not (r/check-permission $plugin "content:write"))
|
||||
(u/display-not-valid :addRow "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwsl/add-layout-track #{$id} :row {:type type :value value})))))
|
||||
|
||||
|
@ -57,6 +56,9 @@
|
|||
(not (us/safe-number? value)))
|
||||
(u/display-not-valid :addRowAtIndex-value value)
|
||||
|
||||
(not (r/check-permission $plugin "content:write"))
|
||||
(u/display-not-valid :addRowAtIndex "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwsl/add-layout-track #{$id} :row {:type type :value value} index)))))
|
||||
|
||||
|
@ -71,6 +73,9 @@
|
|||
(not (us/safe-number? value)))
|
||||
(u/display-not-valid :addColumn-value value)
|
||||
|
||||
(not (r/check-permission $plugin "content:write"))
|
||||
(u/display-not-valid :addColumn "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwsl/add-layout-track #{$id} :column {:type type :value value})))))
|
||||
|
||||
|
@ -87,6 +92,9 @@
|
|||
(not (us/safe-number? value)))
|
||||
(u/display-not-valid :addColumnAtIndex-value value)
|
||||
|
||||
(not (r/check-permission $plugin "content:write"))
|
||||
(u/display-not-valid :addColumnAtIndex "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [type (keyword type)]
|
||||
(st/emit! (dwsl/add-layout-track #{$id} :column {:type type :value value} index)))))
|
||||
|
@ -97,6 +105,9 @@
|
|||
(not (us/safe-int? index))
|
||||
(u/display-not-valid :removeRow index)
|
||||
|
||||
(not (r/check-permission $plugin "content:write"))
|
||||
(u/display-not-valid :removeRow "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwsl/remove-layout-track #{$id} :row index))))
|
||||
|
||||
|
@ -106,6 +117,9 @@
|
|||
(not (us/safe-int? index))
|
||||
(u/display-not-valid :removeColumn index)
|
||||
|
||||
(not (r/check-permission $plugin "content:write"))
|
||||
(u/display-not-valid :removeColumn "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwsl/remove-layout-track #{$id} :column index))))
|
||||
|
||||
|
@ -123,6 +137,9 @@
|
|||
(not (us/safe-number? value)))
|
||||
(u/display-not-valid :setColumn-value value)
|
||||
|
||||
(not (r/check-permission $plugin "content:write"))
|
||||
(u/display-not-valid :setColumn "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwsl/change-layout-track #{$id} :column index (d/without-nils {:type type :value value}))))))
|
||||
|
||||
|
@ -140,12 +157,20 @@
|
|||
(not (us/safe-number? value)))
|
||||
(u/display-not-valid :setRow-value value)
|
||||
|
||||
(not (r/check-permission $plugin "content:write"))
|
||||
(u/display-not-valid :setRow "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwsl/change-layout-track #{$id} :row index (d/without-nils {:type type :value value}))))))
|
||||
|
||||
(remove
|
||||
[_]
|
||||
(st/emit! (dwsl/remove-layout #{$id})))
|
||||
(cond
|
||||
(not (r/check-permission $plugin "content:write"))
|
||||
(u/display-not-valid :remove "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwsl/remove-layout #{$id}))))
|
||||
|
||||
(appendChild
|
||||
[_ child row column]
|
||||
|
@ -159,6 +184,9 @@
|
|||
(or (< column 0) (not (us/safe-int? column)))
|
||||
(u/display-not-valid :appendChild-column column)
|
||||
|
||||
(not (r/check-permission $plugin "content:write"))
|
||||
(u/display-not-valid :appendChild "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [child-id (obj/get child "$id")]
|
||||
(st/emit! (dwt/move-shapes-to-frame #{child-id} $id nil [row column])
|
||||
|
@ -185,15 +213,18 @@
|
|||
(not (contains? ctl/grid-direction-types value))
|
||||
(u/display-not-valid :dir value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :dir "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-grid-dir value}))))))}
|
||||
|
||||
{:name "rows"
|
||||
:get #(-> % u/proxy->shape :layout-grid-rows make-tracks)}
|
||||
:get #(-> % u/proxy->shape :layout-grid-rows format/format-tracks)}
|
||||
|
||||
{:name "columns"
|
||||
:get #(-> % u/proxy->shape :layout-grid-columns make-tracks)}
|
||||
:get #(-> % u/proxy->shape :layout-grid-columns format/format-tracks)}
|
||||
|
||||
{:name "alignItems"
|
||||
:get #(-> % u/proxy->shape :layout-align-items d/name)
|
||||
|
@ -204,6 +235,9 @@
|
|||
(not (contains? ctl/align-items-types value))
|
||||
(u/display-not-valid :alignItems value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :alignItems "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-align-items value}))))))}
|
||||
|
@ -217,6 +251,9 @@
|
|||
(not (contains? ctl/align-content-types value))
|
||||
(u/display-not-valid :alignContent value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :alignContent "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-align-content value}))))))}
|
||||
|
@ -230,6 +267,9 @@
|
|||
(not (contains? ctl/justify-items-types value))
|
||||
(u/display-not-valid :justifyItems value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :justifyItems "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-justify-items value}))))))}
|
||||
|
@ -243,6 +283,9 @@
|
|||
(not (contains? ctl/justify-content-types value))
|
||||
(u/display-not-valid :justifyContent value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :justifyContent "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-justify-content value}))))))}
|
||||
|
@ -255,6 +298,9 @@
|
|||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :rowGap value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :rowGap "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-gap {:row-gap value}})))))}
|
||||
|
@ -267,6 +313,9 @@
|
|||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :columnGap value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :columnGap "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-gap {:column-gap value}})))))}
|
||||
|
@ -279,6 +328,9 @@
|
|||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :verticalPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :verticalPadding "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p1 value :p3 value}})))))}
|
||||
|
@ -291,6 +343,9 @@
|
|||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :horizontalPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :horizontalPadding "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value :p4 value}})))))}
|
||||
|
@ -303,6 +358,9 @@
|
|||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :topPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :topPadding "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p1 value}})))))}
|
||||
|
@ -315,6 +373,9 @@
|
|||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :rightPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :righPadding "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value}})))))}
|
||||
|
@ -327,6 +388,9 @@
|
|||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :bottomPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :bottomPadding "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p3 value}})))))}
|
||||
|
@ -339,6 +403,9 @@
|
|||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :leftPadding value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :leftPadding "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id (obj/get self "$id")]
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p4 value}})))))})))
|
||||
|
@ -370,10 +437,13 @@
|
|||
shape (u/proxy->shape self)]
|
||||
(cond
|
||||
(not (us/safe-int? value))
|
||||
(u/display-not-valid :row value)
|
||||
(u/display-not-valid :row-value value)
|
||||
|
||||
(nil? cell)
|
||||
(u/display-not-valid :cell "cell not found")
|
||||
(u/display-not-valid :row-cell "cell not found")
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :row "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwsl/update-grid-cell-position (:parent-id shape) (:id cell) {:row value})))))}
|
||||
|
@ -391,6 +461,9 @@
|
|||
(nil? cell)
|
||||
(u/display-not-valid :rowSpan-cell "cell not found")
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :rowSpan "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwsl/update-grid-cell-position (:parent-id shape) (:id cell) {:row-span value})))))}
|
||||
|
||||
|
@ -407,6 +480,9 @@
|
|||
(nil? cell)
|
||||
(u/display-not-valid :column-cell "cell not found")
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :column "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwsl/update-grid-cell-position (:parent-id shape) (:id cell) {:column value})))))}
|
||||
|
||||
|
@ -423,6 +499,9 @@
|
|||
(nil? cell)
|
||||
(u/display-not-valid :columnSpan-cell "cell not found")
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :columnSpan "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwsl/update-grid-cell-position (:parent-id shape) (:id cell) {:column-span value})))))}
|
||||
|
||||
|
@ -439,6 +518,9 @@
|
|||
(nil? cell)
|
||||
(u/display-not-valid :areaName-cell "cell not found")
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :areaName "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwsl/update-grid-cells (:parent-id shape) #{(:id cell)} {:area-name value})))))}
|
||||
|
||||
|
@ -456,6 +538,9 @@
|
|||
(nil? cell)
|
||||
(u/display-not-valid :position-cell "cell not found")
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :position "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwsl/change-cells-mode (:parent-id shape) #{(:id cell)} value)))))}
|
||||
|
||||
|
@ -473,6 +558,9 @@
|
|||
(nil? cell)
|
||||
(u/display-not-valid :alignSelf-cell "cell not found")
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :alignSelf "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwsl/update-grid-cells (:parent-id shape) #{(:id cell)} {:align-self value})))))}
|
||||
|
||||
|
@ -490,5 +578,8 @@
|
|||
(nil? cell)
|
||||
(u/display-not-valid :justifySelf-cell "cell not found")
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :justifySelf "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwsl/update-grid-cells (:parent-id shape) #{(:id cell)} {:justify-self value})))))}))))
|
||||
|
|
|
@ -22,7 +22,11 @@
|
|||
[app.main.data.workspace.texts :as dwt]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.format :as format]
|
||||
[app.plugins.parser :as parser]
|
||||
[app.plugins.register :as r]
|
||||
[app.plugins.shape :as shape]
|
||||
[app.plugins.text :as text]
|
||||
[app.plugins.utils :as u]
|
||||
[app.util.object :as obj]
|
||||
[beicon.v2.core :as rx]
|
||||
|
@ -37,45 +41,53 @@
|
|||
|
||||
(remove
|
||||
[_]
|
||||
(st/emit! (dwl/delete-color {:id $id})))
|
||||
(cond
|
||||
(not (r/check-permission $plugin "library:write"))
|
||||
(u/display-not-valid :remove "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwl/delete-color {:id $id}))))
|
||||
|
||||
(clone
|
||||
[_]
|
||||
(let [color-id (uuid/next)
|
||||
color (-> (u/locate-library-color $file $id)
|
||||
(assoc :id color-id))]
|
||||
(st/emit! (dwl/add-color color {:rename? false}))
|
||||
(lib-color-proxy $plugin $id color-id)))
|
||||
(cond
|
||||
(not (r/check-permission $plugin "library:write"))
|
||||
(u/display-not-valid :clone "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [color-id (uuid/next)
|
||||
color (-> (u/locate-library-color $file $id)
|
||||
(assoc :id color-id))]
|
||||
(st/emit! (dwl/add-color color {:rename? false}))
|
||||
(lib-color-proxy $plugin $id color-id))))
|
||||
|
||||
(asFill [_]
|
||||
(let [color (u/locate-library-color $file $id)]
|
||||
(u/to-js
|
||||
(d/without-nils
|
||||
{:fill-color (:color color)
|
||||
:fill-opacity (:opacity color)
|
||||
:fill-color-gradient (:gradient color)
|
||||
:fill-color-ref-file $file
|
||||
:fill-color-ref-id $id
|
||||
:fill-image (:image color)}))))
|
||||
(format/format-fill
|
||||
{:fill-color (:color color)
|
||||
:fill-opacity (:opacity color)
|
||||
:fill-color-gradient (:gradient color)
|
||||
:fill-color-ref-file $file
|
||||
:fill-color-ref-id $id
|
||||
:fill-image (:image color)})))
|
||||
|
||||
(asStroke [_]
|
||||
(let [color (u/locate-library-color $file $id)]
|
||||
(u/to-js
|
||||
(d/without-nils
|
||||
{:stroke-color (:color color)
|
||||
:stroke-opacity (:opacity color)
|
||||
:stroke-color-gradient (:gradient color)
|
||||
:stroke-color-ref-file $file
|
||||
:stroke-color-ref-id $id
|
||||
:stroke-image (:image color)
|
||||
:stroke-style :solid
|
||||
:stroke-alignment :inner}))))
|
||||
(format/format-stroke
|
||||
{:stroke-color (:color color)
|
||||
:stroke-opacity (:opacity color)
|
||||
:stroke-color-gradient (:gradient color)
|
||||
:stroke-color-ref-file $file
|
||||
:stroke-color-ref-id $id
|
||||
:stroke-image (:image color)
|
||||
:stroke-style :solid
|
||||
:stroke-alignment :inner})))
|
||||
|
||||
(getPluginData
|
||||
[self key]
|
||||
(cond
|
||||
(not (string? key))
|
||||
(u/display-not-valid :color-plugin-data-key key)
|
||||
(u/display-not-valid :getPluginData-key key)
|
||||
|
||||
:else
|
||||
(let [color (u/proxy->library-color self)]
|
||||
|
@ -85,13 +97,16 @@
|
|||
[_ key value]
|
||||
(cond
|
||||
(not= $file (:current-file-id @st/state))
|
||||
(u/display-not-valid :color-edit-non-local-library $file)
|
||||
(u/display-not-valid :setPluginData-non-local-library $file)
|
||||
|
||||
(not (string? key))
|
||||
(u/display-not-valid :color-plugin-data-key key)
|
||||
(u/display-not-valid :setPluginData-key key)
|
||||
|
||||
(and (some? value) (not (string? value)))
|
||||
(u/display-not-valid :color-plugin-data value)
|
||||
(u/display-not-valid :setPluginData-value value)
|
||||
|
||||
(not (r/check-permission $plugin "library:write"))
|
||||
(u/display-not-valid :setPluginData "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dw/set-plugin-data $file :color $id (keyword "plugin" (str $plugin)) key value))))
|
||||
|
@ -105,10 +120,10 @@
|
|||
[self namespace key]
|
||||
(cond
|
||||
(not (string? namespace))
|
||||
(u/display-not-valid :color-plugin-data-namespace namespace)
|
||||
(u/display-not-valid :getSharedPluginData-namespace namespace)
|
||||
|
||||
(not (string? key))
|
||||
(u/display-not-valid :color-plugin-data-key key)
|
||||
(u/display-not-valid :getSharedPluginData-key key)
|
||||
|
||||
:else
|
||||
(let [color (u/proxy->library-color self)]
|
||||
|
@ -118,16 +133,19 @@
|
|||
[_ namespace key value]
|
||||
(cond
|
||||
(not= $file (:current-file-id @st/state))
|
||||
(u/display-not-valid :color-edit-non-local-library $file)
|
||||
(u/display-not-valid :setSharedPluginData-non-local-library $file)
|
||||
|
||||
(not (string? namespace))
|
||||
(u/display-not-valid :color-plugin-data-namespace namespace)
|
||||
(u/display-not-valid :setSharedPluginData-namespace namespace)
|
||||
|
||||
(not (string? key))
|
||||
(u/display-not-valid :color-plugin-data-key key)
|
||||
(u/display-not-valid :setSharedPluginData-key key)
|
||||
|
||||
(and (some? value) (not (string? value)))
|
||||
(u/display-not-valid :color-plugin-data value)
|
||||
(u/display-not-valid :setSharedPluginData-value value)
|
||||
|
||||
(not (r/check-permission $plugin "library:write"))
|
||||
(u/display-not-valid :setSharedPluginData "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dw/set-plugin-data $file :color $id (keyword "shared" namespace) key value))))
|
||||
|
@ -136,7 +154,7 @@
|
|||
[self namespace]
|
||||
(cond
|
||||
(not (string? namespace))
|
||||
(u/display-not-valid :color-plugin-data-namespace namespace)
|
||||
(u/display-not-valid :getSharedPluginDataKeys-namespace namespace)
|
||||
|
||||
:else
|
||||
(let [color (u/proxy->library-color self)]
|
||||
|
@ -164,7 +182,10 @@
|
|||
(fn [self value]
|
||||
(cond
|
||||
(not (string? value))
|
||||
(u/display-not-valid :library-color-name value)
|
||||
(u/display-not-valid :name value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :name "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [color (u/proxy->library-color self)
|
||||
|
@ -177,7 +198,10 @@
|
|||
(fn [self value]
|
||||
(cond
|
||||
(not (string? value))
|
||||
(u/display-not-valid :library-color-path value)
|
||||
(u/display-not-valid :path value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :path "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [color (-> (u/proxy->library-color self)
|
||||
|
@ -190,7 +214,10 @@
|
|||
(fn [self value]
|
||||
(cond
|
||||
(or (not (string? value)) (not (cc/valid-hex-color? value)))
|
||||
(u/display-not-valid :library-color-color value)
|
||||
(u/display-not-valid :color value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :color "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [color (-> (u/proxy->library-color self)
|
||||
|
@ -203,7 +230,10 @@
|
|||
(fn [self value]
|
||||
(cond
|
||||
(or (not (number? value)) (< value 0) (> value 1))
|
||||
(u/display-not-valid :library-color-opacity value)
|
||||
(u/display-not-valid :opacity value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :opacity "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [color (-> (u/proxy->library-color self)
|
||||
|
@ -211,13 +241,16 @@
|
|||
(st/emit! (dwl/update-color color file-id)))))}
|
||||
|
||||
{:name "gradient"
|
||||
:get #(-> % u/proxy->library-color :gradient u/to-js)
|
||||
:get #(-> % u/proxy->library-color :gradient format/format-gradient)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [value (u/from-js value)]
|
||||
(let [value (parser/parse-gradient value)]
|
||||
(cond
|
||||
(not (sm/validate ::ctc/gradient value))
|
||||
(u/display-not-valid :library-color-gradient value)
|
||||
(u/display-not-valid :gradient value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :gradient "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [color (-> (u/proxy->library-color self)
|
||||
|
@ -225,13 +258,16 @@
|
|||
(st/emit! (dwl/update-color color file-id))))))}
|
||||
|
||||
{:name "image"
|
||||
:get #(-> % u/proxy->library-color :image u/to-js)
|
||||
:get #(-> % u/proxy->library-color :image format/format-image)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [value (u/from-js value)]
|
||||
(let [value (parser/parse-image-data value)]
|
||||
(cond
|
||||
(not (sm/validate ::ctc/image-color value))
|
||||
(u/display-not-valid :library-color-image value)
|
||||
(u/display-not-valid :image value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :image "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [color (-> (u/proxy->library-color self)
|
||||
|
@ -242,15 +278,25 @@
|
|||
Object
|
||||
(remove
|
||||
[_]
|
||||
(st/emit! (dwl/delete-typography {:id $id})))
|
||||
(cond
|
||||
(not (r/check-permission $plugin "library:write"))
|
||||
(u/display-not-valid :remove "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwl/delete-typography {:id $id}))))
|
||||
|
||||
(clone
|
||||
[_]
|
||||
(let [typo-id (uuid/next)
|
||||
typo (-> (u/locate-library-typography $file $id)
|
||||
(assoc :id typo-id))]
|
||||
(st/emit! (dwl/add-typography typo false))
|
||||
(lib-typography-proxy $plugin $id typo-id)))
|
||||
(cond
|
||||
(not (r/check-permission $plugin "library:write"))
|
||||
(u/display-not-valid :clone "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [typo-id (uuid/next)
|
||||
typo (-> (u/locate-library-typography $file $id)
|
||||
(assoc :id typo-id))]
|
||||
(st/emit! (dwl/add-typography typo false))
|
||||
(lib-typography-proxy $plugin $id typo-id))))
|
||||
|
||||
(applyToText
|
||||
[_ shape]
|
||||
|
@ -258,6 +304,9 @@
|
|||
(not (shape/shape-proxy? shape))
|
||||
(u/display-not-valid :applyToText shape)
|
||||
|
||||
(not (r/check-permission $plugin "content:write"))
|
||||
(u/display-not-valid :applyToText "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [shape-id (obj/get shape "$id")
|
||||
typography (u/locate-library-typography $file $id)]
|
||||
|
@ -266,9 +315,12 @@
|
|||
(applyToTextRange
|
||||
[self range]
|
||||
(cond
|
||||
(not (shape/text-range? range))
|
||||
(not (text/text-range? range))
|
||||
(u/display-not-valid :applyToText range)
|
||||
|
||||
(not (r/check-permission $plugin "content:write"))
|
||||
(u/display-not-valid :applyToText "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [shape-id (obj/get range "$id")
|
||||
start (obj/get range "start")
|
||||
|
@ -295,13 +347,16 @@
|
|||
[_ key value]
|
||||
(cond
|
||||
(not= $file (:current-file-id @st/state))
|
||||
(u/display-not-valid :typography-edit-non-local-library $file)
|
||||
(u/display-not-valid :setPluginData-non-local-library $file)
|
||||
|
||||
(not (string? key))
|
||||
(u/display-not-valid :typography-plugin-data-key key)
|
||||
(u/display-not-valid :setPluginData-key key)
|
||||
|
||||
(and (some? value) (not (string? value)))
|
||||
(u/display-not-valid :typography-plugin-data value)
|
||||
(u/display-not-valid :setPluginData-value value)
|
||||
|
||||
(not (r/check-permission $plugin "library:write"))
|
||||
(u/display-not-valid :setPluginData "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dw/set-plugin-data $file :typography $id (keyword "plugin" (str $plugin)) key value))))
|
||||
|
@ -315,10 +370,10 @@
|
|||
[self namespace key]
|
||||
(cond
|
||||
(not (string? namespace))
|
||||
(u/display-not-valid :typography-plugin-data-namespace namespace)
|
||||
(u/display-not-valid :getSharedPluginData-namespace namespace)
|
||||
|
||||
(not (string? key))
|
||||
(u/display-not-valid :typography-plugin-data-key key)
|
||||
(u/display-not-valid :getSharedPluginData-key key)
|
||||
|
||||
:else
|
||||
(let [typography (u/proxy->library-typography self)]
|
||||
|
@ -328,16 +383,19 @@
|
|||
[_ namespace key value]
|
||||
(cond
|
||||
(not= $file (:current-file-id @st/state))
|
||||
(u/display-not-valid :typography-edit-non-local-library $file)
|
||||
(u/display-not-valid :setSharedPluginData-non-local-library $file)
|
||||
|
||||
(not (string? namespace))
|
||||
(u/display-not-valid :typography-plugin-data-namespace namespace)
|
||||
(u/display-not-valid :setSharedPluginData-namespace namespace)
|
||||
|
||||
(not (string? key))
|
||||
(u/display-not-valid :typography-plugin-data-key key)
|
||||
(u/display-not-valid :setSharedPluginData-key key)
|
||||
|
||||
(and (some? value) (not (string? value)))
|
||||
(u/display-not-valid :typography-plugin-data value)
|
||||
(u/display-not-valid :setSharedPluginData-value value)
|
||||
|
||||
(not (r/check-permission $plugin "library:write"))
|
||||
(u/display-not-valid :setSharedPluginData "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dw/set-plugin-data $file :typography $id (keyword "shared" namespace) key value))))
|
||||
|
@ -346,7 +404,7 @@
|
|||
[self namespace]
|
||||
(cond
|
||||
(not (string? namespace))
|
||||
(u/display-not-valid :typography-plugin-data-namespace namespace)
|
||||
(u/display-not-valid :getSharedPluginDataKeys-namespace namespace)
|
||||
|
||||
:else
|
||||
(let [typography (u/proxy->library-typography self)]
|
||||
|
@ -375,7 +433,10 @@
|
|||
(fn [self value]
|
||||
(cond
|
||||
(not (string? value))
|
||||
(u/display-not-valid :library-typography-name value)
|
||||
(u/display-not-valid :name value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :name "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [typo (u/proxy->library-typography self)
|
||||
|
@ -388,7 +449,10 @@
|
|||
(fn [self value]
|
||||
(cond
|
||||
(not (string? value))
|
||||
(u/display-not-valid :library-typography-path value)
|
||||
(u/display-not-valid :path value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :path "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [typo (-> (u/proxy->library-typography self)
|
||||
|
@ -401,7 +465,10 @@
|
|||
(fn [self value]
|
||||
(cond
|
||||
(not (string? value))
|
||||
(u/display-not-valid :library-typography-font-id value)
|
||||
(u/display-not-valid :fontId value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :fontId "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [typo (-> (u/proxy->library-typography self)
|
||||
|
@ -414,7 +481,10 @@
|
|||
(fn [self value]
|
||||
(cond
|
||||
(not (string? value))
|
||||
(u/display-not-valid :library-typography-font-family value)
|
||||
(u/display-not-valid :fontFamily value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :fontFamily "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [typo (-> (u/proxy->library-typography self)
|
||||
|
@ -427,7 +497,10 @@
|
|||
(fn [self value]
|
||||
(cond
|
||||
(not (string? value))
|
||||
(u/display-not-valid :library-typography-font-variant-id value)
|
||||
(u/display-not-valid :fontVariantId value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :fontVariantId "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [typo (-> (u/proxy->library-typography self)
|
||||
|
@ -440,7 +513,10 @@
|
|||
(fn [self value]
|
||||
(cond
|
||||
(not (string? value))
|
||||
(u/display-not-valid :library-typography-font-size value)
|
||||
(u/display-not-valid :fontSize value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :fontSize "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [typo (-> (u/proxy->library-typography self)
|
||||
|
@ -453,7 +529,10 @@
|
|||
(fn [self value]
|
||||
(cond
|
||||
(not (string? value))
|
||||
(u/display-not-valid :library-typography-font-weight value)
|
||||
(u/display-not-valid :fontWeight value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :fontWeight "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [typo (-> (u/proxy->library-typography self)
|
||||
|
@ -466,7 +545,10 @@
|
|||
(fn [self value]
|
||||
(cond
|
||||
(not (string? value))
|
||||
(u/display-not-valid :library-typography-font-style value)
|
||||
(u/display-not-valid :fontStyle value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :fontStyle "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [typo (-> (u/proxy->library-typography self)
|
||||
|
@ -479,7 +561,10 @@
|
|||
(fn [self value]
|
||||
(cond
|
||||
(not (string? value))
|
||||
(u/display-not-valid :library-typography-font-height value)
|
||||
(u/display-not-valid :lineHeight value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :lineHeight "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [typo (-> (u/proxy->library-typography self)
|
||||
|
@ -492,7 +577,10 @@
|
|||
(fn [self value]
|
||||
(cond
|
||||
(not (string? value))
|
||||
(u/display-not-valid :library-typography-letter-spacing value)
|
||||
(u/display-not-valid :letterSpacing value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :letterSpacing "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [typo (-> (u/proxy->library-typography self)
|
||||
|
@ -505,7 +593,10 @@
|
|||
(fn [self value]
|
||||
(cond
|
||||
(not (string? value))
|
||||
(u/display-not-valid :library-typography-text-transform value)
|
||||
(u/display-not-valid :textTransform value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :textTransform "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [typo (-> (u/proxy->library-typography self)
|
||||
|
@ -517,13 +608,23 @@
|
|||
|
||||
(remove
|
||||
[_]
|
||||
(st/emit! (dwl/delete-component {:id $id})))
|
||||
(cond
|
||||
(not (r/check-permission $plugin "library:write"))
|
||||
(u/display-not-valid :remove "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwl/delete-component {:id $id}))))
|
||||
|
||||
(instance
|
||||
[_]
|
||||
(let [id-ref (atom nil)]
|
||||
(st/emit! (dwl/instantiate-component $file $id (gpt/point 0 0) {:id-ref id-ref}))
|
||||
(shape/shape-proxy $plugin @id-ref)))
|
||||
(cond
|
||||
(not (r/check-permission $plugin "content:write"))
|
||||
(u/display-not-valid :instance "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(let [id-ref (atom nil)]
|
||||
(st/emit! (dwl/instantiate-component $file $id (gpt/point 0 0) {:id-ref id-ref}))
|
||||
(shape/shape-proxy $plugin @id-ref))))
|
||||
|
||||
(getPluginData
|
||||
[self key]
|
||||
|
@ -539,13 +640,16 @@
|
|||
[_ key value]
|
||||
(cond
|
||||
(not= $file (:current-file-id @st/state))
|
||||
(u/display-not-valid :component-edit-non-local-library $file)
|
||||
(u/display-not-valid :setPluginData-non-local-library $file)
|
||||
|
||||
(not (string? key))
|
||||
(u/display-not-valid :component-plugin-data-key key)
|
||||
(u/display-not-valid :setPluginData-key key)
|
||||
|
||||
(and (some? value) (not (string? value)))
|
||||
(u/display-not-valid :component-plugin-data value)
|
||||
(u/display-not-valid :setPluginData-value value)
|
||||
|
||||
(not (r/check-permission $plugin "library:write"))
|
||||
(u/display-not-valid :setPluginData "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dw/set-plugin-data $file :component $id (keyword "plugin" (str $plugin)) key value))))
|
||||
|
@ -572,16 +676,19 @@
|
|||
[_ namespace key value]
|
||||
(cond
|
||||
(not= $file (:current-file-id @st/state))
|
||||
(u/display-not-valid :component-edit-non-local-library $file)
|
||||
(u/display-not-valid :setSharedPluginData-non-local-library $file)
|
||||
|
||||
(not (string? namespace))
|
||||
(u/display-not-valid :component-plugin-data-namespace namespace)
|
||||
(u/display-not-valid :setSharedPluginData-namespace namespace)
|
||||
|
||||
(not (string? key))
|
||||
(u/display-not-valid :component-plugin-data-key key)
|
||||
(u/display-not-valid :setSharedPluginData-key key)
|
||||
|
||||
(and (some? value) (not (string? value)))
|
||||
(u/display-not-valid :component-plugin-data value)
|
||||
(u/display-not-valid :setSharedPluginData-value value)
|
||||
|
||||
(not (r/check-permission $plugin "library:write"))
|
||||
(u/display-not-valid :setSharedPluginData "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dw/set-plugin-data $file :component $id (keyword "shared" namespace) key value))))
|
||||
|
@ -625,7 +732,10 @@
|
|||
(fn [self value]
|
||||
(cond
|
||||
(not (string? value))
|
||||
(u/display-not-valid :library-component-name value)
|
||||
(u/display-not-valid :name value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :name "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [component (u/proxy->library-component self)
|
||||
|
@ -638,7 +748,10 @@
|
|||
(fn [self value]
|
||||
(cond
|
||||
(not (string? value))
|
||||
(u/display-not-valid :library-component-path value)
|
||||
(u/display-not-valid :path value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
(u/display-not-valid :path "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [component (u/proxy->library-component self)
|
||||
|
@ -652,22 +765,37 @@
|
|||
|
||||
(createColor
|
||||
[_]
|
||||
(let [color-id (uuid/next)]
|
||||
(st/emit! (dwl/add-color {:id color-id :name "Color" :color "#000000" :opacity 1} {:rename? false}))
|
||||
(lib-color-proxy $plugin $id color-id)))
|
||||
(cond
|
||||
(not (r/check-permission $plugin "library:write"))
|
||||
(u/display-not-valid :createColor "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [color-id (uuid/next)]
|
||||
(st/emit! (dwl/add-color {:id color-id :name "Color" :color "#000000" :opacity 1} {:rename? false}))
|
||||
(lib-color-proxy $plugin $id color-id))))
|
||||
|
||||
(createTypography
|
||||
[_]
|
||||
(let [typography-id (uuid/next)]
|
||||
(st/emit! (dwl/add-typography (ctt/make-typography {:id typography-id :name "Typography"}) false))
|
||||
(lib-typography-proxy $plugin $id typography-id)))
|
||||
(cond
|
||||
(not (r/check-permission $plugin "library:write"))
|
||||
(u/display-not-valid :createTypography "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [typography-id (uuid/next)]
|
||||
(st/emit! (dwl/add-typography (ctt/make-typography {:id typography-id :name "Typography"}) false))
|
||||
(lib-typography-proxy $plugin $id typography-id))))
|
||||
|
||||
(createComponent
|
||||
[_ shapes]
|
||||
(let [id-ref (atom nil)
|
||||
ids (into #{} (map #(obj/get % "$id")) shapes)]
|
||||
(st/emit! (dwl/add-component id-ref ids))
|
||||
(lib-component-proxy $plugin $id @id-ref)))
|
||||
(cond
|
||||
(not (r/check-permission $plugin "library:write"))
|
||||
(u/display-not-valid :createComponent "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [id-ref (atom nil)
|
||||
ids (into #{} (map #(obj/get % "$id")) shapes)]
|
||||
(st/emit! (dwl/add-component id-ref ids))
|
||||
(lib-component-proxy $plugin $id @id-ref))))
|
||||
|
||||
;; Plugin data
|
||||
(getPluginData
|
||||
|
@ -684,10 +812,13 @@
|
|||
[_ key value]
|
||||
(cond
|
||||
(not (string? key))
|
||||
(u/display-not-valid :file-plugin-data-key key)
|
||||
(u/display-not-valid :setPluginData-key key)
|
||||
|
||||
(and (some? value) (not (string? value)))
|
||||
(u/display-not-valid :file-plugin-data value)
|
||||
(u/display-not-valid :setPluginData-value value)
|
||||
|
||||
(not (r/check-permission $plugin "library:write"))
|
||||
(u/display-not-valid :setPluginData "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dw/set-plugin-data $id :file (keyword "plugin" (str $plugin)) key value))))
|
||||
|
@ -715,13 +846,16 @@
|
|||
|
||||
(cond
|
||||
(not (string? namespace))
|
||||
(u/display-not-valid :file-plugin-data-namespace namespace)
|
||||
(u/display-not-valid :setSharedPluginData-namespace namespace)
|
||||
|
||||
(not (string? key))
|
||||
(u/display-not-valid :file-plugin-data-key key)
|
||||
(u/display-not-valid :setSharedPluginData-key key)
|
||||
|
||||
(and (some? value) (not (string? value)))
|
||||
(u/display-not-valid :file-plugin-data value)
|
||||
(u/display-not-valid :setSharedPluginData-value value)
|
||||
|
||||
(not (r/check-permission $plugin "library:write"))
|
||||
(u/display-not-valid :setSharedPluginData "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dw/set-plugin-data $id :file (keyword "shared" namespace) key value))))
|
||||
|
@ -730,7 +864,7 @@
|
|||
[self namespace]
|
||||
(cond
|
||||
(not (string? namespace))
|
||||
(u/display-not-valid :file-plugin-data-namespace namespace)
|
||||
(u/display-not-valid :namespace namespace)
|
||||
|
||||
:else
|
||||
(let [file (u/proxy->file self)]
|
||||
|
@ -804,21 +938,26 @@
|
|||
|
||||
(connectLibrary
|
||||
[_ library-id]
|
||||
(p/create
|
||||
(fn [resolve reject]
|
||||
(cond
|
||||
(not (string? library-id))
|
||||
(do (u/display-not-valid :connectLibrary library-id)
|
||||
(reject nil))
|
||||
(cond
|
||||
(not (r/check-permission $plugin "library:write"))
|
||||
(u/display-not-valid :connectLibrary "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(let [file-id (:current-file-id @st/state)
|
||||
library-id (uuid/uuid library-id)]
|
||||
(->> st/stream
|
||||
(rx/filter (ptk/type? ::dwl/attach-library-finished))
|
||||
(rx/take 1)
|
||||
(rx/subs! #(resolve (library-proxy $plugin library-id)) reject))
|
||||
(st/emit! (dwl/link-file-to-library file-id library-id))))))))
|
||||
:else
|
||||
(p/create
|
||||
(fn [resolve reject]
|
||||
(cond
|
||||
(not (string? library-id))
|
||||
(do (u/display-not-valid :connectLibrary library-id)
|
||||
(reject nil))
|
||||
|
||||
:else
|
||||
(let [file-id (:current-file-id @st/state)
|
||||
library-id (uuid/uuid library-id)]
|
||||
(->> st/stream
|
||||
(rx/filter (ptk/type? ::dwl/attach-library-finished))
|
||||
(rx/take 1)
|
||||
(rx/subs! #(resolve (library-proxy $plugin library-id)) reject))
|
||||
(st/emit! (dwl/link-file-to-library file-id library-id)))))))))
|
||||
|
||||
(defn library-subcontext
|
||||
[plugin-id]
|
||||
|
|
|
@ -13,9 +13,12 @@
|
|||
[app.common.uuid :as uuid]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.parser :as parser]
|
||||
[app.plugins.register :as r]
|
||||
[app.plugins.shape :as shape]
|
||||
[app.plugins.utils :as u]
|
||||
[app.util.object :as obj]))
|
||||
[app.util.object :as obj]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
(deftype PageProxy [$plugin $file $id]
|
||||
Object
|
||||
|
@ -34,11 +37,28 @@
|
|||
(shape/shape-proxy $plugin $file $id uuid/zero))
|
||||
|
||||
(findShapes
|
||||
[_]
|
||||
[_ criteria]
|
||||
;; Returns a lazy (iterable) of all available shapes
|
||||
(when (and (some? $file) (some? $id))
|
||||
(let [page (u/locate-page $file $id)]
|
||||
(apply array (sequence (map (partial shape/shape-proxy $plugin)) (keys (:objects page)))))))
|
||||
(let [criteria (parser/parse-criteria criteria)
|
||||
match-criteria?
|
||||
(if (some? criteria)
|
||||
(fn [[_ shape]]
|
||||
(and
|
||||
(or (not (:name criteria))
|
||||
(= (str/lower (:name criteria)) (str/lower (:name shape))))
|
||||
|
||||
(or (not (:name-like criteria))
|
||||
(str/includes? (str/lower (:name shape)) (str/lower (:name-like criteria))))
|
||||
|
||||
(or (not (:type criteria))
|
||||
(= (:type criteria) (:type shape)))))
|
||||
identity)]
|
||||
(when (and (some? $file) (some? $id))
|
||||
(let [page (u/locate-page $file $id)
|
||||
xf (comp
|
||||
(filter match-criteria?)
|
||||
(map #(shape/shape-proxy $plugin $file $id (first %))))]
|
||||
(apply array (sequence xf (:objects page)))))))
|
||||
|
||||
;; Plugin data
|
||||
(getPluginData
|
||||
|
@ -55,10 +75,13 @@
|
|||
[_ key value]
|
||||
(cond
|
||||
(not (string? key))
|
||||
(u/display-not-valid :page-plugin-data-key key)
|
||||
(u/display-not-valid :setPluginData-key key)
|
||||
|
||||
(and (some? value) (not (string? value)))
|
||||
(u/display-not-valid :page-plugin-data value)
|
||||
(u/display-not-valid :setPluginData-value value)
|
||||
|
||||
(not (r/check-permission $plugin "content:write"))
|
||||
(u/display-not-valid :setPluginData "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dw/set-plugin-data $file :page $id (keyword "plugin" (str $plugin)) key value))))
|
||||
|
@ -86,13 +109,16 @@
|
|||
|
||||
(cond
|
||||
(not (string? namespace))
|
||||
(u/display-not-valid :page-plugin-data-namespace namespace)
|
||||
(u/display-not-valid :setSharedPluginData-namespace namespace)
|
||||
|
||||
(not (string? key))
|
||||
(u/display-not-valid :page-plugin-data-key key)
|
||||
(u/display-not-valid :setSharedPluginData-key key)
|
||||
|
||||
(and (some? value) (not (string? value)))
|
||||
(u/display-not-valid :page-plugin-data value)
|
||||
(u/display-not-valid :setSharedPluginData-value value)
|
||||
|
||||
(not (r/check-permission $plugin "content:write"))
|
||||
(u/display-not-valid :setSharedPluginData "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dw/set-plugin-data $file :page $id (keyword "shared" namespace) key value))))
|
||||
|
@ -132,7 +158,10 @@
|
|||
(fn [_ value]
|
||||
(cond
|
||||
(not (string? value))
|
||||
(u/display-not-valid :page-name value)
|
||||
(u/display-not-valid :name value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :name "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dw/rename-page id value))))}
|
||||
|
@ -148,7 +177,10 @@
|
|||
(fn [_ value]
|
||||
(cond
|
||||
(or (not (string? value)) (not (cc/valid-hex-color? value)))
|
||||
(u/display-not-valid :page-background-color value)
|
||||
(u/display-not-valid :background value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :background "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dw/change-canvas-color id {:color value}))))}))
|
||||
|
|
396
frontend/src/app/plugins/parser.cljs
Normal file
396
frontend/src/app/plugins/parser.cljs
Normal file
|
@ -0,0 +1,396 @@
|
|||
;; 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.plugins.parser
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.util.object :as obj]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
(defn parse-id
|
||||
[id]
|
||||
(when id (uuid/uuid id)))
|
||||
|
||||
(defn parse-keyword
|
||||
[kw]
|
||||
(when kw (keyword kw)))
|
||||
|
||||
(defn parse-hex
|
||||
[color]
|
||||
(if (string? color) (-> color str/lower) color))
|
||||
|
||||
;; {
|
||||
;; name?: string;
|
||||
;; nameLike?: string;
|
||||
;; type?:
|
||||
;; | 'frame'
|
||||
;; | 'group'
|
||||
;; | 'bool'
|
||||
;; | 'rect'
|
||||
;; | 'path'
|
||||
;; | 'text'
|
||||
;; | 'circle'
|
||||
;; | 'svg-raw'
|
||||
;; | 'image';
|
||||
;; }
|
||||
(defn parse-criteria
|
||||
[^js criteria]
|
||||
(when (some? criteria)
|
||||
(d/without-nils
|
||||
{:name (obj/get criteria "name")
|
||||
:name-like (obj/get criteria "nameLike")
|
||||
:type (-> (obj/get criteria "type") parse-keyword)})))
|
||||
|
||||
;;export type PenpotImageData = {
|
||||
;; name?: string;
|
||||
;; width: number;
|
||||
;; height: number;
|
||||
;; mtype?: string;
|
||||
;; id: string;
|
||||
;; keepApectRatio?: boolean;
|
||||
;;}
|
||||
(defn parse-image-data
|
||||
[^js image-data]
|
||||
(when (some? image-data)
|
||||
(d/without-nils
|
||||
{:id (-> (obj/get image-data "id") parse-id)
|
||||
:name (obj/get image-data "name")
|
||||
:width (obj/get image-data "width")
|
||||
:height (obj/get image-data "height")
|
||||
:mtype (obj/get image-data "mtype")
|
||||
:keep-aspect-ratio (obj/get image-data "keepApectRatio")})))
|
||||
|
||||
;; export type PenpotGradient = {
|
||||
;; type: 'linear' | 'radial';
|
||||
;; startX: number;
|
||||
;; startY: number;
|
||||
;; endX: number;
|
||||
;; endY: number;
|
||||
;; width: number;
|
||||
;; stops: Array<{ color: string; opacity?: number; offset: number }>;
|
||||
;; }
|
||||
(defn parse-gradient-stop
|
||||
[^js stop]
|
||||
(when (some? stop)
|
||||
(d/without-nils
|
||||
{:color (-> (obj/get stop "color") parse-hex)
|
||||
:opacity (obj/get stop "opacity")
|
||||
:offset (obj/get stop "offset")})))
|
||||
|
||||
(defn parse-gradient
|
||||
[^js gradient]
|
||||
(when (some? gradient)
|
||||
(d/without-nils
|
||||
{:type (-> (obj/get gradient "type") parse-keyword)
|
||||
:start-x (obj/get gradient "startX")
|
||||
:start-y (obj/get gradient "startY")
|
||||
:end-x (obj/get gradient "endX")
|
||||
:end-y (obj/get gradient "endY")
|
||||
:width (obj/get gradient "width")
|
||||
:stops (->> (obj/get gradient "stops")
|
||||
(mapv parse-gradient-stop))})))
|
||||
|
||||
;; export interface PenpotColor {
|
||||
;; id?: string;
|
||||
;; name?: string;
|
||||
;; path?: string;
|
||||
;; color?: string;
|
||||
;; opacity?: number;
|
||||
;; refId?: string;
|
||||
;; refFile?: string;
|
||||
;; gradient?: PenpotGradient;
|
||||
;; image?: PenpotImageData;
|
||||
;; }
|
||||
(defn parse-color
|
||||
[^js color]
|
||||
(when (some? color)
|
||||
(d/without-nils
|
||||
{:id (-> (obj/get color "id") parse-id)
|
||||
:name (obj/get color "name")
|
||||
:path (obj/get color "path")
|
||||
:color (-> (obj/get color "color") parse-hex)
|
||||
:opacity (obj/get color "opacity")
|
||||
:ref-id (-> (obj/get color "refId") parse-id)
|
||||
:ref-file (-> (obj/get color "refFile") parse-id)
|
||||
:gradient (-> (obj/get color "gradient") parse-gradient)
|
||||
:image (-> (obj/get color "image") parse-image-data)})))
|
||||
|
||||
;; export interface PenpotShadow {
|
||||
;; id?: string;
|
||||
;; style?: 'drop-shadow' | 'inner-shadow';
|
||||
;; offsetX?: number;
|
||||
;; offsetY?: number;
|
||||
;; blur?: number;
|
||||
;; spread?: number;
|
||||
;; hidden?: boolean;
|
||||
;; color?: PenpotColor;
|
||||
;; }
|
||||
(defn parse-shadow
|
||||
[^js shadow]
|
||||
(when (some? shadow)
|
||||
(d/without-nils
|
||||
{:id (-> (obj/get shadow "id") parse-id)
|
||||
:style (-> (obj/get shadow "style") parse-keyword)
|
||||
:offset-x (obj/get shadow "offsetX")
|
||||
:offset-y (obj/get shadow "offsetY")
|
||||
:blur (obj/get shadow "blur")
|
||||
:spread (obj/get shadow "spread")
|
||||
:hidden (obj/get shadow "hidden")
|
||||
:color (-> (obj/get shadow "color") parse-color)})))
|
||||
|
||||
(defn parse-shadows
|
||||
[^js shadows]
|
||||
(when (some? shadows)
|
||||
(into [] (map parse-shadow) shadows)))
|
||||
|
||||
;;export interface PenpotFill {
|
||||
;; fillColor?: string;
|
||||
;; fillOpacity?: number;
|
||||
;; fillColorGradient?: PenpotGradient;
|
||||
;; fillColorRefFile?: string;
|
||||
;; fillColorRefId?: string;
|
||||
;; fillImage?: PenpotImageData;
|
||||
;;}
|
||||
(defn parse-fill
|
||||
[^js fill]
|
||||
(when (some? fill)
|
||||
(d/without-nils
|
||||
{:fill-color (-> (obj/get fill "fillColor") parse-hex)
|
||||
:fill-opacity (obj/get fill "fillOpacity")
|
||||
:fill-color-gradient (-> (obj/get fill "fillColorGradient") parse-gradient)
|
||||
:fill-color-ref-file (-> (obj/get fill "fillColorRefFile") parse-id)
|
||||
:fill-color-ref-id (-> (obj/get fill "fillColorRefId") parse-id)
|
||||
:fill-image (-> (obj/get fill "fillImage") parse-image-data)})))
|
||||
|
||||
(defn parse-fills
|
||||
[^js fills]
|
||||
(when (some? fills)
|
||||
(into [] (map parse-fill) fills)))
|
||||
|
||||
;; export interface PenpotStroke {
|
||||
;; strokeColor?: string;
|
||||
;; strokeColorRefFile?: string;
|
||||
;; strokeColorRefId?: string;
|
||||
;; strokeOpacity?: number;
|
||||
;; strokeStyle?: 'solid' | 'dotted' | 'dashed' | 'mixed' | 'none' | 'svg';
|
||||
;; strokeWidth?: number;
|
||||
;; strokeAlignment?: 'center' | 'inner' | 'outer';
|
||||
;; strokeCapStart?: PenpotStrokeCap;
|
||||
;; strokeCapEnd?: PenpotStrokeCap;
|
||||
;; strokeColorGradient?: PenpotGradient;
|
||||
;; }
|
||||
(defn parse-stroke
|
||||
[^js stroke]
|
||||
(when (some? stroke)
|
||||
(d/without-nils
|
||||
{:stroke-color (-> (obj/get stroke "strokeColor") parse-hex)
|
||||
:stroke-color-ref-file (-> (obj/get stroke "strokeColorRefFile") parse-id)
|
||||
:stroke-color-ref-id (-> (obj/get stroke "strokeColorRefId") parse-id)
|
||||
:stroke-opacity (obj/get stroke "strokeOpacity")
|
||||
:stroke-style (-> (obj/get stroke "strokeStyle") parse-keyword)
|
||||
:stroke-width (obj/get stroke "strokeWidth")
|
||||
:stroke-alignment (-> (obj/get stroke "strokeAlignment") parse-keyword)
|
||||
:stroke-cap-start (-> (obj/get stroke "strokeCapStart") parse-keyword)
|
||||
:stroke-cap-end (-> (obj/get stroke "strokeCapEnd") parse-keyword)
|
||||
:stroke-color-gradient (-> (obj/get stroke "strokeColorGradient") parse-gradient)})))
|
||||
|
||||
(defn parse-strokes
|
||||
[^js strokes]
|
||||
(when (some? strokes)
|
||||
(into [] (map parse-stroke) strokes)))
|
||||
|
||||
;; export interface PenpotBlur {
|
||||
;; id?: string;
|
||||
;; type?: 'layer-blur';
|
||||
;; value?: number;
|
||||
;; hidden?: boolean;
|
||||
;; }
|
||||
(defn parse-blur
|
||||
[^js blur]
|
||||
(when (some? blur)
|
||||
(d/without-nils
|
||||
{:id (-> (obj/get blur "id") parse-id)
|
||||
:type (-> (obj/get blur "type") parse-keyword)
|
||||
:value (obj/get blur "value")
|
||||
:hidden (obj/get blur "hidden")})))
|
||||
|
||||
|
||||
;; export interface PenpotExport {
|
||||
;; type: 'png' | 'jpeg' | 'svg' | 'pdf';
|
||||
;; scale: number;
|
||||
;; suffix: string;
|
||||
;; }
|
||||
(defn parse-export
|
||||
[^js export]
|
||||
(when (some? export)
|
||||
(d/without-nils
|
||||
{:type (-> (obj/get export "type") parse-keyword)
|
||||
:scale (obj/get export "scale")
|
||||
:suffix (obj/get export "suffix")})))
|
||||
|
||||
(defn parse-exports
|
||||
[^js exports]
|
||||
(when (some? exports)
|
||||
(into [] (map parse-export) exports)))
|
||||
|
||||
;; export interface PenpotFrameGuideColumnParams {
|
||||
;; color: { color: string; opacity: number };
|
||||
;; type?: 'stretch' | 'left' | 'center' | 'right';
|
||||
;; size?: number;
|
||||
;; margin?: number;
|
||||
;; itemLength?: number;
|
||||
;; gutter?: number;
|
||||
;; }
|
||||
(defn parse-frame-guide-column-params
|
||||
[^js params]
|
||||
(when params
|
||||
(d/without-nils
|
||||
{:color (-> (obj/get params "color") parse-color)
|
||||
:type (-> (obj/get params "type") parse-keyword)
|
||||
:size (obj/get params "size")
|
||||
:margin (obj/get params "margin")
|
||||
:item-length (obj/get params "itemLength")
|
||||
:gutter (obj/get params "gutter")})))
|
||||
|
||||
;; export interface PenpotFrameGuideColumn {
|
||||
;; type: 'column';
|
||||
;; display: boolean;
|
||||
;; params: PenpotFrameGuideColumnParams;
|
||||
;; }
|
||||
(defn parse-frame-guide-column
|
||||
[^js guide]
|
||||
(when guide
|
||||
(d/without-nils
|
||||
{:type (-> (obj/get guide "type") parse-keyword)
|
||||
:display (obj/get guide "display")
|
||||
:params (-> (obj/get guide "params") parse-frame-guide-column-params)})))
|
||||
|
||||
;; export interface PenpotFrameGuideRow {
|
||||
;; type: 'row';
|
||||
;; display: boolean;
|
||||
;; params: PenpotFrameGuideColumnParams;
|
||||
;; }
|
||||
|
||||
(defn parse-frame-guide-row
|
||||
[^js guide]
|
||||
(when guide
|
||||
(d/without-nils
|
||||
{:type (-> (obj/get guide "type") parse-keyword)
|
||||
:display (obj/get guide "display")
|
||||
:params (-> (obj/get guide "params") parse-frame-guide-column-params)})))
|
||||
|
||||
;;export interface PenpotFrameGuideSquareParams {
|
||||
;; color: { color: string; opacity: number };
|
||||
;; size?: number;
|
||||
;;}
|
||||
(defn parse-frame-guide-square-params
|
||||
[^js params]
|
||||
(when (some? params)
|
||||
(d/without-nils
|
||||
{:color (-> (obj/get params "color") parse-color)
|
||||
:size (obj/get params "size")})))
|
||||
|
||||
;; export interface PenpotFrameGuideSquare {
|
||||
;; type: 'square';
|
||||
;; display: boolean;
|
||||
;; params: PenpotFrameGuideSquareParams;
|
||||
;; }
|
||||
(defn parse-frame-guide-square
|
||||
[^js guide]
|
||||
(when guide
|
||||
(d/without-nils
|
||||
{:type (-> (obj/get guide "type") parse-keyword)
|
||||
:display (obj/get guide "display")
|
||||
:params (-> (obj/get guide "params") parse-frame-guide-column-params)})))
|
||||
|
||||
(defn parse-frame-guide
|
||||
[^js guide]
|
||||
(when (some? guide)
|
||||
(case (obj/get guide "type")
|
||||
"column"
|
||||
parse-frame-guide-column
|
||||
|
||||
"row"
|
||||
parse-frame-guide-row
|
||||
|
||||
"square"
|
||||
(parse-frame-guide-square guide))))
|
||||
|
||||
(defn parse-frame-guides
|
||||
[^js guides]
|
||||
(when (some? guides)
|
||||
(into [] (map parse-frame-guide) guides)))
|
||||
|
||||
;;interface PenpotPathCommand {
|
||||
;; command:
|
||||
;; | 'M' | 'move-to'
|
||||
;; | 'Z' | 'close-path'
|
||||
;; | 'L' | 'line-to'
|
||||
;; | 'H' | 'line-to-horizontal'
|
||||
;; | 'V' | 'line-to-vertical'
|
||||
;; | 'C' | 'curve-to'
|
||||
;; | 'S' | 'smooth-curve-to'
|
||||
;; | 'Q' | 'quadratic-bezier-curve-to'
|
||||
;; | 'T' | 'smooth-quadratic-bezier-curve-to'
|
||||
;; | 'A' | 'elliptical-arc';
|
||||
;;
|
||||
;; params?: {
|
||||
;; x?: number;
|
||||
;; y?: number;
|
||||
;; c1x: number;
|
||||
;; c1y: number;
|
||||
;; c2x: number;
|
||||
;; c2y: number;
|
||||
;; rx?: number;
|
||||
;; ry?: number;
|
||||
;; xAxisRotation?: number;
|
||||
;; largeArcFlag?: boolean;
|
||||
;; sweepFlag?: boolean;
|
||||
;; };
|
||||
;;}
|
||||
(defn parse-command-type
|
||||
[^string command-type]
|
||||
(case command-type
|
||||
"M" :move-to
|
||||
"Z" :close-path
|
||||
"L" :line-to
|
||||
"H" :line-to-horizontal
|
||||
"V" :line-to-vertical
|
||||
"C" :curve-to
|
||||
"S" :smooth-curve-to
|
||||
"Q" :quadratic-bezier-curve-to
|
||||
"T" :smooth-quadratic-bezier-curve-to
|
||||
"A" :elliptical-arc
|
||||
(parse-keyword command-type)))
|
||||
|
||||
(defn parse-command-params
|
||||
[^js params]
|
||||
(when (some? params)
|
||||
(d/without-nils
|
||||
{:x (obj/get params "x")
|
||||
:y (obj/get params "y")
|
||||
:c1x (obj/get params "c1x")
|
||||
:c1y (obj/get params "c1y")
|
||||
:c2x (obj/get params "c2x")
|
||||
:c2y (obj/get params "c2y")
|
||||
:rx (obj/get params "rx")
|
||||
:ry (obj/get params "ry")
|
||||
:x-axis-rotation (obj/get params "xAxisRotation")
|
||||
:large-arc-flag (obj/get params "largeArcFlag")
|
||||
:sweep-flag (obj/get params "sweepFlag")})))
|
||||
|
||||
(defn parse-command
|
||||
[^js command]
|
||||
(when (some? command)
|
||||
(d/without-nils
|
||||
{:command (-> (obj/get command "command") parse-command-type)
|
||||
:params (-> (obj/get command "paras") parse-command-params)})))
|
||||
|
||||
(defn parse-path-content
|
||||
[^js content]
|
||||
(when (some? content)
|
||||
(into [] (map parse-command) content)))
|
|
@ -9,6 +9,7 @@
|
|||
(:require
|
||||
[app.common.geom.rect :as grc]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.plugins.format :as format]
|
||||
[app.plugins.shape :as shape]
|
||||
[app.plugins.utils :as u]))
|
||||
|
||||
|
@ -22,4 +23,4 @@
|
|||
(let [shapes (->> shapes (map u/proxy->shape))]
|
||||
(-> (gsh/shapes->rect shapes)
|
||||
(grc/rect->center)
|
||||
(u/to-js)))))
|
||||
(format/format-point)))))
|
||||
|
|
55
frontend/src/app/plugins/register.cljs
Normal file
55
frontend/src/app/plugins/register.cljs
Normal file
|
@ -0,0 +1,55 @@
|
|||
;; 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.plugins.register
|
||||
"RPC for plugins runtime."
|
||||
(:require
|
||||
[app.common.data :as d]))
|
||||
|
||||
;; TODO: Remove clj->js and parse into a better data structure for accessing the permissions
|
||||
|
||||
(def pluginsdb (atom nil))
|
||||
|
||||
(defn load-from-store
|
||||
[]
|
||||
(let [ls (.-localStorage js/window)
|
||||
plugins-val (.getItem ls "plugins")]
|
||||
(when plugins-val
|
||||
(let [plugins-js (.parse js/JSON plugins-val)]
|
||||
(js->clj plugins-js {:keywordize-keys true})))))
|
||||
|
||||
(defn save-to-store
|
||||
[plugins]
|
||||
(let [ls (.-localStorage js/window)
|
||||
plugins-js (clj->js plugins)
|
||||
plugins-val (.stringify js/JSON plugins-js)]
|
||||
(.setItem ls "plugins" plugins-val)))
|
||||
|
||||
(defn init
|
||||
[]
|
||||
(reset! pluginsdb (load-from-store)))
|
||||
|
||||
(defn install-plugin!
|
||||
[plugin]
|
||||
(let [plugins (vec (conj (seq @pluginsdb) plugin))]
|
||||
(reset! pluginsdb plugins)
|
||||
(save-to-store plugins)))
|
||||
|
||||
(defn remove-plugin!
|
||||
[{:keys [plugin-id]}]
|
||||
(let [plugins
|
||||
(into []
|
||||
(keep (fn [plugin]
|
||||
(when (not= plugin-id (:plugin-id plugin)) plugin)))
|
||||
@pluginsdb)]
|
||||
(reset! pluginsdb plugins)
|
||||
(save-to-store plugins)))
|
||||
|
||||
(defn check-permission
|
||||
[plugin-id permission]
|
||||
(or (= plugin-id "TEST")
|
||||
(let [{:keys [permissions]} (->> @pluginsdb (d/seek #(= (:plugin-id %) plugin-id)))]
|
||||
(->> permissions (d/seek #(= % permission))))))
|
File diff suppressed because it is too large
Load diff
575
frontend/src/app/plugins/text.cljs
Normal file
575
frontend/src/app/plugins/text.cljs
Normal file
|
@ -0,0 +1,575 @@
|
|||
;; 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.plugins.text
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.record :as crc]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.text :as txt]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.main.data.workspace.shapes :as dwsh]
|
||||
[app.main.data.workspace.texts :as dwt]
|
||||
[app.main.fonts :as fonts]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.format :as format]
|
||||
[app.plugins.parser :as parser]
|
||||
[app.plugins.register :as r]
|
||||
[app.plugins.utils :as u]
|
||||
[app.util.object :as obj]
|
||||
[app.util.text-editor :as ted]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
;; This regex seems duplicated but probably in the future when we support diferent units
|
||||
;; this will need to reflect changes for each property
|
||||
|
||||
(def font-size-re #"^\d*\.?\d*$")
|
||||
(def line-height-re #"^\d*\.?\d*$")
|
||||
(def letter-spacing-re #"^\d*\.?\d*$")
|
||||
(def text-transform-re #"uppercase|capitalize|lowercase|none")
|
||||
(def text-decoration-re #"underline|line-through|none")
|
||||
(def text-direction-re #"ltr|rtl")
|
||||
(def text-align-re #"left|center|right|justify")
|
||||
(def vertical-align-re #"top|center|bottom")
|
||||
|
||||
(defn mixed-value
|
||||
[values]
|
||||
(let [s (set values)]
|
||||
(if (= (count s) 1) (first s) "mixed")))
|
||||
|
||||
(defn font-data
|
||||
[font variant]
|
||||
(d/without-nils
|
||||
{:font-id (:id font)
|
||||
:font-family (:family font)
|
||||
:font-variant-id (:id variant)
|
||||
:font-style (:style variant)
|
||||
:font-weight (:weight variant)}))
|
||||
|
||||
(defn variant-data
|
||||
[variant]
|
||||
(d/without-nils
|
||||
{:font-variant-id (:id variant)
|
||||
:font-style (:style variant)
|
||||
:font-weight (:weight variant)}))
|
||||
|
||||
(deftype TextRange [$plugin $file $page $id start end]
|
||||
Object
|
||||
(applyTypography [_ typography]
|
||||
(let [typography (u/proxy->library-typography typography)
|
||||
attrs (-> typography
|
||||
(assoc :typography-ref-file $file)
|
||||
(assoc :typography-ref-id (:id typography))
|
||||
(dissoc :id :name))]
|
||||
(st/emit! (dwt/update-text-range $id start end attrs)))))
|
||||
|
||||
(defn text-range?
|
||||
[range]
|
||||
(instance? TextRange range))
|
||||
|
||||
(defn text-props
|
||||
[shape]
|
||||
(d/merge
|
||||
(dwt/current-root-values {:shape shape :attrs txt/root-attrs})
|
||||
(dwt/current-paragraph-values {:shape shape :attrs txt/paragraph-attrs})
|
||||
(dwt/current-text-values {:shape shape :attrs txt/text-node-attrs})))
|
||||
|
||||
(defn text-range
|
||||
[plugin-id file-id page-id id start end]
|
||||
(-> (TextRange. plugin-id file-id page-id id start end)
|
||||
(crc/add-properties!
|
||||
{:name "$plugin" :enumerable false :get (constantly plugin-id)}
|
||||
{:name "$id" :enumerable false :get (constantly id)}
|
||||
{:name "$file" :enumerable false :get (constantly file-id)}
|
||||
{:name "$page" :enumerable false :get (constantly page-id)}
|
||||
|
||||
{:name "shape"
|
||||
:get #(-> % u/proxy->shape)}
|
||||
|
||||
{:name "characters"
|
||||
:get #(let [range-data
|
||||
(-> % u/proxy->shape :content (txt/content-range->text+styles start end))]
|
||||
(->> range-data (map :text) (str/join "")))}
|
||||
|
||||
{:name "fontId"
|
||||
:get #(let [range-data
|
||||
(-> % u/proxy->shape :content (txt/content-range->text+styles start end))]
|
||||
(->> range-data (map :font-id) mixed-value))
|
||||
|
||||
:set
|
||||
(fn [_ value]
|
||||
(let [font (when (string? value) (fonts/get-font-data value))
|
||||
variant (fonts/get-default-variant font)]
|
||||
(cond
|
||||
(not (some? font))
|
||||
(u/display-not-valid :fontId value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :fontId "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-text-range id start end (font-data font variant))))))}
|
||||
|
||||
{:name "fontFamily"
|
||||
:get #(let [range-data
|
||||
(-> % u/proxy->shape :content (txt/content-range->text+styles start end))]
|
||||
(->> range-data (map :font-family) mixed-value))
|
||||
|
||||
:set
|
||||
(fn [_ value]
|
||||
(let [font (fonts/find-font-data {:font-family value})
|
||||
variant (fonts/get-default-variant font)]
|
||||
(cond
|
||||
(not (string? value))
|
||||
(u/display-not-valid :fontFamily value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :fontFamily "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-text-range id start end (font-data font variant))))))}
|
||||
|
||||
{:name "fontVariantId"
|
||||
:get #(let [range-data
|
||||
(-> % u/proxy->shape :content (txt/content-range->text+styles start end))]
|
||||
(->> range-data (map :font-variant-id) mixed-value))
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [font (fonts/get-font-data (obj/get self "fontId"))
|
||||
variant (fonts/get-variant font value)]
|
||||
(cond
|
||||
(not (string? value))
|
||||
(u/display-not-valid :fontVariantId value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :fontVariantId "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-text-range id start end (variant-data variant))))))}
|
||||
|
||||
{:name "fontSize"
|
||||
:get #(let [range-data
|
||||
(-> % u/proxy->shape :content (txt/content-range->text+styles start end))]
|
||||
(->> range-data (map :font-size) mixed-value))
|
||||
:set
|
||||
(fn [_ value]
|
||||
(let [value (str/trim (dm/str value))]
|
||||
(cond
|
||||
(or (empty? value) (not (re-matches font-size-re value)))
|
||||
(u/display-not-valid :fontSize value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :fontSize "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-text-range id start end {:font-size value})))))}
|
||||
|
||||
{:name "fontWeight"
|
||||
:get #(let [range-data
|
||||
(-> % u/proxy->shape :content (txt/content-range->text+styles start end))]
|
||||
(->> range-data (map :font-weight) mixed-value))
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [font (fonts/get-font-data (obj/get self "fontId"))
|
||||
variant (fonts/find-variant font {:weight (dm/str value)})]
|
||||
(cond
|
||||
(nil? variant)
|
||||
(u/display-not-valid :fontWeight (dm/str "Font weight '" value "' not supported for the current font"))
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :fontWeight "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-text-range id start end (variant-data variant))))))}
|
||||
|
||||
{:name "fontStyle"
|
||||
:get #(let [range-data
|
||||
(-> % u/proxy->shape :content (txt/content-range->text+styles start end))]
|
||||
(->> range-data (map :font-style) mixed-value))
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [font (fonts/get-font-data (obj/get self "fontId"))
|
||||
variant (fonts/find-variant font {:weight (dm/str value)})]
|
||||
(cond
|
||||
(nil? variant)
|
||||
(u/display-not-valid :fontStyle (dm/str "Font style '" value "' not supported for the current font"))
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :fontStyle "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-text-range id start end (variant-data variant))))))}
|
||||
|
||||
{:name "lineHeight"
|
||||
:get #(let [range-data
|
||||
(-> % u/proxy->shape :content (txt/content-range->text+styles start end))]
|
||||
(->> range-data (map :line-height) mixed-value))
|
||||
:set
|
||||
(fn [_ value]
|
||||
(let [value (str/trim (dm/str value))]
|
||||
(cond
|
||||
(or (empty? value) (not (re-matches line-height-re value)))
|
||||
(u/display-not-valid :lineHeight value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :lineHeight "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-text-range id start end {:line-height value})))))}
|
||||
|
||||
{:name "letterSpacing"
|
||||
:get #(let [range-data
|
||||
(-> % u/proxy->shape :content (txt/content-range->text+styles start end))]
|
||||
(->> range-data (map :letter-spacing) mixed-value))
|
||||
:set
|
||||
(fn [_ value]
|
||||
(let [value (str/trim (dm/str value))]
|
||||
(cond
|
||||
(or (empty? value) (re-matches letter-spacing-re value))
|
||||
(u/display-not-valid :letterSpacing value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :letterSpacing "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-text-range id start end {:letter-spacing value})))))}
|
||||
|
||||
{:name "textTransform"
|
||||
:get #(let [range-data
|
||||
(-> % u/proxy->shape :content (txt/content-range->text+styles start end))]
|
||||
(->> range-data (map :text-transform) mixed-value))
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(and (string? value) (re-matches text-transform-re value))
|
||||
(u/display-not-valid :textTransform value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :textTransform "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-text-range id start end {:text-transform value}))))}
|
||||
|
||||
{:name "textDecoration"
|
||||
:get #(let [range-data
|
||||
(-> % u/proxy->shape :content (txt/content-range->text+styles start end))]
|
||||
(->> range-data (map :text-decoration) mixed-value))
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(and (string? value) (re-matches text-decoration-re value))
|
||||
(u/display-not-valid :textDecoration value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :textDecoration "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-text-range id start end {:text-decoration value}))))}
|
||||
|
||||
{:name "direction"
|
||||
:get #(let [range-data
|
||||
(-> % u/proxy->shape :content (txt/content-range->text+styles start end))]
|
||||
(->> range-data (map :direction) mixed-value))
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(and (string? value) (re-matches text-direction-re value))
|
||||
(u/display-not-valid :direction value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :direction "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-text-range id start end {:direction value}))))}
|
||||
|
||||
{:name "align"
|
||||
:get #(let [range-data
|
||||
(-> % u/proxy->shape :content (txt/content-range->text+styles start end))]
|
||||
(->> range-data (map :text-align) mixed-value))
|
||||
:set
|
||||
(fn [_ value]
|
||||
(cond
|
||||
(and (string? value) (re-matches text-align-re value))
|
||||
(u/display-not-valid :align value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :align "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-text-range id start end {:text-align value}))))}
|
||||
|
||||
{:name "fills"
|
||||
:get #(let [range-data
|
||||
(-> % u/proxy->shape :content (txt/content-range->text+styles start end))]
|
||||
(->> range-data (map :fills) mixed-value format/format-fills))
|
||||
:set
|
||||
(fn [_ value]
|
||||
(let [value (parser/parse-fills value)]
|
||||
(cond
|
||||
(not (sm/validate [:vector ::cts/fill] value))
|
||||
(u/display-not-valid :fills value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :fills "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-text-range id start end {:fills value})))))})))
|
||||
|
||||
(defn add-text-props
|
||||
[plugin-id shape-proxy]
|
||||
(crc/add-properties!
|
||||
shape-proxy
|
||||
{:name "characters"
|
||||
:get #(-> % u/proxy->shape :content txt/content->text)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")]
|
||||
;; The user is currently editing the text. We need to update the
|
||||
;; editor as well
|
||||
(cond
|
||||
(or (not (string? value)) (empty? value))
|
||||
(u/display-not-valid :characters value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :characters "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
(contains? (:workspace-editor-state @st/state) id)
|
||||
(let [shape (u/proxy->shape self)
|
||||
editor
|
||||
(-> shape
|
||||
(txt/change-text value)
|
||||
:content
|
||||
ted/import-content
|
||||
ted/create-editor-state)]
|
||||
(st/emit! (dwt/update-editor-state shape editor)))
|
||||
|
||||
:else
|
||||
(st/emit! (dwsh/update-shapes [id] #(txt/change-text % value))))))}
|
||||
|
||||
{:name "growType"
|
||||
:get #(-> % u/proxy->shape :grow-type d/name)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")
|
||||
value (keyword value)]
|
||||
(cond
|
||||
(not (contains? #{:auto-width :auto-height :fixed} value))
|
||||
(u/display-not-valid :growType value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :growType "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwsh/update-shapes [id] #(assoc % :grow-type value))))))}
|
||||
|
||||
{:name "fontId"
|
||||
:get #(-> % u/proxy->shape text-props :font-id format/format-mixed)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")
|
||||
font (when (string? value) (fonts/get-font-data value))
|
||||
variant (fonts/get-default-variant font)]
|
||||
(cond
|
||||
(not (some? font))
|
||||
(u/display-not-valid :fontId value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :fontId "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-attrs id (font-data font variant))))))}
|
||||
|
||||
{:name "fontFamily"
|
||||
:get #(-> % u/proxy->shape text-props :font-family format/format-mixed)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")
|
||||
font (fonts/find-font-data {:font-family value})
|
||||
variant (fonts/get-default-variant font)]
|
||||
(cond
|
||||
(not (some? font))
|
||||
(u/display-not-valid :fontFamily value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :fontFamily "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-attrs id (font-data font variant))))))}
|
||||
|
||||
{:name "fontVariantId"
|
||||
:get #(-> % u/proxy->shape text-props :font-variant-id format/format-mixed)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")
|
||||
font (fonts/get-font-data (obj/get self "fontId"))
|
||||
variant (fonts/get-variant font value)]
|
||||
(cond
|
||||
(not (some? variant))
|
||||
(u/display-not-valid :fontVariantId value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :fontVariantId "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-attrs id (variant-data variant))))))}
|
||||
|
||||
{:name "fontSize"
|
||||
:get #(-> % u/proxy->shape text-props :font-size format/format-mixed)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")
|
||||
value (str/trim (dm/str value))]
|
||||
(cond
|
||||
(or (empty? value) (not (re-matches font-size-re value)))
|
||||
(u/display-not-valid :fontSize value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :fontSize "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-attrs id {:font-size value})))))}
|
||||
|
||||
{:name "fontWeight"
|
||||
:get #(-> % u/proxy->shape text-props :font-weight format/format-mixed)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")
|
||||
font (fonts/get-font-data (obj/get self "fontId"))
|
||||
variant (fonts/find-variant font {:weight (dm/str value)})]
|
||||
(cond
|
||||
(nil? variant)
|
||||
(u/display-not-valid :fontWeight (dm/str "Font weight '" value "' not supported for the current font"))
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :fontWeight "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-attrs id (variant-data variant))))))}
|
||||
|
||||
{:name "fontStyle"
|
||||
:get #(-> % u/proxy->shape text-props :font-style format/format-mixed)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")
|
||||
font (fonts/get-font-data (obj/get self "fontId"))
|
||||
variant (fonts/find-variant font {:weight (dm/str value)})]
|
||||
(cond
|
||||
(nil? variant)
|
||||
(u/display-not-valid :fontStyle (dm/str "Font style '" value "' not supported for the current font"))
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :fontStyle "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-attrs id (variant-data variant))))))}
|
||||
|
||||
{:name "lineHeight"
|
||||
:get #(-> % u/proxy->shape text-props :line-height format/format-mixed)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")
|
||||
value (str/trim (dm/str value))]
|
||||
(cond
|
||||
(or (empty? value) (not (re-matches line-height-re value)))
|
||||
(u/display-not-valid :lineHeight value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :lineHeight "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-attrs id {:line-height value})))))}
|
||||
|
||||
{:name "letterSpacing"
|
||||
:get #(-> % u/proxy->shape text-props :letter-spacing format/format-mixed)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")
|
||||
value (str/trim (dm/str value))]
|
||||
(cond
|
||||
(or (empty? value) (re-matches letter-spacing-re value))
|
||||
(u/display-not-valid :letterSpacing value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :letterSpacing "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-attrs id {:letter-spacing value})))))}
|
||||
|
||||
{:name "textTransform"
|
||||
:get #(-> % u/proxy->shape text-props :text-transform format/format-mixed)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")]
|
||||
(cond
|
||||
(and (string? value) (re-matches text-transform-re value))
|
||||
(u/display-not-valid :textTransform value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :textTransform "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-attrs id {:text-transform value})))))}
|
||||
|
||||
{:name "textDecoration"
|
||||
:get #(-> % u/proxy->shape text-props :text-decoration format/format-mixed)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")]
|
||||
(cond
|
||||
(and (string? value) (re-matches text-decoration-re value))
|
||||
(u/display-not-valid :textDecoration value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :textDecoration "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-attrs id {:text-decoration value})))))}
|
||||
|
||||
{:name "direction"
|
||||
:get #(-> % u/proxy->shape text-props :text-direction format/format-mixed)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")]
|
||||
(cond
|
||||
(and (string? value) (re-matches text-direction-re value))
|
||||
(u/display-not-valid :textDirection value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :textDirection "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-attrs id {:text-direction value})))))}
|
||||
|
||||
{:name "align"
|
||||
:get #(-> % u/proxy->shape text-props :text-align format/format-mixed)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")]
|
||||
(cond
|
||||
(and (string? value) (re-matches text-align-re value))
|
||||
(u/display-not-valid :align value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :align "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-attrs id {:text-align value})))))}
|
||||
|
||||
{:name "verticalAlign"
|
||||
:get #(-> % u/proxy->shape text-props :vertical-align)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (obj/get self "$id")]
|
||||
(cond
|
||||
(and (string? value) (re-matches vertical-align-re value))
|
||||
(u/display-not-valid :verticalAlign value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
(u/display-not-valid :verticalAlign "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwt/update-attrs id {:vertical-align value})))))}))
|
|
@ -8,6 +8,7 @@
|
|||
(:require
|
||||
[app.common.record :as crc]
|
||||
[app.config :as cfg]
|
||||
[app.plugins.format :as format]
|
||||
[app.plugins.utils :as u]
|
||||
[app.util.object :as obj]))
|
||||
|
||||
|
@ -54,5 +55,5 @@
|
|||
(-> (ActiveUserProxy. plugin-id session-id)
|
||||
(add-user-properties)
|
||||
(crc/add-properties!
|
||||
{:name "position" :get (fn [_] (-> (u/locate-presence session-id) :point u/to-js))}
|
||||
{:name "position" :get (fn [_] (-> (u/locate-presence session-id) :point format/format-point))}
|
||||
{:name "zoom" :get (fn [_] (-> (u/locate-presence session-id) :zoom))})))
|
||||
|
|
|
@ -9,13 +9,10 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.spec :as us]
|
||||
[app.common.types.container :as ctn]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.store :as st]
|
||||
[app.util.object :as obj]
|
||||
[cuerdas.core :as str]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(defn locate-file
|
||||
|
@ -143,58 +140,6 @@
|
|||
(-> (get-state self attr)
|
||||
(mapfn))))
|
||||
|
||||
(defn from-js
|
||||
"Converts the object back to js"
|
||||
([obj]
|
||||
(from-js obj #{:type}))
|
||||
([obj keyword-keys]
|
||||
(when (some? obj)
|
||||
(let [process-node
|
||||
(fn process-node [node]
|
||||
(reduce-kv
|
||||
(fn [m k v]
|
||||
(let [k (keyword (str/kebab k))
|
||||
v (cond (map? v)
|
||||
(process-node v)
|
||||
|
||||
(vector? v)
|
||||
(mapv process-node v)
|
||||
|
||||
(and (string? v) (re-matches us/uuid-rx v))
|
||||
(uuid/uuid v)
|
||||
|
||||
(contains? keyword-keys k)
|
||||
(keyword v)
|
||||
|
||||
:else v)]
|
||||
(assoc m k v)))
|
||||
{}
|
||||
node))]
|
||||
(process-node (js->clj obj))))))
|
||||
|
||||
(defn to-js
|
||||
"Converts to javascript an camelize the keys"
|
||||
[obj]
|
||||
(when (some? obj)
|
||||
(let [result
|
||||
(reduce-kv
|
||||
(fn [m k v]
|
||||
(let [v (cond (object? v) (to-js v)
|
||||
(uuid? v) (dm/str v)
|
||||
:else v)]
|
||||
(assoc m (str/camel (name k)) v)))
|
||||
{}
|
||||
obj)]
|
||||
(clj->js result))))
|
||||
|
||||
(defn array-to-js
|
||||
[value]
|
||||
(if (coll? value)
|
||||
(.freeze
|
||||
js/Object
|
||||
(apply array (->> value (map to-js))))
|
||||
value))
|
||||
|
||||
(defn result-p
|
||||
"Creates a pair of atom+promise. The promise will be resolved when the atom gets a value.
|
||||
We use this to return the promise to the library clients and resolve its value when a value is passed
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
[app.main.data.workspace.viewport :as dwv]
|
||||
[app.main.data.workspace.zoom :as dwz]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.format :as format]
|
||||
[app.plugins.utils :as u]
|
||||
[app.util.object :as obj]))
|
||||
|
||||
|
@ -88,6 +89,6 @@
|
|||
:get
|
||||
(fn [_]
|
||||
(let [vport (dm/get-in @st/state [:workspace-local :vport])]
|
||||
(.freeze js/Object (clj->js vport))))}))
|
||||
(.freeze js/Object (format/format-bounds vport))))}))
|
||||
|
||||
|
||||
|
|
|
@ -156,3 +156,8 @@
|
|||
x)
|
||||
|
||||
:else x)))
|
||||
|
||||
(defn clear-empty
|
||||
[^js obj]
|
||||
(when (some? obj)
|
||||
(js* "Object.entries(~{}).reduce((a, [k,v]) => (v == null ? a : (a[k]=v, a)), {}) " obj)))
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
_ (set! st/state store)
|
||||
|
||||
context (api/create-context "tests")
|
||||
context (api/create-context "TEST")
|
||||
|
||||
page (. context -currentPage)
|
||||
|
||||
|
@ -162,9 +162,8 @@
|
|||
:offset-y 4
|
||||
:blur 4
|
||||
:spread 0
|
||||
:color {:color "#FABADA" :opacity 1}
|
||||
:color {:color "#fabada" :opacity 1}
|
||||
:hidden false}]))))
|
||||
|
||||
(let [shadow #js {:style "fail"}]
|
||||
(set! (.-shadows shape) #js [shadow])
|
||||
(t/is (= (-> (. shape -shadows) (aget 0) (aget "style")) "drop-shadow"))))
|
||||
|
@ -208,20 +207,20 @@
|
|||
|
||||
(t/testing " - fills"
|
||||
(set! (.-fills shape) #js [#js {:fillColor 100}])
|
||||
(t/is (= (-> (. shape -fills) (aget 0) (aget "fillColor")) "#B1B2B5"))
|
||||
(t/is (= (get-in @store (get-shape-path :fills)) [{:fill-color "#B1B2B5" :fill-opacity 1}]))
|
||||
(t/is (= (-> (. shape -fills) (aget 0) (aget "fillColor")) "#B1B2B5"))
|
||||
|
||||
(set! (.-fills shape) #js [#js {:fillColor "#FABADA" :fillOpacity 1}])
|
||||
(t/is (= (-> (. shape -fills) (aget 0) (aget "fillColor")) "#FABADA"))
|
||||
(t/is (= (-> (. shape -fills) (aget 0) (aget "fillOpacity")) 1))
|
||||
(t/is (= (get-in @store (get-shape-path :fills)) [{:fill-color "#FABADA" :fill-opacity 1}])))
|
||||
(set! (.-fills shape) #js [#js {:fillColor "#fabada" :fillOpacity 1}])
|
||||
(t/is (= (get-in @store (get-shape-path :fills)) [{:fill-color "#fabada" :fill-opacity 1}]))
|
||||
(t/is (= (-> (. shape -fills) (aget 0) (aget "fillColor")) "#fabada"))
|
||||
(t/is (= (-> (. shape -fills) (aget 0) (aget "fillOpacity")) 1)))
|
||||
|
||||
(t/testing " - strokes"
|
||||
(set! (.-fills shape) #js [#js {:strokeColor "#FABADA" :strokeOpacity 1 :stroke-width 5}])
|
||||
(t/is (= (-> (. shape -fills) (aget 0) (aget "strokeColor")) "#FABADA"))
|
||||
(t/is (= (-> (. shape -fills) (aget 0) (aget "strokeOpacity")) 1))
|
||||
(t/is (= (-> (. shape -fills) (aget 0) (aget "strokeWidth")) 5))
|
||||
(t/is (= (get-in @store (get-shape-path :fills)) [{:stroke-color "#FABADA" :stroke-opacity 1 :stroke-width 5}]))))
|
||||
(set! (.-strokes shape) #js [#js {:strokeColor "#fabada" :strokeOpacity 1 :strokeWidth 5}])
|
||||
(t/is (= (get-in @store (get-shape-path :strokes)) [{:stroke-color "#fabada" :stroke-opacity 1 :stroke-width 5}]))
|
||||
(t/is (= (-> (. shape -strokes) (aget 0) (aget "strokeColor")) "#fabada"))
|
||||
(t/is (= (-> (. shape -strokes) (aget 0) (aget "strokeOpacity")) 1))
|
||||
(t/is (= (-> (. shape -strokes) (aget 0) (aget "strokeWidth")) 5))))
|
||||
|
||||
(t/testing "Relative properties"
|
||||
(let [frame (.createFrame context)]
|
||||
|
|
|
@ -847,6 +847,9 @@ msgstr "Cancel"
|
|||
msgid "ds.confirm-ok"
|
||||
msgstr "Ok"
|
||||
|
||||
msgid "ds.confirm-allow"
|
||||
msgstr "Allow"
|
||||
|
||||
#: src/app/main/ui/confirm.cljs, src/app/main/ui/confirm.cljs
|
||||
msgid "ds.confirm-title"
|
||||
msgstr "Are you sure?"
|
||||
|
@ -5290,3 +5293,24 @@ msgstr "Plugins manager"
|
|||
|
||||
msgid "workspace.plugins.plugin-list-link"
|
||||
msgstr "Plugins List"
|
||||
|
||||
msgid "workspace.plugins.permissions.title"
|
||||
msgstr "THIS PLUGIN WANTS ACCESS TO:"
|
||||
|
||||
msgid "workspace.plugins.permissions.disclaimer"
|
||||
msgstr "Note that this plugin has been created by an external party."
|
||||
|
||||
msgid "workspace.plugins.permissions.content-read"
|
||||
msgstr "Read the content of files that users have access to."
|
||||
|
||||
msgid "workspace.plugins.permissions.content-write"
|
||||
msgstr "Read and modify the content of files that users have access to."
|
||||
|
||||
msgid "workspace.plugins.permissions.user-read"
|
||||
msgstr "Read the profile information of the current user."
|
||||
|
||||
msgid "workspace.plugins.permissions.library-read"
|
||||
msgstr "Read your libraries and assets."
|
||||
|
||||
msgid "workspace.plugins.permissions.library-write"
|
||||
msgstr "Read and modify your libraries and assets."
|
||||
|
|
|
@ -869,6 +869,9 @@ msgstr "Cancelar"
|
|||
msgid "ds.confirm-ok"
|
||||
msgstr "Ok"
|
||||
|
||||
msgid "ds.confirm-allow"
|
||||
msgstr "Permitir"
|
||||
|
||||
#: src/app/main/ui/confirm.cljs, src/app/main/ui/confirm.cljs
|
||||
msgid "ds.confirm-title"
|
||||
msgstr "¿Está Seguro?"
|
||||
|
@ -5394,3 +5397,24 @@ msgstr "Gestor de extensiones"
|
|||
|
||||
msgid "workspace.plugins.plugin-list-link"
|
||||
msgstr "Lista de extensiones"
|
||||
|
||||
msgid "workspace.plugins.permissions.title"
|
||||
msgstr "LA EXTENSIÓN SOLICITA PERMISO PARA ACCEDER:"
|
||||
|
||||
msgid "workspace.plugins.permissions.disclaimer"
|
||||
msgstr "Tenga en cuenta que esta extensión ha sido desarrollada por terceros."
|
||||
|
||||
msgid "workspace.plugins.permissions.content-read"
|
||||
msgstr "Leer el contenido de sus archivos."
|
||||
|
||||
msgid "workspace.plugins.permissions.content-write"
|
||||
msgstr "Leer y modificar el contenido de sus archivos."
|
||||
|
||||
msgid "workspace.plugins.permissions.user-read"
|
||||
msgstr "Leer la información del usuario actual."
|
||||
|
||||
msgid "workspace.plugins.permissions.library-read"
|
||||
msgstr "Leer la información de sus bibliotecas y recursos."
|
||||
|
||||
msgid "workspace.plugins.permissions.library-write"
|
||||
msgstr "Leer y modificar la información de sus bibliotecas y recursos."
|
||||
|
|
Loading…
Add table
Reference in a new issue