From 6aeb87a122836f880f8acb8f505597830bffcacf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Fri, 21 Jun 2024 11:48:33 +0200 Subject: [PATCH 1/2] :bug: Rework svg export of deleted components --- frontend/src/app/main/render.cljs | 21 +++++++++++++-------- frontend/src/app/worker/export.cljs | 8 ++++---- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/frontend/src/app/main/render.cljs b/frontend/src/app/main/render.cljs index bbf85e4ad..4cec0c71c 100644 --- a/frontend/src/app/main/render.cljs +++ b/frontend/src/app/main/render.cljs @@ -23,6 +23,7 @@ [app.common.geom.shapes.bounds :as gsb] [app.common.logging :as l] [app.common.math :as mth] + [app.common.types.components-list :as ctkl] [app.common.types.file :as ctf] [app.common.types.modifiers :as ctm] [app.common.types.shape-tree :as ctst] @@ -525,8 +526,10 @@ (mf/defc components-svg {::mf/wrap-props false} - [{:keys [data children embed include-metadata source]}] - (let [source (keyword (d/nilv source "components"))] + [{:keys [data children embed include-metadata deleted?]}] + (let [components (if (not deleted?) + (ctkl/components-seq data) + (ctkl/deleted-components-seq data))] [:& (mf/provider embed/context) {:value embed} [:& (mf/provider export/include-metadata-ctx) {:value include-metadata} [:svg {:version "1.1" @@ -536,9 +539,9 @@ :style {:display (when-not (some? children) "none")} :fill "none"} [:defs - (for [[id component] (source data)] + (for [component components] (let [component (ctf/load-component-objects data component)] - [:& component-symbol {:key (dm/str id) :component component}]))] + [:& component-symbol {:key (dm/str (:id component)) :component component}]))] children]]])) @@ -595,10 +598,12 @@ (rds/renderToStaticMarkup elem))))))) (defn render-components - [data source] + [data deleted?] (let [;; Join all components objects into a single map - objects (->> (source data) - (vals) + components (if (not deleted?) + (ctkl/components-seq data) + (ctkl/deleted-components-seq data)) + objects (->> components (map (partial ctf/load-component-objects data)) (map :objects) (reduce conj))] @@ -615,7 +620,7 @@ #js {:data data :embed true :include-metadata true - :source (name source)})] + :deleted? deleted?})] (rds/renderToStaticMarkup elem)))))))) (defn render-frame diff --git a/frontend/src/app/worker/export.cljs b/frontend/src/app/worker/export.cljs index 604845c73..b43bbbe11 100644 --- a/frontend/src/app/worker/export.cljs +++ b/frontend/src/app/worker/export.cljs @@ -52,7 +52,7 @@ :libraries (->> (:libraries file) (into #{}) (mapv str)) :exportType (d/name export-type) :hasComponents (d/not-empty? (ctkl/components-seq (:data file))) - :hasDeletedComponents (d/not-empty? (get-in file [:data :deleted-components])) + :hasDeletedComponents (d/not-empty? (ctkl/deleted-components-seq (:data file))) :hasMedia (d/not-empty? (get-in file [:data :media])) :hasColors (d/not-empty? (get-in file [:data :colors])) :hasTypographies (d/not-empty? (get-in file [:data :typographies]))}))))] @@ -151,12 +151,12 @@ (defn parse-library-components [file] - (->> (r/render-components (:data file) :components) + (->> (r/render-components (:data file) false) (rx/map #(vector (str (:id file) "/components.svg") %)))) (defn parse-deleted-components [file] - (->> (r/render-components (:data file) :deleted-components) + (->> (r/render-components (:data file) true) (rx/map #(vector (str (:id file) "/deleted-components.svg") %)))) (defn fetch-file-with-libraries @@ -380,7 +380,7 @@ deleted-components-stream (->> files-stream (rx/merge-map vals) - (rx/filter #(d/not-empty? (get-in % [:data :deleted-components]))) + (rx/filter #(d/not-empty? (ctkl/deleted-components-seq (:data %)))) (rx/merge-map parse-deleted-components)) pages-stream From 798970a9239d9accc8010a6bb47b1627e93dc1ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Fri, 21 Jun 2024 18:45:00 +0200 Subject: [PATCH 2/2] :bug: Rework svg import of deleted components --- common/src/app/common/files/builder.cljc | 85 +++++++++++++----------- frontend/src/app/main/render.cljs | 15 +++-- frontend/src/app/worker/import.cljs | 53 +++++++++------ 3 files changed, 88 insertions(+), 65 deletions(-) diff --git a/common/src/app/common/files/builder.cljc b/common/src/app/common/files/builder.cljc index 8605a5e1f..988164c20 100644 --- a/common/src/app/common/files/builder.cljc +++ b/common/src/app/common/files/builder.cljc @@ -41,16 +41,19 @@ (let [components-v2 (dm/get-in file [:data :options :components-v2]) component-id (:current-component-id file) change (cond-> change - (and add-container? (some? component-id)) + (and add-container? (some? component-id) (not components-v2)) (-> (assoc :component-id component-id) (cond-> (some? (:current-frame-id file)) (assoc :frame-id (:current-frame-id file)))) - (and add-container? (nil? component-id)) + (and add-container? (or (nil? component-id) components-v2)) (assoc :page-id (:current-page-id file) :frame-id (:current-frame-id file))) - valid? (ch/check-change! change)] + valid? (or (and components-v2 + (nil? (:component-id change)) + (nil? (:page-id change))) + (ch/check-change! change))] (when-not valid? (let [explain (sm/explain ::ch/change change)] @@ -62,7 +65,7 @@ ::sm/explain explain)))) (cond-> file - (and valid? (not (and components-v2 add-container? (some? component-id)))) + (and valid? (or (not add-container?) (some? (:component-id change)) (some? (:page-id change)))) (-> (update :changes conjv change) ;; In components-v2 we do not add shapes (update :data ch/process-changes [change] false)) ;; inside a component @@ -524,6 +527,11 @@ path (:path data) main-instance-id (:main-instance-id data) main-instance-page (:main-instance-page data) + + ;; In components v1 we must create the root shape and set it inside + ;; the :objects attribute of the component. When in components-v2, + ;; this will be ignored as the root shape has already been created + ;; in its page, by the normal page import. attrs (-> data (assoc :type root-type) (assoc :x (:x selrect)) @@ -559,6 +567,29 @@ (assoc :current-component-id (:id obj)) (assoc :current-frame-id (if (= (:type obj) :frame) (:id obj) uuid/zero)))))) +(defn start-deleted-component + [file data] + (let [attrs (-> data + (assoc :id (:main-instance-id data)) + (assoc :component-file (:id file)) + (assoc :component-id (:id data)) + (assoc :x (:main-instance-x data)) + (assoc :y (:main-instance-y data)) + (dissoc :path) + (dissoc :main-instance-id) + (dissoc :main-instance-page) + (dissoc :main-instance-x) + (dissoc :main-instance-y) + (dissoc :main-instance-parent) + (dissoc :main-instance-frame))] + ;; To create a deleted component, first we add all shapes of the main instance + ;; in the main instance page, and in the finish event we delete it. + (-> file + (update :parent-stack conjv (:main-instance-parent data)) + (assoc :current-page-id (:main-instance-page data)) + (assoc :current-frame-id (:main-instance-frame data)) + (add-artboard attrs)))) + (defn finish-component [file] (let [component-id (:current-component-id file) @@ -623,43 +654,18 @@ (update :parent-stack pop)))) (defn finish-deleted-component - [component-id page-id main-instance-x main-instance-y file] + [component-id file] (let [file (assoc file :current-component-id component-id) - page (ctpl/get-page (:data file) page-id) - component (ctkl/get-component (:data file) component-id) - main-instance-id (:main-instance-id component) - - ; To obtain a deleted component, we first create the component - ; and the main instance in the workspace, and then delete them. - [_ shapes] - (ctn/make-component-instance page - component - (:data file) - (gpt/point main-instance-x - main-instance-y) - true - {:main-instance true - :force-id main-instance-id})] - (as-> file $ - (reduce #(commit-change %1 - {:type :add-obj - :id (:id %2) - :page-id (:id page) - :parent-id (:parent-id %2) - :frame-id (:frame-id %2) - :ignore-touched true - :obj %2}) - $ - shapes) - (commit-change $ {:type :del-component + component (ctkl/get-component (:data file) component-id)] + (-> file + (close-artboard) + (commit-change {:type :del-component :id component-id}) - (reduce #(commit-change %1 {:type :del-obj - :page-id page-id - :ignore-touched true - :id (:id %2)}) - $ - shapes) - (dissoc $ :current-component-id)))) + (commit-change {:type :del-obj + :page-id (:main-instance-page component) + :id (:main-instance-id component) + :ignore-touched true}) + (dissoc :current-page-id)))) (defn create-component-instance [file data] @@ -670,7 +676,6 @@ page-id (:current-page-id file) page (ctpl/get-page (:data file) page-id) component (ctkl/get-component (:data file) component-id) - ;; main-instance-id (:main-instance-id component) components-v2 (dm/get-in file [:options :components-v2]) diff --git a/frontend/src/app/main/render.cljs b/frontend/src/app/main/render.cljs index 4cec0c71c..a371a67d3 100644 --- a/frontend/src/app/main/render.cljs +++ b/frontend/src/app/main/render.cljs @@ -485,15 +485,18 @@ path (:path component) root-id (or (:main-instance-id component) (:id component)) + orig-root (get (:objects component) root-id) objects (adapt-objects-for-shape (:objects component) root-id) root-shape (get objects root-id) selrect (:selrect root-shape) - main-instance-id (:main-instance-id component) - main-instance-page (:main-instance-page component) - main-instance-x (:main-instance-x component) - main-instance-y (:main-instance-y component) + main-instance-id (:main-instance-id component) + main-instance-page (:main-instance-page component) + main-instance-x (when (:deleted component) (:x orig-root)) + main-instance-y (when (:deleted component) (:y orig-root)) + main-instance-parent (when (:deleted component) (:parent-id orig-root)) + main-instance-frame (when (:deleted component) (:frame-id orig-root)) vbox (format-viewbox @@ -517,7 +520,9 @@ "penpot:main-instance-id" main-instance-id "penpot:main-instance-page" main-instance-page "penpot:main-instance-x" main-instance-x - "penpot:main-instance-y" main-instance-y} + "penpot:main-instance-y" main-instance-y + "penpot:main-instance-parent" main-instance-parent + "penpot:main-instance-frame" main-instance-frame} [:title name] [:> shape-container {:shape root-shape} (case (:type root-shape) diff --git a/frontend/src/app/worker/import.cljs b/frontend/src/app/worker/import.cljs index 901b3edcd..186de184d 100644 --- a/frontend/src/app/worker/import.cljs +++ b/frontend/src/app/worker/import.cljs @@ -253,6 +253,7 @@ frame (when (and (some? frame-id) (not= frame-id uuid/zero)) (fb/lookup-shape file frame-id))] + (js/console.log " translate-frame" (clj->js frame)) (if (some? frame) (-> data (d/update-when :x + (:x frame)) @@ -283,7 +284,13 @@ (cond-> (some? old-id) (assoc :id (resolve old-id))) (cond-> (< (:version context 1) 2) - (translate-frame type file)))] + (translate-frame type file)) + ;; Shapes inside the deleted component should be stored with absolute coordinates + ;; so we calculate that with the x and y stored in the context + (cond-> (:x context) + (assoc :x (:x context))) + (cond-> (:y context) + (assoc :y (:y context))))] (try (let [file (case type :frame (fb/add-artboard file data) @@ -455,17 +462,19 @@ (rx/map fb/finish-component)))) (defn import-deleted-component [context file node] - (let [resolve (:resolve context) - content (parser/find-node node :g) - file-id (:id file) - old-id (parser/get-id node) - id (resolve old-id) - path (get-in node [:attrs :penpot:path] "") - main-instance-id (resolve (uuid (get-in node [:attrs :penpot:main-instance-id] ""))) - main-instance-page (resolve (uuid (get-in node [:attrs :penpot:main-instance-page] ""))) - main-instance-x (get-in node [:attrs :penpot:main-instance-x] "") - main-instance-y (get-in node [:attrs :penpot:main-instance-y] "") - type (parser/get-type content) + (let [resolve (:resolve context) + content (parser/find-node node :g) + file-id (:id file) + old-id (parser/get-id node) + id (resolve old-id) + path (get-in node [:attrs :penpot:path] "") + main-instance-id (resolve (uuid (get-in node [:attrs :penpot:main-instance-id] ""))) + main-instance-page (resolve (uuid (get-in node [:attrs :penpot:main-instance-page] ""))) + main-instance-x (-> (get-in node [:attrs :penpot:main-instance-x] "") (d/parse-double)) + main-instance-y (-> (get-in node [:attrs :penpot:main-instance-y] "") (d/parse-double)) + main-instance-parent (resolve (uuid (get-in node [:attrs :penpot:main-instance-parent] ""))) + main-instance-frame (resolve (uuid (get-in node [:attrs :penpot:main-instance-frame] ""))) + type (parser/get-type content) data (-> (parser/parse-data type content) (assoc :path path) @@ -473,12 +482,20 @@ (assoc :main-instance-id main-instance-id) (assoc :main-instance-page main-instance-page) (assoc :main-instance-x main-instance-x) - (assoc :main-instance-y main-instance-y)) + (assoc :main-instance-y main-instance-y) + (assoc :main-instance-parent main-instance-parent) + (assoc :main-instance-frame main-instance-frame)) - file (-> file (fb/start-component data)) + file (-> file + (fb/start-component data) + (fb/start-deleted-component data)) component-id (:current-component-id file) - children (parser/node-seq node)] + children (parser/node-seq node) + ;; Shapes inside the deleted component should be stored with absolute coordinates so we include this info in the context. + context (-> context + (assoc :x main-instance-x) + (assoc :y main-instance-y))] (->> (rx/from children) (rx/filter parser/shape?) (rx/skip 1) @@ -486,11 +503,7 @@ (rx/mapcat (partial resolve-media context file-id)) (rx/reduce (partial process-import-node context) file) (rx/map fb/finish-component) - (rx/map (partial fb/finish-deleted-component - component-id - main-instance-page - main-instance-x - main-instance-y))))) + (rx/map (partial fb/finish-deleted-component component-id))))) (defn process-pages [context file]