mirror of
https://github.com/penpot/penpot.git
synced 2025-05-31 12:36:10 +02:00
Merge branch 'wip/shape-data-structure-refactor' into develop
This commit is contained in:
commit
188872d712
125 changed files with 7967 additions and 3972 deletions
|
@ -17,28 +17,28 @@
|
|||
id (when (uuid-str? id) (uuid id))]
|
||||
[:main.dashboard-main
|
||||
[:& messages-widget]
|
||||
[:& header {:section :dashboard/projects}]
|
||||
[:& header {:section :dashboard-projects}]
|
||||
[:& projects/projects-page {:id id}]]))
|
||||
|
||||
(mf/defc dashboard-assets
|
||||
[{:keys [route] :as props}]
|
||||
(let [section (:name route)
|
||||
(let [section (get-in route [:data :name])
|
||||
{:keys [id type]} (get-in route [:params :query])
|
||||
id (cond
|
||||
;; (str/digits? id) (parse-int id)
|
||||
(uuid-str? id) (uuid id)
|
||||
(str/empty-or-nil? id) nil
|
||||
:else id)
|
||||
type (when (str/alpha? type) (keyword type))]
|
||||
type (if (str/alpha? type) (keyword type) :own)]
|
||||
[:main.dashboard-main
|
||||
[:& messages-widget]
|
||||
[:& header {:section section}]
|
||||
(case section
|
||||
:dashboard/icons
|
||||
:dashboard-icons
|
||||
[:& icons/icons-page {:type type :id id}]
|
||||
|
||||
:dashboard/images
|
||||
:dashboard-images
|
||||
[:& images/images-page {:type type :id id}]
|
||||
|
||||
:dashboard/colors
|
||||
:dashboard-colors
|
||||
[:& colors/colors-page {:type type :id id}])]))
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
(delete []
|
||||
(st/emit!
|
||||
(dc/delete-collection (:id coll))
|
||||
(rt/nav :dashboard/colors nil {:type (:type coll)})))
|
||||
(rt/nav :dashboard-colors nil {:type (:type coll)})))
|
||||
|
||||
(on-delete []
|
||||
(modal/show! confirm-dialog {:on-accept delete}))]
|
||||
|
@ -79,7 +79,7 @@
|
|||
editable? (= type :own)]
|
||||
(letfn [(on-click [event]
|
||||
(let [type (or type :own)]
|
||||
(st/emit! (rt/nav :dashboard/colors nil {:type type :id id}))))
|
||||
(st/emit! (rt/nav :dashboard-colors nil {:type type :id id}))))
|
||||
(on-input-change [event]
|
||||
(let [value (dom/get-target event)
|
||||
value (dom/get-value value)]
|
||||
|
@ -107,14 +107,14 @@
|
|||
:on-key-down on-input-keyup}]
|
||||
[:span.close {:on-click on-cancel} i/close]]
|
||||
[:span.element-title name])
|
||||
[:span.element-subtitle
|
||||
#_[:span.element-subtitle
|
||||
(tr "ds.num-elements" (t/c colors))]])))
|
||||
|
||||
(mf/defc nav
|
||||
[{:keys [id type colls selected-coll] :as props}]
|
||||
(let [own? (= type :own)
|
||||
builtin? (= type :builtin)
|
||||
select-tab #(st/emit! (rt/nav :dashboard/colors nil {:type %}))]
|
||||
select-tab #(st/emit! (rt/nav :dashboard-colors nil {:type %}))]
|
||||
[:div.library-bar
|
||||
[:div.library-bar-inside
|
||||
[:ul.library-tabs
|
||||
|
@ -259,7 +259,8 @@
|
|||
[{:keys [id type coll] :as props}]
|
||||
(let [selected (mf/deref selected-colors-iref)]
|
||||
[:section.dashboard-grid.library
|
||||
[:& grid-header {:coll coll}]
|
||||
(when coll
|
||||
[:& grid-header {:coll coll}])
|
||||
[:& grid {:coll coll :id id :type type :selected selected}]
|
||||
(when (seq selected)
|
||||
[:& grid-options {:id id :type type
|
||||
|
@ -282,14 +283,12 @@
|
|||
(first colls))
|
||||
id (:id selected-coll)]
|
||||
|
||||
(mf/use-effect #(st/emit! (dc/initialize)) #js [id type])
|
||||
(mf/use-effect #(st/emit! (dc/fetch-collections)))
|
||||
|
||||
[:section.dashboard-content
|
||||
[:& nav {:type type
|
||||
:id id
|
||||
:colls colls
|
||||
:selected-coll selected-coll}]
|
||||
:colls colls}]
|
||||
[:& content {:type type
|
||||
:id id
|
||||
:coll selected-coll}]]))
|
||||
|
|
|
@ -25,26 +25,26 @@
|
|||
|
||||
(mf/defc header
|
||||
[{:keys [section] :as props}]
|
||||
(let [projects? (= section :dashboard/projects)
|
||||
icons? (= section :dashboard/icons)
|
||||
images? (= section :dashboard/images)
|
||||
colors? (= section :dashboard/colors)]
|
||||
(let [projects? (= section :dashboard-projects)
|
||||
icons? (= section :dashboard-icons)
|
||||
images? (= section :dashboard-images)
|
||||
colors? (= section :dashboard-colors)]
|
||||
[:header#main-bar.main-bar
|
||||
[:div.main-logo
|
||||
[:& header-link {:section :dashboard/projects
|
||||
[:& header-link {:section :dashboard-projects
|
||||
:content i/logo}]]
|
||||
[:ul.main-nav
|
||||
[:li {:class (when projects? "current")}
|
||||
[:& header-link {:section :dashboard/projects
|
||||
[:& header-link {:section :dashboard-projects
|
||||
:content (tr "ds.projects")}]]
|
||||
[:li {:class (when icons? "current")}
|
||||
[:& header-link {:section :dashboard/icons
|
||||
[:& header-link {:section :dashboard-icons
|
||||
:content (tr "ds.icons")}]]
|
||||
[:li {:class (when images? "current")}
|
||||
[:& header-link {:section :dashboard/images
|
||||
[:& header-link {:section :dashboard-images
|
||||
:content (tr "ds.images")}]]
|
||||
[:li {:class (when colors? "current")}
|
||||
[:& header-link {:section :dashboard/colors
|
||||
[:& header-link {:section :dashboard-colors
|
||||
:content (tr "ds.colors")}]]]
|
||||
[:& user]]))
|
||||
|
||||
|
|
|
@ -79,29 +79,14 @@
|
|||
|
||||
;; --- Nav
|
||||
|
||||
(defn- make-num-icons-iref
|
||||
[id]
|
||||
(letfn [(selector [icons]
|
||||
(->> (vals icons)
|
||||
(filter #(= id (:collection-id %)))
|
||||
(count)))]
|
||||
(-> (comp (l/key :icons)
|
||||
(l/lens selector))
|
||||
(l/derive st/state))))
|
||||
|
||||
(mf/defc nav-item
|
||||
[{:keys [coll selected?] :as props}]
|
||||
(let [local (mf/use-state {})
|
||||
{:keys [id type name num-icons]} coll
|
||||
;; TODO: recalculate the num-icons on crud operations for
|
||||
;; avod doing this on UI.
|
||||
;; num-icons-iref (mf/use-memo {:deps #js [id]
|
||||
;; :fn #(make-num-icons-iref (:id coll))})
|
||||
;; num-icons (mf/deref num-icons-iref)
|
||||
{:keys [id type name]} coll
|
||||
editable? (= type :own)]
|
||||
(letfn [(on-click [event]
|
||||
(let [type (or type :own)]
|
||||
(st/emit! (rt/nav :dashboard/icons {} {:type type :id id}))))
|
||||
(st/emit! (rt/nav :dashboard-icons {} {:type type :id id}))))
|
||||
(on-input-change [event]
|
||||
(-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
|
@ -127,15 +112,14 @@
|
|||
:on-change on-input-change
|
||||
:on-key-down on-input-keyup}]
|
||||
[:span.close {:on-click on-cancel} i/close]]
|
||||
[:span.element-title (if id name "Storage")])
|
||||
[:span.element-subtitle (tr "ds.num-elements" (t/c num-icons))]])))
|
||||
[:span.element-title (if id name "Storage")])])))
|
||||
|
||||
|
||||
(mf/defc nav
|
||||
[{:keys [id type colls selected-coll] :as props}]
|
||||
(let [own? (= type :own)
|
||||
builtin? (= type :builtin)
|
||||
select-tab #(st/emit! (rt/nav :dashboard/icons nil {:type %}))]
|
||||
select-tab #(st/emit! (rt/nav :dashboard-icons nil {:type %}))]
|
||||
[:div.library-bar
|
||||
[:div.library-bar-inside
|
||||
[:ul.library-tabs
|
||||
|
@ -350,54 +334,12 @@
|
|||
:selected (contains? (:selected opts) (:id icon))
|
||||
:edition? (= (:edition opts) (:id icon))}])]]]))
|
||||
|
||||
;; --- Menu
|
||||
|
||||
(mf/defc menu
|
||||
[{:keys [opts coll] :as props}]
|
||||
(let [ordering (:order opts :name)
|
||||
filtering (:filter opts "")
|
||||
icount (count (:icons coll))]
|
||||
(letfn [(on-term-change [event]
|
||||
(let [term (-> (dom/get-target event)
|
||||
(dom/get-value))]
|
||||
(st/emit! (di/update-opts :filter term))))
|
||||
(on-ordering-change [event]
|
||||
(let [value (dom/event->value event)
|
||||
value (read-string value)]
|
||||
(st/emit! (di/update-opts :order value))))
|
||||
(on-clear [event]
|
||||
(st/emit! (di/update-opts :filter "")))]
|
||||
[:section.dashboard-bar.library-gap
|
||||
[:div.dashboard-info
|
||||
|
||||
;; Counter
|
||||
[:span.dashboard-icons (tr "ds.num-icons" (t/c icount))]
|
||||
|
||||
;; Sorting
|
||||
[:div
|
||||
[:span (tr "ds.ordering")]
|
||||
[:select.input-select {:on-change on-ordering-change
|
||||
:value (pr-str ordering)}
|
||||
(for [[key value] (seq +ordering-options+)]
|
||||
[:option {:key key :value (pr-str key)} (tr value)])]]
|
||||
|
||||
;; Search
|
||||
[:form.dashboard-search
|
||||
[:input.input-text {:key :icons-search-box
|
||||
:type "text"
|
||||
:on-change on-term-change
|
||||
:auto-focus true
|
||||
:placeholder (tr "ds.search.placeholder")
|
||||
:value filtering}]
|
||||
[:div.clear-search {:on-click on-clear} i/close]]]])))
|
||||
|
||||
;; --- Content
|
||||
|
||||
(mf/defc content
|
||||
[{:keys [id type coll] :as props}]
|
||||
(let [opts (mf/deref opts-iref)]
|
||||
[:*
|
||||
[:& menu {:opts opts :coll coll}]
|
||||
[:section.dashboard-grid.library
|
||||
(when coll
|
||||
[:& grid-header {:coll coll}])
|
||||
|
@ -425,15 +367,13 @@
|
|||
:else (first colls))
|
||||
id (:id selected-coll)]
|
||||
(mf/use-effect #(st/emit! di/fetch-collections))
|
||||
(mf/use-effect {:fn #(st/emit! di/initialize
|
||||
(di/fetch-icons id))
|
||||
:deps #js [id type]})
|
||||
(mf/use-effect {:fn #(st/emit! (di/fetch-icons id))
|
||||
:deps #js [(str id)]})
|
||||
|
||||
[:section.dashboard-content
|
||||
[:& nav {:type type
|
||||
:id id
|
||||
:colls colls
|
||||
:selected-coll selected-coll}]
|
||||
:colls colls}]
|
||||
[:& content {:type type
|
||||
:id id
|
||||
:coll selected-coll}]]))
|
||||
|
|
|
@ -26,30 +26,6 @@
|
|||
[uxbox.util.router :as rt]
|
||||
[uxbox.util.time :as dt]))
|
||||
|
||||
;; --- Helpers & Constants
|
||||
|
||||
(def +ordering-options+
|
||||
{:name "ds.ordering.by-name"
|
||||
:created "ds.ordering.by-creation-date"})
|
||||
|
||||
(defn- sort-images-by
|
||||
[ordering images]
|
||||
(case ordering
|
||||
:name (sort-by :name images)
|
||||
:created (reverse (sort-by :created-at images))
|
||||
images))
|
||||
|
||||
(defn- contains-term?
|
||||
[phrase term]
|
||||
(let [term (name term)]
|
||||
(str/includes? (str/lower phrase) (str/trim (str/lower term)))))
|
||||
|
||||
(defn- filter-images-by
|
||||
[term images]
|
||||
(if (str/blank? term)
|
||||
images
|
||||
(filter #(contains-term? (:name %) term) images)))
|
||||
|
||||
;; --- Refs
|
||||
|
||||
(def collections-iref
|
||||
|
@ -80,61 +56,41 @@
|
|||
|
||||
;; --- Nav
|
||||
|
||||
(defn- make-num-images-iref
|
||||
[id]
|
||||
(letfn [(selector [images]
|
||||
(->> (vals images)
|
||||
(filter #(= id (:collection-id %)))
|
||||
(count)))]
|
||||
(-> (comp (l/key :images)
|
||||
(l/lens selector))
|
||||
(l/derive st/state))))
|
||||
|
||||
(mf/defc nav-item
|
||||
[{:keys [coll selected?] :as props}]
|
||||
(let [local (mf/use-state {})
|
||||
{:keys [id type name num-images]} coll
|
||||
;; TODO: recalculate the num-images on crud operations for
|
||||
;; avod doing this on UI.
|
||||
num-images-iref (mf/use-memo #(make-num-images-iref (:id coll)) #js [id])
|
||||
num-images (mf/deref num-images-iref)
|
||||
editable? (= type :own)]
|
||||
(letfn [(on-click [event]
|
||||
(let [type (or type :own)]
|
||||
(st/emit! (rt/nav :dashboard/images {} {:type type :id id}))))
|
||||
(on-input-change [event]
|
||||
(-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(swap! local assoc :name)))
|
||||
(on-cancel [event]
|
||||
(swap! local dissoc :name :edit))
|
||||
(on-double-click [event]
|
||||
(when editable?
|
||||
(swap! local assoc :edit true)))
|
||||
(on-input-keyup [event]
|
||||
(when (kbd/enter? event)
|
||||
(let [value (-> (dom/get-target event) (dom/get-value))]
|
||||
(st/emit! (di/rename-collection id (str/trim (:name @local))))
|
||||
(swap! local assoc :edit false))))]
|
||||
[:li {:on-click on-click
|
||||
:on-double-click on-double-click
|
||||
:class-name (when selected? "current")}
|
||||
(if (:edit @local)
|
||||
[:div
|
||||
[:input.element-title {:value (if (:name @local)
|
||||
(:name @local)
|
||||
(if id name "Storage"))
|
||||
:on-change on-input-change
|
||||
:on-key-down on-input-keyup}]
|
||||
[:span.close {:on-click on-cancel} i/close]]
|
||||
[:span.element-title (if id name "Storage")])
|
||||
[:span.element-subtitle (tr "ds.num-elements" (t/c num-images))]])))
|
||||
editable? (= type :own)
|
||||
on-click
|
||||
(fn [event]
|
||||
(let [type (or type :own)]
|
||||
(st/emit! (rt/nav :dashboard-images {} {:type type :id id}))))
|
||||
|
||||
on-cancel-edition #(swap! local dissoc :edit)
|
||||
on-double-click #(when editable? (swap! local assoc :edit true))
|
||||
on-input-keyup
|
||||
(fn [event]
|
||||
(when (kbd/enter? event)
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(str/trim))]
|
||||
(st/emit! (di/rename-collection id value))
|
||||
(swap! local assoc :edit false))))]
|
||||
[:li {:on-click on-click
|
||||
:on-double-click on-double-click
|
||||
:class-name (when selected? "current")}
|
||||
(if (:edit @local)
|
||||
[:div
|
||||
[:input.element-title {:default-value name
|
||||
:on-key-down on-input-keyup}]
|
||||
[:span.close {:on-click on-cancel-edition} i/close]]
|
||||
[:span.element-title (if id name "Storage")])]))
|
||||
|
||||
(mf/defc nav
|
||||
[{:keys [id type colls selected-coll] :as props}]
|
||||
[{:keys [id type colls] :as props}]
|
||||
(let [own? (= type :own)
|
||||
builtin? (= type :builtin)
|
||||
select-tab #(st/emit! (rt/nav :dashboard/images nil {:type %}))]
|
||||
select-tab #(st/emit! (rt/nav :dashboard-images nil {:type %}))]
|
||||
[:div.library-bar
|
||||
[:div.library-bar-inside
|
||||
[:ul.library-tabs
|
||||
|
@ -148,7 +104,7 @@
|
|||
[:ul.library-elements
|
||||
(when own?
|
||||
[:li
|
||||
[:a.btn-primary {:on-click #(st/emit! (di/create-collection))}
|
||||
[:a.btn-primary {:on-click #(st/emit! di/create-collection)}
|
||||
(tr "ds.images-collection.new")]])
|
||||
(when own?
|
||||
[:& nav-item {:selected? (nil? id)}])
|
||||
|
@ -168,7 +124,7 @@
|
|||
colls (->> (vals colls)
|
||||
(filter #(= :own (:type %)))
|
||||
(remove #(= selected (:id %)))
|
||||
(sort-by :name colls))
|
||||
#_(sort-by :name colls))
|
||||
on-select (fn [event id]
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
|
@ -306,20 +262,21 @@
|
|||
;; --- Grid
|
||||
|
||||
(defn- make-images-iref
|
||||
[id]
|
||||
(-> (comp (l/key :images)
|
||||
(l/lens (fn [images]
|
||||
(->> (vals images)
|
||||
(filter #(= id (:collection-id %)))))))
|
||||
(l/derive st/state)))
|
||||
[id type]
|
||||
(letfn [(selector-fn [state]
|
||||
(let [images (vals (:images state))]
|
||||
(filterv #(= id (:collection-id %)) images)))]
|
||||
(-> (l/lens selector-fn)
|
||||
(l/derive st/state))))
|
||||
|
||||
(mf/defc grid
|
||||
[{:keys [id type coll opts] :as props}]
|
||||
(let [editable? (or (= type :own) (nil? id))
|
||||
images-iref (mf/use-memo #(make-images-iref id) #js [id])
|
||||
images-iref (mf/use-memo
|
||||
{:fn #(make-images-iref id type)
|
||||
:deps (mf/deps id type)})
|
||||
images (->> (mf/deref images-iref)
|
||||
(filter-images-by (:filter opts ""))
|
||||
(sort-images-by (:order opts :name)))]
|
||||
(sort-by :created-at))]
|
||||
[:div.dashboard-grid-content
|
||||
[:div.dashboard-grid-row
|
||||
(when editable?
|
||||
|
@ -332,53 +289,53 @@
|
|||
|
||||
;; --- Menu
|
||||
|
||||
(mf/defc menu
|
||||
[{:keys [opts coll] :as props}]
|
||||
(let [ordering (:order opts :name)
|
||||
filtering (:filter opts "")
|
||||
icount (count (:images coll))]
|
||||
(letfn [(on-term-change [event]
|
||||
(let [term (-> (dom/get-target event)
|
||||
(dom/get-value))]
|
||||
(st/emit! (di/update-opts :filter term))))
|
||||
(on-ordering-change [event]
|
||||
(let [value (dom/event->value event)
|
||||
value (read-string value)]
|
||||
(st/emit! (di/update-opts :order value))))
|
||||
(on-clear [event]
|
||||
(st/emit! (di/update-opts :filter "")))]
|
||||
[:section.dashboard-bar.library-gap
|
||||
[:div.dashboard-info
|
||||
;; (mf/defc menu
|
||||
;; [{:keys [opts coll] :as props}]
|
||||
;; (let [ordering (:order opts :name)
|
||||
;; filtering (:filter opts "")
|
||||
;; icount (count (:images coll))]
|
||||
;; (letfn [(on-term-change [event]
|
||||
;; (let [term (-> (dom/get-target event)
|
||||
;; (dom/get-value))]
|
||||
;; (st/emit! (di/update-opts :filter term))))
|
||||
;; (on-ordering-change [event]
|
||||
;; (let [value (dom/event->value event)
|
||||
;; value (read-string value)]
|
||||
;; (st/emit! (di/update-opts :order value))))
|
||||
;; (on-clear [event]
|
||||
;; (st/emit! (di/update-opts :filter "")))]
|
||||
;; [:section.dashboard-bar.library-gap
|
||||
;; [:div.dashboard-info
|
||||
|
||||
;; Counter
|
||||
[:span.dashboard-images (tr "ds.num-images" (t/c icount))]
|
||||
;; ;; Counter
|
||||
;; [:span.dashboard-images (tr "ds.num-images" (t/c icount))]
|
||||
|
||||
;; Sorting
|
||||
[:div
|
||||
[:span (tr "ds.ordering")]
|
||||
[:select.input-select {:on-change on-ordering-change
|
||||
:value (pr-str ordering)}
|
||||
(for [[key value] (seq +ordering-options+)]
|
||||
[:option {:key key :value (pr-str key)} (tr value)])]]
|
||||
;; ;; Sorting
|
||||
;; [:div
|
||||
;; [:span (tr "ds.ordering")]
|
||||
;; [:select.input-select {:on-change on-ordering-change
|
||||
;; :value (pr-str ordering)}
|
||||
;; (for [[key value] (seq +ordering-options+)]
|
||||
;; [:option {:key key :value (pr-str key)} (tr value)])]]
|
||||
|
||||
;; Search
|
||||
[:form.dashboard-search
|
||||
[:input.input-text {:key :images-search-box
|
||||
:type "text"
|
||||
:on-change on-term-change
|
||||
:auto-focus true
|
||||
:placeholder (tr "ds.search.placeholder")
|
||||
:value filtering}]
|
||||
[:div.clear-search {:on-click on-clear} i/close]]]])))
|
||||
;; ;; Search
|
||||
;; [:form.dashboard-search
|
||||
;; [:input.input-text {:key :images-search-box
|
||||
;; :type "text"
|
||||
;; :on-change on-term-change
|
||||
;; :auto-focus true
|
||||
;; :placeholder (tr "ds.search.placeholder")
|
||||
;; :value filtering}]
|
||||
;; [:div.clear-search {:on-click on-clear} i/close]]]])))
|
||||
|
||||
(mf/defc content
|
||||
[{:keys [id type coll] :as props}]
|
||||
(let [opts (mf/deref opts-iref)]
|
||||
[:*
|
||||
[:& menu {:opts opts :coll coll}]
|
||||
[:section.dashboard-grid.library
|
||||
(when coll
|
||||
[:& grid-header {:coll coll}])
|
||||
|
||||
[:& grid {:id id
|
||||
:type type
|
||||
:coll coll
|
||||
|
@ -390,28 +347,26 @@
|
|||
|
||||
(mf/defc images-page
|
||||
[{:keys [id type] :as props}]
|
||||
(let [type (or type :own)
|
||||
colls (mf/deref collections-iref)
|
||||
(let [colls (mf/deref collections-iref)
|
||||
colls (cond->> (vals colls)
|
||||
(= type :own) (filter #(= :own (:type %)))
|
||||
(= type :builtin) (filter #(= :builtin (:type %)))
|
||||
true (sort-by :created-at))
|
||||
selected-coll (cond
|
||||
(and (= type :own) (nil? id)) nil
|
||||
(uuid? id) (seek #(= id (:id %)) colls)
|
||||
:else (first colls))
|
||||
id (:id selected-coll)]
|
||||
|
||||
(mf/use-effect #(st/emit! (di/fetch-collections)))
|
||||
(mf/use-effect {:fn #(st/emit! (di/initialize)
|
||||
(di/fetch-images id))
|
||||
:deps #js [id type]})
|
||||
coll (cond
|
||||
(and (= type :own) (nil? id)) nil
|
||||
(uuid? id) (seek #(= id (:id %)) colls)
|
||||
:else (first colls))
|
||||
id (:id coll)]
|
||||
|
||||
(mf/use-effect #(st/emit! di/fetch-collections))
|
||||
(mf/use-effect {:fn #(st/emit! (di/fetch-images (:id coll)))
|
||||
:deps #js [(str (:id coll))]})
|
||||
|
||||
[:section.dashboard-content
|
||||
[:& nav {:type type
|
||||
:id id
|
||||
:colls colls
|
||||
:selected-coll selected-coll}]
|
||||
:colls colls}]
|
||||
[:& content {:type type
|
||||
:id id
|
||||
:coll selected-coll}]]))
|
||||
:coll coll}]]))
|
||||
|
|
|
@ -64,59 +64,6 @@
|
|||
files
|
||||
(filter #(contains-term? (:name %) term) files)))
|
||||
|
||||
;; --- Menu (Filter & Sort)
|
||||
|
||||
(mf/defc menu
|
||||
[{:keys [id opts files] :as props}]
|
||||
(let [ordering (:order opts :modified)
|
||||
filtering (:filter opts "")
|
||||
|
||||
on-term-change
|
||||
(fn [event]
|
||||
(let [term (-> (dom/get-target event)
|
||||
(dom/get-value))]
|
||||
(st/emit! (udp/update-opts :filter term))))
|
||||
|
||||
on-order-change
|
||||
(fn [event]
|
||||
(let [value (dom/event->value event)
|
||||
value (read-string value)]
|
||||
(st/emit! (udp/update-opts :order value))))
|
||||
|
||||
on-clear
|
||||
(fn [event]
|
||||
(st/emit! (udp/update-opts :filter "")))]
|
||||
|
||||
[:section.dashboard-bar.library-gap
|
||||
[:div.dashboard-info
|
||||
|
||||
;; Counter
|
||||
[:span.dashboard-images (tr "ds.num-files" (t/c (count files)))]
|
||||
|
||||
[:div
|
||||
;; Sorting
|
||||
;; TODO: convert to separate component?
|
||||
(when id
|
||||
[:*
|
||||
[:span (tr "ds.ordering")]
|
||||
[:select.input-select {:on-change on-order-change
|
||||
:value (pr-str ordering)}
|
||||
(for [[key value] (seq +ordering-options+)]
|
||||
(let [key (pr-str key)]
|
||||
[:option {:key key :value key} (tr value)]))]])]
|
||||
|
||||
;; Search
|
||||
;; TODO: convert to separate component?
|
||||
[:form.dashboard-search
|
||||
[:input.input-text
|
||||
{:key :images-search-box
|
||||
:type "text"
|
||||
:on-change on-term-change
|
||||
:auto-focus true
|
||||
:placeholder (tr "ds.search.placeholder")
|
||||
:value (or filtering "")}]
|
||||
[:div.clear-search {:on-click on-clear} i/close]]]]))
|
||||
|
||||
;; --- Grid Item Thumbnail
|
||||
|
||||
(mf/defc grid-item-thumbnail
|
||||
|
@ -160,12 +107,12 @@
|
|||
(str (tr "ds.updated-at" (dt/timeago (:modified-at file))))]]
|
||||
|
||||
[:div.project-th-actions
|
||||
[:div.project-th-icon.pages
|
||||
i/page
|
||||
#_[:span (:total-pages project)]]
|
||||
#_[:div.project-th-icon.comments
|
||||
i/chat
|
||||
[:span "0"]]
|
||||
;; [:div.project-th-icon.pages
|
||||
;; i/page
|
||||
;; #_[:span (:total-pages project)]]
|
||||
;; [:div.project-th-icon.comments
|
||||
;; i/chat
|
||||
;; [:span "0"]]
|
||||
[:div.project-th-icon.edit
|
||||
{:on-click on-edit}
|
||||
i/pencil]
|
||||
|
@ -176,7 +123,7 @@
|
|||
;; --- Grid
|
||||
|
||||
(mf/defc grid
|
||||
[{:keys [opts files] :as props}]
|
||||
[{:keys [id opts files] :as props}]
|
||||
(let [order (:order opts :modified)
|
||||
filter (:filter opts "")
|
||||
files (->> files
|
||||
|
@ -184,15 +131,13 @@
|
|||
(sort-by order))
|
||||
on-click #(do
|
||||
(dom/prevent-default %)
|
||||
#_(modal/show! create-project-dialog {})
|
||||
#_(udl/open! :create-project))
|
||||
]
|
||||
(st/emit! (udp/create-file {:project-id id})))]
|
||||
[:section.dashboard-grid
|
||||
[:h2 (tr "ds.projects.file-name")]
|
||||
[:div.dashboard-grid-content
|
||||
[:div.dashboard-grid-row
|
||||
[:div.grid-item.add-project #_{:on-click on-click}
|
||||
[:span (tr "ds.project-file")]]
|
||||
(when id
|
||||
[:div.grid-item.add-project {:on-click on-click}
|
||||
[:span (tr "ds.new-file")]])
|
||||
(for [item files]
|
||||
[:& grid-item {:file item :key (:id item)}])]]]))
|
||||
|
||||
|
@ -236,16 +181,23 @@
|
|||
(sort-by :created-at))]
|
||||
[:div.library-bar
|
||||
[:div.library-bar-inside
|
||||
[:form.dashboard-search
|
||||
[:input.input-text
|
||||
{:key :images-search-box
|
||||
:type "text"
|
||||
:auto-focus true
|
||||
:placeholder (tr "ds.search.placeholder")}]
|
||||
[:div.clear-search i/close]]
|
||||
[:ul.library-elements
|
||||
[:li
|
||||
[:a.btn-primary #_{:on-click #(st/emit! di/create-collection)}
|
||||
"new project +"]]
|
||||
|
||||
[:li {:style {:marginBottom "20px"}
|
||||
:on-click #(st/emit! (udp/go-to-project nil))
|
||||
[:li.recent-projects {:on-click #(st/emit! (udp/go-to-project nil))
|
||||
:class-name (when (nil? id) "current")}
|
||||
[:span.element-title "Recent"]]
|
||||
|
||||
[:div.projects-row
|
||||
[:span "PROJECTS"]
|
||||
[:a.add-project #_{:on-click #(st/emit! di/create-collection)}
|
||||
i/close]]
|
||||
|
||||
(for [item projects]
|
||||
[:& nav-item {:id (:id item)
|
||||
:key (:id item)
|
||||
|
@ -268,10 +220,8 @@
|
|||
[{:keys [id] :as props}]
|
||||
(let [opts (mf/deref opts-iref)
|
||||
files (mf/deref files-ref)]
|
||||
[:*
|
||||
[:& menu {:id id :opts opts :files files}]
|
||||
[:section.dashboard-grid.library
|
||||
[:& grid {:id id :opts opts :files files}]]]))
|
||||
[:section.dashboard-grid.library
|
||||
[:& grid {:id id :opts opts :files files}]]))
|
||||
|
||||
;; --- Projects Page
|
||||
|
||||
|
|
|
@ -4,7 +4,43 @@
|
|||
;;
|
||||
;; Copyright (c) 2016-2017 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.main.ui.shapes.attrs)
|
||||
(ns uxbox.main.ui.shapes.attrs
|
||||
(:require [cuerdas.core :as str]))
|
||||
|
||||
|
||||
;; (defn camel-case
|
||||
;; "Returns camel case version of the key, e.g. :http-equiv becomes :httpEquiv."
|
||||
;; [k]
|
||||
;; (if (or (keyword? k)
|
||||
;; (string? k)
|
||||
;; (symbol? k))
|
||||
;; (let [[first-word & words] (str/split (name k) #"-")]
|
||||
;; (if (or (empty? words)
|
||||
;; (= "aria" first-word)
|
||||
;; (= "data" first-word))
|
||||
;; k
|
||||
;; (-> (map str/capital words)
|
||||
;; (conj first-word)
|
||||
;; str/join
|
||||
;; keyword)))
|
||||
;; k))
|
||||
|
||||
(defn- process-key
|
||||
[k]
|
||||
(if (keyword? k)
|
||||
(cond
|
||||
(keyword-identical? k :stroke-color) :stroke
|
||||
(keyword-identical? k :fill-color) :fill
|
||||
(str/includes? (name k) "-") (str/camel k)
|
||||
:else k)))
|
||||
|
||||
(defn- process-attrs
|
||||
[m]
|
||||
(persistent!
|
||||
(reduce-kv (fn [m k v]
|
||||
(assoc! m (process-key k) v))
|
||||
(transient {})
|
||||
m)))
|
||||
|
||||
(def shape-style-attrs
|
||||
#{:fill-color
|
||||
|
@ -17,12 +53,6 @@
|
|||
:rx
|
||||
:ry})
|
||||
|
||||
(def shape-default-attrs
|
||||
{:stroke-color "#000000"
|
||||
:stroke-opacity 1
|
||||
:fill-color "#000000"
|
||||
:fill-opacity 1})
|
||||
|
||||
(defn- stroke-type->dasharray
|
||||
[style]
|
||||
(case style
|
||||
|
@ -30,24 +60,23 @@
|
|||
: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-attr
|
||||
;; [[key value :as pair]]
|
||||
;; (case key
|
||||
;; :stroke-color [:stroke value]
|
||||
;; :fill-color [:fill value]
|
||||
;; pair))
|
||||
|
||||
(defn- rename-attrs
|
||||
[attrs]
|
||||
(into {} (map rename-attr) attrs))
|
||||
;; (defn- rename-attrs
|
||||
;; [attrs]
|
||||
;; (into {} (map rename-attr) attrs))
|
||||
|
||||
(defn- transform-stroke-attrs
|
||||
[{:keys [stroke-style] :or {stroke-style :none} :as attrs}]
|
||||
(case stroke-style
|
||||
:none (dissoc attrs :stroke-style :stroke-width :stroke-opacity :stroke-color)
|
||||
:solid (-> (merge shape-default-attrs attrs)
|
||||
(dissoc :stroke-style))
|
||||
(-> (merge shape-default-attrs attrs)
|
||||
:solid (dissoc attrs :stroke-style)
|
||||
(-> attrs
|
||||
(assoc :stroke-dasharray (stroke-type->dasharray stroke-style))
|
||||
(dissoc :stroke-style))))
|
||||
|
||||
|
@ -56,4 +85,4 @@
|
|||
[shape]
|
||||
(-> (select-keys shape shape-style-attrs)
|
||||
(transform-stroke-attrs)
|
||||
(rename-attrs)))
|
||||
(process-attrs)))
|
||||
|
|
|
@ -47,18 +47,19 @@
|
|||
|
||||
(mf/defc image-shape
|
||||
[{:keys [shape image] :as props}]
|
||||
(let [{:keys [id x1 y1 width height modifier-mtx]} (geom/size shape)
|
||||
(let [{:keys [id x y width height modifier-mtx]} shape
|
||||
moving? (boolean modifier-mtx)
|
||||
transform (when (gmt/matrix? modifier-mtx)
|
||||
(str modifier-mtx))
|
||||
|
||||
props {:x x1 :y y1
|
||||
:id (str "shape-" id)
|
||||
:preserve-aspect-ratio "none"
|
||||
:class (classnames :move-cursor moving?)
|
||||
:xlink-href (:url image)
|
||||
:transform transform
|
||||
:width width
|
||||
:height height}
|
||||
attrs (merge props (attrs/extract-style-attrs shape))]
|
||||
[:> :image (normalize-props attrs)]))
|
||||
props (-> (attrs/extract-style-attrs shape)
|
||||
(assoc :x x
|
||||
:y y
|
||||
:id (str "shape-" id)
|
||||
:preserveAspectRatio "none"
|
||||
:class (classnames :move-cursor moving?)
|
||||
:xlinkHref (:url image)
|
||||
:transform transform
|
||||
:width width
|
||||
:height height))]
|
||||
[:& "image" props]))
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
(ns uxbox.main.ui.shapes.rect
|
||||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[cuerdas.core :as str]
|
||||
[uxbox.main.geom :as geom]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.ui.shapes.attrs :as attrs]
|
||||
|
@ -46,18 +47,19 @@
|
|||
(gmt/matrix? modifier-mtx) (geom/transform shape modifier-mtx)
|
||||
:else shape)
|
||||
|
||||
{:keys [x1 y1 width height] :as shape} (geom/size shape)
|
||||
{:keys [x y width height]} shape
|
||||
|
||||
transform (when (pos? rotation)
|
||||
(str (rotate (gmt/matrix) shape)))
|
||||
|
||||
moving? (boolean modifier-mtx)
|
||||
|
||||
props {:x x1 :y y1
|
||||
:id (str "shape-" id)
|
||||
:className (classnames :move-cursor moving?)
|
||||
:width width
|
||||
:height height
|
||||
:transform transform}
|
||||
attrs (merge (attrs/extract-style-attrs shape) props)]
|
||||
[:& "rect" attrs]))
|
||||
props (-> (attrs/extract-style-attrs shape)
|
||||
(assoc :x x
|
||||
:y y
|
||||
:id (str "shape-" id)
|
||||
:className (classnames :move-cursor moving?)
|
||||
:width width
|
||||
:height height
|
||||
:transform transform))]
|
||||
[:& "rect" props]))
|
||||
|
|
|
@ -122,7 +122,7 @@
|
|||
style (make-style shape)
|
||||
on-input (fn [ev]
|
||||
(let [content (dom/event->inner-text ev)]
|
||||
(st/emit! (udw/update-shape-attrs id {:content content}))))]
|
||||
#_(st/emit! (udw/update-shape-attrs id {:content content}))))]
|
||||
[:foreignObject {:x x1 :y y1 :width width :height height}
|
||||
[:div {:style (normalize-props style)
|
||||
:ref (::container own)
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
[rumext.alpha :as mf]
|
||||
[uxbox.main.constants :as c]
|
||||
[uxbox.main.data.history :as udh]
|
||||
[uxbox.main.data.pages :as udp]
|
||||
[uxbox.main.data.undo :as udu]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.data.workspace-websocket :as dws]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.ui.confirm]
|
||||
|
@ -55,12 +55,12 @@
|
|||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(if (pos? (.-deltaY event))
|
||||
(st/emit! (udw/decrease-zoom))
|
||||
(st/emit! (udw/increase-zoom)))
|
||||
(st/emit! (dw/decrease-zoom))
|
||||
(st/emit! (dw/increase-zoom)))
|
||||
(scroll/scroll-to-point dom mouse-point scroll-position))))
|
||||
|
||||
(mf/defc workspace-content
|
||||
[{:keys [layout page file] :as params}]
|
||||
[{:keys [layout page file flags] :as params}]
|
||||
(let [canvas (mf/use-ref nil)
|
||||
left-sidebar? (not (empty? (keep layout [:layers :sitemap
|
||||
:document-history])))
|
||||
|
@ -93,29 +93,50 @@
|
|||
(when right-sidebar?
|
||||
[:& right-sidebar {:page page :layout layout}])]))
|
||||
|
||||
(mf/defc workspace
|
||||
[{:keys [file-id page-id] :as props}]
|
||||
|
||||
(mf/defc workspace-page
|
||||
[{:keys [file-id page-id layout file flags] :as props}]
|
||||
(mf/use-effect
|
||||
{:deps #js [file-id page-id]
|
||||
:fn (fn []
|
||||
(let [sub (shortcuts/init)]
|
||||
(st/emit! (udw/initialize file-id page-id))
|
||||
#(rx/cancel! sub)))})
|
||||
|
||||
(let [layout (mf/deref refs/workspace-layout)
|
||||
file (mf/deref refs/workspace-file)
|
||||
page (mf/deref refs/workspace-page)
|
||||
flags (mf/deref refs/selected-flags)]
|
||||
{:deps (mf/deps file-id page-id)
|
||||
:fn #(st/emit! (dw/initialize-page page-id))})
|
||||
|
||||
(let [page (mf/deref refs/workspace-page)]
|
||||
[:> rdnd/provider {:backend rdnd/html5}
|
||||
[:& messages-widget]
|
||||
[:& header {:page page :layout layout :flags flags}]
|
||||
|
||||
(when (:colorpalette flags)
|
||||
(when (:colorpalette layout)
|
||||
[:& colorpalette])
|
||||
|
||||
(when (and layout page)
|
||||
[:& workspace-content {:layout layout
|
||||
:flags flags
|
||||
:file file
|
||||
:page page}])]))
|
||||
|
||||
|
||||
|
||||
(mf/defc workspace
|
||||
[{:keys [file-id page-id] :as props}]
|
||||
(mf/use-effect
|
||||
{:deps (mf/deps file-id)
|
||||
:fn (fn []
|
||||
(st/emit! (dw/initialize file-id))
|
||||
#(st/emit! (dw/finalize file-id)))})
|
||||
|
||||
(mf/use-effect
|
||||
{:deps (mf/deps file-id page-id)
|
||||
:fn (fn []
|
||||
(let [sub (shortcuts/init)]
|
||||
#(rx/cancel! sub)))})
|
||||
|
||||
(let [layout (mf/deref refs/workspace-layout)
|
||||
file (mf/deref refs/workspace-file)
|
||||
flags (mf/deref refs/selected-flags)]
|
||||
|
||||
;; TODO: maybe loading state?
|
||||
(when file
|
||||
[:& workspace-page {:layout layout
|
||||
:file file
|
||||
:flags flags
|
||||
:page-id page-id
|
||||
:file-id file-id}])))
|
||||
|
|
|
@ -30,10 +30,9 @@
|
|||
(mf/defc palette-item
|
||||
[{:keys [color] :as props}]
|
||||
(letfn [(select-color [event]
|
||||
(let [attrs (if (kbd/shift? event)
|
||||
{:stroke-color color}
|
||||
{:fill-color color})]
|
||||
(st/emit! (udw/update-selected-shapes-attrs attrs))))]
|
||||
(if (kbd/shift? event)
|
||||
(st/emit! (udw/update-selected-shapes :stroke-color color))
|
||||
(st/emit! (udw/update-selected-shapes :fill-color color))))]
|
||||
(let [rgb-vec (hex->rgb color)
|
||||
rgb-color (apply str "" (interpose ", " rgb-vec))]
|
||||
[:div.color-cell {:key (str color)
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
(let [event (js/MouseEvent. "click")
|
||||
link (.createElement js/document "a")
|
||||
now (dt/now)
|
||||
stream (->> (rx/from-coll (generate-files pages))
|
||||
stream (->> (rx/from (generate-files pages))
|
||||
(rx/reduce conj [])
|
||||
(rx/mapcat zip/build)
|
||||
(rx/map blob/create-uri)
|
||||
|
|
|
@ -51,8 +51,7 @@
|
|||
:fill-opacity 0
|
||||
:segments []}
|
||||
{:type :canvas
|
||||
:name "Canvas"
|
||||
:stroke-color "#000000"}
|
||||
:name "Canvas"}
|
||||
{:type :curve
|
||||
:name "Path"
|
||||
:stroke-style :solid
|
||||
|
@ -109,18 +108,17 @@
|
|||
(def handle-drawing-generic
|
||||
(letfn [(initialize-drawing [state point]
|
||||
(let [shape (get-in state [:workspace-local :drawing])
|
||||
shape (geom/setup shape {:x1 (:x point)
|
||||
:y1 (:y point)
|
||||
:x2 (+ (:x point) 2)
|
||||
:y2 (+ (:y point) 2)})]
|
||||
shape (geom/setup shape {:x (:x point)
|
||||
:y (:y point)
|
||||
:width 2
|
||||
:height 2})]
|
||||
(assoc-in state [:workspace-local :drawing] (assoc shape ::initialized? true))))
|
||||
|
||||
(resize-shape [shape point lock?]
|
||||
(let [shape (-> (geom/shape->rect-shape shape)
|
||||
(geom/size))
|
||||
result (geom/resize-shape :bottom-right shape point lock?)
|
||||
scale (geom/calculate-scale-ratio shape result)
|
||||
mtx (geom/generate-resize-matrix :bottom-right shape scale)]
|
||||
(let [shape' (geom/shape->rect-shape shape)
|
||||
result (geom/resize-shape :bottom-right shape' point lock?)
|
||||
scale (geom/calculate-scale-ratio shape' result)
|
||||
mtx (geom/generate-resize-matrix :bottom-right shape' scale)]
|
||||
(assoc shape :modifier-mtx mtx)))
|
||||
|
||||
(update-drawing [state point lock?]
|
||||
|
@ -150,13 +148,13 @@
|
|||
|
||||
(def handle-drawing-path
|
||||
(letfn [(stoper-event? [{:keys [type shift] :as event}]
|
||||
(or (= event :interrupt)
|
||||
(and (uws/mouse-event? event)
|
||||
(or (and (= type :double-click) shift)
|
||||
(= type :context-menu)))
|
||||
(and (uws/keyboard-event? event)
|
||||
(= type :down)
|
||||
(= 13 (:key event)))))
|
||||
(or (= event ::end-path-drawing)
|
||||
(and (uws/mouse-event? event)
|
||||
(or (and (= type :double-click) shift)
|
||||
(= type :context-menu)))
|
||||
(and (uws/keyboard-event? event)
|
||||
(= type :down)
|
||||
(= 13 (:key event)))))
|
||||
|
||||
(initialize-drawing [state point]
|
||||
(-> state
|
||||
|
@ -238,8 +236,7 @@
|
|||
|
||||
(def handle-drawing-curve
|
||||
(letfn [(stoper-event? [{:keys [type shift] :as event}]
|
||||
(or (= event :interrupt)
|
||||
(and (uws/mouse-event? event) (= type :up))))
|
||||
(uws/mouse-event? event) (= type :up))
|
||||
|
||||
(initialize-drawing [state]
|
||||
(assoc-in state [:workspace-local :drawing ::initialized?] true))
|
||||
|
@ -280,9 +277,11 @@
|
|||
(geom/transform shape modifier-mtx)
|
||||
shape)
|
||||
shape (dissoc shape ::initialized? :modifier-mtx)]
|
||||
;; Add & select the cred shape to the workspace
|
||||
(rx/of (dw/add-shape shape)
|
||||
dw/select-first-shape))))))))
|
||||
;; Add & select the created shape to the workspace
|
||||
(rx/of dw/deselect-all
|
||||
(if (= :canvas (:type shape))
|
||||
(dw/add-canvas shape)
|
||||
(dw/add-shape shape))))))))))
|
||||
|
||||
(def close-drawing-path
|
||||
(ptk/reify ::close-drawing-path
|
||||
|
@ -322,7 +321,8 @@
|
|||
(dom/stop-propagation event)
|
||||
(st/emit! (dw/set-tooltip nil)
|
||||
close-drawing-path
|
||||
:interrupt))
|
||||
::end-path-drawing))
|
||||
|
||||
(on-mouse-enter [event]
|
||||
(st/emit! (dw/set-tooltip "Click to close the path")))
|
||||
(on-mouse-leave [event]
|
||||
|
|
|
@ -7,23 +7,19 @@
|
|||
|
||||
(ns uxbox.main.ui.workspace.header
|
||||
(:require
|
||||
[rumext.core :as mx]
|
||||
[lentes.core :as l]
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.config :as cfg]
|
||||
[uxbox.main.data.history :as udh]
|
||||
[uxbox.main.data.pages :as udp]
|
||||
[uxbox.main.data.undo :as udu]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.ui.workspace.images :refer [import-image-modal]]
|
||||
[uxbox.main.ui.modal :as modal]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.ui.modal :as modal]
|
||||
[uxbox.main.ui.users :refer [user]]
|
||||
[uxbox.main.ui.workspace.clipboard]
|
||||
[uxbox.util.data :refer [index-of]]
|
||||
[uxbox.util.i18n :refer (tr)]
|
||||
[uxbox.util.geom.point :as gpt]
|
||||
[uxbox.main.ui.workspace.images :refer [import-image-modal]]
|
||||
[uxbox.util.i18n :refer [tr]]
|
||||
[uxbox.util.math :as mth]
|
||||
[uxbox.util.router :as rt]))
|
||||
|
||||
|
@ -40,100 +36,154 @@
|
|||
[:span {} (str (mth/round (* 100 zoom)) "%")]
|
||||
[:span.remove-zoom {:on-click increase} "+"]]]))
|
||||
|
||||
;; --- Header Users
|
||||
|
||||
(mf/defc user-widget
|
||||
[{:keys [user self?] :as props}]
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (:fullname user)
|
||||
:on-click (when self?
|
||||
#(st/emit! (rt/navigate :settings/profile)))}
|
||||
[:img {:style {:border-color (:color user)}
|
||||
:src (if self? "/images/avatar.jpg" "/images/avatar-red.jpg")}]])
|
||||
|
||||
(mf/defc active-users
|
||||
[props]
|
||||
(let [profile (mf/deref refs/profile)
|
||||
users (mf/deref refs/workspace-users)]
|
||||
[:ul.user-multi
|
||||
[:& user-widget {:user profile :self? true}]
|
||||
(for [id (->> (:active users)
|
||||
(remove #(= % (:id profile))))]
|
||||
[:& user-widget {:user (get-in users [:by-id id])
|
||||
:key id}])]))
|
||||
|
||||
;; --- Header Component
|
||||
|
||||
(mf/defc header
|
||||
[{:keys [page layout flags] :as props}]
|
||||
(let [toggle #(st/emit! (dw/toggle-flag %))
|
||||
toggle-layout #(st/emit! (dw/toggle-layout-flag %))
|
||||
on-undo #(st/emit! (udu/undo))
|
||||
on-redo #(st/emit! (udu/redo))
|
||||
on-image #(modal/show! import-image-modal {})
|
||||
;;on-download #(udl/open! :download)
|
||||
]
|
||||
file (mf/deref refs/workspace-file)
|
||||
selected-drawtool (mf/deref refs/selected-drawing-tool)
|
||||
select-drawtool #(st/emit! :interrupt
|
||||
(dw/deactivate-ruler)
|
||||
(dw/select-for-drawing %))]
|
||||
|
||||
[:header#workspace-bar.workspace-bar
|
||||
[:div.main-icon
|
||||
[:a {:on-click #(st/emit! (rt/nav :dashboard-projects))} i/logo-icon]]
|
||||
|
||||
[:div.project-tree-btn
|
||||
{:alt (tr "header.sitemap")
|
||||
:class (when (contains? layout :sitemap) "selected")
|
||||
:on-click #(st/emit! (dw/toggle-layout-flag :sitemap))}
|
||||
i/project-tree
|
||||
[:span {} (:name page)]]
|
||||
[:span (:project-name file) " / " (:name file)]]
|
||||
|
||||
[:& active-users]
|
||||
|
||||
[:div.workspace-options
|
||||
[:ul.options-btn
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (tr "header.draw-tools")
|
||||
:class (when (contains? layout :drawtools) "selected")
|
||||
:on-click #(st/emit! (dw/toggle-layout-flag :drawtools))}
|
||||
i/shapes]
|
||||
{:alt (tr "workspace.header.canvas")
|
||||
:class (when (= selected-drawtool :canvas) "selected")
|
||||
:on-click (partial select-drawtool :canvas)}
|
||||
i/artboard]
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (tr "header.color-palette")
|
||||
{:alt (tr "workspace.header.rect")
|
||||
:class (when (= selected-drawtool :rect) "selected")
|
||||
:on-click (partial select-drawtool :rect)}
|
||||
i/box]
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (tr "workspace.header.circle")
|
||||
:class (when (= selected-drawtool :circle) "selected")
|
||||
:on-click (partial select-drawtool :circle)}
|
||||
i/circle]
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (tr "workspace.header.text")
|
||||
:class (when (= selected-drawtool :text) "selected")
|
||||
:on-click (partial select-drawtool :text)}
|
||||
i/text]
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (tr "workspace.header.path")
|
||||
:class (when (= selected-drawtool :path) "selected")
|
||||
:on-click (partial select-drawtool :path)}
|
||||
i/curve]
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (tr "workspace.header.curve")
|
||||
:class (when (= selected-drawtool :curve) "selected")
|
||||
:on-click (partial select-drawtool :curve)}
|
||||
i/pencil]
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (tr "workspace.header.color-palette")
|
||||
:class (when (contains? layout :colorpalette) "selected")
|
||||
:on-click #(st/emit! (dw/toggle-layout-flag :colorpalette))}
|
||||
i/palette]
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (tr "header.icons")
|
||||
{:alt (tr "workspace.header.icons")
|
||||
:class (when (contains? layout :icons) "selected")
|
||||
:on-click #(st/emit! (dw/toggle-layout-flag :icons))}
|
||||
i/icon-set]
|
||||
;; [:li.tooltip.tooltip-bottom
|
||||
;; {:alt (tr "header.layers")
|
||||
;; :class (when (contains? layout :layers) "selected")
|
||||
;; :on-click #(st/emit! (dw/toggle-layout-flag :layers))}
|
||||
;; i/layers]
|
||||
;; [:li.tooltip.tooltip-bottom
|
||||
;; {:alt (tr "header.element-options")
|
||||
;; :class (when (contains? layout :element-options) "selected")
|
||||
;; :on-click #(st/emit! (dw/toggle-layout-flag :element-options))}
|
||||
;; i/options]
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (tr "header.layers")
|
||||
:class (when (contains? layout :layers) "selected")
|
||||
:on-click #(st/emit! (dw/toggle-layout-flag :layers))}
|
||||
i/layers]
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (tr "header.element-options")
|
||||
:class (when (contains? layout :element-options) "selected")
|
||||
:on-click #(st/emit! (dw/toggle-layout-flag :element-options))}
|
||||
i/options]
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (tr "header.document-history")
|
||||
{:alt (tr "workspace.header.document-history")
|
||||
:class (when (contains? layout :document-history) "selected")
|
||||
:on-click #(st/emit! (dw/toggle-layout-flag :document-history))}
|
||||
i/undo-history]]
|
||||
[:ul.options-btn
|
||||
i/undo-history]
|
||||
;; [:li.tooltip.tooltip-bottom
|
||||
;; {:alt (tr "header.undo")
|
||||
;; :on-click on-undo}
|
||||
;; i/undo]
|
||||
;; [:li.tooltip.tooltip-bottom
|
||||
;; {:alt (tr "header.redo")
|
||||
;; :on-click on-redo}
|
||||
;; i/redo]
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (tr "header.undo")
|
||||
:on-click on-undo}
|
||||
i/undo]
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (tr "header.redo")
|
||||
:on-click on-redo}
|
||||
i/redo]]
|
||||
[:ul.options-btn
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (tr "header.download")
|
||||
{:alt (tr "workspace.header.download")
|
||||
;; :on-click on-download
|
||||
}
|
||||
i/download]
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (tr "header.image")
|
||||
{:alt (tr "workspace.header.image")
|
||||
:on-click on-image}
|
||||
i/image]]
|
||||
[:ul.options-btn
|
||||
i/image]
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (tr "header.rules")
|
||||
:class (when (contains? flags :rules) "selected")
|
||||
:on-click (partial toggle :rules)}
|
||||
{:alt (tr "workspace.header.rules")
|
||||
:class (when (contains? layout :rules) "selected")
|
||||
:on-click (partial toggle-layout :rules)}
|
||||
i/ruler]
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (tr "header.grid")
|
||||
{:alt (tr "workspace.header.grid")
|
||||
:class (when (contains? flags :grid) "selected")
|
||||
:on-click (partial toggle :grid)}
|
||||
i/grid]
|
||||
[:li.tooltip.tooltip-bottom
|
||||
{:alt (tr "header.grid-snap")
|
||||
{:alt (tr "workspace.header.grid-snap")
|
||||
:class (when (contains? flags :grid-snap) "selected")
|
||||
:on-click (partial toggle :grid-snap)}
|
||||
i/grid-snap]]
|
||||
;; [:li.tooltip.tooltip-bottom
|
||||
;; {:alt (tr "header.align")}
|
||||
;; i/alignment]]
|
||||
[:ul.options-btn
|
||||
[:li.tooltip.tooltip-bottom.view-mode
|
||||
{:alt (tr "header.view-mode")
|
||||
i/grid-snap]]]
|
||||
;; [:li.tooltip.tooltip-bottom
|
||||
;; {:alt (tr "header.align")}
|
||||
;; i/alignment]]
|
||||
;; [:& user]
|
||||
[:div.secondary-options
|
||||
[:& zoom-widget]
|
||||
[:a.tooltip.tooltip-bottom.view-mode
|
||||
{:alt (tr "workspace.header.view-mode")
|
||||
;; :on-click #(st/emit! (dw/->OpenView (:id page)))
|
||||
}
|
||||
i/play]]
|
||||
[:& zoom-widget]]
|
||||
[:& user]]))
|
||||
i/play]]
|
||||
]))
|
||||
|
|
|
@ -129,13 +129,9 @@
|
|||
(read-string)
|
||||
(swap! local assoc :id))]
|
||||
|
||||
(mf/use-effect
|
||||
{:fn #(do (st/emit! (udi/fetch-collections))
|
||||
(st/emit! (udi/fetch-images nil)))})
|
||||
|
||||
(mf/use-effect
|
||||
{:deps #js [type id]
|
||||
:fn #(st/emit! (udi/fetch-images id))})
|
||||
(mf/use-effect #(st/emit! udi/fetch-collections))
|
||||
(mf/use-effect {:deps #js [(str id)]
|
||||
:fn #(st/emit! (udi/fetch-images id))})
|
||||
|
||||
[:div.lightbox-body.big-lightbox
|
||||
[:h3 (tr "image.import-library")]
|
||||
|
|
|
@ -26,10 +26,10 @@
|
|||
(def ^:private +circle-props+
|
||||
{:r 6
|
||||
:style {:fillOpacity "1"
|
||||
:strokeWidth "1px"
|
||||
:strokeWidth "2px"
|
||||
:vectorEffect "non-scaling-stroke"}
|
||||
:fill "#31e6e0"
|
||||
:stroke "#28c4d4"})
|
||||
:fill "rgba(49,239,184,.7)"
|
||||
:stroke "#31EFB8"})
|
||||
|
||||
;; --- Resize Implementation
|
||||
|
||||
|
@ -90,63 +90,63 @@
|
|||
:on-mouse-down on-click
|
||||
:r r
|
||||
:style {:fillOpacity "1"
|
||||
:strokeWidth "1px"
|
||||
:strokeWidth "2px"
|
||||
:vectorEffect "non-scaling-stroke"}
|
||||
:fill "#31e6e0"
|
||||
:stroke "#28c4d4"
|
||||
:fill "rgba(49,239,184,.7)"
|
||||
:stroke "#31EFB8"
|
||||
:cx cx
|
||||
:cy cy}])
|
||||
|
||||
(mf/defc controls
|
||||
[{:keys [shape zoom on-click] :as props}]
|
||||
(let [{:keys [x1 y1 width height]} shape
|
||||
(let [{:keys [x y width height]} shape
|
||||
radius (if (> (max width height) handler-size-threshold) 6.0 4.0)]
|
||||
[:g.controls
|
||||
[:rect.main {:x x1 :y y1
|
||||
[:rect.main {:x x :y y
|
||||
:width width
|
||||
:height height
|
||||
:stroke-dasharray (str (/ 5.0 zoom) "," (/ 5 zoom))
|
||||
:style {:stroke "#333" :fill "transparent"
|
||||
:stroke-dasharray (str (/ 8.0 zoom) "," (/ 5 zoom))
|
||||
:style {:stroke "#31EFB8" :fill "transparent"
|
||||
:stroke-opacity "1"}}]
|
||||
[:& control-item {:class "top"
|
||||
:on-click #(on-click :top %)
|
||||
:r (/ radius zoom)
|
||||
:cx (+ x1 (/ width 2))
|
||||
:cy (- y1 2)}]
|
||||
:cx (+ x (/ width 2))
|
||||
:cy (- y 2)}]
|
||||
[:& control-item {:on-click #(on-click :right %)
|
||||
:r (/ radius zoom)
|
||||
:cy (+ y1 (/ height 2))
|
||||
:cx (+ x1 width 1)
|
||||
:cy (+ y (/ height 2))
|
||||
:cx (+ x width 1)
|
||||
:class "right"}]
|
||||
[:& control-item {:on-click #(on-click :bottom %)
|
||||
:r (/ radius zoom)
|
||||
:cx (+ x1 (/ width 2))
|
||||
:cy (+ y1 height 2)
|
||||
:cx (+ x (/ width 2))
|
||||
:cy (+ y height 2)
|
||||
:class "bottom"}]
|
||||
[:& control-item {:on-click #(on-click :left %)
|
||||
:r (/ radius zoom)
|
||||
:cy (+ y1 (/ height 2))
|
||||
:cx (- x1 3)
|
||||
:cy (+ y (/ height 2))
|
||||
:cx (- x 3)
|
||||
:class "left"}]
|
||||
[:& control-item {:on-click #(on-click :top-left %)
|
||||
:r (/ radius zoom)
|
||||
:cx x1
|
||||
:cy y1
|
||||
:cx x
|
||||
:cy y
|
||||
:class "top-left"}]
|
||||
[:& control-item {:on-click #(on-click :top-right %)
|
||||
:r (/ radius zoom)
|
||||
:cx (+ x1 width)
|
||||
:cy y1
|
||||
:cx (+ x width)
|
||||
:cy y
|
||||
:class "top-right"}]
|
||||
[:& control-item {:on-click #(on-click :bottom-left %)
|
||||
:r (/ radius zoom)
|
||||
:cx x1
|
||||
:cy (+ y1 height)
|
||||
:cx x
|
||||
:cy (+ y height)
|
||||
:class "bottom-left"}]
|
||||
[:& control-item {:on-click #(on-click :bottom-right %)
|
||||
:r (/ radius zoom)
|
||||
:cx (+ x1 width)
|
||||
:cy (+ y1 height)
|
||||
:cx (+ x width)
|
||||
:cy (+ y height)
|
||||
:class "bottom-right"}]]))
|
||||
|
||||
;; --- Selection Handlers (Component)
|
||||
|
@ -183,8 +183,8 @@
|
|||
:r (/ 6.0 zoom)
|
||||
:key index
|
||||
:on-mouse-down #(on-mouse-down % index)
|
||||
:fill "#31e6e0"
|
||||
:stroke "#28c4d4"
|
||||
:fill "rgba(49,239,184,.7)"
|
||||
:stroke "#31EFB8"
|
||||
:style {:cursor "pointer"}}])])))
|
||||
|
||||
;; TODO: add specs for clarity
|
||||
|
@ -203,15 +203,15 @@
|
|||
|
||||
(mf/defc text-edition-selection-handlers
|
||||
[{:keys [shape zoom] :as props}]
|
||||
(let [{:keys [x1 y1 width height] :as shape} (geom/selection-rect shape)]
|
||||
(let [{:keys [x y width height] :as shape} (geom/selection-rect shape)]
|
||||
[:g.controls
|
||||
[:rect.main {:x x1 :y y1
|
||||
[:rect.main {:x x :y y
|
||||
:width width
|
||||
:height height
|
||||
;; :stroke-dasharray (str (/ 5.0 zoom) "," (/ 5 zoom))
|
||||
:style {:stroke "#333"
|
||||
:style {:stroke "#31EFB8"
|
||||
:stroke-width "0.5"
|
||||
:stroke-opacity "0.5"
|
||||
:stroke-opacity "1"
|
||||
:fill "transparent"}}]]))
|
||||
|
||||
(mf/defc single-selection-handlers
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
:ctrl+b #(st/emit! (dw/select-for-drawing :rect))
|
||||
:ctrl+e #(st/emit! (dw/select-for-drawing :circle))
|
||||
:ctrl+t #(st/emit! (dw/select-for-drawing :text))
|
||||
:esc #(st/emit! dw/deselect-all)
|
||||
:esc #(st/emit! :interrupt dw/deselect-all)
|
||||
:delete #(st/emit! dw/delete-selected)
|
||||
:ctrl+up #(st/emit! (dw/order-selected-shapes :up))
|
||||
:ctrl+down #(st/emit! (dw/order-selected-shapes :down))
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
(ns uxbox.main.ui.workspace.sidebar
|
||||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.main.ui.workspace.sidebar.drawtools :refer [draw-toolbox]]
|
||||
[uxbox.main.ui.workspace.sidebar.history :refer [history-toolbox]]
|
||||
[uxbox.main.ui.workspace.sidebar.icons :refer [icons-toolbox]]
|
||||
[uxbox.main.ui.workspace.sidebar.layers :refer [layers-toolbox]]
|
||||
|
@ -36,8 +35,6 @@
|
|||
[{:keys [layout page] :as props}]
|
||||
[:aside#settings-bar.settings-bar
|
||||
[:div.settings-bar-inside
|
||||
(when (contains? layout :drawtools)
|
||||
[:& draw-toolbox {:layout layout}])
|
||||
(when (contains? layout :element-options)
|
||||
[:& options-toolbox {:page page}])
|
||||
#_(when (contains? layout :icons)
|
||||
|
|
|
@ -1,85 +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 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
||||
;; Copyright (c) 2015-2019 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.main.ui.workspace.sidebar.drawtools
|
||||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.util.i18n :refer [tr]]
|
||||
[uxbox.util.uuid :as uuid]))
|
||||
|
||||
;; --- Constants
|
||||
|
||||
(def +draw-tools+
|
||||
[{:icon i/box
|
||||
:help "ds.help.rect"
|
||||
:type :rect
|
||||
:priority 1}
|
||||
{:icon i/circle
|
||||
:help "ds.help.circle"
|
||||
:type :circle
|
||||
:priority 2}
|
||||
{:icon i/text
|
||||
:help "ds.help.text"
|
||||
:type :text
|
||||
:priority 4}
|
||||
{:icon i/curve
|
||||
:help "ds.help.path"
|
||||
:type :path
|
||||
:priority 5}
|
||||
{:icon i/pencil
|
||||
:help "ds.help.curve"
|
||||
:type :curve
|
||||
:priority 6}
|
||||
;; TODO: we need an icon for canvas creation
|
||||
{:icon i/box
|
||||
:help "ds.help.canvas"
|
||||
:type :canvas
|
||||
:priority 7}])
|
||||
|
||||
;; --- Draw Toolbox (Component)
|
||||
|
||||
(mf/defc draw-toolbox
|
||||
{:wrap [mf/wrap-memo]}
|
||||
[{:keys [flags] :as props}]
|
||||
(letfn [(close [event]
|
||||
(st/emit! (dw/toggle-layout-flag :drawtools)))
|
||||
(select [event tool]
|
||||
(st/emit! :interrupt
|
||||
(dw/deactivate-ruler)
|
||||
(dw/select-for-drawing tool)))
|
||||
(toggle-ruler [event]
|
||||
(st/emit! (dw/select-for-drawing nil)
|
||||
dw/deselect-all
|
||||
(dw/toggle-ruler)))]
|
||||
|
||||
(let [selected (mf/deref refs/selected-drawing-tool)
|
||||
tools (sort-by (comp :priority second) +draw-tools+)]
|
||||
[:div.tool-window.drawing-tools
|
||||
[:div.tool-window-bar
|
||||
[:div.tool-window-icon i/window]
|
||||
[:span (tr "ds.settings.draw-tools")]
|
||||
[:div.tool-window-close {:on-click close} i/close]]
|
||||
[:div.tool-window-content
|
||||
(for [item tools]
|
||||
(let [selected? (= (:type item) selected)]
|
||||
[:div.tool-btn.tooltip.tooltip-hover
|
||||
{:alt (tr (:help item))
|
||||
:class (when selected? "selected")
|
||||
:key (:type item)
|
||||
:on-click #(select % (:type item))}
|
||||
(:icon item)]))
|
||||
|
||||
#_[:div.tool-btn.tooltip.tooltip-hover
|
||||
{:alt (tr "ds.help.ruler")
|
||||
:on-click toggle-ruler
|
||||
:class (when (contains? flags :ruler) "selected")}
|
||||
i/ruler-tool]]])))
|
||||
|
|
@ -10,7 +10,6 @@
|
|||
[rumext.alpha :as mf]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.data.history :as udh]
|
||||
[uxbox.main.data.pages :as udp]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
[lentes.core :as l]
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.data.pages :as udp]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
|
@ -206,7 +205,7 @@
|
|||
:class (when-not collapsed? "inverse")}
|
||||
i/arrow-slide]]
|
||||
[:ul
|
||||
(for [[index shape] shapes]
|
||||
(for [[index shape] (reverse shapes)]
|
||||
[:& layer-item {:shape shape
|
||||
:selected selected
|
||||
:index index
|
||||
|
@ -260,7 +259,8 @@
|
|||
[:div.tool-window-bar
|
||||
[:div.tool-window-icon i/layers]
|
||||
[:span (tr "ds.settings.layers")]
|
||||
[:div.tool-window-close {:on-click on-click} i/close]]
|
||||
;; [:div.tool-window-close {:on-click on-click} i/close]
|
||||
]
|
||||
[:div.tool-window-content
|
||||
[:& canvas-list {:canvas canvas
|
||||
:shapes all-shapes
|
||||
|
|
|
@ -9,103 +9,44 @@
|
|||
(:require
|
||||
[lentes.core :as l]
|
||||
[rumext.alpha :as mf]
|
||||
[rumext.core :as mx]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.geom :as geom]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.ui.shapes.attrs :refer [shape-default-attrs]]
|
||||
[uxbox.main.ui.workspace.sidebar.options.circle-measures :as options-circlem]
|
||||
[uxbox.main.ui.workspace.sidebar.options.fill :as options-fill]
|
||||
[uxbox.main.ui.workspace.sidebar.options.icon-measures :as options-iconm]
|
||||
[uxbox.main.ui.workspace.sidebar.options.image-measures :as options-imagem]
|
||||
[uxbox.main.ui.workspace.sidebar.options.interactions :as options-interactions]
|
||||
[uxbox.main.ui.workspace.sidebar.options.page :as options-page]
|
||||
[uxbox.main.ui.workspace.sidebar.options.rect-measures :as options-rectm]
|
||||
[uxbox.main.ui.workspace.sidebar.options.stroke :as options-stroke]
|
||||
[uxbox.main.ui.workspace.sidebar.options.text :as options-text]
|
||||
[uxbox.util.data :as data]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.main.ui.workspace.sidebar.options.rect :as rect]
|
||||
[uxbox.main.ui.workspace.sidebar.options.circle :as circle]
|
||||
[uxbox.main.ui.workspace.sidebar.options.path :as path]
|
||||
[uxbox.main.ui.workspace.sidebar.options.image :as image]
|
||||
[uxbox.main.ui.workspace.sidebar.options.page :as page]
|
||||
[uxbox.util.i18n :refer [tr]]))
|
||||
|
||||
;; --- Constants
|
||||
|
||||
(def ^:private +menus-map+
|
||||
{:icon [::icon-measures ::fill ::stroke]
|
||||
:rect [::rect-measures ::fill ::stroke]
|
||||
:path [::fill ::stroke ::interactions]
|
||||
:circle [::circle-measures ::fill ::stroke]
|
||||
:text [::fill ::text]
|
||||
:image [::image-measures]
|
||||
::page [::page-measures ::page-grid-options]})
|
||||
|
||||
(def ^:private +menus+
|
||||
[{:name "element.measures"
|
||||
:id ::icon-measures
|
||||
:icon i/infocard
|
||||
:comp options-iconm/icon-measures-menu}
|
||||
{:name "element.measures"
|
||||
:id ::image-measures
|
||||
:icon i/infocard
|
||||
:comp options-imagem/image-measures-menu}
|
||||
{:name "element.measures"
|
||||
:id ::rect-measures
|
||||
:icon i/infocard
|
||||
:comp options-rectm/rect-measures-menu}
|
||||
{:name "element.measures"
|
||||
:id ::circle-measures
|
||||
:icon i/infocard
|
||||
:comp options-circlem/circle-measures-menu}
|
||||
{:name "element.fill"
|
||||
:id ::fill
|
||||
:icon i/fill
|
||||
:comp options-fill/fill-menu}
|
||||
{:name "element.stroke"
|
||||
:id ::stroke
|
||||
:icon i/stroke
|
||||
:comp options-stroke/stroke-menu}
|
||||
{:name "element.text"
|
||||
:id ::text
|
||||
:icon i/text
|
||||
:comp options-text/text-menu}
|
||||
{:name "element.interactions"
|
||||
:id ::interactions
|
||||
:icon i/action
|
||||
:comp options-interactions/interactions-menu}
|
||||
{:name "element.page-measures"
|
||||
:id ::page-measures
|
||||
:icon i/page
|
||||
:comp options-page/measures-menu}
|
||||
{:name "element.page-grid-options"
|
||||
:id ::page-grid-options
|
||||
:icon i/grid
|
||||
:comp options-page/grid-options-menu}])
|
||||
|
||||
(def ^:private +menus-by-id+
|
||||
(data/index-by-id +menus+))
|
||||
;; (def ^:private +menus-map+
|
||||
;; {:icon [::icon-measures ::fill ::stroke]
|
||||
;; :rect [::rect-measures ::fill ::stroke]
|
||||
;; :path [::fill ::stroke ::interactions]
|
||||
;; :circle [::circle-measures ::fill ::stroke]
|
||||
;; :text [::fill ::text]
|
||||
;; :image [::image-measures]
|
||||
;; ::page [::page-measures ::page-grid-options]})
|
||||
|
||||
;; --- Options
|
||||
|
||||
(mf/defc shape-options
|
||||
[{:keys [shape-id] :as props}]
|
||||
(let [shape-iref (mf/use-memo {:deps #js [shape-id]
|
||||
(let [shape-iref (mf/use-memo {:deps #js [(str shape-id)]
|
||||
:fn #(-> (l/in [:workspace-data :shapes-by-id shape-id])
|
||||
(l/derive st/state))})
|
||||
shape (mf/deref shape-iref)
|
||||
menus (get +menus-map+ (:type shape))]
|
||||
shape (mf/deref shape-iref)]
|
||||
[:div
|
||||
(for [mid menus]
|
||||
(let [{:keys [comp] :as menu} (get +menus-by-id+ mid)]
|
||||
[:& comp {:menu menu :shape shape :key mid}]))]))
|
||||
|
||||
(mf/defc page-options
|
||||
[{:keys [page] :as props}]
|
||||
(let [menus (get +menus-map+ ::page)]
|
||||
[:div
|
||||
(for [mid menus]
|
||||
(let [{:keys [comp] :as menu} (get +menus-by-id+ mid)]
|
||||
[:& comp {:menu menu :page page :key mid}]))]))
|
||||
(case (:type shape)
|
||||
:rect [:& rect/options {:shape shape}]
|
||||
:circle [:& circle/options {:shape shape}]
|
||||
:path [:& path/options {:shape shape}]
|
||||
:curve [:& path/options {:shape shape}]
|
||||
:image [:& image/options {:shape shape}]
|
||||
nil)]))
|
||||
|
||||
(mf/defc options-toolbox
|
||||
{:wrap [mf/wrap-memo]}
|
||||
|
@ -113,12 +54,12 @@
|
|||
(let [close #(st/emit! (udw/toggle-layout-flag :element-options))
|
||||
selected (mf/deref refs/selected-shapes)]
|
||||
[:div.elementa-options.tool-window
|
||||
[:div.tool-window-bar
|
||||
[:div.tool-window-icon i/options]
|
||||
[:span (tr "ds.settings.element-options")]
|
||||
[:div.tool-window-close {:on-click close} i/close]]
|
||||
;; [:div.tool-window-bar
|
||||
;; [:div.tool-window-icon i/options]
|
||||
;; [:span (tr "ds.settings.element-options")]
|
||||
;; [:div.tool-window-close {:on-click close} i/close]]
|
||||
[:div.tool-window-content
|
||||
[:div.element-options
|
||||
(if (= (count selected) 1)
|
||||
[:& shape-options {:shape-id (first selected)}]
|
||||
[:& page-options {:page page}])]]]))
|
||||
[:& page/options {:page page}])]]]))
|
||||
|
|
132
frontend/src/uxbox/main/ui/workspace/sidebar/options/circle.cljs
Normal file
132
frontend/src/uxbox/main/ui/workspace/sidebar/options/circle.cljs
Normal file
|
@ -0,0 +1,132 @@
|
|||
;; 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 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
||||
;; Copyright (c) 2015-2019 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.main.ui.workspace.sidebar.options.circle
|
||||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.common.data :as d]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.geom :as geom]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-menu]]
|
||||
[uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-menu]]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.geom.point :as gpt]
|
||||
[uxbox.util.i18n :refer [tr]]
|
||||
[uxbox.util.math :as math :refer (precision-or-0)]))
|
||||
|
||||
(mf/defc measures-menu
|
||||
[{:keys [shape] :as props}]
|
||||
(let [on-size-change
|
||||
(fn [event attr]
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(d/parse-integer 0))]
|
||||
(st/emit! (udw/update-dimensions (:id shape) {attr value}))))
|
||||
|
||||
on-proportion-lock-change
|
||||
(fn [event]
|
||||
(st/emit! (udw/toggle-shape-proportion-lock (:id shape))))
|
||||
|
||||
on-size-rx-change #(on-size-change % :rx)
|
||||
on-size-ry-change #(on-size-change % :ry)
|
||||
|
||||
on-position-change
|
||||
(fn [event attr]
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(d/parse-integer))
|
||||
point (gpt/point {attr value})]
|
||||
(st/emit! (udw/update-position (:id shape) point))))
|
||||
|
||||
on-pos-cx-change #(on-position-change % :x)
|
||||
on-pos-cy-change #(on-position-change % :y)
|
||||
|
||||
on-rotation-change
|
||||
(fn [event]
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(d/parse-integer 0))]
|
||||
(st/emit! (udw/update-shape (:id shape) {:rotation value}))))
|
||||
|
||||
on-radius-change
|
||||
(fn [event]
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(d/parse-double 0))]
|
||||
(st/emit! (udw/update-shape (:id shape) {:rx value :ry value}))))]
|
||||
|
||||
[:div.element-set
|
||||
[:div.element-set-title (tr "workspace.options.measures")]
|
||||
[:div.element-set-content
|
||||
|
||||
;; SIZE
|
||||
[:span (tr "workspace.options.size")]
|
||||
[:div.row-flex
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text {:type "number"
|
||||
:min "0"
|
||||
:on-change on-size-rx-change
|
||||
:value (-> (:rx shape)
|
||||
(math/precision 2)
|
||||
(d/coalesce-str "0"))}]]
|
||||
[:div.lock-size {:class (when (:proportion-lock shape) "selected")
|
||||
:on-click on-proportion-lock-change}
|
||||
(if (:proportion-lock shape)
|
||||
i/lock
|
||||
i/unlock)]
|
||||
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text {:type "number"
|
||||
:min "0"
|
||||
:on-change on-size-ry-change
|
||||
:value (-> (:ry shape)
|
||||
(math/precision 2)
|
||||
(d/coalesce-str "0"))}]]]
|
||||
|
||||
;; POSITION
|
||||
[:span (tr "workspace.options.position")]
|
||||
[:div.row-flex
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text {:type "number"
|
||||
:on-change on-pos-cx-change
|
||||
:value (-> (:cx shape)
|
||||
(math/precision 2)
|
||||
(d/coalesce-str "0"))}]]
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text {:type "number"
|
||||
:on-change on-pos-cy-change
|
||||
:value (-> (:cy shape)
|
||||
(math/precision 2)
|
||||
(d/coalesce-str "0"))}]]]
|
||||
;; ROTATION & RADIUS
|
||||
[:span (tr "workspace.options.rotation-radius")]
|
||||
[:div.row-flex
|
||||
[:div.input-element.degrees
|
||||
[:input.input-text {:placeholder ""
|
||||
:type "number"
|
||||
:min 0
|
||||
:max 360
|
||||
:on-change on-rotation-change
|
||||
:value (-> (:rotation shape)
|
||||
(math/precision 2)
|
||||
(d/coalesce-str "0"))}]]
|
||||
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text {:type "number"
|
||||
:on-change on-radius-change
|
||||
:value (-> (:rx shape)
|
||||
(math/precision 2)
|
||||
(d/coalesce-str "0"))}]]]]]))
|
||||
|
||||
(mf/defc options
|
||||
[{:keys [shape] :as props}]
|
||||
[:div
|
||||
[:& measures-menu {:shape shape}]
|
||||
[:& fill-menu {:shape shape}]
|
||||
[:& stroke-menu {:shape shape}]])
|
|
@ -1,117 +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 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
||||
;; Copyright (c) 2015-2019 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.main.ui.workspace.sidebar.options.circle-measures
|
||||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.geom :as geom]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.util.data :refer (parse-int parse-float read-string)]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.geom.point :as gpt]
|
||||
[uxbox.util.i18n :refer (tr)]
|
||||
[uxbox.util.math :refer (precision-or-0)]))
|
||||
|
||||
(declare on-size-change)
|
||||
(declare on-rotation-change)
|
||||
(declare on-position-change)
|
||||
(declare on-proportion-lock-change)
|
||||
|
||||
(mf/defc circle-measures-menu
|
||||
[{:keys [menu shape] :as props}]
|
||||
[:div.element-set {:key (str (:id menu))}
|
||||
[:div.element-set-title (:name menu)]
|
||||
[:div.element-set-content
|
||||
;; SLIDEBAR FOR ROTATION AND OPACITY
|
||||
[:span (tr "ds.size")]
|
||||
[:div.row-flex
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:placeholder (tr "ds.width")
|
||||
:type "number"
|
||||
:min "0"
|
||||
:value (precision-or-0 (:rx shape 0) 2)
|
||||
:on-change #(on-size-change % shape :rx)}]]
|
||||
[:div.lock-size {:class (when (:proportion-lock shape) "selected")
|
||||
:on-click #(on-proportion-lock-change % shape)}
|
||||
(if (:proportion-lock shape) i/lock i/unlock)]
|
||||
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:placeholder (tr "ds.height")
|
||||
:type "number"
|
||||
:min "0"
|
||||
:value (precision-or-0 (:ry shape 0) 2)
|
||||
:on-change #(on-size-change % shape :ry)}]]]
|
||||
|
||||
[:span (tr "ds.position")]
|
||||
[:div.row-flex
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:placeholder "cx"
|
||||
:type "number"
|
||||
:value (precision-or-0 (:cx shape 0) 2)
|
||||
:on-change #(on-position-change % shape :x)}]]
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:placeholder "cy"
|
||||
:type "number"
|
||||
:value (precision-or-0 (:cy shape 0) 2)
|
||||
:on-change #(on-position-change % shape :y)}]]]
|
||||
|
||||
[:span (tr "ds.rotation")]
|
||||
[:div.row-flex
|
||||
[:input.slidebar
|
||||
{:type "range"
|
||||
:min 0
|
||||
:max 360
|
||||
:value (:rotation shape 0)
|
||||
:on-change #(on-rotation-change % shape)}]]
|
||||
|
||||
[:div.row-flex
|
||||
[:div.input-element.degrees
|
||||
[:input.input-text
|
||||
{:placeholder ""
|
||||
:type "number"
|
||||
:min 0
|
||||
:max 360
|
||||
:value (precision-or-0 (:rotation shape 0) 2)
|
||||
:on-change #(on-rotation-change % shape)}]]
|
||||
[:input.input-text
|
||||
{:style {:visibility "hidden"}}]]]])
|
||||
|
||||
(defn- on-size-change
|
||||
[event shape attr]
|
||||
(let [value (dom/event->value event)
|
||||
value (parse-int value 0)
|
||||
sid (:id shape)
|
||||
props {attr value}]
|
||||
(st/emit! (udw/update-dimensions sid props))))
|
||||
|
||||
(defn- on-rotation-change
|
||||
[event shape]
|
||||
(let [value (dom/event->value event)
|
||||
value (parse-int value 0)
|
||||
sid (:id shape)]
|
||||
(st/emit! (udw/update-shape-attrs sid {:rotation value}))))
|
||||
|
||||
(defn- on-position-change
|
||||
[event shape attr]
|
||||
(let [value (dom/event->value event)
|
||||
value (parse-int value nil)
|
||||
sid (:id shape)
|
||||
point (gpt/point {attr value})]
|
||||
(st/emit! (udw/update-position sid point))))
|
||||
|
||||
(defn- on-proportion-lock-change
|
||||
[event shape]
|
||||
(if (:proportion-lock shape)
|
||||
(st/emit! (udw/unlock-proportions (:id shape)))
|
||||
(st/emit! (udw/lock-proportions (:id shape)))))
|
||||
|
|
@ -9,43 +9,45 @@
|
|||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.common.data :as d]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.ui.modal :as modal]
|
||||
[uxbox.main.ui.workspace.colorpicker :refer [colorpicker-modal]]
|
||||
[uxbox.util.data :refer [parse-float]]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.i18n :refer [tr]]))
|
||||
|
||||
(mf/defc fill-menu
|
||||
[{:keys [menu shape]}]
|
||||
(letfn [(change-attrs [attrs]
|
||||
(st/emit! (udw/update-shape-attrs (:id shape) attrs)))
|
||||
[{:keys [shape] :as props}]
|
||||
(letfn [(update-shape! [attr value]
|
||||
(st/emit! (udw/update-shape (:id shape) {attr value})))
|
||||
(on-color-change [event]
|
||||
(let [value (dom/event->value event)]
|
||||
(change-attrs {:fill-color value})))
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value))]
|
||||
(update-shape! :fill-color value)))
|
||||
(on-opacity-change [event]
|
||||
(let [value (dom/event->value event)
|
||||
value (parse-float value 1)
|
||||
value (/ value 10000)]
|
||||
(change-attrs {:fill-opacity value})))
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(d/parse-double 1)
|
||||
(/ 10000))]
|
||||
(update-shape! :fill-opacity value)))
|
||||
(show-color-picker [event]
|
||||
(let [x (.-clientX event)
|
||||
y (.-clientY event)
|
||||
props {:x x :y y
|
||||
:on-change #(change-attrs {:fill-color %})
|
||||
:on-change #(update-shape! :fill-color %)
|
||||
:default "#ffffff"
|
||||
:value (:fill-color shape)
|
||||
:transparent? true}]
|
||||
(modal/show! colorpicker-modal props)))]
|
||||
[:div.element-set
|
||||
[:div.element-set-title (:name menu)]
|
||||
[:div.element-set-title (tr "element.fill")]
|
||||
[:div.element-set-content
|
||||
|
||||
[:span (tr "ds.color")]
|
||||
[:span (tr "workspace.options.color")]
|
||||
[:div.row-flex.color-data
|
||||
[:span.color-th
|
||||
{:style {:background-color (:fill-color shape)}
|
||||
{:style {:background-color (:fill-color shape "#000000")}
|
||||
:on-click show-color-picker}]
|
||||
[:div.color-info
|
||||
[:input
|
||||
|
@ -53,7 +55,7 @@
|
|||
:value (:fill-color shape "")}]]]
|
||||
|
||||
;; SLIDEBAR FOR ROTATION AND OPACITY
|
||||
[:span (tr "ds.opacity")]
|
||||
[:span (tr "workspace.options.opacity")]
|
||||
[:div.row-flex
|
||||
[:input.slidebar
|
||||
{:type "range"
|
||||
|
|
|
@ -95,7 +95,7 @@
|
|||
[event shape]
|
||||
(let [value (dom/event->value event)
|
||||
value (parse-int value 0)]
|
||||
(st/emit! (udw/update-shape-attrs (:id shape) {:rotation value}))))
|
||||
#_(st/emit! (udw/update-shape-attrs (:id shape) {:rotation value}))))
|
||||
|
||||
(defn- on-position-change
|
||||
[event shape attr]
|
||||
|
@ -107,7 +107,7 @@
|
|||
|
||||
(defn- on-proportion-lock-change
|
||||
[event shape]
|
||||
(if (:proportion-lock shape)
|
||||
#_(if (:proportion-lock shape)
|
||||
(st/emit! (udw/unlock-proportions (:id shape)))
|
||||
(st/emit! (udw/lock-proportions (:id shape)))))
|
||||
|
||||
|
|
|
@ -1,134 +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-2017 Andrey Antukh <niwi@niwi.nz>
|
||||
;; Copyright (c) 2015-2017 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
||||
|
||||
(ns uxbox.main.ui.workspace.sidebar.options.image-measures
|
||||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.geom :as geom]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.util.data :refer (parse-int parse-float read-string)]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.geom.point :as gpt]
|
||||
[uxbox.util.i18n :refer (tr)]
|
||||
[uxbox.util.math :refer (precision-or-0)]))
|
||||
|
||||
(declare on-size-change)
|
||||
(declare on-rotation-change)
|
||||
(declare on-opacity-change)
|
||||
(declare on-position-change)
|
||||
(declare on-proportion-lock-change)
|
||||
|
||||
(mf/defc image-measures-menu
|
||||
[{:keys [menu shape] :as props}]
|
||||
(let [size (geom/size shape)]
|
||||
[:div.element-set
|
||||
[:div.element-set-title (:name menu)]
|
||||
[:div.element-set-content
|
||||
;; SLIDEBAR FOR ROTATION AND OPACITY
|
||||
[:span (tr "ds.size")]
|
||||
[:div.row-flex
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:placeholder (tr "ds.width")
|
||||
:type "number"
|
||||
:min "0"
|
||||
:value (precision-or-0 (:width size) 2)
|
||||
:on-change #(on-size-change % shape :width)}]]
|
||||
[:div.lock-size
|
||||
{:class (when (:proportion-lock shape) "selected")
|
||||
:on-click #(on-proportion-lock-change % shape)}
|
||||
(if (:proportion-lock shape) i/lock i/unlock)]
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:placeholder (tr "ds.height")
|
||||
:type "number"
|
||||
:min "0"
|
||||
:value (precision-or-0 (:height size) 2)
|
||||
:on-change #(on-size-change % shape :height)}]]]
|
||||
|
||||
[:span (tr "ds.position")]
|
||||
[:div.row-flex
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:placeholder "X"
|
||||
:type "number"
|
||||
:value (precision-or-0 (:x1 shape 0) 2)
|
||||
:on-change #(on-position-change % shape :x)}]]
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:placeholder "Y"
|
||||
:type "number"
|
||||
:value (precision-or-0 (:y1 shape 0) 2)
|
||||
:on-change #(on-position-change % shape :y)}]]]
|
||||
|
||||
;; [:span (tr "ds.rotation")]
|
||||
;; [:div.row-flex
|
||||
;; [:input.slidebar
|
||||
;; {:type "range"
|
||||
;; :min 0
|
||||
;; :max 360
|
||||
;; :value (:rotation shape 0)
|
||||
;; :on-change on-rotation-change}]]
|
||||
|
||||
;; [:div.row-flex
|
||||
;; [:div.input-element.degrees
|
||||
;; [: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"}}]]
|
||||
|
||||
|
||||
[:span (tr "ds.opacity")]
|
||||
[:div.row-flex
|
||||
[:input.slidebar
|
||||
{:type "range"
|
||||
:min "0"
|
||||
:max "10000"
|
||||
:value (* 10000 (:opacity shape 1))
|
||||
:step "1"
|
||||
:on-change #(on-opacity-change % shape)}]]]]))
|
||||
|
||||
(defn- on-size-change
|
||||
[event shape attr]
|
||||
(let [value (dom/event->value event)
|
||||
value (parse-int value 0)
|
||||
props {attr value}]
|
||||
(st/emit! (dw/update-dimensions (:id shape) props))))
|
||||
|
||||
(defn- on-rotation-change
|
||||
[event shape]
|
||||
(let [value (dom/event->value event)
|
||||
value (parse-int value 0)]
|
||||
(st/emit! (dw/update-shape-attrs (:id shape) {:rotation value}))))
|
||||
|
||||
(defn- on-opacity-change
|
||||
[event shape]
|
||||
(let [value (dom/event->value event)
|
||||
value (parse-float value 1)
|
||||
value (/ value 10000)]
|
||||
(st/emit! (dw/update-shape-attrs (:id shape) {:opacity value}))))
|
||||
|
||||
(defn- on-position-change
|
||||
[event shape attr]
|
||||
(let [value (dom/event->value event)
|
||||
value (parse-int value nil)
|
||||
point (gpt/point {attr value})]
|
||||
(st/emit! (dw/update-position (:id shape) point))))
|
||||
|
||||
(defn- on-proportion-lock-change
|
||||
[event shape]
|
||||
(if (:proportion-lock shape)
|
||||
(st/emit! (dw/unlock-proportions (:id shape)))
|
||||
(st/emit! (dw/lock-proportions (:id shape)))))
|
|
@ -22,452 +22,452 @@
|
|||
|
||||
;; --- Helpers
|
||||
|
||||
(defn- on-change
|
||||
([form attr event]
|
||||
(dom/prevent-default event)
|
||||
(let [value (dom/event->value event)
|
||||
value (read-string value)]
|
||||
(swap! form assoc attr value)))
|
||||
([form attr keep event]
|
||||
(let [data (select-keys @form keep)]
|
||||
(reset! form data)
|
||||
(on-change form attr event))))
|
||||
;; (defn- on-change
|
||||
;; ([form attr event]
|
||||
;; (dom/prevent-default event)
|
||||
;; (let [value (dom/event->value event)
|
||||
;; value (read-string value)]
|
||||
;; (swap! form assoc attr value)))
|
||||
;; ([form attr keep event]
|
||||
;; (let [data (select-keys @form keep)]
|
||||
;; (reset! form data)
|
||||
;; (on-change form attr event))))
|
||||
|
||||
;; --- Interactions List
|
||||
;; ;; --- Interactions List
|
||||
|
||||
(defn- translate-trigger-name
|
||||
[trigger]
|
||||
(case trigger
|
||||
:click "Click"
|
||||
:doubleclick "Double Click"
|
||||
:rightclick "Right Click"
|
||||
:hover "Hover"
|
||||
:mousein "Mouse In"
|
||||
:mouseout "Mouse Out"
|
||||
;; :swiperight "Swipe Right"
|
||||
;; :swipeleft "Swipe Left"
|
||||
;; :swipedown "Swipe Down"
|
||||
;; :touchandhold "Touch and Hold"
|
||||
;; :holdrelease "Hold release"
|
||||
(pr-str trigger)))
|
||||
;; (defn- translate-trigger-name
|
||||
;; [trigger]
|
||||
;; (case trigger
|
||||
;; :click "Click"
|
||||
;; :doubleclick "Double Click"
|
||||
;; :rightclick "Right Click"
|
||||
;; :hover "Hover"
|
||||
;; :mousein "Mouse In"
|
||||
;; :mouseout "Mouse Out"
|
||||
;; ;; :swiperight "Swipe Right"
|
||||
;; ;; :swipeleft "Swipe Left"
|
||||
;; ;; :swipedown "Swipe Down"
|
||||
;; ;; :touchandhold "Touch and Hold"
|
||||
;; ;; :holdrelease "Hold release"
|
||||
;; (pr-str trigger)))
|
||||
|
||||
(mf/defc interactions-list
|
||||
[{:keys [shape form] :as props}]
|
||||
(letfn [(on-edit [item event]
|
||||
(dom/prevent-default event)
|
||||
(reset! form item))
|
||||
(delete [item]
|
||||
(let [sid (:id shape)
|
||||
id (:id item)]
|
||||
(st/emit! (dw/delete-interaction sid id))))
|
||||
(on-delete [item event]
|
||||
(dom/prevent-default event)
|
||||
(let [delete (partial delete item)]
|
||||
(udl/open! :confirm {:on-accept delete})))]
|
||||
[:ul.element-list
|
||||
(for [item (vals (:interactions shape))
|
||||
:let [key (pr-str (:id item))]]
|
||||
[:li {:key key}
|
||||
[:div.list-icon i/action]
|
||||
[:span (translate-trigger-name (:trigger item))]
|
||||
[:div.list-actions
|
||||
[:a {:on-click (partial on-edit item)} i/pencil]
|
||||
[:a {:on-click (partial on-delete item)} i/trash]]])]))
|
||||
;; (mf/defc interactions-list
|
||||
;; [{:keys [shape form] :as props}]
|
||||
;; (letfn [(on-edit [item event]
|
||||
;; (dom/prevent-default event)
|
||||
;; (reset! form item))
|
||||
;; (delete [item]
|
||||
;; (let [sid (:id shape)
|
||||
;; id (:id item)]
|
||||
;; (st/emit! (dw/delete-interaction sid id))))
|
||||
;; (on-delete [item event]
|
||||
;; (dom/prevent-default event)
|
||||
;; (let [delete (partial delete item)]
|
||||
;; (udl/open! :confirm {:on-accept delete})))]
|
||||
;; [:ul.element-list
|
||||
;; (for [item (vals (:interactions shape))
|
||||
;; :let [key (pr-str (:id item))]]
|
||||
;; [:li {:key key}
|
||||
;; [:div.list-icon i/action]
|
||||
;; [:span (translate-trigger-name (:trigger item))]
|
||||
;; [:div.list-actions
|
||||
;; [:a {:on-click (partial on-edit item)} i/pencil]
|
||||
;; [:a {:on-click (partial on-delete item)} i/trash]]])]))
|
||||
|
||||
;; --- Trigger Input
|
||||
;; ;; --- Trigger Input
|
||||
|
||||
(mf/defc trigger-input
|
||||
[{:keys [form] :as props}]
|
||||
;; (mf/use-effect
|
||||
;; {:init #(when-not (:trigger @form) (swap! form assoc :trigger :click))
|
||||
;; :deps true})
|
||||
[:div
|
||||
[:span "Trigger"]
|
||||
[:div.row-flex
|
||||
[:select.input-select {:placeholder "Choose a trigger"
|
||||
:on-change (partial on-change form :trigger)
|
||||
:value (pr-str (:trigger @form))}
|
||||
[:option {:value ":click"} "Click"]
|
||||
[:option {:value ":doubleclick"} "Double-click"]
|
||||
[:option {:value ":rightclick"} "Right-click"]
|
||||
[:option {:value ":hover"} "Hover"]
|
||||
[:option {:value ":mousein"} "Mouse in"]
|
||||
[:option {:value ":mouseout"} "Mouse out"]
|
||||
#_[:option {:value ":swiperight"} "Swipe right"]
|
||||
#_[:option {:value ":swipeleft"} "Swipe left"]
|
||||
#_[:option {:value ":swipedown"} "Swipe dpwn"]
|
||||
#_[:option {:value ":touchandhold"} "Touch and hold"]
|
||||
#_[:option {:value ":holdrelease"} "Hold release"]
|
||||
#_[:option {:value ":keypress"} "Key press"]
|
||||
#_[:option {:value ":pageisloaded"} "Page is loaded"]
|
||||
#_[:option {:value ":windowscroll"} "Window is scrolled to"]]]])
|
||||
;; (mf/defc trigger-input
|
||||
;; [{:keys [form] :as props}]
|
||||
;; ;; (mf/use-effect
|
||||
;; ;; {:init #(when-not (:trigger @form) (swap! form assoc :trigger :click))
|
||||
;; ;; :deps true})
|
||||
;; [:div
|
||||
;; [:span "Trigger"]
|
||||
;; [:div.row-flex
|
||||
;; [:select.input-select {:placeholder "Choose a trigger"
|
||||
;; :on-change (partial on-change form :trigger)
|
||||
;; :value (pr-str (:trigger @form))}
|
||||
;; [:option {:value ":click"} "Click"]
|
||||
;; [:option {:value ":doubleclick"} "Double-click"]
|
||||
;; [:option {:value ":rightclick"} "Right-click"]
|
||||
;; [:option {:value ":hover"} "Hover"]
|
||||
;; [:option {:value ":mousein"} "Mouse in"]
|
||||
;; [:option {:value ":mouseout"} "Mouse out"]
|
||||
;; #_[:option {:value ":swiperight"} "Swipe right"]
|
||||
;; #_[:option {:value ":swipeleft"} "Swipe left"]
|
||||
;; #_[:option {:value ":swipedown"} "Swipe dpwn"]
|
||||
;; #_[:option {:value ":touchandhold"} "Touch and hold"]
|
||||
;; #_[:option {:value ":holdrelease"} "Hold release"]
|
||||
;; #_[:option {:value ":keypress"} "Key press"]
|
||||
;; #_[:option {:value ":pageisloaded"} "Page is loaded"]
|
||||
;; #_[:option {:value ":windowscroll"} "Window is scrolled to"]]]])
|
||||
|
||||
;; --- URL Input
|
||||
;; ;; --- URL Input
|
||||
|
||||
(mf/defc url-input
|
||||
[form]
|
||||
[:div
|
||||
[:span "Url"]
|
||||
[:div.row-flex
|
||||
[:input.input-text
|
||||
{:placeholder "http://"
|
||||
:on-change (partial on-change form :url)
|
||||
:value (:url @form "")
|
||||
:type "url"}]]])
|
||||
|
||||
;; --- Elements Input
|
||||
|
||||
(defn- collect-shapes
|
||||
[state page]
|
||||
(let [shapes-by-id (:shapes state)
|
||||
shapes (get-in state [:pages page :shapes])]
|
||||
(letfn [(resolve-shape [acc id]
|
||||
(let [shape (get shapes-by-id id)]
|
||||
(if (= (:type shape) :group)
|
||||
(reduce resolve-shape (conj acc shape) (:items shape))
|
||||
(conj acc shape))))]
|
||||
(reduce resolve-shape [] shapes))))
|
||||
|
||||
(mf/defc elements-input
|
||||
[{:keys [page-id form] :as props}]
|
||||
(let [shapes (collect-shapes @st/state page-id)]
|
||||
[:div
|
||||
[:span "Element"]
|
||||
[:div.row-flex
|
||||
[:select.input-select
|
||||
{:placeholder "Choose an element"
|
||||
:on-change (partial on-change form :element)
|
||||
:value (pr-str (:element @form))}
|
||||
[:option {:value "nil"} "---"]
|
||||
(for [shape shapes
|
||||
:let [key (pr-str (:id shape))]]
|
||||
[:option {:key key :value key} (:name shape)])]]]))
|
||||
|
||||
;; --- Page Input
|
||||
|
||||
(mf/defc pages-input
|
||||
[form-ref path]
|
||||
;; FIXME: react on ref
|
||||
#_(let [pages (mx/react refs/selected-project-pages)]
|
||||
(when (and (not (:page @form-ref))
|
||||
(pos? (count pages)))
|
||||
(swap! form-ref assoc :page (:id (first pages))))
|
||||
[:div
|
||||
[:span "Page"]
|
||||
[:div.row-flex
|
||||
[:select.input-select {:placeholder "Choose a page"
|
||||
:on-change (partial on-change form-ref :page)
|
||||
:value (pr-str (:page @form-ref))}
|
||||
(for [page pages
|
||||
:let [key (pr-str (:id page))]]
|
||||
[:option {:key key :value key} (:name page)])]]]))
|
||||
|
||||
;; --- Animation
|
||||
|
||||
(mf/defc animation-input
|
||||
[{:keys [form] :as props}]
|
||||
(when-not (:action @form)
|
||||
(swap! form assoc :animation :none))
|
||||
[:div
|
||||
[:span "Animation"]
|
||||
[:div.row-flex
|
||||
[:select.input-select
|
||||
{:placeholder "Animation"
|
||||
:on-change (partial on-change form :animation)
|
||||
:value (pr-str (:animation @form))}
|
||||
[:option {:value ":none"} "None"]
|
||||
[:option {:value ":fade"} "Fade"]
|
||||
[:option {:value ":slide"} "Slide"]]]])
|
||||
|
||||
;; --- MoveTo Input
|
||||
|
||||
(mf/defc moveto-input
|
||||
[{:keys [form] :as props}]
|
||||
(when-not (:moveto-x @form)
|
||||
(swap! form assoc :moveto-x 0))
|
||||
(when-not (:moveto-y @form)
|
||||
(swap! form assoc :moveto-y 0))
|
||||
[:div
|
||||
[:span "Move to position"]
|
||||
[:div.row-flex
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:placeholder "X"
|
||||
:on-change (partial on-change form :moveto-x)
|
||||
:type "number"
|
||||
:value (:moveto-x @form "")}]]
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:placeholder "Y"
|
||||
:on-change (partial on-change form :moveto-y)
|
||||
:type "number"
|
||||
:value (:moveto-y @form "")}]]]])
|
||||
|
||||
;; --- MoveBy Input
|
||||
|
||||
(mf/defc moveby-input
|
||||
[{:keys [form] :as props}]
|
||||
(when-not (:moveby-x @form)
|
||||
(swap! form assoc :moveby-x 0))
|
||||
(when-not (:moveby-y @form)
|
||||
(swap! form assoc :moveby-y 0))
|
||||
[:div
|
||||
[:span "Move to position"]
|
||||
[:div.row-flex
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:placeholder "X"
|
||||
:on-change (partial on-change form :moveby-x)
|
||||
:type "number"
|
||||
:value (:moveby-x @form "")}]]
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:placeholder "Y"
|
||||
:on-change (partial on-change form :moveby-y)
|
||||
:type "number"
|
||||
:value (:moveby-y @form "")}]]]])
|
||||
|
||||
;; --- Opacity Input
|
||||
|
||||
(mf/defc opacity-input
|
||||
[{:keys [form] :as props}]
|
||||
(when-not (:opacity @form)
|
||||
(swap! form assoc :opacity 100))
|
||||
[:div
|
||||
[:span "Opacity"]
|
||||
[:div.row-flex
|
||||
[:div.input-element.percentail
|
||||
[:input.input-text
|
||||
{:placeholder "%"
|
||||
:on-change (partial on-change form :opacity)
|
||||
:min "0"
|
||||
:max "100"
|
||||
:type "number"
|
||||
:value (:opacity @form "")}]]]])
|
||||
|
||||
;; --- Rotate Input
|
||||
|
||||
;; (mx/defc rotate-input
|
||||
;; (mf/defc url-input
|
||||
;; [form]
|
||||
;; [:div
|
||||
;; [:span "Rotate (dg)"]
|
||||
;; [:span "Url"]
|
||||
;; [:div.row-flex
|
||||
;; [:div.input-element.degrees
|
||||
;; [:input.input-text
|
||||
;; {:placeholder "http://"
|
||||
;; :on-change (partial on-change form :url)
|
||||
;; :value (:url @form "")
|
||||
;; :type "url"}]]])
|
||||
|
||||
;; ;; --- Elements Input
|
||||
|
||||
;; (defn- collect-shapes
|
||||
;; [state page]
|
||||
;; (let [shapes-by-id (:shapes state)
|
||||
;; shapes (get-in state [:pages page :shapes])]
|
||||
;; (letfn [(resolve-shape [acc id]
|
||||
;; (let [shape (get shapes-by-id id)]
|
||||
;; (if (= (:type shape) :group)
|
||||
;; (reduce resolve-shape (conj acc shape) (:items shape))
|
||||
;; (conj acc shape))))]
|
||||
;; (reduce resolve-shape [] shapes))))
|
||||
|
||||
;; (mf/defc elements-input
|
||||
;; [{:keys [page-id form] :as props}]
|
||||
;; (let [shapes (collect-shapes @st/state page-id)]
|
||||
;; [:div
|
||||
;; [:span "Element"]
|
||||
;; [:div.row-flex
|
||||
;; [:select.input-select
|
||||
;; {:placeholder "Choose an element"
|
||||
;; :on-change (partial on-change form :element)
|
||||
;; :value (pr-str (:element @form))}
|
||||
;; [:option {:value "nil"} "---"]
|
||||
;; (for [shape shapes
|
||||
;; :let [key (pr-str (:id shape))]]
|
||||
;; [:option {:key key :value key} (:name shape)])]]]))
|
||||
|
||||
;; ;; --- Page Input
|
||||
|
||||
;; (mf/defc pages-input
|
||||
;; [form-ref path]
|
||||
;; ;; FIXME: react on ref
|
||||
;; #_(let [pages (mx/react refs/selected-project-pages)]
|
||||
;; (when (and (not (:page @form-ref))
|
||||
;; (pos? (count pages)))
|
||||
;; (swap! form-ref assoc :page (:id (first pages))))
|
||||
;; [:div
|
||||
;; [:span "Page"]
|
||||
;; [:div.row-flex
|
||||
;; [:select.input-select {:placeholder "Choose a page"
|
||||
;; :on-change (partial on-change form-ref :page)
|
||||
;; :value (pr-str (:page @form-ref))}
|
||||
;; (for [page pages
|
||||
;; :let [key (pr-str (:id page))]]
|
||||
;; [:option {:key key :value key} (:name page)])]]]))
|
||||
|
||||
;; ;; --- Animation
|
||||
|
||||
;; (mf/defc animation-input
|
||||
;; [{:keys [form] :as props}]
|
||||
;; (when-not (:action @form)
|
||||
;; (swap! form assoc :animation :none))
|
||||
;; [:div
|
||||
;; [:span "Animation"]
|
||||
;; [:div.row-flex
|
||||
;; [:select.input-select
|
||||
;; {:placeholder "Animation"
|
||||
;; :on-change (partial on-change form :animation)
|
||||
;; :value (pr-str (:animation @form))}
|
||||
;; [:option {:value ":none"} "None"]
|
||||
;; [:option {:value ":fade"} "Fade"]
|
||||
;; [:option {:value ":slide"} "Slide"]]]])
|
||||
|
||||
;; ;; --- MoveTo Input
|
||||
|
||||
;; (mf/defc moveto-input
|
||||
;; [{:keys [form] :as props}]
|
||||
;; (when-not (:moveto-x @form)
|
||||
;; (swap! form assoc :moveto-x 0))
|
||||
;; (when-not (:moveto-y @form)
|
||||
;; (swap! form assoc :moveto-y 0))
|
||||
;; [:div
|
||||
;; [:span "Move to position"]
|
||||
;; [:div.row-flex
|
||||
;; [:div.input-element.pixels
|
||||
;; [:input.input-text
|
||||
;; {:placeholder "dg"
|
||||
;; :on-change (partial on-change form :rotation)
|
||||
;; {:placeholder "X"
|
||||
;; :on-change (partial on-change form :moveto-x)
|
||||
;; :type "number"
|
||||
;; :value (:rotation @form "")}]]]])
|
||||
;; :value (:moveto-x @form "")}]]
|
||||
;; [:div.input-element.pixels
|
||||
;; [:input.input-text
|
||||
;; {:placeholder "Y"
|
||||
;; :on-change (partial on-change form :moveto-y)
|
||||
;; :type "number"
|
||||
;; :value (:moveto-y @form "")}]]]])
|
||||
|
||||
;; --- Resize Input
|
||||
;; ;; --- MoveBy Input
|
||||
|
||||
(mf/defc resize-input
|
||||
[{:keys [form] :as props}]
|
||||
[:div
|
||||
[:span "Resize"]
|
||||
[:div.row-flex
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:placeholder "Width"
|
||||
:on-change (partial on-change form :resize-width)
|
||||
:type "number"
|
||||
:value (:resize-width @form "")}]]
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:placeholder "Height"
|
||||
:on-change (partial on-change form :resize-height)
|
||||
:type "number"
|
||||
:value (:resize-height @form "")}]]]])
|
||||
;; (mf/defc moveby-input
|
||||
;; [{:keys [form] :as props}]
|
||||
;; (when-not (:moveby-x @form)
|
||||
;; (swap! form assoc :moveby-x 0))
|
||||
;; (when-not (:moveby-y @form)
|
||||
;; (swap! form assoc :moveby-y 0))
|
||||
;; [:div
|
||||
;; [:span "Move to position"]
|
||||
;; [:div.row-flex
|
||||
;; [:div.input-element.pixels
|
||||
;; [:input.input-text
|
||||
;; {:placeholder "X"
|
||||
;; :on-change (partial on-change form :moveby-x)
|
||||
;; :type "number"
|
||||
;; :value (:moveby-x @form "")}]]
|
||||
;; [:div.input-element.pixels
|
||||
;; [:input.input-text
|
||||
;; {:placeholder "Y"
|
||||
;; :on-change (partial on-change form :moveby-y)
|
||||
;; :type "number"
|
||||
;; :value (:moveby-y @form "")}]]]])
|
||||
|
||||
;; --- Color Input
|
||||
;; ;; --- Opacity Input
|
||||
|
||||
(mf/defc colorpicker
|
||||
[{:keys [x y on-change value]}]
|
||||
(let [left (- x 260)
|
||||
top (- y 50)]
|
||||
[:div.colorpicker-tooltip
|
||||
{:style {:left (str left "px")
|
||||
:top (str top "px")}}
|
||||
;; (mf/defc opacity-input
|
||||
;; [{:keys [form] :as props}]
|
||||
;; (when-not (:opacity @form)
|
||||
;; (swap! form assoc :opacity 100))
|
||||
;; [:div
|
||||
;; [:span "Opacity"]
|
||||
;; [:div.row-flex
|
||||
;; [:div.input-element.percentail
|
||||
;; [:input.input-text
|
||||
;; {:placeholder "%"
|
||||
;; :on-change (partial on-change form :opacity)
|
||||
;; :min "0"
|
||||
;; :max "100"
|
||||
;; :type "number"
|
||||
;; :value (:opacity @form "")}]]]])
|
||||
|
||||
(cp/colorpicker
|
||||
:theme :small
|
||||
:value value
|
||||
:on-change on-change)]))
|
||||
;; ;; --- Rotate Input
|
||||
|
||||
(defmethod lbx/render-lightbox :interactions/colorpicker
|
||||
[params]
|
||||
(colorpicker params))
|
||||
;; ;; (mx/defc rotate-input
|
||||
;; ;; [form]
|
||||
;; ;; [:div
|
||||
;; ;; [:span "Rotate (dg)"]
|
||||
;; ;; [:div.row-flex
|
||||
;; ;; [:div.input-element.degrees
|
||||
;; ;; [:input.input-text
|
||||
;; ;; {:placeholder "dg"
|
||||
;; ;; :on-change (partial on-change form :rotation)
|
||||
;; ;; :type "number"
|
||||
;; ;; :value (:rotation @form "")}]]]])
|
||||
|
||||
(mf/defc color-input
|
||||
[{:keys [form] :as props}]
|
||||
(when-not (:fill-color @form)
|
||||
(swap! form assoc :fill-color "#000000"))
|
||||
(when-not (:stroke-color @form)
|
||||
(swap! form assoc :stroke-color "#000000"))
|
||||
(letfn [(on-change [attr color]
|
||||
(swap! form assoc attr color))
|
||||
(on-change-fill-color [event]
|
||||
(let [value (dom/event->value event)]
|
||||
(when (color? value)
|
||||
(on-change :fill-color value))))
|
||||
(on-change-stroke-color [event]
|
||||
(let [value (dom/event->value event)]
|
||||
(when (color? value)
|
||||
(on-change :stroke-color value))))
|
||||
(show-picker [attr event]
|
||||
(let [x (.-clientX event)
|
||||
y (.-clientY event)
|
||||
opts {:x x :y y
|
||||
:on-change (partial on-change attr)
|
||||
:value (get @form attr)
|
||||
:transparent? true}]
|
||||
(udl/open! :interactions/colorpicker opts)))]
|
||||
(let [stroke-color (:stroke-color @form)
|
||||
fill-color (:fill-color @form)]
|
||||
[:div
|
||||
[:div.row-flex
|
||||
[:div.column-half
|
||||
[:span "Fill"]
|
||||
[:div.color-data
|
||||
[:span.color-th
|
||||
{:style {:background-color fill-color}
|
||||
:on-click (partial show-picker :fill-color)}]
|
||||
[:div.color-info
|
||||
[:input
|
||||
{:on-change on-change-fill-color
|
||||
:value fill-color}]]]]
|
||||
[:div.column-half
|
||||
[:span "Stroke"]
|
||||
[:div.color-data
|
||||
[:span.color-th
|
||||
{:style {:background-color stroke-color}
|
||||
:on-click (partial show-picker :stroke-color)}]
|
||||
[:div.color-info
|
||||
[:input
|
||||
{:on-change on-change-stroke-color
|
||||
:value stroke-color}]]]]]])))
|
||||
;; ;; --- Resize Input
|
||||
|
||||
;; --- Easing Input
|
||||
;; (mf/defc resize-input
|
||||
;; [{:keys [form] :as props}]
|
||||
;; [:div
|
||||
;; [:span "Resize"]
|
||||
;; [:div.row-flex
|
||||
;; [:div.input-element.pixels
|
||||
;; [:input.input-text
|
||||
;; {:placeholder "Width"
|
||||
;; :on-change (partial on-change form :resize-width)
|
||||
;; :type "number"
|
||||
;; :value (:resize-width @form "")}]]
|
||||
;; [:div.input-element.pixels
|
||||
;; [:input.input-text
|
||||
;; {:placeholder "Height"
|
||||
;; :on-change (partial on-change form :resize-height)
|
||||
;; :type "number"
|
||||
;; :value (:resize-height @form "")}]]]])
|
||||
|
||||
(mf/defc easing-input
|
||||
[{:keys [form] :as props}]
|
||||
(when-not (:easing @form)
|
||||
(swap! form assoc :easing :linear))
|
||||
[:div
|
||||
[:span "Easing"]
|
||||
[:div.row-flex
|
||||
[:select.input-select
|
||||
{:placeholder "Easing"
|
||||
:on-change (partial on-change form :easing)
|
||||
:value (pr-str (:easing @form))}
|
||||
[:option {:value ":linear"} "Linear"]
|
||||
[:option {:value ":easein"} "Ease in"]
|
||||
[:option {:value ":easeout"} "Ease out"]
|
||||
[:option {:value ":easeinout"} "Ease in out"]]]])
|
||||
;; ;; --- Color Input
|
||||
|
||||
;; --- Duration Input
|
||||
;; (mf/defc colorpicker
|
||||
;; [{:keys [x y on-change value]}]
|
||||
;; (let [left (- x 260)
|
||||
;; top (- y 50)]
|
||||
;; [:div.colorpicker-tooltip
|
||||
;; {:style {:left (str left "px")
|
||||
;; :top (str top "px")}}
|
||||
|
||||
(mf/defc duration-input
|
||||
[{:keys [form] :as props}]
|
||||
(when-not (:duration @form)
|
||||
(swap! form assoc :duration 300))
|
||||
(when-not (:delay @form)
|
||||
(swap! form assoc :delay 0))
|
||||
[:div
|
||||
[:span "Duration | Delay"]
|
||||
[:div.row-flex
|
||||
[:div.input-element.miliseconds
|
||||
[:input.input-text
|
||||
{:placeholder "Duration"
|
||||
:type "number"
|
||||
:on-change (partial on-change form :duration)
|
||||
:value (pr-str (:duration @form))}]]
|
||||
[:div.input-element.miliseconds
|
||||
[:input.input-text {:placeholder "Delay"
|
||||
:type "number"
|
||||
:on-change (partial on-change form :delay)
|
||||
:value (pr-str (:delay @form))}]]]])
|
||||
;; (cp/colorpicker
|
||||
;; :theme :small
|
||||
;; :value value
|
||||
;; :on-change on-change)]))
|
||||
|
||||
;; --- Action Input
|
||||
;; (defmethod lbx/render-lightbox :interactions/colorpicker
|
||||
;; [params]
|
||||
;; (colorpicker params))
|
||||
|
||||
(mf/defc action-input
|
||||
[{:keys [shape form] :as props}]
|
||||
;; (when-not (:action @form)
|
||||
;; (swap! form assoc :action :show))
|
||||
(let [form-data (deref form)
|
||||
simple? #{:gotourl :gotopage}
|
||||
elements? (complement simple?)
|
||||
animation? #{:show :hide :toggle}
|
||||
only-easing? (complement animation?)]
|
||||
[:div
|
||||
[:span "Action"]
|
||||
[:div.row-flex
|
||||
[:select.input-select
|
||||
{:placeholder "Choose an action"
|
||||
:on-change (partial on-change form :action [:trigger])
|
||||
:value (pr-str (:action form-data))}
|
||||
[:option {:value ":show"} "Show"]
|
||||
[:option {:value ":hide"} "Hide"]
|
||||
[:option {:value ":toggle"} "Toggle"]
|
||||
;; [:option {:value ":moveto"} "Move to"]
|
||||
[:option {:value ":moveby"} "Move by"]
|
||||
[:option {:value ":opacity"} "Opacity"]
|
||||
[:option {:value ":size"} "Size"]
|
||||
[:option {:value ":color"} "Color"]
|
||||
;; [:option {:value ":rotate"} "Rotate"]
|
||||
[:option {:value ":gotopage"} "Go to page"]
|
||||
[:option {:value ":gotourl"} "Go to URL"]
|
||||
#_[:option {:value ":goback"} "Go back"]
|
||||
[:option {:value ":scrolltoelement"} "Scroll to element"]]]
|
||||
;; (mf/defc color-input
|
||||
;; [{:keys [form] :as props}]
|
||||
;; (when-not (:fill-color @form)
|
||||
;; (swap! form assoc :fill-color "#000000"))
|
||||
;; (when-not (:stroke-color @form)
|
||||
;; (swap! form assoc :stroke-color "#000000"))
|
||||
;; (letfn [(on-change [attr color]
|
||||
;; (swap! form assoc attr color))
|
||||
;; (on-change-fill-color [event]
|
||||
;; (let [value (dom/event->value event)]
|
||||
;; (when (color? value)
|
||||
;; (on-change :fill-color value))))
|
||||
;; (on-change-stroke-color [event]
|
||||
;; (let [value (dom/event->value event)]
|
||||
;; (when (color? value)
|
||||
;; (on-change :stroke-color value))))
|
||||
;; (show-picker [attr event]
|
||||
;; (let [x (.-clientX event)
|
||||
;; y (.-clientY event)
|
||||
;; opts {:x x :y y
|
||||
;; :on-change (partial on-change attr)
|
||||
;; :value (get @form attr)
|
||||
;; :transparent? true}]
|
||||
;; (udl/open! :interactions/colorpicker opts)))]
|
||||
;; (let [stroke-color (:stroke-color @form)
|
||||
;; fill-color (:fill-color @form)]
|
||||
;; [:div
|
||||
;; [:div.row-flex
|
||||
;; [:div.column-half
|
||||
;; [:span "Fill"]
|
||||
;; [:div.color-data
|
||||
;; [:span.color-th
|
||||
;; {:style {:background-color fill-color}
|
||||
;; :on-click (partial show-picker :fill-color)}]
|
||||
;; [:div.color-info
|
||||
;; [:input
|
||||
;; {:on-change on-change-fill-color
|
||||
;; :value fill-color}]]]]
|
||||
;; [:div.column-half
|
||||
;; [:span "Stroke"]
|
||||
;; [:div.color-data
|
||||
;; [:span.color-th
|
||||
;; {:style {:background-color stroke-color}
|
||||
;; :on-click (partial show-picker :stroke-color)}]
|
||||
;; [:div.color-info
|
||||
;; [:input
|
||||
;; {:on-change on-change-stroke-color
|
||||
;; :value stroke-color}]]]]]])))
|
||||
|
||||
(case (:action form-data)
|
||||
:gotourl [:& url-input {:form form}]
|
||||
;; :gotopage (pages-input form)
|
||||
:color [:& color-input {:form form}]
|
||||
;; :rotate (rotate-input form)
|
||||
:size [:& resize-input {:form form}]
|
||||
:moveto [:& moveto-input {:form form}]
|
||||
:moveby [:& moveby-input {:form form}]
|
||||
:opacity [:& opacity-input {:form form}]
|
||||
nil)
|
||||
;; ;; --- Easing Input
|
||||
|
||||
(when (elements? (:action form-data))
|
||||
[:& elements-input {:page-id (:page shape)
|
||||
:form form}])
|
||||
;; (mf/defc easing-input
|
||||
;; [{:keys [form] :as props}]
|
||||
;; (when-not (:easing @form)
|
||||
;; (swap! form assoc :easing :linear))
|
||||
;; [:div
|
||||
;; [:span "Easing"]
|
||||
;; [:div.row-flex
|
||||
;; [:select.input-select
|
||||
;; {:placeholder "Easing"
|
||||
;; :on-change (partial on-change form :easing)
|
||||
;; :value (pr-str (:easing @form))}
|
||||
;; [:option {:value ":linear"} "Linear"]
|
||||
;; [:option {:value ":easein"} "Ease in"]
|
||||
;; [:option {:value ":easeout"} "Ease out"]
|
||||
;; [:option {:value ":easeinout"} "Ease in out"]]]])
|
||||
|
||||
(when (and (animation? (:action form-data))
|
||||
(:element form-data))
|
||||
[:& animation-input {:form form}])
|
||||
;; ;; --- Duration Input
|
||||
|
||||
(when (or (not= (:animation form-data :none) :none)
|
||||
(and (only-easing? (:action form-data))
|
||||
(:element form-data)))
|
||||
[:*
|
||||
[:& easing-input {:form form}]
|
||||
[:& duration-input {:form form}]])]))
|
||||
;; (mf/defc duration-input
|
||||
;; [{:keys [form] :as props}]
|
||||
;; (when-not (:duration @form)
|
||||
;; (swap! form assoc :duration 300))
|
||||
;; (when-not (:delay @form)
|
||||
;; (swap! form assoc :delay 0))
|
||||
;; [:div
|
||||
;; [:span "Duration | Delay"]
|
||||
;; [:div.row-flex
|
||||
;; [:div.input-element.miliseconds
|
||||
;; [:input.input-text
|
||||
;; {:placeholder "Duration"
|
||||
;; :type "number"
|
||||
;; :on-change (partial on-change form :duration)
|
||||
;; :value (pr-str (:duration @form))}]]
|
||||
;; [:div.input-element.miliseconds
|
||||
;; [:input.input-text {:placeholder "Delay"
|
||||
;; :type "number"
|
||||
;; :on-change (partial on-change form :delay)
|
||||
;; :value (pr-str (:delay @form))}]]]])
|
||||
|
||||
;; ;; --- Action Input
|
||||
|
||||
;; (mf/defc action-input
|
||||
;; [{:keys [shape form] :as props}]
|
||||
;; ;; (when-not (:action @form)
|
||||
;; ;; (swap! form assoc :action :show))
|
||||
;; (let [form-data (deref form)
|
||||
;; simple? #{:gotourl :gotopage}
|
||||
;; elements? (complement simple?)
|
||||
;; animation? #{:show :hide :toggle}
|
||||
;; only-easing? (complement animation?)]
|
||||
;; [:div
|
||||
;; [:span "Action"]
|
||||
;; [:div.row-flex
|
||||
;; [:select.input-select
|
||||
;; {:placeholder "Choose an action"
|
||||
;; :on-change (partial on-change form :action [:trigger])
|
||||
;; :value (pr-str (:action form-data))}
|
||||
;; [:option {:value ":show"} "Show"]
|
||||
;; [:option {:value ":hide"} "Hide"]
|
||||
;; [:option {:value ":toggle"} "Toggle"]
|
||||
;; ;; [:option {:value ":moveto"} "Move to"]
|
||||
;; [:option {:value ":moveby"} "Move by"]
|
||||
;; [:option {:value ":opacity"} "Opacity"]
|
||||
;; [:option {:value ":size"} "Size"]
|
||||
;; [:option {:value ":color"} "Color"]
|
||||
;; ;; [:option {:value ":rotate"} "Rotate"]
|
||||
;; [:option {:value ":gotopage"} "Go to page"]
|
||||
;; [:option {:value ":gotourl"} "Go to URL"]
|
||||
;; #_[:option {:value ":goback"} "Go back"]
|
||||
;; [:option {:value ":scrolltoelement"} "Scroll to element"]]]
|
||||
|
||||
;; (case (:action form-data)
|
||||
;; :gotourl [:& url-input {:form form}]
|
||||
;; ;; :gotopage (pages-input form)
|
||||
;; :color [:& color-input {:form form}]
|
||||
;; ;; :rotate (rotate-input form)
|
||||
;; :size [:& resize-input {:form form}]
|
||||
;; :moveto [:& moveto-input {:form form}]
|
||||
;; :moveby [:& moveby-input {:form form}]
|
||||
;; :opacity [:& opacity-input {:form form}]
|
||||
;; nil)
|
||||
|
||||
;; (when (elements? (:action form-data))
|
||||
;; [:& elements-input {:page-id (:page shape)
|
||||
;; :form form}])
|
||||
|
||||
;; (when (and (animation? (:action form-data))
|
||||
;; (:element form-data))
|
||||
;; [:& animation-input {:form form}])
|
||||
|
||||
;; (when (or (not= (:animation form-data :none) :none)
|
||||
;; (and (only-easing? (:action form-data))
|
||||
;; (:element form-data)))
|
||||
;; [:*
|
||||
;; [:& easing-input {:form form}]
|
||||
;; [:& duration-input {:form form}]])]))
|
||||
|
||||
|
||||
;; --- Form
|
||||
;; ;; --- Form
|
||||
|
||||
(mf/defc interactions-form
|
||||
[{:keys [shape form] :as props}]
|
||||
(letfn [(on-submit [event]
|
||||
(dom/prevent-default event)
|
||||
(let [sid (:id shape)
|
||||
data (deref form)]
|
||||
(st/emit! (dw/update-interaction sid data))
|
||||
(reset! form nil)))
|
||||
(on-cancel [event]
|
||||
(dom/prevent-default event)
|
||||
(reset! form nil))]
|
||||
[:form {:on-submit on-submit}
|
||||
[:& trigger-input {:form form}]
|
||||
[:& action-input {:shape shape :form form}]
|
||||
[:div.row-flex
|
||||
[:input.btn-primary.btn-small.save-btn
|
||||
{:value "Save" :type "submit"}]
|
||||
[:a.cancel-btn {:on-click on-cancel}
|
||||
"Cancel"]]]))
|
||||
;; (mf/defc interactions-form
|
||||
;; [{:keys [shape form] :as props}]
|
||||
;; (letfn [(on-submit [event]
|
||||
;; (dom/prevent-default event)
|
||||
;; (let [sid (:id shape)
|
||||
;; data (deref form)]
|
||||
;; (st/emit! (dw/update-interaction sid data))
|
||||
;; (reset! form nil)))
|
||||
;; (on-cancel [event]
|
||||
;; (dom/prevent-default event)
|
||||
;; (reset! form nil))]
|
||||
;; [:form {:on-submit on-submit}
|
||||
;; [:& trigger-input {:form form}]
|
||||
;; [:& action-input {:shape shape :form form}]
|
||||
;; [:div.row-flex
|
||||
;; [:input.btn-primary.btn-small.save-btn
|
||||
;; {:value "Save" :type "submit"}]
|
||||
;; [:a.cancel-btn {:on-click on-cancel}
|
||||
;; "Cancel"]]]))
|
||||
|
||||
;; --- Interactions Menu
|
||||
|
||||
|
@ -477,7 +477,7 @@
|
|||
|
||||
(mf/defc interactions-menu
|
||||
[{:keys [menu shape] :as props}]
|
||||
(let [form (mf/use-state nil)
|
||||
#_(let [form (mf/use-state nil)
|
||||
interactions (:interactions shape)]
|
||||
[:div.element-set {:key (str (:id menu))}
|
||||
[:div.element-set-title (:name menu)]
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
[rumext.alpha :as mf]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.constants :as c]
|
||||
[uxbox.main.data.pages :as udp]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
|
@ -23,94 +22,59 @@
|
|||
[uxbox.util.i18n :refer [tr]]
|
||||
[uxbox.util.spec :refer [color?]]))
|
||||
|
||||
(mf/defc measures-menu
|
||||
[{:keys [menu page] :as props}]
|
||||
(mf/defc metadata-options
|
||||
[{:keys [page] :as props}]
|
||||
(let [metadata (:metadata page)
|
||||
metadata (merge c/page-metadata metadata)]
|
||||
(letfn [(on-size-change [event attr]
|
||||
(let [value (-> (dom/event->value event)
|
||||
(parse-int nil))]
|
||||
(st/emit! (->> (assoc metadata attr value)
|
||||
(udp/update-metadata (:id page))))))
|
||||
change-color
|
||||
(fn [color]
|
||||
#_(st/emit! (->> (assoc metadata :background color)
|
||||
(udp/update-metadata (:id page)))))
|
||||
on-color-change
|
||||
(fn [event]
|
||||
(let [value (dom/event->value event)]
|
||||
(change-color value)))
|
||||
|
||||
(change-color [color]
|
||||
(st/emit! (->> (assoc metadata :background color)
|
||||
(udp/update-metadata (:id page)))))
|
||||
show-color-picker
|
||||
(fn [event]
|
||||
(let [x (.-clientX event)
|
||||
y (.-clientY event)
|
||||
props {:x x :y y
|
||||
:default "#ffffff"
|
||||
:value (:background metadata)
|
||||
:transparent? true
|
||||
:on-change change-color}]
|
||||
(modal/show! colorpicker-modal props)))]
|
||||
|
||||
(on-color-change [event]
|
||||
(let [value (dom/event->value event)]
|
||||
(change-color value)))
|
||||
[:div.element-set
|
||||
[:div.element-set-title (tr "workspace.options.page-measures")]
|
||||
[:div.element-set-content
|
||||
[:span (tr "workspace.options.background-color")]
|
||||
[:div.row-flex.color-data
|
||||
[:span.color-th
|
||||
{:style {:background-color (:background metadata "#ffffff")}
|
||||
:on-click show-color-picker}]
|
||||
[:div.color-info
|
||||
[:input
|
||||
{:on-change on-color-change
|
||||
:value (:background metadata "#ffffff")}]]]]]))
|
||||
|
||||
(on-name-change [event]
|
||||
(let [value (-> (dom/event->value event)
|
||||
(str/trim))]
|
||||
(st/emit! (-> (assoc page :name value)
|
||||
(udp/update-page-attrs)))))
|
||||
|
||||
(show-color-picker [event]
|
||||
(let [x (.-clientX event)
|
||||
y (.-clientY event)
|
||||
props {:x x :y y
|
||||
:default "#ffffff"
|
||||
:value (:background metadata)
|
||||
:transparent? true
|
||||
:on-change change-color}]
|
||||
(modal/show! colorpicker-modal props)))]
|
||||
|
||||
[:div.element-set
|
||||
[:div.element-set-title (tr (:name menu))]
|
||||
[:div.element-set-content
|
||||
[:span (tr "ds.name")]
|
||||
[:div.row-flex
|
||||
[:div.input-element
|
||||
[:input.input-text
|
||||
{:type "text"
|
||||
:on-change on-name-change
|
||||
:value (str (:name page))
|
||||
:placeholder "page name"}]]]
|
||||
|
||||
[:span (tr "ds.size")]
|
||||
[:div.row-flex
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:type "number"
|
||||
:on-change #(on-size-change % :width)
|
||||
:value (str (:width metadata))
|
||||
:placeholder (tr "ds.width")}]]
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:type "number"
|
||||
:on-change #(on-size-change % :height)
|
||||
:value (str (:height metadata))
|
||||
:placeholder (tr "ds.height")}]]]
|
||||
|
||||
[:span (tr "ds.background-color")]
|
||||
[:div.row-flex.color-data
|
||||
[:span.color-th
|
||||
{:style {:background-color (:background metadata)}
|
||||
:on-click show-color-picker}]
|
||||
[:div.color-info
|
||||
[:input
|
||||
{:on-change on-color-change
|
||||
:value (:background metadata)}]]]]])))
|
||||
|
||||
(mf/defc grid-options-menu
|
||||
[{:keys [menu page] :as props}]
|
||||
(mf/defc grid-options
|
||||
[{:keys [page] :as props}]
|
||||
(let [metadata (:metadata page)
|
||||
metadata (merge c/page-metadata metadata)]
|
||||
(letfn [(on-x-change [event]
|
||||
(let [value (-> (dom/event->value event)
|
||||
#_(let [value (-> (dom/event->value event)
|
||||
(parse-int nil))]
|
||||
(st/emit! (->> (assoc metadata :grid-x-axis value)
|
||||
(udp/update-metadata (:id page))))))
|
||||
(on-y-change [event]
|
||||
(let [value (-> (dom/event->value event)
|
||||
#_(let [value (-> (dom/event->value event)
|
||||
(parse-int nil))]
|
||||
(st/emit! (->> (assoc metadata :grid-y-axis value)
|
||||
(udp/update-metadata (:id page))))))
|
||||
|
||||
(change-color [color]
|
||||
(st/emit! (->> (assoc metadata :grid-color color)
|
||||
#_(st/emit! (->> (assoc metadata :grid-color color)
|
||||
(udp/update-metadata (:id page)))))
|
||||
(on-color-change [event]
|
||||
(let [value (dom/event->value event)]
|
||||
|
@ -126,9 +90,9 @@
|
|||
:on-change change-color}]
|
||||
(modal/show! colorpicker-modal props)))]
|
||||
[:div.element-set
|
||||
[:div.element-set-title (tr (:name menu))]
|
||||
[:div.element-set-title (tr "element.page-grid-options")]
|
||||
[:div.element-set-content
|
||||
[:span (tr "ds.size")]
|
||||
[:span (tr "workspace.options.size")]
|
||||
[:div.row-flex
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
|
@ -142,7 +106,7 @@
|
|||
:value (:grid-y-axis metadata)
|
||||
:on-change on-y-change
|
||||
:placeholder "y"}]]]
|
||||
[:span (tr "ds.color")]
|
||||
[:span (tr "workspace.options.color")]
|
||||
[:div.row-flex.color-data
|
||||
[:span.color-th
|
||||
{:style {:background-color (:grid-color metadata)}
|
||||
|
@ -151,3 +115,10 @@
|
|||
[:input
|
||||
{:on-change on-color-change
|
||||
:value (:grid-color metadata "#cccccc")}]]]]])))
|
||||
|
||||
(mf/defc options
|
||||
[{:keys [page] :as props}]
|
||||
[:div
|
||||
[:& metadata-options {:page page}]
|
||||
[:& grid-options {:page page}]])
|
||||
|
||||
|
|
137
frontend/src/uxbox/main/ui/workspace/sidebar/options/rect.cljs
Normal file
137
frontend/src/uxbox/main/ui/workspace/sidebar/options/rect.cljs
Normal file
|
@ -0,0 +1,137 @@
|
|||
;; 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-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
|
||||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.common.data :as d]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.geom :as geom]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-menu]]
|
||||
[uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-menu]]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.geom.point :as gpt]
|
||||
[uxbox.util.i18n :refer [tr]]
|
||||
[uxbox.util.math :as math]))
|
||||
|
||||
(mf/defc measures-menu
|
||||
[{:keys [shape] :as props}]
|
||||
(let [on-size-change
|
||||
(fn [event attr]
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(d/parse-integer 0))]
|
||||
(st/emit! (udw/update-dimensions (:id shape) {attr value}))))
|
||||
|
||||
on-proportion-lock-change
|
||||
(fn [event]
|
||||
(st/emit! (udw/toggle-shape-proportion-lock (:id shape))))
|
||||
|
||||
on-position-change
|
||||
(fn [event attr]
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(d/parse-integer))
|
||||
point (gpt/point {attr value})]
|
||||
(st/emit! (udw/update-position (:id shape) point))))
|
||||
|
||||
on-rotation-change
|
||||
(fn [event]
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(d/parse-integer 0))]
|
||||
(st/emit! (udw/update-shape (:id shape) {:rotation value}))))
|
||||
|
||||
on-radius-change
|
||||
(fn [event]
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(d/parse-double 0))]
|
||||
(st/emit! (udw/update-shape (:id shape) {:rx value :ry value}))))
|
||||
|
||||
on-width-change #(on-size-change % :width)
|
||||
on-height-change #(on-size-change % :height)
|
||||
on-pos-x-change #(on-position-change % :x)
|
||||
on-pos-y-change #(on-position-change % :y)]
|
||||
|
||||
[:div.element-set
|
||||
[:div.element-set-title (tr "workspace.options.measures")]
|
||||
[:div.element-set-content
|
||||
[:span (tr "workspace.options.size")]
|
||||
|
||||
;; WIDTH & HEIGHT
|
||||
[:div.row-flex
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text {:type "number"
|
||||
:min "0"
|
||||
:on-change on-width-change
|
||||
:value (-> (:width shape)
|
||||
(math/precision 2)
|
||||
(d/coalesce-str "0"))}]]
|
||||
|
||||
[:div.lock-size {:class (when (:proportion-lock shape) "selected")
|
||||
:on-click on-proportion-lock-change}
|
||||
(if (:proportion-lock shape)
|
||||
i/lock
|
||||
i/unlock)]
|
||||
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text {:type "number"
|
||||
:min "0"
|
||||
:on-change on-height-change
|
||||
:value (-> (:height shape)
|
||||
(math/precision 2)
|
||||
(d/coalesce-str "0"))}]]]
|
||||
|
||||
;; POSITION
|
||||
[:span (tr "workspace.options.position")]
|
||||
[:div.row-flex
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text {:placeholder "x"
|
||||
:type "number"
|
||||
:on-change on-pos-x-change
|
||||
:value (-> (:x shape)
|
||||
(math/precision 2)
|
||||
(d/coalesce-str "0"))}]]
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text {:placeholder "y"
|
||||
:type "number"
|
||||
:on-change on-pos-y-change
|
||||
:value (-> (:y shape)
|
||||
(math/precision 2)
|
||||
(d/coalesce-str "0"))}]]]
|
||||
|
||||
[:span (tr "workspace.options.rotation-radius")]
|
||||
[:div.row-flex
|
||||
[:div.input-element.degrees
|
||||
[:input.input-text {:placeholder ""
|
||||
:type "number"
|
||||
:min 0
|
||||
:max 360
|
||||
:on-change on-rotation-change
|
||||
:value (-> (:rotation shape 0)
|
||||
(math/precision 2)
|
||||
(d/coalesce-str "0"))}]]
|
||||
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:placeholder "rx"
|
||||
:type "number"
|
||||
:on-change on-radius-change
|
||||
:value (-> (:rx shape)
|
||||
(math/precision 2)
|
||||
(d/coalesce-str "0"))}]]]]]))
|
||||
|
||||
|
||||
(mf/defc options
|
||||
[{:keys [shape] :as props}]
|
||||
[:div
|
||||
[:& measures-menu {:shape shape}]
|
||||
[:& fill-menu {:shape shape}]
|
||||
[:& stroke-menu {:shape shape}]])
|
|
@ -1,108 +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-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
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.geom :as geom]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.util.data :refer [parse-int parse-float read-string]]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.geom.point :as gpt]
|
||||
[uxbox.util.i18n :refer [tr]]
|
||||
[uxbox.util.math :refer [precision-or-0]]))
|
||||
|
||||
(declare on-size-change)
|
||||
(declare on-rotation-change)
|
||||
(declare on-position-change)
|
||||
(declare on-proportion-lock-change)
|
||||
|
||||
(mf/defc rect-measures-menu
|
||||
[{:keys [menu shape] :as props}]
|
||||
(let [size (geom/size shape)]
|
||||
[:div.element-set
|
||||
[:div.element-set-title (:name menu)]
|
||||
[:div.element-set-content
|
||||
;; SLIDEBAR FOR ROTATION AND OPACITY
|
||||
[:span (tr "ds.size")]
|
||||
[:div.row-flex
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text {:placeholder (tr "ds.width")
|
||||
:type "number"
|
||||
:min "0"
|
||||
:value (precision-or-0 (:width size) 2)
|
||||
:on-change #(on-size-change % shape :width)}]]
|
||||
|
||||
[:div.lock-size {:class (when (:proportion-lock shape) "selected")
|
||||
:on-click #(on-proportion-lock-change % shape)}
|
||||
(if (:proportion-lock shape) i/lock i/unlock)]
|
||||
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text {:placeholder (tr "ds.height")
|
||||
:type "number"
|
||||
:min "0"
|
||||
:value (precision-or-0 (:height size) 2)
|
||||
:on-change #(on-size-change % shape :height)}]]]
|
||||
|
||||
[:span (tr "ds.position")]
|
||||
[:div.row-flex
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text {:placeholder "x"
|
||||
:type "number"
|
||||
:value (precision-or-0 (:x1 shape 0) 2)
|
||||
:on-change #(on-position-change % shape :x)}]]
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text {:placeholder "y"
|
||||
:type "number"
|
||||
:value (precision-or-0 (:y1 shape 0) 2)
|
||||
:on-change #(on-position-change % shape :y)}]]]
|
||||
|
||||
[:span (tr "ds.rotation")]
|
||||
[:div.row-flex
|
||||
[:input.slidebar {:type "range"
|
||||
:min 0
|
||||
:max 360
|
||||
:value (:rotation shape 0)
|
||||
:on-change #(on-rotation-change % shape)}]]
|
||||
|
||||
[:div.row-flex
|
||||
[:div.input-element.degrees
|
||||
[:input.input-text {:placeholder ""
|
||||
:type "number"
|
||||
:min 0
|
||||
:max 360
|
||||
:value (precision-or-0 (:rotation shape "0") 2)
|
||||
:on-change #(on-rotation-change % shape)}]]
|
||||
[:input.input-text {:style {:visibility "hidden"}}]]]]))
|
||||
|
||||
|
||||
(defn- on-size-change
|
||||
[event shape attr]
|
||||
(let [value (-> (dom/event->value event)
|
||||
(parse-int 0))]
|
||||
(st/emit! (udw/update-dimensions (:id shape) {attr value}))))
|
||||
|
||||
(defn- on-rotation-change
|
||||
[event shape]
|
||||
(let [value (dom/event->value event)
|
||||
value (parse-int value 0)]
|
||||
(st/emit! (udw/update-shape-attrs (:id shape) {:rotation value}))))
|
||||
|
||||
(defn- on-position-change
|
||||
[event shape attr]
|
||||
(let [value (-> (dom/event->value event)
|
||||
(parse-int nil))
|
||||
point (gpt/point {attr value})]
|
||||
(st/emit! (udw/update-position (:id shape) point))))
|
||||
|
||||
(defn- on-proportion-lock-change
|
||||
[event shape]
|
||||
(if (:proportion-lock shape)
|
||||
(st/emit! (udw/unlock-proportions (:id shape)))
|
||||
(st/emit! (udw/lock-proportions (:id shape)))))
|
|
@ -8,6 +8,7 @@
|
|||
(ns uxbox.main.ui.workspace.sidebar.options.stroke
|
||||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.common.data :as d]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.store :as st]
|
||||
|
@ -16,126 +17,82 @@
|
|||
[uxbox.util.data :refer [parse-int parse-float read-string]]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.i18n :refer [tr]]
|
||||
[uxbox.util.math :refer [precision-or-0]]))
|
||||
|
||||
(declare on-width-change)
|
||||
(declare on-opacity-change)
|
||||
(declare on-stroke-style-change)
|
||||
(declare on-stroke-color-change)
|
||||
(declare on-border-change)
|
||||
(declare show-color-picker)
|
||||
[uxbox.util.math :as math]))
|
||||
|
||||
(mf/defc stroke-menu
|
||||
[{:keys [menu shape] :as props}]
|
||||
(let [local (mf/use-state {})
|
||||
on-border-lock #(swap! local update :border-lock not)
|
||||
on-stroke-style-change #(on-stroke-style-change % shape)
|
||||
on-width-change #(on-width-change % shape)
|
||||
on-stroke-color-change #(on-stroke-color-change % shape)
|
||||
on-border-change-rx #(on-border-change % shape local :rx)
|
||||
on-border-change-ry #(on-border-change % shape local :ry)
|
||||
on-opacity-change #(on-opacity-change % shape)
|
||||
show-color-picker #(show-color-picker % shape)]
|
||||
[{:keys [shape] :as props}]
|
||||
(let [on-stroke-style-change
|
||||
(fn [event]
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(d/read-string))]
|
||||
(st/emit! (udw/update-shape (:id shape) {:stroke-style value}))))
|
||||
|
||||
on-stroke-width-change
|
||||
(fn [event]
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(d/parse-double 1))]
|
||||
(st/emit! (udw/update-shape (:id shape) {:stroke-width value}))))
|
||||
|
||||
on-stroke-opacity-change
|
||||
(fn [event]
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(d/parse-double 1)
|
||||
(/ 10000))]
|
||||
(st/emit! (udw/update-shape (:id shape) {:stroke-opacity value}))))
|
||||
|
||||
show-color-picker
|
||||
(fn [event]
|
||||
(let [x (.-clientX event)
|
||||
y (.-clientY event)
|
||||
props {:x x :y y
|
||||
:default "#ffffff"
|
||||
:value (:stroke-color shape)
|
||||
:on-change #(st/emit! (udw/update-shape (:id shape) {:stroke-color %}))
|
||||
:transparent? true}]
|
||||
(modal/show! colorpicker-modal props)))]
|
||||
|
||||
[:div.element-set
|
||||
[:div.element-set-title (:name menu)]
|
||||
[:div.element-set-title (tr "workspace.options.stroke")]
|
||||
[:div.element-set-content
|
||||
[:span (tr "ds.style")]
|
||||
|
||||
;; Stroke Style & Width
|
||||
[:span (tr "workspace.options.stroke.style")]
|
||||
[:div.row-flex
|
||||
[:select#style.input-select {:placeholder (tr "ds.style")
|
||||
:value (pr-str (:stroke-style shape))
|
||||
[:select#style.input-select {:value (pr-str (:stroke-style shape))
|
||||
:on-change on-stroke-style-change}
|
||||
[:option {:value ":none"} (tr "ds.none")]
|
||||
[:option {:value ":solid"} (tr "ds.solid")]
|
||||
[:option {:value ":dotted"} (tr "ds.dotted")]
|
||||
[:option {:value ":dashed"} (tr "ds.dashed")]
|
||||
[:option {:value ":mixed"} (tr "ds.mixed")]]
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:placeholder (tr "ds.width")
|
||||
:type "number"
|
||||
:min "0"
|
||||
:value (precision-or-0 (:stroke-width shape 1) 2)
|
||||
:on-change on-width-change}]]]
|
||||
[:option {:value ":none"} (tr "workspace.options.stroke.none")]
|
||||
[:option {:value ":solid"} (tr "workspace.options.stroke.solid")]
|
||||
[:option {:value ":dotted"} (tr "workspace.options.stroke.dotted")]
|
||||
[:option {:value ":dashed"} (tr "workspace.options.stroke.dashed")]
|
||||
[:option {:value ":mixed"} (tr "workspace.options.stroke.mixed")]]
|
||||
|
||||
[:span (tr "ds.color")]
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text {:type "number"
|
||||
:min "0"
|
||||
:value (-> (:stroke-width shape)
|
||||
(math/precision 2)
|
||||
(d/coalesce-str "1"))
|
||||
:on-change on-stroke-width-change}]]]
|
||||
|
||||
;; Stroke Color
|
||||
[:span (tr "workspace.options.color")]
|
||||
[:div.row-flex.color-data
|
||||
[:span.color-th
|
||||
{:style {:background-color (:stroke-color shape)}
|
||||
:on-click show-color-picker}]
|
||||
[: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 "")}]]]
|
||||
[:input {:read-only true
|
||||
:default-value (:stroke-color shape "")}]]]
|
||||
|
||||
[:span (tr "ds.radius")]
|
||||
[:span (tr "workspace.options.opacity")]
|
||||
[:div.row-flex
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:placeholder "rx"
|
||||
:type "number"
|
||||
:value (precision-or-0 (:rx shape 0) 2)
|
||||
:on-change on-border-change-rx}]]
|
||||
[:div.lock-size
|
||||
{:class (when (:border-lock @local) "selected")
|
||||
:on-click on-border-lock}
|
||||
i/lock]
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text
|
||||
{:placeholder "ry"
|
||||
:type "number"
|
||||
:value (precision-or-0 (:ry shape 0) 2)
|
||||
:on-change on-border-change-ry}]]]
|
||||
|
||||
[:span (tr "ds.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}]]]]))
|
||||
|
||||
(defn- on-width-change
|
||||
[event shape]
|
||||
(let [value (-> (dom/event->value event)
|
||||
(parse-float 1))]
|
||||
(st/emit! (udw/update-shape-attrs (:id shape) {:stroke-width value}))))
|
||||
|
||||
(defn- on-opacity-change
|
||||
[event shape]
|
||||
(let [value (-> (dom/event->value event)
|
||||
(parse-float 1)
|
||||
(/ 10000))]
|
||||
(st/emit! (udw/update-shape-attrs (:id shape) {:stroke-opacity value}))))
|
||||
|
||||
(defn- on-stroke-style-change
|
||||
[event shape]
|
||||
(let [value (-> (dom/event->value event)
|
||||
(read-string))]
|
||||
(st/emit! (udw/update-shape-attrs (:id shape) {:stroke-style value}))))
|
||||
|
||||
(defn- on-stroke-color-change
|
||||
[event shape]
|
||||
(let [value (dom/event->value event)]
|
||||
(st/emit! (udw/update-shape-attrs (:id shape) {:stroke-color value}))))
|
||||
|
||||
(defn- on-border-change
|
||||
[event shape local attr]
|
||||
(let [value (-> (dom/event->value event)
|
||||
(parse-int nil))
|
||||
id (:id shape)]
|
||||
(if (:border-lock @local)
|
||||
(st/emit! (udw/update-shape-attrs id {:rx value :ry value}))
|
||||
(st/emit! (udw/update-shape-attrs id {attr value})))))
|
||||
|
||||
(defn- show-color-picker
|
||||
[event shape]
|
||||
(let [x (.-clientX event)
|
||||
y (.-clientY event)
|
||||
props {:x x :y y
|
||||
:default "#ffffff"
|
||||
:value (:stroke-color shape)
|
||||
:on-change #(st/emit! (udw/update-shape-attrs (:id shape) {:stroke-color %}))
|
||||
:transparent? true}]
|
||||
(modal/show! colorpicker-modal props)))
|
||||
[:input.slidebar {:type "range"
|
||||
:min "0"
|
||||
:max "10000"
|
||||
:value (-> (:stroke-opacity shape 1)
|
||||
(* 10000)
|
||||
(d/coalesce-str "1"))
|
||||
:step "1"
|
||||
:on-change on-stroke-opacity-change}]]]]))
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
{:mixins [mx/static]}
|
||||
[menu {:keys [id] :as shape}]
|
||||
(letfn [(update-attrs [attrs]
|
||||
(st/emit! (udw/update-shape-attrs id attrs)))
|
||||
#_(st/emit! (udw/update-shape-attrs id attrs)))
|
||||
(on-font-family-change [event]
|
||||
(let [value (dom/event->value event)
|
||||
attrs {:font-family (read-string value)
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
[lentes.core :as l]
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.data.pages :as udp]
|
||||
[uxbox.main.data.projects :as dp]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.store :as st]
|
||||
|
@ -30,7 +29,7 @@
|
|||
(mf/defc page-item
|
||||
[{:keys [page index deletable? selected?] :as props}]
|
||||
(let [on-edit #(modal/show! page-form-dialog {:page page})
|
||||
delete-fn #(st/emit! (udp/delete-page (:id page)))
|
||||
delete-fn #(st/emit! (dp/delete-page (:id page)))
|
||||
on-delete #(do
|
||||
(dom/prevent-default %)
|
||||
(dom/stop-propagation %)
|
||||
|
@ -101,11 +100,7 @@
|
|||
close-fn #(st/emit! (dw/toggle-layout-flag :sitemap))]
|
||||
[:div.sitemap.tool-window
|
||||
[:div.tool-window-bar
|
||||
[:div.tool-window-icon i/project-tree]
|
||||
[:span (tr "ds.settings.sitemap")]
|
||||
[:div.tool-window-close {:on-click close-fn} i/close]]
|
||||
[:div.add-page {:on-click create-fn} i/close]]
|
||||
[:div.tool-window-content
|
||||
[:div.project-title
|
||||
#_[:span (:name project)]
|
||||
[:div.add-page {:on-click create-fn} i/close]]
|
||||
[:& pages-list {:file file :current-page page}]]]))
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
[cljs.spec.alpha :as s]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.constants :as c]
|
||||
[uxbox.main.data.pages :as udp]
|
||||
[uxbox.main.data.projects :as dp]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.ui.modal :as modal]
|
||||
|
@ -34,8 +34,8 @@
|
|||
(modal/hide!)
|
||||
(let [data (:clean-data form)]
|
||||
(if (nil? (:id data))
|
||||
(st/emit! (udp/create-page data))
|
||||
(st/emit! (udp/rename-page data)))))
|
||||
(st/emit! (dp/create-page data))
|
||||
(st/emit! (dp/rename-page data)))))
|
||||
|
||||
(defn- initial-data
|
||||
[page]
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
[goog.events :as events]
|
||||
[potok.core :as ptk]
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.constants :as c]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.geom :as geom]
|
||||
|
@ -72,14 +73,29 @@
|
|||
|
||||
;; --- Selection Rect
|
||||
|
||||
(defn- selection->rect
|
||||
[data]
|
||||
(let [start (:start data)
|
||||
stop (:stop data)
|
||||
start-x (min (:x start) (:x stop))
|
||||
start-y (min (:y start) (:y stop))
|
||||
end-x (max (:x start) (:x stop))
|
||||
end-y (max (:y start) (:y stop))]
|
||||
(assoc data
|
||||
:type :rect
|
||||
:x start-x
|
||||
:y start-y
|
||||
:width (- end-x start-x)
|
||||
:height (- end-y start-y))))
|
||||
|
||||
(def ^:private handle-selrect
|
||||
(letfn [(update-state [state position]
|
||||
(let [selrect (get-in state [:workspace-local :selrect])]
|
||||
(if selrect
|
||||
(assoc-in state [:workspace-local :selrect]
|
||||
(dw/selection->rect (assoc selrect :stop position)))
|
||||
(selection->rect (assoc selrect :stop position)))
|
||||
(assoc-in state [:workspace-local :selrect]
|
||||
(dw/selection->rect {:start position :stop position})))))
|
||||
(selection->rect {:start position :stop position})))))
|
||||
|
||||
(clear-state [state]
|
||||
(update state :workspace-local dissoc :selrect))]
|
||||
|
@ -99,13 +115,11 @@
|
|||
{:wrap [mf/wrap-memo]}
|
||||
[{:keys [data] :as props}]
|
||||
(when data
|
||||
(let [{:keys [x1 y1 width height]} (geom/size data)]
|
||||
[:rect.selection-rect
|
||||
{:x x1
|
||||
:y y1
|
||||
:width width
|
||||
:height height}])))
|
||||
|
||||
[:rect.selection-rect
|
||||
{:x (:x data)
|
||||
:y (:y data)
|
||||
:width (:width data)
|
||||
:height (:height data)}]))
|
||||
|
||||
;; --- Viewport Positioning
|
||||
|
||||
|
@ -127,6 +141,8 @@
|
|||
|
||||
;; --- Viewport
|
||||
|
||||
(declare remote-user-cursors)
|
||||
|
||||
(mf/defc canvas-and-shapes
|
||||
{:wrap [mf/wrap-memo]}
|
||||
[props]
|
||||
|
@ -137,7 +153,7 @@
|
|||
[:*
|
||||
(for [item canvas]
|
||||
[:& shape-wrapper {:shape item :key (:id item)}])
|
||||
(for [item (reverse shapes)]
|
||||
(for [item shapes]
|
||||
[:& shape-wrapper {:shape item :key (:id item)}])]))
|
||||
|
||||
(mf/defc viewport
|
||||
|
@ -275,4 +291,53 @@
|
|||
(when (contains? flags :ruler)
|
||||
[:& ruler {:zoom zoom :ruler (:ruler local)}])
|
||||
|
||||
|
||||
;; -- METER CURSOR MULTIUSUARIO
|
||||
[:& remote-user-cursors {:page page}]
|
||||
|
||||
[:& selrect {:data (:selrect local)}]]])))
|
||||
|
||||
|
||||
(mf/defc remote-user-cursor
|
||||
[{:keys [pointer user] :as props}]
|
||||
[:g.multiuser-cursor {:key (:user-id pointer)
|
||||
:transform (str "translate(" (:x pointer) "," (:y pointer) ") scale(4)")}
|
||||
[:path {:fill (:color user)
|
||||
:d "M5.292 4.027L1.524.26l-.05-.01L0 0l.258 1.524 3.769 3.768zm-.45 0l-.313.314L1.139.95l.314-.314zm-.5.5l-.315.316-3.39-3.39.315-.315 3.39 3.39zM1.192.526l-.668.667L.431.646.64.43l.552.094z"
|
||||
:font-family "sans-serif"}]
|
||||
[:g {:transform "translate(0 -291.708)"}
|
||||
[:rect {:width "21.415"
|
||||
:height "5.292"
|
||||
:x "6.849"
|
||||
:y "291.755"
|
||||
:fill (:color user)
|
||||
:fill-opacity ".893"
|
||||
:paint-order "stroke fill markers"
|
||||
:rx ".794"
|
||||
:ry ".794"}]
|
||||
[:text {:x "9.811"
|
||||
:y "295.216"
|
||||
:fill "#fff"
|
||||
:stroke-width ".265"
|
||||
:font-family "Open Sans"
|
||||
:font-size"2.91"
|
||||
:font-weight "400"
|
||||
:letter-spacing"0"
|
||||
:style {:line-height "1.25"}
|
||||
:word-spacing "0"
|
||||
;; :style="line-height:1
|
||||
}
|
||||
(:fullname user)]]])
|
||||
|
||||
(mf/defc remote-user-cursors
|
||||
[{:keys [page] :as props}]
|
||||
(let [users (mf/deref refs/workspace-users)
|
||||
pointers (->> (vals (:pointer users))
|
||||
(remove #(not= (:id page) (:page-id %)))
|
||||
(filter #((:active users) (:user-id %))))]
|
||||
(for [pointer pointers]
|
||||
(let [user (get-in users [:by-id (:user-id pointer)])]
|
||||
[:& remote-user-cursor {:pointer pointer
|
||||
:user user
|
||||
:key (:user-id pointer)}]))))
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue