diff --git a/common/src/app/common/pages/spec.cljc b/common/src/app/common/pages/spec.cljc index aec112016..da4f79ae3 100644 --- a/common/src/app/common/pages/spec.cljc +++ b/common/src/app/common/pages/spec.cljc @@ -185,9 +185,9 @@ ;; Interactions -(s/def :internal.shape.interaction/event-type #{:click}) ; In the future we will have more options -(s/def :internal.shape.interaction/action-type #{:navigate}) -(s/def :internal.shape.interaction/destination ::uuid) +(s/def :internal.shape.interaction/event-type #{:click :hover}) +(s/def :internal.shape.interaction/action-type #{:navigate :open-overlay :close-overlay}) +(s/def :internal.shape.interaction/destination (s/nilable ::uuid)) (s/def :internal.shape/interaction (s/keys :req-un [:internal.shape.interaction/event-type @@ -197,6 +197,11 @@ (s/def :internal.shape/interactions (s/coll-of :internal.shape/interaction :kind vector?)) +(def default-interaction + {:event-type :click + :action-type :navigate + :destination nil}) + ;; Size constraints (s/def :internal.shape/constraints-h #{:left :right :leftright :center :scale}) diff --git a/frontend/resources/styles/main/partials/sidebar-element-options.scss b/frontend/resources/styles/main/partials/sidebar-element-options.scss index 0380d9303..f1845e3d9 100644 --- a/frontend/resources/styles/main/partials/sidebar-element-options.scss +++ b/frontend/resources/styles/main/partials/sidebar-element-options.scss @@ -226,6 +226,10 @@ color: $color-gray-20; font-size: $fs11; width: 64px; + + &.wide { + width: 110px; + } } .lock-size { diff --git a/frontend/resources/styles/main/partials/sidebar-interactions.scss b/frontend/resources/styles/main/partials/sidebar-interactions.scss index bd086d303..c8ea87266 100644 --- a/frontend/resources/styles/main/partials/sidebar-interactions.scss +++ b/frontend/resources/styles/main/partials/sidebar-interactions.scss @@ -22,3 +22,28 @@ width: 32px; } } + +.interactions-summary { + width: 100%; + + .trigger-name { + font-size: $fs12; + color: $color-white; + } + + .action-summary { + font-size: $fs11; + color: $color-gray-20; + } +} + +.interactions-element { + display: flex; + align-items: center; + + .element-label { + color: $color-gray-20; + font-size: $fs11; + width: 64px; + } +} diff --git a/frontend/src/app/main/data/viewer.cljs b/frontend/src/app/main/data/viewer.cljs index c30ed5bf2..e438a54f5 100644 --- a/frontend/src/app/main/data/viewer.cljs +++ b/frontend/src/app/main/data/viewer.cljs @@ -31,6 +31,7 @@ :comments-show :unresolved :selected #{} :collapsed #{} + :overlays [] :hover nil}) (declare fetch-comment-threads) @@ -286,7 +287,7 @@ (update [_ state] (assoc-in state [:viewer-local :interactions-show?] false)))) -;; --- Navigation +;; --- Navigation inside page (defn go-to-frame-by-index [index] @@ -324,6 +325,35 @@ qparams (:query-params route)] (rx/of (rt/nav :viewer pparams (assoc qparams :section section))))))) +;; --- Overlays + +(defn open-overlay + [frame-id] + (us/verify ::us/uuid frame-id) + (ptk/reify ::open-overlay + ptk/UpdateEvent + (update [_ state] + (let [route (:route state) + qparams (:query-params route) + page-id (:page-id qparams) + frames (get-in state [:viewer :pages page-id :frames]) + frame (d/seek #(= (:id %) frame-id) frames) + overlays (get-in state [:viewer-local :overlays])] + (if-not (some #(= % frame) overlays) + (update-in state [:viewer-local :overlays] conj frame) + state))))) + +(defn close-overlay + [frame-id] + (ptk/reify ::close-overlay + ptk/UpdateEvent + (update [_ state] + (update-in state [:viewer-local :overlays] + (fn [overlays] + (remove #(= (:id %) frame-id) overlays)))))) + +;; --- Objects selection + (defn deselect-all [] (ptk/reify ::deselect-all ptk/UpdateEvent @@ -397,7 +427,7 @@ (update [_ state] (assoc-in state [:viewer-local :hover] (when hover? id))))) -;; --- NAV +;; --- Navigation outside page (defn go-to-dashboard [] diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 3411db165..362a461f3 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1751,12 +1751,16 @@ ;; Interactions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(declare move-create-interaction) -(declare finish-create-interaction) +(declare move-edit-interaction) +(declare finish-edit-interaction) + +(defn start-edit-interaction + [index] + (ptk/reify ::start-edit-interaction + ptk/UpdateEvent + (update [_ state] + (assoc-in state [:workspace-local :editing-interaction-index] index)) -(defn start-create-interaction - [] - (ptk/reify ::start-create-interaction ptk/WatchEvent (watch [_ state stream] (let [initial-pos @ms/mouse-position @@ -1766,12 +1770,12 @@ (rx/concat (->> ms/mouse-position (rx/take-until stopper) - (rx/map #(move-create-interaction initial-pos %))) - (rx/of (finish-create-interaction initial-pos)))))))) + (rx/map #(move-edit-interaction initial-pos %))) + (rx/of (finish-edit-interaction index initial-pos)))))))) -(defn move-create-interaction +(defn move-edit-interaction [initial-pos position] - (ptk/reify ::move-create-interaction + (ptk/reify ::move-edit-interaction ptk/UpdateEvent (update [_ state] (let [page-id (:current-page-id state) @@ -1785,12 +1789,13 @@ (not= position initial-pos) (assoc-in [:workspace-local :draw-interaction-to] position) (not= start-frame end-frame) (assoc-in [:workspace-local :draw-interaction-to-frame] end-frame)))))) -(defn finish-create-interaction - [initial-pos] - (ptk/reify ::finish-create-interaction +(defn finish-edit-interaction + [index initial-pos] + (ptk/reify ::finish-edit-interaction ptk/UpdateEvent (update [_ state] (-> state + (assoc-in [:workspace-local :editing-interaction-index] nil) (assoc-in [:workspace-local :draw-interaction-to] nil) (assoc-in [:workspace-local :draw-interaction-to-frame] nil))) @@ -1804,16 +1809,27 @@ shape-id (-> state wsh/lookup-selected first) shape (get objects shape-id)] - (when-not (= position initial-pos) - (if (and frame shape-id - (not= (:id frame) (:id shape)) - (not= (:id frame) (:frame-id shape))) - (rx/of (update-shape shape-id - {:interactions [{:event-type :click - :action-type :navigate - :destination (:id frame)}]})) - (rx/of (update-shape shape-id - {:interactions []})))))))) + (when (and shape (not (= position initial-pos))) + (rx/of (dch/update-shapes [shape-id] + (fn [shape] + (update shape :interactions + (fn [interactions] + (if-not frame + ;; Drop in an empty space -> remove interaction + (if index + (into (subvec interactions 0 index) + (subvec interactions (inc index))) + interactions) + (let [frame (if (or (= (:id frame) (:id shape)) + (= (:id frame) (:frame-id shape))) + nil ;; Drop onto self frame -> set destination to none + frame)] + ;; Update or create interaction + (if index + (assoc-in interactions [index :destination] (:id frame)) + (conj (or interactions []) + (assoc spec/default-interaction + :destination (:id frame)))))))))))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; CANVAS OPTIONS diff --git a/frontend/src/app/main/ui/viewer.cljs b/frontend/src/app/main/ui/viewer.cljs index c3b54d8bb..c98628bb4 100644 --- a/frontend/src/app/main/ui/viewer.cljs +++ b/frontend/src/app/main/ui/viewer.cljs @@ -13,6 +13,7 @@ [app.main.store :as st] [app.main.ui.hooks :as hooks] [app.main.ui.icons :as i] + [app.main.ui.shapes.filters :as filters] [app.main.ui.share-link] [app.main.ui.static :as static] [app.main.ui.viewer.comments :refer [comments-layer]] @@ -27,9 +28,15 @@ (defn- calculate-size [frame zoom] - {:width (* (:width frame) zoom) - :height (* (:height frame) zoom) - :vbox (str "0 0 " (:width frame 0) " " (:height frame 0))}) + (let [{:keys [_ _ width height]} (filters/get-filters-bounds frame)] + {:width (* width zoom) + :height (* height zoom) + :vbox (str "0 0 " width " " height)})) + +(defn- position-overlay + [size size-over] + {:x (/ (- (:width size) (:width size-over)) 2) + :y (/ (- (:height size) (:height size-over)) 2)}) (mf/defc viewer [{:keys [params data]}] @@ -137,7 +144,24 @@ :page page :file file :users users - :local local}]]))]]])) + :local local}] + + (for [overlay (:overlays local)] + (let [size-over (calculate-size overlay zoom) + pos-over (position-overlay size size-over)] + [:div.viewport-container + {:style {:width (:width size-over) + :height (:height size-over) + :position "absolute" + :left (:x pos-over) + :top (:y pos-over)}} + [:& interactions/viewport + {:frame overlay + :size size-over + :page page + :file file + :users users + :local local}]]))]))]]])) ;; --- Component: Viewer Page diff --git a/frontend/src/app/main/ui/viewer/shapes.cljs b/frontend/src/app/main/ui/viewer/shapes.cljs index 39d90d175..d4850808c 100644 --- a/frontend/src/app/main/ui/viewer/shapes.cljs +++ b/frontend/src/app/main/ui/viewer/shapes.cljs @@ -28,14 +28,27 @@ [rumext.alpha :as mf])) (defn on-mouse-down - [event interactions] - (let [interaction (first (filter #(= (:event-type %) :click) interactions))] + [event shape] + (doseq [interaction (->> (:interactions shape) + (filter #(= (:event-type %) :click)))] + (case (:action-type interaction) :navigate (let [frame-id (:destination interaction)] (dom/stop-propagation event) (st/emit! (dv/go-to-frame frame-id))) + :open-overlay + (let [frame-id (:destination interaction)] + (dom/stop-propagation event) + (st/emit! (dv/open-overlay frame-id))) + + :close-overlay + (let [frame-id (or (:destination interaction) + (:frame-id shape))] + (dom/stop-propagation event) + (st/emit! (dv/close-overlay frame-id))) + nil))) (mf/defc interaction @@ -61,17 +74,15 @@ {::mf/wrap-props false} [props] (let [shape (unchecked-get props "shape") - objects (unchecked-get props "objects") childs (unchecked-get props "childs") frame (unchecked-get props "frame") - interactions (->> (:interactions shape) - (filter #(contains? objects (:destination %)))) + interactions (:interactions shape) on-mouse-down (mf/use-callback - (mf/deps interactions) + (mf/deps shape) (fn [event] - (on-mouse-down event interactions))) + (on-mouse-down event shape))) svg-element? (and (= :svg-raw (:type shape)) (not= :svg (get-in shape [:content :tag])))] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs index 500b5e038..0f9b20400 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs @@ -8,70 +8,148 @@ (:require [app.common.data :as d] [app.common.pages :as cp] + [app.common.pages.spec :as spec] + [app.common.uuid :as uuid] [app.main.data.workspace :as dw] [app.main.refs :as refs] [app.main.store :as st] - [app.main.ui.components.dropdown :refer [dropdown]] [app.main.ui.icons :as i] + [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [rumext.alpha :as mf])) -(mf/defc interactions-menu - [{:keys [shape] :as props}] - (let [objects (deref refs/workspace-page-objects) - interaction (first (:interactions shape)) ; TODO: in the - ; future we may - ; have several - ; interactions in - ; one shape +(defn- event-type-names + [] + {:click (tr "workspace.options.interaction-on-click") + :hover (tr "workspace.options.interaction-while-hovering")}) +(defn- event-type-name + [interaction] + (get (event-type-names) (:event-type interaction) "--")) + +(defn- action-type-names + [] + {:navigate (tr "workspace.options.interaction-navigate-to") + :open-overlay (tr "workspace.options.interaction-open-overlay") + :close-overlay (tr "workspace.options.interaction-close-overlay")}) + +(defn- action-summary + [interaction destination] + (case (:action-type interaction) + :navigate (tr "workspace.options.interaction-navigate-to-dest" + (get destination :name (tr "workspace.options.interaction-none"))) + :open-overlay (tr "workspace.options.interaction-open-overlay-dest" + (get destination :name (tr "workspace.options.interaction-none"))) + :close-overlay (tr "workspace.options.interaction-close-overlay-dest" + (get destination :name (tr "workspace.options.interaction-self"))) + "--")) + +(mf/defc interaction-entry + [{:keys [index shape interaction update-interaction remove-interaction]}] + (let [objects (deref refs/workspace-page-objects) destination (get objects (:destination interaction)) frames (mf/use-memo (mf/deps objects) #(cp/select-frames objects)) - show-frames-dropdown? (mf/use-state false) + extended-open? (mf/use-state false) - on-set-blur #(reset! show-frames-dropdown? false) - on-navigate #(when destination - (st/emit! (dw/select-shapes (d/ordered-set (:id destination))))) + change-event-type + (fn [event] + (let [value (-> event dom/get-target dom/get-value d/read-string)] + (update-interaction index #(assoc % :event-type value)))) - on-select-destination - (fn [dest] - (if (nil? dest) - (st/emit! (dw/update-shape (:id shape) {:interactions []})) - (st/emit! (dw/update-shape (:id shape) {:interactions [{:event-type :click - :action-type :navigate - :destination dest}]}))))] + change-action-type + (fn [event] + (let [value (-> event dom/get-target dom/get-value d/read-string)] + (update-interaction index #(assoc % :action-type value)))) - (if (not shape) - [:* - [:div.interactions-help-icon i/interaction] - [:div.interactions-help (tr "workspace.options.select-a-shape")] - [:div.interactions-help-icon i/play] - [:div.interactions-help (tr "workspace.options.use-play-button")]] - - [:div.element-set {:on-blur on-set-blur} - [:div.element-set-title - [:span (tr "workspace.options.navigate-to")]] - [:div.element-set-content - [:div.row-flex - [:div.custom-select.flex-grow {:on-click #(reset! show-frames-dropdown? true)} - (if destination - [:span (:name destination)] - [:span (tr "workspace.options.select-artboard")]) - [:span.dropdown-button i/arrow-down] - [:& dropdown {:show @show-frames-dropdown? - :on-close #(reset! show-frames-dropdown? false)} - [:ul.custom-select-dropdown - [:li.dropdown-separator - {:on-click #(on-select-destination nil)} - (tr "workspace.options.none")] + change-destination + (fn [event] + (let [value (-> event dom/get-target dom/get-value) + value (when (not= value "") (uuid/uuid value))] + (update-interaction index #(assoc % :destination value))))] + [:* + [:div.element-set-options-group + [:div.element-set-actions-button {:on-click #(swap! extended-open? not)} + i/actions] + [:div.interactions-summary + [:div.trigger-name (event-type-name interaction)] + [:div.action-summary (action-summary interaction destination)]] + [:div.elemen-set-actions {:on-click #(remove-interaction index)} + [:div.element-set-actions-button i/minus]]] + (when @extended-open? + [:div.element-set + [:div.element-set-content + [:div.interactions-element + [:span.element-set-subtitle.wide (tr "workspace.options.interaction-trigger")] + [:select.input-select + {:default-value (str (:event-type interaction)) + :on-change change-event-type} + (for [[value name] (event-type-names)] + [:option {:value (str value)} name])]] + [:div.interactions-element + [:span.element-set-subtitle.wide (tr "workspace.options.interaction-action")] + [:select.input-select + {:default-value (str (:action-type interaction)) + :on-change change-action-type} + (for [[value name] (action-type-names)] + [:option {:value (str value)} name])]] + [:div.interactions-element + [:span.element-set-subtitle.wide (tr "workspace.options.interaction-destination")] + [:select.input-select + {:default-value (str (:destination interaction)) + :on-change change-destination} + [:option {:value ""} (tr "workspace.options.interaction-none")] (for [frame frames] (when (and (not= (:id frame) (:id shape)) ; A frame cannot navigate to itself (not= (:id frame) (:frame-id shape))) ; nor a shape to its container frame - [:li {:key (:id frame) - :on-click #(on-select-destination (:id frame))} - (:name frame)]))]]] - [:span.navigate-icon {:style {:visibility (when (not destination) "hidden")} - :on-click on-navigate} i/navigate]]]]))) + [:option {:value (str (:id frame))} (:name frame)]))]]]])])) + +(mf/defc interactions-menu + [{:keys [shape] :as props}] + (let [interactions (get shape :interactions []) + + add-interaction + (fn [_] + (let [new-interactions + (conj interactions (update spec/default-interaction :event-type identity))] + (st/emit! (dw/update-shape (:id shape) {:interactions new-interactions})))) + + remove-interaction + (fn [index] + (let [new-interactions + (into (subvec interactions 0 index) + (subvec interactions (inc index)))] + (st/emit! (dw/update-shape (:id shape) {:interactions new-interactions})))) + + update-interaction + (fn [index update-fn] + (let [new-interactions (update interactions index update-fn)] + (st/emit! (dw/update-shape (:id shape) {:interactions new-interactions})))) ] + + [:div.element-set + (when shape + [:div.element-set-title + [:span (tr "workspace.options.interactions")] + [:div.add-page {:on-click add-interaction} + i/plus]]) + + [:div.element-set-content + (when (= (count interactions) 0) + [:* + (when shape + [:* + [:div.interactions-help-icon i/plus] + [:div.interactions-help (tr "workspace.options.add-interaction")]]) + [:div.interactions-help-icon i/interaction] + [:div.interactions-help (tr "workspace.options.select-a-shape")] + [:div.interactions-help-icon i/play] + [:div.interactions-help (tr "workspace.options.use-play-button")]])] + (for [[index interaction] (d/enumerate interactions)] + [:& interaction-entry {:index index + :shape shape + :interaction interaction + :update-interaction update-interaction + :remove-interaction remove-interaction}])])) + diff --git a/frontend/src/app/main/ui/workspace/viewport/interactions.cljs b/frontend/src/app/main/ui/workspace/viewport/interactions.cljs index ca0d1b0e2..aaa267bd5 100644 --- a/frontend/src/app/main/ui/workspace/viewport/interactions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/interactions.cljs @@ -7,24 +7,20 @@ (ns app.main.ui.workspace.viewport.interactions "Visually show shape interactions in workspace" (:require + [app.common.data :as d] [app.main.data.workspace :as dw] [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.workspace.viewport.outline :refer [outline]] [app.util.dom :as dom] [cuerdas.core :as str] - [rumext.alpha :as mf] - )) - -(defn- get-click-interaction - [shape] - (first (filter #(= (:event-type %) :click) (:interactions shape)))) + [rumext.alpha :as mf])) (defn- on-mouse-down - [event {:keys [id] :as shape}] + [event index {:keys [id] :as shape}] (dom/stop-propagation event) (st/emit! (dw/select-shape id)) - (st/emit! (dw/start-create-interaction))) + (st/emit! (dw/start-edit-interaction index))) (defn connect-to-shape "Calculate the best position to draw an interaction line @@ -84,38 +80,56 @@ (mf/defc interaction-marker - [{:keys [x y arrow-dir zoom] :as props}] - (let [arrow-pdata (case arrow-dir - :right "M -5 0 l 8 0 l -4 -4 m 4 4 l -4 4" - :left "M 5 0 l -8 0 l 4 -4 m -4 4 l 4 4" - []) + [{:keys [x y stroke action-type arrow-dir zoom] :as props}] + (let [icon-pdata (case action-type + :navigate (case arrow-dir + :right "M -5 0 l 8 0 l -4 -4 m 4 4 l -4 4" + :left "M 5 0 l -8 0 l 4 -4 m -4 4 l 4 4" + nil) + :open-overlay (case arrow-dir + ;; TODO: have a different icon for open overlay? + :right "M -5 0 l 8 0 l -4 -4 m 4 4 l -4 4" + :left "M 5 0 l -8 0 l 4 -4 m -4 4 l 4 4" + nil) + + :close-overlay "M -4 -4 L 4 4 M -4 4 L 4 -4" + + nil) inv-zoom (/ 1 zoom)] [:* [:circle {:cx 0 :cy 0 :r 8 - :stroke "#31EFB8" + :stroke stroke :stroke-width 2 :fill "#FFFFFF" :transform (str "scale(" inv-zoom ", " inv-zoom ") " "translate(" (* zoom x) ", " (* zoom y) ")")}] - (when arrow-dir - [:path {:stroke "#31EFB8" + (when icon-pdata + [:path {:stroke stroke :fill "none" :stroke-width 2 - :d arrow-pdata + :d icon-pdata :transform (str "scale(" inv-zoom ", " inv-zoom ") " "translate(" (* zoom x) ", " (* zoom y) ")")}])])) (mf/defc interaction-path - [{:keys [orig-shape dest-shape dest-point selected? zoom] :as props}] + [{:keys [index orig-shape dest-shape dest-point selected? action-type zoom] :as props}] (let [[orig-pos orig-x orig-y dest-pos dest-x dest-y] - (if dest-shape + (cond + dest-shape (connect-to-shape orig-shape dest-shape) - (connect-to-point orig-shape dest-point)) + + dest-point + (connect-to-point orig-shape dest-point) + + :else + (connect-to-point orig-shape + {:x (+ (:x2 (:selrect orig-shape)) 100) + :y (- (:y1 (:selrect orig-shape)) 50)})) orig-dx (if (= orig-pos :right) 100 -100) dest-dx (if (= dest-pos :right) 100 -100) @@ -126,25 +140,38 @@ arrow-dir (if (= dest-pos :left) :right :left)] (if-not selected? - [:path {:stroke "#B1B2B5" - :fill "none" - :pointer-events "visible" - :stroke-width (/ 2 zoom) - :d pdata - :on-mouse-down #(on-mouse-down % orig-shape)}] + [:g {:on-mouse-down #(on-mouse-down % index orig-shape)} + [:path {:stroke "#B1B2B5" + :fill "none" + :pointer-events "visible" + :stroke-width (/ 2 zoom) + :d pdata}] + (when (and (not dest-shape) + (= action-type :close-overlay)) + [:& interaction-marker {:index index + :x dest-x + :y dest-y + :stroke "#B1B2B5" + :action-type action-type + :arrow-dir arrow-dir + :zoom zoom}])] - [:g {:on-mouse-down #(on-mouse-down % orig-shape)} + [:g {:on-mouse-down #(on-mouse-down % index orig-shape)} [:path {:stroke "#31EFB8" :fill "none" :pointer-events "visible" :stroke-width (/ 2 zoom) :d pdata}] - [:& interaction-marker {:x orig-x + [:& interaction-marker {:index index + :x orig-x :y orig-y - :arrow-dir nil + :stroke "#31EFB8" :zoom zoom}] - [:& interaction-marker {:x dest-x + [:& interaction-marker {:index index + :x dest-x :y dest-y + :stroke "#31EFB8" + :action-type action-type :arrow-dir arrow-dir :zoom zoom}] @@ -154,13 +181,15 @@ (mf/defc interaction-handle - [{:keys [shape zoom] :as props}] + [{:keys [index shape zoom] :as props}] (let [shape-rect (:selrect shape) handle-x (+ (:x shape-rect) (:width shape-rect)) handle-y (+ (:y shape-rect) (/ (:height shape-rect) 2))] - [:g {:on-mouse-down #(on-mouse-down % shape)} + [:g {:on-mouse-down #(on-mouse-down % index shape)} [:& interaction-marker {:x handle-x :y handle-y + :stroke "#31EFB8" + :action-type :navigate :arrow-dir :right :zoom zoom}]])) @@ -171,8 +200,9 @@ zoom (mf/deref refs/selected-zoom) current-transform (:transform local) objects (mf/deref refs/workspace-page-objects) - active-shapes (filter #(first (get-click-interaction %)) (vals objects)) + active-shapes (filter #(seq (:interactions %)) (vals objects)) selected-shapes (map #(get objects %) selected) + editing-interaction-index (:editing-interaction-index local) draw-interaction-to (:draw-interaction-to local) draw-interaction-to-frame (:draw-interaction-to-frame local) first-selected (first selected-shapes)] @@ -180,39 +210,46 @@ [:g.interactions [:g.non-selected (for [shape active-shapes] - (let [interaction (get-click-interaction shape) - dest-shape (get objects (:destination interaction)) - selected? (contains? selected (:id shape))] - (when-not (or selected? (not dest-shape)) - [:& interaction-path {:key (:id shape) - :orig-shape shape - :dest-shape dest-shape - :selected selected - :selected? false - :zoom zoom}])))] + (for [[index interaction] (d/enumerate (:interactions shape))] + (let [dest-shape (get objects (:destination interaction)) + selected? (contains? selected (:id shape))] + (when-not selected? + [:& interaction-path {:key (str (:id shape) "-" index) + :index index + :orig-shape shape + :dest-shape dest-shape + :selected selected + :selected? false + :action-type (:action-type interaction) + :zoom zoom}]))))] [:g.selected - (if (and draw-interaction-to first-selected) + (when (and draw-interaction-to first-selected) [:& interaction-path {:key "interactive" + :index nil :orig-shape first-selected :dest-point draw-interaction-to :dest-shape draw-interaction-to-frame :selected? true - :zoom zoom}] - - (for [shape selected-shapes] - (let [interaction (get-click-interaction shape) - dest-shape (get objects (:destination interaction))] - (if dest-shape - [:& interaction-path {:key (:id shape) - :orig-shape shape - :dest-shape dest-shape + :action-type :navigate + :zoom zoom}]) + (for [shape selected-shapes] + (if (seq (:interactions shape)) + (for [[index interaction] (d/enumerate (:interactions shape))] + (when-not (= index editing-interaction-index) + (let [dest-shape (get objects (:destination interaction))] + [:& interaction-path {:key (str (:id shape) "-" index) + :index index + :orig-shape shape + :dest-shape dest-shape + :selected selected + :selected? true + :action-type (:action-type interaction) + :zoom zoom}]))) + (when (not (#{:move :rotate} current-transform)) + [:& interaction-handle {:key (:id shape) + :index nil + :shape shape :selected selected - :selected? true - :zoom zoom}] - (when (not (#{:move :rotate} current-transform)) - [:& interaction-handle {:key (:id shape) - :shape shape - :selected selected - :zoom zoom}])))))]])) + :zoom zoom}])))]])) diff --git a/frontend/translations/ca.po b/frontend/translations/ca.po index 5ab7d6d07..1cbfc7354 100644 --- a/frontend/translations/ca.po +++ b/frontend/translations/ca.po @@ -2152,14 +2152,6 @@ msgstr "Agrupa les capes" msgid "workspace.options.layer-options.title.multiple" msgstr "Capes seleccionades" -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.navigate-to" -msgstr "Vés a" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.none" -msgstr "Cap" - #: src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs msgid "workspace.options.position" msgstr "Posició" @@ -2719,4 +2711,4 @@ msgid "workspace.updates.update" msgstr "Actualitza" msgid "workspace.viewport.click-to-close-path" -msgstr "Feu clic per a tancar el camí" \ No newline at end of file +msgstr "Feu clic per a tancar el camí" diff --git a/frontend/translations/de.po b/frontend/translations/de.po index b66d51f92..a372ea895 100644 --- a/frontend/translations/de.po +++ b/frontend/translations/de.po @@ -1995,14 +1995,6 @@ msgstr "Ebenen gruppieren" msgid "workspace.options.layer-options.title.multiple" msgstr "Ausgewählte Ebenen" -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.navigate-to" -msgstr "Navigiere zu" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.none" -msgstr "Keine" - #: src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs msgid "workspace.options.position" msgstr "Position" @@ -2523,4 +2515,4 @@ msgid "workspace.updates.update" msgstr "Aktualisieren" msgid "workspace.viewport.click-to-close-path" -msgstr "Klicken Sie, um den Pfad zu schließen" \ No newline at end of file +msgstr "Klicken Sie, um den Pfad zu schließen" diff --git a/frontend/translations/el.po b/frontend/translations/el.po index 3812b4182..c404cb727 100644 --- a/frontend/translations/el.po +++ b/frontend/translations/el.po @@ -1832,14 +1832,6 @@ msgstr "στρώματα Ομάδα" msgid "workspace.options.layer-options.title.multiple" msgstr "Επιλεγμένα επίπεδα" -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.navigate-to" -msgstr "Μεταβείτε στο" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.none" -msgstr "Κανένας" - #: src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs msgid "workspace.options.position" msgstr "Θέση" @@ -2357,4 +2349,4 @@ msgid "workspace.updates.update" msgstr "Ενημέρωση" msgid "workspace.viewport.click-to-close-path" -msgstr "Κάντε κλικ για να κλείσετε τη διαδρομή" \ No newline at end of file +msgstr "Κάντε κλικ για να κλείσετε τη διαδρομή" diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 80da61909..0ed54d467 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -2374,14 +2374,6 @@ msgstr "Group layers" msgid "workspace.options.layer-options.title.multiple" msgstr "Selected layers" -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.navigate-to" -msgstr "Navigate to" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.none" -msgstr "None" - #: src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs msgid "workspace.options.position" msgstr "Position" @@ -2405,6 +2397,66 @@ msgstr "Single corners" msgid "workspace.options.rotation" msgstr "Rotation" +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.add-interaction" +msgstr "Click the + button to add interactions." + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-action" +msgstr "Action" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-close-overlay" +msgstr "Close overlay" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-close-overlay-dest" +msgstr "Close overlay: %s" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-destination" +msgstr "Destination" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-navigate-to" +msgstr "Navigate to" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-navigate-to-dest" +msgstr "Navigate to: %s" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-none" +msgstr "none" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-on-click" +msgstr "On Click" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-open-overlay" +msgstr "Open overlay" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-open-overlay-dest" +msgstr "Open overlay: %s" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-self" +msgstr "self" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-trigger" +msgstr "Trigger" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-while-hovering" +msgstr "While Hovering" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interactions" +msgstr "Interactions" + #: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs msgid "workspace.options.select-a-shape" msgstr "Select a shape, artboard or group to drag a connection to other artboard." diff --git a/frontend/translations/es.po b/frontend/translations/es.po index f2c97d48e..83b47aefe 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -2257,14 +2257,6 @@ msgstr "Capas de grupo" msgid "workspace.options.layer-options.title.multiple" msgstr "Capas seleccionadas" -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.navigate-to" -msgstr "Navegar a" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.none" -msgstr "Ninguno" - #: src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs msgid "workspace.options.position" msgstr "Posición" @@ -2288,6 +2280,66 @@ msgstr "Esquinas individuales" msgid "workspace.options.rotation" msgstr "Rotación" +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.add-interaction" +msgstr "Pulsa el botón + para añadir interacciones." + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-action" +msgstr "Acción" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-close-overlay" +msgstr "Close overlay" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-close-overlay-dest" +msgstr "Close overlay: %s" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-destination" +msgstr "Destino" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-navigate-to" +msgstr "Navigate to" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-navigate-to-dest" +msgstr "Navigate to: %s" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-none" +msgstr "none" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-on-click" +msgstr "On Click" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-open-overlay" +msgstr "Open overlay" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-open-overlay-dest" +msgstr "Open overlay: %s" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-self" +msgstr "self" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-trigger" +msgstr "Trigger" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-while-hovering" +msgstr "While Hovering" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interactions" +msgstr "Interacciones" + #: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs msgid "workspace.options.select-a-shape" msgstr "" diff --git a/frontend/translations/fr.po b/frontend/translations/fr.po index 3b98ea239..b19d285e7 100644 --- a/frontend/translations/fr.po +++ b/frontend/translations/fr.po @@ -2157,14 +2157,6 @@ msgstr "Grouper les calques" msgid "workspace.options.layer-options.title.multiple" msgstr "Calques sélectionnés" -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.navigate-to" -msgstr "Naviguer vers" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.none" -msgstr "Aucun" - #: src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs msgid "workspace.options.position" msgstr "Position" @@ -2723,4 +2715,4 @@ msgid "workspace.updates.update" msgstr "Actualiser" msgid "workspace.viewport.click-to-close-path" -msgstr "Cliquez pour fermer le chemin" \ No newline at end of file +msgstr "Cliquez pour fermer le chemin" diff --git a/frontend/translations/pt_BR.po b/frontend/translations/pt_BR.po index 8e8046458..d9a5e7181 100644 --- a/frontend/translations/pt_BR.po +++ b/frontend/translations/pt_BR.po @@ -1662,14 +1662,6 @@ msgstr "Camadas do grupo" msgid "workspace.options.layer-options.title.multiple" msgstr "Camadas selecionadas" -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.navigate-to" -msgstr "Navegar para" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.none" -msgstr "Nenhum" - #: src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs msgid "workspace.options.position" msgstr "Posição" @@ -1993,4 +1985,4 @@ msgid "workspace.updates.update" msgstr "Atualizar" msgid "workspace.viewport.click-to-close-path" -msgstr "Clique para fechar o caminho" \ No newline at end of file +msgstr "Clique para fechar o caminho" diff --git a/frontend/translations/ro.po b/frontend/translations/ro.po index 2dd4d6e5d..f152603df 100644 --- a/frontend/translations/ro.po +++ b/frontend/translations/ro.po @@ -2048,14 +2048,6 @@ msgstr "Grupează layere" msgid "workspace.options.layer-options.title.multiple" msgstr "Layere selectate" -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.navigate-to" -msgstr "Navighează la" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.none" -msgstr "Nici unul" - #: src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs msgid "workspace.options.position" msgstr "Poziţie" @@ -2610,4 +2602,4 @@ msgid "workspace.updates.update" msgstr "Actualizează" msgid "workspace.viewport.click-to-close-path" -msgstr "Click pentru a închide calea" \ No newline at end of file +msgstr "Click pentru a închide calea" diff --git a/frontend/translations/ru.po b/frontend/translations/ru.po index 6f0d9cc98..8bfbc788f 100644 --- a/frontend/translations/ru.po +++ b/frontend/translations/ru.po @@ -957,14 +957,6 @@ msgstr "Заливка для группы" msgid "workspace.options.group-stroke" msgstr "Обводка для группы" -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.navigate-to" -msgstr "Перейти к" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.none" -msgstr "Не задано" - #: src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs msgid "workspace.options.position" msgstr "Позиция" @@ -1184,4 +1176,4 @@ msgid "workspace.updates.update" msgstr "" msgid "workspace.viewport.click-to-close-path" -msgstr "Кликни чтобы закончить фигуру" \ No newline at end of file +msgstr "Кликни чтобы закончить фигуру" diff --git a/frontend/translations/tr.po b/frontend/translations/tr.po index afaf33288..71869c92a 100644 --- a/frontend/translations/tr.po +++ b/frontend/translations/tr.po @@ -2029,14 +2029,6 @@ msgstr "Katman grubu" msgid "workspace.options.layer-options.title.multiple" msgstr "Seçili katmanlar" -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.navigate-to" -msgstr "Git" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.none" -msgstr "Hiç biri" - #: src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs msgid "workspace.options.position" msgstr "Konum" @@ -2539,4 +2531,4 @@ msgstr "Paylaşılmış kütüphanelerde güncellemeler mevcut" #: src/app/main/data/workspace/libraries.cljs msgid "workspace.updates.update" -msgstr "Güncelle" \ No newline at end of file +msgstr "Güncelle" diff --git a/frontend/translations/zh_CN.po b/frontend/translations/zh_CN.po index 71d16f01c..ec412058b 100644 --- a/frontend/translations/zh_CN.po +++ b/frontend/translations/zh_CN.po @@ -2101,14 +2101,6 @@ msgstr "图层成组" msgid "workspace.options.layer-options.title.multiple" msgstr "已选中的图层" -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.navigate-to" -msgstr "导航到" - -#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs -msgid "workspace.options.none" -msgstr "无" - #: src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs msgid "workspace.options.position" msgstr "位置" @@ -2655,4 +2647,4 @@ msgid "workspace.updates.update" msgstr "更新" msgid "workspace.viewport.click-to-close-path" -msgstr "单击以闭合路径" \ No newline at end of file +msgstr "单击以闭合路径"