mirror of
https://github.com/penpot/penpot.git
synced 2025-03-14 08:41:48 -05:00
🎉 Enable auto-flows
This commit is contained in:
parent
925058467f
commit
38952b6734
6 changed files with 122 additions and 42 deletions
|
@ -9,6 +9,7 @@
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
|
[app.common.types.interactions :as cti]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[cuerdas.core :as str]))
|
[cuerdas.core :as str]))
|
||||||
|
|
||||||
|
@ -476,3 +477,10 @@
|
||||||
(let [path-split (split-path path)]
|
(let [path-split (split-path path)]
|
||||||
(merge-path-item (first path-split) name)))
|
(merge-path-item (first path-split) name)))
|
||||||
|
|
||||||
|
(defn connected-frame?
|
||||||
|
"Check if some frame is origin or destination of any navigate interaction
|
||||||
|
in the page"
|
||||||
|
[frame-id objects]
|
||||||
|
(let [children (get-object-with-children frame-id objects)]
|
||||||
|
(or (some cti/flow-origin? (map :interactions children))
|
||||||
|
(some #(cti/flow-to? % frame-id) (map :interactions (vals objects))))))
|
||||||
|
|
|
@ -326,7 +326,35 @@
|
||||||
|
|
||||||
;; -- Helpers for interactions
|
;; -- Helpers for interactions
|
||||||
|
|
||||||
|
(defn add-interaction
|
||||||
|
[interactions interaction]
|
||||||
|
(conj (or interactions []) interaction))
|
||||||
|
|
||||||
|
(defn remove-interaction
|
||||||
|
[interactions index]
|
||||||
|
(let [interactions (or interactions [])]
|
||||||
|
(into (subvec interactions 0 index)
|
||||||
|
(subvec interactions (inc index)))))
|
||||||
|
|
||||||
|
(defn update-interaction
|
||||||
|
[interactions index update-fn]
|
||||||
|
(update interactions index update-fn))
|
||||||
|
|
||||||
(defn actionable?
|
(defn actionable?
|
||||||
|
"Check if there is any interaction that is clickable by the user"
|
||||||
[interactions]
|
[interactions]
|
||||||
(some #(= (:event-type %) :click) interactions))
|
(some #(= (:event-type %) :click) interactions))
|
||||||
|
|
||||||
|
(defn flow-origin?
|
||||||
|
"Check if there is any interaction of type :navigate that goes outside"
|
||||||
|
[interactions]
|
||||||
|
(some #(and (= (:action-type %) :navigate)
|
||||||
|
(some? (:destination %)))
|
||||||
|
interactions))
|
||||||
|
|
||||||
|
(defn flow-to?
|
||||||
|
"Check if there is any interaction of type :navigate that goes to the given frame"
|
||||||
|
[interactions frame-id]
|
||||||
|
(some #(and (= (:action-type %) :navigate)
|
||||||
|
(= (:destination %) frame-id))
|
||||||
|
interactions))
|
||||||
|
|
|
@ -77,11 +77,11 @@
|
||||||
|
|
||||||
(defn add-flow
|
(defn add-flow
|
||||||
[flows flow]
|
[flows flow]
|
||||||
(conj flows flow))
|
(conj (or flows []) flow))
|
||||||
|
|
||||||
(defn remove-flow
|
(defn remove-flow
|
||||||
[flows flow-id]
|
[flows flow-id]
|
||||||
(vec (remove #(= (:id %) flow-id) flows)))
|
(d/removev #(= (:id %) flow-id) flows))
|
||||||
|
|
||||||
(defn update-flow
|
(defn update-flow
|
||||||
[flows flow-id update-fn]
|
[flows flow-id update-fn]
|
||||||
|
|
|
@ -22,9 +22,9 @@
|
||||||
|
|
||||||
;; --- Flows
|
;; --- Flows
|
||||||
|
|
||||||
(defn add-flow-selected-frame
|
(defn add-flow
|
||||||
[]
|
[starting-frame]
|
||||||
(ptk/reify ::add-flow-selected-frame
|
(ptk/reify ::add-flow
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [it state _]
|
(watch [it state _]
|
||||||
(let [page-id (:current-page-id state)
|
(let [page-id (:current-page-id state)
|
||||||
|
@ -34,14 +34,12 @@
|
||||||
:options
|
:options
|
||||||
:flows] [])
|
:flows] [])
|
||||||
|
|
||||||
selected (wsh/lookup-selected state)
|
|
||||||
|
|
||||||
unames (into #{} (map :name flows))
|
unames (into #{} (map :name flows))
|
||||||
name (dwc/generate-unique-name unames "Flow-1")
|
name (dwc/generate-unique-name unames "Flow-1")
|
||||||
|
|
||||||
new-flow {:id (uuid/next)
|
new-flow {:id (uuid/next)
|
||||||
:name name
|
:name name
|
||||||
:starting-frame (first selected)}]
|
:starting-frame starting-frame}]
|
||||||
|
|
||||||
(rx/of (dch/commit-changes
|
(rx/of (dch/commit-changes
|
||||||
{:redo-changes [{:type :set-option
|
{:redo-changes [{:type :set-option
|
||||||
|
@ -54,6 +52,14 @@
|
||||||
:value flows}]
|
:value flows}]
|
||||||
:origin it}))))))
|
:origin it}))))))
|
||||||
|
|
||||||
|
(defn add-flow-selected-frame
|
||||||
|
[]
|
||||||
|
(ptk/reify ::add-flow-selected-frame
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
(let [selected (wsh/lookup-selected state)]
|
||||||
|
(rx/of (add-flow (first selected)))))))
|
||||||
|
|
||||||
(defn remove-flow
|
(defn remove-flow
|
||||||
[flow-id]
|
[flow-id]
|
||||||
(us/verify ::us/uuid flow-id)
|
(us/verify ::us/uuid flow-id)
|
||||||
|
@ -120,6 +126,53 @@
|
||||||
|
|
||||||
;; --- Interactions
|
;; --- Interactions
|
||||||
|
|
||||||
|
(defn add-new-interaction
|
||||||
|
([shape] (add-new-interaction shape nil))
|
||||||
|
([shape destination]
|
||||||
|
(ptk/reify ::add-new-interaction
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
(let [page-id (:current-page-id state)
|
||||||
|
objects (wsh/lookup-page-objects state page-id)
|
||||||
|
frame (cph/get-frame shape objects)
|
||||||
|
flows (get-in state [:workspace-data
|
||||||
|
:pages-index
|
||||||
|
page-id
|
||||||
|
:options
|
||||||
|
:flows] [])
|
||||||
|
flow (cto/get-frame-flow flows (:id frame))]
|
||||||
|
(rx/concat
|
||||||
|
(rx/of (dch/update-shapes [(:id shape)]
|
||||||
|
(fn [shape]
|
||||||
|
(let [new-interaction (cti/set-destination
|
||||||
|
cti/default-interaction
|
||||||
|
destination)]
|
||||||
|
(update shape :interactions
|
||||||
|
cti/add-interaction new-interaction)))))
|
||||||
|
(when (and (not (cph/connected-frame? (:id frame) objects))
|
||||||
|
(nil? flow))
|
||||||
|
(rx/of (add-flow (:id frame))))))))))
|
||||||
|
|
||||||
|
(defn remove-interaction
|
||||||
|
[shape index]
|
||||||
|
(ptk/reify ::remove-interaction
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ _ _]
|
||||||
|
(rx/of (dch/update-shapes [(:id shape)]
|
||||||
|
(fn [shape]
|
||||||
|
(update shape :interactions
|
||||||
|
cti/remove-interaction index)))))))
|
||||||
|
|
||||||
|
(defn update-interaction
|
||||||
|
[shape index update-fn]
|
||||||
|
(ptk/reify ::update-interaction
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ _ _]
|
||||||
|
(rx/of (dch/update-shapes [(:id shape)]
|
||||||
|
(fn [shape]
|
||||||
|
(update shape :interactions
|
||||||
|
cti/update-interaction index update-fn)))))))
|
||||||
|
|
||||||
(declare move-edit-interaction)
|
(declare move-edit-interaction)
|
||||||
(declare finish-edit-interaction)
|
(declare finish-edit-interaction)
|
||||||
|
|
||||||
|
@ -179,28 +232,23 @@
|
||||||
shape (get objects shape-id)]
|
shape (get objects shape-id)]
|
||||||
|
|
||||||
(when (and shape (not (= position initial-pos)))
|
(when (and shape (not (= position initial-pos)))
|
||||||
(rx/of (dch/update-shapes [shape-id]
|
(if (nil? frame)
|
||||||
(fn [shape]
|
(when index
|
||||||
(update shape :interactions
|
(rx/of (remove-interaction shape index)))
|
||||||
(fn [interactions]
|
(let [frame (if (or (= (:id frame) (:id shape))
|
||||||
(if-not frame
|
(= (:id frame) (:frame-id shape)))
|
||||||
;; Drop in an empty space -> remove interaction
|
nil ;; Drop onto self frame -> set destination to none
|
||||||
(if index
|
frame)]
|
||||||
(into (subvec interactions 0 index)
|
(if (nil? index)
|
||||||
(subvec interactions (inc index)))
|
(rx/of (add-new-interaction shape (:id frame)))
|
||||||
interactions)
|
(rx/of (update-interaction shape index
|
||||||
(let [frame (if (or (= (:id frame) (:id shape))
|
(fn [interaction]
|
||||||
(= (:id frame) (:frame-id shape)))
|
(cond-> interaction
|
||||||
nil ;; Drop onto self frame -> set destination to none
|
(not (cti/has-destination interaction))
|
||||||
frame)]
|
(cti/set-action-type :navigate)
|
||||||
;; Update or create interaction
|
|
||||||
(if (and index (cti/has-destination (get interactions index)))
|
|
||||||
(update interactions index
|
|
||||||
#(cti/set-destination % (:id frame)))
|
|
||||||
(conj (or interactions [])
|
|
||||||
(cti/set-destination cti/default-interaction
|
|
||||||
(:id frame))))))))))))))))
|
|
||||||
|
|
||||||
|
:always
|
||||||
|
(cti/set-destination (:id frame))))))))))))))
|
||||||
;; --- Overlays
|
;; --- Overlays
|
||||||
|
|
||||||
(declare move-overlay-pos)
|
(declare move-overlay-pos)
|
||||||
|
|
|
@ -360,22 +360,16 @@
|
||||||
flows (:flows options)
|
flows (:flows options)
|
||||||
|
|
||||||
add-interaction
|
add-interaction
|
||||||
(fn [_]
|
(fn []
|
||||||
(let [new-interactions (conj interactions cti/default-interaction)]
|
(st/emit! (dwi/add-new-interaction shape)))
|
||||||
(st/emit! (dw/update-shape (:id shape) {:interactions new-interactions}))))
|
|
||||||
|
|
||||||
remove-interaction
|
remove-interaction
|
||||||
(fn [index]
|
(fn [index]
|
||||||
(let [new-interactions
|
(st/emit! (dwi/remove-interaction shape index)))
|
||||||
(into (subvec interactions 0 index)
|
|
||||||
(subvec interactions (inc index)))]
|
|
||||||
(st/emit! (dw/update-shape (:id shape) {:interactions new-interactions}))))
|
|
||||||
|
|
||||||
update-interaction
|
update-interaction
|
||||||
(fn [index update-fn]
|
(fn [index update-fn]
|
||||||
(let [new-interactions (update interactions index update-fn)]
|
(st/emit! (dwi/update-interaction shape index update-fn)))]
|
||||||
(st/emit! (dw/update-shape (:id shape) {:interactions new-interactions})))) ]
|
|
||||||
|
|
||||||
[:*
|
[:*
|
||||||
(if shape
|
(if shape
|
||||||
[:& shape-flows {:flows flows
|
[:& shape-flows {:flows flows
|
||||||
|
@ -383,7 +377,7 @@
|
||||||
[:& page-flows {:flows flows}])
|
[:& page-flows {:flows flows}])
|
||||||
|
|
||||||
[:div.element-set.interactions-options
|
[:div.element-set.interactions-options
|
||||||
(when shape
|
(when (and shape (not= (:frame-id shape) uuid/zero))
|
||||||
[:div.element-set-title
|
[:div.element-set-title
|
||||||
[:span (tr "workspace.options.interactions")]
|
[:span (tr "workspace.options.interactions")]
|
||||||
[:div.add-page {:on-click add-interaction}
|
[:div.add-page {:on-click add-interaction}
|
||||||
|
@ -391,7 +385,7 @@
|
||||||
[:div.element-set-content
|
[:div.element-set-content
|
||||||
(when (= (count interactions) 0)
|
(when (= (count interactions) 0)
|
||||||
[:*
|
[:*
|
||||||
(when shape
|
(when (and shape (not= (:frame-id shape) uuid/zero))
|
||||||
[:*
|
[:*
|
||||||
[:div.interactions-help-icon i/plus]
|
[:div.interactions-help-icon i/plus]
|
||||||
[:div.interactions-help.separator (tr "workspace.options.add-interaction")]])
|
[:div.interactions-help.separator (tr "workspace.options.add-interaction")]])
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.pages.helpers :as cph]
|
[app.common.pages.helpers :as cph]
|
||||||
[app.common.types.interactions :as cti]
|
[app.common.types.interactions :as cti]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
@ -319,7 +320,8 @@
|
||||||
:position (:overlay-position interaction)
|
:position (:overlay-position interaction)
|
||||||
:objects objects
|
:objects objects
|
||||||
:hover-disabled? hover-disabled?}]))])))
|
:hover-disabled? hover-disabled?}]))])))
|
||||||
(when (not (#{:move :rotate} current-transform))
|
(when (and (not= (:frame-id shape) uuid/zero)
|
||||||
|
(not (#{:move :rotate} current-transform)))
|
||||||
[:& interaction-handle {:key (:id shape)
|
[:& interaction-handle {:key (:id shape)
|
||||||
:index nil
|
:index nil
|
||||||
:shape shape
|
:shape shape
|
||||||
|
|
Loading…
Add table
Reference in a new issue