diff --git a/frontend/resources/locales.json b/frontend/resources/locales.json index 5972e39592..cd1596cd2e 100644 --- a/frontend/resources/locales.json +++ b/frontend/resources/locales.json @@ -416,7 +416,7 @@ } }, "dashboard.sidebar.drafts" : { - "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:128" ], + "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:129" ], "translations" : { "en" : "Drafts", "fr" : "Brouillons", @@ -424,7 +424,7 @@ } }, "dashboard.sidebar.libraries" : { - "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:134" ], + "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:135" ], "translations" : { "en" : "Libraries", "fr" : "Librairies", @@ -432,7 +432,7 @@ } }, "dashboard.sidebar.recent" : { - "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:121" ], + "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:122" ], "translations" : { "en" : "Recent", "fr" : "Récent", @@ -528,7 +528,7 @@ } }, "ds.search.placeholder" : { - "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:187" ], + "used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:188" ], "translations" : { "en" : "Search...", "fr" : "Rechercher...", @@ -584,7 +584,7 @@ } }, "errors.image-format-unsupported" : { - "used-in" : [ "src/uxbox/main/data/users.cljs:177", "src/uxbox/main/data/workspace/persistence.cljs:365", "src/uxbox/main/data/images.cljs:376" ], + "used-in" : [ "src/uxbox/main/data/images.cljs:376", "src/uxbox/main/data/workspace/persistence.cljs:365", "src/uxbox/main/data/users.cljs:177" ], "translations" : { "en" : "The image format is not supported (must be svg, jpg or png).", "fr" : "Le format d'image n'est pas supporté (doit être svg, jpg ou png).", @@ -592,7 +592,7 @@ } }, "errors.image-too-large" : { - "used-in" : [ "src/uxbox/main/data/users.cljs:175", "src/uxbox/main/data/workspace/persistence.cljs:363", "src/uxbox/main/data/images.cljs:374" ], + "used-in" : [ "src/uxbox/main/data/images.cljs:374", "src/uxbox/main/data/workspace/persistence.cljs:363", "src/uxbox/main/data/users.cljs:175" ], "translations" : { "en" : "The image is too large to be inserted (must be under 5mb).", "fr" : "L'image est trop grande (doit être inférieure à 5 Mo).", @@ -632,7 +632,7 @@ } }, "errors.unexpected-error" : { - "used-in" : [ "src/uxbox/main/data/users.cljs:185", "src/uxbox/main/data/workspace/persistence.cljs:334", "src/uxbox/main/data/workspace/persistence.cljs:374", "src/uxbox/main/data/images.cljs:385", "src/uxbox/main/ui/settings/change_email.cljs:51", "src/uxbox/main/ui/auth/register.cljs:54" ], + "used-in" : [ "src/uxbox/main/data/images.cljs:385", "src/uxbox/main/data/workspace/persistence.cljs:334", "src/uxbox/main/data/workspace/persistence.cljs:374", "src/uxbox/main/data/users.cljs:185", "src/uxbox/main/ui/auth/register.cljs:54", "src/uxbox/main/ui/settings/change_email.cljs:51" ], "translations" : { "en" : "An unexpected error occurred.", "fr" : "Une erreur inattendue c'est produite", @@ -672,7 +672,7 @@ } }, "image.loading" : { - "used-in" : [ "src/uxbox/main/data/users.cljs:191", "src/uxbox/main/data/workspace/persistence.cljs:341", "src/uxbox/main/data/workspace/persistence.cljs:382", "src/uxbox/main/data/images.cljs:393" ], + "used-in" : [ "src/uxbox/main/data/images.cljs:393", "src/uxbox/main/data/workspace/persistence.cljs:341", "src/uxbox/main/data/workspace/persistence.cljs:382", "src/uxbox/main/data/users.cljs:191" ], "translations" : { "en" : "Loading image...", "fr" : "Chargement de l'image...", @@ -839,6 +839,13 @@ "es" : "Cambiar el idioma de la interfaz" } }, + "settings.multiple" : { + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:127", "src/uxbox/main/ui/workspace/sidebar/options/rows/color_row.cljs:117", "src/uxbox/main/ui/workspace/sidebar/options/rows/color_row.cljs:126" ], + "translations" : { + "en" : "Multiple", + "es" : "Múltiple" + } + }, "settings.new-email-label" : { "used-in" : [ "src/uxbox/main/ui/settings/change_email.cljs:75" ], "translations" : { @@ -1360,7 +1367,7 @@ } }, "workspace.options.design" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options.cljs:107" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options.cljs:70" ], "translations" : { "en" : "Design", "fr" : "Conception", @@ -1380,7 +1387,7 @@ } }, "workspace.options.fill" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:383", "src/uxbox/main/ui/workspace/sidebar/options/fill.cljs:41" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/fill.cljs:45", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:382" ], "translations" : { "en" : "Fill", "fr" : "Remplissage", @@ -1388,7 +1395,7 @@ } }, "workspace.options.font-options" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:389" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:388" ], "translations" : { "en" : "Text", "fr" : "Texte", @@ -1396,7 +1403,7 @@ } }, "workspace.options.font-options.align-bottom" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:294" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:293" ], "translations" : { "en" : "Align bottom", "fr" : "Aligner en bas", @@ -1428,7 +1435,7 @@ } }, "workspace.options.font-options.align-middle" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:289" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:288" ], "translations" : { "en" : "Align middle", "fr" : "Aligner au milieu", @@ -1444,7 +1451,7 @@ } }, "workspace.options.font-options.align-top" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:284" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:283" ], "translations" : { "en" : "Align top", "fr" : "Aligner en haut", @@ -1452,7 +1459,7 @@ } }, "workspace.options.font-options.decoration" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:315" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:314" ], "translations" : { "en" : "Decoration", "fr" : "Décoration", @@ -1460,7 +1467,7 @@ } }, "workspace.options.font-options.letter-spacing" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:241" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:240" ], "translations" : { "en" : "Letter Spacing", "fr" : "Espacement de caractères", @@ -1468,7 +1475,7 @@ } }, "workspace.options.font-options.line-height" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:229" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:228" ], "translations" : { "en" : "Line height", "fr" : "Hauteur de ligne", @@ -1476,7 +1483,7 @@ } }, "workspace.options.font-options.lowercase" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:364" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:363" ], "translations" : { "en" : "Lowercase", "fr" : "Minuscule", @@ -1484,7 +1491,7 @@ } }, "workspace.options.font-options.none" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:318", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:354" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:317", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:353" ], "translations" : { "en" : "None", "fr" : "Aucune", @@ -1492,7 +1499,7 @@ } }, "workspace.options.font-options.strikethrough" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:330" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:329" ], "translations" : { "en" : "Strikethrough", "fr" : "Barré", @@ -1500,7 +1507,7 @@ } }, "workspace.options.font-options.text-case" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:351" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:350" ], "translations" : { "en" : "Case", "fr" : "Casse", @@ -1508,7 +1515,7 @@ } }, "workspace.options.font-options.titlecase" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:369" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:368" ], "translations" : { "en" : "Titlecase", "fr" : "Titre", @@ -1516,7 +1523,7 @@ } }, "workspace.options.font-options.underline" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:324" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:323" ], "translations" : { "en" : "Underline", "fr" : "Souligner", @@ -1524,7 +1531,7 @@ } }, "workspace.options.font-options.uppercase" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:359" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:358" ], "translations" : { "en" : "Uppercase", "fr" : "Majuscule", @@ -1532,7 +1539,7 @@ } }, "workspace.options.font-options.vertical-align" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:281" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:280" ], "translations" : { "en" : "Vertical align", "fr" : "Alignement vertical", @@ -1724,7 +1731,7 @@ } }, "workspace.options.position" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/frame.cljs:125", "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:112" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:112", "src/uxbox/main/ui/workspace/sidebar/options/frame.cljs:125" ], "translations" : { "en" : "Position", "fr" : "Position", @@ -1732,7 +1739,7 @@ } }, "workspace.options.prototype" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options.cljs:115" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options.cljs:80" ], "translations" : { "en" : "Prototype", "fr" : "Prototype", @@ -1772,7 +1779,7 @@ } }, "workspace.options.size" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/frame.cljs:98", "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:82" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:82", "src/uxbox/main/ui/workspace/sidebar/options/frame.cljs:98" ], "translations" : { "en" : "Size", "fr" : "Taille", @@ -1788,7 +1795,7 @@ } }, "workspace.options.stroke" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:90", "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:124" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:112", "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:150" ], "translations" : { "en" : "Stroke", "fr" : "Bordure", @@ -1796,7 +1803,7 @@ } }, "workspace.options.stroke.center" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:110" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:134" ], "translations" : { "en" : "Center", "fr" : "Centre", @@ -1804,7 +1811,7 @@ } }, "workspace.options.stroke.dashed" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:118" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:144" ], "translations" : { "en" : "Dashed", "fr" : "Tiré", @@ -1812,7 +1819,7 @@ } }, "workspace.options.stroke.dotted" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:117" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:143" ], "translations" : { "en" : "Dotted", "fr" : "Pointillé", @@ -1820,7 +1827,7 @@ } }, "workspace.options.stroke.inner" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:111" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:135" ], "translations" : { "en" : "Inside", "fr" : "Intérieur", @@ -1828,7 +1835,7 @@ } }, "workspace.options.stroke.mixed" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:119" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:145" ], "translations" : { "en" : "Mixed", "fr" : "Mixte", @@ -1836,7 +1843,7 @@ } }, "workspace.options.stroke.outer" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:112" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:136" ], "translations" : { "en" : "Outside", "fr" : "Extérieur", @@ -1844,7 +1851,7 @@ } }, "workspace.options.stroke.solid" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:116" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:142" ], "translations" : { "en" : "Solid", "fr" : "Solide", diff --git a/frontend/resources/styles/main/partials/colorpicker.scss b/frontend/resources/styles/main/partials/colorpicker.scss index 514fad23d4..f143d882b6 100644 --- a/frontend/resources/styles/main/partials/colorpicker.scss +++ b/frontend/resources/styles/main/partials/colorpicker.scss @@ -176,10 +176,13 @@ &:invalid { border-color: $color-danger; } - } } + ::placeholder{ + color: $color-gray-10; + } + .type { color: $color-gray-10; margin-right: $x-small; diff --git a/frontend/resources/styles/main/partials/sidebar-element-options.scss b/frontend/resources/styles/main/partials/sidebar-element-options.scss index fdeba7c6fa..77a542f784 100644 --- a/frontend/resources/styles/main/partials/sidebar-element-options.scss +++ b/frontend/resources/styles/main/partials/sidebar-element-options.scss @@ -444,6 +444,10 @@ border: 1px solid $color-gray-10; border-radius: $br-small; cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + color: $color-gray-10; flex-shrink: 0; height: 20px; margin: 5px 4px 0 0; diff --git a/frontend/src/uxbox/main/refs.cljs b/frontend/src/uxbox/main/refs.cljs index 091fb0b9e8..6f6d1b51b3 100644 --- a/frontend/src/uxbox/main/refs.cljs +++ b/frontend/src/uxbox/main/refs.cljs @@ -119,6 +119,14 @@ (def selected-shapes (l/derived :selected workspace-local)) +(def selected-objects + (letfn [(selector [state] + (let [selected (get-in state [:workspace-local :selected]) + page-id (get-in state [:workspace-page :id]) + objects (get-in state [:workspace-data page-id :objects])] + (->> selected (map #(get objects %)))))] + (l/derived selector st/state))) + (def selected-shapes-with-children (letfn [(selector [state] (let [selected (get-in state [:workspace-local :selected]) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options.cljs index b4a1b086b0..b67d60799d 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options.cljs @@ -26,11 +26,12 @@ [uxbox.main.ui.workspace.sidebar.options.group :as group] [uxbox.main.ui.workspace.sidebar.options.icon :as icon] [uxbox.main.ui.workspace.sidebar.options.image :as image] - [uxbox.main.ui.workspace.sidebar.options.interactions :refer [interactions-menu]] + [uxbox.main.ui.workspace.sidebar.options.text :as text] [uxbox.main.ui.workspace.sidebar.options.page :as page] + [uxbox.main.ui.workspace.sidebar.options.multiple :as multiple] + [uxbox.main.ui.workspace.sidebar.options.interactions :refer [interactions-menu]] [uxbox.main.ui.workspace.sidebar.options.path :as path] [uxbox.main.ui.workspace.sidebar.options.rect :as rect] - [uxbox.main.ui.workspace.sidebar.options.text :as text] [uxbox.util.dom :as dom] [uxbox.util.http :as http] [uxbox.util.i18n :as i18n :refer [tr t]] @@ -106,7 +107,7 @@ (mf/defc options-content {::mf/wrap [mf/memo]} - [{:keys [section selected shape page] :as props}] + [{:keys [section shapes page] :as props}] (let [locale (mf/deref i18n/locale)] [:div.tool-window [:div.tool-window-content @@ -116,26 +117,22 @@ :title (t locale "workspace.options.design")} [:div.element-options [:& align-options] - (if (= (count selected) 1) - [:& shape-options {:shape shape :page page}] - [:& page/options {:page page}])]] + (case (count shapes) + 0 [:& page/options {:page page}] + 1 [:& shape-options {:shape (first shapes)}] + [:& multiple/options {:shapes shapes}])]] [:& tab-element {:id :prototype :title (t locale "workspace.options.prototype")} [:div.element-options - [:& interactions-menu {:shape shape}]]]]]])) + [:& interactions-menu {:shape (first shapes)}]]]]]])) (mf/defc options-toolbox {::mf/wrap [mf/memo]} [{:keys [page local] :as props}] - (let [selected (:selected local) - section (:options-mode local) - shape-id (first selected) - page-id (:id page) - shape-iref (-> (mf/deps shape-id page-id) - (mf/use-memo #(refs/object-by-id shape-id))) - shape (mf/deref shape-iref)] + (let [section (:options-mode local) + shapes (mf/deref refs/selected-objects)] [:& options-content {:selected selected :shape shape :page page diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/circle.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/circle.cljs index a0aae202f8..78bb4892ba 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/circle.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/circle.cljs @@ -10,7 +10,7 @@ (ns uxbox.main.ui.workspace.sidebar.options.circle (:require [rumext.alpha :as mf] - [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-menu]] + [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]] [uxbox.main.ui.workspace.sidebar.options.measures :refer [measures-menu]] [uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-menu]])) @@ -19,5 +19,5 @@ [:div [:& measures-menu {:shape shape :options #{:size :position :rotation}}] - [:& fill-menu {:shape shape}] + [:& fill-menu {:ids [(:id shape)] :values (select-keys shape fill-attrs)}] [:& stroke-menu {:shape shape}]]) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/fill.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/fill.cljs index 17a82ae6fc..a0f034e357 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/fill.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/fill.cljs @@ -10,35 +10,39 @@ (ns uxbox.main.ui.workspace.sidebar.options.fill (:require [rumext.alpha :as mf] - [uxbox.main.data.workspace :as udw] + [uxbox.main.data.workspace.common :as dwc] [uxbox.main.store :as st] [uxbox.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] [uxbox.util.object :as obj] [uxbox.util.i18n :as i18n :refer [tr t]])) +(def fill-attrs [:fill-color :fill-opacity]) + (defn- fill-menu-memo-equals? [np op] - (let [new-shape (obj/get np "shape") - old-shape (obj/get op "shape")] - (and (= (:id new-shape) - (:id old-shape)) - (identical? (:fill-color new-shape) - (:fill-color old-shape)) - (identical? (:fill-opacity new-shape) - (:fill-opacity old-shape))))) + (let [new-ids (obj/get np "ids") + old-ids (obj/get op "ids") + new-values (obj/get np "values") + old-values (obj/get op "values")] + (and (= new-ids old-ids) + (identical? (:fill-color new-values) + (:fill-color old-values)) + (identical? (:fill-opacity new-values) + (:fill-opacity old-values))))) (mf/defc fill-menu {::mf/wrap [#(mf/memo' % fill-menu-memo-equals?)]} - [{:keys [shape] :as props}] + [{:keys [ids values] :as props}] (let [locale (i18n/use-locale) - color {:value (:fill-color shape) - :opacity (:fill-opacity shape)} + color {:value (:fill-color values) + :opacity (:fill-opacity values)} handle-change-color (fn [value opacity] - (let [change {:fill-color value - :fill-opacity opacity}] - (st/emit! (udw/update-shape (:id shape) change))))] + (let [change #(cond-> % + value (assoc :fill-color value) + opacity (assoc :fill-opacity opacity))] + (st/emit! (dwc/update-shapes ids change))))] [:div.element-set [:div.element-set-title (t locale "workspace.options.fill")] [:div.element-set-content - [:& color-row {:value color + [:& color-row {:color color :on-change handle-change-color}]]])) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/frame.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/frame.cljs index 9431b5da31..cdb3ad4563 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/frame.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/frame.cljs @@ -20,7 +20,7 @@ [uxbox.main.data.workspace :as udw] [uxbox.main.ui.icons :as i] [uxbox.main.ui.components.dropdown :refer [dropdown]] - [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-menu]] + [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]] [uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-menu]] [uxbox.main.ui.workspace.sidebar.options.frame-grid :refer [frame-grid]])) @@ -202,7 +202,7 @@ [{:keys [shape] :as props}] [:div [:& measures-menu {:shape shape}] - [:& fill-menu {:shape shape}] + [:& fill-menu {:ids [(:id shape)] :values (select-keys shape fill-attrs)}] [:& stroke-menu {:shape shape}] [:& frame-grid {:shape shape}]]) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/frame_grid.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/frame_grid.cljs index 4885ad36f4..8f6ebb3025 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/frame_grid.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/frame_grid.cljs @@ -218,7 +218,7 @@ :value (:margin params) :on-change (handle-change :params :margin)}]]) - [:& color-row {:value (:color params) + [:& color-row {:color (:color params) :on-change handle-change-color}] [:div.row-flex [:button.btn-options {:disabled is-default diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/icon.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/icon.cljs index 406242c67d..222b72eaf5 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/icon.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/icon.cljs @@ -11,12 +11,12 @@ (:require [rumext.alpha :as mf] [uxbox.main.ui.workspace.sidebar.options.measures :refer [measures-menu]] - [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-menu]] + [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]] [uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-menu]])) (mf/defc options [{:keys [shape] :as props}] [:div [:& measures-menu {:shape shape}] - [:& fill-menu {:shape shape}] + [:& fill-menu {:ids [(:id shape)] :values (select-keys shape fill-attrs)}] [:& stroke-menu {:shape shape}]]) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/multiple.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/multiple.cljs new file mode 100644 index 0000000000..81d41d9fca --- /dev/null +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/multiple.cljs @@ -0,0 +1,37 @@ +;; 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 uxbox.main.ui.workspace.sidebar.options.multiple + (:require + [rumext.alpha :as mf] + [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]] + [uxbox.main.ui.workspace.sidebar.options.measures :refer [measures-menu]] + [uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-menu]])) + +(defn- get-multi + [shapes attrs] + (let [combine-value #(if (= %1 %2) %1 :multiple) + + combine-values (fn [attrs shape values] + (map #(combine-value (get shape %) (get values %)) attrs)) + + reducer (fn [result shape] + (zipmap attrs (combine-values attrs shape result)))] + + (reduce reducer (select-keys (first shapes) attrs) (rest shapes)))) + + +(mf/defc options + {::mf/wrap [mf/memo]} + [{:keys [shapes] :as props}] + (let [ids (map :id shapes) + fill-values (get-multi shapes fill-attrs)] + [:div + [:& fill-menu {:ids ids :values fill-values}]])) + diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/page.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/page.cljs index 5e0c2ef23b..7a13bab876 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/page.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/page.cljs @@ -37,8 +37,7 @@ [:div.element-set-title (t locale "workspace.options.canvas-background")] [:div.element-set-content [:& color-row {:disable-opacity true - :value {:value (get options :background "#E8E9EA") + :color {:value (get options :background "#E8E9EA") :opacity 1} - :on-change handle-change-color}]]]) - ) + :on-change handle-change-color}]]])) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/path.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/path.cljs index 1e28244118..b23b570577 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/path.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/path.cljs @@ -11,11 +11,11 @@ (:require [rumext.alpha :as mf] [uxbox.common.data :as d] - [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-menu]] + [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]] [uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-menu]])) (mf/defc options [{:keys [shape] :as props}] [:div - [:& fill-menu {:shape shape}] + [:& fill-menu {:ids [(:id shape)] :values (select-keys shape fill-attrs)}] [:& stroke-menu {:shape shape}]]) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/rect.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/rect.cljs index b13418bd2b..0c2d63568f 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/rect.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/rect.cljs @@ -10,14 +10,15 @@ (ns uxbox.main.ui.workspace.sidebar.options.rect (:require [rumext.alpha :as mf] - [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-menu]] + [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]] [uxbox.main.ui.workspace.sidebar.options.measures :refer [measures-menu]] [uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-menu]])) (mf/defc options {::mf/wrap [mf/memo]} [{:keys [shape] :as props}] - [:div - [:& measures-menu {:shape shape}] - [:& fill-menu {:shape shape}] - [:& stroke-menu {:shape shape}]]) + (let [fill-values (select-keys shape fill-attrs)] + [:div + [:& measures-menu {:shape shape}] + [:& fill-menu {:ids [(:id shape)] :values fill-values}] + [:& stroke-menu {:shape shape}]])) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/rows/color_row.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/rows/color_row.cljs index 68d3bfe45d..f55d5a9d25 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/rows/color_row.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/rows/color_row.cljs @@ -12,6 +12,8 @@ [rumext.alpha :as mf] [uxbox.common.math :as math] [uxbox.util.dom :as dom] + [uxbox.util.data :refer [classnames]] + [uxbox.util.i18n :as i18n :refer [tr]] [uxbox.main.ui.modal :as modal] [uxbox.main.ui.workspace.colorpicker :refer [colorpicker-modal]] [uxbox.common.data :as d])) @@ -29,76 +31,99 @@ :disable-opacity disable-opacity}] (modal/show! colorpicker-modal props)))) +(defn value-to-background [value] + (if (= value :multiple) "transparent" value)) + +(defn remove-hash [value] + (if (= value :multiple) "" (subs value 1))) + +(defn append-hash [value] + (str "#" value)) + (defn opacity->string [opacity] - (if (and opacity (not= opacity "")) + (if (= opacity :multiple) + "" (str (-> opacity (d/coalesce 1) (* 100) - (math/round))) - "")) + (math/round))))) (defn string->opacity [opacity-str] - (when (and opacity-str (not= "" opacity-str)) - (-> opacity-str - (d/parse-integer 1) - (/ 100)))) + (-> opacity-str + (d/parse-integer 1) + (/ 100))) -(mf/defc color-row [{:keys [value on-change disable-opacity]}] - (let [default-value {:value "#000000" :opacity 1} +(defn remove-multiple [v] + (if (= v :multiple) nil v)) - parse-value (fn [value] - (-> (merge default-value value) +(mf/defc color-row [{:keys [color on-change disable-opacity]}] + (let [default-color {:value "#000000" :opacity 1} + + parse-color (fn [color] + (-> (merge default-color color) (update :value #(or % "#000000")) (update :opacity #(or % 1)))) - state (mf/use-state (parse-value value)) + state (mf/use-state (parse-color color)) - change-color (fn [new-value] - (let [{:keys [value opacity]} @state] - (swap! state assoc :value new-value) - (when on-change (on-change new-value opacity)))) + value (:value @state) + opacity (:opacity @state) + + change-value (fn [new-value] + (swap! state assoc :value new-value) + (when on-change (on-change new-value (remove-multiple opacity)))) change-opacity (fn [new-opacity] - (let [{:keys [value opacity]} @state] - (swap! state assoc :opacity new-opacity) - (when (and new-opacity on-change) (on-change value new-opacity)))) + (swap! state assoc :opacity new-opacity) + (when on-change (on-change (remove-multiple value) new-opacity))) - handle-pick-color (fn [color opacity] - (reset! state {:value color :opacity opacity}) - (when on-change (on-change color opacity))) + handle-pick-color (fn [new-value new-opacity] + (reset! state {:value new-value :opacity new-opacity}) + (when on-change (on-change new-value new-opacity))) + + handle-value-change (fn [event] + (let [target (dom/get-target event)] + (when (dom/valid? target) + (-> target + dom/get-value + append-hash + change-value)))) - handle-input-color-change (fn [event] - (let [target (dom/get-target event) - value (dom/get-value target)] - (when (dom/valid? target) - (change-color (str "#" value))))) handle-opacity-change (fn [event] - (-> event - dom/get-target - dom/get-value - string->opacity - change-opacity)) - select-all #(-> % (dom/get-target) (.select))] + (let [target (dom/get-target event)] + (when (dom/valid? target) + (-> target + dom/get-value + string->opacity + change-opacity)))) + + select-all (fn [event] + (dom/select-text! (dom/get-target event)))] (mf/use-effect - (mf/deps value) - #(reset! state (parse-value value))) + (mf/deps color) + #(reset! state (parse-color color))) + ;; is this necessary? [:div.row-flex.color-data [:span.color-th - {:style {:background-color (-> @state :value)} - :on-click (color-picker-callback @state handle-pick-color disable-opacity)}] + {:style {:background-color (-> value value-to-background)} + :on-click (color-picker-callback @state handle-pick-color disable-opacity)} + (when (= value :multiple) "?")] [:div.color-info - [:input {:value (-> @state :value (subs 1)) + [:input {:value (-> value remove-hash) :pattern "^[0-9a-fA-F]{0,6}$" + :placeholder (tr "settings.multiple") :on-click select-all - :on-change handle-input-color-change}]] + :on-change handle-value-change}]] (when (not disable-opacity) - [:div.input-element.percentail + [:div.input-element + {:class (classnames :percentail (not= opacity :multiple))} [:input.input-text {:type "number" - :value (-> @state :opacity opacity->string) + :value (-> opacity opacity->string) + :placeholder (tr "settings.multiple") :on-click select-all :on-change handle-opacity-change :min "0" @@ -107,7 +132,7 @@ #_[:input.slidebar {:type "range" :min "0" :max "100" - :value (-> @state :opacity opacity->string) + :value (-> opacity opacity->string) :step "1" :on-change handle-opacity-change}]])) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs index dc3e401461..ea814fecd1 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs @@ -92,7 +92,7 @@ [:div.element-set-content ;; Stroke Color - [:& color-row {:value current-stroke-color + [:& color-row {:color current-stroke-color :on-change handle-change-stroke-color}] ;; Stroke Width, Alignment & Style diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/text.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/text.cljs index 7f2d3f5175..f6e8cbc876 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/text.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/text.cljs @@ -199,9 +199,8 @@ :attrs {:fill value :opacity opacity}})))] - [:& color-row {:value current-color - :on-change handle-change-color}] - )) + [:& color-row {:color current-color + :on-change handle-change-color}])) (mf/defc spacing-options [{:keys [editor shape locale] :as props}]