From 09d1c958ce65bc6abd4a6ee8d95edbb54f108ccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Thu, 7 Oct 2021 17:09:16 +0200 Subject: [PATCH] :sparkles: Include advanced interactions and flows in import/export --- common/src/app/common/file_builder.cljc | 75 ++++++++++++++++--- common/src/app/common/types/page_options.cljc | 6 +- frontend/src/app/main/ui/shapes/export.cljs | 68 ++++++++++------- frontend/src/app/util/import/parser.cljs | 42 ++++++++--- frontend/src/app/worker/import.cljs | 5 +- 5 files changed, 146 insertions(+), 50 deletions(-) diff --git a/common/src/app/common/file_builder.cljc b/common/src/app/common/file_builder.cljc index 8b84d8c114..0ae1127dff 100644 --- a/common/src/app/common/file_builder.cljc +++ b/common/src/app/common/file_builder.cljc @@ -374,21 +374,76 @@ (-> file (update :parent-stack pop))) +(defn- read-classifier + [interaction-src] + (select-keys interaction-src [:event-type :action-type])) + +(defmulti read-event-opts :event-type) + +(defmethod read-event-opts :after-delay + [interaction-src] + (select-keys interaction-src [:delay])) + +(defmethod read-event-opts :default + [_] + {}) + +(defmulti read-action-opts :action-type) + +(defmethod read-action-opts :navigate + [interaction-src] + (select-keys interaction-src [:destination])) + +(defmethod read-action-opts :open-overlay + [interaction-src] + (select-keys interaction-src [:destination + :overlay-position + :overlay-pos-type + :close-click-outside + :background-overlay])) + +(defmethod read-action-opts :toggle-overlay + [interaction-src] + (select-keys interaction-src [:destination + :overlay-position + :overlay-pos-type + :close-click-outside + :background-overlay])) + +(defmethod read-action-opts :close-overlay + [interaction-src] + (select-keys interaction-src [:destination])) + +(defmethod read-action-opts :prev-screen + [_] + {}) + +(defmethod read-action-opts :open-url + [interaction-src] + (select-keys interaction-src [:url])) + (defn add-interaction - [file from-id {:keys [action-type event-type destination]}] + [file from-id interaction-src] (assert (some? (lookup-shape file from-id)) (str "Cannot locate shape with id " from-id)) - (assert (some? (lookup-shape file destination)) (str "Cannot locate shape with id " destination)) - (let [interactions (->> (lookup-shape file from-id) - :interactions - (filterv #(or (not= (:action-type %) action-type) - (not= (:event-type %) event-type)))) - interactions (-> interactions + (let [{:keys [event-type action-type]} (read-classifier interaction-src) + {:keys [delay]} (read-event-opts interaction-src) + {:keys [destination overlay-pos-type overlay-position url + close-click-outside background-overlay]} (read-action-opts interaction-src) + + interactions (-> (lookup-shape file from-id) + :interactions (conjv - {:action-type action-type - :event-type event-type - :destination destination}))] + (d/without-nils {:event-type event-type + :action-type action-type + :delay delay + :destination destination + :overlay-pos-type overlay-pos-type + :overlay-position overlay-position + :url url + :close-click-outside close-click-outside + :background-overlay background-overlay})))] (commit-change file {:type :mod-obj diff --git a/common/src/app/common/types/page_options.cljc b/common/src/app/common/types/page_options.cljc index db8271693b..ff440dca53 100644 --- a/common/src/app/common/types/page_options.cljc +++ b/common/src/app/common/types/page_options.cljc @@ -12,11 +12,11 @@ ;; --- Grid options -(s/def :artboard-grid.color/value ::us/string) +(s/def :artboard-grid.color/color ::us/string) (s/def :artboard-grid.color/opacity ::us/safe-number) (s/def :artboard-grid/size ::us/safe-integer) -(s/def :artboard-grid/color (s/keys :req-un [:artboard-grid.color/value +(s/def :artboard-grid/color (s/keys :req-un [:artboard-grid.color/color :artboard-grid.color/opacity])) (s/def :artboard-grid/type #{:stretch :left :center :right}) (s/def :artboard-grid/item-length (s/nilable ::us/safe-integer)) @@ -38,7 +38,7 @@ (s/def :artboard-grid/row :artboard-grid/column) (s/def ::saved-grids - (s/keys :req-un [:artboard-grid/square + (s/keys :opt-un [:artboard-grid/square :artboard-grid/row :artboard-grid/column])) diff --git a/frontend/src/app/main/ui/shapes/export.cljs b/frontend/src/app/main/ui/shapes/export.cljs index 97a9caf88e..f204282980 100644 --- a/frontend/src/app/main/ui/shapes/export.cljs +++ b/frontend/src/app/main/ui/shapes/export.cljs @@ -131,30 +131,41 @@ (mf/defc export-grid-data [{:keys [grids]}] - (when-not (empty? grids) - [:> "penpot:grids" #js {} - (for [{:keys [type display params]} grids] - (let [props (->> (d/without-keys params [:color]) - (prefix-keys) - (clj->js))] - [:> "penpot:grid" - (-> props - (obj/set! "penpot:color" (get-in params [:color :color])) - (obj/set! "penpot:opacity" (get-in params [:color :opacity])) - (obj/set! "penpot:type" (d/name type)) - (cond-> (some? display) - (obj/set! "penpot:display" (str display))))]))])) + [:> "penpot:grids" #js {} + (for [{:keys [type display params]} grids] + (let [props (->> (d/without-keys params [:color]) + (prefix-keys) + (clj->js))] + [:> "penpot:grid" + (-> props + (obj/set! "penpot:color" (get-in params [:color :color])) + (obj/set! "penpot:opacity" (get-in params [:color :opacity])) + (obj/set! "penpot:type" (d/name type)) + (cond-> (some? display) + (obj/set! "penpot:display" (str display))))]))]) + +(mf/defc export-flows + [{:keys [flows]}] + [:> "penpot:flows" #js {} + (for [{:keys [id name starting-frame]} flows] + [:> "penpot:flow" #js {:id id + :name name + :starting-frame starting-frame}])]) (mf/defc export-page [{:keys [options]}] - (let [saved-grids (get options :saved-grids)] - (when-not (empty? saved-grids) - (let [parse-grid - (fn [[type params]] - {:type type :params params}) - grids (->> saved-grids (mapv parse-grid))] - [:> "penpot:page" #js {} - [:& export-grid-data {:grids grids}]])))) + (let [saved-grids (get options :saved-grids) + flows (get options :flows)] + (when (or (seq saved-grids) (seq flows)) + (let [parse-grid + (fn [[type params]] + {:type type :params params}) + grids (->> saved-grids (mapv parse-grid))] + [:> "penpot:page" #js {} + (when (seq saved-grids) + [:& export-grid-data {:grids grids}]) + (when (seq flows) + [:& export-flows {:flows flows}])])))) (mf/defc export-shadow-data [{:keys [shadow]}] @@ -220,11 +231,18 @@ [{:keys [interactions]}] (when-not (empty? interactions) [:> "penpot:interactions" #js {} - (for [{:keys [action-type destination event-type]} interactions] + (for [interaction interactions] [:> "penpot:interaction" - #js {:penpot:action-type (d/name action-type) - :penpot:destination (str destination) - :penpot:event-type (d/name event-type)}])])) + #js {:penpot:event-type (d/name (:event-type interaction)) + :penpot:action-type (d/name (:action-type interaction)) + :penpot:delay ((d/nilf str) (:delay interaction)) + :penpot:destination ((d/nilf str) (:destination interaction)) + :penpot:overlay-pos-type ((d/nilf d/name) (:overlay-pos-type interaction)) + :penpot:overlay-position-x ((d/nilf get-in) interaction [:overlay-position :x]) + :penpot:overlay-position-y ((d/nilf get-in) interaction [:overlay-position :y]) + :penpot:url (:url interaction) + :penpot:close-click-outside ((d/nilf str) (:close-click-outside interaction)) + :penpot:background-overlay ((d/nilf str) (:background-overlay interaction))}])])) (mf/defc export-data [{:keys [shape]}] diff --git a/frontend/src/app/util/import/parser.cljs b/frontend/src/app/util/import/parser.cljs index 08d4a3037e..4210b012f1 100644 --- a/frontend/src/app/util/import/parser.cljs +++ b/frontend/src/app/util/import/parser.cljs @@ -477,7 +477,6 @@ :suffix (get-meta node :suffix) :scale (get-meta node :scale d/parse-double)}) - (defn parse-grid-node [node] (let [attrs (-> node :attrs remove-penpot-prefix) color {:color (:color attrs) @@ -494,8 +493,18 @@ :params params})) (defn parse-grids [node] - (let [grid-node (get-data node :penpot:grids)] - (->> grid-node :content (mapv parse-grid-node)))) + (let [grids-node (get-data node :penpot:grids)] + (->> grids-node :content (mapv parse-grid-node)))) + +(defn parse-flow-node [node] + (let [attrs (-> node :attrs remove-penpot-prefix)] + {:id (uuid/next) + :name (-> attrs :name) + :starting-frame (-> attrs :starting-frame uuid)})) + +(defn parse-flows [node] + (let [flows-node (get-data node :penpot:flows)] + (->> flows-node :content (mapv parse-flow-node)))) (defn extract-from-data ([node tag] @@ -725,24 +734,35 @@ (defn parse-page-data [node] - (let [style (parse-style (get-in node [:attrs :style])) + (let [style (parse-style (get-in node [:attrs :style])) background (:background style) - grids (->> (parse-grids node) - (group-by :type) - (d/mapm (fn [_ v] (-> v first :params))))] + grids (->> (parse-grids node) + (group-by :type) + (d/mapm (fn [_ v] (-> v first :params)))) + flows (parse-flows node)] (cond-> {} (some? background) (assoc-in [:options :background] background) (d/not-empty? grids) - (assoc-in [:options :saved-grids] grids)))) + (assoc-in [:options :saved-grids] grids) + + (d/not-empty? flows) + (assoc-in [:options :flows] flows)))) (defn parse-interactions [node] (let [interactions-node (get-data node :penpot:interactions)] (->> (find-all-nodes interactions-node :penpot:interaction) (mapv (fn [node] - {:destination (get-meta node :destination uuid/uuid) - :action-type (get-meta node :action-type keyword) - :event-type (get-meta node :event-type keyword)}))))) + {:event-type (get-meta node :event-type keyword) + :action-type (get-meta node :action-type keyword) + :delay (get-meta node :delay d/parse-double) + :destination (get-meta node :destination uuid/uuid) + :overlay-pos-type (get-meta node :overlay-pos-type keyword) + :overlay-position-x (get-meta node :overlay-position-x d/parse-double) + :overlay-position-y (get-meta node :overlay-position-x d/parse-double) + :url (get-meta node :url str) + :close-click-outside (get-meta node :close-click-outside str->bool) + :background-overlay (get-meta node :background-overlay str->bool)}))))) diff --git a/frontend/src/app/worker/import.cljs b/frontend/src/app/worker/import.cljs index 29d3f37e66..b6ec843d69 100644 --- a/frontend/src/app/worker/import.cljs +++ b/frontend/src/app/worker/import.cljs @@ -315,7 +315,10 @@ page-data (-> (cip/parse-page-data content) (assoc :name page-name) (assoc :id (resolve page-id))) - file (-> file (fb/add-page page-data))] + flows (->> (get-in page-data [:options :flows]) + (mapv #(update % :starting-frame resolve))) + page-data (d/assoc-in-when page-data [:options :flows] flows) + file (-> file (fb/add-page page-data))] (->> (rx/from nodes) (rx/filter cip/shape?) (rx/mapcat (partial resolve-media context file-id))