From a2555f473dfa7911f19222f6327de6d262c320d3 Mon Sep 17 00:00:00 2001 From: Pablo Alba Date: Wed, 12 Feb 2025 21:40:01 +0100 Subject: [PATCH] wip --- .../src/app/common/files/changes_builder.cljc | 7 ++ common/src/app/common/logic/shapes.cljc | 77 ++++++++++++++++--- common/src/app/common/logic/variants.cljc | 46 +++++++++++ common/src/app/common/types/container.cljc | 14 +++- frontend/src/app/main/data/workspace.cljs | 2 + .../src/app/main/data/workspace/groups.cljs | 3 +- .../app/main/data/workspace/transforms.cljs | 2 + .../src/app/main/data/workspace/variants.cljs | 39 +++------- .../app/main/ui/workspace/context_menu.cljs | 4 +- 9 files changed, 146 insertions(+), 48 deletions(-) create mode 100644 common/src/app/common/logic/variants.cljc diff --git a/common/src/app/common/files/changes_builder.cljc b/common/src/app/common/files/changes_builder.cljc index c07738c3a..f5b48df50 100644 --- a/common/src/app/common/files/changes_builder.cljc +++ b/common/src/app/common/files/changes_builder.cljc @@ -1001,6 +1001,13 @@ :objects (:objects prev-component)})) changes)))) +(defn update-components + ([changes ids update-fn] + (reduce + (fn [changes id] (update-component changes id update-fn)) + changes + ids))) + (defn delete-component [changes id page-id] (assert-library! changes) diff --git a/common/src/app/common/logic/shapes.cljc b/common/src/app/common/logic/shapes.cljc index b53d2af2a..712d63de7 100644 --- a/common/src/app/common/logic/shapes.cljc +++ b/common/src/app/common/logic/shapes.cljc @@ -10,12 +10,14 @@ [app.common.files.changes-builder :as pcb] [app.common.files.helpers :as cfh] [app.common.geom.shapes :as gsh] + [app.common.logic.variants :as clv] [app.common.types.component :as ctk] [app.common.types.container :as ctn] [app.common.types.shape.interactions :as ctsi] [app.common.types.shape.layout :as ctl] [app.common.types.token :as cto] - [app.common.uuid :as uuid])) + [app.common.uuid :as uuid] + [cuerdas.core :as str])) (defn- generate-unapply-tokens "When updating attributes that have a token applied, we must unapply it, because the value @@ -238,23 +240,37 @@ [all-parents changes])) + + +(defn- assign-values [items names-str] + (let [names (str/split names-str " / ") + assigned (mapv #(assoc % :value (nth names %2 "--")) items (range)) + remaining (drop (count items) names) + new-properties (map-indexed (fn [i v] {:name (str "Property" (+ (count items) i 1)) :value v}) remaining)] + (into assigned new-properties))) + (defn generate-relocate - [changes objects parent-id page-id to-index ids & {:keys [cell ignore-parents?]}] + [changes objects parent-id page-id to-index ids data & {:keys [cell ignore-parents?]}] (let [ids (cfh/order-by-indexed-shapes objects ids) shapes (map (d/getf objects) ids) parent (get objects parent-id) all-parents (into #{parent-id} (map #(cfh/get-parent-id objects %)) ids) parents (if ignore-parents? #{parent-id} all-parents) - children-ids - (->> ids - (mapcat #(cfh/get-children-ids-with-self objects %))) + children-ids (mapcat #(cfh/get-children-ids-with-self objects %) ids) - child-heads - (->> ids - (mapcat #(ctn/get-child-heads objects %)) - (map :id)) + child-heads (mapcat #(ctn/get-child-heads objects %) ids) + child-heads-ids (map :id child-heads) + + + variant-properties (when (ctk/is-variant-container? parent) + (as-> parent $ + (:shapes $) + (first $) + (get objects $) + (:component-id $) + (get-in data [:components $ :variant-properties]))) component-main-parent (ctn/find-component-main objects parent false) @@ -342,6 +358,7 @@ (-> changes (pcb/with-page-id page-id) (pcb/with-objects objects) + (pcb/with-library-data data) ;; Remove layout-item properties when moving a shape outside a layout (cond-> (not (ctl/any-layout? parent)) @@ -353,7 +370,7 @@ ;; Remove the swap slots if it is moving to a different component (pcb/update-shapes - child-heads + child-heads-ids (fn [shape] (cond-> shape (not= component-main-parent (ctn/find-component-main objects shape false)) @@ -365,7 +382,45 @@ ;; Add component-root property when moving a component outside a component (cond-> (not (ctn/get-instance-root objects parent)) - (pcb/update-shapes child-heads #(assoc % :component-root true))) + (pcb/update-shapes child-heads-ids #(assoc % :component-root true))) + + ;; Remove variant info when moving outside a variant-container + (cond-> (not (ctk/is-variant-container? parent)) + (-> (pcb/update-shapes child-heads-ids #(dissoc % :variant-id :variant-name)) + (pcb/update-components (map :component-id child-heads) #(dissoc % :variant-id :variant-properties)))) + + ;; Add variant info when moving into a variant-container + (cond-> (ctk/is-variant-container? parent) + ((fn [changes] + (reduce + (fn [changes shape] + (let [names (str/split (:name shape) " / ") + num-props (count variant-properties) + num-new-props (if (< (count names) num-props) + 0 + (- (count names) num-props )) + + related-components (->> (:components data) + vals + (filter #(= (:variant-id %) (:id parent))) + reverse) + + changes (if (pos? num-new-props) + (reduce (fn [changes iteration] + (clv/generate-add-new-property changes + related-components + (str "Property" (+ iteration num-props 1)))) + changes + (range num-new-props)) + changes) + + props (assign-values variant-properties (:name shape)) + variant-name (str/replace (:name shape) " / " ", ")] + (-> (pcb/update-component changes (:component-id shape) #(assoc % :variant-id (:id parent) :variant-properties props :name (:name parent))) + (pcb/update-shapes [(:id shape)] #(assoc % :variant-id (:id parent) :variant-name variant-name :name (:name parent)))))) + changes + child-heads)) + #_(pcb/update-components (map :component-id child-heads) #(assoc % :variant-id (:id parent) :variant-properties variant-properties)))) ;; Move the shapes (pcb/change-parent parent-id diff --git a/common/src/app/common/logic/variants.cljc b/common/src/app/common/logic/variants.cljc new file mode 100644 index 000000000..13ff26e03 --- /dev/null +++ b/common/src/app/common/logic/variants.cljc @@ -0,0 +1,46 @@ +;; 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.variants + (:require + [app.common.files.changes-builder :as pcb] + [cuerdas.core :as str])) + +(defn properties-to-name + [properties] + (->> properties + (map :value) + (str/join ", "))) + +(defn generate-add-new-property + ([changes related-components] + (let [property-name (str "Property" (-> related-components + first + :variant-properties + count + inc))] + (generate-add-new-property changes related-components property-name))) + + ([changes related-components property-name] + (let [[_ changes] + (reduce (fn [[num changes] component] + (let [main-id (:main-instance-id component) + _ (prn "Adding" property-name (str "Value" num)) + add-variant #(let [_ (prn %) + _ (prn "add-variant " property-name (str "Value" num))] + (-> (or % []) + (conj {:name property-name :value (str "Value" num)}))) + add-name #(let [_ (prn %)] + (if (str/empty? %) + (str "Value" num) + (str % ", " "Value" num)))] + [(inc num) + (-> changes + (pcb/update-component (:id component) #(update % :variant-properties add-variant)) + (pcb/update-shapes [main-id] #(update % :variant-name add-name)))])) + [1 changes] + related-components)] + changes))) \ No newline at end of file diff --git a/common/src/app/common/types/container.cljc b/common/src/app/common/types/container.cljc index 38d222735..cb85a039e 100644 --- a/common/src/app/common/types/container.cljc +++ b/common/src/app/common/types/container.cljc @@ -535,11 +535,17 @@ (letfn [(get-frame [parent-id] (if (cfh/frame-shape? objects parent-id) parent-id (get-in objects [parent-id :frame-id])))] (let [parent (get objects parent-id) - ;; We can always move the children to the parent they already have. + ;; We can always move the children to the parent they already have. + ;; But if we are pasting, those are new items, so it is considered a change no-changes? - (->> children (every? #(= parent-id (:parent-id %))))] - ;; In case no-changes is true we must ensure we are copy pasting the children in the same position - (if (or (and no-changes? (not pasting?)) (not (invalid-structure-for-component? objects parent children pasting? libraries))) + (and (->> children (every? #(= parent-id (:parent-id %)))) + (not pasting?)) + all-main? + (->> children (every? #(ctk/main-instance? %)))] + (if (or no-changes? + (and (not (invalid-structure-for-component? objects parent children pasting? libraries)) + (or all-main? + (not (ctk/is-variant-container? parent))))) [parent-id (get-frame parent-id)] (recur (:parent-id parent) objects children pasting? libraries)))))) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index c181104c4..30bd903b0 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -879,6 +879,7 @@ (watch [it state _] (let [page-id (:current-page-id state) objects (dsh/lookup-page-objects state page-id) + data (dsh/lookup-file-data state) ;; Ignore any shape whose parent is also intended to be moved ids (cfh/clean-loops objects ids) @@ -894,6 +895,7 @@ page-id to-index ids + data :ignore-parents? ignore-parents?) undo-id (js/Symbol)] diff --git a/frontend/src/app/main/data/workspace/groups.cljs b/frontend/src/app/main/data/workspace/groups.cljs index b0f97b055..6d7d18f1c 100644 --- a/frontend/src/app/main/data/workspace/groups.cljs +++ b/frontend/src/app/main/data/workspace/groups.cljs @@ -232,7 +232,8 @@ ids (->> ids (remove #(ctn/has-any-copy-parent? objects (get objects %))) ;; components can't be ungrouped - (remove #(ctk/instance-head? (get objects %)))) + (remove #(ctk/instance-head? (get objects %))) + (remove #(ctk/is-variant-container? (get objects %)))) changes-list (sequence (keep prepare) ids) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 5b3988427..8b9239573 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -871,6 +871,7 @@ (watch [it state _] (let [page-id (:current-page-id state) objects (dsh/lookup-page-objects state page-id) + data (dsh/lookup-file-data state) ids (cleanup-invalid-moving-shapes ids objects frame-id) changes (cls/generate-relocate (pcb/empty-changes it) objects @@ -878,6 +879,7 @@ page-id drop-index ids + data :cell cell)] (when (and (some? frame-id) (d/not-empty? changes)) diff --git a/frontend/src/app/main/data/workspace/variants.cljs b/frontend/src/app/main/data/workspace/variants.cljs index 54cdc3fd1..d9f980340 100644 --- a/frontend/src/app/main/data/workspace/variants.cljs +++ b/frontend/src/app/main/data/workspace/variants.cljs @@ -9,6 +9,7 @@ [app.common.colors :as clr] [app.common.data.macros :as dm] [app.common.files.changes-builder :as pcb] + [app.common.logic.variants :as clv] [app.common.uuid :as uuid] [app.main.data.changes :as dch] [app.main.data.helpers :as dsh] @@ -18,15 +19,10 @@ [app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.undo :as dwu] [beicon.v2.core :as rx] - [cuerdas.core :as str] [potok.v2.core :as ptk])) -(defn properties-to-name - [properties] - (->> properties - (map :value) - (str/join ", "))) + (defn update-property-name "Update the variant property name on the position pos @@ -83,7 +79,7 @@ (let [props (:variant-properties component) props (vec (concat (subvec props 0 pos) (subvec props (inc pos)))) main-id (:main-instance-id component) - name (properties-to-name props)] + name (clv/properties-to-name props)] (-> changes (pcb/update-component (:id component) #(assoc % :variant-properties props)) (pcb/update-shapes [main-id] #(assoc % :variant-name name))))) @@ -110,7 +106,7 @@ properties (-> (:variant-properties component) (assoc-in [pos :value] value)) - name (properties-to-name properties) + name (clv/properties-to-name properties) changes (-> (pcb/empty-changes it page-id) (pcb/with-library-data data) @@ -123,6 +119,8 @@ (dch/commit-changes changes) (dwu/commit-undo-transaction undo-id)))))) + + (defn add-new-property "Add a new variant property to all the components with this variant-id" [variant-id] @@ -131,36 +129,17 @@ (watch [it state _] (let [page-id (:current-page-id state) data (dsh/lookup-file-data state) - objects (dsh/lookup-page-objects state page-id) + objects (dsh/lookup-page-objects state page-id) related-components (->> (:components data) vals (filter #(= (:variant-id %) variant-id)) reverse) - - property-name (str "Property" (-> related-components - first - :variant-properties - count - inc)) - changes (-> (pcb/empty-changes it page-id) (pcb/with-library-data data) - (pcb/with-objects objects)) - - [_ changes] - (reduce (fn [[num changes] component] - (let [props (-> (or (:variant-properties component) []) - (conj {:name property-name :value (str "Value" num)})) - main-id (:main-instance-id component) - variant-name (properties-to-name props)] - [(inc num) - (-> changes - (pcb/update-component (:id component) #(assoc % :variant-properties props)) - (pcb/update-shapes [main-id] #(assoc % :variant-name variant-name)))])) - [1 changes] - related-components) + (pcb/with-objects objects) + (clv/generate-add-new-property related-components)) undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index 1d0de3364..81d63dd32 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -324,8 +324,8 @@ any-in-copy? (some true? (map #(ctn/has-any-copy-parent? objects %) shapes)) ;; components can't be ungrouped - has-frame? (->> shapes (d/seek #(and (cfh/frame-shape? %) (not (ctk/instance-head? %))))) - has-group? (->> shapes (d/seek #(and (cfh/group-shape? %) (not (ctk/instance-head? %))))) + has-frame? (->> shapes (d/seek #(and (cfh/frame-shape? %) (not (ctk/instance-head? %)) (not (ctk/is-variant-container? %))))) + has-group? (->> shapes (d/seek #(and (cfh/group-shape? %) (not (ctk/instance-head? %)) (not (ctk/is-variant-container? %))))) has-bool? (->> shapes (d/seek cfh/bool-shape?)) has-mask? (->> shapes (d/seek :masked-group))