Merge pull request #1225 from penpot/complex-interactions2
Complex interactions2
|
@ -161,6 +161,12 @@
|
||||||
(when parent-id
|
(when parent-id
|
||||||
(lazy-seq (cons parent-id (get-parents parent-id objects))))))
|
(lazy-seq (cons parent-id (get-parents parent-id objects))))))
|
||||||
|
|
||||||
|
(defn get-frame
|
||||||
|
"Get the frame that contains the shape. If the shape is already a frame, get itself."
|
||||||
|
[shape objects]
|
||||||
|
(if (= (:type shape) :frame)
|
||||||
|
shape
|
||||||
|
(get objects (:frame-id shape))))
|
||||||
|
|
||||||
(defn clean-loops
|
(defn clean-loops
|
||||||
"Clean a list of ids from circular references."
|
"Clean a list of ids from circular references."
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
[app.common.geom.matrix :as gmt]
|
[app.common.geom.matrix :as gmt]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[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]
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
[clojure.spec.alpha :as s]))
|
[clojure.spec.alpha :as s]))
|
||||||
|
@ -30,9 +31,6 @@
|
||||||
(s/def ::component-root? boolean?)
|
(s/def ::component-root? boolean?)
|
||||||
(s/def ::shape-ref uuid?)
|
(s/def ::shape-ref uuid?)
|
||||||
|
|
||||||
(s/def ::safe-integer ::us/safe-integer)
|
|
||||||
(s/def ::safe-number ::us/safe-number)
|
|
||||||
|
|
||||||
(s/def :internal.matrix/a ::us/safe-number)
|
(s/def :internal.matrix/a ::us/safe-number)
|
||||||
(s/def :internal.matrix/b ::us/safe-number)
|
(s/def :internal.matrix/b ::us/safe-number)
|
||||||
(s/def :internal.matrix/c ::us/safe-number)
|
(s/def :internal.matrix/c ::us/safe-number)
|
||||||
|
@ -61,15 +59,15 @@
|
||||||
;; GRADIENTS
|
;; GRADIENTS
|
||||||
|
|
||||||
(s/def :internal.gradient.stop/color ::string)
|
(s/def :internal.gradient.stop/color ::string)
|
||||||
(s/def :internal.gradient.stop/opacity ::safe-number)
|
(s/def :internal.gradient.stop/opacity ::us/safe-number)
|
||||||
(s/def :internal.gradient.stop/offset ::safe-number)
|
(s/def :internal.gradient.stop/offset ::us/safe-number)
|
||||||
|
|
||||||
(s/def :internal.gradient/type #{:linear :radial})
|
(s/def :internal.gradient/type #{:linear :radial})
|
||||||
(s/def :internal.gradient/start-x ::safe-number)
|
(s/def :internal.gradient/start-x ::us/safe-number)
|
||||||
(s/def :internal.gradient/start-y ::safe-number)
|
(s/def :internal.gradient/start-y ::us/safe-number)
|
||||||
(s/def :internal.gradient/end-x ::safe-number)
|
(s/def :internal.gradient/end-x ::us/safe-number)
|
||||||
(s/def :internal.gradient/end-y ::safe-number)
|
(s/def :internal.gradient/end-y ::us/safe-number)
|
||||||
(s/def :internal.gradient/width ::safe-number)
|
(s/def :internal.gradient/width ::us/safe-number)
|
||||||
|
|
||||||
(s/def :internal.gradient/stop
|
(s/def :internal.gradient/stop
|
||||||
(s/keys :req-un [:internal.gradient.stop/color
|
(s/keys :req-un [:internal.gradient.stop/color
|
||||||
|
@ -95,7 +93,7 @@
|
||||||
(s/def :internal.color/path (s/nilable ::string))
|
(s/def :internal.color/path (s/nilable ::string))
|
||||||
(s/def :internal.color/value (s/nilable ::string))
|
(s/def :internal.color/value (s/nilable ::string))
|
||||||
(s/def :internal.color/color (s/nilable ::string))
|
(s/def :internal.color/color (s/nilable ::string))
|
||||||
(s/def :internal.color/opacity (s/nilable ::safe-number))
|
(s/def :internal.color/opacity (s/nilable ::us/safe-number))
|
||||||
(s/def :internal.color/gradient (s/nilable ::gradient))
|
(s/def :internal.color/gradient (s/nilable ::gradient))
|
||||||
|
|
||||||
(s/def ::color
|
(s/def ::color
|
||||||
|
@ -113,10 +111,10 @@
|
||||||
(s/def :internal.shadow/id uuid?)
|
(s/def :internal.shadow/id uuid?)
|
||||||
(s/def :internal.shadow/style #{:drop-shadow :inner-shadow})
|
(s/def :internal.shadow/style #{:drop-shadow :inner-shadow})
|
||||||
(s/def :internal.shadow/color ::color)
|
(s/def :internal.shadow/color ::color)
|
||||||
(s/def :internal.shadow/offset-x ::safe-number)
|
(s/def :internal.shadow/offset-x ::us/safe-number)
|
||||||
(s/def :internal.shadow/offset-y ::safe-number)
|
(s/def :internal.shadow/offset-y ::us/safe-number)
|
||||||
(s/def :internal.shadow/blur ::safe-number)
|
(s/def :internal.shadow/blur ::us/safe-number)
|
||||||
(s/def :internal.shadow/spread ::safe-number)
|
(s/def :internal.shadow/spread ::us/safe-number)
|
||||||
(s/def :internal.shadow/hidden boolean?)
|
(s/def :internal.shadow/hidden boolean?)
|
||||||
|
|
||||||
(s/def :internal.shadow/shadow
|
(s/def :internal.shadow/shadow
|
||||||
|
@ -137,7 +135,7 @@
|
||||||
|
|
||||||
(s/def :internal.blur/id uuid?)
|
(s/def :internal.blur/id uuid?)
|
||||||
(s/def :internal.blur/type #{:layer-blur})
|
(s/def :internal.blur/type #{:layer-blur})
|
||||||
(s/def :internal.blur/value ::safe-number)
|
(s/def :internal.blur/value ::us/safe-number)
|
||||||
(s/def :internal.blur/hidden boolean?)
|
(s/def :internal.blur/hidden boolean?)
|
||||||
|
|
||||||
(s/def ::blur
|
(s/def ::blur
|
||||||
|
@ -148,17 +146,17 @@
|
||||||
|
|
||||||
;; Page Options
|
;; Page Options
|
||||||
(s/def :internal.page.grid.color/value string?)
|
(s/def :internal.page.grid.color/value string?)
|
||||||
(s/def :internal.page.grid.color/opacity ::safe-number)
|
(s/def :internal.page.grid.color/opacity ::us/safe-number)
|
||||||
|
|
||||||
(s/def :internal.page.grid/size ::safe-integer)
|
(s/def :internal.page.grid/size ::us/safe-integer)
|
||||||
(s/def :internal.page.grid/color
|
(s/def :internal.page.grid/color
|
||||||
(s/keys :req-un [:internal.page.grid.color/value
|
(s/keys :req-un [:internal.page.grid.color/value
|
||||||
:internal.page.grid.color/opacity]))
|
:internal.page.grid.color/opacity]))
|
||||||
|
|
||||||
(s/def :internal.page.grid/type #{:stretch :left :center :right})
|
(s/def :internal.page.grid/type #{:stretch :left :center :right})
|
||||||
(s/def :internal.page.grid/item-length (s/nilable ::safe-integer))
|
(s/def :internal.page.grid/item-length (s/nilable ::us/safe-integer))
|
||||||
(s/def :internal.page.grid/gutter (s/nilable ::safe-integer))
|
(s/def :internal.page.grid/gutter (s/nilable ::us/safe-integer))
|
||||||
(s/def :internal.page.grid/margin (s/nilable ::safe-integer))
|
(s/def :internal.page.grid/margin (s/nilable ::us/safe-integer))
|
||||||
|
|
||||||
(s/def :internal.page.grid/square
|
(s/def :internal.page.grid/square
|
||||||
(s/keys :req-un [:internal.page.grid/size
|
(s/keys :req-un [:internal.page.grid/size
|
||||||
|
@ -183,25 +181,6 @@
|
||||||
(s/def :internal.page/options
|
(s/def :internal.page/options
|
||||||
(s/keys :opt-un [:internal.page.options/background]))
|
(s/keys :opt-un [:internal.page.options/background]))
|
||||||
|
|
||||||
;; Interactions
|
|
||||||
|
|
||||||
(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
|
|
||||||
:internal.shape.interaction/action-type
|
|
||||||
:internal.shape.interaction/destination]))
|
|
||||||
|
|
||||||
(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
|
;; Size constraints
|
||||||
|
|
||||||
(s/def :internal.shape/constraints-h #{:left :right :leftright :center :scale})
|
(s/def :internal.shape/constraints-h #{:left :right :leftright :center :scale})
|
||||||
|
@ -232,33 +211,33 @@
|
||||||
(s/def :internal.shape/content any?)
|
(s/def :internal.shape/content any?)
|
||||||
|
|
||||||
(s/def :internal.shape/fill-color string?)
|
(s/def :internal.shape/fill-color string?)
|
||||||
(s/def :internal.shape/fill-opacity ::safe-number)
|
(s/def :internal.shape/fill-opacity ::us/safe-number)
|
||||||
(s/def :internal.shape/fill-color-gradient (s/nilable ::gradient))
|
(s/def :internal.shape/fill-color-gradient (s/nilable ::gradient))
|
||||||
(s/def :internal.shape/fill-color-ref-file (s/nilable uuid?))
|
(s/def :internal.shape/fill-color-ref-file (s/nilable uuid?))
|
||||||
(s/def :internal.shape/fill-color-ref-id (s/nilable uuid?))
|
(s/def :internal.shape/fill-color-ref-id (s/nilable uuid?))
|
||||||
|
|
||||||
(s/def :internal.shape/font-family string?)
|
(s/def :internal.shape/font-family string?)
|
||||||
(s/def :internal.shape/font-size ::safe-integer)
|
(s/def :internal.shape/font-size ::us/safe-integer)
|
||||||
(s/def :internal.shape/font-style string?)
|
(s/def :internal.shape/font-style string?)
|
||||||
(s/def :internal.shape/font-weight string?)
|
(s/def :internal.shape/font-weight string?)
|
||||||
(s/def :internal.shape/hidden boolean?)
|
(s/def :internal.shape/hidden boolean?)
|
||||||
(s/def :internal.shape/letter-spacing ::safe-number)
|
(s/def :internal.shape/letter-spacing ::us/safe-number)
|
||||||
(s/def :internal.shape/line-height ::safe-number)
|
(s/def :internal.shape/line-height ::us/safe-number)
|
||||||
(s/def :internal.shape/locked boolean?)
|
(s/def :internal.shape/locked boolean?)
|
||||||
(s/def :internal.shape/page-id uuid?)
|
(s/def :internal.shape/page-id uuid?)
|
||||||
(s/def :internal.shape/proportion ::safe-number)
|
(s/def :internal.shape/proportion ::us/safe-number)
|
||||||
(s/def :internal.shape/proportion-lock boolean?)
|
(s/def :internal.shape/proportion-lock boolean?)
|
||||||
(s/def :internal.shape/rx ::safe-number)
|
(s/def :internal.shape/rx ::us/safe-number)
|
||||||
(s/def :internal.shape/ry ::safe-number)
|
(s/def :internal.shape/ry ::us/safe-number)
|
||||||
(s/def :internal.shape/r1 ::safe-number)
|
(s/def :internal.shape/r1 ::us/safe-number)
|
||||||
(s/def :internal.shape/r2 ::safe-number)
|
(s/def :internal.shape/r2 ::us/safe-number)
|
||||||
(s/def :internal.shape/r3 ::safe-number)
|
(s/def :internal.shape/r3 ::us/safe-number)
|
||||||
(s/def :internal.shape/r4 ::safe-number)
|
(s/def :internal.shape/r4 ::us/safe-number)
|
||||||
(s/def :internal.shape/stroke-color string?)
|
(s/def :internal.shape/stroke-color string?)
|
||||||
(s/def :internal.shape/stroke-color-gradient (s/nilable ::gradient))
|
(s/def :internal.shape/stroke-color-gradient (s/nilable ::gradient))
|
||||||
(s/def :internal.shape/stroke-color-ref-file (s/nilable uuid?))
|
(s/def :internal.shape/stroke-color-ref-file (s/nilable uuid?))
|
||||||
(s/def :internal.shape/stroke-color-ref-id (s/nilable uuid?))
|
(s/def :internal.shape/stroke-color-ref-id (s/nilable uuid?))
|
||||||
(s/def :internal.shape/stroke-opacity ::safe-number)
|
(s/def :internal.shape/stroke-opacity ::us/safe-number)
|
||||||
(s/def :internal.shape/stroke-style #{:solid :dotted :dashed :mixed :none :svg})
|
(s/def :internal.shape/stroke-style #{:solid :dotted :dashed :mixed :none :svg})
|
||||||
|
|
||||||
(def stroke-caps-line #{:round :square})
|
(def stroke-caps-line #{:round :square})
|
||||||
|
@ -271,26 +250,26 @@
|
||||||
[shape]
|
[shape]
|
||||||
(= (:type shape) :path))
|
(= (:type shape) :path))
|
||||||
|
|
||||||
(s/def :internal.shape/stroke-width ::safe-number)
|
(s/def :internal.shape/stroke-width ::us/safe-number)
|
||||||
(s/def :internal.shape/stroke-alignment #{:center :inner :outer})
|
(s/def :internal.shape/stroke-alignment #{:center :inner :outer})
|
||||||
(s/def :internal.shape/text-align #{"left" "right" "center" "justify"})
|
(s/def :internal.shape/text-align #{"left" "right" "center" "justify"})
|
||||||
(s/def :internal.shape/x ::safe-number)
|
(s/def :internal.shape/x ::us/safe-number)
|
||||||
(s/def :internal.shape/y ::safe-number)
|
(s/def :internal.shape/y ::us/safe-number)
|
||||||
(s/def :internal.shape/cx ::safe-number)
|
(s/def :internal.shape/cx ::us/safe-number)
|
||||||
(s/def :internal.shape/cy ::safe-number)
|
(s/def :internal.shape/cy ::us/safe-number)
|
||||||
(s/def :internal.shape/width ::safe-number)
|
(s/def :internal.shape/width ::us/safe-number)
|
||||||
(s/def :internal.shape/height ::safe-number)
|
(s/def :internal.shape/height ::us/safe-number)
|
||||||
(s/def :internal.shape/index integer?)
|
(s/def :internal.shape/index integer?)
|
||||||
(s/def :internal.shape/shadow ::shadow)
|
(s/def :internal.shape/shadow ::shadow)
|
||||||
(s/def :internal.shape/blur ::blur)
|
(s/def :internal.shape/blur ::blur)
|
||||||
|
|
||||||
(s/def :internal.shape/x1 ::safe-number)
|
(s/def :internal.shape/x1 ::us/safe-number)
|
||||||
(s/def :internal.shape/y1 ::safe-number)
|
(s/def :internal.shape/y1 ::us/safe-number)
|
||||||
(s/def :internal.shape/x2 ::safe-number)
|
(s/def :internal.shape/x2 ::us/safe-number)
|
||||||
(s/def :internal.shape/y2 ::safe-number)
|
(s/def :internal.shape/y2 ::us/safe-number)
|
||||||
|
|
||||||
(s/def :internal.shape.export/suffix string?)
|
(s/def :internal.shape.export/suffix string?)
|
||||||
(s/def :internal.shape.export/scale ::safe-number)
|
(s/def :internal.shape.export/scale ::us/safe-number)
|
||||||
(s/def :internal.shape/export
|
(s/def :internal.shape/export
|
||||||
(s/keys :req-un [::type
|
(s/keys :req-un [::type
|
||||||
:internal.shape.export/suffix
|
:internal.shape.export/suffix
|
||||||
|
@ -366,7 +345,7 @@
|
||||||
:internal.shape/transform-inverse
|
:internal.shape/transform-inverse
|
||||||
:internal.shape/width
|
:internal.shape/width
|
||||||
:internal.shape/height
|
:internal.shape/height
|
||||||
:internal.shape/interactions
|
::cti/interactions
|
||||||
:internal.shape/masked-group?
|
:internal.shape/masked-group?
|
||||||
:internal.shape/shadow
|
:internal.shape/shadow
|
||||||
:internal.shape/blur]))
|
:internal.shape/blur]))
|
||||||
|
@ -402,8 +381,8 @@
|
||||||
:internal.color/gradient]))
|
:internal.color/gradient]))
|
||||||
|
|
||||||
(s/def :internal.media-object/name ::string)
|
(s/def :internal.media-object/name ::string)
|
||||||
(s/def :internal.media-object/width ::safe-integer)
|
(s/def :internal.media-object/width ::us/safe-integer)
|
||||||
(s/def :internal.media-object/height ::safe-integer)
|
(s/def :internal.media-object/height ::us/safe-integer)
|
||||||
(s/def :internal.media-object/mtype ::string)
|
(s/def :internal.media-object/mtype ::string)
|
||||||
|
|
||||||
(s/def ::media-object
|
(s/def ::media-object
|
||||||
|
|
283
common/src/app/common/types/interactions.cljc
Normal file
|
@ -0,0 +1,283 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) UXBOX Labs SL
|
||||||
|
|
||||||
|
(ns app.common.types.interactions
|
||||||
|
(:require
|
||||||
|
[app.common.geom.point :as gpt]
|
||||||
|
[app.common.spec :as us]
|
||||||
|
[clojure.spec.alpha :as s]))
|
||||||
|
|
||||||
|
(s/def ::point
|
||||||
|
(s/and (s/keys :req-un [::x ::y])
|
||||||
|
gpt/point?))
|
||||||
|
|
||||||
|
;; -- Options depending on event type
|
||||||
|
|
||||||
|
(s/def ::event-type #{:click
|
||||||
|
:mouse-over
|
||||||
|
:mouse-press
|
||||||
|
:mouse-enter
|
||||||
|
:mouse-leave
|
||||||
|
:after-delay})
|
||||||
|
|
||||||
|
(s/def ::delay ::us/safe-integer)
|
||||||
|
|
||||||
|
(defmulti event-opts-spec :event-type)
|
||||||
|
|
||||||
|
(defmethod event-opts-spec :after-delay [_]
|
||||||
|
(s/keys :req-un [::delay]))
|
||||||
|
|
||||||
|
(defmethod event-opts-spec :default [_]
|
||||||
|
(s/keys :req-un []))
|
||||||
|
|
||||||
|
(s/def ::event-opts
|
||||||
|
(s/multi-spec event-opts-spec ::event-type))
|
||||||
|
|
||||||
|
;; -- Options depending on action type
|
||||||
|
|
||||||
|
(s/def ::action-type #{:navigate
|
||||||
|
:open-overlay
|
||||||
|
:close-overlay
|
||||||
|
:prev-screen
|
||||||
|
:open-url})
|
||||||
|
|
||||||
|
(s/def ::destination (s/nilable ::us/uuid))
|
||||||
|
(s/def ::overlay-pos-type #{:manual
|
||||||
|
:center
|
||||||
|
:top-left
|
||||||
|
:top-right
|
||||||
|
:top-center
|
||||||
|
:bottom-left
|
||||||
|
:bottom-right
|
||||||
|
:bottom-center})
|
||||||
|
(s/def ::overlay-position ::point)
|
||||||
|
(s/def ::url ::us/string)
|
||||||
|
(s/def ::close-click-outside ::us/boolean)
|
||||||
|
(s/def ::background-overlay ::us/boolean)
|
||||||
|
|
||||||
|
(defmulti action-opts-spec :action-type)
|
||||||
|
|
||||||
|
(defmethod action-opts-spec :navigate [_]
|
||||||
|
(s/keys :req-un [::destination]))
|
||||||
|
|
||||||
|
(defmethod action-opts-spec :open-overlay [_]
|
||||||
|
(s/keys :req-un [::destination
|
||||||
|
::overlay-position
|
||||||
|
::overlay-pos-type]
|
||||||
|
:opt-un [::close-click-outside
|
||||||
|
::background-overlay]))
|
||||||
|
|
||||||
|
(defmethod action-opts-spec :close-overlay [_]
|
||||||
|
(s/keys :req-un [::destination]))
|
||||||
|
|
||||||
|
(defmethod action-opts-spec :prev-screen [_]
|
||||||
|
(s/keys :req-un []))
|
||||||
|
|
||||||
|
(defmethod action-opts-spec :open-url [_]
|
||||||
|
(s/keys :req-un [::url]))
|
||||||
|
|
||||||
|
(s/def ::action-opts
|
||||||
|
(s/multi-spec action-opts-spec ::action-type))
|
||||||
|
|
||||||
|
;; -- Interaction
|
||||||
|
|
||||||
|
(s/def ::classifier
|
||||||
|
(s/keys :req-un [::event-type
|
||||||
|
::action-type]))
|
||||||
|
|
||||||
|
(s/def ::interaction
|
||||||
|
(s/merge ::classifier
|
||||||
|
::event-opts
|
||||||
|
::action-opts))
|
||||||
|
|
||||||
|
(s/def ::interactions
|
||||||
|
(s/coll-of ::interaction :kind vector?))
|
||||||
|
|
||||||
|
(def default-interaction
|
||||||
|
{:event-type :click
|
||||||
|
:action-type :navigate
|
||||||
|
:destination nil})
|
||||||
|
|
||||||
|
(def default-delay 100)
|
||||||
|
|
||||||
|
;; -- Helpers
|
||||||
|
|
||||||
|
(declare calc-overlay-position)
|
||||||
|
|
||||||
|
(defn set-event-type
|
||||||
|
[interaction event-type]
|
||||||
|
(us/verify ::interaction interaction)
|
||||||
|
(us/verify ::event-type event-type)
|
||||||
|
(if (= (:event-type interaction) event-type)
|
||||||
|
interaction
|
||||||
|
(case event-type
|
||||||
|
|
||||||
|
:after-delay
|
||||||
|
(assoc interaction
|
||||||
|
:event-type event-type
|
||||||
|
:delay (get interaction :delay default-delay))
|
||||||
|
|
||||||
|
(assoc interaction
|
||||||
|
:event-type event-type))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn set-action-type
|
||||||
|
[interaction action-type shape objects]
|
||||||
|
(us/verify ::interaction interaction)
|
||||||
|
(us/verify ::action-type action-type)
|
||||||
|
(if (= (:action-type interaction) action-type)
|
||||||
|
interaction
|
||||||
|
(case action-type
|
||||||
|
|
||||||
|
:navigate
|
||||||
|
(assoc interaction
|
||||||
|
:action-type action-type
|
||||||
|
:destination (get interaction :destination))
|
||||||
|
|
||||||
|
:open-overlay
|
||||||
|
(let [destination (get interaction :destination)
|
||||||
|
overlay-pos-type (get interaction :overlay-pos-type :center)
|
||||||
|
overlay-position (get interaction
|
||||||
|
:overlay-position
|
||||||
|
(calc-overlay-position
|
||||||
|
destination
|
||||||
|
interaction
|
||||||
|
shape
|
||||||
|
objects
|
||||||
|
overlay-pos-type))]
|
||||||
|
(assoc interaction
|
||||||
|
:action-type action-type
|
||||||
|
:destination destination
|
||||||
|
:overlay-pos-type overlay-pos-type
|
||||||
|
:overlay-position overlay-position))
|
||||||
|
|
||||||
|
:close-overlay
|
||||||
|
(assoc interaction
|
||||||
|
:action-type action-type
|
||||||
|
:destination (get interaction :destination))
|
||||||
|
|
||||||
|
:prev-screen
|
||||||
|
(assoc interaction
|
||||||
|
:action-type action-type)
|
||||||
|
|
||||||
|
:open-url
|
||||||
|
(assoc interaction
|
||||||
|
:action-type action-type
|
||||||
|
:url (get interaction :url "")))))
|
||||||
|
|
||||||
|
(defn set-destination
|
||||||
|
[interaction destination shape objects]
|
||||||
|
(us/verify ::interaction interaction)
|
||||||
|
(us/verify ::destination destination)
|
||||||
|
(assert (or (nil? destination)
|
||||||
|
(some? (get objects destination))))
|
||||||
|
(assert #(:navigate :open-overlay :close-overlay) (:action-type interaction))
|
||||||
|
(cond-> interaction
|
||||||
|
:always
|
||||||
|
(assoc :destination destination)
|
||||||
|
|
||||||
|
(= (:action-type interaction) :open-overlay)
|
||||||
|
(assoc :overlay-pos-type :center
|
||||||
|
:overlay-position (calc-overlay-position destination
|
||||||
|
interaction
|
||||||
|
shape
|
||||||
|
objects
|
||||||
|
:center))))
|
||||||
|
|
||||||
|
(defn set-overlay-pos-type
|
||||||
|
[interaction overlay-pos-type shape objects]
|
||||||
|
(us/verify ::interaction interaction)
|
||||||
|
(us/verify ::overlay-pos-type overlay-pos-type)
|
||||||
|
(assert #(= :open-overlay (:action-type interaction)))
|
||||||
|
(assoc interaction
|
||||||
|
:overlay-pos-type overlay-pos-type
|
||||||
|
:overlay-position (calc-overlay-position (:destination interaction)
|
||||||
|
interaction
|
||||||
|
shape
|
||||||
|
objects
|
||||||
|
overlay-pos-type)))
|
||||||
|
|
||||||
|
(defn toggle-overlay-pos-type
|
||||||
|
[interaction overlay-pos-type shape objects]
|
||||||
|
(us/verify ::interaction interaction)
|
||||||
|
(us/verify ::overlay-pos-type overlay-pos-type)
|
||||||
|
(assert #(= :open-overlay (:action-type interaction)))
|
||||||
|
(let [new-pos-type (if (= (:overlay-pos-type interaction) overlay-pos-type)
|
||||||
|
:manual
|
||||||
|
overlay-pos-type)]
|
||||||
|
(assoc interaction
|
||||||
|
:overlay-pos-type new-pos-type
|
||||||
|
:overlay-position (calc-overlay-position (:destination interaction)
|
||||||
|
interaction
|
||||||
|
shape
|
||||||
|
objects
|
||||||
|
new-pos-type))))
|
||||||
|
|
||||||
|
(defn set-overlay-position
|
||||||
|
[interaction overlay-position]
|
||||||
|
(us/verify ::interaction interaction)
|
||||||
|
(us/verify ::overlay-position overlay-position)
|
||||||
|
(assert #(= :open-overlay (:action-type interaction)))
|
||||||
|
(assoc interaction
|
||||||
|
:overlay-pos-type :manual
|
||||||
|
:overlay-position overlay-position))
|
||||||
|
|
||||||
|
(defn set-close-click-outside
|
||||||
|
[interaction close-click-outside]
|
||||||
|
(us/verify ::interaction interaction)
|
||||||
|
(us/verify ::us/boolean close-click-outside)
|
||||||
|
(assert #(= :open-overlay (:action-type interaction)))
|
||||||
|
(assoc interaction :close-click-outside close-click-outside))
|
||||||
|
|
||||||
|
(defn set-background-overlay
|
||||||
|
[interaction background-overlay]
|
||||||
|
(us/verify ::interaction interaction)
|
||||||
|
(us/verify ::us/boolean background-overlay)
|
||||||
|
(assert #(= :open-overlay (:action-type interaction)))
|
||||||
|
(assoc interaction :background-overlay background-overlay))
|
||||||
|
|
||||||
|
(defn- calc-overlay-position
|
||||||
|
[destination interaction shape objects overlay-pos-type]
|
||||||
|
(if (nil? destination)
|
||||||
|
(gpt/point 0 0)
|
||||||
|
(let [dest-frame (get objects destination)
|
||||||
|
overlay-size (:selrect dest-frame)
|
||||||
|
orig-frame (if (= (:type shape) :frame)
|
||||||
|
shape
|
||||||
|
(get objects (:frame-id shape)))
|
||||||
|
frame-size (:selrect orig-frame)]
|
||||||
|
(case overlay-pos-type
|
||||||
|
|
||||||
|
:center
|
||||||
|
(gpt/point (/ (- (:width frame-size) (:width overlay-size)) 2)
|
||||||
|
(/ (- (:height frame-size) (:height overlay-size)) 2))
|
||||||
|
|
||||||
|
:top-left
|
||||||
|
(gpt/point 0 0)
|
||||||
|
|
||||||
|
:top-right
|
||||||
|
(gpt/point (- (:width frame-size) (:width overlay-size))
|
||||||
|
0)
|
||||||
|
|
||||||
|
:top-center
|
||||||
|
(gpt/point (/ (- (:width frame-size) (:width overlay-size)) 2)
|
||||||
|
0)
|
||||||
|
|
||||||
|
:bottom-left
|
||||||
|
(gpt/point 0
|
||||||
|
(- (:height frame-size) (:height overlay-size)))
|
||||||
|
|
||||||
|
:bottom-right
|
||||||
|
(gpt/point (- (:width frame-size) (:width overlay-size))
|
||||||
|
(- (:height frame-size) (:height overlay-size)))
|
||||||
|
|
||||||
|
:bottom-center
|
||||||
|
(gpt/point (/ (- (:width frame-size) (:width overlay-size)) 2)
|
||||||
|
(- (:height frame-size) (:height overlay-size)))
|
||||||
|
|
||||||
|
:manual
|
||||||
|
(:overlay-position interaction)))))
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18">
|
||||||
|
<g>
|
||||||
|
<rect rx="0" ry="0" x="0" y="0" width="18" height="18" id="a" fill="none" stroke-width="2" stroke-opacity="1"/>
|
||||||
|
<rect rx="0" ry="0" x="5" y="10" width="8" height="8"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 260 B |
6
frontend/resources/images/icons/position-bottom-left.svg
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18">
|
||||||
|
<g>
|
||||||
|
<rect rx="0" ry="0" x="0" y="0" width="18" height="18" id="a" fill="none" stroke-width="2" stroke-opacity="1"/>
|
||||||
|
<rect rx="0" ry="0" x="0" y="10" width="8" height="8"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 260 B |
|
@ -0,0 +1,6 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18">
|
||||||
|
<g>
|
||||||
|
<rect rx="0" ry="0" x="0" y="0" width="18" height="18" id="a" fill="none" stroke-width="2" stroke-opacity="1"/>
|
||||||
|
<rect rx="0" ry="0" x="10" y="10" width="8" height="8"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 261 B |
6
frontend/resources/images/icons/position-center.svg
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18">
|
||||||
|
<g>
|
||||||
|
<rect rx="0" ry="0" x="0" y="0" width="18" height="18" id="a" fill="none" stroke-width="2" stroke-opacity="1"/>
|
||||||
|
<rect rx="0" ry="0" x="5" y="5" width="8" height="8"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 259 B |
6
frontend/resources/images/icons/position-top-center.svg
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18">
|
||||||
|
<g>
|
||||||
|
<rect rx="0" ry="0" x="0" y="0" width="18" height="18" id="a" fill="none" stroke-width="2" stroke-opacity="1"/>
|
||||||
|
<rect rx="0" ry="0" x="5" width="8" height="8"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 253 B |
7
frontend/resources/images/icons/position-top-left.svg
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18">
|
||||||
|
<g>
|
||||||
|
<rect rx="0" ry="0" x="0" y="0" width="18" height="18" id="a" fill="none" stroke-width="2" stroke-opacity="1"/>
|
||||||
|
<rect rx="0" ry="0" x="0" width="8" height="8"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
|
After Width: | Height: | Size: 254 B |
6
frontend/resources/images/icons/position-top-right.svg
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18">
|
||||||
|
<g>
|
||||||
|
<rect rx="0" ry="0" x="0" y="0" width="18" height="18" id="a" fill="none" stroke-width="2" stroke-opacity="1"/>
|
||||||
|
<rect rx="0" ry="0" x="10" width="8" height="8"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 254 B |
|
@ -43,3 +43,19 @@
|
||||||
grid-row: 1 / span 2;
|
grid-row: 1 / span 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.viewer-overlay {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewer-overlay-background {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
&.visible {
|
||||||
|
background-color: rgb(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -222,6 +222,31 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input-checkbox {
|
||||||
|
label {
|
||||||
|
color: $color-gray-20;
|
||||||
|
}
|
||||||
|
|
||||||
|
label::before {
|
||||||
|
background-color: transparent;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
label::after {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + label::before {
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + label::after {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.element-set-subtitle {
|
.element-set-subtitle {
|
||||||
color: $color-gray-20;
|
color: $color-gray-20;
|
||||||
font-size: $fs11;
|
font-size: $fs11;
|
||||||
|
@ -883,12 +908,31 @@
|
||||||
&.selected {
|
&.selected {
|
||||||
border: 1px solid $color-primary;
|
border: 1px solid $color-primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-top: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.open {
|
||||||
|
&:hover {
|
||||||
|
background: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.interactions-options {
|
||||||
|
&.element-set {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.element-set-options-group {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.exports-options,
|
.exports-options,
|
||||||
.shadow-options{
|
.shadow-options {
|
||||||
.element-set-options-group {
|
.element-set-options-group {
|
||||||
justify-content: space-between;
|
|
||||||
.delete-icon {
|
.delete-icon {
|
||||||
display: flex;
|
display: flex;
|
||||||
min-width: 40px;
|
min-width: 40px;
|
||||||
|
@ -902,10 +946,6 @@
|
||||||
fill: $color-gray-20;
|
fill: $color-gray-20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(:first-child) {
|
|
||||||
margin-top: 7px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-button {
|
.download-button {
|
||||||
|
@ -945,11 +985,15 @@
|
||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
fill: $color-gray-20;
|
fill: $color-gray-20;
|
||||||
|
stroke: $color-gray-20;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover svg {
|
&:hover svg,
|
||||||
|
&.active svg {
|
||||||
fill: $color-primary;
|
fill: $color-primary;
|
||||||
|
stroke: $color-primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.actions-inside {
|
&.actions-inside {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
|
|
@ -7,8 +7,14 @@
|
||||||
|
|
||||||
.interactions-help {
|
.interactions-help {
|
||||||
font-size: $fs12;
|
font-size: $fs12;
|
||||||
margin: 0 $medium;
|
padding: 7px $medium;
|
||||||
|
margin: 0 -7px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
|
&.separator {
|
||||||
|
padding-bottom: $medium;
|
||||||
|
border-bottom: 1px solid $color-black;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.interactions-help-icon {
|
.interactions-help-icon {
|
||||||
|
@ -24,7 +30,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.interactions-summary {
|
.interactions-summary {
|
||||||
width: 100%;
|
cursor: pointer;
|
||||||
|
flex-basis: 0;
|
||||||
|
flex-grow: 1;
|
||||||
|
|
||||||
.trigger-name {
|
.trigger-name {
|
||||||
font-size: $fs12;
|
font-size: $fs12;
|
||||||
|
@ -40,10 +48,34 @@
|
||||||
.interactions-element {
|
.interactions-element {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
margin: 0 -7px;
|
||||||
|
padding: 0 7px;
|
||||||
|
|
||||||
.element-label {
|
.element-label {
|
||||||
color: $color-gray-20;
|
color: $color-gray-20;
|
||||||
font-size: $fs11;
|
font-size: $fs11;
|
||||||
width: 64px;
|
width: 64px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.separator {
|
||||||
|
border-top: 1px solid $color-black;
|
||||||
|
margin-top: $x-small;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.interactions-pos-buttons {
|
||||||
|
margin-top: $small;
|
||||||
|
padding-top: $small;
|
||||||
|
padding-bottom: $small;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.element-set-actions-button {
|
||||||
|
min-width: 18px;
|
||||||
|
min-height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -328,8 +328,11 @@
|
||||||
;; --- Overlays
|
;; --- Overlays
|
||||||
|
|
||||||
(defn open-overlay
|
(defn open-overlay
|
||||||
[frame-id]
|
[frame-id position close-click-outside background-overlay]
|
||||||
(us/verify ::us/uuid frame-id)
|
(us/verify ::us/uuid frame-id)
|
||||||
|
(us/verify ::us/point position)
|
||||||
|
(us/verify (s/nilable ::us/boolean) close-click-outside)
|
||||||
|
(us/verify (s/nilable ::us/boolean) background-overlay)
|
||||||
(ptk/reify ::open-overlay
|
(ptk/reify ::open-overlay
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
|
@ -340,7 +343,11 @@
|
||||||
frame (d/seek #(= (:id %) frame-id) frames)
|
frame (d/seek #(= (:id %) frame-id) frames)
|
||||||
overlays (get-in state [:viewer-local :overlays])]
|
overlays (get-in state [:viewer-local :overlays])]
|
||||||
(if-not (some #(= % frame) overlays)
|
(if-not (some #(= % frame) overlays)
|
||||||
(update-in state [:viewer-local :overlays] conj frame)
|
(update-in state [:viewer-local :overlays] conj
|
||||||
|
{:frame frame
|
||||||
|
:position position
|
||||||
|
:close-click-outside close-click-outside
|
||||||
|
:background-overlay background-overlay})
|
||||||
state)))))
|
state)))))
|
||||||
|
|
||||||
(defn close-overlay
|
(defn close-overlay
|
||||||
|
@ -350,7 +357,7 @@
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(update-in state [:viewer-local :overlays]
|
(update-in state [:viewer-local :overlays]
|
||||||
(fn [overlays]
|
(fn [overlays]
|
||||||
(remove #(= (:id %) frame-id) overlays))))))
|
(remove #(= (:id (:frame %)) frame-id) overlays))))))
|
||||||
|
|
||||||
;; --- Objects selection
|
;; --- Objects selection
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
[app.common.pages.spec :as spec]
|
[app.common.pages.spec :as spec]
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.common.transit :as t]
|
[app.common.transit :as t]
|
||||||
|
[app.common.types.interactions :as cti]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cfg]
|
[app.config :as cfg]
|
||||||
[app.main.data.events :as ev]
|
[app.main.data.events :as ev]
|
||||||
|
@ -1826,10 +1827,93 @@
|
||||||
frame)]
|
frame)]
|
||||||
;; Update or create interaction
|
;; Update or create interaction
|
||||||
(if index
|
(if index
|
||||||
(assoc-in interactions [index :destination] (:id frame))
|
(update interactions index
|
||||||
|
#(cti/set-destination % (:id frame) shape objects))
|
||||||
(conj (or interactions [])
|
(conj (or interactions [])
|
||||||
(assoc spec/default-interaction
|
(cti/set-destination cti/default-interaction
|
||||||
:destination (:id frame))))))))))))))))
|
(:id frame)
|
||||||
|
shape
|
||||||
|
objects)))))))))))))))
|
||||||
|
|
||||||
|
(declare move-overlay-pos)
|
||||||
|
(declare finish-move-overlay-pos)
|
||||||
|
|
||||||
|
(defn start-move-overlay-pos
|
||||||
|
[index]
|
||||||
|
(ptk/reify ::start-move-overlay-pos
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(-> state
|
||||||
|
(assoc-in [:workspace-local :move-overlay-to] nil)
|
||||||
|
(assoc-in [:workspace-local :move-overlay-index] index)))
|
||||||
|
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(let [initial-pos @ms/mouse-position
|
||||||
|
selected (wsh/lookup-selected state)
|
||||||
|
stopper (rx/filter ms/mouse-up? stream)]
|
||||||
|
(when (= 1 (count selected))
|
||||||
|
(let [page-id (:current-page-id state)
|
||||||
|
objects (wsh/lookup-page-objects state page-id)
|
||||||
|
shape (->> state
|
||||||
|
wsh/lookup-selected
|
||||||
|
first
|
||||||
|
(get objects))
|
||||||
|
overlay-pos (-> shape
|
||||||
|
(get-in [:interactions index])
|
||||||
|
:overlay-position)
|
||||||
|
orig-frame (cph/get-frame shape objects)
|
||||||
|
frame-pos (gpt/point (:x orig-frame) (:y orig-frame))
|
||||||
|
offset (-> initial-pos
|
||||||
|
(gpt/subtract overlay-pos)
|
||||||
|
(gpt/subtract frame-pos))]
|
||||||
|
(rx/concat
|
||||||
|
(->> ms/mouse-position
|
||||||
|
(rx/take-until stopper)
|
||||||
|
(rx/map #(move-overlay-pos % frame-pos offset)))
|
||||||
|
(rx/of (finish-move-overlay-pos index frame-pos offset)))))))))
|
||||||
|
|
||||||
|
(defn move-overlay-pos
|
||||||
|
[pos frame-pos offset]
|
||||||
|
(ptk/reify ::move-overlay-pos
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(let [pos (-> pos
|
||||||
|
(gpt/subtract frame-pos)
|
||||||
|
(gpt/subtract offset))]
|
||||||
|
(assoc-in state [:workspace-local :move-overlay-to] pos)))))
|
||||||
|
|
||||||
|
(defn finish-move-overlay-pos
|
||||||
|
[index frame-pos offset]
|
||||||
|
(ptk/reify ::finish-move-overlay-pos
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(-> state
|
||||||
|
(d/dissoc-in [:workspace-local :move-overlay-to])
|
||||||
|
(d/dissoc-in [:workspace-local :move-overlay-index])))
|
||||||
|
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
(let [pos @ms/mouse-position
|
||||||
|
overlay-pos (-> pos
|
||||||
|
(gpt/subtract frame-pos)
|
||||||
|
(gpt/subtract offset))
|
||||||
|
|
||||||
|
page-id (:current-page-id state)
|
||||||
|
objects (wsh/lookup-page-objects state page-id)
|
||||||
|
shape (->> state
|
||||||
|
wsh/lookup-selected
|
||||||
|
first
|
||||||
|
(get objects))
|
||||||
|
|
||||||
|
interactions (:interactions shape)
|
||||||
|
|
||||||
|
new-interactions
|
||||||
|
(update interactions index
|
||||||
|
#(cti/set-overlay-position % overlay-pos))]
|
||||||
|
|
||||||
|
(rx/of (update-shape (:id shape) {:interactions new-interactions}))))))
|
||||||
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; CANVAS OPTIONS
|
;; CANVAS OPTIONS
|
||||||
|
|
|
@ -101,6 +101,13 @@
|
||||||
(def play (icon-xref :play))
|
(def play (icon-xref :play))
|
||||||
(def plus (icon-xref :plus))
|
(def plus (icon-xref :plus))
|
||||||
(def pointer-inner (icon-xref :pointer-inner))
|
(def pointer-inner (icon-xref :pointer-inner))
|
||||||
|
(def position-bottom-center (icon-xref :position-bottom-center))
|
||||||
|
(def position-bottom-left (icon-xref :position-bottom-left))
|
||||||
|
(def position-bottom-right (icon-xref :position-bottom-right))
|
||||||
|
(def position-center (icon-xref :position-center))
|
||||||
|
(def position-top-center (icon-xref :position-top-center))
|
||||||
|
(def position-top-left (icon-xref :position-top-left))
|
||||||
|
(def position-top-right (icon-xref :position-top-right))
|
||||||
(def radius (icon-xref :radius))
|
(def radius (icon-xref :radius))
|
||||||
(def radius-1 (icon-xref :radius-1))
|
(def radius-1 (icon-xref :radius-1))
|
||||||
(def radius-4 (icon-xref :radius-4))
|
(def radius-4 (icon-xref :radius-4))
|
||||||
|
|
|
@ -33,11 +33,6 @@
|
||||||
:height (* height zoom)
|
:height (* height zoom)
|
||||||
:vbox (str "0 0 " width " " height)}))
|
: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
|
(mf/defc viewer
|
||||||
[{:keys [params data]}]
|
[{:keys [params data]}]
|
||||||
|
|
||||||
|
@ -70,7 +65,12 @@
|
||||||
(mf/deps section)
|
(mf/deps section)
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(when (= section :comments)
|
(when (= section :comments)
|
||||||
(st/emit! (dcm/close-thread)))))]
|
(st/emit! (dcm/close-thread)))))
|
||||||
|
|
||||||
|
close-overlay
|
||||||
|
(mf/use-callback
|
||||||
|
(fn [frame]
|
||||||
|
(st/emit! (dv/close-overlay (:id frame)))))]
|
||||||
|
|
||||||
(hooks/use-shortcuts ::viewer sc/shortcuts)
|
(hooks/use-shortcuts ::viewer sc/shortcuts)
|
||||||
|
|
||||||
|
@ -125,7 +125,6 @@
|
||||||
:section section
|
:section section
|
||||||
:local local}]
|
:local local}]
|
||||||
|
|
||||||
|
|
||||||
[:div.viewport-container
|
[:div.viewport-container
|
||||||
{:style {:width (:width size)
|
{:style {:width (:width size)
|
||||||
:height (:height size)
|
:height (:height size)
|
||||||
|
@ -147,21 +146,32 @@
|
||||||
:local local}]
|
:local local}]
|
||||||
|
|
||||||
(for [overlay (:overlays local)]
|
(for [overlay (:overlays local)]
|
||||||
(let [size-over (calculate-size overlay zoom)
|
(let [size-over (calculate-size (:frame overlay) zoom)]
|
||||||
pos-over (position-overlay size size-over)]
|
[:*
|
||||||
[:div.viewport-container
|
(when (or (:close-click-outside overlay)
|
||||||
{:style {:width (:width size-over)
|
(:background-overlay overlay))
|
||||||
:height (:height size-over)
|
[:div.viewer-overlay-background
|
||||||
:position "absolute"
|
{:class (dom/classnames
|
||||||
:left (:x pos-over)
|
:visible (:background-overlay overlay))
|
||||||
:top (:y pos-over)}}
|
:style {:width (:width frame)
|
||||||
[:& interactions/viewport
|
:height (:height frame)
|
||||||
{:frame overlay
|
:position "absolute"
|
||||||
:size size-over
|
:left 0
|
||||||
:page page
|
:top 0}
|
||||||
:file file
|
:on-click #(when (:close-click-outside overlay)
|
||||||
:users users
|
(close-overlay (:frame overlay)))}])
|
||||||
:local local}]]))]))]]]))
|
[:div.viewport-container.viewer-overlay
|
||||||
|
{:style {:width (:width size-over)
|
||||||
|
:height (:height size-over)
|
||||||
|
:left (* (:x (:position overlay)) zoom)
|
||||||
|
:top (* (:y (:position overlay)) zoom)}}
|
||||||
|
[:& interactions/viewport
|
||||||
|
{:frame (:frame overlay)
|
||||||
|
:size size-over
|
||||||
|
:page page
|
||||||
|
:file file
|
||||||
|
:users users
|
||||||
|
:local local}]]]))]))]]]))
|
||||||
|
|
||||||
;; --- Component: Viewer Page
|
;; --- Component: Viewer Page
|
||||||
|
|
||||||
|
|
|
@ -39,9 +39,15 @@
|
||||||
(st/emit! (dv/go-to-frame frame-id)))
|
(st/emit! (dv/go-to-frame frame-id)))
|
||||||
|
|
||||||
:open-overlay
|
:open-overlay
|
||||||
(let [frame-id (:destination interaction)]
|
(let [frame-id (:destination interaction)
|
||||||
|
position (:overlay-position interaction)
|
||||||
|
close-click-outside (:close-click-outside interaction)
|
||||||
|
background-overlay (:background-overlay interaction)]
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(st/emit! (dv/open-overlay frame-id)))
|
(st/emit! (dv/open-overlay frame-id
|
||||||
|
position
|
||||||
|
close-click-outside
|
||||||
|
background-overlay)))
|
||||||
|
|
||||||
:close-overlay
|
:close-overlay
|
||||||
(let [frame-id (or (:destination interaction)
|
(let [frame-id (or (:destination interaction)
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.pages :as cp]
|
[app.common.pages :as cp]
|
||||||
[app.common.pages.spec :as spec]
|
[app.common.types.interactions :as cti]
|
||||||
[app.common.uuid :as uuid]
|
[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]
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
(defn- event-type-names
|
(defn- event-type-names
|
||||||
[]
|
[]
|
||||||
{:click (tr "workspace.options.interaction-on-click")
|
{:click (tr "workspace.options.interaction-on-click")
|
||||||
:hover (tr "workspace.options.interaction-while-hovering")})
|
:mouse-over (tr "workspace.options.interaction-while-hovering")})
|
||||||
|
|
||||||
(defn- event-type-name
|
(defn- event-type-name
|
||||||
[interaction]
|
[interaction]
|
||||||
|
@ -31,7 +31,8 @@
|
||||||
[]
|
[]
|
||||||
{:navigate (tr "workspace.options.interaction-navigate-to")
|
{:navigate (tr "workspace.options.interaction-navigate-to")
|
||||||
:open-overlay (tr "workspace.options.interaction-open-overlay")
|
:open-overlay (tr "workspace.options.interaction-open-overlay")
|
||||||
:close-overlay (tr "workspace.options.interaction-close-overlay")})
|
:close-overlay (tr "workspace.options.interaction-close-overlay")
|
||||||
|
:prev-screen (tr "workspace.options.interaction-prev-screen")})
|
||||||
|
|
||||||
(defn- action-summary
|
(defn- action-summary
|
||||||
[interaction destination]
|
[interaction destination]
|
||||||
|
@ -44,6 +45,17 @@
|
||||||
(get destination :name (tr "workspace.options.interaction-self")))
|
(get destination :name (tr "workspace.options.interaction-self")))
|
||||||
"--"))
|
"--"))
|
||||||
|
|
||||||
|
(defn- overlay-pos-type-names
|
||||||
|
[]
|
||||||
|
{:manual (tr "workspace.options.interaction-pos-manual")
|
||||||
|
:center (tr "workspace.options.interaction-pos-center")
|
||||||
|
:top-left (tr "workspace.options.interaction-pos-top-left")
|
||||||
|
:top-right (tr "workspace.options.interaction-pos-top-right")
|
||||||
|
:top-center (tr "workspace.options.interaction-pos-top-center")
|
||||||
|
:bottom-left (tr "workspace.options.interaction-pos-bottom-left")
|
||||||
|
:bottom-right (tr "workspace.options.interaction-pos-bottom-right")
|
||||||
|
:bottom-center (tr "workspace.options.interaction-pos-bottom-center")})
|
||||||
|
|
||||||
(mf/defc interaction-entry
|
(mf/defc interaction-entry
|
||||||
[{:keys [index shape interaction update-interaction remove-interaction]}]
|
[{:keys [index shape interaction update-interaction remove-interaction]}]
|
||||||
(let [objects (deref refs/workspace-page-objects)
|
(let [objects (deref refs/workspace-page-objects)
|
||||||
|
@ -51,60 +63,139 @@
|
||||||
frames (mf/use-memo (mf/deps objects)
|
frames (mf/use-memo (mf/deps objects)
|
||||||
#(cp/select-frames objects))
|
#(cp/select-frames objects))
|
||||||
|
|
||||||
|
action-type (:action-type interaction)
|
||||||
|
overlay-pos-type (:overlay-pos-type interaction)
|
||||||
|
close-click-outside? (:close-click-outside interaction false)
|
||||||
|
background-overlay? (:background-overlay interaction false)
|
||||||
|
|
||||||
extended-open? (mf/use-state false)
|
extended-open? (mf/use-state false)
|
||||||
|
|
||||||
change-event-type
|
change-event-type
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [value (-> event dom/get-target dom/get-value d/read-string)]
|
(let [value (-> event dom/get-target dom/get-value d/read-string)]
|
||||||
(update-interaction index #(assoc % :event-type value))))
|
(update-interaction index #(cti/set-event-type % value))))
|
||||||
|
|
||||||
change-action-type
|
change-action-type
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [value (-> event dom/get-target dom/get-value d/read-string)]
|
(let [value (-> event dom/get-target dom/get-value d/read-string)]
|
||||||
(update-interaction index #(assoc % :action-type value))))
|
(update-interaction index #(cti/set-action-type % value shape objects))))
|
||||||
|
|
||||||
change-destination
|
change-destination
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [value (-> event dom/get-target dom/get-value)
|
(let [value (-> event dom/get-target dom/get-value)
|
||||||
value (when (not= value "") (uuid/uuid value))]
|
value (when (not= value "") (uuid/uuid value))]
|
||||||
(update-interaction index #(assoc % :destination value))))]
|
(update-interaction index #(cti/set-destination % value shape objects))))
|
||||||
|
|
||||||
|
change-overlay-pos-type
|
||||||
|
(fn [event]
|
||||||
|
(let [value (-> event dom/get-target dom/get-value d/read-string)]
|
||||||
|
(update-interaction index #(cti/set-overlay-pos-type % value shape objects))))
|
||||||
|
|
||||||
|
toggle-overlay-pos-type
|
||||||
|
(fn [pos-type]
|
||||||
|
(update-interaction index #(cti/toggle-overlay-pos-type % pos-type shape objects)))
|
||||||
|
|
||||||
|
change-close-click-outside
|
||||||
|
(fn [event]
|
||||||
|
(let [value (-> event dom/get-target dom/checked?)]
|
||||||
|
(update-interaction index #(cti/set-close-click-outside % value))))
|
||||||
|
|
||||||
|
change-background-overlay
|
||||||
|
(fn [event]
|
||||||
|
(let [value (-> event dom/get-target dom/checked?)]
|
||||||
|
(update-interaction index #(cti/set-background-overlay % value))))]
|
||||||
|
|
||||||
[:*
|
[:*
|
||||||
[:div.element-set-options-group
|
[:div.element-set-options-group {:class (dom/classnames
|
||||||
|
:open @extended-open?)}
|
||||||
[:div.element-set-actions-button {:on-click #(swap! extended-open? not)}
|
[:div.element-set-actions-button {:on-click #(swap! extended-open? not)}
|
||||||
i/actions]
|
i/actions]
|
||||||
[:div.interactions-summary
|
[:div.interactions-summary {:on-click #(swap! extended-open? not)}
|
||||||
[:div.trigger-name (event-type-name interaction)]
|
[:div.trigger-name (event-type-name interaction)]
|
||||||
[:div.action-summary (action-summary interaction destination)]]
|
[:div.action-summary (action-summary interaction destination)]]
|
||||||
[:div.elemen-set-actions {:on-click #(remove-interaction index)}
|
[:div.elemen-set-actions {:on-click #(remove-interaction index)}
|
||||||
[:div.element-set-actions-button i/minus]]]
|
[:div.element-set-actions-button i/minus]]
|
||||||
(when @extended-open?
|
(when @extended-open?
|
||||||
[:div.element-set
|
|
||||||
[:div.element-set-content
|
[:div.element-set-content
|
||||||
[:div.interactions-element
|
[:div.interactions-element.separator
|
||||||
[:span.element-set-subtitle.wide (tr "workspace.options.interaction-trigger")]
|
[:span.element-set-subtitle.wide (tr "workspace.options.interaction-trigger")]
|
||||||
[:select.input-select
|
[:select.input-select
|
||||||
{:default-value (str (:event-type interaction))
|
{:value (str (:event-type interaction))
|
||||||
:on-change change-event-type}
|
:on-change change-event-type}
|
||||||
(for [[value name] (event-type-names)]
|
(for [[value name] (event-type-names)]
|
||||||
[:option {:value (str value)} name])]]
|
[:option {:value (str value)} name])]]
|
||||||
[:div.interactions-element
|
[:div.interactions-element.separator
|
||||||
[:span.element-set-subtitle.wide (tr "workspace.options.interaction-action")]
|
[:span.element-set-subtitle.wide (tr "workspace.options.interaction-action")]
|
||||||
[:select.input-select
|
[:select.input-select
|
||||||
{:default-value (str (:action-type interaction))
|
{:value (str (:action-type interaction))
|
||||||
:on-change change-action-type}
|
:on-change change-action-type}
|
||||||
(for [[value name] (action-type-names)]
|
(for [[value name] (action-type-names)]
|
||||||
[:option {:value (str value)} name])]]
|
[:option {:value (str value)} name])]]
|
||||||
[:div.interactions-element
|
(when (#{:navigate :open-overlay :close-overlay} action-type)
|
||||||
|
[:div.interactions-element
|
||||||
[:span.element-set-subtitle.wide (tr "workspace.options.interaction-destination")]
|
[:span.element-set-subtitle.wide (tr "workspace.options.interaction-destination")]
|
||||||
[:select.input-select
|
[:select.input-select
|
||||||
{:default-value (str (:destination interaction))
|
{:value (str (:destination interaction))
|
||||||
:on-change change-destination}
|
:on-change change-destination}
|
||||||
[:option {:value ""} (tr "workspace.options.interaction-none")]
|
[:option {:value ""} (tr "workspace.options.interaction-none")]
|
||||||
(for [frame frames]
|
(for [frame frames]
|
||||||
(when (and (not= (:id frame) (:id shape)) ; A frame cannot navigate to itself
|
(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
|
(not= (:id frame) (:frame-id shape))) ; nor a shape to its container frame
|
||||||
[:option {:value (str (:id frame))} (:name frame)]))]]]])]))
|
[:option {:value (str (:id frame))} (:name frame)]))]])
|
||||||
|
(when (= action-type :open-overlay)
|
||||||
|
[:*
|
||||||
|
[:div.interactions-element
|
||||||
|
[:span.element-set-subtitle.wide (tr "workspace.options.interaction-position")]
|
||||||
|
[:select.input-select
|
||||||
|
{:value (str (:overlay-pos-type interaction))
|
||||||
|
:on-change change-overlay-pos-type}
|
||||||
|
(for [[value name] (overlay-pos-type-names)]
|
||||||
|
[:option {:value (str value)} name])]]
|
||||||
|
[:div.interactions-element.interactions-pos-buttons
|
||||||
|
[:div.element-set-actions-button
|
||||||
|
{:class (dom/classnames :active (= overlay-pos-type :center))
|
||||||
|
:on-click #(toggle-overlay-pos-type :center)}
|
||||||
|
i/position-center]
|
||||||
|
[:div.element-set-actions-button
|
||||||
|
{:class (dom/classnames :active (= overlay-pos-type :top-left))
|
||||||
|
:on-click #(toggle-overlay-pos-type :top-left)}
|
||||||
|
i/position-top-left]
|
||||||
|
[:div.element-set-actions-button
|
||||||
|
{:class (dom/classnames :active (= overlay-pos-type :top-right))
|
||||||
|
:on-click #(toggle-overlay-pos-type :top-right)}
|
||||||
|
i/position-top-right]
|
||||||
|
[:div.element-set-actions-button
|
||||||
|
{:class (dom/classnames :active (= overlay-pos-type :top-center))
|
||||||
|
:on-click #(toggle-overlay-pos-type :top-center)}
|
||||||
|
i/position-top-center]
|
||||||
|
[:div.element-set-actions-button
|
||||||
|
{:class (dom/classnames :active (= overlay-pos-type :bottom-left))
|
||||||
|
:on-click #(toggle-overlay-pos-type :bottom-left)}
|
||||||
|
i/position-bottom-left]
|
||||||
|
[:div.element-set-actions-button
|
||||||
|
{:class (dom/classnames :active (= overlay-pos-type :bottom-right))
|
||||||
|
:on-click #(toggle-overlay-pos-type :bottom-right)}
|
||||||
|
i/position-bottom-right]
|
||||||
|
[:div.element-set-actions-button
|
||||||
|
{:class (dom/classnames :active (= overlay-pos-type :bottom-center))
|
||||||
|
:on-click #(toggle-overlay-pos-type :bottom-center)}
|
||||||
|
i/position-bottom-center]]
|
||||||
|
[:div.interactions-element
|
||||||
|
[:div.input-checkbox
|
||||||
|
[:input {:type "checkbox"
|
||||||
|
:id (str "close-" index)
|
||||||
|
:checked close-click-outside?
|
||||||
|
:on-change change-close-click-outside}]
|
||||||
|
[:label {:for (str "close-" index)}
|
||||||
|
(tr "workspace.options.interaction-close-outside")]]]
|
||||||
|
[:div.interactions-element
|
||||||
|
[:div.input-checkbox
|
||||||
|
[:input {:type "checkbox"
|
||||||
|
:id (str "background-" index)
|
||||||
|
:checked background-overlay?
|
||||||
|
:on-change change-background-overlay}]
|
||||||
|
[:label {:for (str "background-" index)}
|
||||||
|
(tr "workspace.options.interaction-background")]]]])])]]))
|
||||||
|
|
||||||
(mf/defc interactions-menu
|
(mf/defc interactions-menu
|
||||||
[{:keys [shape] :as props}]
|
[{:keys [shape] :as props}]
|
||||||
|
@ -112,8 +203,7 @@
|
||||||
|
|
||||||
add-interaction
|
add-interaction
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(let [new-interactions
|
(let [new-interactions (conj interactions cti/default-interaction)]
|
||||||
(conj interactions (update spec/default-interaction :event-type identity))]
|
|
||||||
(st/emit! (dw/update-shape (:id shape) {:interactions new-interactions}))))
|
(st/emit! (dw/update-shape (:id shape) {:interactions new-interactions}))))
|
||||||
|
|
||||||
remove-interaction
|
remove-interaction
|
||||||
|
@ -128,7 +218,7 @@
|
||||||
(let [new-interactions (update interactions index update-fn)]
|
(let [new-interactions (update interactions index update-fn)]
|
||||||
(st/emit! (dw/update-shape (:id shape) {:interactions new-interactions})))) ]
|
(st/emit! (dw/update-shape (:id shape) {:interactions new-interactions})))) ]
|
||||||
|
|
||||||
[:div.element-set
|
[:div.element-set.interactions-options
|
||||||
(when shape
|
(when shape
|
||||||
[:div.element-set-title
|
[:div.element-set-title
|
||||||
[:span (tr "workspace.options.interactions")]
|
[:span (tr "workspace.options.interactions")]
|
||||||
|
@ -141,15 +231,16 @@
|
||||||
(when shape
|
(when shape
|
||||||
[:*
|
[:*
|
||||||
[:div.interactions-help-icon i/plus]
|
[:div.interactions-help-icon i/plus]
|
||||||
[:div.interactions-help (tr "workspace.options.add-interaction")]])
|
[:div.interactions-help.separator (tr "workspace.options.add-interaction")]])
|
||||||
[:div.interactions-help-icon i/interaction]
|
[:div.interactions-help-icon i/interaction]
|
||||||
[:div.interactions-help (tr "workspace.options.select-a-shape")]
|
[:div.interactions-help (tr "workspace.options.select-a-shape")]
|
||||||
[:div.interactions-help-icon i/play]
|
[:div.interactions-help-icon i/play]
|
||||||
[:div.interactions-help (tr "workspace.options.use-play-button")]])]
|
[:div.interactions-help (tr "workspace.options.use-play-button")]])]
|
||||||
(for [[index interaction] (d/enumerate interactions)]
|
[:div.groups
|
||||||
[:& interaction-entry {:index index
|
(for [[index interaction] (d/enumerate interactions)]
|
||||||
:shape shape
|
[:& interaction-entry {:index index
|
||||||
:interaction interaction
|
:shape shape
|
||||||
:update-interaction update-interaction
|
:interaction interaction
|
||||||
:remove-interaction remove-interaction}])]))
|
:update-interaction update-interaction
|
||||||
|
:remove-interaction remove-interaction}])]]))
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
"Visually show shape interactions in workspace"
|
"Visually show shape interactions in workspace"
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
|
[app.common.pages.helpers :as cph]
|
||||||
[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]
|
||||||
|
@ -86,11 +87,8 @@
|
||||||
:right "M -5 0 l 8 0 l -4 -4 m 4 4 l -4 4"
|
: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"
|
:left "M 5 0 l -8 0 l 4 -4 m -4 4 l 4 4"
|
||||||
nil)
|
nil)
|
||||||
:open-overlay (case arrow-dir
|
|
||||||
;; TODO: have a different icon for open overlay?
|
:open-overlay "M-4 -4 h6 v6 h-6 z M2 -2 h2.5 v6.5 h-6.5 v-2.5"
|
||||||
: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"
|
:close-overlay "M -4 -4 L 4 4 M -4 4 L 4 -4"
|
||||||
|
|
||||||
|
@ -99,17 +97,15 @@
|
||||||
[:*
|
[:*
|
||||||
[:circle {:cx 0
|
[:circle {:cx 0
|
||||||
:cy 0
|
:cy 0
|
||||||
:r 8
|
:r (if (some? action-type) 8 4)
|
||||||
:stroke stroke
|
:fill stroke
|
||||||
:stroke-width 2
|
|
||||||
:fill "#FFFFFF"
|
|
||||||
:transform (str
|
:transform (str
|
||||||
"scale(" inv-zoom ", " inv-zoom ") "
|
"scale(" inv-zoom ", " inv-zoom ") "
|
||||||
"translate(" (* zoom x) ", " (* zoom y) ")")}]
|
"translate(" (* zoom x) ", " (* zoom y) ")")}]
|
||||||
(when icon-pdata
|
(when icon-pdata
|
||||||
[:path {:stroke stroke
|
[:path {:fill stroke
|
||||||
:fill "none"
|
:stroke-width 1
|
||||||
:stroke-width 2
|
:stroke "#FFFFFF"
|
||||||
:d icon-pdata
|
:d icon-pdata
|
||||||
:transform (str
|
:transform (str
|
||||||
"scale(" inv-zoom ", " inv-zoom ") "
|
"scale(" inv-zoom ", " inv-zoom ") "
|
||||||
|
@ -117,7 +113,7 @@
|
||||||
|
|
||||||
|
|
||||||
(mf/defc interaction-path
|
(mf/defc interaction-path
|
||||||
[{:keys [index orig-shape dest-shape dest-point selected? action-type zoom] :as props}]
|
[{:keys [index level 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]
|
(let [[orig-pos orig-x orig-y dest-pos dest-x dest-y]
|
||||||
(cond
|
(cond
|
||||||
dest-shape
|
dest-shape
|
||||||
|
@ -129,7 +125,8 @@
|
||||||
:else
|
:else
|
||||||
(connect-to-point orig-shape
|
(connect-to-point orig-shape
|
||||||
{:x (+ (:x2 (:selrect orig-shape)) 100)
|
{:x (+ (:x2 (:selrect orig-shape)) 100)
|
||||||
:y (- (:y1 (:selrect orig-shape)) 50)}))
|
:y (+ (- (:y1 (:selrect orig-shape)) 50)
|
||||||
|
(* level 16))}))
|
||||||
|
|
||||||
orig-dx (if (= orig-pos :right) 100 -100)
|
orig-dx (if (= orig-pos :right) 100 -100)
|
||||||
dest-dx (if (= dest-pos :right) 100 -100)
|
dest-dx (if (= dest-pos :right) 100 -100)
|
||||||
|
@ -146,8 +143,7 @@
|
||||||
:pointer-events "visible"
|
:pointer-events "visible"
|
||||||
:stroke-width (/ 2 zoom)
|
:stroke-width (/ 2 zoom)
|
||||||
:d pdata}]
|
:d pdata}]
|
||||||
(when (and (not dest-shape)
|
(when (not dest-shape)
|
||||||
(= action-type :close-overlay))
|
|
||||||
[:& interaction-marker {:index index
|
[:& interaction-marker {:index index
|
||||||
:x dest-x
|
:x dest-x
|
||||||
:y dest-y
|
:y dest-y
|
||||||
|
@ -162,6 +158,11 @@
|
||||||
:pointer-events "visible"
|
:pointer-events "visible"
|
||||||
:stroke-width (/ 2 zoom)
|
:stroke-width (/ 2 zoom)
|
||||||
:d pdata}]
|
:d pdata}]
|
||||||
|
|
||||||
|
(when dest-shape
|
||||||
|
[:& outline {:shape dest-shape
|
||||||
|
:color "#31EFB8"}])
|
||||||
|
|
||||||
[:& interaction-marker {:index index
|
[:& interaction-marker {:index index
|
||||||
:x orig-x
|
:x orig-x
|
||||||
:y orig-y
|
:y orig-y
|
||||||
|
@ -173,11 +174,7 @@
|
||||||
:stroke "#31EFB8"
|
:stroke "#31EFB8"
|
||||||
:action-type action-type
|
:action-type action-type
|
||||||
:arrow-dir arrow-dir
|
:arrow-dir arrow-dir
|
||||||
:zoom zoom}]
|
:zoom zoom}]])))
|
||||||
|
|
||||||
(when dest-shape
|
|
||||||
[:& outline {:shape dest-shape
|
|
||||||
:color "#31EFB8"}])])))
|
|
||||||
|
|
||||||
|
|
||||||
(mf/defc interaction-handle
|
(mf/defc interaction-handle
|
||||||
|
@ -194,6 +191,37 @@
|
||||||
:zoom zoom}]]))
|
:zoom zoom}]]))
|
||||||
|
|
||||||
|
|
||||||
|
(mf/defc overlay-marker
|
||||||
|
[{:keys [index orig-shape dest-shape position objects] :as props}]
|
||||||
|
(let [start-move-position
|
||||||
|
(fn [_]
|
||||||
|
(st/emit! (dw/start-move-overlay-pos index)))]
|
||||||
|
|
||||||
|
(when dest-shape
|
||||||
|
(let [orig-frame (cph/get-frame orig-shape objects)
|
||||||
|
marker-x (+ (:x orig-frame) (:x position))
|
||||||
|
marker-y (+ (:y orig-frame) (:y position))
|
||||||
|
width (:width dest-shape)
|
||||||
|
height (:height dest-shape)]
|
||||||
|
[:g {:on-mouse-down start-move-position}
|
||||||
|
[:path {:stroke "#31EFB8"
|
||||||
|
:fill "#000000"
|
||||||
|
:fill-opacity 0.3
|
||||||
|
:stroke-width 1
|
||||||
|
:d (str "M" marker-x " " marker-y " "
|
||||||
|
"h " width " "
|
||||||
|
"v " height " "
|
||||||
|
"h -" width " z"
|
||||||
|
"M" marker-x " " marker-y " "
|
||||||
|
"l " width " " height " "
|
||||||
|
"M" marker-x " " (+ marker-y height) " "
|
||||||
|
"l " width " -" height " ")}]
|
||||||
|
[:circle {:cx (+ marker-x (/ width 2))
|
||||||
|
:cy (+ marker-y (/ height 2))
|
||||||
|
:r 8
|
||||||
|
:fill "#31EFB8"}]
|
||||||
|
]))))
|
||||||
|
|
||||||
(mf/defc interactions
|
(mf/defc interactions
|
||||||
[{:keys [selected] :as props}]
|
[{:keys [selected] :as props}]
|
||||||
(let [local (mf/deref refs/workspace-local)
|
(let [local (mf/deref refs/workspace-local)
|
||||||
|
@ -205,17 +233,26 @@
|
||||||
editing-interaction-index (:editing-interaction-index local)
|
editing-interaction-index (:editing-interaction-index local)
|
||||||
draw-interaction-to (:draw-interaction-to local)
|
draw-interaction-to (:draw-interaction-to local)
|
||||||
draw-interaction-to-frame (:draw-interaction-to-frame local)
|
draw-interaction-to-frame (:draw-interaction-to-frame local)
|
||||||
first-selected (first selected-shapes)]
|
move-overlay-to (:move-overlay-to local)
|
||||||
|
move-overlay-index (:move-overlay-index local)
|
||||||
|
first-selected (first selected-shapes)
|
||||||
|
|
||||||
|
calc-level (fn [index interactions]
|
||||||
|
(->> (subvec interactions 0 index)
|
||||||
|
(filter #(nil? (:destination %)))
|
||||||
|
(count)))]
|
||||||
|
|
||||||
[:g.interactions
|
[:g.interactions
|
||||||
[:g.non-selected
|
[:g.non-selected
|
||||||
(for [shape active-shapes]
|
(for [shape active-shapes]
|
||||||
(for [[index interaction] (d/enumerate (:interactions shape))]
|
(for [[index interaction] (d/enumerate (:interactions shape))]
|
||||||
(let [dest-shape (get objects (:destination interaction))
|
(let [dest-shape (get objects (:destination interaction))
|
||||||
selected? (contains? selected (:id shape))]
|
selected? (contains? selected (:id shape))
|
||||||
|
level (calc-level index (:interactions shape))]
|
||||||
(when-not selected?
|
(when-not selected?
|
||||||
[:& interaction-path {:key (str (:id shape) "-" index)
|
[:& interaction-path {:key (str (:id shape) "-" index)
|
||||||
:index index
|
:index index
|
||||||
|
:level level
|
||||||
:orig-shape shape
|
:orig-shape shape
|
||||||
:dest-shape dest-shape
|
:dest-shape dest-shape
|
||||||
:selected selected
|
:selected selected
|
||||||
|
@ -237,15 +274,33 @@
|
||||||
(if (seq (:interactions shape))
|
(if (seq (:interactions shape))
|
||||||
(for [[index interaction] (d/enumerate (:interactions shape))]
|
(for [[index interaction] (d/enumerate (:interactions shape))]
|
||||||
(when-not (= index editing-interaction-index)
|
(when-not (= index editing-interaction-index)
|
||||||
(let [dest-shape (get objects (:destination interaction))]
|
(let [dest-shape (get objects (:destination interaction))
|
||||||
[:& interaction-path {:key (str (:id shape) "-" index)
|
level (calc-level index (:interactions shape))]
|
||||||
:index index
|
[:*
|
||||||
:orig-shape shape
|
[:& interaction-path {:key (str (:id shape) "-" index)
|
||||||
:dest-shape dest-shape
|
:index index
|
||||||
:selected selected
|
:level level
|
||||||
:selected? true
|
:orig-shape shape
|
||||||
:action-type (:action-type interaction)
|
:dest-shape dest-shape
|
||||||
:zoom zoom}])))
|
:selected selected
|
||||||
|
:selected? true
|
||||||
|
:action-type (:action-type interaction)
|
||||||
|
:zoom zoom}]
|
||||||
|
(when (= (:action-type interaction) :open-overlay)
|
||||||
|
(if (and (some? move-overlay-to)
|
||||||
|
(= move-overlay-index index))
|
||||||
|
[:& overlay-marker {:key (str "pos" (:id shape) "-" index)
|
||||||
|
:index index
|
||||||
|
:orig-shape shape
|
||||||
|
:dest-shape dest-shape
|
||||||
|
:position move-overlay-to
|
||||||
|
:objects objects}]
|
||||||
|
[:& overlay-marker {:key (str "pos" (:id shape) "-" index)
|
||||||
|
:index index
|
||||||
|
:orig-shape shape
|
||||||
|
:dest-shape dest-shape
|
||||||
|
:position (:overlay-position interaction)
|
||||||
|
:objects objects}]))])))
|
||||||
(when (not (#{:move :rotate} current-transform))
|
(when (not (#{:move :rotate} current-transform))
|
||||||
[:& interaction-handle {:key (:id shape)
|
[:& interaction-handle {:key (:id shape)
|
||||||
:index nil
|
:index nil
|
||||||
|
|
|
@ -2405,6 +2405,14 @@ msgstr "Click the + button to add interactions."
|
||||||
msgid "workspace.options.interaction-action"
|
msgid "workspace.options.interaction-action"
|
||||||
msgstr "Action"
|
msgstr "Action"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-background"
|
||||||
|
msgstr "Add background overlay"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-close-outside"
|
||||||
|
msgstr "Close when clicking outside"
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
msgid "workspace.options.interaction-close-overlay"
|
msgid "workspace.options.interaction-close-overlay"
|
||||||
msgstr "Close overlay"
|
msgstr "Close overlay"
|
||||||
|
@ -2441,6 +2449,42 @@ msgstr "Open overlay"
|
||||||
msgid "workspace.options.interaction-open-overlay-dest"
|
msgid "workspace.options.interaction-open-overlay-dest"
|
||||||
msgstr "Open overlay: %s"
|
msgstr "Open overlay: %s"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-pos-manual"
|
||||||
|
msgstr "Manual"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-pos-center"
|
||||||
|
msgstr "Center"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-pos-top-left"
|
||||||
|
msgstr "Top left"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-pos-top-right"
|
||||||
|
msgstr "Top right"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-pos-top-center"
|
||||||
|
msgstr "Top center"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-pos-bottom-left"
|
||||||
|
msgstr "Bottom left"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-pos-bottom-right"
|
||||||
|
msgstr "Bottom right"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-pos-bottom-center"
|
||||||
|
msgstr "Bottom center"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-position"
|
||||||
|
msgstr "Position"
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
msgid "workspace.options.interaction-self"
|
msgid "workspace.options.interaction-self"
|
||||||
msgstr "self"
|
msgstr "self"
|
||||||
|
|
|
@ -2288,6 +2288,14 @@ msgstr "Pulsa el botón + para añadir interacciones."
|
||||||
msgid "workspace.options.interaction-action"
|
msgid "workspace.options.interaction-action"
|
||||||
msgstr "Acción"
|
msgstr "Acción"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-background"
|
||||||
|
msgstr "Añadir sombreado de fondo"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-close-outside"
|
||||||
|
msgstr "Cerrar al pulsar fuera"
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
msgid "workspace.options.interaction-close-overlay"
|
msgid "workspace.options.interaction-close-overlay"
|
||||||
msgstr "Close overlay"
|
msgstr "Close overlay"
|
||||||
|
@ -2324,6 +2332,42 @@ msgstr "Open overlay"
|
||||||
msgid "workspace.options.interaction-open-overlay-dest"
|
msgid "workspace.options.interaction-open-overlay-dest"
|
||||||
msgstr "Open overlay: %s"
|
msgstr "Open overlay: %s"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-pos-manual"
|
||||||
|
msgstr "Manual"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-pos-center"
|
||||||
|
msgstr "Centro"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-pos-top-left"
|
||||||
|
msgstr "Arriba izquierda"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-pos-top-right"
|
||||||
|
msgstr "Arriba derecha"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-pos-top-center"
|
||||||
|
msgstr "Arriba centro"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-pos-bottom-left"
|
||||||
|
msgstr "Abajo izquierda"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-pos-bottom-right"
|
||||||
|
msgstr "Abajo derecha"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-pos-bottom-center"
|
||||||
|
msgstr "Abajo centro"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
|
msgid "workspace.options.interaction-position"
|
||||||
|
msgstr "Posición"
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
|
||||||
msgid "workspace.options.interaction-self"
|
msgid "workspace.options.interaction-self"
|
||||||
msgstr "self"
|
msgstr "self"
|
||||||
|
|