diff --git a/CHANGES.md b/CHANGES.md index 68e935d56..64671a27e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,7 @@ ### :bug: Bugs fixed + ## 2.6.0 (Unreleased) ### :rocket: Epics and highlights @@ -35,6 +36,9 @@ - Fix duplicate page with component over frame [Taiga #8151](https://tree.taiga.io/project/penpot/issue/8151) and [Taiga #9698](https://tree.taiga.io/project/penpot/issue/9698) - The plugin list in the navigation menu lacks scrolling, some plugins are not visible when a large number are installed [Taiga #9360](https://tree.taiga.io/project/penpot/us/9360) - Fix hidden toolbar click event still available [Taiga #10437](https://tree.taiga.io/project/penpot/us/10437) +- Fix hovering over templates [Taiga #10545](https://tree.taiga.io/project/penpot/issue/10545) +- Fix problem with default shadows value in plugins [Plugins #191](https://github.com/penpot/penpot-plugins/issues/191) +- Fix problem with constraints when creating group [Taiga #10455](https://tree.taiga.io/project/penpot/issue/10455) ## 2.5.4 diff --git a/backend/src/app/srepl/helpers.clj b/backend/src/app/srepl/helpers.clj index d8293253e..aee2ffd3d 100644 --- a/backend/src/app/srepl/helpers.clj +++ b/backend/src/app/srepl/helpers.clj @@ -10,6 +10,7 @@ (:require [app.binfile.common :as bfc] [app.common.data :as d] + [app.common.files.migrations :as fmg] [app.common.files.validate :as cfv] [app.db :as db] [app.features.components-v2 :as feat.comp-v2] @@ -142,7 +143,9 @@ (update-fn file opts)))] (when (and (some? file') - (not (identical? file file'))) + (or (fmg/migrated? file) + (not (identical? file file')))) + (when validate? (cfv/validate-file-schema! file')) diff --git a/common/src/app/common/features.cljc b/common/src/app/common/features.cljc index bb5340e9c..b396e1937 100644 --- a/common/src/app/common/features.cljc +++ b/common/src/app/common/features.cljc @@ -61,7 +61,8 @@ "styles/v2" "layout/grid" "components/v2" - "plugins/runtime"}) + "plugins/runtime" + "design-tokens/v1"}) ;; A set of features which only affects on frontend and can be enabled ;; and disabled freely by the user any time. This features does not diff --git a/common/src/app/common/files/changes.cljc b/common/src/app/common/files/changes.cljc index a830bdefc..1a45f64bf 100644 --- a/common/src/app/common/files/changes.cljc +++ b/common/src/app/common/files/changes.cljc @@ -382,13 +382,13 @@ [:set-group-path [:vector :string]] [:set-group-fname :string]]] - [:move-token-set-before - [:map {:title "MoveTokenSetBefore"} - [:type [:= :move-token-set-before]] + [:move-token-set + [:map {:title "MoveTokenSet"} + [:type [:= :move-token-set]] [:from-path [:vector :string]] [:to-path [:vector :string]] [:before-path [:maybe [:vector :string]]] - [:before-group? [:maybe :boolean]]]] + [:before-group [:maybe :boolean]]]] [:move-token-set-group-before [:map {:title "MoveTokenSetGroupBefore"} @@ -1051,11 +1051,11 @@ (ctob/ensure-tokens-lib) (ctob/rename-set-group set-group-path set-group-fname))))) -(defmethod process-change :move-token-set-before - [data {:keys [from-path to-path before-path before-group?] :as changes}] +(defmethod process-change :move-token-set + [data {:keys [from-path to-path before-path before-group] :as changes}] (update data :tokens-lib #(-> % (ctob/ensure-tokens-lib) - (ctob/move-set from-path to-path before-path before-group?)))) + (ctob/move-set from-path to-path before-path before-group)))) (defmethod process-change :move-token-set-group-before [data {:keys [from-path to-path before-path before-group?]}] diff --git a/common/src/app/common/files/changes_builder.cljc b/common/src/app/common/files/changes_builder.cljc index a4ceb41eb..f955214d6 100644 --- a/common/src/app/common/files/changes_builder.cljc +++ b/common/src/app/common/files/changes_builder.cljc @@ -809,19 +809,19 @@ (update :undo-changes conj {:type :rename-token-set-group :set-group-path undo-path :set-group-fname undo-fname}) (apply-changes-local)))) -(defn move-token-set-before +(defn move-token-set [changes {:keys [from-path to-path before-path before-group? prev-before-path prev-before-group?] :as opts}] (-> changes - (update :redo-changes conj {:type :move-token-set-before + (update :redo-changes conj {:type :move-token-set :from-path from-path :to-path to-path :before-path before-path - :before-group? before-group?}) - (update :undo-changes conj {:type :move-token-set-before + :before-group before-group?}) + (update :undo-changes conj {:type :move-token-set :from-path to-path :to-path from-path :before-path prev-before-path - :before-group? prev-before-group?}) + :before-group prev-before-group?}) (apply-changes-local))) (defn move-token-set-group-before diff --git a/common/src/app/common/files/helpers.cljc b/common/src/app/common/files/helpers.cljc index 1b49099f2..3795812c3 100644 --- a/common/src/app/common/files/helpers.cljc +++ b/common/src/app/common/files/helpers.cljc @@ -283,6 +283,22 @@ :else (get-root-frame objects (:frame-id frame))))) +(defn get-parent-frame + "Similar to `get-frame, but always return the parent frame. When root + frame is provided, then itself is returned." + [objects shape-or-id] + (cond + (map? shape-or-id) + (get objects (dm/get-prop shape-or-id :frame-id)) + + (= uuid/zero shape-or-id) + (get objects uuid/zero) + + :else + (some->> shape-or-id + (get objects) + (get-frame objects)))) + (defn valid-frame-target? [objects parent-id shape-id] (let [shape (get objects shape-id)] diff --git a/common/src/app/common/files/migrations.cljc b/common/src/app/common/files/migrations.cljc index b4f908e56..734b3e429 100644 --- a/common/src/app/common/files/migrations.cljc +++ b/common/src/app/common/files/migrations.cljc @@ -29,7 +29,6 @@ [app.common.types.file :as ctf] [app.common.types.shape :as cts] [app.common.types.shape.shadow :as ctss] - [app.common.types.tokens-lib :as ctob] [app.common.uuid :as uuid] [clojure.set :as set] [cuerdas.core :as str])) @@ -97,13 +96,13 @@ (if (nil? migrations) (generate-migrations-from-version version) migrations))) - (migrate) (update :features (fnil into #{}) (deref cfeat/*new*)) ;; NOTE: in some future we can consider to apply ;; a migration to the whole database and remove ;; this code from this function that executes on ;; each file migration operation - (update :features cfeat/migrate-legacy-features))))) + (update :features cfeat/migrate-legacy-features) + (migrate))))) (defn migrated? [file] @@ -1226,32 +1225,7 @@ (update :pages-index update-vals update-container) (update :components update-vals update-container)))) -(defmethod migrate-data "Ensure hidden theme" - [data _] - (letfn [(update-tokens-lib [tokens-lib] - (let [hidden-theme (ctob/get-hidden-theme tokens-lib)] - (if (nil? hidden-theme) - (ctob/add-theme tokens-lib (ctob/make-hidden-token-theme)) - tokens-lib)))] - (if (contains? data :tokens-lib) - (update data :tokens-lib update-tokens-lib) - data))) - -(defmethod migrate-data "Add token theme id" - [data _] - (letfn [(update-tokens-lib [tokens-lib] - (let [themes (ctob/get-themes tokens-lib)] - (reduce (fn [lib theme] - (if (:id theme) - lib - (ctob/update-theme lib (:group theme) (:name theme) #(assoc % :id (str (uuid/next)))))) - tokens-lib - themes)))] - (if (contains? data :tokens-lib) - (update data :tokens-lib update-tokens-lib) - data))) - -(defmethod migrate-data "Remove tokens from groups" +(defmethod migrate-data "0001-remove-tokens-from-groups" [data _] (letfn [(update-object [object] (cond-> object @@ -1320,6 +1294,4 @@ "legacy-65" "legacy-66" "legacy-67" - "Ensure hidden theme" - "Add token theme id" - "Remove tokens from groups"])) + "0001-remove-tokens-from-groups"])) diff --git a/common/src/app/common/logic/tokens.cljc b/common/src/app/common/logic/tokens.cljc index 84f2c3b7f..50fdc7b8a 100644 --- a/common/src/app/common/logic/tokens.cljc +++ b/common/src/app/common/logic/tokens.cljc @@ -1,11 +1,21 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS INC + (ns app.common.logic.tokens (:require [app.common.files.changes-builder :as pcb] [app.common.types.tokens-lib :as ctob])) (defn generate-update-active-sets - "Copy the active sets from the currently active themes and move them to the hidden token theme and update the theme with `update-theme-fn`. - Use this for managing sets active state without having to modify a user created theme (\"no themes selected\" state in the ui)." + "Copy the active sets from the currently active themes and move them + to the hidden token theme and update the theme with + `update-theme-fn`. + + Use this for managing sets active state without having to modify a + user created theme (\"no themes selected\" state in the ui)." [changes tokens-lib update-theme-fn] (let [prev-active-token-themes (ctob/get-active-theme-paths tokens-lib) active-token-set-names (ctob/get-active-themes-set-names tokens-lib) @@ -21,7 +31,8 @@ hidden-token-theme)))) (defn generate-toggle-token-set - "Toggle a token set at `set-name` in `tokens-lib` without modifying a user theme." + "Toggle a token set at `set-name` in `tokens-lib` without modifying a + user theme." [changes tokens-lib set-name] (generate-update-active-sets changes tokens-lib #(ctob/toggle-set % set-name))) @@ -49,12 +60,20 @@ :or {collapsed-paths #{}}}] (let [tree (-> (ctob/get-set-tree tokens-lib) (ctob/walk-sets-tree-seq :skip-children-pred #(contains? collapsed-paths %))) + from (nth tree from-index) to (nth tree to-index) before (case position :top to - :bot (nth tree (inc to-index) nil) + :bot (let [v (nth tree (inc to-index) nil)] + ;; if the next index is a group, we need to set it as + ;; nil because if we set a path on different subpath, + ;; the move algorightm will simply remove the set + (if (:group? v) + nil + v)) :center nil) + prev-before (if (:group? from) (->> (drop (inc from-index) tree) (filter (fn [element] @@ -113,9 +132,9 @@ (defn generate-move-token-set "Create changes for dropping a token set or token set. Throws for impossible moves." - [changes tokens-lib drop-opts] - (if-let [drop-opts' (calculate-move-token-set-or-set-group tokens-lib drop-opts)] - (pcb/move-token-set-before changes drop-opts') + [changes tokens-lib params] + (if-let [params (calculate-move-token-set-or-set-group tokens-lib params)] + (pcb/move-token-set changes params) changes)) (defn generate-move-token-set-group diff --git a/common/src/app/common/schema.cljc b/common/src/app/common/schema.cljc index e7329e621..6d89efd89 100644 --- a/common/src/app/common/schema.cljc +++ b/common/src/app/common/schema.cljc @@ -1019,26 +1019,26 @@ (def valid-text? (validator ::text)) -(def check-safe-int! +(def check-safe-int (check-fn ::safe-int)) -(def check-set-of-strings! +(def check-set-of-strings (check-fn ::set-of-strings)) -(def check-email! +(def check-email (check-fn ::email)) -(def check-uuid! +(def check-uuid (check-fn ::uuid :hint "expected valid uuid instance")) -(def check-string! +(def check-string (check-fn :string :hint "expected string")) -(def check-coll-of-uuid! +(def check-coll-of-uuid (check-fn ::coll-of-uuid)) -(def check-set-of-uuid! +(def check-set-of-uuid (check-fn ::set-of-uuid)) -(def check-set-of-emails! +(def check-set-of-emails (check-fn [::set ::email])) diff --git a/common/src/app/common/types/shape/interactions.cljc b/common/src/app/common/types/shape/interactions.cljc index 29ef5902f..111bba5cb 100644 --- a/common/src/app/common/types/shape/interactions.cljc +++ b/common/src/app/common/types/shape/interactions.cljc @@ -7,7 +7,6 @@ (ns app.common.types.shape.interactions (:require [app.common.data :as d] - [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] [app.common.geom.point :as gpt] [app.common.geom.shapes.bounds :as gsb] @@ -180,7 +179,7 @@ (sm/register! ::interaction schema:interaction) -(def check-interaction! +(def check-interaction (sm/check-fn schema:interaction)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -203,18 +202,13 @@ (defn set-event-type [interaction event-type shape] - (dm/assert! - "Should be an interraction map" - (check-interaction! interaction)) + (assert (check-interaction interaction)) + (assert (contains? event-types event-type) + "should be a valid event type") - (dm/assert! - "Should be a valid event type" - (contains? event-types event-type)) - - (dm/assert! - "The `:after-delay` event type incompatible with not frame shapes" - (or (not= event-type :after-delay) - (cfh/frame-shape? shape))) + (assert (or (not= event-type :after-delay) + (cfh/frame-shape? shape)) + "the `:after-delay` event type incompatible with not frame shapes") (if (= (:event-type interaction) event-type) interaction @@ -230,14 +224,9 @@ (defn set-action-type [interaction action-type] - - (dm/assert! - "Should be an interraction map" - (check-interaction! interaction)) - - (dm/assert! - "Should be a valid event type" - (contains? action-types action-type)) + (assert (check-interaction interaction)) + (assert (contains? action-types action-type) + "Should be a valid event type") (let [new-interaction (if (= (:action-type interaction) action-type) @@ -284,18 +273,10 @@ (defn set-delay [interaction delay] - - (dm/assert! - "expected valid interaction map" - (check-interaction! interaction)) - - (dm/assert! - "expected valid delay" - (sm/check-safe-int! delay)) - - (dm/assert! - "expected compatible interaction event type" - (has-delay interaction)) + (assert (check-interaction interaction)) + (assert (sm/check-safe-int delay)) + (assert (has-delay interaction) + "expected compatible interaction event type") (assoc interaction :delay delay)) @@ -315,14 +296,9 @@ (defn set-destination [interaction destination] - - (dm/assert! - "expected valid interaction map" - (check-interaction! interaction)) - - (dm/assert! - "expected compatible interaction event type" - (has-destination interaction)) + (assert (check-interaction interaction)) + (assert (has-destination interaction) + "expected compatible interaction event type") (cond-> interaction :always @@ -340,17 +316,11 @@ (defn set-preserve-scroll [interaction preserve-scroll] - (dm/assert! - "expected valid interaction map" - (check-interaction! interaction)) - - (dm/assert! - "expected boolean for `preserve-scroll`" - (boolean? preserve-scroll)) - - (dm/assert! - "expected compatible interaction map with preserve-scroll" - (has-preserve-scroll interaction)) + (assert (check-interaction interaction)) + (assert (boolean? preserve-scroll) + "expected boolean for `preserve-scroll`") + (assert (has-preserve-scroll interaction) + "expected compatible interaction map with preserve-scroll") (assoc interaction :preserve-scroll preserve-scroll)) @@ -361,17 +331,11 @@ (defn set-url [interaction url] - (dm/assert! - "expected valid interaction map" - (check-interaction! interaction)) - - (dm/assert! - "expected a string for `url`" - (string? url)) - - (dm/assert! - "expected compatible interaction map with url param" - (has-url interaction)) + (assert (check-interaction interaction)) + (assert (string? url) + "expected a string for `url`") + (assert (has-url interaction) + "expected compatible interaction map with url param") (assoc interaction :url url)) @@ -382,17 +346,12 @@ (defn set-overlay-pos-type [interaction overlay-pos-type shape objects] - (dm/assert! - "expected valid interaction map" - (check-interaction! interaction)) + (assert (check-interaction interaction)) - (dm/assert! - "expected valid overlay positioning type" - (contains? overlay-positioning-types overlay-pos-type)) - - (dm/assert! - "expected compatible interaction map" - (has-overlay-opts interaction)) + (assert (contains? overlay-positioning-types overlay-pos-type) + "expected valid overlay positioning type") + (assert (has-overlay-opts interaction) + "expected compatible interaction map") (assoc interaction :overlay-pos-type overlay-pos-type @@ -403,17 +362,11 @@ (defn toggle-overlay-pos-type [interaction overlay-pos-type shape objects] - (dm/assert! - "expected valid interaction map" - (check-interaction! interaction)) - - (dm/assert! - "expected valid overlay positioning type" - (contains? overlay-positioning-types overlay-pos-type)) - - (dm/assert! - "expected compatible interaction map" - (has-overlay-opts interaction)) + (assert (check-interaction interaction)) + (assert (contains? overlay-positioning-types overlay-pos-type) + "expected valid overlay positioning type") + (assert (has-overlay-opts interaction) + "expected compatible interaction map") (let [new-pos-type (if (= (:overlay-pos-type interaction) overlay-pos-type) :manual @@ -427,17 +380,12 @@ (defn set-overlay-position [interaction overlay-position] - (dm/assert! - "expected valid interaction map" - (check-interaction! interaction)) + (assert (check-interaction interaction)) + (assert (gpt/point? overlay-position) + "expected valid overlay position") + (assert (has-overlay-opts interaction) + "expected compatible interaction map") - (dm/assert! - "expected valid overlay position" - (gpt/point? overlay-position)) - - (dm/assert! - "expected compatible interaction map" - (has-overlay-opts interaction)) (assoc interaction :overlay-pos-type :manual @@ -446,52 +394,34 @@ (defn set-close-click-outside [interaction close-click-outside] - (dm/assert! - "expected valid interaction map" - (check-interaction! interaction)) - - (dm/assert! - "expected boolean value for `close-click-outside`" - (boolean? close-click-outside)) - - (dm/assert! - "expected compatible interaction map" - (has-overlay-opts interaction)) + (assert (check-interaction interaction)) + (assert (boolean? close-click-outside) + "expected boolean value for `close-click-outside`") + (assert (has-overlay-opts interaction) + "expected compatible interaction map") (assoc interaction :close-click-outside close-click-outside)) (defn set-background-overlay [interaction background-overlay] - (dm/assert! - "expected valid interaction map" - (check-interaction! interaction)) - - (dm/assert! - "expected boolean value for `background-overlay`" - (boolean? background-overlay)) - - (dm/assert! - "expected compatible interaction map" - (has-overlay-opts interaction)) + (assert (check-interaction interaction)) + (assert (boolean? background-overlay) + "expected boolean value for `background-overlay`") + (assert (has-overlay-opts interaction) + "expected compatible interaction map") (assoc interaction :background-overlay background-overlay)) (defn set-position-relative-to [interaction position-relative-to] - (dm/assert! - "expected valid interaction map" - (check-interaction! interaction)) - - (dm/assert! - "expected valid uuid for `position-relative-to`" - (or (nil? position-relative-to) - (uuid? position-relative-to))) - - (dm/assert! - "expected compatible interaction map" - (has-overlay-opts interaction)) + (assert (check-interaction interaction)) + (assert (or (nil? position-relative-to) + (uuid? position-relative-to)) + "expected valid uuid for `position-relative-to`") + (assert (has-overlay-opts interaction) + "expected compatible interaction map") (assoc interaction :position-relative-to position-relative-to)) @@ -519,13 +449,9 @@ frame-offset] ;; if this interaction starts in a frame opened ;; on another interaction, this is the position ;; of that frame - (dm/assert! - "expected valid interaction map" - (check-interaction! interaction)) - - (dm/assert! - "expected compatible interaction map" - (has-overlay-opts interaction)) + (assert (check-interaction interaction)) + (assert (has-overlay-opts interaction) + "expected compatible interaction map") (let [;; When the interactive item is inside a nested frame we need to add to the offset the position ;; of the parent-frame otherwise the position won't match @@ -617,22 +543,15 @@ (defn set-animation-type [interaction animation-type] - (dm/assert! - "expected valid interaction map" - (check-interaction! interaction)) - (dm/assert! - "expected valid value for `animation-type`" - (or (nil? animation-type) - (contains? animation-types animation-type))) - - (dm/assert! - "expected interaction map compatible with animation" - (has-animation? interaction)) - - (dm/assert! - "expected allowed animation type" - (allowed-animation? (:action-type interaction) animation-type)) + (assert (check-interaction interaction)) + (assert (or (nil? animation-type) + (contains? animation-types animation-type)) + "expected valid value for `animation-type`") + (assert (has-animation? interaction) + "expected interaction map compatible with animation") + (assert (allowed-animation? (:action-type interaction) animation-type) + "expected allowed animation type") (if (= (-> interaction :animation :animation-type) animation-type) interaction @@ -668,17 +587,10 @@ (defn set-duration [interaction duration] - (dm/assert! - "expected valid interaction map" - (check-interaction! interaction)) - - (dm/assert! - "expected valid duration" - (sm/check-safe-int! duration)) - - (dm/assert! - "expected compatible interaction map" - (has-duration? interaction)) + (assert (check-interaction interaction)) + (assert (sm/check-safe-int duration)) + (assert (has-duration? interaction) + "expected compatible interaction map") (update interaction :animation assoc :duration duration)) @@ -689,17 +601,11 @@ (defn set-easing [interaction easing] - (dm/assert! - "expected valid interaction map" - (check-interaction! interaction)) - - (dm/assert! - "expected valid easing" - (contains? easing-types easing)) - - (dm/assert! - "expected compatible interaction map" - (has-easing? interaction)) + (assert (check-interaction interaction)) + (assert (contains? easing-types easing) + "expected valid easing") + (assert (has-easing? interaction) + "expected compatible interaction map") (update interaction :animation assoc :easing easing)) @@ -712,17 +618,11 @@ (defn set-way [interaction way] - (dm/assert! - "expected valid interaction map" - (check-interaction! interaction)) - - (dm/assert! - "expected valid way" - (contains? way-types way)) - - (dm/assert! - "expected compatible interaction map" - (has-way? interaction)) + (assert (check-interaction interaction)) + (assert (contains? way-types way) + "expected valid way") + (assert (has-way? interaction) + "expected compatible interaction map") (update interaction :animation assoc :way way)) @@ -733,26 +633,20 @@ (defn set-direction [interaction direction] - (dm/assert! - "expected valid interaction map" - (check-interaction! interaction)) + (assert (check-interaction interaction)) + (assert (contains? direction-types direction) + "expected valid direction") - (dm/assert! - "expected valid direction" - (contains? direction-types direction)) - - (dm/assert! - "expected compatible interaction map" - (has-direction? interaction)) + (assert (has-direction? interaction) + "expected compatible interaction map") (update interaction :animation assoc :direction direction)) (defn invert-direction [animation] - (dm/assert! - "expected valid animation map" - (or (nil? animation) - (check-animation! animation))) + (assert (or (nil? animation) + (check-animation! animation)) + "expected valid animation map") (case (:direction animation) :right @@ -768,24 +662,18 @@ (defn has-offset-effect? [interaction] - ; Offset-effect is ignored in slide animations of overlay actions + ;; Offset-effect is ignored in slide animations of overlay actions (and (= (:action-type interaction) :navigate) (= (-> interaction :animation :animation-type) :slide))) (defn set-offset-effect [interaction offset-effect] - (dm/assert! - "expected valid interaction map" - (check-interaction! interaction)) - - (dm/assert! - "expected valid boolean for `offset-effect`" - (boolean? offset-effect)) - - (dm/assert! - "expected compatible interaction map" - (has-offset-effect? interaction)) + (assert (check-interaction interaction)) + (assert (boolean? offset-effect) + "expected valid boolean for `offset-effect`") + (assert (has-offset-effect? interaction) + "expected compatible interaction map") (update interaction :animation assoc :offset-effect offset-effect)) diff --git a/common/src/app/common/types/tokens_lib.cljc b/common/src/app/common/types/tokens_lib.cljc index 08485d5ad..e85cea19b 100644 --- a/common/src/app/common/types/tokens_lib.cljc +++ b/common/src/app/common/types/tokens_lib.cljc @@ -588,7 +588,7 @@ (update :group d/nilv top-level-theme-group-name) (update :description d/nilv "") (update :is-source d/nilv false) - (update :id d/nilv (str (uuid/next))) + (update :id #(or % (str (uuid/next)))) (update :modified-at #(or % (dt/now))) (update :sets set) (check-token-theme-attrs) @@ -612,7 +612,6 @@ (get-theme-tree [_] "get a nested tree of all themes in the library") (get-themes [_] "get an ordered sequence of all themes in the library") (get-theme [_ group name] "get one theme looking for name") - (get-hidden-theme [_] "get the theme hidden from the user, used for managing active sets without a user created theme.") (get-theme-groups [_] "get a sequence of group names by order") (get-active-theme-paths [_] "get the active theme paths") (get-active-themes [_] "get an ordered sequence of active themes in the library") @@ -946,14 +945,21 @@ Will return a value that matches this schema: (let [prefixed-from-path (set-full-path->set-prefixed-full-path from-path) prev-set (get-in sets prefixed-from-path)] (if (instance? TokenSet prev-set) - (let [prefixed-to-path (set-full-path->set-prefixed-full-path to-path) - prefixed-before-path (when before-path - (if before-group? - (mapv add-set-path-group-prefix before-path) - (set-full-path->set-prefixed-full-path before-path))) + (let [prefixed-to-path + (set-full-path->set-prefixed-full-path to-path) + + prefixed-before-path + (when before-path + (if before-group? + (mapv add-set-path-group-prefix before-path) + (set-full-path->set-prefixed-full-path before-path))) + + set + (assoc prev-set :name (join-set-path to-path)) + + reorder? + (= prefixed-from-path prefixed-to-path) - set (assoc prev-set :name (join-set-path to-path)) - reorder? (= prefixed-from-path prefixed-to-path) sets' (if reorder? (d/oreorder-before sets @@ -965,6 +971,7 @@ Will return a value that matches this schema: (d/oassoc-in-before sets prefixed-before-path prefixed-to-path set) (d/oassoc-in sets prefixed-to-path set)) (d/dissoc-in prefixed-from-path)))] + (TokensLib. sets' (if reorder? themes @@ -1130,9 +1137,6 @@ Will return a value that matches this schema: (get-theme [_ group name] (dm/get-in themes [group name])) - (get-hidden-theme [this] - (get-theme this hidden-token-theme-group hidden-token-theme-name)) - (set-active-themes [_ active-themes] (TokensLib. sets themes @@ -1368,6 +1372,10 @@ Will return a value that matches this schema: (valid-token-themes? themes) (valid-active-token-themes? active-themes)))) +(defn get-hidden-theme + [tokens-lib] + (get-theme tokens-lib hidden-token-theme-group hidden-token-theme-name)) + (defn valid-tokens-lib? [o] (and (instance? TokensLib o) @@ -1382,27 +1390,32 @@ Will return a value that matches this schema: (def ^:private check-active-themes (sm/check-fn schema:active-themes :hint "expected valid active themes")) +(defn- ensure-hidden-theme + "A helper that is responsible to ensure that the hidden theme always + exists on the themes data structure" + [themes] + (update themes hidden-token-theme-group + (fn [data] + (if (contains? data hidden-token-theme-name) + data + (d/oassoc data hidden-token-theme-name (make-hidden-token-theme)))))) + +;; NOTE: is possible that ordered map is not the most apropriate +;; data structure and maybe we need a specific that allows us an +;; easy way to reorder it, or just store inside Tokens data +;; structure the data and the order separately as we already do +;; with pages and pages-index. (defn make-tokens-lib "Create an empty or prepopulated tokens library." - ([] - ;; NOTE: is possible that ordered map is not the most apropriate - ;; data structure and maybe we need a specific that allows us an - ;; easy way to reorder it, or just store inside Tokens data - ;; structure the data and the order separately as we already do - ;; with pages and pages-index. - (make-tokens-lib :sets (d/ordered-map) - :themes (d/ordered-map) - :active-themes #{hidden-token-theme-path})) - - ([& {:keys [sets themes active-themes]}] - (let [active-themes (d/nilv active-themes #{hidden-token-theme-path}) - themes (if (empty? themes) - (update themes hidden-token-theme-group d/oassoc hidden-token-theme-name (make-hidden-token-theme)) - themes)] - (TokensLib. - (check-token-sets sets) - (check-token-themes themes) - (check-active-themes active-themes))))) + [& {:keys [sets themes active-themes]}] + (let [sets (or sets (d/ordered-map)) + themes (-> (or themes (d/ordered-map)) + (ensure-hidden-theme)) + active-themes (or active-themes #{hidden-token-theme-path})] + (TokensLib. + (check-token-sets sets) + (check-token-themes themes) + (check-active-themes active-themes)))) (defn ensure-tokens-lib [tokens-lib] @@ -1445,6 +1458,71 @@ Will return a value that matches this schema: :wfn #(into {} %) :rfn #(map->Token %)}) +#?(:clj + (defn- read-tokens-lib-v1-0 + "Reads the first version of tokens lib, now completly obsolete" + [r] + (let [;; Migrate sets tree without prefix to new format + prev-sets (->> (fres/read-object! r) + (tree-seq d/ordered-map? vals) + (filter (partial instance? TokenSet))) + + sets (-> (reduce add-set (make-tokens-lib) prev-sets) + (deref) + (:sets)) + + _set-groups (fres/read-object! r) + themes (fres/read-object! r) + active-themes (fres/read-object! r)] + (->TokensLib sets themes active-themes)))) + +#?(:clj + (defn- read-tokens-lib-v1-1 + "Reads the tokens lib data structure and ensures that hidden + theme exists and adds missing ID on themes" + [r] + (let [sets (fres/read-object! r) + themes (fres/read-object! r) + active-themes (fres/read-object! r) + + ;; Ensure we have at least a hidden theme + themes + (ensure-hidden-theme themes) + + ;; Ensure we add an :id field for each existing theme + themes + (reduce (fn [result group-id] + (update result group-id + (fn [themes] + (reduce (fn [themes theme-id] + (update themes theme-id + (fn [theme] + (if (get theme :id) + theme + (assoc theme :id (str (uuid/next))))))) + themes + (keys themes))))) + themes + (keys themes))] + + (->TokensLib sets themes active-themes)))) + +#?(:clj + (defn- write-tokens-lib + [n w ^TokensLib o] + (fres/write-tag! w n 3) + (fres/write-object! w (.-sets o)) + (fres/write-object! w (.-themes o)) + (fres/write-object! w (.-active-themes o)))) + +#?(:clj + (defn- read-tokens-lib + [r] + (let [sets (fres/read-object! r) + themes (fres/read-object! r) + active-themes (fres/read-object! r)] + (->TokensLib sets themes active-themes)))) + #?(:clj (fres/add-handlers! {:name "penpot/token/v1" @@ -1474,32 +1552,15 @@ Will return a value that matches this schema: (let [obj (fres/read-object! r)] (map->TokenTheme obj)))} + ;; LEGACY TOKENS LIB READERS (with migrations) {:name "penpot/tokens-lib/v1" - :rfn (fn [r] - (let [;; Migrate sets tree without prefix to new format - prev-sets (->> (fres/read-object! r) - (tree-seq d/ordered-map? vals) - (filter (partial instance? TokenSet))) - - ;; FIXME: wtf we usind deref here? - sets (-> (reduce add-set (make-tokens-lib) prev-sets) - (deref) - (:sets)) - - _set-groups (fres/read-object! r) - themes (fres/read-object! r) - active-themes (fres/read-object! r)] - (->TokensLib sets themes active-themes)))} + :rfn read-tokens-lib-v1-0} {:name "penpot/tokens-lib/v1.1" + :rfn read-tokens-lib-v1-1} + + ;; CURRENT TOKENS LIB READER & WRITTER + {:name "penpot/tokens-lib/v1.2" :class TokensLib - :wfn (fn [n w o] - (fres/write-tag! w n 3) - (fres/write-object! w (.-sets o)) - (fres/write-object! w (.-themes o)) - (fres/write-object! w (.-active-themes o))) - :rfn (fn [r] - (let [sets (fres/read-object! r) - themes (fres/read-object! r) - active-themes (fres/read-object! r)] - (->TokensLib sets themes active-themes)))})) + :wfn write-tokens-lib + :rfn read-tokens-lib})) diff --git a/common/test/common_tests/types/tokens_lib_test.cljc b/common/test/common_tests/types/tokens_lib_test.cljc index ba9cb5f12..6779ac08e 100644 --- a/common/test/common_tests/types/tokens_lib_test.cljc +++ b/common/test/common_tests/types/tokens_lib_test.cljc @@ -84,52 +84,65 @@ (t/is (thrown-with-msg? #?(:cljs js/Error :clj Exception) #"expected valid params for token-set" (ctob/make-token-set params))))) -(t/deftest move-token-set - (t/testing "flat" - (let [tokens-lib (-> (ctob/make-tokens-lib) - (ctob/add-set (ctob/make-token-set :name "A")) - (ctob/add-set (ctob/make-token-set :name "B")) - (ctob/add-set (ctob/make-token-set :name "Move"))) - move (fn [from-path to-path before-path before-group?] - (->> (ctob/move-set tokens-lib from-path to-path before-path before-group?) - (ctob/get-ordered-set-names) - (into [])))] - (t/testing "move to top" - (t/is (= ["Move" "A" "B"] (move ["Move"] ["Move"] ["A"] false)))) +(t/deftest move-token-set-flat + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "A")) + (ctob/add-set (ctob/make-token-set :name "B")) + (ctob/add-set (ctob/make-token-set :name "Move"))) + move (fn [from-path to-path before-path before-group?] + (->> (ctob/move-set tokens-lib from-path to-path before-path before-group?) + (ctob/get-ordered-set-names) + (into [])))] + (t/testing "move to top" + (t/is (= ["Move" "A" "B"] (move ["Move"] ["Move"] ["A"] false)))) - (t/testing "move in-between" - (t/is (= ["A" "Move" "B"] (move ["Move"] ["Move"] ["B"] false)))) + (t/testing "move in-between" + (t/is (= ["A" "Move" "B"] (move ["Move"] ["Move"] ["B"] false)))) - (t/testing "move to bottom" - (t/is (= ["A" "B" "Move"] (move ["Move"] ["Move"] nil false)))))) + (t/testing "move to bottom" + (t/is (= ["A" "B" "Move"] (move ["Move"] ["Move"] nil false)))))) - (t/testing "nested" - (let [tokens-lib (-> (ctob/make-tokens-lib) - (ctob/add-set (ctob/make-token-set :name "Foo/Baz")) - (ctob/add-set (ctob/make-token-set :name "Foo/Bar")) - (ctob/add-set (ctob/make-token-set :name "Foo"))) - move (fn [from-path to-path before-path before-group?] - (->> (ctob/move-set tokens-lib from-path to-path before-path before-group?) - (ctob/get-ordered-set-names) - (into [])))] - (t/testing "move outside of group" - (t/is (= ["Foo/Baz" "Bar" "Foo"] (move ["Foo" "Bar"] ["Bar"] ["Foo"] false))) - (t/is (= ["Bar" "Foo/Baz" "Foo"] (move ["Foo" "Bar"] ["Bar"] ["Foo" "Baz"] true))) - (t/is (= ["Foo/Baz" "Foo" "Bar"] (move ["Foo" "Bar"] ["Bar"] nil false)))) +(t/deftest move-token-set-nested + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "Foo/Baz")) + (ctob/add-set (ctob/make-token-set :name "Foo/Bar")) + (ctob/add-set (ctob/make-token-set :name "Foo"))) + move (fn [from-path to-path before-path before-group?] + (->> (ctob/move-set tokens-lib from-path to-path before-path before-group?) + (ctob/get-ordered-set-names) + (into [])))] + (t/testing "move outside of group" + (t/is (= ["Foo/Baz" "Bar" "Foo"] (move ["Foo" "Bar"] ["Bar"] ["Foo"] false))) + (t/is (= ["Bar" "Foo/Baz" "Foo"] (move ["Foo" "Bar"] ["Bar"] ["Foo" "Baz"] true))) + (t/is (= ["Foo/Baz" "Foo" "Bar"] (move ["Foo" "Bar"] ["Bar"] nil false)))) - (t/testing "move inside of group" - (t/is (= ["Foo/Foo" "Foo/Baz" "Foo/Bar"] (move ["Foo"] ["Foo" "Foo"] ["Foo" "Baz"] false))) - (t/is (= ["Foo/Baz" "Foo/Bar" "Foo/Foo"] (move ["Foo"] ["Foo" "Foo"] nil false)))))) + (t/testing "move inside of group" + (t/is (= ["Foo/Foo" "Foo/Baz" "Foo/Bar"] (move ["Foo"] ["Foo" "Foo"] ["Foo" "Baz"] false))) + (t/is (= ["Foo/Baz" "Foo/Bar" "Foo/Foo"] (move ["Foo"] ["Foo" "Foo"] nil false)))))) - ;; FIXME - (t/testing "updates theme set names" - (let [tokens-lib (-> (ctob/make-tokens-lib) - (ctob/add-set (ctob/make-token-set :name "Foo/Bar/Baz")) - (ctob/add-set (ctob/make-token-set :name "Other")) - (ctob/add-theme (ctob/make-token-theme :name "Theme" - :sets #{"Foo/Bar/Baz"})) - (ctob/move-set ["Foo" "Bar" "Baz"] ["Other/Baz"] nil nil))] - (t/is (= #{"Other/Baz"} (:sets (ctob/get-theme tokens-lib "" "Theme"))))))) + +(t/deftest move-token-set-nested-2 + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "a/b")) + (ctob/add-set (ctob/make-token-set :name "a/a")) + (ctob/add-set (ctob/make-token-set :name "b/a")) + (ctob/add-set (ctob/make-token-set :name "b/b"))) + move (fn [from-path to-path before-path before-group?] + (->> (ctob/move-set tokens-lib from-path to-path before-path before-group?) + (ctob/get-ordered-set-names) + (vec)))] + (t/testing "move within group" + (t/is (= ["a/b" "a/a" "b/a" "b/b"] (vec (ctob/get-ordered-set-names tokens-lib)))) + (t/is (= ["a/a" "a/b" "b/a" "b/b"] (move ["a" "b"] ["a" "b"] nil true)))))) + +(t/deftest move-token-set-nested-3 + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "Foo/Bar/Baz")) + (ctob/add-set (ctob/make-token-set :name "Other")) + (ctob/add-theme (ctob/make-token-theme :name "Theme" + :sets #{"Foo/Bar/Baz"})) + (ctob/move-set ["Foo" "Bar" "Baz"] ["Other/Baz"] nil nil))] + (t/is (= #{"Other/Baz"} (:sets (ctob/get-theme tokens-lib "" "Theme")))))) (t/deftest move-token-set-group (t/testing "reordering" @@ -213,7 +226,7 @@ (t/is (= (ctob/set-count tokens-lib) 0)))) (t/deftest make-invalid-tokens-lib - (let [params {:sets nil :themes nil}] + (let [params {:sets {} :themes {}}] (t/is (thrown-with-msg? #?(:cljs js/Error :clj Exception) #"expected valid token sets" (ctob/make-tokens-lib params))))) diff --git a/docs/technical-guide/getting-started/docker.md b/docs/technical-guide/getting-started/docker.md index 400714498..118e85723 100644 --- a/docs/technical-guide/getting-started/docker.md +++ b/docs/technical-guide/getting-started/docker.md @@ -2,6 +2,14 @@ title: 1.3 Install with Docker --- +
+Installing and maintaining a self-hosted Penpot instance requires some technical knowledge: +Docker and Docker Compose, basic DNS management, and proxy configuration. +If you're not comfortable with this stack, we encourage you to try +more straight-forward installations with Elestio +or use the SAAS at https://design.penpot.app. +
+ # Install with Docker This section details everything you need to know to get Penpot up and running in @@ -10,42 +18,10 @@ production environments using Docker. For this, we provide a series of *Dockerfi ## Install Docker --Skip this section if you already have docker installed, up and running. -
- -Currently, Docker comes into two different flavours: - -### Docker Desktop - -This is the only option to have Docker in a Windows or MacOS. Recently it's also available -for Linux, in the most popular distributions (Debian, Ubuntu and Fedora). - -You can install it following the official guide. - -Docker Desktop has a graphical control panel (GUI) to manage the service and view the -containers, images and volumes. But you need the command line (Terminal in Linux and Mac, or -PowerShell in Windows) to build and run the containers, and execute other operations. - -It already includes **docker compose** utility, needed by Penpot. - -### Docker Engine - -This is the classic and default Docker setup for Linux machines, and the only option for a -Linux VPS without graphical interface. - -You can install it following the official guide. - -And you also need the [docker -compose](https://docs.docker.com/compose/cli-command/#installing-compose-v2) (V2) -plugin. You can use the old **docker-compose** tool, but all the documentation supposes -you are using the V2. - -You can easily check which version of **docker compose** you have. If you can execute -docker compose
command, then you have V2. If you need to write docker-compose
(with a
--
) for it to work, you have the old version.
+To host a Penpot instance with Docker, it's necessary to have
+docker
and docker compose
+installed. Check the comprehensive official documentation
+to install and maintain docker.
## Start Penpot
diff --git a/frontend/src/app/main/data/comments.cljs b/frontend/src/app/main/data/comments.cljs
index b509f49ce..0d7677f82 100644
--- a/frontend/src/app/main/data/comments.cljs
+++ b/frontend/src/app/main/data/comments.cljs
@@ -648,9 +648,7 @@
(defn detach-comment-thread
"Detach comment threads that are inside a frame when that frame is deleted"
[ids]
- (dm/assert!
- "expected a valid coll of uuid's"
- (sm/check-coll-of-uuid! ids))
+ (assert (sm/check-coll-of-uuid ids))
(ptk/reify ::detach-comment-thread
ptk/WatchEvent
diff --git a/frontend/src/app/main/data/dashboard.cljs b/frontend/src/app/main/data/dashboard.cljs
index f74c834e3..57a886340 100644
--- a/frontend/src/app/main/data/dashboard.cljs
+++ b/frontend/src/app/main/data/dashboard.cljs
@@ -536,11 +536,8 @@
(defn move-files
[{:keys [ids project-id] :as params}]
- (dm/assert! (uuid? project-id))
-
- (dm/assert!
- "expected a valid set of uuids"
- (sm/check-set-of-uuid! ids))
+ (assert (uuid? project-id))
+ (assert (sm/check-set-of-uuid ids))
(ptk/reify ::move-files
ev/Event
diff --git a/frontend/src/app/main/data/team.cljs b/frontend/src/app/main/data/team.cljs
index 383183a6c..2ee1e5828 100644
--- a/frontend/src/app/main/data/team.cljs
+++ b/frontend/src/app/main/data/team.cljs
@@ -350,12 +350,10 @@
(defn create-invitations
[{:keys [emails role team-id resend?] :as params}]
- (dm/assert! (keyword? role))
- (dm/assert! (uuid? team-id))
- (dm/assert!
- "expected a valid set of emails"
- (sm/check-set-of-emails! emails))
+ (assert (keyword? role))
+ (assert (uuid? team-id))
+ (assert (sm/check-set-of-emails emails))
(ptk/reify ::create-invitations
ev/Event
@@ -376,11 +374,8 @@
(defn copy-invitation-link
[{:keys [email team-id] :as params}]
- (dm/assert!
- "expected a valid email"
- (sm/check-email! email))
-
- (dm/assert! (uuid? team-id))
+ (assert (sm/check-email email))
+ (assert (uuid? team-id))
(ptk/reify ::copy-invitation-link
IDeref
@@ -406,12 +401,9 @@
(defn update-invitation-role
[{:keys [email team-id role] :as params}]
- (dm/assert!
- "expected a valid email"
- (sm/check-email! email))
-
- (dm/assert! (uuid? team-id))
- (dm/assert! (contains? ctt/valid-roles role))
+ (assert (sm/check-email email))
+ (assert (uuid? team-id))
+ (assert (contains? ctt/valid-roles role))
(ptk/reify ::update-invitation-role
IDeref
@@ -428,8 +420,9 @@
(defn delete-invitation
[{:keys [email team-id] :as params}]
- (dm/assert! (sm/check-email! email))
- (dm/assert! (uuid? team-id))
+ (assert (sm/check-email email))
+ (assert (uuid? team-id))
+
(ptk/reify ::delete-invitation
ptk/WatchEvent
(watch [_ _ _]
diff --git a/frontend/src/app/main/data/tokens.cljs b/frontend/src/app/main/data/tokens.cljs
index 6f5ea56d6..415c06bbb 100644
--- a/frontend/src/app/main/data/tokens.cljs
+++ b/frontend/src/app/main/data/tokens.cljs
@@ -252,6 +252,8 @@
:level :error
:timeout 9000})))))))
+;; FIXME: add schema for params
+
(defn drop-token-set-group [drop-opts]
(ptk/reify ::drop-token-set-group
ptk/WatchEvent
@@ -265,17 +267,21 @@
(rx/of
(drop-error (ex-data e))))))))
-(defn drop-token-set [drop-opts]
+;; FIXME: add schema for params
+
+(defn drop-token-set
+ [params]
(ptk/reify ::drop-token-set
ptk/WatchEvent
(watch [it state _]
(try
- (when-let [changes (clt/generate-move-token-set (pcb/empty-changes it) (get-tokens-lib state) drop-opts)]
+ (let [tokens-lib (get-tokens-lib state)
+ changes (-> (pcb/empty-changes it)
+ (clt/generate-move-token-set tokens-lib params))]
(rx/of (dch/commit-changes changes)
(wtu/update-workspace-tokens)))
- (catch :default e
- (rx/of
- (drop-error (ex-data e))))))))
+ (catch :default cause
+ (rx/of (drop-error (ex-data cause))))))))
(defn- create-token-with-set
"A special case when a first token is created and no set exists"
diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs
index b676dc8d9..1f353c4ac 100644
--- a/frontend/src/app/main/data/workspace.cljs
+++ b/frontend/src/app/main/data/workspace.cljs
@@ -406,6 +406,7 @@
:workspace-media-objects
:workspace-persistence
:workspace-presence
+ :workspace-tokens
:workspace-undo)
(update :workspace-global dissoc :read-only?)
(assoc-in [:workspace-global :options-mode] :design)))
diff --git a/frontend/src/app/main/data/workspace/comments.cljs b/frontend/src/app/main/data/workspace/comments.cljs
index 97bc7747e..5920f4615 100644
--- a/frontend/src/app/main/data/workspace/comments.cljs
+++ b/frontend/src/app/main/data/workspace/comments.cljs
@@ -134,9 +134,7 @@
;; Move comment threads that are inside a frame when that frame is moved"
(defmethod ptk/resolve ::move-frame-comment-threads
[_ ids]
- (dm/assert!
- "expected a valid coll of uuid's"
- (sm/check-coll-of-uuid! ids))
+ (assert (sm/check-coll-of-uuid ids))
(ptk/reify ::move-frame-comment-threads
ptk/WatchEvent
diff --git a/frontend/src/app/main/data/workspace/groups.cljs b/frontend/src/app/main/data/workspace/groups.cljs
index 2e1c1c0ff..bb0dfe1a8 100644
--- a/frontend/src/app/main/data/workspace/groups.cljs
+++ b/frontend/src/app/main/data/workspace/groups.cljs
@@ -120,6 +120,14 @@
(pcb/with-page-id page-id)
(pcb/with-objects objects)
(pcb/add-object group {:index group-idx})
+
+ ;; Create a group needs to reset the constraints to scale/scale
+ (pcb/update-shapes
+ (map :id shapes)
+ (fn [shape]
+ (-> shape
+ (d/assoc-when :constraints-h :scale)
+ (d/assoc-when :constraints-v :scale))))
(pcb/update-shapes (map :id shapes) ctl/remove-layout-item-data)
(pcb/change-parent (:id group) (reverse shapes))
(pcb/update-shapes (map :id shapes-to-detach) ctk/detach-shape)
diff --git a/frontend/src/app/main/data/workspace/modifiers.cljs b/frontend/src/app/main/data/workspace/modifiers.cljs
index de9d58800..ace4d0fc4 100644
--- a/frontend/src/app/main/data/workspace/modifiers.cljs
+++ b/frontend/src/app/main/data/workspace/modifiers.cljs
@@ -533,14 +533,98 @@
(assoc state :workspace-modifiers modif-tree)))))
+(def ^:private xf:without-uuid-zero
+ (remove #(= % uuid/zero)))
+
+(def ^:private transform-attrs
+ #{:selrect
+ :points
+ :x
+ :y
+ :r1
+ :r2
+ :r3
+ :r4
+ :shadow
+ :blur
+ :strokes
+ :width
+ :height
+ :content
+ :transform
+ :transform-inverse
+ :rotation
+ :flip-x
+ :flip-y
+ :grow-type
+ :position-data
+ :layout-gap
+ :layout-padding
+ :layout-item-h-sizing
+ :layout-item-max-h
+ :layout-item-max-w
+ :layout-item-min-h
+ :layout-item-min-w
+ :layout-item-v-sizing
+ :layout-padding-type
+ :layout-item-margin
+ :layout-item-margin-type
+ :layout-grid-cells
+ :layout-grid-columns
+ :layout-grid-rows})
+
+(defn apply-modifiers*
+ "A lower-level version of apply-modifiers, that expects receive ready
+ to use objects, object-modifiers and text-modifiers."
+ [objects object-modifiers text-modifiers options]
+ (ptk/reify ::apply-modifiers*
+ ptk/WatchEvent
+ (watch [_ _ _]
+ (let [ids
+ (into [] xf:without-uuid-zero (keys object-modifiers))
+
+ ids-with-children
+ (into ids
+ (mapcat (partial cfh/get-children-ids objects))
+ ids)
+
+ ignore-tree
+ (calculate-ignore-tree object-modifiers objects)
+
+ options
+ (-> options
+ (assoc :reg-objects? true)
+ (assoc :ignore-tree ignore-tree)
+ ;; Attributes that can change in the transform. This
+ ;; way we don't have to check all the attributes
+ (assoc :attrs transform-attrs))
+
+ update-shape
+ (fn [shape]
+ (let [shape-id (dm/get-prop shape :id)
+ modifiers (dm/get-in object-modifiers [shape-id :modifiers])
+ text-shape? (cfh/text-shape? shape)
+ pos-data (when ^boolean text-shape?
+ (dm/get-in text-modifiers [shape-id :position-data]))]
+ (-> shape
+ (gsh/transform-shape modifiers)
+ (cond-> (d/not-empty? pos-data)
+ (assoc-position-data pos-data shape))
+ (cond-> text-shape?
+ (update-grow-type shape)))))]
+
+ (rx/of (ptk/event ::dwg/move-frame-guides {:ids ids-with-children :modifiers object-modifiers})
+ (ptk/event ::dwcm/move-frame-comment-threads ids-with-children)
+ (dwsh/update-shapes ids update-shape options))))))
+
(defn apply-modifiers
([]
(apply-modifiers nil))
-
- ([{:keys [modifiers undo-transation? stack-undo? ignore-constraints
- ignore-snap-pixel ignore-touched undo-group page-id]
- :or {undo-transation? true stack-undo? false ignore-constraints false
- ignore-snap-pixel false ignore-touched false}}]
+ ([{:keys [modifiers undo-transation? ignore-constraints
+ ignore-snap-pixel page-id]
+ :or {undo-transation? true ignore-constraints false
+ ignore-snap-pixel false}
+ :as options}]
(ptk/reify ::apply-modifiers
ptk/WatchEvent
(watch [_ state _]
@@ -553,88 +637,17 @@
(calculate-modifiers state ignore-constraints ignore-snap-pixel modifiers page-id)
(get state :workspace-modifiers))
- ids
- (into []
- (remove #(= % uuid/zero))
- (keys object-modifiers))
-
- ids-with-children
- (into ids
- (mapcat (partial cfh/get-children-ids objects))
- ids)
-
- ignore-tree
- (calculate-ignore-tree object-modifiers objects)
-
- undo-id (js/Symbol)]
+ undo-id
+ (js/Symbol)]
(rx/concat
(if undo-transation?
(rx/of (dwu/start-undo-transaction undo-id))
(rx/empty))
- (rx/of (ptk/event ::dwg/move-frame-guides {:ids ids-with-children :modifiers object-modifiers})
- (ptk/event ::dwcm/move-frame-comment-threads ids-with-children)
- (dwsh/update-shapes
- ids
- (fn [shape]
- (let [modif (get-in object-modifiers [(:id shape) :modifiers])
- text-shape? (cfh/text-shape? shape)
- position-data (when text-shape?
- (dm/get-in text-modifiers [(:id shape) :position-data]))]
- (-> shape
- (gsh/transform-shape modif)
- (cond-> (d/not-empty? position-data)
- (assoc-position-data position-data shape))
- (cond-> text-shape?
- (update-grow-type shape)))))
- {:reg-objects? true
- :stack-undo? stack-undo?
- :ignore-tree ignore-tree
- :ignore-touched ignore-touched
- :undo-group undo-group
- :page-id page-id
- ;; Attributes that can change in the transform. This way we don't have to check
- ;; all the attributes
- :attrs [:selrect
- :points
- :x
- :y
- :r1
- :r2
- :r3
- :r4
- :shadow
- :blur
- :strokes
- :width
- :height
- :content
- :transform
- :transform-inverse
- :rotation
- :flip-x
- :flip-y
- :grow-type
- :position-data
- :layout-gap
- :layout-padding
- :layout-item-h-sizing
- :layout-item-margin
- :layout-item-max-h
- :layout-item-max-w
- :layout-item-min-h
- :layout-item-min-w
- :layout-item-v-sizing
- :layout-padding-type
- :layout-gap
- :layout-item-margin
- :layout-item-margin-type
- :layout-grid-cells
- :layout-grid-columns
- :layout-grid-rows]})
- ;; We've applied the text-modifier so we can dissoc the temporary data
+ (rx/of (apply-modifiers* objects object-modifiers text-modifiers options)
(fn [state]
- (update state :workspace-text-modifier #(apply dissoc % ids))))
+ (let [ids (into [] xf:without-uuid-zero (keys object-modifiers))]
+ (update state :workspace-text-modifier #(apply dissoc % ids)))))
(if (nil? modifiers)
(rx/of (clear-local-transform))
(rx/empty))
diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs
index cceea35af..b65989e26 100644
--- a/frontend/src/app/main/data/workspace/shapes.cljs
+++ b/frontend/src/app/main/data/workspace/shapes.cljs
@@ -51,11 +51,8 @@
([ids update-fn {:keys [reg-objects? save-undo? stack-undo? attrs ignore-tree page-id ignore-touched undo-group with-objects? changed-sub-attr]
:or {reg-objects? false save-undo? true stack-undo? false ignore-touched false with-objects? false}}]
- (dm/assert!
- "expected a valid coll of uuid's"
- (sm/check-coll-of-uuid! ids))
-
- (dm/assert! (fn? update-fn))
+ (assert (sm/check-coll-of-uuid ids))
+ (assert (fn? update-fn))
(ptk/reify ::update-shapes
ptk/WatchEvent
@@ -162,9 +159,7 @@
([ids] (delete-shapes nil ids {}))
([page-id ids] (delete-shapes page-id ids {}))
([page-id ids options]
- (dm/assert!
- "expected a valid set of uuid's"
- (sm/check-set-of-uuid! ids))
+ (assert (sm/check-set-of-uuid ids))
(ptk/reify ::delete-shapes
ptk/WatchEvent
diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs
index 0c5effb80..ccd166395 100644
--- a/frontend/src/app/main/data/workspace/transforms.cljs
+++ b/frontend/src/app/main/data/workspace/transforms.cljs
@@ -340,35 +340,35 @@
(rx/filter (ptk/type? ::trigger-bounding-box-cloaking) stream)))))))
(defn update-dimensions
- "Change size of shapes, from the sideber options form.
- Will ignore pixel snap used in the options side panel"
+ "Change size of shapes, from the sidebar options form
+ (will ignore pixel snap)"
([ids attr value] (update-dimensions ids attr value nil))
([ids attr value options]
- (dm/assert! (number? value))
- (dm/assert!
- "expected valid coll of uuids"
- (every? uuid? ids))
- (dm/assert!
- "expected valid attr"
- (contains? #{:width :height} attr))
- (ptk/reify ::update-dimensions
- ptk/UpdateEvent
- (update [_ state]
- (let [page-id (or (get options :page-id)
- (get state :current-page-id))
+ (assert (number? value))
+ (assert (every? uuid? ids)
+ "expected valid coll of uuids")
+ (assert (contains? #{:width :height} attr)
+ "expected valid attr")
+
+ (ptk/reify ::update-dimensions
+ ptk/WatchEvent
+ (watch [_ state _]
+ (let [page-id
+ (or (get options :page-id)
+ (get state :current-page-id))
+
+ objects
+ (dsh/lookup-page-objects state page-id)
- objects (dsh/lookup-page-objects state page-id)
get-modifier
- (fn [shape] (ctm/change-dimensions-modifiers shape attr value))
+ (fn [shape]
+ (ctm/change-dimensions-modifiers shape attr value))
+
modif-tree
(-> (dwm/build-modif-tree ids objects get-modifier)
(gm/set-objects-modifiers objects))]
- (assoc state :workspace-modifiers modif-tree)))
-
- ptk/WatchEvent
- (watch [_ _ _]
- (rx/of (dwm/apply-modifiers options))))))
+ (rx/of (dwm/apply-modifiers* objects modif-tree nil options)))))))
(defn change-orientation
"Change orientation of shapes, from the sidebar options form.
@@ -859,42 +859,44 @@
(rx/of (reorder-selected-layout-child direction))
(rx/of (nudge-selected-shapes direction shift?)))))))
-(defn- get-delta [position bbox]
- (let [cpos (gpt/point (:x bbox) (:y bbox))
- pos (gpt/point (or (:x position) (:x bbox))
- (or (:y position) (:y bbox)))]
- (gpt/subtract pos cpos)))
-
-(defn- get-relative-delta [position bbox frame]
- (let [frame-bbox (-> frame :points grc/points->rect)
- relative-cpos (gpt/subtract (gpt/point (:x bbox) (:y bbox))
- (gpt/point (:x frame-bbox)
- (:y frame-bbox)))
- cpos (gpt/point (:x relative-cpos) (:y relative-cpos))
- pos (gpt/point (or (:x position) (:x relative-cpos))
- (or (:y position) (:y relative-cpos)))]
- (gpt/subtract pos cpos)))
+(defn- calculate-delta
+ [position bbox relative-to]
+ (let [current (gpt/point (:x bbox) (:y bbox))
+ position (gpt/point (or (some-> (:x position) (+ (dm/get-prop relative-to :x)))
+ (:x bbox))
+ (or (some-> (:y position) (+ (dm/get-prop relative-to :y)))
+ (:y bbox)))]
+ (gpt/subtract position current)))
(defn update-position
- "Move shapes to a new position"
+ "Move shapes to a new position. It will resolve to the current frame
+ of the shape, unless given the absolute option. In this case it will
+ resolve to the root frame of the page.
+
+ The position is a map that can have a partial position (it means it
+ can receive {:x 10}."
([id position] (update-position id position nil))
([id position options]
- (dm/assert! (uuid? id))
+ (assert (uuid? id) "expected a valid uuid for `id`")
+ (assert (map? position) "expected a valid map for `position`")
+
(ptk/reify ::update-position
ptk/WatchEvent
(watch [_ state _]
- (let [page-id (or (get options :page-id)
- (get state :current-page-id))
- objects (dsh/lookup-page-objects state page-id)
- shape (get objects id)
- ;; FIXME: performance rect
- bbox (-> shape :points grc/points->rect)
- frame (cfh/get-frame objects shape)
- delta (if (:absolute? options)
- (get-delta position bbox)
- (get-relative-delta position bbox frame))
- modif-tree (dwm/create-modif-tree [id] (ctm/move-modifiers delta))]
- (rx/of (dwm/apply-modifiers {:modifiers modif-tree
+ (let [page-id (or (get options :page-id)
+ (get state :current-page-id))
+ objects (dsh/lookup-page-objects state page-id)
+ shape (get objects id)
+
+ bbox (-> shape :points grc/points->rect)
+ frame (if (:absolute? options)
+ (cfh/get-frame objects)
+ (cfh/get-parent-frame objects shape))
+
+ delta (calculate-delta position bbox frame)
+ modifiers (dwm/create-modif-tree [id] (ctm/move-modifiers delta))]
+
+ (rx/of (dwm/apply-modifiers {:modifiers modifiers
:page-id page-id
:ignore-constraints false
:ignore-touched (:ignore-touched options)
diff --git a/frontend/src/app/main/data/workspace/undo.cljs b/frontend/src/app/main/data/workspace/undo.cljs
index 52a8f68af..114ba759f 100644
--- a/frontend/src/app/main/data/workspace/undo.cljs
+++ b/frontend/src/app/main/data/workspace/undo.cljs
@@ -22,7 +22,8 @@
;; Change this to :info :debug or :trace to debug this module
(log/set-level! :warn)
-(def discard-transaction-time-millis (* 20 1000))
+(def ^:private
+ discard-transaction-time-millis (* 20 1000))
(def ^:private
schema:undo-entry
@@ -30,7 +31,7 @@
[:undo-changes [:vector ::cpc/change]]
[:redo-changes [:vector ::cpc/change]]])
-(def check-undo-entry!
+(def check-undo-entry
(sm/check-fn schema:undo-entry))
(def MAX-UNDO-SIZE 50)
@@ -48,8 +49,7 @@
(ptk/reify ::materialize-undo
ptk/UpdateEvent
(update [_ state]
- (-> state
- (assoc-in [:workspace-undo :index] index)))))
+ (update state :workspace-undo assoc :index index))))
(defn- add-undo-entry
[state entry]
@@ -88,12 +88,9 @@
(defn append-undo
[entry stack?]
- (dm/assert!
- "expected valid undo entry"
- (check-undo-entry! entry))
- (dm/assert!
- (boolean? stack?))
+ (assert (check-undo-entry entry))
+ (assert (boolean? stack?))
(ptk/reify ::append-undo
ptk/UpdateEvent
@@ -118,17 +115,11 @@
(defn start-undo-transaction
"Start a transaction, so that every changes inside are added together in a single undo entry."
- [id]
+ [id & {:keys [timeout] :or {timeout discard-transaction-time-millis}}]
(ptk/reify ::start-undo-transaction
- ptk/WatchEvent
- (watch [_ _ _]
- (->> (rx/of (check-open-transactions))
- ;; Wait the configured time
- (rx/delay discard-transaction-time-millis)))
-
ptk/UpdateEvent
(update [_ state]
- (log/info :msg "start-undo-transaction")
+ (log/info :hint "start-undo-transaction")
;; We commit the old transaction before starting the new one
(let [current-tx (get-in state [:workspace-undo :transaction])
pending-tx (get-in state [:workspace-undo :transactions-pending])]
@@ -136,20 +127,28 @@
(nil? current-tx) (assoc-in [:workspace-undo :transaction] empty-tx)
(nil? pending-tx) (assoc-in [:workspace-undo :transactions-pending] #{id})
(some? pending-tx) (update-in [:workspace-undo :transactions-pending] conj id)
- :always (update-in [:workspace-undo :transactions-pending-ts] assoc id (dt/now)))))))
+ :always (update-in [:workspace-undo :transactions-pending-ts] assoc id (dt/now)))))
+
+ ptk/WatchEvent
+ (watch [_ _ _]
+ (when (and timeout (pos? timeout))
+ (->> (rx/of (check-open-transactions timeout))
+ ;; Wait the configured time
+ (rx/delay timeout))))))
+
(defn discard-undo-transaction []
(ptk/reify ::discard-undo-transaction
ptk/UpdateEvent
(update [_ state]
- (log/info :msg "discard-undo-transaction")
+ (log/info :hint "discard-undo-transaction")
(update state :workspace-undo dissoc :transaction :transactions-pending :transactions-pending-ts))))
(defn commit-undo-transaction [id]
(ptk/reify ::commit-undo-transaction
ptk/UpdateEvent
(update [_ state]
- (log/info :msg "commit-undo-transaction")
+ (log/info :hint "commit-undo-transaction")
(let [state (-> state
(update-in [:workspace-undo :transactions-pending] disj id)
(update-in [:workspace-undo :transactions-pending-ts] dissoc id))]
@@ -166,15 +165,15 @@
(assoc state :workspace-undo {}))))
(defn check-open-transactions
- []
+ [timeout]
(ptk/reify ::check-open-transactions
ptk/WatchEvent
(watch [_ state _]
- (log/info :msg "check-open-transactions")
+ (log/info :hint "check-open-transactions" :timeout timeout)
(let [pending-ts (-> (dm/get-in state [:workspace-undo :transactions-pending-ts])
- (update-vals #(.toMillis (dt/diff (dt/now) %))))]
+ (update-vals #(inst-ms (dt/diff (dt/now) %))))]
(->> pending-ts
- (filter (fn [[_ ts]] (>= ts discard-transaction-time-millis)))
+ (filter (fn [[_ ts]] (>= ts timeout)))
(rx/from)
(rx/tap #(js/console.warn (dm/str "FORCE COMMIT TRANSACTION AFTER " (second %) "MS")))
(rx/map first)
diff --git a/frontend/src/app/main/ui/dashboard/templates.cljs b/frontend/src/app/main/ui/dashboard/templates.cljs
index ae2df1b08..ac4a62512 100644
--- a/frontend/src/app/main/ui/dashboard/templates.cljs
+++ b/frontend/src/app/main/ui/dashboard/templates.cljs
@@ -112,16 +112,16 @@
(dom/stop-propagation event)
(on-import item event))))]
- [:a {:class (stl/css :card-container)
- :tab-index (if (or (not is-visible) collapsed) "-1" "0")
- :id id
- :data-index index
- :on-click on-click
- :on-mouse-down dom/prevent-default
- :on-mouse-enter #(reset! hover? true)
- :on-mouse-leave #(reset! hover? false)
- :on-key-down on-key-down}
- [:div {:class (stl/css :template-card)}
+ [:div {:class (stl/css :card-container)
+ :tab-index (if (or (not is-visible) collapsed) "-1" "0")
+ :id id
+ :data-index index}
+ [:a {:class (stl/css :template-card)
+ :on-click on-click
+ :on-mouse-down dom/prevent-default
+ :on-mouse-enter #(reset! hover? true)
+ :on-mouse-leave #(reset! hover? false)
+ :on-key-down on-key-down}
[:div {:class (stl/css :img-container)}
[:img {:src (dm/str thb)
:alt (:name item)
diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs
index 4642633f1..eb7069cb6 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs
@@ -175,7 +175,7 @@
show-in-viewer-ref (mf/use-ref nil)
;; PRESETS
- preset-state* (mf/use-state false)
+ preset-state* (mf/use-state false)
show-presets-dropdown? (deref preset-state*)
open-presets
@@ -205,11 +205,11 @@
;; ORIENTATION
- orientation (when (= type :frame)
- (cond (> (:width values) (:height values))
- :horiz
- :else
- :vert))
+ orientation
+ (when (= type :frame)
+ (if (> (:width values) (:height values))
+ :horiz
+ :vert))
on-orientation-change
(mf/use-fn
@@ -235,10 +235,8 @@
(run! #(st/emit! (udw/set-shape-proportion-lock % new-lock)) ids))))
;; POSITION
-
do-position-change
(mf/use-fn
- (mf/deps ids)
(fn [shape' value attr]
(st/emit! (udw/update-position (:id shape') {attr value}))))
@@ -248,7 +246,7 @@
(fn [value attr]
(st/emit! (udw/trigger-bounding-box-cloaking ids))
(binding [cts/*wasm-sync* true]
- (doall (map #(do-position-change %1 value attr) shapes)))))
+ (run! #(do-position-change %1 value attr) shapes))))
;; ROTATION
diff --git a/frontend/src/app/main/ui/workspace/tokens/changes.cljs b/frontend/src/app/main/ui/workspace/tokens/changes.cljs
index 1137b28e4..8bdc1a67f 100644
--- a/frontend/src/app/main/ui/workspace/tokens/changes.cljs
+++ b/frontend/src/app/main/ui/workspace/tokens/changes.cljs
@@ -304,13 +304,11 @@
ptk/WatchEvent
(watch [_ state _]
(when (number? value)
- (let [page-id' (or page-id (get state :current-page-id))]
- (rx/concat
- (map #(dwt/update-position % (zipmap attributes (repeat value))
- {:ignore-touched true
- :page-id page-id'})
- shape-ids))))))))
-
+ (let [page-id (or page-id (get state :current-page-id))]
+ (->> (rx/from shape-ids)
+ (rx/map #(dwt/update-position % (zipmap attributes (repeat value))
+ {:ignore-touched true
+ :page-id page-id})))))))))
(defn update-layout-sizing-limits
([value shape-ids attributes] (update-layout-sizing-limits value shape-ids attributes nil))
diff --git a/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs b/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs
index be7fee634..cdeec2753 100644
--- a/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs
+++ b/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs
@@ -140,24 +140,18 @@
[:div {:class (stl/css :theme-row-right)}
- (if-let [sets-count (some-> theme :sets seq count)]
- [:> button* {:class (stl/css :sets-count-button)
+ (let [sets-count (some-> theme :sets seq count)]
+ [:> button* {:class (stl/css-case :sets-count-button sets-count
+ :sets-count-empty-button (not sets-count))
:variant "secondary"
:type "button"
:title (tr "workspace.token.sets-hint")
:on-click on-edit-theme}
[:div {:class (stl/css :label-wrapper)}
[:> text* {:as "span" :typography "body-medium"}
- (tr "workspace.token.num-active-sets" sets-count)]
- [:> icon* {:icon-id "arrow-right"}]]]
-
- [:> button* {:class (stl/css :sets-count-empty-button)
- :type "button"
- :variant "secondary"
- :on-click on-edit-theme}
- [:div {:class (stl/css :label-wrapper)}
- [:> text* {:as "span" :typography "body-medium"}
- (tr "workspace.token.no-active-sets")]
+ (if sets-count
+ (tr "workspace.token.num-active-sets" sets-count)
+ (tr "workspace.token.no-active-sets"))]
[:> icon* {:icon-id "arrow-right"}]]])
[:> icon-button* {:on-click delete-theme
diff --git a/frontend/src/app/main/ui/workspace/tokens/sets.cljs b/frontend/src/app/main/ui/workspace/tokens/sets.cljs
index 9ad06f0cb..d118136fc 100644
--- a/frontend/src/app/main/ui/workspace/tokens/sets.cljs
+++ b/frontend/src/app/main/ui/workspace/tokens/sets.cljs
@@ -368,13 +368,13 @@
(mf/use-fn
(mf/deps collapsed-paths)
(fn [tree-index position data]
- (let [props {:from-index (:index data)
- :to-index tree-index
- :position position
- :collapsed-paths collapsed-paths}]
+ (let [params {:from-index (:index data)
+ :to-index tree-index
+ :position position
+ :collapsed-paths collapsed-paths}]
(if (:is-group data)
- (st/emit! (dt/drop-token-set-group props))
- (st/emit! (dt/drop-token-set props))))))
+ (st/emit! (dt/drop-token-set-group params))
+ (st/emit! (dt/drop-token-set params))))))
on-toggle-collapse
(mf/use-fn
diff --git a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs
index cce133af3..2f375cf56 100644
--- a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs
+++ b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs
@@ -103,8 +103,9 @@
(defn- generate-tooltip
"Generates a tooltip for a given token"
[is-viewer shape theme-token token half-applied no-valid-value ref-not-in-active-set]
- (let [{:keys [name value type]} token
- {:keys [resolved-value]} theme-token
+ (let [{:keys [name value type resolved-value]} token
+ resolved-value-theme (:resolved-value theme-token)
+ resolved-value (or resolved-value-theme resolved-value)
{:keys [title] :as token-props} (wtch/get-token-properties theme-token)
applied-tokens (:applied-tokens shape)
app-token-vals (set (vals applied-tokens))
diff --git a/frontend/src/app/main/ui/workspace/tokens/update.cljs b/frontend/src/app/main/ui/workspace/tokens/update.cljs
index b60a8c441..9de0bd233 100644
--- a/frontend/src/app/main/ui/workspace/tokens/update.cljs
+++ b/frontend/src/app/main/ui/workspace/tokens/update.cljs
@@ -1,6 +1,13 @@
+;; 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.main.ui.workspace.tokens.update
(:require
[app.common.files.helpers :as cfh]
+ [app.common.logging :as l]
[app.common.types.token :as ctt]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.shapes :as dwsh]
@@ -9,6 +16,7 @@
[app.main.ui.workspace.tokens.changes :as wtch]
[app.main.ui.workspace.tokens.style-dictionary :as wtsd]
[app.main.ui.workspace.tokens.token-set :as wtts]
+ [app.util.time :as dt]
[beicon.v2.core :as rx]
[clojure.data :as data]
[clojure.set :as set]
@@ -70,7 +78,7 @@
(reduce
(fn [acc [attrs v]]
(cond
- (some attrs #{:widht :height}) (let [[_ a b] (data/diff #{:width :height} attrs)]
+ (some attrs #{:width :height}) (let [[_ a b] (data/diff #{:width :height} attrs)]
(cond-> (assoc acc b v)
;; Exact match in attrs
a (assoc a v)))
@@ -127,8 +135,14 @@
[state resolved-tokens]
(let [file-id (get state :current-file-id)
current-page-id (get state :current-page-id)
- fdata (dsh/lookup-file-data state file-id)]
- (->> (rx/from (:pages fdata))
+ fdata (dsh/lookup-file-data state file-id)
+ tpoint (dt/tpoint-ms)]
+
+ (l/inf :status "START" :hint "update-tokens")
+ (->> (rx/concat
+ (rx/of current-page-id)
+ (->> (rx/from (:pages fdata))
+ (rx/filter (fn [id] (not= id current-page-id)))))
(rx/mapcat
(fn [page-id]
(let [page
@@ -140,6 +154,12 @@
actions
(actionize-shapes-update-info page-id attrs)]
+ (l/inf :status "PROGRESS"
+ :hint "update-tokens"
+ :page-id (str page-id)
+ :elapsed (tpoint)
+ ::l/sync? true)
+
(rx/merge
(rx/from actions)
(->> (rx/from frame-ids)
@@ -151,7 +171,11 @@
(fn [shape]
(dissoc shape :position-data))
{:page-id page-id
- :ignore-touched true}))))))))))
+ :ignore-touched true})))))))
+ (rx/finalize
+ (fn [_]
+ (let [elapsed (tpoint)]
+ (l/inf :status "END" :hint "update-tokens" :elapsed elapsed)))))))
(defn update-workspace-tokens
[]
@@ -164,6 +188,6 @@
(rx/mapcat (fn [sd-tokens]
(let [undo-id (js/Symbol)]
(rx/concat
- (rx/of (dwu/start-undo-transaction undo-id))
+ (rx/of (dwu/start-undo-transaction undo-id :timeout false))
(update-tokens state sd-tokens)
(rx/of (dwu/commit-undo-transaction undo-id)))))))))))
diff --git a/frontend/src/app/plugins/format.cljs b/frontend/src/app/plugins/format.cljs
index 6555f6a36..fdd1c7be9 100644
--- a/frontend/src/app/plugins/format.cljs
+++ b/frontend/src/app/plugins/format.cljs
@@ -176,8 +176,9 @@
(defn format-shadows
[shadows]
- (when (some? shadows)
- (format-array format-shadow shadows)))
+ (if (some? shadows)
+ (format-array format-shadow shadows)
+ (array)))
;;export interface Fill {
;; fillColor?: string;
diff --git a/frontend/translations/es.po b/frontend/translations/es.po
index 2517f9095..fdc013d6c 100644
--- a/frontend/translations/es.po
+++ b/frontend/translations/es.po
@@ -6738,7 +6738,7 @@ msgstr "%s sets activos"
#: src/app/main/ui/workspace/tokens/modals/themes.cljs:147
msgid "workspace.token.sets-hint"
-msgstr "Editar tema y gestionar set"
+msgstr "Editar tema y gestionar sets"
#: src/app/main/ui/workspace/tokens/token_pill.cljs:114
#, fuzzy