0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-12 15:51:37 -05:00

Process interactions on import

This commit is contained in:
alonso.torres 2021-06-17 16:24:39 +02:00
parent 4e909dc369
commit 4d0dcc5876
4 changed files with 192 additions and 95 deletions

View file

@ -291,6 +291,31 @@
(-> file
(update :parent-stack pop)))
(defn add-interaction
[file action-type event-type from-id destination-id]
(assert (some? (lookup-shape file from-id)) (str "Cannot locate shape with id " from-id))
(assert (some? (lookup-shape file destination-id)) (str "Cannot locate shape with id " destination-id))
(let [interactions (->> (lookup-shape file from-id)
:interactions
(filterv #(or (not= (:action-type %) action-type)
(not= (:event-type %) event-type))))
conj (fnil conj [])
interactions (-> interactions
(conj
{:action-type action-type
:event-type event-type
:destination destination-id}))]
(commit-change
file
{:type :mod-obj
:page-id (:current-page-id file)
:id from-id
:operations
[{:type :set :attr :interactions :val interactions}]})))
(defn generate-changes
[file]
(:changes file))

View file

@ -91,20 +91,22 @@
[(str "penpot:" (d/name k)) v])]
(into {} (map prefix-entry) m)))
(mf/defc export-grid-data
[{:keys [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))))]))])
(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))))]))]))
(mf/defc export-page
[{:keys [options]}]
@ -117,62 +119,85 @@
[:> "penpot:page" #js {}
[:& export-grid-data {:grids grids}]]))))
(mf/defc export-shadow-data
[{:keys [shadow]}]
(for [{:keys [style hidden color offset-x offset-y blur spread]} shadow]
[:> "penpot:shadow"
#js {:penpot:shadow-type (d/name style)
:penpot:hidden (str hidden)
:penpot:color (str (:color color))
:penpot:opacity (str (:opacity color))
:penpot:offset-x (str offset-x)
:penpot:offset-y (str offset-y)
:penpot:blur (str blur)
:penpot:spread (str spread)}]))
(mf/defc export-blur-data [{:keys [blur]}]
(when (some? blur)
(let [{:keys [type hidden value]} blur]
[:> "penpot:blur"
#js {:penpot:blur-type (d/name type)
:penpot:hidden (str hidden)
:penpot:value (str value)}])))
(mf/defc export-exports-data [{:keys [exports]}]
(for [{:keys [scale suffix type]} exports]
[:> "penpot:export"
#js {:penpot:type (d/name type)
:penpot:suffix suffix
:penpot:scale (str scale)}]))
(mf/defc export-svg-data [shape]
[:*
(when (contains? shape :svg-attrs)
(let [svg-transform (get shape :svg-transform)
svg-attrs (->> shape :svg-attrs keys (mapv d/name) (str/join ",") )
svg-defs (->> shape :svg-defs keys (mapv d/name) (str/join ","))]
[:> "penpot:svg-import"
#js {:penpot:svg-attrs (when-not (empty? svg-attrs) svg-attrs)
:penpot:svg-defs (when-not (empty? svg-defs) svg-defs)
:penpot:svg-transform (when svg-transform (str svg-transform))
:penpot:svg-viewbox-x (get-in shape [:svg-viewbox :x])
:penpot:svg-viewbox-y (get-in shape [:svg-viewbox :y])
:penpot:svg-viewbox-width (get-in shape [:svg-viewbox :width])
:penpot:svg-viewbox-height (get-in shape [:svg-viewbox :height])}
(for [[def-id def-xml] (:svg-defs shape)]
[:> "penpot:svg-def" #js {:def-id def-id}
[:& render-xml {:xml def-xml}]])]))
(when (= (:type shape) :svg-raw)
(let [props
(-> (obj/new)
(obj/set! "penpot:x" (:x shape))
(obj/set! "penpot:y" (:y shape))
(obj/set! "penpot:width" (:width shape))
(obj/set! "penpot:height" (:height shape))
(obj/set! "penpot:tag" (-> (get-in shape [:content :tag]) d/name))
(obj/merge! (-> (get-in shape [:content :attrs])
(clj->js))))]
[:> "penpot:svg-content" props
(for [leaf (->> shape :content :content (filter string?))]
[:> "penpot:svg-child" {} leaf])]))])
(mf/defc export-interactions-data
[{:keys [interactions]}]
(when-not (empty? interactions)
[:> "penpot:interactions" #js {}
(for [{:keys [action-type destination event-type]} interactions]
[:> "penpot:interaction"
#js {:penpot:action-type (d/name action-type)
:penpot:destination (str destination)
:penpot:event-type (d/name event-type)}])]))
(mf/defc export-data
[{:keys [shape]}]
(let [props (-> (obj/new)
(add-data shape))]
(let [props (-> (obj/new) (add-data shape))
frame? (= (:type shape) :frame)]
[:> "penpot:shape" props
(for [{:keys [style hidden color offset-x offset-y blur spread]} (:shadow shape)]
[:> "penpot:shadow" #js {:penpot:shadow-type (d/name style)
:penpot:hidden (str hidden)
:penpot:color (str (:color color))
:penpot:opacity (str (:opacity color))
:penpot:offset-x (str offset-x)
:penpot:offset-y (str offset-y)
:penpot:blur (str blur)
:penpot:spread (str spread)}])
(when (some? (:blur shape))
(let [{:keys [type hidden value]} (:blur shape)]
[:> "penpot:blur" #js {:penpot:blur-type (d/name type)
:penpot:hidden (str hidden)
:penpot:value (str value)}]))
(for [{:keys [scale suffix type]} (:exports shape)]
[:> "penpot:export" #js {:penpot:type (d/name type)
:penpot:suffix suffix
:penpot:scale (str scale)}])
(when (contains? shape :svg-attrs)
(let [svg-transform (get shape :svg-transform)
svg-attrs (->> shape :svg-attrs keys (mapv d/name) (str/join ",") )
svg-defs (->> shape :svg-defs keys (mapv d/name) (str/join ","))]
[:> "penpot:svg-import" #js {:penpot:svg-attrs (when-not (empty? svg-attrs) svg-attrs)
:penpot:svg-defs (when-not (empty? svg-defs) svg-defs)
:penpot:svg-transform (when svg-transform (str svg-transform))
:penpot:svg-viewbox-x (get-in shape [:svg-viewbox :x])
:penpot:svg-viewbox-y (get-in shape [:svg-viewbox :y])
:penpot:svg-viewbox-width (get-in shape [:svg-viewbox :width])
:penpot:svg-viewbox-height (get-in shape [:svg-viewbox :height])}
(for [[def-id def-xml] (:svg-defs shape)]
[:> "penpot:svg-def" #js {:def-id def-id}
[:& render-xml {:xml def-xml}]])]))
(when (= (:type shape) :svg-raw)
(let [props (-> (obj/new)
(obj/set! "penpot:x" (:x shape))
(obj/set! "penpot:y" (:y shape))
(obj/set! "penpot:width" (:width shape))
(obj/set! "penpot:height" (:height shape))
(obj/set! "penpot:tag" (-> (get-in shape [:content :tag]) d/name))
(obj/merge! (-> (get-in shape [:content :attrs])
(clj->js))))]
[:> "penpot:svg-content" props
(for [leaf (->> shape :content :content (filter string?))]
[:> "penpot:svg-child" {} leaf])]))
(when (and (= (:type shape) :frame)
(seq (:grids shape)))
[:& export-grid-data {:grids (:grids shape)}])]))
[:& export-shadow-data shape]
[:& export-blur-data shape]
[:& export-exports-data shape]
[:& export-svg-data shape]
[:& export-interactions-data shape]
[:& export-grid-data shape]]))

