diff --git a/resources/public/images/svg/picker.svg b/resources/public/images/svg/picker.svg new file mode 100644 index 0000000000..a8289a958b --- /dev/null +++ b/resources/public/images/svg/picker.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/styles/dependencies/helpers.scss b/resources/styles/dependencies/helpers.scss index 5f050a678a..26a81fc4fe 100644 --- a/resources/styles/dependencies/helpers.scss +++ b/resources/styles/dependencies/helpers.scss @@ -29,7 +29,7 @@ $br-big: 8px; .row-flex { align-items: center; display: flex; - margin-bottom: $x-small; + margin-bottom: $small; &.column { flex-direction: column; diff --git a/resources/styles/partials/colorpicker.scss b/resources/styles/partials/colorpicker.scss index 5d6be9d3eb..b81d861161 100644 --- a/resources/styles/partials/colorpicker.scss +++ b/resources/styles/partials/colorpicker.scss @@ -7,94 +7,191 @@ .color-picker { display: flex; + flex-direction: column; - /* Common stuff */ - .picker-wrapper, - .slide-wrapper { - position: relative; + .picker-area { + display: flex; + + /* Common stuff */ + .picker-wrapper, + .slide-wrapper { + position: relative; + } + .picker-indicator, + .slide-indicator { + position: absolute; + left: 0; + top: 0; + pointer-events: none; + } + .picker, + .slide { + cursor: crosshair; + } } - .picker-indicator, - .slide-indicator { - position: absolute; - left: 0; - top: 0; - pointer-events: none; - } - .picker, - .slide { - cursor: crosshair; - } -} -/* Default skin */ - -.color-picker-default { - padding: 4px; - border-radius: 2px; - - .picker { + .inputs-area { + display: flex; + justify-content: space-around; width: 200px; - height: 200px; + + .row-flex{ + margin: 0; + } + + > input { + width: 50%; + } + + .input-text { + color: $intense-ui-text; + font-size: $fs13; + margin: 5px; + padding: 5px; + width: 100%; + } + } - .slide { - width: 20px; - height: 200px; + span { + color: $medium-ui-text; + font-size: $fs12; } - .slide-wrapper { - margin-left: 4px; + + + /* Default skin */ + + &.theme-default { + padding: 4px; + border-radius: 2px; + width: 230px; + + .picker { + width: 200px; + height: 200px; + } + + .slide { + width: 20px; + height: 200px; + } + .slide-wrapper { + margin-left: 4px; + } + .picker-indicator { + width: 5px; + height: 5px; + border: 2px solid darkblue; + border-radius: 4px; + opacity: .5; + background-color: white; + } + .slide-indicator { + width: 28px; + height: 10px; + left: -4px; + opacity: .6; + border: 4px solid lightblue; + border-radius: 4px; + background-color: white; + } + + .inputs-area { + width: 230px; + } + } - .picker-indicator { - width: 5px; - height: 5px; - border: 2px solid darkblue; - border-radius: 4px; - opacity: .5; - background-color: white; + + /* Small skin */ + + &.theme-small { + border-radius: 2px; + + .picker { + width: 170px; + height: 170px; + } + + .slide { + width: 20px; + height: 170px; + } + .slide-wrapper { + margin-left: 4px; + } + .picker-indicator { + width: 5px; + height: 5px; + border: 2px solid darkblue; + border-radius: 4px; + opacity: .5; + background-color: white; + } + .slide-indicator { + width: 28px; + height: 10px; + left: -4px; + opacity: .6; + border: 4px solid lightblue; + border-radius: 4px; + background-color: white; + } + } - .slide-indicator { - width: 28px; - height: 10px; - left: -4px; - opacity: .6; - border: 4px solid lightblue; - border-radius: 4px; - background-color: white; + +} + +/* NEW COLOR PICKER */ +/* color th */ +.color-data { + align-items: center; + display: flex; + position: relative; + + .color-info { + border: 1px solid $soft-ui-border; + border-radius: $br-small; + margin: 3px 0 0 $x-small; + padding: 0 $x-small; + } + + .type { + color: $soft-ui-text; + margin-right: $x-small; + } + + .number { + color: $intense-ui-text; } } -/* Small skin */ +.colorpicker-tooltip { + background: $color-white; + border-radius: $br-small; + display: flex; + flex-direction: column; + left: 1400px; + top: 100px; + padding: $small; + position: absolute; + z-index: 11; + width: auto; -.color-picker-small { - border-radius: 2px; - - .picker { - width: 170px; - height: 170px; + span { + color: $medium-ui-text; + font-size: $fs12; } - .slide { - width: 20px; - height: 170px; - } - .slide-wrapper { - margin-left: 4px; - } - .picker-indicator { - width: 5px; - height: 5px; - border: 2px solid darkblue; - border-radius: 4px; - opacity: .5; - background-color: white; - } - .slide-indicator { - width: 28px; - height: 10px; - left: -4px; - opacity: .6; - border: 4px solid lightblue; - border-radius: 4px; - background-color: white; + .inputs-area { + + .input-text { + color: $intense-ui-text; + font-size: $fs13; + margin: 5px; + padding: 5px; + width: 100%; + } + } + } diff --git a/resources/styles/partials/lightbox.scss b/resources/styles/partials/lightbox.scss index b602ab2b08..0eb2364c47 100644 --- a/resources/styles/partials/lightbox.scss +++ b/resources/styles/partials/lightbox.scss @@ -17,6 +17,10 @@ width: 100%; z-index: 1000; + &.transparent { + background-color: rgba(0,0,0,0); + } + .lightbox-body { align-items: center; background-color: $color-white; diff --git a/resources/styles/partials/sidebar-element-options.scss b/resources/styles/partials/sidebar-element-options.scss index 9528c8d03d..cf09de28f1 100644 --- a/resources/styles/partials/sidebar-element-options.scss +++ b/resources/styles/partials/sidebar-element-options.scss @@ -150,14 +150,14 @@ &.palette-th { align-items: center; - border: 2px solid $medium-ui-icons; + border: 1px solid $medium-ui-icons; display: flex; justify-content: center; svg { fill: $medium-ui-icons; - height: 18px; - width: 18px; + height: 16px; + width: 16px; } &:hover { diff --git a/src/uxbox/ui/auth.cljs b/src/uxbox/ui/auth.cljs index c3643551da..cad763888b 100644 --- a/src/uxbox/ui/auth.cljs +++ b/src/uxbox/ui/auth.cljs @@ -1,3 +1,9 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) 2016 Andrey Antukh + (ns uxbox.ui.auth (:require [sablono.core :as html :refer-macros [html]] [lentes.core :as l] diff --git a/src/uxbox/ui/colorpicker.cljs b/src/uxbox/ui/colorpicker.cljs index b0fc66260c..b8486238c1 100644 --- a/src/uxbox/ui/colorpicker.cljs +++ b/src/uxbox/ui/colorpicker.cljs @@ -10,9 +10,11 @@ [lentes.core :as l] [goog.events :as events] [uxbox.schema :as sc] - [uxbox.util.color :as color] + [uxbox.ui.mixins :as mx] [uxbox.util.math :as mth] - [uxbox.ui.mixins :as mx]) + [uxbox.util.data :as data] + [uxbox.util.dom :as dom] + [uxbox.util.color :as color]) (:import goog.events.EventType)) ;; --- Picker Box @@ -115,6 +117,10 @@ [own & {:keys [value on-change theme] :or {value "#d4edfb" theme :default}}] (let [local (:rum/local own) + value-rgb (color/hex->rgb value) + classes (case theme + :default "theme-default" + :small "theme-small") dimensions (case theme :default default-dimensions :small small-dimensions @@ -128,47 +134,88 @@ (/ (:pi-width dimensions) 2)) sit (- (/ (* (- h 15) (:s-height dimensions)) 360) - (/ (:si-height dimensions) 2)) + (/ (:si-height dimensions) 2))] + (letfn [(on-mouse-down [event] + (swap! local assoc :mousedown true)) + (on-mouse-up [event] + (swap! local assoc :mousedown false)) + (on-mouse-move-slide [event] + (when (:mousedown @local) + (on-slide-click local dimensions event))) + (on-mouse-move-picker [event] + (when (:mousedown @local) + (on-picker-click local dimensions on-change color event))) + (on-hex-changed [event] + (let [value (-> (dom/get-target event) + (dom/get-value))] + (when (color/hex? value) + (on-change value)))) + (on-rgb-change [rgb id event] + (let [value (-> (dom/get-target event) + (dom/get-value) + (data/parse-int 0)) + rgb (assoc rgb id value) + hex (color/rgb->hex rgb)] + (when (color/hex? hex) + (on-change hex))))] + (html + [:div.color-picker {:class classes} + [:div.picker-area + #_[:div.tester {:style {:width "100px" :height "100px" + :border "1px solid black" + :position "fixed" :top "50px" :left "50px" + :backgroundColor (color/hsv->hex color)}}] + [:div.picker-wrapper + [:div.picker + {:ref "picker" + :on-click (partial on-picker-click local dimensions on-change color) + :on-mouse-down on-mouse-down + :on-mouse-up on-mouse-up + :on-mouse-move on-mouse-move-picker + :style {:backgroundColor bg}} + (picker-box)] + [:div.picker-indicator + {:ref "picker-indicator" + :style {:top (str pil "px") + :left (str pit "px") + :pointerEvents "none"}}]] + [:div.slide-wrapper + [:div.slide + {:ref "slide" + :on-mouse-down on-mouse-down + :on-mouse-up on-mouse-up + :on-mouse-move on-mouse-move-slide + :on-click (partial on-slide-click local dimensions)} + (slider-box)] + [:div.slide-indicator + {:ref "slide-indicator" + :style {:top (str sit "px") + :pointerEvents "none"}}]]] + + [:div.inputs-area + [:input.input-text + {:placeholder "#" + :type "text" + :value value + :on-change on-hex-changed}] + [:div.row-flex + [:input.input-text + {:placeholder "R" + :on-change (partial on-rgb-change value-rgb 0) + :value (nth value-rgb 0) + :type "number"}] + [:input.input-text + {:placeholder "G" + :on-change (partial on-rgb-change value-rgb 1) + :value (nth value-rgb 1) + :type "number"}] + [:input.input-text + {:placeholder "B" + :on-change (partial on-rgb-change value-rgb 2) + :value (nth value-rgb 2) + :type "number"}]]]])))) - on-mouse-down #(swap! local assoc :mousedown true) - on-mouse-up #(swap! local assoc :mousedown false) - on-mouse-move-slide #(when (:mousedown @local) - (on-slide-click local dimensions %)) - on-mouse-move-picker #(when (:mousedown @local) - (on-picker-click local dimensions on-change color %))] - (html - [:div.color-picker - #_[:div.tester {:style {:width "100px" :height "100px" - :border "1px solid black" - :position "fixed" :top "50px" :left "50px" - :backgroundColor (color/hsv->hex color)}}] - [:div.picker-wrapper - [:div.picker - {:ref "picker" - :on-click (partial on-picker-click local dimensions on-change color) - :on-mouse-down on-mouse-down - :on-mouse-up on-mouse-up - :on-mouse-move on-mouse-move-picker - :style {:backgroundColor bg}} - (picker-box)] - [:div.picker-indicator - {:ref "picker-indicator" - :style {:top (str pil "px") - :left (str pit "px") - :pointerEvents "none"}}]] - [:div.slide-wrapper - [:div.slide - {:ref "slide" - :on-mouse-down on-mouse-down - :on-mouse-up on-mouse-up - :on-mouse-move on-mouse-move-slide - :on-click (partial on-slide-click local dimensions)} - (slider-box)] - [:div.slide-indicator - {:ref "slide-indicator" - :style {:top (str sit "px") - :pointerEvents "none"}}]]]))) (def ^:static colorpicker (mx/component diff --git a/src/uxbox/ui/dashboard/colors.cljs b/src/uxbox/ui/dashboard/colors.cljs index 5e6294e70d..31fd7d07a9 100644 --- a/src/uxbox/ui/dashboard/colors.cljs +++ b/src/uxbox/ui/dashboard/colors.cljs @@ -265,14 +265,7 @@ [:div.lightbox-body [:h3 "New color"] [:form - [:div.row-flex - [:input#color-hex.input-text - {:placeholder "#" - :class (form/error-class local :hex) - :on-change on-change - :value (or (:hex @local) color "") - :type "text"}]] - [:div.row-flex.center.color-picker-default + [:div.row-flex.center (colorpicker :value (or (:hex @local) color "#00ccff") :on-change #(swap! local assoc :hex %))] diff --git a/src/uxbox/ui/icons.cljs b/src/uxbox/ui/icons.cljs index 12426d1769..7058ecfa03 100644 --- a/src/uxbox/ui/icons.cljs +++ b/src/uxbox/ui/icons.cljs @@ -680,3 +680,14 @@ {:style {:stroke nil} :d "M34 6h-24c-2.21 0-4 1.79-4 4v28c0 2.21 1.79 4 4 4h28c2.21 0 4-1.79 4-4v-24l-8-8zm-10 32c-3.31 0-6-2.69-6-6s2.69-6 6-6 6 2.69 6 6-2.69 6-6 6zm6-20h-20v-8h20v8z"}]])) + +(def picker + (html + [:svg + {:viewBox "0 0 500.00001 500.00001" + :height "500" + :width "500"} + [:g + [:path + {:d + "M11.402 498.536c-4.64-1.613-8.317-5.335-9.896-10.02-.732-2.168-.824-7.17-.824-44.7 0-45.853-.04-45.148 2.807-49.542.653-1.01 53.238-53.866 116.855-117.46 63.617-63.59 115.667-115.852 115.667-116.134 0-.282-11.486-11.997-25.524-26.033-14.038-14.036-25.524-25.75-25.524-26.034 0-.283 14.816-15.328 32.924-33.434l32.924-32.922 29.607 29.59 29.607 29.592 44.286-44.17c32.81-32.726 45.278-44.843 48.115-46.76 7.434-5.025 16.28-8.752 24.758-10.432 5.316-1.053 18.308-.91 23.737.26 25.043 5.4 44.058 24.808 49.064 50.08.927 4.68.927 17.78 0 22.46-1.68 8.48-5.407 17.326-10.432 24.76-1.917 2.836-14.034 15.303-46.76 48.114l-44.17 44.286 29.59 29.608 29.592 29.608-32.92 32.923c-18.107 18.108-33.152 32.924-33.435 32.924-.283 0-11.998-11.485-26.034-25.523s-25.75-25.524-26.033-25.524c-.282 0-52.543 52.05-116.135 115.667-63.593 63.617-116.45 116.202-117.46 116.856-4.4 2.85-3.662 2.81-49.686 2.783-37.102-.023-42.692-.126-44.702-.824zM199.638 353.77C262.6 290.81 314.115 239.07 314.115 238.79c0-.67-52.165-52.838-52.834-52.838-.282 0-52.026 51.515-114.986 114.477L31.82 414.904v26.057c0 19.588.153 26.21.614 26.67.46.462 7.084.614 26.67.614H85.16L199.64 353.77z"}]]])) diff --git a/src/uxbox/ui/lightbox.cljs b/src/uxbox/ui/lightbox.cljs index 66f28ce806..186f0b7cd1 100644 --- a/src/uxbox/ui/lightbox.cljs +++ b/src/uxbox/ui/lightbox.cljs @@ -6,6 +6,8 @@ [uxbox.data.lightbox :as udl] [uxbox.ui.mixins :as mx] [uxbox.ui.keyboard :as k] + [uxbox.util.dom :as dom] + [uxbox.util.data :refer (classnames)] [goog.events :as events]) (:import goog.events.EventType)) @@ -21,9 +23,17 @@ (defmethod render-lightbox :default [_] nil) (defn- on-esc-clicked - [e] - (when (k/esc? e) - (udl/close!))) + [event] + (when (k/esc? event) + (udl/close!) + (dom/stop-propagation event))) + +(defn- on-out-clicked + [own event] + (let [parent (mx/get-ref-dom own "parent") + current (dom/get-target event)] + (when (dom/equals? parent current) + (udl/close!)))) (defn- lightbox-will-mount [own] @@ -43,10 +53,15 @@ (defn- lightbox-render [own] - (let [data (rum/react lightbox-l)] + (let [data (rum/react lightbox-l) + classes (classnames + :hide (nil? data) + :transparent (:transparent? data))] (html [:div.lightbox - {:class (when (nil? data) "hide")} + {:class classes + :ref "parent" + :on-click (partial on-out-clicked own)} (render-lightbox data)]))) (def lightbox diff --git a/src/uxbox/ui/users.cljs b/src/uxbox/ui/users.cljs index e89f0d10c8..982becec75 100644 --- a/src/uxbox/ui/users.cljs +++ b/src/uxbox/ui/users.cljs @@ -1,3 +1,9 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) 2016 Andrey Antukh + (ns uxbox.ui.users (:require [sablono.core :as html :refer-macros [html]] [lentes.core :as l] diff --git a/src/uxbox/ui/workspace/colorpicker.cljs b/src/uxbox/ui/workspace/colorpicker.cljs new file mode 100644 index 0000000000..5afdfbd3e6 --- /dev/null +++ b/src/uxbox/ui/workspace/colorpicker.cljs @@ -0,0 +1,68 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) 2016 Andrey Antukh +;; Copyright (c) 2016 Juan de la Cruz + +(ns uxbox.ui.workspace.colorpicker + (:require [sablono.core :as html :refer-macros [html]] + [rum.core :as rum] + [lentes.core :as l] + [uxbox.locales :refer (tr)] + [uxbox.router :as r] + [uxbox.rstore :as rs] + [uxbox.state :as st] + [uxbox.data.workspace :as udw] + [uxbox.data.shapes :as uds] + [uxbox.ui.workspace.base :as wb] + [uxbox.ui.icons :as i] + [uxbox.ui.mixins :as mx] + [uxbox.ui.lightbox :as lbx] + [uxbox.ui.colorpicker :as cp] + [uxbox.ui.workspace.recent-colors :refer (recent-colors)] + [uxbox.ui.workspace.base :as wb] + [uxbox.util.geom :as geom] + [uxbox.util.dom :as dom] + [uxbox.util.data :refer (parse-int parse-float read-string)])) + +(defn- focus-shape + [id] + (as-> (l/in [:shapes-by-id id]) $ + (l/focus-atom $ st/state))) + +(defn- colorpicker-render + [own {:keys [x y shape attr] :as opts}] + (let [shape (rum/react (focus-shape shape)) + left (- x 260) + top (- y 50)] + (letfn [(change-color [color] + (let [attrs {:color color}] + (rs/emit! + (case attr + :stroke (uds/update-stroke-attrs (:id shape) attrs) + :fill (uds/update-fill-attrs (:id shape) attrs))))) + (on-change-color [event] + (let [color (dom/event->value event)] + (change-color color)))] + (html + [:div.colorpicker-tooltip + {:style {:left (str left "px") + :top (str top "px")}} + + (cp/colorpicker + :theme :small + :value (:stroke shape "#000000") + :on-change change-color) + + (recent-colors shape change-color)])))) + +(def colorpicker + (mx/component + {:render colorpicker-render + :name "colorpicker" + :mixins [rum/reactive mx/static]})) + +(defmethod lbx/render-lightbox :workspace/colorpicker + [params] + (colorpicker params)) diff --git a/src/uxbox/ui/workspace/header.cljs b/src/uxbox/ui/workspace/header.cljs index 1dad5d9961..4f33031291 100644 --- a/src/uxbox/ui/workspace/header.cljs +++ b/src/uxbox/ui/workspace/header.cljs @@ -94,6 +94,11 @@ :class (when (contains? flags :drawtools) "selected") :on-click (partial toggle :drawtools)} i/shapes] + [:li.tooltip.tooltip-bottom + {:alt "Color Palette (---)" + :class (when (contains? flags :colorpalette) "selected") + :on-click (partial toggle :colorpalette)} + i/palette] [:li.tooltip.tooltip-bottom {:alt "Icons (Ctrl + Shift + I)" :class (when (contains? flags :icons) "selected") diff --git a/src/uxbox/ui/workspace/recent_colors.cljs b/src/uxbox/ui/workspace/recent_colors.cljs index 0fb4dac7ed..d14de70f81 100644 --- a/src/uxbox/ui/workspace/recent_colors.cljs +++ b/src/uxbox/ui/workspace/recent_colors.cljs @@ -18,12 +18,7 @@ [uxbox.util.dom :as dom] [uxbox.ui.workspace.base :as wb])) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Helpers -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(def ^:private ^:static toggle-colorpalette - #(rs/emit! (dw/toggle-flag :colorpalette))) +;; --- Helpers (defn- count-color [state shape prop] @@ -41,9 +36,7 @@ (sort-by second (into [] $)) (take 5 (map first $)))) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Component -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; --- Component (defn- recent-colors-render [own {:keys [page id] :as shape} callback] @@ -56,16 +49,14 @@ [:span (tr "ds.recent-colors")] [:div.row-flex (for [color colors] - [:span.color-th {:style {:background color} + [:span.color-th {:style {:background-color color} :key color :on-click (partial callback color)}]) (for [i (range (- 5 (count colors)))] [:span.color-th {:key (str "empty" i)}]) + [:span.color-th.palette-th i/picker]]]))) - [:span.color-th.palette-th {:on-click toggle-colorpalette} - i/palette]]]))) - -(def ^:static recent-colors +(def recent-colors (mx/component {:render recent-colors-render :name "recent-colors" diff --git a/src/uxbox/ui/workspace/settings.cljs b/src/uxbox/ui/workspace/settings.cljs index 1f9947425b..7e91becc93 100644 --- a/src/uxbox/ui/workspace/settings.cljs +++ b/src/uxbox/ui/workspace/settings.cljs @@ -80,10 +80,9 @@ :min 1 :max 100}]] [:span.lightbox-label "Grid color"] - [:div.color-picker-default - (uucp/colorpicker - :value (:grid/color form) - :on-change on-color-change)] + (uucp/colorpicker + :value (:grid/color form) + :on-change on-color-change) [:span.lightbox-label "Grid magnet option"] [:div.input-checkbox.check-primary [:input diff --git a/src/uxbox/ui/workspace/sidebar/options.cljs b/src/uxbox/ui/workspace/sidebar/options.cljs index c884864689..26744e19cf 100644 --- a/src/uxbox/ui/workspace/sidebar/options.cljs +++ b/src/uxbox/ui/workspace/sidebar/options.cljs @@ -19,19 +19,22 @@ [uxbox.ui.workspace.base :as wb] [uxbox.ui.icons :as i] [uxbox.ui.mixins :as mx] - [uxbox.ui.colorpicker :refer (colorpicker)] + [uxbox.ui.workspace.colorpicker :refer (colorpicker)] [uxbox.ui.workspace.recent-colors :refer (recent-colors)] - [uxbox.ui.workspace.base :as wb] + [uxbox.ui.workspace.sidebar.options.icon-measures :as options-iconm] + [uxbox.ui.workspace.sidebar.options.circle-measures :as options-circlem] + [uxbox.ui.workspace.sidebar.options.rect-measures :as options-rectm] + [uxbox.ui.workspace.sidebar.options.line-measures :as options-linem] + [uxbox.ui.workspace.sidebar.options.fill :as options-fill] + [uxbox.ui.workspace.sidebar.options.text :as options-text] + [uxbox.ui.workspace.sidebar.options.stroke :as options-stroke] [uxbox.util.geom :as geom] - [uxbox.util.lens :as ul] [uxbox.util.dom :as dom] [uxbox.util.data :refer (parse-int parse-float read-string)])) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Constants -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; --- Constants -(def ^:const ^:private +menus-map+ +(def ^:private +menus-map+ {:icon [:menu/icon-measures :menu/fill :menu/stroke] :rect [:menu/rect-measures :menu/fill :menu/stroke] :line [:menu/line-measures :menu/stroke] @@ -39,590 +42,42 @@ :text [:menu/fill :menu/text] :group []}) -(def ^:const ^:private +menus-by-id+ - {:menu/icon-measures +(def ^:private +menus+ + [{:name "Size, position & rotation" + :id :menu/icon-measures + :icon i/infocard + :comp options-iconm/icon-measures-menu} {:name "Size, position & rotation" - :icon i/infocard} - - :menu/rect-measures + :id :menu/rect-measures + :icon i/infocard + :comp options-rectm/rect-measures-menu} {:name "Size, position & rotation" - :icon i/infocard} - - :menu/line-measures + :id :menu/line-measures + :icon i/infocard + :comp options-linem/line-measures-menu} {:name "Size, position & rotation" - :icon i/infocard} - - :menu/circle-measures - {:name "Size, position & rotation" - :icon i/infocard} - - :menu/fill + :id :menu/circle-measures + :icon i/infocard + :comp options-circlem/circle-measures-menu} {:name "Fill" - :icon i/fill} - - :menu/stroke + :id :menu/fill + :icon i/fill + :comp options-fill/fill-menu} {:name "Stroke" - :icon i/stroke} - - :menu/text + :id :menu/stroke + :icon i/stroke + :comp options-stroke/stroke-menu} {:name "Text" - :icon i/text}}) + :id :menu/text + :icon i/text + :comp options-text/text-menu}]) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Implementation -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(def ^:private +menus-by-id+ + (into {} (map #(vector (:id %) %)) +menus+)) -(defmulti -render-menu - (fn [menu own shape] (:id menu))) +;; --- Options -(defmethod -render-menu :menu/stroke - [menu own shape] - (letfn [(change-stroke [value] - (let [sid (:id shape)] - (rs/emit! (uds/update-stroke-attrs sid value)))) - (on-width-change [event] - (let [value (dom/event->value event) - value (parse-float value 1)] - (change-stroke {:width value}))) - (on-opacity-change [event] - (let [value (dom/event->value event) - value (parse-float value 1) - value (/ value 10000)] - (change-stroke {:opacity value}))) - (on-color-change [event] - (let [value (dom/event->value event)] - (change-stroke {:color value}))) - (on-stroke-style-change [event] - (let [value (dom/event->value event) - value (read-string value)] - (change-stroke {:type value})))] - (html - [:div.element-set {:key (str (:id menu))} - [:div.element-set-title (:name menu)] - [:div.element-set-content - [:span "Style"] - [:div.row-flex - [:select#style.input-select {:placeholder "Style" - :value (:stroke-type shape) - :on-change on-stroke-style-change} - [:option {:value ":none"} "None"] - [:option {:value ":solid"} "Solid"] - [:option {:value ":dotted"} "Dotted"] - [:option {:value ":dashed"} "Dashed"] - [:option {:value ":mixed"} "Mixed"]] - [:input.input-text - {:placeholder "Width" - :type "number" - :min "0" - :value (:stroke-width shape "1") - :on-change on-width-change}]] - - ;; SLIDEBAR FOR ROTATION AND OPACITY - [:span "Color"] - [:div.color-picker-small - (colorpicker - :theme :small - :value (:stroke shape "#000000") - :on-change #(change-stroke {:color %}))] - - [:div.row-flex - [:input.input-text - {:placeholder "#" - :type "text" - :value (:stroke shape "") - :on-change on-color-change}]] - - (recent-colors shape #(change-stroke {:color %})) - - ;; SLIDEBAR FOR ROTATION AND OPACITY - [:span "Opacity"] - [:div.row-flex - [:input.slidebar - {:type "range" - :min "0" - :max "10000" - :value (* 10000 (:stroke-opacity shape 1)) - :step "1" - :on-change on-opacity-change}]]]]))) - -(defmethod -render-menu :menu/fill - [menu own shape] - (letfn [(change-fill [value] - (let [sid (:id shape)] - (rs/emit! (uds/update-fill-attrs sid value)))) - (on-color-change [event] - (let [value (dom/event->value event)] - (change-fill {:color value}))) - (on-opacity-change [event] - (let [value (dom/event->value event) - value (parse-float value 1) - value (/ value 10000)] - (change-fill {:opacity value}))) - (on-color-picker-event [color] - (change-fill {:color color}))] - (html - [:div.element-set {:key (str (:id menu))} - [:div.element-set-title (:name menu)] - [:div.element-set-content - ;; SLIDEBAR FOR ROTATION AND OPACITY - [:span "Color"] - - [:div.color-picker-small - (colorpicker - :theme :small - :value (:fill shape "#000000") - :on-change #(on-color-picker-event %))] - - [:div.row-flex - [:input.input-text - {:placeholder "#" - :type "text" - :value (:fill shape "") - :on-change on-color-change}]] - - (recent-colors shape #(change-fill {:color %})) - - ;; SLIDEBAR FOR ROTATION AND OPACITY - [:span "Opacity"] - [:div.row-flex - [:input.slidebar - {:type "range" - :min "0" - :max "10000" - :value (* 10000 (:fill-opacity shape 1)) - :step "1" - :on-change on-opacity-change}]]]]))) - -(defmethod -render-menu :menu/rect-measures - [menu own shape local] - (letfn [(on-size-change [attr event] - (let [value (dom/event->value event) - value (parse-int value 0) - sid (:id shape) - props {attr value}] - (rs/emit! (uds/update-size sid props)))) - (on-rotation-change [event] - (let [value (dom/event->value event) - value (parse-int value 0) - sid (:id shape)] - (rs/emit! (uds/update-rotation sid value)))) - (on-pos-change [attr event] - (let [value (dom/event->value event) - value (parse-int value nil) - sid (:id shape) - props {attr value}] - (rs/emit! (uds/update-position sid props)))) - (on-border-change [attr event] - (let [value (dom/event->value event) - value (parse-int value nil) - sid (:id shape) - props {attr value}] - (rs/emit! (uds/update-radius-attrs sid props))))] - (let [size (geom/size shape)] - (html - [:div.element-set {:key (str (:id menu))} - [:div.element-set-title (:name menu)] - [:div.element-set-content - ;; SLIDEBAR FOR ROTATION AND OPACITY - [:span "Size"] - [:div.row-flex - [:input.input-text - {:placeholder "Width" - :type "number" - :min "0" - :value (:width size) - :on-change (partial on-size-change :width)}] - [:div.lock-size i/lock] - [:input.input-text - {:placeholder "Height" - :type "number" - :min "0" - :value (:height size) - :on-change (partial on-size-change :height)}]] - - [:span "Position"] - [:div.row-flex - [:input.input-text - {:placeholder "x" - :type "number" - :value (:x1 shape "") - :on-change (partial on-pos-change :x)}] - [:input.input-text - {:placeholder "y" - :type "number" - :value (:y1 shape "") - :on-change (partial on-pos-change :y)}]] - - [:span "Border radius"] - [:div.row-flex - [:input.input-text - {:placeholder "rx" - :type "number" - :value (:rx shape "") - :on-change (partial on-border-change :rx)}] - [:div.lock-size i/lock] - [:input.input-text - {:placeholder "ry" - :type "number" - :value (:ry shape "") - :on-change (partial on-border-change :ry)}]] - - [:span "Rotation"] - [:div.row-flex - [:input.slidebar - {:type "range" - :min 0 - :max 360 - :value (:rotation shape 0) - :on-change on-rotation-change}]] - - [:div.row-flex - [:input.input-text - {:placeholder "" - :type "number" - :min 0 - :max 360 - :value (:rotation shape "0") - :on-change on-rotation-change - }] - [:input.input-text - {:style {:visibility "hidden"}}] - ]]] - )))) - - -(defmethod -render-menu :menu/icon-measures - [menu own shape] - (letfn [(on-size-change [attr event] - (let [value (dom/event->value event) - value (parse-int value 0) - sid (:id shape) - props {attr value}] - (rs/emit! (uds/update-size sid props)))) - (on-rotation-change [event] - (let [value (dom/event->value event) - value (parse-int value 0) - sid (:id shape)] - (rs/emit! (uds/update-rotation sid value)))) - (on-pos-change [attr event] - (let [value (dom/event->value event) - value (parse-int value nil) - sid (:id shape) - props {attr value}] - (rs/emit! (uds/update-position sid props))))] - (let [size (geom/size shape)] - (html - [:div.element-set {:key (str (:id menu))} - [:div.element-set-title (:name menu)] - [:div.element-set-content - ;; SLIDEBAR FOR ROTATION AND OPACITY - [:span "Size"] - [:div.row-flex - [:input.input-text - {:placeholder "Width" - :type "number" - :min "0" - :value (:width size) - :on-change (partial on-size-change :width)}] - [:div.lock-size i/lock] - [:input.input-text - {:placeholder "Height" - :type "number" - :min "0" - :value (:height size) - :on-change (partial on-size-change :height)}]] - - [:span "Position"] - [:div.row-flex - [:input.input-text - {:placeholder "x" - :type "number" - :value (:x1 shape "") - :on-change (partial on-pos-change :x)}] - [:input.input-text - {:placeholder "y" - :type "number" - :value (:y1 shape "") - :on-change (partial on-pos-change :y)}]] - - [:span "Rotation"] - [:div.row-flex - [:input.slidebar - {:type "range" - :min 0 - :max 360 - :value (:rotation shape 0) - :on-change on-rotation-change}]] - - [:div.row-flex - [:input.input-text - {:placeholder "" - :type "number" - :min 0 - :max 360 - :value (:rotation shape "0") - :on-change on-rotation-change - }] - [:input.input-text - {:style {:visibility "hidden"}}] - ]]] - )))) - -(defmethod -render-menu :menu/circle-measures - [menu own shape] - (letfn [(on-size-change [attr event] - (let [value (dom/event->value event) - value (parse-int value 0) - sid (:id shape) - props {attr value}] - (rs/emit! (uds/update-radius-attrs sid props)))) - (on-rotation-change [event] - (let [value (dom/event->value event) - value (parse-int value 0) - sid (:id shape)] - (rs/emit! (uds/update-rotation sid value)))) - (on-pos-change [attr event] - (let [value (dom/event->value event) - value (parse-int value nil) - sid (:id shape) - props {attr value}] - (rs/emit! (uds/update-position sid props))))] - (html - [:div.element-set {:key (str (:id menu))} - [:div.element-set-title (:name menu)] - [:div.element-set-content - ;; SLIDEBAR FOR ROTATION AND OPACITY - [:span "Size"] - [:div.row-flex - [:input.input-text - {:placeholder "Width" - :type "number" - :min "0" - :value (:rx shape) - :on-change (partial on-size-change :rx)}] - [:div.lock-size i/lock] - [:input.input-text - {:placeholder "Height" - :type "number" - :min "0" - :value (:ry shape) - :on-change (partial on-size-change :ry)}]] - - [:span "Position"] - [:div.row-flex - [:input.input-text - {:placeholder "cx" - :type "number" - :value (:cx shape "") - :on-change (partial on-pos-change :x)}] - [:input.input-text - {:placeholder "cy" - :type "number" - :value (:cy shape "") - :on-change (partial on-pos-change :y)}]] - - [:span "Rotation"] - [:div.row-flex - [:input.slidebar - {:type "range" - :min 0 - :max 360 - :value (:rotation shape 0) - :on-change on-rotation-change}]] - - [:div.row-flex - [:input.input-text - {:placeholder "" - :type "number" - :min 0 - :max 360 - :value (:rotation shape "0") - :on-change on-rotation-change - }] - [:input.input-text - {:style {:visibility "hidden"}}] - ]]] - ))) - -(defmethod -render-menu :menu/line-measures - [menu own shape] - (letfn [(on-rotation-change [event] - (let [value (dom/event->value event) - value (parse-int value 0) - sid (:id shape)] - (rs/emit! (uds/update-rotation sid value)))) - (on-pos-change [attr event] - (let [value (dom/event->value event) - value (parse-int value nil) - sid (:id shape) - props {attr value}] - (rs/emit! (uds/update-line-attrs sid props))))] - (html - [:div.element-set {:key (str (:id menu))} - [:div.element-set-title (:name menu)] - [:div.element-set-content - [:span "Position"] - [:div.row-flex - [:input.input-text - {:placeholder "x1" - :type "number" - :value (:x1 shape "") - :on-change (partial on-pos-change :x1)}] - [:input.input-text - {:placeholder "y1" - :type "number" - :value (:y1 shape "") - :on-change (partial on-pos-change :y1)}]] - - [:div.row-flex - [:input.input-text - {:placeholder "x2" - :type "number" - :value (:x2 shape "") - :on-change (partial on-pos-change :x2)}] - [:input.input-text - {:placeholder "y2" - :type "number" - :value (:y2 shape "") - :on-change (partial on-pos-change :y2)}]] - - [:span "Rotation"] - [:div.row-flex - [:input.slidebar - {:type "range" - :min 0 - :max 360 - :value (:rotation shape 0) - :on-change on-rotation-change}]] - - [:div.row-flex - [:input.input-text - {:placeholder "" - :type "number" - :min 0 - :max 360 - :value (:rotation shape "0") - :on-change on-rotation-change - }] - [:input.input-text - {:style {:visibility "hidden"}}] - ]]] - ))) - -(defmethod -render-menu :menu/text - [menu own {:keys [font] :as shape}] - (letfn [(on-font-family-change [event] - (let [value (dom/event->value event) - sid (:id shape) - params {:family (read-string value) - :weight "normal" - :style "normal"}] - (rs/emit! (uds/update-font-attrs sid params)))) - (on-font-size-change [event] - (let [value (dom/event->value event) - params {:size (parse-int value)} - sid (:id shape)] - (rs/emit! (uds/update-font-attrs sid params)))) - (on-font-letter-spacing-change [event] - (let [value (dom/event->value event) - params {:letter-spacing (parse-float value)} - sid (:id shape)] - (rs/emit! (uds/update-font-attrs sid params)))) - (on-font-line-height-change [event] - (let [value (dom/event->value event) - params {:line-height (parse-float value)} - sid (:id shape)] - (rs/emit! (uds/update-font-attrs sid params)))) - (on-font-align-change [event value] - (let [params {:align value} - sid (:id shape)] - (rs/emit! (uds/update-font-attrs sid params)))) - - (on-font-style-change [event] - (let [value (dom/event->value event) - [weight style] (read-string value) - sid (:id shape) - params {:style style - :weight weight}] - (rs/emit! (uds/update-font-attrs sid params))))] - (let [{:keys [family style weight size align line-height letter-spacing] - :or {family "sourcesanspro" - align "left" - style "normal" - weight "normal" - letter-spacing 1 - line-height 1.4 - size 16}} font - styles (:styles (first (filter #(= (:id %) family) library/+fonts+)))] - (html - [:div.element-set {:key (str (:id menu))} - [:div.element-set-title (:name menu)] - [:div.element-set-content - - [:span "Font family"] - [:div.row-flex - [:select.input-select {:value (pr-str family) - :on-change on-font-family-change} - (for [font library/+fonts+] - [:option {:value (pr-str (:id font)) - :key (:id font)} (:name font)])]] - - [:span "Size and Weight"] - [:div.row-flex - [:input.input-text - {:placeholder "Font Size" - :type "number" - :min "0" - :max "200" - :value size - :on-change on-font-size-change}] - [:select.input-select {:value (pr-str [weight style]) - :on-change on-font-style-change} - (for [style styles - :let [data (mapv #(get style %) [:weight :style])]] - [:option {:value (pr-str data) - :key (:name style)} (:name style)])]] - - [:span "Line height and Letter spacing"] - [:div.row-flex - [:input.input-text - {:placeholder "Line height" - :type "number" - :step "0.1" - :min "0" - :max "200" - :value line-height - :on-change on-font-line-height-change}] - [:input.input-text - {:placeholder "Letter spacing" - :type "number" - :step "0.1" - :min "0" - :max "200" - :value letter-spacing - :on-change on-font-letter-spacing-change}]] - - - [:span "Text align"] - [:div.row-flex.align-icons - [:span {:class (when (= align "left") "current") - :on-click #(on-font-align-change % "left")} - i/align-left] - [:span {:class (when (= align "right") "current") - :on-click #(on-font-align-change % "right")} - i/align-right] - [:span {:class (when (= align "center") "current") - :on-click #(on-font-align-change % "center")} - i/align-center] - [:span {:class (when (= align "justify") "current") - :on-click #(on-font-align-change % "justify")} - i/align-justify]]]])))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Components -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defn options-menus-render +(defn- options-render [own shape] (let [local (:rum/local own) menus (get +menus-map+ (:type shape)) @@ -632,20 +87,18 @@ [:ul.element-icons (for [menu-id (get +menus-map+ (:type shape)) :let [menu (get +menus-by-id+ menu-id) - menu (assoc menu :id menu-id) selected? (= active-menu menu-id)]] [:li#e-info {:on-click #(swap! local assoc :menu menu-id) :key (str "menu-" (:id menu)) :class (when selected? "selected")} (:icon menu)])] (when-let [menu (get +menus-by-id+ active-menu)] - (let [menu (assoc menu :id active-menu)] - (-render-menu menu own shape local)))]))) + ((:comp menu) menu shape))]))) -(def ^:static ^:private options-menus +(def ^:private options (mx/component - {:render options-menus-render - :name "options-menus" + {:render options-render + :name "options" :mixins [mx/static (mx/local)]})) (def ^:const selected-shape-l @@ -653,7 +106,7 @@ (let [selected (get-in state [:workspace :selected])] (when (= 1 (count selected)) (get-in state [:shapes-by-id (first selected)]))))] - (as-> (ul/getter getter) $ + (as-> (l/getter getter) $ (l/focus-atom $ st/state)))) (defn options-toolbox-render @@ -669,7 +122,7 @@ [:div.tool-window-content [:div.element-options (if shape - (options-menus shape))]]]))) + (options shape))]]]))) (def ^:static options-toolbox (mx/component diff --git a/src/uxbox/ui/workspace/sidebar/options/circle_measures.cljs b/src/uxbox/ui/workspace/sidebar/options/circle_measures.cljs new file mode 100644 index 0000000000..1901bb651c --- /dev/null +++ b/src/uxbox/ui/workspace/sidebar/options/circle_measures.cljs @@ -0,0 +1,107 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) 2015-2016 Andrey Antukh +;; Copyright (c) 2015-2016 Juan de la Cruz + +(ns uxbox.ui.workspace.sidebar.options.circle-measures + (:require [sablono.core :as html :refer-macros [html]] + [rum.core :as rum] + [lentes.core :as l] + [uxbox.locales :refer (tr)] + [uxbox.router :as r] + [uxbox.rstore :as rs] + [uxbox.state :as st] + [uxbox.library :as library] + [uxbox.data.workspace :as udw] + [uxbox.data.shapes :as uds] + [uxbox.ui.icons :as i] + [uxbox.ui.mixins :as mx] + [uxbox.ui.workspace.colorpicker :refer (colorpicker)] + [uxbox.ui.workspace.recent-colors :refer (recent-colors)] + [uxbox.util.geom :as geom] + [uxbox.util.dom :as dom] + [uxbox.util.data :refer (parse-int parse-float read-string)])) + +(defn- circle-measures-menu-render + [own menu shape] + (letfn [(on-size-change [attr event] + (let [value (dom/event->value event) + value (parse-int value 0) + sid (:id shape) + props {attr value}] + (rs/emit! (uds/update-radius-attrs sid props)))) + (on-rotation-change [event] + (let [value (dom/event->value event) + value (parse-int value 0) + sid (:id shape)] + (rs/emit! (uds/update-rotation sid value)))) + (on-pos-change [attr event] + (let [value (dom/event->value event) + value (parse-int value nil) + sid (:id shape) + props {attr value}] + (rs/emit! (uds/update-position sid props))))] + (html + [:div.element-set {:key (str (:id menu))} + [:div.element-set-title (:name menu)] + [:div.element-set-content + ;; SLIDEBAR FOR ROTATION AND OPACITY + [:span "Size"] + [:div.row-flex + [:input.input-text + {:placeholder "Width" + :type "number" + :min "0" + :value (:rx shape) + :on-change (partial on-size-change :rx)}] + [:div.lock-size i/lock] + [:input.input-text + {:placeholder "Height" + :type "number" + :min "0" + :value (:ry shape) + :on-change (partial on-size-change :ry)}]] + + [:span "Position"] + [:div.row-flex + [:input.input-text + {:placeholder "cx" + :type "number" + :value (:cx shape "") + :on-change (partial on-pos-change :x)}] + [:input.input-text + {:placeholder "cy" + :type "number" + :value (:cy shape "") + :on-change (partial on-pos-change :y)}]] + + [:span "Rotation"] + [:div.row-flex + [:input.slidebar + {:type "range" + :min 0 + :max 360 + :value (:rotation shape 0) + :on-change on-rotation-change}]] + + [:div.row-flex + [:input.input-text + {:placeholder "" + :type "number" + :min 0 + :max 360 + :value (:rotation shape "0") + :on-change on-rotation-change + }] + [:input.input-text + {:style {:visibility "hidden"}}] + ]]] + ))) + +(def circle-measures-menu + (mx/component + {:render circle-measures-menu-render + :name "circle-measures-menu" + :mixins [mx/static]})) diff --git a/src/uxbox/ui/workspace/sidebar/options/fill.cljs b/src/uxbox/ui/workspace/sidebar/options/fill.cljs new file mode 100644 index 0000000000..9dcfa67010 --- /dev/null +++ b/src/uxbox/ui/workspace/sidebar/options/fill.cljs @@ -0,0 +1,83 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) 2015-2016 Andrey Antukh +;; Copyright (c) 2015-2016 Juan de la Cruz + +(ns uxbox.ui.workspace.sidebar.options.fill + (:require [sablono.core :as html :refer-macros [html]] + [rum.core :as rum] + [lentes.core :as l] + [uxbox.locales :refer (tr)] + [uxbox.router :as r] + [uxbox.rstore :as rs] + [uxbox.state :as st] + [uxbox.library :as library] + [uxbox.data.shapes :as uds] + [uxbox.data.lightbox :as udl] + [uxbox.ui.icons :as i] + [uxbox.ui.mixins :as mx] + [uxbox.util.dom :as dom] + [uxbox.util.data :refer (parse-int parse-float read-string)])) + +(defn fill-menu-render + [own menu shape] + (letfn [(change-fill [value] + (let [sid (:id shape)] + (rs/emit! (uds/update-fill-attrs sid value)))) + (on-color-change [event] + (let [value (dom/event->value event)] + (change-fill {:color value}))) + (on-opacity-change [event] + (let [value (dom/event->value event) + value (parse-float value 1) + value (/ value 10000)] + (change-fill {:opacity value}))) + (on-color-picker-event [color] + (change-fill {:color color})) + (show-color-picker [event] + (let [x (.-clientX event) + y (.-clientY event) + opts {:x x :y y + :shape (:id shape) + :attr :fill + :transparent? true}] + (udl/open! :workspace/colorpicker opts)))] + + (html + [:div.element-set {:key (str (:id menu))} + [:div.element-set-title (:name menu)] + [:div.element-set-content + + [:span "Color"] + [:div.row-flex.color-data + [:span.color-th + {:style {:background-color (:fill shape)} + :on-click show-color-picker}] + [:div.color-info + [:span (:fill shape)]]] + + [:div.row-flex + [:input.input-text + {:placeholder "#" + :type "text" + :value (:fill shape "") + :on-change on-color-change}]] + + ;; SLIDEBAR FOR ROTATION AND OPACITY + [:span "Opacity"] + [:div.row-flex + [:input.slidebar + {:type "range" + :min "0" + :max "10000" + :value (* 10000 (:fill-opacity shape 1)) + :step "1" + :on-change on-opacity-change}]]]]))) + +(def fill-menu + (mx/component + {:render fill-menu-render + :name "fill-menu" + :mixins [mx/static]})) diff --git a/src/uxbox/ui/workspace/sidebar/options/icon_measures.cljs b/src/uxbox/ui/workspace/sidebar/options/icon_measures.cljs new file mode 100644 index 0000000000..d9ce24eeb2 --- /dev/null +++ b/src/uxbox/ui/workspace/sidebar/options/icon_measures.cljs @@ -0,0 +1,107 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) 2015-2016 Andrey Antukh +;; Copyright (c) 2015-2016 Juan de la Cruz + +(ns uxbox.ui.workspace.sidebar.options.icon-measures + (:require [sablono.core :as html :refer-macros [html]] + [rum.core :as rum] + [lentes.core :as l] + [uxbox.locales :refer (tr)] + [uxbox.router :as r] + [uxbox.rstore :as rs] + [uxbox.state :as st] + [uxbox.library :as library] + [uxbox.data.workspace :as udw] + [uxbox.data.shapes :as uds] + [uxbox.ui.icons :as i] + [uxbox.ui.mixins :as mx] + [uxbox.ui.workspace.colorpicker :refer (colorpicker)] + [uxbox.ui.workspace.recent-colors :refer (recent-colors)] + [uxbox.util.geom :as geom] + [uxbox.util.dom :as dom] + [uxbox.util.data :refer (parse-int parse-float read-string)])) + +(defn- icon-measures-menu-render + [own menu shape] + (letfn [(on-size-change [attr event] + (let [value (dom/event->value event) + value (parse-int value 0) + sid (:id shape) + props {attr value}] + (rs/emit! (uds/update-size sid props)))) + (on-rotation-change [event] + (let [value (dom/event->value event) + value (parse-int value 0) + sid (:id shape)] + (rs/emit! (uds/update-rotation sid value)))) + (on-pos-change [attr event] + (let [value (dom/event->value event) + value (parse-int value nil) + sid (:id shape) + props {attr value}] + (rs/emit! (uds/update-position sid props))))] + (let [size (geom/size shape)] + (html + [:div.element-set {:key (str (:id menu))} + [:div.element-set-title (:name menu)] + [:div.element-set-content + ;; SLIDEBAR FOR ROTATION AND OPACITY + [:span "Size"] + [:div.row-flex + [:input.input-text + {:placeholder "Width" + :type "number" + :min "0" + :value (:width size) + :on-change (partial on-size-change :width)}] + [:div.lock-size i/lock] + [:input.input-text + {:placeholder "Height" + :type "number" + :min "0" + :value (:height size) + :on-change (partial on-size-change :height)}]] + + [:span "Position"] + [:div.row-flex + [:input.input-text + {:placeholder "x" + :type "number" + :value (:x1 shape "") + :on-change (partial on-pos-change :x)}] + [:input.input-text + {:placeholder "y" + :type "number" + :value (:y1 shape "") + :on-change (partial on-pos-change :y)}]] + + [:span "Rotation"] + [:div.row-flex + [:input.slidebar + {:type "range" + :min 0 + :max 360 + :value (:rotation shape 0) + :on-change on-rotation-change}]] + + [:div.row-flex + [:input.input-text + {:placeholder "" + :type "number" + :min 0 + :max 360 + :value (:rotation shape "0") + :on-change on-rotation-change + }] + [:input.input-text + {:style {:visibility "hidden"}}] + ]]])))) + +(def icon-measures-menu + (mx/component + {:render icon-measures-menu-render + :name "icon-measures-menu" + :mixins [mx/static]})) diff --git a/src/uxbox/ui/workspace/sidebar/options/line_measures.cljs b/src/uxbox/ui/workspace/sidebar/options/line_measures.cljs new file mode 100644 index 0000000000..fce0e075c9 --- /dev/null +++ b/src/uxbox/ui/workspace/sidebar/options/line_measures.cljs @@ -0,0 +1,96 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) 2015-2016 Andrey Antukh +;; Copyright (c) 2015-2016 Juan de la Cruz + +(ns uxbox.ui.workspace.sidebar.options.line-measures + (:require [sablono.core :as html :refer-macros [html]] + [rum.core :as rum] + [lentes.core :as l] + [uxbox.locales :refer (tr)] + [uxbox.router :as r] + [uxbox.rstore :as rs] + [uxbox.state :as st] + [uxbox.library :as library] + [uxbox.data.workspace :as udw] + [uxbox.data.shapes :as uds] + [uxbox.ui.icons :as i] + [uxbox.ui.mixins :as mx] + [uxbox.ui.workspace.colorpicker :refer (colorpicker)] + [uxbox.ui.workspace.recent-colors :refer (recent-colors)] + [uxbox.util.geom :as geom] + [uxbox.util.dom :as dom] + [uxbox.util.data :refer (parse-int parse-float read-string)])) + +(defn- line-measures-menu-render + [own menu shape] + (letfn [(on-rotation-change [event] + (let [value (dom/event->value event) + value (parse-int value 0) + sid (:id shape)] + (rs/emit! (uds/update-rotation sid value)))) + (on-pos-change [attr event] + (let [value (dom/event->value event) + value (parse-int value nil) + sid (:id shape) + props {attr value}] + (rs/emit! (uds/update-line-attrs sid props))))] + (html + [:div.element-set {:key (str (:id menu))} + [:div.element-set-title (:name menu)] + [:div.element-set-content + [:span "Position"] + [:div.row-flex + [:input.input-text + {:placeholder "x1" + :type "number" + :value (:x1 shape "") + :on-change (partial on-pos-change :x1)}] + [:input.input-text + {:placeholder "y1" + :type "number" + :value (:y1 shape "") + :on-change (partial on-pos-change :y1)}]] + + [:div.row-flex + [:input.input-text + {:placeholder "x2" + :type "number" + :value (:x2 shape "") + :on-change (partial on-pos-change :x2)}] + [:input.input-text + {:placeholder "y2" + :type "number" + :value (:y2 shape "") + :on-change (partial on-pos-change :y2)}]] + + [:span "Rotation"] + [:div.row-flex + [:input.slidebar + {:type "range" + :min 0 + :max 360 + :value (:rotation shape 0) + :on-change on-rotation-change}]] + + [:div.row-flex + [:input.input-text + {:placeholder "" + :type "number" + :min 0 + :max 360 + :value (:rotation shape "0") + :on-change on-rotation-change + }] + [:input.input-text + {:style {:visibility "hidden"}}] + ]]] + ))) + +(def line-measures-menu + (mx/component + {:render line-measures-menu-render + :name "line-measures-menu" + :mixins [mx/static]})) diff --git a/src/uxbox/ui/workspace/sidebar/options/rect_measures.cljs b/src/uxbox/ui/workspace/sidebar/options/rect_measures.cljs new file mode 100644 index 0000000000..963bf2aac8 --- /dev/null +++ b/src/uxbox/ui/workspace/sidebar/options/rect_measures.cljs @@ -0,0 +1,128 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) 2015-2016 Andrey Antukh +;; Copyright (c) 2015-2016 Juan de la Cruz + +(ns uxbox.ui.workspace.sidebar.options.rect-measures + (:require [sablono.core :as html :refer-macros [html]] + [rum.core :as rum] + [lentes.core :as l] + [uxbox.locales :refer (tr)] + [uxbox.router :as r] + [uxbox.rstore :as rs] + [uxbox.state :as st] + [uxbox.library :as library] + [uxbox.data.workspace :as udw] + [uxbox.data.shapes :as uds] + [uxbox.ui.icons :as i] + [uxbox.ui.mixins :as mx] + [uxbox.ui.workspace.colorpicker :refer (colorpicker)] + [uxbox.ui.workspace.recent-colors :refer (recent-colors)] + [uxbox.util.geom :as geom] + [uxbox.util.dom :as dom] + [uxbox.util.data :refer (parse-int parse-float read-string)])) + +(defn rect-measures-menu-render + [own menu shape] + (letfn [(on-size-change [attr event] + (let [value (dom/event->value event) + value (parse-int value 0) + sid (:id shape) + props {attr value}] + (rs/emit! (uds/update-size sid props)))) + (on-rotation-change [event] + (let [value (dom/event->value event) + value (parse-int value 0) + sid (:id shape)] + (rs/emit! (uds/update-rotation sid value)))) + (on-pos-change [attr event] + (let [value (dom/event->value event) + value (parse-int value nil) + sid (:id shape) + props {attr value}] + (rs/emit! (uds/update-position sid props)))) + (on-border-change [attr event] + (let [value (dom/event->value event) + value (parse-int value nil) + sid (:id shape) + props {attr value}] + (rs/emit! (uds/update-radius-attrs sid props))))] + (let [size (geom/size shape)] + (html + [:div.element-set {:key (str (:id menu))} + [:div.element-set-title (:name menu)] + [:div.element-set-content + ;; SLIDEBAR FOR ROTATION AND OPACITY + [:span "Size"] + [:div.row-flex + [:input.input-text + {:placeholder "Width" + :type "number" + :min "0" + :value (:width size) + :on-change (partial on-size-change :width)}] + [:div.lock-size i/lock] + [:input.input-text + {:placeholder "Height" + :type "number" + :min "0" + :value (:height size) + :on-change (partial on-size-change :height)}]] + + [:span "Position"] + [:div.row-flex + [:input.input-text + {:placeholder "x" + :type "number" + :value (:x1 shape "") + :on-change (partial on-pos-change :x)}] + [:input.input-text + {:placeholder "y" + :type "number" + :value (:y1 shape "") + :on-change (partial on-pos-change :y)}]] + + [:span "Border radius"] + [:div.row-flex + [:input.input-text + {:placeholder "rx" + :type "number" + :value (:rx shape "") + :on-change (partial on-border-change :rx)}] + [:div.lock-size i/lock] + [:input.input-text + {:placeholder "ry" + :type "number" + :value (:ry shape "") + :on-change (partial on-border-change :ry)}]] + + [:span "Rotation"] + [:div.row-flex + [:input.slidebar + {:type "range" + :min 0 + :max 360 + :value (:rotation shape 0) + :on-change on-rotation-change}]] + + [:div.row-flex + [:input.input-text + {:placeholder "" + :type "number" + :min 0 + :max 360 + :value (:rotation shape "0") + :on-change on-rotation-change + }] + [:input.input-text + {:style {:visibility "hidden"}}] + ]]])))) + +(def rect-measures-menu + (mx/component + {:render rect-measures-menu-render + :name "rect-measures" + :mixins [mx/static]})) + diff --git a/src/uxbox/ui/workspace/sidebar/options/stroke.cljs b/src/uxbox/ui/workspace/sidebar/options/stroke.cljs new file mode 100644 index 0000000000..a7fc4a36ca --- /dev/null +++ b/src/uxbox/ui/workspace/sidebar/options/stroke.cljs @@ -0,0 +1,97 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) 2015-2016 Andrey Antukh +;; Copyright (c) 2015-2016 Juan de la Cruz + +(ns uxbox.ui.workspace.sidebar.options.stroke + (:require [sablono.core :as html :refer-macros [html]] + [rum.core :as rum] + [lentes.core :as l] + [uxbox.locales :refer (tr)] + [uxbox.router :as r] + [uxbox.rstore :as rs] + [uxbox.state :as st] + [uxbox.library :as library] + [uxbox.data.shapes :as uds] + [uxbox.data.lightbox :as udl] + [uxbox.ui.icons :as i] + [uxbox.ui.mixins :as mx] + [uxbox.util.dom :as dom] + [uxbox.util.data :refer (parse-int parse-float read-string)])) + +(defn- stroke-menu-render + [own menu shape] + (letfn [(change-stroke [value] + (let [sid (:id shape)] + (rs/emit! (uds/update-stroke-attrs sid value)))) + (on-width-change [event] + (let [value (dom/event->value event) + value (parse-float value 1)] + (change-stroke {:width value}))) + (on-opacity-change [event] + (let [value (dom/event->value event) + value (parse-float value 1) + value (/ value 10000)] + (change-stroke {:opacity value}))) + (on-color-change [event] + (let [value (dom/event->value event)] + (change-stroke {:color value}))) + (on-stroke-style-change [event] + (let [value (dom/event->value event) + value (read-string value)] + (change-stroke {:type value}))) + (show-color-picker [event] + (let [x (.-clientX event) + y (.-clientY event) + opts {:x x :y y + :shape (:id shape) + :attr :stroke + :transparent? true}] + (udl/open! :workspace/colorpicker opts)))] + (let [local (:rum/local own)] + (html + [:div.element-set {:key (str (:id menu))} + [:div.element-set-title (:name menu)] + [:div.element-set-content + [:span "Style"] + [:div.row-flex + [:select#style.input-select {:placeholder "Style" + :value (:stroke-type shape) + :on-change on-stroke-style-change} + [:option {:value ":none"} "None"] + [:option {:value ":solid"} "Solid"] + [:option {:value ":dotted"} "Dotted"] + [:option {:value ":dashed"} "Dashed"] + [:option {:value ":mixed"} "Mixed"]] + [:input.input-text + {:placeholder "Width" + :type "number" + :min "0" + :value (:stroke-width shape "1") + :on-change on-width-change}]] + + [:span "Color"] + [:div.row-flex.color-data + [:span.color-th + {:style {:background-color (:stroke shape)} + :on-click show-color-picker}] + [:div.color-info + [:span (:stroke shape)]]] + + [:span "Opacity"] + [:div.row-flex + [:input.slidebar + {:type "range" + :min "0" + :max "10000" + :value (* 10000 (:stroke-opacity shape 1)) + :step "1" + :on-change on-opacity-change}]]]])))) + +(def stroke-menu + (mx/component + {:render stroke-menu-render + :name "stroke-menu" + :mixed [mx/static]})) diff --git a/src/uxbox/ui/workspace/sidebar/options/text.cljs b/src/uxbox/ui/workspace/sidebar/options/text.cljs new file mode 100644 index 0000000000..9a330c7442 --- /dev/null +++ b/src/uxbox/ui/workspace/sidebar/options/text.cljs @@ -0,0 +1,142 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) 2015-2016 Andrey Antukh +;; Copyright (c) 2015-2016 Juan de la Cruz + +(ns uxbox.ui.workspace.sidebar.options.text + (:require [sablono.core :as html :refer-macros [html]] + [rum.core :as rum] + [lentes.core :as l] + [uxbox.locales :refer (tr)] + [uxbox.router :as r] + [uxbox.rstore :as rs] + [uxbox.state :as st] + [uxbox.library :as library] + [uxbox.data.workspace :as udw] + [uxbox.data.shapes :as uds] + [uxbox.ui.workspace.base :as wb] + [uxbox.ui.icons :as i] + [uxbox.ui.mixins :as mx] + [uxbox.ui.workspace.colorpicker :refer (colorpicker)] + [uxbox.ui.workspace.recent-colors :refer (recent-colors)] + [uxbox.ui.workspace.base :as wb] + [uxbox.util.geom :as geom] + [uxbox.util.dom :as dom] + [uxbox.util.data :refer (parse-int parse-float read-string)])) + +(defn- text-menu-render + [own menu {:keys [font] :as shape}] + (letfn [(on-font-family-change [event] + (let [value (dom/event->value event) + sid (:id shape) + params {:family (read-string value) + :weight "normal" + :style "normal"}] + (rs/emit! (uds/update-font-attrs sid params)))) + (on-font-size-change [event] + (let [value (dom/event->value event) + params {:size (parse-int value)} + sid (:id shape)] + (rs/emit! (uds/update-font-attrs sid params)))) + (on-font-letter-spacing-change [event] + (let [value (dom/event->value event) + params {:letter-spacing (parse-float value)} + sid (:id shape)] + (rs/emit! (uds/update-font-attrs sid params)))) + (on-font-line-height-change [event] + (let [value (dom/event->value event) + params {:line-height (parse-float value)} + sid (:id shape)] + (rs/emit! (uds/update-font-attrs sid params)))) + (on-font-align-change [event value] + (let [params {:align value} + sid (:id shape)] + (rs/emit! (uds/update-font-attrs sid params)))) + + (on-font-style-change [event] + (let [value (dom/event->value event) + [weight style] (read-string value) + sid (:id shape) + params {:style style + :weight weight}] + (rs/emit! (uds/update-font-attrs sid params))))] + (let [{:keys [family style weight size align line-height letter-spacing] + :or {family "sourcesanspro" + align "left" + style "normal" + weight "normal" + letter-spacing 1 + line-height 1.4 + size 16}} font + styles (:styles (first (filter #(= (:id %) family) library/+fonts+)))] + (html + [:div.element-set {:key (str (:id menu))} + [:div.element-set-title (:name menu)] + [:div.element-set-content + + [:span "Font family"] + [:div.row-flex + [:select.input-select {:value (pr-str family) + :on-change on-font-family-change} + (for [font library/+fonts+] + [:option {:value (pr-str (:id font)) + :key (:id font)} (:name font)])]] + + [:span "Size and Weight"] + [:div.row-flex + [:input.input-text + {:placeholder "Font Size" + :type "number" + :min "0" + :max "200" + :value size + :on-change on-font-size-change}] + [:select.input-select {:value (pr-str [weight style]) + :on-change on-font-style-change} + (for [style styles + :let [data (mapv #(get style %) [:weight :style])]] + [:option {:value (pr-str data) + :key (:name style)} (:name style)])]] + + [:span "Line height and Letter spacing"] + [:div.row-flex + [:input.input-text + {:placeholder "Line height" + :type "number" + :step "0.1" + :min "0" + :max "200" + :value line-height + :on-change on-font-line-height-change}] + [:input.input-text + {:placeholder "Letter spacing" + :type "number" + :step "0.1" + :min "0" + :max "200" + :value letter-spacing + :on-change on-font-letter-spacing-change}]] + + + [:span "Text align"] + [:div.row-flex.align-icons + [:span {:class (when (= align "left") "current") + :on-click #(on-font-align-change % "left")} + i/align-left] + [:span {:class (when (= align "right") "current") + :on-click #(on-font-align-change % "right")} + i/align-right] + [:span {:class (when (= align "center") "current") + :on-click #(on-font-align-change % "center")} + i/align-center] + [:span {:class (when (= align "justify") "current") + :on-click #(on-font-align-change % "justify")} + i/align-justify]]]])))) + +(def text-menu + (mx/component + {:render text-menu-render + :name "text-menu" + :mixins [mx/static]})) diff --git a/src/uxbox/util/color.cljs b/src/uxbox/util/color.cljs index f228fd5bb4..2805ebc8e9 100644 --- a/src/uxbox/util/color.cljs +++ b/src/uxbox/util/color.cljs @@ -47,3 +47,6 @@ (-> (hex->rgb data) (conj opacity))) +(defn hex? + [v] + (not (nil? (re-find #"^#[0-9A-Fa-f]{6}$" v)))) diff --git a/src/uxbox/util/dom.cljs b/src/uxbox/util/dom.cljs index 572058ddd1..a6de948247 100644 --- a/src/uxbox/util/dom.cljs +++ b/src/uxbox/util/dom.cljs @@ -55,3 +55,7 @@ or checkbox is checked or not." [node] (.-checked node)) + +(defn ^boolean equals? + [node-a node-b] + (.isEqualNode node-a node-b))