diff --git a/frontend/src/uxbox/main/data/shapes.cljs b/frontend/src/uxbox/main/data/shapes.cljs index ac60186c3..4bb81504c 100644 --- a/frontend/src/uxbox/main/data/shapes.cljs +++ b/frontend/src/uxbox/main/data/shapes.cljs @@ -90,18 +90,6 @@ (rx/map (fn [{:keys [x y] :as pt}] (apply-temporal-displacement id (gpt/subtract pt point1))))))))) -(defn update-line-attrs - [sid {:keys [x1 y1 x2 y2] :as opts}] - (reify - udp/IPageUpdate - ptk/UpdateEvent - (update [_ state] - (let [shape (get-in state [:shapes sid]) - props (select-keys opts [:x1 :y1 :x2 :y2]) - props' (select-keys shape [:x1 :y1 :x2 :y2])] - (update-in state [:shapes sid] geom/setup - (merge props' props)))))) - (defn update-rotation [sid rotation] {:pre [(number? rotation) @@ -236,57 +224,68 @@ (update [_ state] (assoc-in state [:shapes sid :content] content)))) -(defn update-fill-attrs - [sid {:keys [color opacity] :as opts}] - (reify - udp/IPageUpdate - ptk/UpdateEvent - (update [_ state] - (update-in state [:shapes sid] - merge - (when color {:fill color}) - (when opacity {:fill-opacity opacity}))))) +;; --- Update Shape Attrs -(defn update-font-attrs - [sid {:keys [family style weight size align - letter-spacing line-height] :as opts}] - (reify - udp/IPageUpdate - ptk/UpdateEvent - (update [_ state] - (update-in state [:shapes sid :font] - merge - (when line-height {:line-height line-height}) - (when letter-spacing {:letter-spacing letter-spacing}) - (when align {:align align}) - (when family {:family family}) - (when style {:style style}) - (when weight {:weight weight}) - (when size {:size size}))))) +(declare UpdateAttrs) -(defn update-stroke-attrs - [sid {:keys [color opacity type width] :as opts}] - (reify - udp/IPageUpdate - ptk/UpdateEvent - (update [_ state] - (update-in state [:shapes sid] - merge - (when type {:stroke-type type}) - (when width {:stroke-width width}) - (when color {:stroke color}) - (when opacity {:stroke-opacity opacity}))))) +(deftype UpdateAttrs [id attrs] + ptk/WatchEvent + (watch [_ state stream] + (println "update-attrs" id attrs) + (let [{:keys [type] :as shape} (get-in state [:shapes id])] + (if (= type :group) + (rx/from-coll (map #(UpdateAttrs. % attrs) (:items shape))) + (rx/of #(update-in % [:shapes id] merge attrs)))))) -(defn update-radius-attrs - [sid {:keys [rx ry] :as opts}] - (reify - udp/IPageUpdate - ptk/UpdateEvent - (update [_ state] - (update-in state [:shapes sid] - merge - (when rx {:rx rx}) - (when ry {:ry ry}))))) +(s/def ::fill-color us/color?) +(s/def ::fill-opacity number?) +(s/def ::line-height number?) +(s/def ::letter-spacing number?) +(s/def ::text-align #{"left" "right" "center" "justify"}) +(s/def ::font-family string?) +(s/def ::font-style string?) +(s/def ::font-weight string?) +(s/def ::font-size number?) +(s/def ::stroke-style #{:none :solid :dotted :dashed :mixed}) +(s/def ::stroke-width number?) +(s/def ::stroke-color us/color?) +(s/def ::stroke-opacity number?) +(s/def ::rx number?) +(s/def ::ry number?) +(s/def ::proportion number?) +(s/def ::proportion-lock boolean?) +(s/def ::collapsed boolean?) +(s/def ::hidden boolean?) +(s/def ::blocked boolean?) +(s/def ::locked boolean?) + +(s/def ::shape-attrs + (s/keys :opt-un [::fill-color + ::fill-opacity + ::line-height + ::letter-spacing + ::text-align + ::font-family + ::font-style + ::font-weight + ::font-size + ::stroke-style + ::stroke-width + ::stroke-color + ::stroke-opacity + ::rx ::ry + ::proportion-lock + ::proportion + ::collapsed + ::hidden + ::blocked + ::locked])) + +(defn update-attrs + [id attrs] + {:pre [(uuid? id) (us/valid? ::shape-attrs attrs)]} + (let [atts (us/extract attrs ::shape-attrs)] + (UpdateAttrs. id attrs))) ;; --- Shape Proportions @@ -629,27 +628,16 @@ (rx/from-coll (into [(deselect-all)] (map #(delete-shape %) selected))))))) -(defn update-selected-shapes-fill - "Update the fill related attributed on - selected shapes." - [opts] - (reify - ptk/WatchEvent - (watch [_ state stream] - (->> (get-in state [:workspace :selected]) - (map #(update-fill-attrs % opts)) - (rx/from-coll))))) +(deftype UpdateSelectedShapesAttrs [attrs] + ptk/WatchEvent + (watch [_ state stream] + (let [xf (map #(update-attrs % attrs))] + (rx/from-coll (sequence xf (get-in state [:workspace :selected])))))) -(defn update-selected-shapes-stroke - "Update the fill related attributed on - selected shapes." - [opts] - (reify - ptk/WatchEvent - (watch [_ state s] - (rx/from-coll - (->> (get-in state [:workspace :selected]) - (map #(update-stroke-attrs % opts))))))) +(defn update-selected-shapes-attrs + [attrs] + {:pre [(us/valid? ::shape-attrs attrs)]} + (UpdateSelectedShapesAttrs. attrs)) ;; --- Move Selected Layer diff --git a/frontend/src/uxbox/main/ui/shapes/attrs.cljs b/frontend/src/uxbox/main/ui/shapes/attrs.cljs index 939244c84..da55e4e89 100644 --- a/frontend/src/uxbox/main/ui/shapes/attrs.cljs +++ b/frontend/src/uxbox/main/ui/shapes/attrs.cljs @@ -2,47 +2,55 @@ ;; 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-2017 Andrey Antukh (ns uxbox.main.ui.shapes.attrs) -(def ^:private +style-attrs+ - #{:fill :fill-opacity :opacity - :stroke :stroke-opacity :stroke-width - :stroke-type :rx :ry}) +(def shape-style-attrs + #{:fill-color + :fill-opacity + :stroke-color + :stroke-opacity + :stroke-width + :stroke-style + :rx + :ry}) -(defn- transform-stroke-type +(def shape-default-attrs + {:stroke-color "#000000" + :stroke-opacity 1 + :fill-color "#000000" + :fill-opacity 1}) + +(defn- stroke-type->dasharray + [style] + (case style + :mixed "5,5,1,5" + :dotted "5,5" + :dashed "10,10")) + +(defn- rename-attr + [[key value :as pair]] + (case key + :stroke-color [:stroke value] + :fill-color [:fill value] + pair)) + +(defn- rename-attrs [attrs] - (if-let [type (:stroke-type attrs)] - (let [value (case type - :mixed "5,5,1,5" - :dotted "5,5" - :dashed "10,10" - nil)] - (if value - (-> attrs - (assoc! :stroke-dasharray value) - (dissoc! :stroke-type)) - (dissoc! attrs :stroke-type))) - attrs)) + (into {} (map rename-attr) attrs)) (defn- transform-stroke-attrs - [attrs] - (if (= (:stroke-type attrs :none) :none) - (dissoc! attrs :stroke-type :stroke-width :stroke-opacity :stroke) - (transform-stroke-type attrs))) + [{:keys [stroke-style] :or {stroke-style :none} :as attrs}] + (if (= stroke-style :none) + (dissoc attrs :stroke-style :stroke-width :stroke-opacity :stroke-color) + (-> (merge shape-default-attrs attrs) + (assoc :stroke-dasharray (stroke-type->dasharray stroke-style)) + (dissoc :stroke-style)))) (defn- extract-style-attrs "Extract predefinet attrs from shapes." [shape] - (let [attrs (select-keys shape +style-attrs+)] - (-> (transient attrs) - (transform-stroke-attrs) - (persistent!)))) - -(defn- make-debug-attrs - [shape] - (let [attrs (select-keys shape [:rotation :width :height :x :y]) - xf (map (fn [[x v]] - [(keyword (str "data-" (name x))) v]))] - (into {} xf attrs))) + (-> (select-keys shape shape-style-attrs) + (transform-stroke-attrs) + (rename-attrs))) diff --git a/frontend/src/uxbox/main/ui/shapes/group.cljs b/frontend/src/uxbox/main/ui/shapes/group.cljs index 9bb2df9bb..466e920a1 100644 --- a/frontend/src/uxbox/main/ui/shapes/group.cljs +++ b/frontend/src/uxbox/main/ui/shapes/group.cljs @@ -69,9 +69,7 @@ (let [xfmt (cond-> (or tmp-resize-xform (gmt/matrix)) tmp-displacement (gmt/translate tmp-displacement)) - props {:id (str id) :transform (str xfmt)} - - attrs (merge props (attrs/extract-style-attrs shape))] + attrs {:id (str id) :transform (str xfmt)}] [:g attrs (for [item (reverse items) :let [key (str item)]] diff --git a/frontend/src/uxbox/main/ui/shapes/rect.cljs b/frontend/src/uxbox/main/ui/shapes/rect.cljs index b8dacf10d..b3f1e727a 100644 --- a/frontend/src/uxbox/main/ui/shapes/rect.cljs +++ b/frontend/src/uxbox/main/ui/shapes/rect.cljs @@ -31,6 +31,7 @@ ;; --- Rect Shape (defn- rotate + ;; TODO: revisit, i'm not sure if this function is duplicated. [mt {:keys [x1 y1 x2 y2 width height rotation] :as shape}] (let [x-center (+ x1 (/ width 2)) y-center (+ y1 (/ height 2)) diff --git a/frontend/src/uxbox/main/ui/shapes/text.cljs b/frontend/src/uxbox/main/ui/shapes/text.cljs index 584e5df06..0e36be7f7 100644 --- a/frontend/src/uxbox/main/ui/shapes/text.cljs +++ b/frontend/src/uxbox/main/ui/shapes/text.cljs @@ -35,6 +35,7 @@ ;; --- Text Component (declare text-shape) +(declare text-shape-wrapper) (declare text-shape-edit) (mx/defcs text-component @@ -55,7 +56,7 @@ :on-mouse-down on-mouse-down} (if edition? (text-shape-edit shape) - (text-shape shape))]))) + (text-shape-wrapper shape))]))) ;; --- Text Styles Helpers @@ -66,28 +67,36 @@ :stroke-opacity "0.4"}}) (defn- make-style - [{:keys [font fill opacity] - :or {fill "#000000" opacity 1}}] - (let [{:keys [family weight style size align - line-height letter-spacing] - :or {family "sourcesanspro" - weight "normal" - style "normal" - line-height 1.4 - letter-spacing 1 - align "left" - size 16}} font - color (-> fill - (color/hex->rgba opacity) + [{:keys [fill-color + fill-opacity + font-family + font-weight + font-style + font-size + text-align + line-height + letter-spacing] + :or {fill-color "#000000" + fill-opacity 1 + font-family "sourcesanspro" + font-weight "normal" + font-style "normal" + fobt-size 16 + line-height 1.4 + letter-spacing 1 + text-align "left"} + :as shape}] + (let [color (-> fill-color + (color/hex->rgba fill-opacity) (color/rgb->str))] (merge - {:fontSize (str size "px") - :color color - :whiteSpace "pre" - :textAlign align - :fontFamily family - :fontWeight weight - :fontStyle style} + {:fontSize (str font-size "px") + :color fill-color + :whiteSpace "pre-wrap" + :textAlign text-align + :fontFamily font-family + :fontWeight font-weight + :fontStyle font-style} (when line-height {:lineHeight line-height}) (when letter-spacing {:letterSpacing letter-spacing})))) @@ -105,11 +114,9 @@ {:did-mount text-shape-edit-did-mount :mixins [mx/static]} [{:keys [id x1 y1 content] :as shape}] - (let [size (geom/size shape) + (let [{:keys [width height]} (geom/size shape) style (make-style shape) - ;; rfm (geom/transformation-matrix shape) - props {:x x1 :y y1} ;; :transform (str rfm)} - props (merge props size)] + props {:x x1 :y y1 :width width :height height}] (letfn [#_(on-blur [ev] (rlocks/release! :ui/text-edit) (on-done)) @@ -117,15 +124,15 @@ (let [content (dom/event->inner-text ev)] (st/emit! (uds/update-text id {:content content}))))] [:g - [:rect (merge props +select-rect-attrs+)] + #_[:rect (merge props +select-rect-attrs+)] [:foreignObject props - [:p {:ref "container" - ;; :on-blur on-blur - :on-input on-input - :contentEditable true - :style style}]]]))) + [:div {:style style} + [:p {:ref "container" + ;; :on-blur on-blur + :on-input on-input + :contentEditable true}]]]]))) -;; --- Text Shape +;; --- Text Shape Wrapper ;; NOTE: this is a hack for the browser rendering. ;; @@ -135,30 +142,46 @@ ;; completelly invisible. The complete dom rerender fixes that ;; problem. -(defn- text-shape-did-update +(defn text-shape-wrapper-did-mount [own] - (let [pref (mx/ref-node own "fo") - html (.-innerHTML pref)] - (set! (.-innerHTML pref) html) + (let [[shape] (:rum/args own) + dom (mx/ref-node own "fobject") + html (mx/render-static-html (text-shape shape))] + (set! (.-innerHTML dom) html)) + own) + +(defn text-shape-wrapper-did-remount + [old own] + (let [[old-shape] (:rum/args old) + [shape] (:rum/args own)] + (when (not= shape old-shape) + (let [dom (mx/ref-node own "fobject") + html (mx/render-static-html (text-shape shape))] + (set! (.-innerHTML dom) html))) own)) -(mx/defc text-shape +(mx/defc text-shape-wrapper {:mixins [mx/static] - :did-update text-shape-did-update} - [{:keys [tmp-resize-xform] :as shape}] - (let [shape (cond-> (geom/size shape) - tmp-resize-xform (geom/transform shape tmp-resize-xform)) + :did-mount text-shape-wrapper-did-mount + :did-remount text-shape-wrapper-did-remount} + [{:keys [id tmp-resize-xform tmp-displacement] :as shape}] + (let [xfmt (cond-> (gmt/matrix) + tmp-displacement (gmt/translate tmp-displacement) + tmp-resize-xform (gmt/multiply tmp-resize-xform)) - {:keys [id x1 y1 content - width height - tmp-displacement]} (geom/size shape) + {:keys [x1 y1 width height] :as shape} (-> (geom/transform shape xfmt) + (geom/size))] + [:foreignObject {:x x1 + :y y1 + :id (str id) + :ref "fobject" + :width width + :height height}])) - xfmt (cond-> (gmt/matrix) - tmp-displacement (gmt/translate tmp-displacement)) +;; --- Text Shape - style (make-style shape) - props {:x x1 :y y1 :id (str id) :ref "fo" - :width width :height height - :transform (str xfmt)}] - [:foreignObject props - [:p {:ref "p" :style style} content]])) +(mx/defc text-shape + [{:keys [content] :as shape}] + (let [style (make-style shape)] + [:div {:style style} + [:p content]])) diff --git a/frontend/src/uxbox/main/ui/workspace/colorpalette.cljs b/frontend/src/uxbox/main/ui/workspace/colorpalette.cljs index 30beb5396..77413a8b7 100644 --- a/frontend/src/uxbox/main/ui/workspace/colorpalette.cljs +++ b/frontend/src/uxbox/main/ui/workspace/colorpalette.cljs @@ -33,10 +33,10 @@ {:mixins [mx/static]} [color] (letfn [(select-color [event] - (dom/prevent-default event) - (if (kbd/shift? event) - (st/emit! (uds/update-selected-shapes-stroke {:color color})) - (st/emit! (uds/update-selected-shapes-fill {:color color}))))] + (let [attrs (if (kbd/shift? event) + {:stroke-color color} + {:fill-color color})] + (st/emit! (uds/update-selected-shapes-attrs attrs))))] (let [rgb-vec (hex->rgb color) rgb-color (apply str "" (interpose ", " rgb-vec))] [:div.color-cell {:key (str color) diff --git a/frontend/src/uxbox/main/ui/workspace/colorpicker.cljs b/frontend/src/uxbox/main/ui/workspace/colorpicker.cljs index a5c4d17ee..02766d5d0 100644 --- a/frontend/src/uxbox/main/ui/workspace/colorpicker.cljs +++ b/frontend/src/uxbox/main/ui/workspace/colorpicker.cljs @@ -32,15 +32,11 @@ (mx/defcs shape-colorpicker {:mixins [mx/reactive mx/static]} [own {:keys [x y shape attr] :as opts}] - (let [shape (mx/react (focus-shape shape)) + (let [{:keys [id] :as shape} (mx/react (focus-shape shape)) left (- x 260) top (- y 50)] (letfn [(change-color [color] - (let [attrs {:color color}] - (st/emit! - (case attr - :stroke (uds/update-stroke-attrs (:id shape) attrs) - :fill (uds/update-fill-attrs (:id shape) attrs)))))] + (st/emit! (uds/update-attrs id {attr color})))] [:div.colorpicker-tooltip {:style {:left (str left "px") :top (str top "px")}} diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options.cljs index bf5507f8f..6758a5c07 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options.cljs @@ -16,11 +16,10 @@ [uxbox.main.data.shapes :as uds] [uxbox.main.ui.workspace.base :as wb] [uxbox.main.ui.icons :as i] - [uxbox.util.mixins :as mx :include-macros true] + [uxbox.main.ui.shapes.attrs :refer [shape-default-attrs]] [uxbox.main.ui.workspace.sidebar.options.icon-measures :as options-iconm] [uxbox.main.ui.workspace.sidebar.options.circle-measures :as options-circlem] [uxbox.main.ui.workspace.sidebar.options.rect-measures :as options-rectm] - [uxbox.main.ui.workspace.sidebar.options.line-measures :as options-linem] [uxbox.main.ui.workspace.sidebar.options.fill :as options-fill] [uxbox.main.ui.workspace.sidebar.options.text :as options-text] [uxbox.main.ui.workspace.sidebar.options.stroke :as options-stroke] @@ -28,19 +27,19 @@ [uxbox.main.ui.workspace.sidebar.options.interactions :as options-interactions] [uxbox.main.geom :as geom] [uxbox.util.dom :as dom] - [uxbox.util.data :as data])) + [uxbox.util.data :as data] + [uxbox.util.mixins :as mx :include-macros true])) ;; --- Constants (def ^:private +menus-map+ {:icon [::icon-measures ::fill ::stroke ::interactions] :rect [::rect-measures ::fill ::stroke ::interactions] - :line [::line-measures ::stroke ::interactions] :path [::fill ::stroke ::interactions] :circle [::circle-measures ::fill ::stroke ::interactions] :text [::fill ::text ::interactions] :image [::interactions] - :group [::interactions] + :group [::fill ::stroke ::interactions] ::page [::page-measures ::page-grid-options]}) (def ^:private +menus+ @@ -52,10 +51,6 @@ :id ::rect-measures :icon i/infocard :comp options-rectm/rect-measures-menu} - {:name "Size, position & rotation" - :id ::line-measures - :icon i/infocard - :comp options-linem/line-measures-menu} {:name "Size, position & rotation" :id ::circle-measures :icon i/infocard @@ -128,7 +123,8 @@ (mx/defc options-toolbox {:mixins [mx/static mx/reactive]} [] - (let [shape (mx/react selected-shape-ref) + (let [shape (->> (mx/react selected-shape-ref) + (merge shape-default-attrs)) close #(st/emit! (udw/toggle-flag :element-options))] [:div.elementa-options.tool-window [:div.tool-window-bar 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 8ba352a1d..903e046fe 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/fill.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/fill.cljs @@ -2,13 +2,11 @@ ;; 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 +;; Copyright (c) 2015-2017 Andrey Antukh +;; Copyright (c) 2015-2017 Juan de la Cruz (ns uxbox.main.ui.workspace.sidebar.options.fill - (:require [sablono.core :as html :refer-macros [html]] - [rum.core :as rum] - [lentes.core :as l] + (:require [lentes.core :as l] [uxbox.util.i18n :refer (tr)] [uxbox.util.router :as r] [potok.core :as ptk] @@ -21,59 +19,51 @@ [uxbox.util.data :refer (parse-int parse-float read-string)] [uxbox.util.spec :refer (color?)])) -(defn fill-menu-render - [own menu shape] - (letfn [(change-fill [value] - (let [sid (:id shape)] - (st/emit! (uds/update-fill-attrs sid value)))) +(mx/defc fill-menu + {:mixins [mx/static]} + [menu {:keys [id] :as shape}] + (letfn [(change-attrs [attrs] + (st/emit! (uds/update-attrs id attrs))) (on-color-change [event] (let [value (dom/event->value event)] (when (color? value) - (change-fill {:color value})))) + (change-attrs {: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}))) + (change-attrs {:fill-opacity value}))) (on-color-picker-event [color] - (change-fill {:color color})) + (change-attrs {:fill-color color})) (show-color-picker [event] (let [x (.-clientX event) y (.-clientY event) opts {:x x :y y :shape (:id shape) - :attr :fill + :attr :fill-color :transparent? true}] (udl/open! :workspace/shape-colorpicker opts)))] + [:div.element-set {:key (str (:id menu))} + [:div.element-set-title (:name menu)] + [:div.element-set-content - (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-color shape)} + :on-click show-color-picker}] + [:div.color-info + [:input + {:on-change on-color-change + :value (:fill-color shape)}]]] - [:span "Color"] - [:div.row-flex.color-data - [:span.color-th - {:style {:background-color (:fill shape "#000000")} - :on-click show-color-picker}] - [:div.color-info - [:input - {:on-change on-color-change - :value (:fill shape "#000000")}]]] - - ;; 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]})) + ;; SLIDEBAR FOR ROTATION AND OPACITY + [:span "Opacity"] + [:div.row-flex + [:input.slidebar + {:type "range" + :min "0" + :max "10000" + :value (* 10000 (:fill-opacity shape)) + :step "1" + :on-change on-opacity-change}]]]])) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/line_measures.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/line_measures.cljs deleted file mode 100644 index 55d50e872..000000000 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/line_measures.cljs +++ /dev/null @@ -1,94 +0,0 @@ -;; 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.main.ui.workspace.sidebar.options.line-measures - (:require [sablono.core :as html :refer-macros [html]] - [rum.core :as rum] - [lentes.core :as l] - [uxbox.util.i18n :refer (tr)] - [uxbox.util.router :as r] - [potok.core :as ptk] - [uxbox.store :as st] - [uxbox.main.data.workspace :as udw] - [uxbox.main.data.shapes :as uds] - [uxbox.main.ui.icons :as i] - [uxbox.util.mixins :as mx :include-macros true] - [uxbox.main.geom :as geom] - [uxbox.util.dom :as dom] - [uxbox.util.math :refer (precision-or-0)] - [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)] - (st/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}] - (st/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 (precision-or-0 (:x1 shape 0) 2) - :on-change (partial on-pos-change :x1)}] - [:input.input-text - {:placeholder "y1" - :type "number" - :value (precision-or-0 (:y1 shape 0) 2) - :on-change (partial on-pos-change :y1)}]] - - [:div.row-flex - [:input.input-text - {:placeholder "x2" - :type "number" - :value (precision-or-0 (:x2 shape 0) 2) - :on-change (partial on-pos-change :x2)}] - [:input.input-text - {:placeholder "y2" - :type "number" - :value (precision-or-0 (:y2 shape 0) 2) - :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 (precision-or-0 (:rotation shape 0) 2) - :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/frontend/src/uxbox/main/ui/workspace/sidebar/options/rect_measures.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/rect_measures.cljs index eefb438cd..bb8db75ce 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/rect_measures.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/rect_measures.cljs @@ -2,8 +2,8 @@ ;; 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 +;; Copyright (c) 2015-2017 Andrey Antukh +;; Copyright (c) 2015-2017 Juan de la Cruz (ns uxbox.main.ui.workspace.sidebar.options.rect-measures (:require [lentes.core :as l] @@ -23,28 +23,22 @@ (mx/defc rect-measures-menu {:mixins [mx/static]} [menu {:keys [id] :as shape}] - (letfn [(on-size-change [attr event] - (let [value (-> (dom/event->value event) (parse-int 0)) - sid (:id shape) - props {attr value}] - (st/emit! (uds/update-size sid props)))) + (letfn [(on-size-change [event attr] + (let [value (-> (dom/event->value event) + (parse-int 0))] + (st/emit! (uds/update-size id {attr value})))) (on-rotation-change [event] - (let [value (dom/event->value event) - value (parse-int value 0) - sid (:id shape)] - (st/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}] - (st/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}] - (st/emit! (uds/update-radius-attrs sid props)))) + (let [value (-> (dom/event->value event) + (parse-int 0))] + (st/emit! (uds/update-rotation id value)))) + (on-pos-change [event attr] + (let [value (-> (dom/event->value event) + (parse-int nil))] + (st/emit! (uds/update-position id {attr value})))) + (on-border-change [event attr] + (let [value (-> (dom/event->value event) + (parse-int nil))] + (st/emit! (uds/update-attrs id {attr value})))) (on-proportion-lock-change [event] (if (:proportion-lock shape) (st/emit! (uds/unlock-proportions id)) @@ -62,7 +56,7 @@ :type "number" :min "0" :value (precision-or-0 (:width size) 2) - :on-change (partial on-size-change :width)}]] + :on-change #(on-size-change % :width)}]] [:div.lock-size {:class (when (:proportion-lock shape) "selected") :on-click on-proportion-lock-change} @@ -73,7 +67,7 @@ :type "number" :min "0" :value (precision-or-0 (:height size) 2) - :on-change (partial on-size-change :height)}]]] + :on-change #(on-size-change % :height)}]]] [:span "Position"] [:div.row-flex @@ -82,13 +76,13 @@ {:placeholder "x" :type "number" :value (precision-or-0 (:x1 shape 0) 2) - :on-change (partial on-pos-change :x)}]] + :on-change #(on-pos-change % :x)}]] [:div.input-element.pixels [:input.input-text {:placeholder "y" :type "number" :value (precision-or-0 (:y1 shape 0) 2) - :on-change (partial on-pos-change :y)}]]] + :on-change #(on-pos-change % :y)}]]] [:span "Border radius"] [:div.row-flex @@ -96,13 +90,13 @@ {:placeholder "rx" :type "number" :value (precision-or-0 (:rx shape 0) 2) - :on-change (partial on-border-change :rx)}] + :on-change #(on-border-change % :rx)}] [:div.lock-size i/lock] [:input.input-text {:placeholder "ry" :type "number" :value (precision-or-0 (:ry shape 0) 2) - :on-change (partial on-border-change :ry)}]] + :on-change #(on-border-change % :ry)}]] [:span "Rotation"] [:div.row-flex 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 4da16606b..f563b1119 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs @@ -2,13 +2,11 @@ ;; 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 +;; Copyright (c) 2015-2017 Andrey Antukh +;; Copyright (c) 2015-2017 Juan de la Cruz (ns uxbox.main.ui.workspace.sidebar.options.stroke - (:require [sablono.core :as html :refer-macros [html]] - [rum.core :as rum] - [lentes.core :as l] + (:require [lentes.core :as l] [uxbox.util.i18n :refer (tr)] [uxbox.util.router :as r] [potok.core :as ptk] @@ -22,81 +20,73 @@ [uxbox.util.math :refer (precision-or-0)] [uxbox.util.spec :refer (color?)])) -(defn- stroke-menu-render - [own menu shape] - (letfn [(change-stroke [value] - (let [sid (:id shape)] - (st/emit! (uds/update-stroke-attrs sid value)))) +(mx/defc stroke-menu + {:mixed [mx/static]} + [menu {:keys [id] :as shape}] + (letfn [(update-attrs [attrs] + (st/emit! (uds/update-attrs id attrs))) (on-width-change [event] - (let [value (dom/event->value event) - value (parse-float value 1)] - (change-stroke {:width value}))) + (let [value (-> (dom/event->value event) + (parse-float 1))] + (update-attrs {: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}))) + (let [value (-> (dom/event->value event) + (parse-float 1) + (/ 10000))] + (update-attrs {:stroke-opacity value}))) (on-stroke-style-change [event] - (let [value (dom/event->value event) - value (read-string value)] - (change-stroke {:type value}))) + (let [value (-> (dom/event->value event) + (read-string))] + (update-attrs {:stroke-style value}))) (on-stroke-color-change [event] (let [value (dom/event->value event)] (when (color? value) - (change-stroke {:color value})))) + (update-attrs {:stroke-color value})))) (show-color-picker [event] (let [x (.-clientX event) y (.-clientY event) opts {:x x :y y :shape (:id shape) - :attr :stroke + :attr :stroke-color :transparent? true}] (udl/open! :workspace/shape-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"]] - [:div.input-element.pixels - [:input.input-text - {:placeholder "Width" - :type "number" - :min "0" - :value (precision-or-0 (:stroke-width shape 1) 2) - :on-change on-width-change}]]] + [: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 (pr-str (:stroke-style 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"]] + [:div.input-element.pixels + [:input.input-text + {:placeholder "Width" + :type "number" + :min "0" + :value (precision-or-0 (:stroke-width shape 1) 2) + :on-change on-width-change}]]] - [:span "Color"] - [:div.row-flex.color-data - [:span.color-th - {:style {:background-color (:stroke shape "#000000")} - :on-click show-color-picker}] - [:div.color-info - [:input - {:on-change on-stroke-color-change - :value (:stroke shape "#000000")}]]] + [:span "Color"] + [:div.row-flex.color-data + [:span.color-th + {:style {:background-color (:stroke-color shape)} + :on-click show-color-picker}] + [:div.color-info + [:input + {:on-change on-stroke-color-change + :value (:stroke-color 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]})) + [:span "Opacity"] + [:div.row-flex + [:input.slidebar + {:type "range" + :min "0" + :max "10000" + :value (* 10000 (:stroke-opacity shape)) + :step "1" + :on-change on-opacity-change}]]]])) 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 6413bfcf0..cdf601bc8 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/text.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/text.cljs @@ -2,13 +2,11 @@ ;; 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 +;; Copyright (c) 2015-2017 Andrey Antukh +;; Copyright (c) 2015-2017 Juan de la Cruz (ns uxbox.main.ui.workspace.sidebar.options.text - (:require [sablono.core :as html :refer-macros [html]] - [rum.core :as rum] - [lentes.core :as l] + (:require [lentes.core :as l] [uxbox.util.i18n :refer (tr)] [uxbox.util.router :as r] [potok.core :as ptk] @@ -30,136 +28,128 @@ (declare +fonts+) (declare +fonts-by-id+) -(defn- text-menu-render - [own menu {:keys [font] :as shape}] - (letfn [(on-font-family-change [event] +(mx/defc text-menu + {:mixins [mx/static]} + [menu {:keys [id] :as shape}] + (letfn [(update-attrs [attrs] + (st/emit! (uds/update-attrs id attrs))) + (on-font-family-change [event] (let [value (dom/event->value event) - sid (:id shape) - params {:family (read-string value) - :weight "normal" - :style "normal"}] - (st/emit! (uds/update-font-attrs sid params)))) + attrs {:font-family (read-string value) + :font-weight "normal" + :font-style "normal"}] + (update-attrs attrs))) (on-font-size-change [event] - (let [value (dom/event->value event) - params {:size (parse-int value)} - sid (:id shape)] - (st/emit! (uds/update-font-attrs sid params)))) + (let [value (-> (dom/event->value event) + (parse-int 0))] + (update-attrs {:font-size value}))) (on-font-letter-spacing-change [event] - (let [value (dom/event->value event) - params {:letter-spacing (parse-float value)} - sid (:id shape)] - (st/emit! (uds/update-font-attrs sid params)))) + (let [value (-> (dom/event->value event) + (parse-float))] + (update-attrs {:letter-spacing value}))) (on-font-line-height-change [event] - (let [value (dom/event->value event) - params {:line-height (parse-float value)} - sid (:id shape)] - (st/emit! (uds/update-font-attrs sid params)))) + (let [value (-> (dom/event->value event) + (parse-float))] + (update-attrs {:line-height value}))) (on-font-align-change [event value] - (let [params {:align value} - sid (:id shape)] - (st/emit! (uds/update-font-attrs sid params)))) - + (update-attrs {:text-align value})) (on-font-style-change [event] - (let [value (dom/event->value event) - [weight style] (read-string value) - sid (:id shape) - params {:style style - :weight weight}] - (st/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" + (let [[weight style] (-> (dom/event->value event) + (read-string))] + (update-attrs {:font-style style + :font-weight weight})))] + (let [{:keys [font-family + font-style + font-weight + font-size + text-align + line-height + letter-spacing] + :or {font-family "sourcesanspro" + font-style "normal" + font-weight "normal" + font-size 16 + text-align "left" letter-spacing 1 - line-height 1.4 - size 16}} font - styles (:styles (first (filter #(= (:id %) family) +fonts+)))] - (html - [:div.element-set {:key (str (:id menu))} - [:div.element-set-title (:name menu)] - [:div.element-set-content + line-height 1.4}} shape + styles (:styles (first (filter #(= (:id %) font-family) +fonts+)))] + [: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 +fonts+] - [:option {:value (pr-str (:id font)) - :key (:id font)} (:name font)])]] + [:span "Font family"] + [:div.row-flex + [:select.input-select {:value (pr-str font-family) + :on-change on-font-family-change} + (for [font +fonts+] + [:option {:value (pr-str (:id font)) + :key (:id font)} (:name font)])]] - [:span "Size and Weight"] - [:div.row-flex - [:div.editable-select - [:select.input-select - {:id "common-font-sizes" - :on-change on-font-size-change} - [:option {:value "8"} "8"] - [:option {:value "9"} "9"] - [:option {:value "10"} "10"] - [:option {:value "11"} "11"] - [:option {:value "12"} "12"] - [:option {:value "14"} "14"] - [:option {:value "18"} "18"] - [:option {:value "24"} "24"] - [:option {:value "36"} "36"] - [:option {:value "48"} "48"] - [:option {:value "72"} "72"]] - [:input.input-text - {:placeholder "Font Size" - :type "number" - :min "0" - :max "200" - :value (precision-or-0 size 2) - :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 + [:span "Size and Weight"] + [:div.row-flex + [:div.editable-select + [:select.input-select + {:id "common-font-sizes" + :value font-size + :on-change on-font-size-change} + [:option {:value "8"} "8"] + [:option {:value "9"} "9"] + [:option {:value "10"} "10"] + [:option {:value "11"} "11"] + [:option {:value "12"} "12"] + [:option {:value "14"} "14"] + [:option {:value "18"} "18"] + [:option {:value "24"} "24"] + [:option {:value "36"} "36"] + [:option {:value "48"} "48"] + [:option {:value "72"} "72"]] [:input.input-text - {:placeholder "Line height" + {:placeholder "Font Size" :type "number" - :step "0.1" :min "0" :max "200" - :value (precision-or-0 line-height 2) - :on-change on-font-line-height-change}] - [:input.input-text - {:placeholder "Letter spacing" - :type "number" - :step "0.1" - :min "0" - :max "200" - :value (precision-or-0 letter-spacing 2) - :on-change on-font-letter-spacing-change}]] + :value (precision-or-0 font-size 2) + :on-change on-font-size-change}]] + [:select.input-select {:value (pr-str [font-weight font-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 (precision-or-0 line-height 2) + :on-change on-font-line-height-change}] + [:input.input-text + {:placeholder "Letter spacing" + :type "number" + :step "0.1" + :min "0" + :max "200" + :value (precision-or-0 letter-spacing 2) + :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]})) - + [:span "Text align"] + [:div.row-flex.align-icons + [:span {:class (when (= text-align "left") "current") + :on-click #(on-font-align-change % "left")} + i/align-left] + [:span {:class (when (= text-align "right") "current") + :on-click #(on-font-align-change % "right")} + i/align-right] + [:span {:class (when (= text-align "center") "current") + :on-click #(on-font-align-change % "center")} + i/align-center] + [:span {:class (when (= text-align "justify") "current") + :on-click #(on-font-align-change % "justify")} + i/align-justify]]]]))) (def +fonts+ [{:id "sourcesanspro" diff --git a/frontend/src/uxbox/util/spec.cljs b/frontend/src/uxbox/util/spec.cljs index c37dfabcc..aadecb248 100644 --- a/frontend/src/uxbox/util/spec.cljs +++ b/frontend/src/uxbox/util/spec.cljs @@ -45,3 +45,20 @@ (when-not valid (js/console.error (str "Spec validation error:\n" (s/explain-str spec data)))) valid)) + +(defn extract + "Given a map spec, performs a `select-keys` + like exctraction from the object. + + NOTE: this function does not executes + the conform or validation of the data, + is responsability of the user to do it." + [data spec] + (let [desc (s/describe spec) + {:keys [req-un opt-un]} (apply hash-map (rest desc)) + keys (concat + (map (comp keyword name) req-un) + (map (comp keyword name) opt-un))] + (select-keys data keys))) + +