View file

@ -15,6 +15,12 @@
[app.util.path.parser :as upp]
[cuerdas.core :as str]))
(def url-regex
#"url\(#([^\)]*)\)")
(def uuid-regex
#"\w{8}-\w{4}-\w{4}-\w{4}-\w{12}")
(defn valid?
[root]
(contains? (:attrs root) :xmlns:penpot))
@ -41,7 +47,7 @@
(defn find-all-nodes
[node tag]
(when (some? node)
(->> node :content (filterv #(= (:tag %) :defs)))))
(->> node :content (filterv #(= (:tag %) tag)))))
(defn get-data
([node]
@ -65,6 +71,11 @@
(or (close? node)
(some? (get-data node))))
(defn get-id
[node]
(when-let [id (re-find uuid-regex (get-in node [:attrs :id]))]
(uuid/uuid id)))
(defn str->bool
[val]
(when (some? val) (= val "true")))
@ -193,9 +204,6 @@
(assoc :content content)
(assoc :center center))))
(def url-regex #"url\(#([^\)]*)\)")
(defn parse-stops
[gradient-node]
(->> gradient-node
@ -483,7 +491,7 @@
(defn remove-prefix [s]
(cond-> s
(string? s)
(str/replace #"\w{8}-\w{4}-\w{4}-\w{4}-\w{12}-" "")))
(str/replace (re-pattern (str uuid-regex "-")) "")))
(defn get-svg-attrs
[svg-data svg-attrs]
@ -640,3 +648,12 @@
(not (empty? grids))
(assoc-in [:options :saved-grids] grids))))
(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)})))))

View file

@ -78,36 +78,65 @@
(defn add-shape-file
[file node]
(let [type (cip/get-type node)
close? (cip/close? node)
data (cip/parse-data type node)]
(let [type (cip/get-type node)
close? (cip/close? node)]
(if close?
(case type
:frame
(fb/close-artboard file)
:frame (fb/close-artboard file)
:group (fb/close-group file)
:svg-raw (fb/close-svg-raw file)
#_default file)
:group
(fb/close-group file)
(let [data (cip/parse-data type node)
old-id (cip/get-id node)
interactions (cip/parse-interactions node)
:svg-raw
(fb/close-svg-raw file)
file (case type
:frame (fb/add-artboard file data)
:group (fb/add-group file data)
:rect (fb/create-rect file data)
:circle (fb/create-circle file data)
:path (fb/create-path file data)
:text (fb/create-text file data)
:image (fb/create-image file data)
:svg-raw (fb/create-svg-raw file data)
#_default file)]
;; default
file)
(assert (some? old-id) "ID not found")
(case type
:frame (fb/add-artboard file data)
:group (fb/add-group file data)
:rect (fb/create-rect file data)
:circle (fb/create-circle file data)
:path (fb/create-path file data)
:text (fb/create-text file data)
:image (fb/create-image file data)
:svg-raw (fb/create-svg-raw file data)
;; We store this data for post-processing after every shape has been
;; added
(cond-> file
(some? (:last-id file))
(assoc-in [:id-mapping old-id] (:last-id file))
;; default
file))))
(not (empty? interactions))
(assoc-in [:interactions old-id] interactions))))))
(defn post-process-file
[file]
(letfn [(add-interaction
[id file {:keys [action-type event-type destination] :as interaction}]
(fb/add-interaction file action-type event-type id destination))
(add-interactions
[file [old-id interactions]]
(let [id (get-in file [:id-mapping old-id])]
(->> interactions
(mapv (fn [interaction]
(let [id (get-in file [:id-mapping (:destination interaction)])]
(assoc interaction :destination id))))
(reduce
(partial add-interaction id) file))))
(process-interactions
[file]
(reduce add-interactions file (:interactions file)))]
(-> file
(process-interactions)
(dissoc :id-mapping :interactions))))
(defn merge-reduce [f seed ob]
(->> (rx/concat
@ -145,6 +174,7 @@
(rx/filter cip/shape?)
(rx/mapcat (partial resolve-images file-id))
(rx/reduce add-shape-file (fb/add-page file page-data))
(rx/map post-process-file)
(rx/map fb/close-page)))
(rx/empty)))