0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-20 19:51:23 -05:00

Refactor shapes attributes handling.

This commit is contained in:
Andrey Antukh 2017-01-05 23:21:05 +01:00
parent b3d995de53
commit 28d18a07a0
No known key found for this signature in database
GPG key ID: 4DFEBCB8316A8B95
14 changed files with 440 additions and 543 deletions

View file

@ -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

View file

@ -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 <niwi@niwi.nz>
;; Copyright (c) 2016-2017 Andrey Antukh <niwi@niwi.nz>
(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)))

View file

@ -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)]]

View file

@ -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))

View file

@ -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]]))

View file

@ -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)

View file

@ -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")}}

View file

@ -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

View file

@ -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 <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
;; Copyright (c) 2015-2017 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2017 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(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}]]]]))

View file

@ -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 <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(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]}))

View file

@ -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 <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
;; Copyright (c) 2015-2017 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2017 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(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

View file

@ -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 <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
;; Copyright (c) 2015-2017 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2017 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(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}]]]]))

View file

@ -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 <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
;; Copyright (c) 2015-2017 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2017 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(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"

View file

@ -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)))