From 64c0884eb9d0cdd892360787999e34e4772fe070 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 24 Sep 2020 16:55:50 +0200 Subject: [PATCH 1/6] :sparkles: Adds support for drop shadow --- .../styles/common/dependencies/helpers.scss | 5 + .../resources/styles/common/framework.scss | 8 +- .../partials/sidebar-element-options.scss | 41 +++- frontend/src/app/main/exports.cljs | 29 +-- frontend/src/app/main/ui/shapes/attrs.cljs | 3 +- .../src/app/main/ui/shapes/custom_stroke.cljs | 4 +- frontend/src/app/main/ui/shapes/filters.cljs | 77 +++++++ frontend/src/app/main/ui/viewer/shapes.cljs | 11 +- .../app/main/ui/workspace/shapes/common.cljs | 8 +- .../ui/workspace/sidebar/options/common.cljs | 24 +++ .../workspace/sidebar/options/frame_grid.cljs | 12 +- .../ui/workspace/sidebar/options/rect.cljs | 8 +- .../ui/workspace/sidebar/options/shadow.cljs | 195 ++++++++++++++++++ .../ui/workspace/sidebar/options/stroke.cljs | 2 +- frontend/src/app/util/dom.cljs | 4 + 15 files changed, 396 insertions(+), 35 deletions(-) create mode 100644 frontend/src/app/main/ui/shapes/filters.cljs create mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/common.cljs create mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs diff --git a/frontend/resources/styles/common/dependencies/helpers.scss b/frontend/resources/styles/common/dependencies/helpers.scss index 92c0c7494..e23f58b39 100644 --- a/frontend/resources/styles/common/dependencies/helpers.scss +++ b/frontend/resources/styles/common/dependencies/helpers.scss @@ -48,6 +48,11 @@ $br-big: 8px; } } +.row-grid-2 { + display: grid; + grid-template-columns: repeat(2, 1fr); +} + .flex-grow { flex-grow: 1; } diff --git a/frontend/resources/styles/common/framework.scss b/frontend/resources/styles/common/framework.scss index 9a725c916..c19e4a8cc 100644 --- a/frontend/resources/styles/common/framework.scss +++ b/frontend/resources/styles/common/framework.scss @@ -364,7 +364,8 @@ ul.slider-dots { position: relative; width: 75px; - &::after { + &::after, + .after { color: $color-gray-20; font-size: $fs12; height: 20px; @@ -374,6 +375,11 @@ ul.slider-dots { width: 20px; } + .after { + width: auto; + right: 6px; + } + // Input amounts &.pixels { diff --git a/frontend/resources/styles/main/partials/sidebar-element-options.scss b/frontend/resources/styles/main/partials/sidebar-element-options.scss index 229bc2408..4e6201959 100644 --- a/frontend/resources/styles/main/partials/sidebar-element-options.scss +++ b/frontend/resources/styles/main/partials/sidebar-element-options.scss @@ -468,8 +468,8 @@ } .color-th { - background-color: $color-gray-10; - border: 1px solid $color-gray-10; + background-color: $color-gray-30; + border: 1px solid $color-gray-30; border-radius: $br-small; cursor: pointer; display: flex; @@ -765,6 +765,7 @@ top: 0; width: 100%; opacity: 0.4; + z-index: 10; } .element-set-content .advanced-options { @@ -775,6 +776,7 @@ position: relative; top: 2px; width: calc(100% + 16px); + z-index: 20; } .btn-options { @@ -815,7 +817,8 @@ } } -.exports-options { +.exports-options, +.shadow-options{ .element-set-options-group { justify-content: space-between; .delete-icon { @@ -841,3 +844,35 @@ margin-top: 10px; } } + +.shadow-options .color-row-wrap { + margin-left: 6px; + margin-top: 0.5rem; +} + +.element-set-actions-button { + display: flex; + min-width: 30px; + min-height: 30px; + justify-content: center; + align-items: center; + cursor: pointer; + svg { + width: 16px; + height: 16px; + fill: $color-gray-20; + } + + &:hover svg { + fill: $color-primary; + } +} +.element-set-actions { + display: flex; + visibility: hidden; + +} + +.element-set-options-group:hover .element-set-actions { + visibility: visible; +} diff --git a/frontend/src/app/main/exports.cljs b/frontend/src/app/main/exports.cljs index 8a2105d67..89061114f 100644 --- a/frontend/src/app/main/exports.cljs +++ b/frontend/src/app/main/exports.cljs @@ -11,6 +11,7 @@ "The main logic for SVG export functionality." (:require [rumext.alpha :as mf] + [cuerdas.core :as str] [app.common.uuid :as uuid] [app.common.pages :as cp] [app.common.pages-helpers :as cph] @@ -18,6 +19,7 @@ [app.common.geom.shapes :as geom] [app.common.geom.point :as gpt] [app.common.geom.matrix :as gmt] + [app.main.ui.shapes.filters :as filters] [app.main.ui.shapes.frame :as frame] [app.main.ui.shapes.circle :as circle] [app.main.ui.shapes.icon :as icon] @@ -77,18 +79,21 @@ frame-wrapper (mf/use-memo (mf/deps objects) #(frame-wrapper-factory objects))] (when (and shape (not (:hidden shape))) (let [shape (geom/transform-shape frame shape) - opts #js {:shape shape}] - (case (:type shape) - :curve [:> path/path-shape opts] - :text [:> text/text-shape opts] - :icon [:> icon/icon-shape opts] - :rect [:> rect/rect-shape opts] - :path [:> path/path-shape opts] - :image [:> image/image-shape opts] - :circle [:> circle/circle-shape opts] - :frame [:> frame-wrapper {:shape shape}] - :group [:> group-wrapper {:shape shape :frame frame}] - nil)))))) + opts #js {:shape shape} + filter-id (filters/get-filter-id)] + [:g {:filter (filters/filter-str filter-id shape)} + [:& filters/filters {:filter-id filter-id :shape shape}] + (case (:type shape) + :curve [:> path/path-shape opts] + :text [:> text/text-shape opts] + :icon [:> icon/icon-shape opts] + :rect [:> rect/rect-shape opts] + :path [:> path/path-shape opts] + :image [:> image/image-shape opts] + :circle [:> circle/circle-shape opts] + :frame [:> frame-wrapper {:shape shape}] + :group [:> group-wrapper {:shape shape :frame frame}] + nil)]))))) (mf/defc page-svg {::mf/wrap [mf/memo]} diff --git a/frontend/src/app/main/ui/shapes/attrs.cljs b/frontend/src/app/main/ui/shapes/attrs.cljs index 52c028170..def3de31c 100644 --- a/frontend/src/app/main/ui/shapes/attrs.cljs +++ b/frontend/src/app/main/ui/shapes/attrs.cljs @@ -21,7 +21,8 @@ (defn extract-style-attrs [shape] (let [stroke-style (:stroke-style shape :none) - attrs #js {:fill (or (:fill-color shape) "transparent") + attrs #js {;:filter (when (not= :frame (:type shape)) (str "url(#filter_" (:id shape) ")")) + :fill (or (:fill-color shape) "transparent") :fillOpacity (:fill-opacity shape nil) :rx (:rx shape nil) :ry (:ry shape nil)}] diff --git a/frontend/src/app/main/ui/shapes/custom_stroke.cljs b/frontend/src/app/main/ui/shapes/custom_stroke.cljs index b2568e59d..ba0443536 100644 --- a/frontend/src/app/main/ui/shapes/custom_stroke.cljs +++ b/frontend/src/app/main/ui/shapes/custom_stroke.cljs @@ -7,6 +7,7 @@ (ns app.main.ui.shapes.custom-stroke (:require [rumext.alpha :as mf] + [app.common.uuid :as uuid] [app.common.geom.shapes :as geom] [app.util.object :as obj])) @@ -21,7 +22,8 @@ (let [shape (unchecked-get props "shape") base-props (unchecked-get props "base-props") elem-name (unchecked-get props "elem-name") - {:keys [id x y width height]} (geom/shape->rect-shape shape) + {:keys [x y width height]} (geom/shape->rect-shape shape) + id (uuid/next) stroke-style (:stroke-style shape :none) stroke-position (:stroke-alignment shape :center)] (cond diff --git a/frontend/src/app/main/ui/shapes/filters.cljs b/frontend/src/app/main/ui/shapes/filters.cljs new file mode 100644 index 000000000..d07db2cf7 --- /dev/null +++ b/frontend/src/app/main/ui/shapes/filters.cljs @@ -0,0 +1,77 @@ +;; 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/. +;; +;; This Source Code Form is "Incompatible With Secondary Licenses", as +;; defined by the Mozilla Public License, v. 2.0. +;; +;; Copyright (c) 2020 UXBOX Labs SL + +(ns app.main.ui.shapes.filters + (:require + [rumext.alpha :as mf] + [cuerdas.core :as str] + [app.util.color :as color] + [app.common.math :as mth] + [app.common.uuid :as uuid])) + +(defn get-filter-id [] + (str "filter_" (uuid/next))) + +(defn filter-str + [filter-id shape] + + (when (seq (:shadow shape)) + (str/fmt "url(#$0)" [filter-id]))) + +(mf/defc drop-shadow-filter + [{:keys [filter-id filter shape]}] + + (let [{:keys [x y width height]} (:selrect shape) + {:keys [fid color opacity offset-x offset-y blur spread]} filter + + filter-x (min x (+ x offset-x (- spread) (- blur) -5)) + filter-y (min y (+ y offset-y (- spread) (- blur) -5)) + filter-width (+ width (mth/abs offset-x) (* spread 2) (* blur 2) 10) + filter-height (+ height (mth/abs offset-x) (* spread 2) (* blur 2) 10) + + [r g b a] (color/hex->rgba color opacity) + [r g b] [(/ r 255) (/ g 255) (/ b 255)] + color-matrix (str/fmt "0 0 0 0 $0 0 0 0 0 $1 0 0 0 0 $2 0 0 0 $3 0" [r g b a])] + [:filter {:id filter-id + :x filter-x :y filter-y + :width filter-width :height filter-height + :filterUnits "userSpaceOnUse" + :color-interpolation-filters "sRGB"} + [:feFlood {:flood-opacity 0 :result "BackgroundImageFix"}] + [:feColorMatrix {:in "SourceAlpha" :type "matrix" + :values "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"}] + (when (> spread 0) + [:feMorphology {:radius spread + :operator "dilate" + :in "SourceAlpha" + :result "effect1_dropShadow"}]) + + [:feOffset {:dx offset-x :dy offset-y}] + [:feGaussianBlur {:stdDeviation (/ blur 2)}] + + [:feColorMatrix {:type "matrix" :values color-matrix}] + + [:feBlend {:mode "normal" + :in2 "BackgroundImageFix" + :result "effect1_dropShadow"}] + + [:feBlend {:mode "normal" + :in "SourceGraphic" + :in2 "effect1_dropShadow" + :result "shape"}]])) + +(mf/defc filters + [{:keys [filter-id shape]}] + [:defs + (for [{:keys [id type hidden] :as filter} (:shadow shape)] + (when (not hidden) + [:& drop-shadow-filter {:key id + :filter-id filter-id + :filter filter + :shape shape}]))]) diff --git a/frontend/src/app/main/ui/viewer/shapes.cljs b/frontend/src/app/main/ui/viewer/shapes.cljs index 35b0a75bf..c29d23f4d 100644 --- a/frontend/src/app/main/ui/viewer/shapes.cljs +++ b/frontend/src/app/main/ui/viewer/shapes.cljs @@ -11,12 +11,15 @@ "The main container for a frame in viewer mode" (:require [rumext.alpha :as mf] + [cuerdas.core :as str] + [app.common.uuid :as uuid] [app.common.data :as d] [app.common.pages :as cp] [app.common.pages-helpers :as cph] [app.main.data.viewer :as dv] [app.main.refs :as refs] [app.main.store :as st] + [app.main.ui.shapes.filters :as filters] [app.main.ui.shapes.circle :as circle] [app.main.ui.shapes.frame :as frame] [app.main.ui.shapes.group :as group] @@ -53,10 +56,14 @@ on-mouse-down (mf/use-callback (mf/deps shape) - #(on-mouse-down % shape))] + #(on-mouse-down % shape)) + + filter-id (filters/get-filter-id)] [:g.shape {:on-mouse-down on-mouse-down - :cursor (when (:interactions shape) "pointer")} + :cursor (when (:interactions shape) "pointer") + :filter (filters/filter-str filter-id shape)} + [:& filters/filters {:filter-id filter-id :shape shape}] [:& component {:shape shape :frame frame :childs childs diff --git a/frontend/src/app/main/ui/workspace/shapes/common.cljs b/frontend/src/app/main/ui/workspace/shapes/common.cljs index 1967e9dbe..662e89805 100644 --- a/frontend/src/app/main/ui/workspace/shapes/common.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/common.cljs @@ -14,6 +14,7 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.keyboard :as kbd] + [app.main.ui.shapes.filters :as filters] [app.util.dom :as dom] [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] @@ -69,9 +70,12 @@ #(on-mouse-down % shape)) on-context-menu (mf/use-callback (mf/deps shape) - #(on-context-menu % shape))] + #(on-context-menu % shape)) + filter-id (filters/get-filter-id)] [:g.shape {:on-mouse-down on-mouse-down - :on-context-menu on-context-menu} + :on-context-menu on-context-menu + :filter (filters/filter-str filter-id shape)} + [:& filters/filters {:filter-id filter-id :shape shape}] [:& component {:shape shape}]]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs new file mode 100644 index 000000000..9e3c803df --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs @@ -0,0 +1,24 @@ +;; 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/. +;; +;; This Source Code Form is "Incompatible With Secondary Licenses", as +;; defined by the Mozilla Public License, v. 2.0. +;; +;; Copyright (c) 2020 UXBOX Labs SL + +(ns app.main.ui.workspace.sidebar.options.common + (:require + [rumext.alpha :as mf] + [app.util.dom :as dom])) + +(mf/defc advanced-options [{:keys [visible? on-close children]}] + (let [handle-click (fn [event] (when on-close + (do (dom/stop-propagation event) + (on-close))))] + (when visible? + [:* + [:div.focus-overlay {:on-click handle-click}] + [:div.advanced-options {} + children]]))) + diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/frame_grid.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/frame_grid.cljs index 3848e7ea5..04e55265d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/frame_grid.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/frame_grid.cljs @@ -20,6 +20,7 @@ [app.main.data.workspace.grid :as dw] [app.util.geom.grid :as gg] [app.main.ui.icons :as i] + [app.main.ui.workspace.sidebar.options.common :refer [advanced-options]] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] [app.main.ui.workspace.sidebar.options.rows.input-row :refer [input-row]] [app.main.ui.components.select :refer [select]] @@ -30,16 +31,6 @@ (def workspace-saved-grids (l/derived :saved-grids refs/workspace-page-options)) -(mf/defc advanced-options [{:keys [visible? on-close children]}] - (when visible? - [:* - [:div.focus-overlay {:on-click #(when on-close - (do - (dom/stop-propagation %) - (on-close)))}] - [:div.advanced-options {} - children]])) - (defn- get-size-options [locale] [{:value :auto :label (t locale "workspace.options.grid.auto")} :separator @@ -254,3 +245,4 @@ :on-remove (handle-remove-grid index) :on-save-grid handle-save-grid}])])])) + diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rect.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rect.cljs index f74aff236..8e43aeac1 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rect.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rect.cljs @@ -12,7 +12,8 @@ [rumext.alpha :as mf] [app.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]] [app.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]] - [app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]])) + [app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]] + [app.main.ui.workspace.sidebar.options.shadow :refer [shadow-menu]])) (mf/defc options {::mf/wrap [mf/memo]} @@ -31,5 +32,8 @@ :values fill-values}] [:& stroke-menu {:ids ids :type type - :values stroke-values}]])) + :values stroke-values}] + [:& shadow-menu {:ids ids + :type type + :values (select-keys shape [:shadow])}]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs new file mode 100644 index 000000000..47ff7ef24 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs @@ -0,0 +1,195 @@ +;; 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/. +;; +;; This Source Code Form is "Incompatible With Secondary Licenses", as +;; defined by the Mozilla Public License, v. 2.0. +;; +;; Copyright (c) 2020 UXBOX Labs SL + +(ns app.main.ui.workspace.sidebar.options.shadow + (:require + [rumext.alpha :as mf] + [app.common.data :as d] + [app.common.uuid :as uuid] + [app.main.data.workspace.common :as dwc] + [app.main.store :as st] + [app.main.ui.icons :as i] + [app.main.ui.workspace.sidebar.options.common :refer [advanced-options]] + [app.main.ui.workspace.sidebar.options.rows.input-row :refer [input-row]] + [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] + [app.util.dom :as dom])) + +(defn create-shadow [] + (let [id (uuid/next)] + {:id id + :style :drop-shadow + :color "#000000" + :opacity 0.2 + :offset-x 4 + :offset-y 4 + :blur 4 + :spread 0 + :hidden false})) + +(defn valid-number? [value] + (or (number? value) (not (js/isNaN (js/parseInt value))))) + +(mf/defc shadow-entry + [{:keys [ids index value]}] + (let [open-shadow (mf/use-state false) + + basic-offset-x-ref (mf/use-ref nil) + basic-offset-y-ref (mf/use-ref nil) + basic-blur-ref (mf/use-ref nil) + + adv-offset-x-ref (mf/use-ref nil) + adv-offset-y-ref (mf/use-ref nil) + adv-blur-ref (mf/use-ref nil) + adv-spread-ref (mf/use-ref nil) + + remove-shadow-by-id + (fn [values id] (->> values (filterv (fn [s] (not= (:id s) id))))) + + + + on-remove-shadow + (fn [id] + (fn [] + (st/emit! (dwc/update-shapes ids #(update % :shadow remove-shadow-by-id id) )))) + + select-text + (fn [ref] (fn [event] (dom/select-text! (mf/ref-val ref)))) + + update-attr + (fn update-attr + ([index attr valid?] + (update-attr index attr valid? nil)) + + ([index attr valid? update-ref] + (fn [event] + (let [value (dom/get-value (dom/get-target event))] + (when (or (not valid?) (valid? value)) + (do + (when update-ref + (dom/set-value! (mf/ref-val update-ref) value)) + (st/emit! (dwc/update-shapes ids #(assoc-in % [:shadow index attr] (js/parseInt value 10)))))))))) + + update-color + (fn [index] + (fn [color opacity] + (st/emit! (dwc/update-shapes + ids + #(-> % + (assoc-in [:shadow index :color] color) + (assoc-in [:shadow index :opacity] opacity)))))) + + toggle-visibility + (fn [index] + (fn [] + (st/emit! (dwc/update-shapes ids #(update-in % [:shadow index :hidden] not)))))] + [:* + [:div.element-set-options-group + + [:div.element-set-actions-button + {:on-click #(reset! open-shadow true)} + i/actions] + + [:input.input-text {:type "number" + :ref basic-offset-x-ref + :on-change (update-attr index :offset-x valid-number?) + :on-click (select-text basic-offset-x-ref) + :default-value (:offset-x value)}] + [:input.input-text {:type "number" + :ref basic-offset-y-ref + :on-change (update-attr index :offset-y valid-number?) + :on-click (select-text basic-offset-y-ref) + :default-value (:offset-y value)}] + [:input.input-text {:type "number" + :ref basic-blur-ref + :on-click (select-text basic-blur-ref) + :on-change (update-attr index :blur valid-number?) + :min 0 + :default-value (:blur value)}] + + [:div.element-set-actions + [:div.element-set-actions-button {:on-click (toggle-visibility index)} + (if (:hidden value) i/eye-closed i/eye)] + [:div.element-set-actions-button {:on-click (on-remove-shadow (:id value))} + i/minus]]] + + [:& advanced-options {:visible? @open-shadow + :on-close #(reset! open-shadow false)} + [:div.row-grid-2 + [:select.input-select + [:option {:value ":drop-shadow"} "Drop shadow"] + #_[:option {:value ":inner-shadow"} "Inner shadow"]]] + + [:div.row-grid-2 + [:div.input-element + [:input.input-text {:type "number" + :ref adv-offset-x-ref + :no-validate true + :placeholder "--" + :on-click (select-text adv-offset-x-ref) + :on-change (update-attr index :offset-x valid-number? basic-offset-x-ref) + :default-value (:offset-x value)}] + [:span.after "X"]] + + [:div.input-element + [:input.input-text {:type "number" + :ref adv-offset-y-ref + :no-validate true + :placeholder "--" + :on-click (select-text adv-offset-y-ref) + :on-change (update-attr index :offset-y valid-number? basic-offset-y-ref) + :default-value (:offset-y value)}] + [:span.after "Y"]]] + + [:div.row-grid-2 + [:div.input-element + [:input.input-text {:type "number" + :ref adv-blur-ref + :no-validate true + :placeholder "--" + :on-click (select-text adv-blur-ref) + :on-change (update-attr index :blur valid-number? basic-blur-ref) + :min 0 + :default-value (:blur value)}] + [:span.after "Blur"]] + + [:div.input-element + [:input.input-text {:type "number" + :ref adv-spread-ref + :no-validate true + :placeholder "--" + :on-click (select-text adv-spread-ref) + :on-change (update-attr index :spread valid-number?) + :min 0 + :default-value (:spread value)}] + [:span.after "Spread"]]] + + [:div.color-row-wrap + [:& color-row {:color {:value (:color value) :opacity (:opacity value)} + :on-change (update-color index) + :on-open #(st/emit! dwc/start-undo-transaction) + :on-close #(st/emit! dwc/commit-undo-transaction)}]]]])) +(mf/defc shadow-menu + [{:keys [ids type values] :as props}] + + (.log js/console "values" (clj->js values)) + (let [on-add-shadow + (fn [] + (st/emit! (dwc/update-shapes ids #(update % :shadow (fnil conj []) (create-shadow)) )))] + [:div.element-set.shadow-options + [:div.element-set-title + [:span "Shadow"] + [:div.add-page {:on-click on-add-shadow} i/close]] + + (when (seq (:shadow values)) + [:div.element-set-content + (for [[index {:keys [id] :as value}] (d/enumerate (:shadow values []))] + [:& shadow-entry {:key (str "shadow-" id) + :ids ids + :value value + :index index}])])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/stroke.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/stroke.cljs index 29fb7b558..a8927137b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/stroke.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/stroke.cljs @@ -70,7 +70,7 @@ :group (t locale "workspace.options.group-stroke") (t locale "workspace.options.stroke")) - show-options (not= (or (:stroke-style values) :none) :none) + show-options (not= (:stroke-style values :none) :none) current-stroke-color {:value (:stroke-color values) :opacity (:stroke-opacity values) diff --git a/frontend/src/app/util/dom.cljs b/frontend/src/app/util/dom.cljs index dbc05d854..57ac2d37c 100644 --- a/frontend/src/app/util/dom.cljs +++ b/frontend/src/app/util/dom.cljs @@ -103,6 +103,10 @@ [node] (set! (.-value node) "")) +(defn set-value! + [node value] + (set! (.-value node) value)) + (defn select-text! [node] (.select node)) From 215c4fdb569bf91ab36c5e632465fdd4c5a42aaf Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 24 Sep 2020 21:00:25 +0200 Subject: [PATCH 2/6] :sparkles: Adds inner shadow filter --- frontend/src/app/main/ui/shapes/filters.cljs | 149 ++++++++++++++---- .../app/main/ui/workspace/shapes/common.cljs | 6 +- .../app/main/ui/workspace/shapes/frame.cljs | 8 +- .../ui/workspace/sidebar/options/circle.cljs | 8 +- .../ui/workspace/sidebar/options/frame.cljs | 6 +- .../ui/workspace/sidebar/options/shadow.cljs | 9 +- 6 files changed, 144 insertions(+), 42 deletions(-) diff --git a/frontend/src/app/main/ui/shapes/filters.cljs b/frontend/src/app/main/ui/shapes/filters.cljs index d07db2cf7..8b5a537d1 100644 --- a/frontend/src/app/main/ui/shapes/filters.cljs +++ b/frontend/src/app/main/ui/shapes/filters.cljs @@ -24,54 +24,141 @@ (when (seq (:shadow shape)) (str/fmt "url(#$0)" [filter-id]))) +(mf/defc color-matrix + [{:keys [color opacity]}] + (let [[r g b a] (color/hex->rgba color opacity) + [r g b] [(/ r 255) (/ g 255) (/ b 255)]] + [:feColorMatrix + {:type "matrix" + :values (str/fmt "0 0 0 0 $0 0 0 0 0 $1 0 0 0 0 $2 0 0 0 $3 0" [r g b a])}])) + (mf/defc drop-shadow-filter [{:keys [filter-id filter shape]}] (let [{:keys [x y width height]} (:selrect shape) - {:keys [fid color opacity offset-x offset-y blur spread]} filter - - filter-x (min x (+ x offset-x (- spread) (- blur) -5)) - filter-y (min y (+ y offset-y (- spread) (- blur) -5)) - filter-width (+ width (mth/abs offset-x) (* spread 2) (* blur 2) 10) - filter-height (+ height (mth/abs offset-x) (* spread 2) (* blur 2) 10) - - [r g b a] (color/hex->rgba color opacity) - [r g b] [(/ r 255) (/ g 255) (/ b 255)] - color-matrix (str/fmt "0 0 0 0 $0 0 0 0 0 $1 0 0 0 0 $2 0 0 0 $3 0" [r g b a])] - [:filter {:id filter-id - :x filter-x :y filter-y - :width filter-width :height filter-height - :filterUnits "userSpaceOnUse" - :color-interpolation-filters "sRGB"} - [:feFlood {:flood-opacity 0 :result "BackgroundImageFix"}] + {:keys [id in-filter color opacity offset-x offset-y blur spread]} filter] + [:* [:feColorMatrix {:in "SourceAlpha" :type "matrix" :values "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"}] (when (> spread 0) [:feMorphology {:radius spread :operator "dilate" :in "SourceAlpha" - :result "effect1_dropShadow"}]) + :result (str "filter" id)}]) + + [:feOffset {:dx offset-x :dy offset-y}] + [:feGaussianBlur {:stdDeviation (/ blur 2)}] + [:& color-matrix {:color color :opacity opacity}] + + [:feBlend {:mode "normal" + :in2 in-filter + :result (str "filter" id)}]])) + +(mf/defc inner-shadow-filter + [{:keys [filter-id filter shape]}] + + (let [{:keys [x y width height]} (:selrect shape) + {:keys [id in-filter color opacity offset-x offset-y blur spread]} filter] + [:* + [:feColorMatrix {:in "SourceAlpha" :type "matrix" + :values "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" + :result "hardAlpha"}] + + (when (> spread 0) + [:feMorphology {:radius spread + :operator "erode" + :in "SourceAlpha" + :result (str "filter" id)}]) [:feOffset {:dx offset-x :dy offset-y}] [:feGaussianBlur {:stdDeviation (/ blur 2)}] - [:feColorMatrix {:type "matrix" :values color-matrix}] + [:feComposite {:in2 "hardAlpha" + :operator "arithmetic" + :k2 "-1" + :k3 "1"}] + + [:& color-matrix {:color color :opacity opacity}] [:feBlend {:mode "normal" - :in2 "BackgroundImageFix" - :result "effect1_dropShadow"}] + :in2 in-filter + :result (str "filter" id)}]])) - [:feBlend {:mode "normal" - :in "SourceGraphic" - :in2 "effect1_dropShadow" - :result "shape"}]])) +(defn filter-bounds [shape filter] + (let [{:keys [x y width height]} (:selrect shape) + {:keys [offset-x offset-y blur spread] :or {offset-x 0 offset-y 0 blur 0 spread 0}} filter + filter-x (min x (+ x offset-x (- spread) (- blur) -5)) + filter-y (min y (+ y offset-y (- spread) (- blur) -5)) + filter-width (+ width (mth/abs offset-x) (* spread 2) (* blur 2) 10) + filter-height (+ height (mth/abs offset-x) (* spread 2) (* blur 2) 10)] + {:x1 filter-x + :y1 filter-y + :x2 (+ filter-x filter-width) + :y2 (+ filter-y filter-height)})) + +(defn get-filters-bounds + [shape filters] + + (let [filter-bounds (->> + filters + (filter #(= :drop-shadow (:type %))) + (map (partial filter-bounds shape) )) + x1 (apply min (:x1 filter-bounds)) + y1 (apply min (:y1 filter-bounds)) + x2 (apply max (:x2 filter-bounds)) + y2 (apply max (:y2 filter-bounds))] + [x1 y1 (- x2 x1) (- y2 y1)])) (mf/defc filters [{:keys [filter-id shape]}] - [:defs - (for [{:keys [id type hidden] :as filter} (:shadow shape)] - (when (not hidden) - [:& drop-shadow-filter {:key id - :filter-id filter-id - :filter filter - :shape shape}]))]) + + (let [add-in-filter + (fn [filter in-filter] + (assoc filter :in-filter in-filter)) + + filters (->> shape :shadow (filter (comp not :hidden))) + + [filter-x filter-y filter-width filter-height] (get-filters-bounds shape filters)] + (when (seq filters) + [:defs + [:filter {:id filter-id + :x filter-x :y filter-y + :width filter-width :height filter-height + :filterUnits "userSpaceOnUse" + :color-interpolation-filters "sRGB"} + + (let [;; Add as a paramter the input filter + drop-shadow-filters (->> filters (filter #(= :drop-shadow (:style %)))) + drop-shadow-filters (->> drop-shadow-filters + (map #(str "filter" (:id %))) + (concat ["BackgroundImageFix"]) + (map add-in-filter drop-shadow-filters)) + + inner-shadow-filters (->> filters (filter #(= :inner-shadow (:style %)))) + inner-shadow-filters (->> inner-shadow-filters + (map #(str "filter" (:id %))) + (concat ["shape"]) + (map add-in-filter inner-shadow-filters))] + + [:* + [:feFlood {:flood-opacity 0 :result "BackgroundImageFix"}] + (for [{:keys [id type] :as filter} drop-shadow-filters] + [:& drop-shadow-filter {:key id + :filter-id filter-id + :filter filter + :shape shape}]) + + [:feBlend {:mode "normal" + :in "SourceGraphic" + :in2 (if (seq drop-shadow-filters) + (str "filter" (:id (last drop-shadow-filters))) + "BackgroundImageFix") + :result "shape"}] + + (for [{:keys [id type] :as filter} inner-shadow-filters] + [:& inner-shadow-filter {:key id + :filter-id filter-id + :filter filter + :shape shape}]) + ]) + ]]))) diff --git a/frontend/src/app/main/ui/workspace/shapes/common.cljs b/frontend/src/app/main/ui/workspace/shapes/common.cljs index 662e89805..9aeaaacd4 100644 --- a/frontend/src/app/main/ui/workspace/shapes/common.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/common.cljs @@ -71,11 +71,11 @@ on-context-menu (mf/use-callback (mf/deps shape) #(on-context-menu % shape)) - filter-id (filters/get-filter-id)] + filter-id (mf/use-var (filters/get-filter-id))] [:g.shape {:on-mouse-down on-mouse-down :on-context-menu on-context-menu - :filter (filters/filter-str filter-id shape)} - [:& filters/filters {:filter-id filter-id :shape shape}] + :filter (filters/filter-str @filter-id shape)} + [:& filters/filters {:filter-id @filter-id :shape shape}] [:& component {:shape shape}]]))) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/shapes/frame.cljs index 19defafca..1e6702795 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -19,6 +19,7 @@ [app.main.ui.workspace.shapes.common :as common] [app.main.data.workspace.selection :as dws] [app.main.ui.shapes.frame :as frame] + [app.main.ui.shapes.filters :as filters] [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes :as geom] @@ -96,7 +97,9 @@ (mf/use-callback (mf/deps (:id shape)) (fn [] - (st/emit! (dws/change-hover-state (:id shape) false))))] + (st/emit! (dws/change-hover-state (:id shape) false)))) + + filter-id (filters/get-filter-id)] (when-not (:hidden shape) [:g {:class (when selected? "selected") @@ -121,7 +124,8 @@ :on-mouse-over on-mouse-over :on-mouse-out on-mouse-out} (:name shape)] - [:* + [:g.frame {:filter (filters/filter-str filter-id shape)} + [:& filters/filters {:filter-id filter-id :shape shape}] [:& frame-shape {:shape shape :childs children}]]]))))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/circle.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/circle.cljs index 287c2d9c2..3986c025c 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/circle.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/circle.cljs @@ -12,7 +12,8 @@ [rumext.alpha :as mf] [app.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]] [app.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]] - [app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]])) + [app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]] + [app.main.ui.workspace.sidebar.options.shadow :refer [shadow-menu]])) (mf/defc options [{:keys [shape] :as props}] @@ -30,4 +31,7 @@ :values (select-keys shape fill-attrs)}] [:& stroke-menu {:ids ids :type type - :values stroke-values}]])) + :values stroke-values}] + [:& shadow-menu {:ids ids + :type type + :values (select-keys shape [:shadow])}]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/frame.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/frame.cljs index afb6e0e48..78642b1b9 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/frame.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/frame.cljs @@ -22,7 +22,8 @@ [app.main.ui.components.dropdown :refer [dropdown]] [app.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]] [app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]] - [app.main.ui.workspace.sidebar.options.frame-grid :refer [frame-grid]])) + [app.main.ui.workspace.sidebar.options.frame-grid :refer [frame-grid]] + [app.main.ui.workspace.sidebar.options.shadow :refer [shadow-menu]])) (declare +size-presets+) @@ -211,5 +212,8 @@ [:& stroke-menu {:ids ids :type type :values stroke-values}] + [:& shadow-menu {:ids ids + :type type + :values (select-keys shape [:shadow])}] [:& frame-grid {:shape shape}]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs index 47ff7ef24..b3ef6ee70 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs @@ -121,9 +121,13 @@ [:& advanced-options {:visible? @open-shadow :on-close #(reset! open-shadow false)} [:div.row-grid-2 - [:select.input-select + [:select.input-select + {:default-value (str (:style value)) + :on-change (fn [event] + (let [value (-> event dom/get-target dom/get-value d/read-string)] + (st/emit! (dwc/update-shapes ids #(assoc-in % [:shadow index :style] value)))))} [:option {:value ":drop-shadow"} "Drop shadow"] - #_[:option {:value ":inner-shadow"} "Inner shadow"]]] + [:option {:value ":inner-shadow"} "Inner shadow"]]] [:div.row-grid-2 [:div.input-element @@ -177,7 +181,6 @@ (mf/defc shadow-menu [{:keys [ids type values] :as props}] - (.log js/console "values" (clj->js values)) (let [on-add-shadow (fn [] (st/emit! (dwc/update-shapes ids #(update % :shadow (fnil conj []) (create-shadow)) )))] From 091de20934152c91c640f049ec384ba8b29e387d Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 24 Sep 2020 21:15:29 +0200 Subject: [PATCH 3/6] :bug: Fixes problem with width/height --- frontend/src/app/main/ui/shapes/filters.cljs | 12 +++++++----- frontend/src/app/main/ui/workspace/shapes/frame.cljs | 6 +++--- frontend/src/app/main/ui/workspace/shapes/path.cljs | 8 ++++++-- .../app/main/ui/workspace/sidebar/options/path.cljs | 8 ++++++-- .../main/ui/workspace/sidebar/options/shadow.cljs | 2 -- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/frontend/src/app/main/ui/shapes/filters.cljs b/frontend/src/app/main/ui/shapes/filters.cljs index 8b5a537d1..3600042b0 100644 --- a/frontend/src/app/main/ui/shapes/filters.cljs +++ b/frontend/src/app/main/ui/shapes/filters.cljs @@ -101,12 +101,14 @@ (let [filter-bounds (->> filters - (filter #(= :drop-shadow (:type %))) + (filter #(= :drop-shadow (:style %))) (map (partial filter-bounds shape) )) - x1 (apply min (:x1 filter-bounds)) - y1 (apply min (:y1 filter-bounds)) - x2 (apply max (:x2 filter-bounds)) - y2 (apply max (:y2 filter-bounds))] + ;; We add the selrect so the minimum size will be the selrect + filter-bounds (conj filter-bounds (:selrect shape)) + x1 (apply min (map :x1 filter-bounds)) + y1 (apply min (map :y1 filter-bounds)) + x2 (apply max (map :x2 filter-bounds)) + y2 (apply max (map :y2 filter-bounds))] [x1 y1 (- x2 x1) (- y2 y1)])) (mf/defc filters diff --git a/frontend/src/app/main/ui/workspace/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/shapes/frame.cljs index 1e6702795..19a47795f 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -99,7 +99,7 @@ (fn [] (st/emit! (dws/change-hover-state (:id shape) false)))) - filter-id (filters/get-filter-id)] + filter-id (mf/use-var (filters/get-filter-id))] (when-not (:hidden shape) [:g {:class (when selected? "selected") @@ -124,8 +124,8 @@ :on-mouse-over on-mouse-over :on-mouse-out on-mouse-out} (:name shape)] - [:g.frame {:filter (filters/filter-str filter-id shape)} - [:& filters/filters {:filter-id filter-id :shape shape}] + [:g.frame {:filter (filters/filter-str @filter-id shape)} + [:& filters/filters {:filter-id @filter-id :shape shape}] [:& frame-shape {:shape shape :childs children}]]]))))) diff --git a/frontend/src/app/main/ui/workspace/shapes/path.cljs b/frontend/src/app/main/ui/workspace/shapes/path.cljs index 91389707b..5bad12bcd 100644 --- a/frontend/src/app/main/ui/workspace/shapes/path.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/path.cljs @@ -17,6 +17,7 @@ [app.main.store :as st] [app.main.ui.keyboard :as kbd] [app.main.ui.shapes.path :as path] + [app.main.ui.shapes.filters :as filters] [app.main.ui.workspace.shapes.common :as common] [app.main.data.workspace.drawing :as dr] [app.util.dom :as dom] @@ -41,10 +42,13 @@ (do (dom/stop-propagation event) (dom/prevent-default event) - (st/emit! (dw/start-edition-mode (:id shape)))))))] + (st/emit! (dw/start-edition-mode (:id shape))))))) + filter-id (mf/use-var (filters/get-filter-id))] [:g.shape {:on-double-click on-double-click :on-mouse-down on-mouse-down - :on-context-menu on-context-menu} + :on-context-menu on-context-menu + :filter (filters/filter-str @filter-id shape)} + [:& filters/filters {:filter-id @filter-id :shape shape}] [:& path/path-shape {:shape shape :background? true}]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/path.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/path.cljs index e3547846c..9405ff784 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/path.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/path.cljs @@ -12,7 +12,8 @@ [rumext.alpha :as mf] [app.common.data :as d] [app.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]] - [app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]])) + [app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]] + [app.main.ui.workspace.sidebar.options.shadow :refer [shadow-menu]])) (mf/defc options [{:keys [shape] :as props}] @@ -25,4 +26,7 @@ :values (select-keys shape fill-attrs)}] [:& stroke-menu {:ids ids :type type - :values stroke-values}]])) + :values stroke-values}] + [:& shadow-menu {:ids ids + :type type + :values (select-keys shape [:shadow])}]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs index b3ef6ee70..dd31794a1 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs @@ -51,8 +51,6 @@ remove-shadow-by-id (fn [values id] (->> values (filterv (fn [s] (not= (:id s) id))))) - - on-remove-shadow (fn [id] (fn [] From 92db554ae7b9414b008b930270f4b0cfb393d48b Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 24 Sep 2020 21:30:36 +0200 Subject: [PATCH 4/6] :sparkles: Adds i18n for shadow options menu --- frontend/resources/locales.json | 258 +++++++++++------- frontend/src/app/main/exports.cljs | 1 - frontend/src/app/main/ui/shapes/attrs.cljs | 3 +- .../src/app/main/ui/shapes/custom_stroke.cljs | 6 +- frontend/src/app/main/ui/viewer/shapes.cljs | 2 - .../ui/workspace/sidebar/options/shadow.cljs | 23 +- 6 files changed, 174 insertions(+), 119 deletions(-) diff --git a/frontend/resources/locales.json b/frontend/resources/locales.json index 38242cb63..04fd94fd0 100644 --- a/frontend/resources/locales.json +++ b/frontend/resources/locales.json @@ -18,7 +18,7 @@ } }, "auth.create-demo-profile" : { - "used-in" : [ "src/app/main/ui/auth/register.cljs:123", "src/app/main/ui/auth/login.cljs:135" ], + "used-in" : [ "src/app/main/ui/auth/login.cljs:135", "src/app/main/ui/auth/register.cljs:123" ], "translations" : { "en" : "Create demo account", "fr" : "Créer un compte de démonstration", @@ -27,7 +27,7 @@ } }, "auth.create-demo-profile-label" : { - "used-in" : [ "src/app/main/ui/auth/register.cljs:120", "src/app/main/ui/auth/login.cljs:132" ], + "used-in" : [ "src/app/main/ui/auth/login.cljs:132", "src/app/main/ui/auth/register.cljs:120" ], "translations" : { "en" : "Just wanna try it?", "fr" : "Vous voulez juste essayer?", @@ -45,7 +45,7 @@ } }, "auth.email-label" : { - "used-in" : [ "src/app/main/ui/auth/register.cljs:89", "src/app/main/ui/auth/recovery_request.cljs:45", "src/app/main/ui/auth/login.cljs:81" ], + "used-in" : [ "src/app/main/ui/auth/login.cljs:81", "src/app/main/ui/auth/register.cljs:89", "src/app/main/ui/auth/recovery_request.cljs:45" ], "translations" : { "en" : "Email", "fr" : "Adresse email", @@ -186,7 +186,7 @@ } }, "auth.password-label" : { - "used-in" : [ "src/app/main/ui/auth/register.cljs:93", "src/app/main/ui/auth/login.cljs:87" ], + "used-in" : [ "src/app/main/ui/auth/login.cljs:87", "src/app/main/ui/auth/register.cljs:93" ], "translations" : { "en" : "Password", "fr" : "Mot de passe", @@ -294,7 +294,7 @@ } }, "dashboard.grid.add-shared" : { - "used-in" : [ "src/app/main/ui/dashboard/grid.cljs:165", "src/app/main/ui/workspace/header.cljs:175" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:210", "src/app/main/ui/dashboard/grid.cljs:165" ], "translations" : { "en" : "Add as Shared Library", "fr" : "", @@ -303,7 +303,7 @@ } }, "dashboard.grid.add-shared-accept" : { - "used-in" : [ "src/app/main/ui/dashboard/grid.cljs:94", "src/app/main/ui/workspace/header.cljs:98" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:104", "src/app/main/ui/dashboard/grid.cljs:94" ], "translations" : { "en" : "Add as Shared Library", "fr" : "", @@ -312,7 +312,7 @@ } }, "dashboard.grid.add-shared-hint" : { - "used-in" : [ "src/app/main/ui/dashboard/grid.cljs:93", "src/app/main/ui/workspace/header.cljs:97" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:103", "src/app/main/ui/dashboard/grid.cljs:93" ], "translations" : { "en" : "Once added as Shared Library, the assets of this file library will be available to be used among the rest of your files.", "fr" : "", @@ -321,7 +321,7 @@ } }, "dashboard.grid.add-shared-message" : { - "used-in" : [ "src/app/main/ui/dashboard/grid.cljs:92", "src/app/main/ui/workspace/header.cljs:96" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:102", "src/app/main/ui/dashboard/grid.cljs:92" ], "translations" : { "en" : "Add “%s” as Shared Library", "fr" : "", @@ -348,7 +348,7 @@ } }, "dashboard.grid.remove-shared" : { - "used-in" : [ "src/app/main/ui/dashboard/grid.cljs:164", "src/app/main/ui/workspace/header.cljs:173" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:208", "src/app/main/ui/dashboard/grid.cljs:164" ], "translations" : { "en" : "Remove as Shared Library", "fr" : "", @@ -357,7 +357,7 @@ } }, "dashboard.grid.remove-shared-accept" : { - "used-in" : [ "src/app/main/ui/dashboard/grid.cljs:113", "src/app/main/ui/workspace/header.cljs:107" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:113", "src/app/main/ui/dashboard/grid.cljs:113" ], "translations" : { "en" : "Remove as Shared Library", "fr" : "", @@ -366,7 +366,7 @@ } }, "dashboard.grid.remove-shared-hint" : { - "used-in" : [ "src/app/main/ui/dashboard/grid.cljs:112", "src/app/main/ui/workspace/header.cljs:106" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:112", "src/app/main/ui/dashboard/grid.cljs:112" ], "translations" : { "en" : "Once removed as Shared Library, the File Library of this file will stop being available to be used among the rest of your files.", "fr" : "", @@ -375,7 +375,7 @@ } }, "dashboard.grid.remove-shared-message" : { - "used-in" : [ "src/app/main/ui/dashboard/grid.cljs:111", "src/app/main/ui/workspace/header.cljs:105" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:111", "src/app/main/ui/dashboard/grid.cljs:111" ], "translations" : { "en" : "Remove “%s” as Shared Library", "fr" : "", @@ -789,7 +789,7 @@ } }, "errors.media-type-mismatch" : { - "used-in" : [ "src/app/main/data/workspace/persistence.cljs:413", "src/app/main/data/media.cljs:61" ], + "used-in" : [ "src/app/main/data/media.cljs:61", "src/app/main/data/workspace/persistence.cljs:413" ], "translations" : { "en" : "Seems that the contents of the image does not match the file extension.", "fr" : "", @@ -798,7 +798,7 @@ } }, "errors.media-type-not-allowed" : { - "used-in" : [ "src/app/main/data/workspace/persistence.cljs:410", "src/app/main/data/media.cljs:58" ], + "used-in" : [ "src/app/main/data/media.cljs:58", "src/app/main/data/workspace/persistence.cljs:410" ], "translations" : { "en" : "Seems that this is not a valid image.", "fr" : "", @@ -843,7 +843,7 @@ } }, "errors.unexpected-error" : { - "used-in" : [ "src/app/main/data/media.cljs:64", "src/app/main/ui/settings/change_email.cljs:50", "src/app/main/ui/workspace/sidebar/options/exports.cljs:66", "src/app/main/ui/auth/register.cljs:54" ], + "used-in" : [ "src/app/main/data/media.cljs:64", "src/app/main/ui/settings/change_email.cljs:50", "src/app/main/ui/auth/register.cljs:54", "src/app/main/ui/workspace/sidebar/options/exports.cljs:66" ], "translations" : { "en" : "An unexpected error occurred.", "fr" : "Une erreur inattendue c'est produite", @@ -870,7 +870,7 @@ } }, "header.sitemap" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:113" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:135" ], "translations" : { "en" : "Sitemap", "fr" : null, @@ -888,7 +888,7 @@ "unused" : true }, "media.loading" : { - "used-in" : [ "src/app/main/data/workspace/persistence.cljs:395", "src/app/main/data/media.cljs:43" ], + "used-in" : [ "src/app/main/data/media.cljs:43", "src/app/main/data/workspace/persistence.cljs:395" ], "translations" : { "en" : "Loading image...", "fr" : "Chargement de l'image...", @@ -1059,7 +1059,7 @@ } }, "settings.multiple" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:156", "src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:138", "src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:147", "src/app/main/ui/workspace/sidebar/options/text.cljs:123", "src/app/main/ui/workspace/sidebar/options/text.cljs:213", "src/app/main/ui/workspace/sidebar/options/text.cljs:226" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:138", "src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:147", "src/app/main/ui/workspace/sidebar/options/text.cljs:124", "src/app/main/ui/workspace/sidebar/options/text.cljs:219", "src/app/main/ui/workspace/sidebar/options/text.cljs:232", "src/app/main/ui/workspace/sidebar/options/stroke.cljs:156" ], "translations" : { "en" : "Mixed", "fr" : null, @@ -1185,7 +1185,7 @@ } }, "settings.profile-submit-label" : { - "used-in" : [ "src/app/main/ui/settings/password.cljs:93", "src/app/main/ui/settings/options.cljs:67", "src/app/main/ui/settings/profile.cljs:91" ], + "used-in" : [ "src/app/main/ui/settings/options.cljs:67", "src/app/main/ui/settings/profile.cljs:91", "src/app/main/ui/settings/password.cljs:93" ], "translations" : { "en" : "Update settings", "fr" : "Mettre à jour les paramètres", @@ -1581,7 +1581,7 @@ } }, "workspace.header.menu.disable-dynamic-alignment" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:167" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:202" ], "translations" : { "en" : "Disable dynamic alignment", "fr" : "Désactiver l'alignement dynamique", @@ -1590,7 +1590,7 @@ } }, "workspace.header.menu.disable-snap-grid" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:139" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:174" ], "translations" : { "en" : "Disable snap to grid", "fr" : "Désactiver l'alignement sur la grille", @@ -1599,7 +1599,7 @@ } }, "workspace.header.menu.enable-dynamic-alignment" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:168" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:203" ], "translations" : { "en" : "Enable dynamic aligment", "fr" : "Activer l'alignement dynamique", @@ -1608,7 +1608,7 @@ } }, "workspace.header.menu.enable-snap-grid" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:140" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:175" ], "translations" : { "en" : "Snap to grid", "fr" : "Aligner sur la grille", @@ -1617,7 +1617,7 @@ } }, "workspace.header.menu.hide-assets" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:160" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:195" ], "translations" : { "en" : "Hide assets", "fr" : "", @@ -1626,7 +1626,7 @@ } }, "workspace.header.menu.hide-grid" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:132" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:167" ], "translations" : { "en" : "Hide grids", "fr" : "Masquer la grille", @@ -1635,7 +1635,7 @@ } }, "workspace.header.menu.hide-layers" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:146" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:181" ], "translations" : { "en" : "Hide layers", "fr" : "Masquer les couches", @@ -1644,7 +1644,7 @@ } }, "workspace.header.menu.hide-palette" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:153" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:188" ], "translations" : { "en" : "Hide color palette", "fr" : "Masquer la palette de couleurs", @@ -1653,7 +1653,7 @@ } }, "workspace.header.menu.hide-rules" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:125" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:160" ], "translations" : { "en" : "Hide rules", "fr" : "Masquer les règles", @@ -1662,7 +1662,7 @@ } }, "workspace.header.menu.show-assets" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:161" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:196" ], "translations" : { "en" : "Show assets", "fr" : "", @@ -1671,7 +1671,7 @@ } }, "workspace.header.menu.show-grid" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:133" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:168" ], "translations" : { "en" : "Show grid", "fr" : "Montrer la grille", @@ -1680,7 +1680,7 @@ } }, "workspace.header.menu.show-layers" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:147" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:182" ], "translations" : { "en" : "Show layers", "fr" : "Montrer les couches", @@ -1689,7 +1689,7 @@ } }, "workspace.header.menu.show-palette" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:154" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:189" ], "translations" : { "en" : "Show color palette", "fr" : "Montrer la palette de couleurs", @@ -1698,7 +1698,7 @@ } }, "workspace.header.menu.show-rules" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:126" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:161" ], "translations" : { "en" : "Show rules", "fr" : "Montrer les règles", @@ -1707,31 +1707,31 @@ } }, "workspace.header.save-error" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:56" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:58" ], "translations" : { "en" : "Error on saving" } }, "workspace.header.saved" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:51" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:53" ], "translations" : { "en" : "Saved" } }, "workspace.header.saving" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:46" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:48" ], "translations" : { "en" : "Saving" } }, "workspace.header.unsaved" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:41" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:43" ], "translations" : { "en" : "Unsaved changes" } }, "workspace.header.viewer" : { - "used-in" : [ "src/app/main/ui/workspace/header.cljs:213" ], + "used-in" : [ "src/app/main/ui/workspace/header.cljs:249" ], "translations" : { "en" : "View mode (Ctrl + P)", "fr" : "Mode visualisation (Ctrl + P)", @@ -1764,19 +1764,19 @@ } }, "workspace.libraries.colors.file-library" : { - "used-in" : [ "src/app/main/ui/workspace/colorpalette.cljs:150", "src/app/main/ui/workspace/colorpicker.cljs:337" ], + "used-in" : [ "src/app/main/ui/workspace/colorpicker.cljs:338", "src/app/main/ui/workspace/colorpalette.cljs:150" ], "translations" : { "en" : "File library" } }, "workspace.libraries.colors.recent-colors" : { - "used-in" : [ "src/app/main/ui/workspace/colorpalette.cljs:160", "src/app/main/ui/workspace/colorpicker.cljs:336" ], + "used-in" : [ "src/app/main/ui/workspace/colorpicker.cljs:337", "src/app/main/ui/workspace/colorpalette.cljs:160" ], "translations" : { "en" : "Recent colors" } }, "workspace.libraries.colors.save-color" : { - "used-in" : [ "src/app/main/ui/workspace/colorpicker.cljs:372" ], + "used-in" : [ "src/app/main/ui/workspace/colorpicker.cljs:373" ], "translations" : { "en" : "Save color" } @@ -2016,7 +2016,7 @@ } }, "workspace.options.grid.auto" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:44" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:35" ], "translations" : { "en" : "Auto", "fr" : "Automatique", @@ -2025,7 +2025,7 @@ } }, "workspace.options.grid.column" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:138" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:129" ], "translations" : { "en" : "Columns", "fr" : "Colonnes", @@ -2034,7 +2034,7 @@ } }, "workspace.options.grid.params.columns" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:179" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:170" ], "translations" : { "en" : "Columns", "fr" : "Colonnes", @@ -2043,7 +2043,7 @@ } }, "workspace.options.grid.params.gutter" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:212" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:203" ], "translations" : { "en" : "Gutter", "fr" : "Gouttière", @@ -2052,7 +2052,7 @@ } }, "workspace.options.grid.params.height" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:203" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:194" ], "translations" : { "en" : "Height", "fr" : "Hauteur", @@ -2061,7 +2061,7 @@ } }, "workspace.options.grid.params.margin" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:218" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:209" ], "translations" : { "en" : "Margin", "fr" : "Marge", @@ -2070,7 +2070,7 @@ } }, "workspace.options.grid.params.rows" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:170" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:161" ], "translations" : { "en" : "Rows", "fr" : "Lignes", @@ -2079,7 +2079,7 @@ } }, "workspace.options.grid.params.set-default" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:231" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:222" ], "translations" : { "en" : "Set as default", "fr" : "Définir par défaut", @@ -2088,7 +2088,7 @@ } }, "workspace.options.grid.params.size" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:163" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:154" ], "translations" : { "en" : "Size", "fr" : "Taille", @@ -2097,7 +2097,7 @@ } }, "workspace.options.grid.params.type" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:188" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:179" ], "translations" : { "en" : "Type", "fr" : "Type", @@ -2106,7 +2106,7 @@ } }, "workspace.options.grid.params.type.bottom" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:196" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:187" ], "translations" : { "en" : "Bottom", "fr" : "Bas", @@ -2115,7 +2115,7 @@ } }, "workspace.options.grid.params.type.center" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:194" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:185" ], "translations" : { "en" : "Center", "fr" : "Centre", @@ -2124,7 +2124,7 @@ } }, "workspace.options.grid.params.type.left" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:193" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:184" ], "translations" : { "en" : "Left", "fr" : "Gauche", @@ -2133,7 +2133,7 @@ } }, "workspace.options.grid.params.type.right" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:197" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:188" ], "translations" : { "en" : "Right", "fr" : "Droite", @@ -2142,7 +2142,7 @@ } }, "workspace.options.grid.params.type.stretch" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:190" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:181" ], "translations" : { "en" : "Stretch", "fr" : "Étirer", @@ -2151,7 +2151,7 @@ } }, "workspace.options.grid.params.type.top" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:192" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:183" ], "translations" : { "en" : "Top", "fr" : "Haut", @@ -2160,7 +2160,7 @@ } }, "workspace.options.grid.params.use-default" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:229" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:220" ], "translations" : { "en" : "Use default", "fr" : "Utiliser la valeur par défaut", @@ -2169,7 +2169,7 @@ } }, "workspace.options.grid.params.width" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:204" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:195" ], "translations" : { "en" : "Width", "fr" : "Largeur", @@ -2178,7 +2178,7 @@ } }, "workspace.options.grid.row" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:139" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:130" ], "translations" : { "en" : "Rows", "fr" : "Lignes", @@ -2187,7 +2187,7 @@ } }, "workspace.options.grid.square" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:137" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:128" ], "translations" : { "en" : "Square", "fr" : "Carré", @@ -2196,7 +2196,7 @@ } }, "workspace.options.grid.title" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:243" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame_grid.cljs:234" ], "translations" : { "en" : "Grid & Layouts", "fr" : "Grille & couches", @@ -2241,7 +2241,7 @@ } }, "workspace.options.position" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/measures.cljs:146", "src/app/main/ui/workspace/sidebar/options/frame.cljs:125" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame.cljs:126", "src/app/main/ui/workspace/sidebar/options/measures.cljs:146" ], "translations" : { "en" : "Position", "fr" : "Position", @@ -2312,8 +2312,50 @@ "es" : "Borde de selección" } }, + "workspace.options.shadow-options.blur" : { + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/shadow.cljs:163" ], + "translations" : { + "en" : "Blur" + } + }, + "workspace.options.shadow-options.drop-shadow" : { + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/shadow.cljs:129" ], + "translations" : { + "en" : "Drop shadow" + } + }, + "workspace.options.shadow-options.inner-shadow" : { + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/shadow.cljs:130" ], + "translations" : { + "en" : "Inner shadow" + } + }, + "workspace.options.shadow-options.offsetx" : { + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/shadow.cljs:141" ], + "translations" : { + "en" : "X" + } + }, + "workspace.options.shadow-options.offsety" : { + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/shadow.cljs:151" ], + "translations" : { + "en" : "Y" + } + }, + "workspace.options.shadow-options.spread" : { + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/shadow.cljs:174" ], + "translations" : { + "en" : "Spread" + } + }, + "workspace.options.shadow-options.title" : { + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/shadow.cljs:190" ], + "translations" : { + "en" : "Shadow" + } + }, "workspace.options.size" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/measures.cljs:116", "src/app/main/ui/workspace/sidebar/options/frame.cljs:98" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame.cljs:99", "src/app/main/ui/workspace/sidebar/options/measures.cljs:116" ], "translations" : { "en" : "Size", "fr" : "Taille", @@ -2322,7 +2364,7 @@ } }, "workspace.options.size-presets" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame.cljs:80" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/frame.cljs:81" ], "translations" : { "en" : "Size presets", "fr" : "Tailles prédéfinies", @@ -2412,7 +2454,7 @@ } }, "workspace.options.text-options.align-center" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:169" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:175" ], "translations" : { "en" : "Align center", "fr" : "Aligner au centre", @@ -2421,7 +2463,7 @@ } }, "workspace.options.text-options.align-justify" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:179" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:185" ], "translations" : { "en" : "Justify", "fr" : "Justifier", @@ -2430,7 +2472,7 @@ } }, "workspace.options.text-options.align-left" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:164" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:170" ], "translations" : { "en" : "Align left", "fr" : "Aligner à gauche", @@ -2448,7 +2490,7 @@ } }, "workspace.options.text-options.align-right" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:174" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:180" ], "translations" : { "en" : "Align right", "fr" : "Aligner à droite", @@ -2466,7 +2508,7 @@ } }, "workspace.options.text-options.decoration" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:289" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:306" ], "translations" : { "en" : "Decoration", "fr" : "Décoration", @@ -2474,8 +2516,26 @@ "es" : "Decoración" } }, + "workspace.options.text-options.grow-auto-height" : { + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:287" ], + "translations" : { + "en" : "Auto height" + } + }, + "workspace.options.text-options.grow-auto-width" : { + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:282" ], + "translations" : { + "en" : "Auto width" + } + }, + "workspace.options.text-options.grow-fixed" : { + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:277" ], + "translations" : { + "en" : "Fixed" + } + }, "workspace.options.text-options.letter-spacing" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:218" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:224" ], "translations" : { "en" : "Letter Spacing", "fr" : "Espacement de caractères", @@ -2484,7 +2544,7 @@ } }, "workspace.options.text-options.line-height" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:205" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:211" ], "translations" : { "en" : "Line height", "fr" : "Hauteur de ligne", @@ -2493,7 +2553,7 @@ } }, "workspace.options.text-options.lowercase" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:336" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:353" ], "translations" : { "en" : "Lowercase", "fr" : "Minuscule", @@ -2502,7 +2562,7 @@ } }, "workspace.options.text-options.none" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:292", "src/app/main/ui/workspace/sidebar/options/text.cljs:326" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:309", "src/app/main/ui/workspace/sidebar/options/text.cljs:343" ], "translations" : { "en" : "None", "fr" : "Aucune", @@ -2511,7 +2571,7 @@ } }, "workspace.options.text-options.strikethrough" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:304" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:321" ], "translations" : { "en" : "Strikethrough", "fr" : "Barré", @@ -2520,7 +2580,7 @@ } }, "workspace.options.text-options.text-case" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:323" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:340" ], "translations" : { "en" : "Case", "fr" : "Casse", @@ -2529,7 +2589,7 @@ } }, "workspace.options.text-options.title" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:361" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:379" ], "translations" : { "en" : "Text", "fr" : "Texte", @@ -2538,7 +2598,7 @@ } }, "workspace.options.text-options.title-group" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:360" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:378" ], "translations" : { "en" : "Group text", "ru" : "Текст группы", @@ -2546,7 +2606,7 @@ } }, "workspace.options.text-options.title-selection" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:359" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:377" ], "translations" : { "en" : "Selection text", "ru" : "Выбранный текст", @@ -2554,7 +2614,7 @@ } }, "workspace.options.text-options.titlecase" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:341" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:358" ], "translations" : { "en" : "Titlecase", "fr" : "Titre", @@ -2563,7 +2623,7 @@ } }, "workspace.options.text-options.underline" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:298" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:315" ], "translations" : { "en" : "Underline", "fr" : "Souligner", @@ -2572,7 +2632,7 @@ } }, "workspace.options.text-options.uppercase" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:331" ], + "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:348" ], "translations" : { "en" : "Uppercase", "fr" : "Majuscule", @@ -2581,13 +2641,13 @@ } }, "workspace.options.text-options.vertical-align" : { - "used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:257" ], "translations" : { "en" : "Vertical align", "fr" : "Alignement vertical", "ru" : "Вертикальное выравнивание", "es" : "Alineación vertical" - } + }, + "unused" : true }, "workspace.options.use-play-button" : { "used-in" : [ "src/app/main/ui/workspace/sidebar/options/interactions.cljs:55" ], @@ -2617,7 +2677,7 @@ } }, "workspace.toolbar.assets" : { - "used-in" : [ "src/app/main/ui/workspace/left_toolbar.cljs:103" ], + "used-in" : [ "src/app/main/ui/workspace/left_toolbar.cljs:105" ], "translations" : { "en" : "Assets (Ctrl + I)", "fr" : "", @@ -2626,7 +2686,7 @@ } }, "workspace.toolbar.circle" : { - "used-in" : [ "src/app/main/ui/workspace/left_toolbar.cljs:67" ], + "used-in" : [ "src/app/main/ui/workspace/left_toolbar.cljs:69" ], "translations" : { "en" : "Circle (E)", "fr" : "Cercle (E)", @@ -2635,7 +2695,7 @@ } }, "workspace.toolbar.color-palette" : { - "used-in" : [ "src/app/main/ui/workspace/left_toolbar.cljs:113" ], + "used-in" : [ "src/app/main/ui/workspace/left_toolbar.cljs:115" ], "translations" : { "en" : "Color Palette (---)", "fr" : "Palette de couleurs (---)", @@ -2644,7 +2704,7 @@ } }, "workspace.toolbar.curve" : { - "used-in" : [ "src/app/main/ui/workspace/left_toolbar.cljs:86" ], + "used-in" : [ "src/app/main/ui/workspace/left_toolbar.cljs:88" ], "translations" : { "en" : "Curve", "fr" : "Courbe", @@ -2653,7 +2713,7 @@ } }, "workspace.toolbar.frame" : { - "used-in" : [ "src/app/main/ui/workspace/left_toolbar.cljs:57" ], + "used-in" : [ "src/app/main/ui/workspace/left_toolbar.cljs:59" ], "translations" : { "en" : "Artboard (A)", "fr" : "Plan de travail (A)", @@ -2662,7 +2722,7 @@ } }, "workspace.toolbar.image" : { - "used-in" : [ "src/app/main/ui/workspace/left_toolbar.cljs:77" ], + "used-in" : [ "src/app/main/ui/workspace/left_toolbar.cljs:79" ], "translations" : { "en" : "Image (I)", "fr" : "Image (I)", @@ -2680,7 +2740,7 @@ "unused" : true }, "workspace.toolbar.path" : { - "used-in" : [ "src/app/main/ui/workspace/left_toolbar.cljs:91" ], + "used-in" : [ "src/app/main/ui/workspace/left_toolbar.cljs:93" ], "translations" : { "en" : "Path", "fr" : "Chemin", @@ -2689,7 +2749,7 @@ } }, "workspace.toolbar.rect" : { - "used-in" : [ "src/app/main/ui/workspace/left_toolbar.cljs:62" ], + "used-in" : [ "src/app/main/ui/workspace/left_toolbar.cljs:64" ], "translations" : { "en" : "Box (B)", "fr" : "Boîte (B)", @@ -2698,7 +2758,7 @@ } }, "workspace.toolbar.text" : { - "used-in" : [ "src/app/main/ui/workspace/left_toolbar.cljs:72" ], + "used-in" : [ "src/app/main/ui/workspace/left_toolbar.cljs:74" ], "translations" : { "en" : "Text (T)", "fr" : "Texte (T)", @@ -2707,7 +2767,7 @@ } }, "workspace.updates.dismiss" : { - "used-in" : [ "src/app/main/data/workspace/libraries.cljs:487" ], + "used-in" : [ "src/app/main/data/workspace/libraries.cljs:488" ], "translations" : { "en" : "Dismiss", "fr" : "", @@ -2716,7 +2776,7 @@ } }, "workspace.updates.there-are-updates" : { - "used-in" : [ "src/app/main/data/workspace/libraries.cljs:483" ], + "used-in" : [ "src/app/main/data/workspace/libraries.cljs:484" ], "translations" : { "en" : "There are updates in shared libraries", "fr" : "", @@ -2725,7 +2785,7 @@ } }, "workspace.updates.update" : { - "used-in" : [ "src/app/main/data/workspace/libraries.cljs:485" ], + "used-in" : [ "src/app/main/data/workspace/libraries.cljs:486" ], "translations" : { "en" : "Update", "fr" : "", @@ -2741,9 +2801,5 @@ "ru" : "Кликни чтобы закончить фигуру", "es" : "Pulsar para cerrar la ruta" } - }, - - "workspace.options.text-options.grow-fixed": "Fixed", - "workspace.options.text-options.grow-auto-width": "Auto width", - "workspace.options.text-options.grow-auto-height": "Auto height" + } } diff --git a/frontend/src/app/main/exports.cljs b/frontend/src/app/main/exports.cljs index 89061114f..7169782d6 100644 --- a/frontend/src/app/main/exports.cljs +++ b/frontend/src/app/main/exports.cljs @@ -11,7 +11,6 @@ "The main logic for SVG export functionality." (:require [rumext.alpha :as mf] - [cuerdas.core :as str] [app.common.uuid :as uuid] [app.common.pages :as cp] [app.common.pages-helpers :as cph] diff --git a/frontend/src/app/main/ui/shapes/attrs.cljs b/frontend/src/app/main/ui/shapes/attrs.cljs index def3de31c..52c028170 100644 --- a/frontend/src/app/main/ui/shapes/attrs.cljs +++ b/frontend/src/app/main/ui/shapes/attrs.cljs @@ -21,8 +21,7 @@ (defn extract-style-attrs [shape] (let [stroke-style (:stroke-style shape :none) - attrs #js {;:filter (when (not= :frame (:type shape)) (str "url(#filter_" (:id shape) ")")) - :fill (or (:fill-color shape) "transparent") + attrs #js {:fill (or (:fill-color shape) "transparent") :fillOpacity (:fill-opacity shape nil) :rx (:rx shape nil) :ry (:ry shape nil)}] diff --git a/frontend/src/app/main/ui/shapes/custom_stroke.cljs b/frontend/src/app/main/ui/shapes/custom_stroke.cljs index ba0443536..8d0784f8f 100644 --- a/frontend/src/app/main/ui/shapes/custom_stroke.cljs +++ b/frontend/src/app/main/ui/shapes/custom_stroke.cljs @@ -23,7 +23,7 @@ base-props (unchecked-get props "base-props") elem-name (unchecked-get props "elem-name") {:keys [x y width height]} (geom/shape->rect-shape shape) - id (uuid/next) + stroke-id (mf/use-var (uuid/next)) stroke-style (:stroke-style shape :none) stroke-position (:stroke-alignment shape :center)] (cond @@ -34,7 +34,7 @@ ;; Inner alignment: display the shape with double width stroke, ;; and clip the result with the original shape without stroke. (= stroke-position :inner) - (let [clip-id (str "clip-" id) + (let [clip-id (str "clip-" @stroke-id) clip-props (-> (obj/merge! #js {} base-props) (obj/merge! #js {:stroke nil @@ -61,7 +61,7 @@ ;; without stroke (= stroke-position :outer) - (let [mask-id (str "mask-" id) + (let [mask-id (str "mask-" @stroke-id) stroke-width (.-strokeWidth ^js base-props) mask-props1 (-> (obj/merge! #js {} base-props) (obj/merge! #js {:stroke "white" diff --git a/frontend/src/app/main/ui/viewer/shapes.cljs b/frontend/src/app/main/ui/viewer/shapes.cljs index c29d23f4d..2ed021856 100644 --- a/frontend/src/app/main/ui/viewer/shapes.cljs +++ b/frontend/src/app/main/ui/viewer/shapes.cljs @@ -11,8 +11,6 @@ "The main container for a frame in viewer mode" (:require [rumext.alpha :as mf] - [cuerdas.core :as str] - [app.common.uuid :as uuid] [app.common.data :as d] [app.common.pages :as cp] [app.common.pages-helpers :as cph] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs index dd31794a1..0f13a906b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shadow.cljs @@ -18,7 +18,8 @@ [app.main.ui.workspace.sidebar.options.common :refer [advanced-options]] [app.main.ui.workspace.sidebar.options.rows.input-row :refer [input-row]] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] - [app.util.dom :as dom])) + [app.util.dom :as dom] + [app.util.i18n :as i18n :refer [t]])) (defn create-shadow [] (let [id (uuid/next)] @@ -37,7 +38,8 @@ (mf/defc shadow-entry [{:keys [ids index value]}] - (let [open-shadow (mf/use-state false) + (let [locale (i18n/use-locale) + open-shadow (mf/use-state false) basic-offset-x-ref (mf/use-ref nil) basic-offset-y-ref (mf/use-ref nil) @@ -124,8 +126,8 @@ :on-change (fn [event] (let [value (-> event dom/get-target dom/get-value d/read-string)] (st/emit! (dwc/update-shapes ids #(assoc-in % [:shadow index :style] value)))))} - [:option {:value ":drop-shadow"} "Drop shadow"] - [:option {:value ":inner-shadow"} "Inner shadow"]]] + [:option {:value ":drop-shadow"} (t locale "workspace.options.shadow-options.drop-shadow")] + [:option {:value ":inner-shadow"} (t locale "workspace.options.shadow-options.inner-shadow")]]] [:div.row-grid-2 [:div.input-element @@ -136,7 +138,7 @@ :on-click (select-text adv-offset-x-ref) :on-change (update-attr index :offset-x valid-number? basic-offset-x-ref) :default-value (:offset-x value)}] - [:span.after "X"]] + [:span.after (t locale "workspace.options.shadow-options.offsetx")]] [:div.input-element [:input.input-text {:type "number" @@ -146,7 +148,7 @@ :on-click (select-text adv-offset-y-ref) :on-change (update-attr index :offset-y valid-number? basic-offset-y-ref) :default-value (:offset-y value)}] - [:span.after "Y"]]] + [:span.after (t locale "workspace.options.shadow-options.offsety")]]] [:div.row-grid-2 [:div.input-element @@ -158,7 +160,7 @@ :on-change (update-attr index :blur valid-number? basic-blur-ref) :min 0 :default-value (:blur value)}] - [:span.after "Blur"]] + [:span.after (t locale "workspace.options.shadow-options.blur")]] [:div.input-element [:input.input-text {:type "number" @@ -169,7 +171,7 @@ :on-change (update-attr index :spread valid-number?) :min 0 :default-value (:spread value)}] - [:span.after "Spread"]]] + [:span.after (t locale "workspace.options.shadow-options.spread")]]] [:div.color-row-wrap [:& color-row {:color {:value (:color value) :opacity (:opacity value)} @@ -179,12 +181,13 @@ (mf/defc shadow-menu [{:keys [ids type values] :as props}] - (let [on-add-shadow + (let [locale (i18n/use-locale) + on-add-shadow (fn [] (st/emit! (dwc/update-shapes ids #(update % :shadow (fnil conj []) (create-shadow)) )))] [:div.element-set.shadow-options [:div.element-set-title - [:span "Shadow"] + [:span (t locale "workspace.options.shadow-options.title")] [:div.add-page {:on-click on-add-shadow} i/close]] (when (seq (:shadow values)) From 7950cc07c1205db474a8bf5bab18cf10592c978b Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 24 Sep 2020 21:42:30 +0200 Subject: [PATCH 5/6] :bug: Fix shift+click on the palette --- .../app/main/ui/workspace/colorpalette.cljs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/colorpalette.cljs b/frontend/src/app/main/ui/workspace/colorpalette.cljs index 5b9ad9f24..9b264d236 100644 --- a/frontend/src/app/main/ui/workspace/colorpalette.cljs +++ b/frontend/src/app/main/ui/workspace/colorpalette.cljs @@ -48,16 +48,16 @@ ;; --- Components (mf/defc palette-item - [{:keys [color size]}] - (let [select-color + [{:keys [color size local?]}] + (let [id (:id color) + file-id (:file-id color) + select-color (fn [event] - (if (kbd/shift? event) - (st/emit! (udw/update-color-on-selected-shapes {:stroke-color (:value color) - :stroke-color-ref-file (:file-id color) - :stroke-color-ref-id (:id color)})) - (st/emit! (udw/update-color-on-selected-shapes {:fill-color (:value color) - :fill-color-ref-file (:file-id color) - :fill-color-ref-id (:id color)}))))] + (println "item" id file-id) + (let [ids (get-in @st/state [:workspace-local :selected])] + (if (kbd/shift? event) + (st/emit! (mdc/change-stroke ids (:value color) id file-id)) + (st/emit! (mdc/change-fill ids (:value color) id file-id)))))] [:div.color-cell {:class (str "cell-"(name size)) :key (or (str (:id color)) (:value color)) From f6870a2fee639b634ef4dea0ed17b070a01f51d8 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 25 Sep 2020 09:13:50 +0200 Subject: [PATCH 6/6] :sparkles: Review improvements --- frontend/src/app/main/ui/shapes/filters.cljs | 4 ++-- frontend/src/app/main/ui/workspace/colorpalette.cljs | 1 - frontend/src/app/main/ui/workspace/shapes/common.cljs | 6 +++--- frontend/src/app/main/ui/workspace/shapes/frame.cljs | 6 +++--- frontend/src/app/main/ui/workspace/shapes/path.cljs | 6 +++--- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/frontend/src/app/main/ui/shapes/filters.cljs b/frontend/src/app/main/ui/shapes/filters.cljs index 3600042b0..5f583b2dc 100644 --- a/frontend/src/app/main/ui/shapes/filters.cljs +++ b/frontend/src/app/main/ui/shapes/filters.cljs @@ -133,13 +133,13 @@ drop-shadow-filters (->> filters (filter #(= :drop-shadow (:style %)))) drop-shadow-filters (->> drop-shadow-filters (map #(str "filter" (:id %))) - (concat ["BackgroundImageFix"]) + (cons "BackgroundImageFix") (map add-in-filter drop-shadow-filters)) inner-shadow-filters (->> filters (filter #(= :inner-shadow (:style %)))) inner-shadow-filters (->> inner-shadow-filters (map #(str "filter" (:id %))) - (concat ["shape"]) + (cons "shape") (map add-in-filter inner-shadow-filters))] [:* diff --git a/frontend/src/app/main/ui/workspace/colorpalette.cljs b/frontend/src/app/main/ui/workspace/colorpalette.cljs index 9b264d236..bfda8cd1b 100644 --- a/frontend/src/app/main/ui/workspace/colorpalette.cljs +++ b/frontend/src/app/main/ui/workspace/colorpalette.cljs @@ -53,7 +53,6 @@ file-id (:file-id color) select-color (fn [event] - (println "item" id file-id) (let [ids (get-in @st/state [:workspace-local :selected])] (if (kbd/shift? event) (st/emit! (mdc/change-stroke ids (:value color) id file-id)) diff --git a/frontend/src/app/main/ui/workspace/shapes/common.cljs b/frontend/src/app/main/ui/workspace/shapes/common.cljs index 9aeaaacd4..2df882f9e 100644 --- a/frontend/src/app/main/ui/workspace/shapes/common.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/common.cljs @@ -71,11 +71,11 @@ on-context-menu (mf/use-callback (mf/deps shape) #(on-context-menu % shape)) - filter-id (mf/use-var (filters/get-filter-id))] + filter-id (mf/use-memo filters/get-filter-id)] [:g.shape {:on-mouse-down on-mouse-down :on-context-menu on-context-menu - :filter (filters/filter-str @filter-id shape)} - [:& filters/filters {:filter-id @filter-id :shape shape}] + :filter (filters/filter-str filter-id shape)} + [:& filters/filters {:filter-id filter-id :shape shape}] [:& component {:shape shape}]]))) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/shapes/frame.cljs index 19a47795f..0fb0a0024 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -99,7 +99,7 @@ (fn [] (st/emit! (dws/change-hover-state (:id shape) false)))) - filter-id (mf/use-var (filters/get-filter-id))] + filter-id (mf/use-memo filters/get-filter-id)] (when-not (:hidden shape) [:g {:class (when selected? "selected") @@ -124,8 +124,8 @@ :on-mouse-over on-mouse-over :on-mouse-out on-mouse-out} (:name shape)] - [:g.frame {:filter (filters/filter-str @filter-id shape)} - [:& filters/filters {:filter-id @filter-id :shape shape}] + [:g.frame {:filter (filters/filter-str filter-id shape)} + [:& filters/filters {:filter-id filter-id :shape shape}] [:& frame-shape {:shape shape :childs children}]]]))))) diff --git a/frontend/src/app/main/ui/workspace/shapes/path.cljs b/frontend/src/app/main/ui/workspace/shapes/path.cljs index 5bad12bcd..d128509aa 100644 --- a/frontend/src/app/main/ui/workspace/shapes/path.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/path.cljs @@ -43,12 +43,12 @@ (dom/stop-propagation event) (dom/prevent-default event) (st/emit! (dw/start-edition-mode (:id shape))))))) - filter-id (mf/use-var (filters/get-filter-id))] + filter-id (mf/use-memo filters/get-filter-id)] [:g.shape {:on-double-click on-double-click :on-mouse-down on-mouse-down :on-context-menu on-context-menu - :filter (filters/filter-str @filter-id shape)} - [:& filters/filters {:filter-id @filter-id :shape shape}] + :filter (filters/filter-str filter-id shape)} + [:& filters/filters {:filter-id filter-id :shape shape}] [:& path/path-shape {:shape shape :background? true}]]))