diff --git a/frontend/uxbox/data/workspace.cljs b/frontend/uxbox/data/workspace.cljs
index 4269fa4d0..fd90f10a7 100644
--- a/frontend/uxbox/data/workspace.cljs
+++ b/frontend/uxbox/data/workspace.cljs
@@ -26,7 +26,6 @@
(reify
rs/UpdateEvent
(-apply-update [_ state]
- (println "toggle-grid")
(update-in state [:workspace :grid-enabled] (fnil not false)))
IPrintWithWriter
diff --git a/frontend/uxbox/router.cljs b/frontend/uxbox/router.cljs
index 7cd88ed1b..3df27fa8d 100644
--- a/frontend/uxbox/router.cljs
+++ b/frontend/uxbox/router.cljs
@@ -11,6 +11,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Events
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
(defn update-location
[{:keys [handler route-params] :as params}]
(reify
diff --git a/frontend/uxbox/ui/workspace.cljs b/frontend/uxbox/ui/workspace.cljs
index 98f1151dc..34aecf0e7 100644
--- a/frontend/uxbox/ui/workspace.cljs
+++ b/frontend/uxbox/ui/workspace.cljs
@@ -7,6 +7,9 @@
[uxbox.data.projects :as dp]
[uxbox.ui.util :as util]
[uxbox.ui.workspace.base :as wb]
+ [uxbox.ui.workspace.toolbar :as wt]
+ [uxbox.ui.workspace.leftsidebar :as wl]
+ [uxbox.ui.workspace.header :as wh]
[uxbox.ui.workspace.rules :as wr]
[uxbox.ui.workspace.workarea :as wa]))
@@ -19,13 +22,13 @@
(println "workspace-render")
(html
[:div
- (wb/header)
+ (wh/header)
[:main.main-content
[:section.workspace-content
;; Toolbar
- (wb/toolbar)
+ (wt/toolbar)
;; Project bar
- (wb/project-sidebar)
+ (wl/left-sidebar)
;; Rules
(wr/h-rule)
(wr/v-rule)
diff --git a/frontend/uxbox/ui/workspace/base.cljs b/frontend/uxbox/ui/workspace/base.cljs
index ae7bd0831..d8d53d2ac 100644
--- a/frontend/uxbox/ui/workspace/base.cljs
+++ b/frontend/uxbox/ui/workspace/base.cljs
@@ -1,23 +1,10 @@
(ns uxbox.ui.workspace.base
- (:require [sablono.core :as html :refer-macros [html]]
- [rum.core :as rum]
- [beicon.core :as rx]
+ (:require [beicon.core :as rx]
[cats.labs.lens :as l]
- [cuerdas.core :as str]
- [uxbox.router :as r]
[uxbox.rstore :as rs]
[uxbox.state :as s]
[uxbox.data.projects :as dp]
- [uxbox.data.workspace :as dw]
- [uxbox.util.lens :as ul]
- [uxbox.ui.icons.dashboard :as icons]
- [uxbox.ui.icons :as i]
- [uxbox.ui.lightbox :as lightbox]
- [uxbox.ui.keyboard :as k]
- [uxbox.ui.users :as ui.u]
- [uxbox.ui.navigation :as nav]
- [uxbox.ui.dom :as dom]
- [uxbox.ui.util :as util]))
+ [uxbox.util.lens :as ul]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Lenses
@@ -61,238 +48,3 @@
(def document-start-x 50)
(def document-start-y 50)
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Header
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(defn on-download-clicked
- [event page]
- (let [content (.-innerHTML (.getElementById js/document "page-layout"))
- width (:width page)
- height (:height page)
- html (str "")
- data (js/Blob. #js [html] #js {:type "application/octet-stream"})
- url (.createObjectURL (.-URL js/window) data)]
- (set! (.-href (.-currentTarget event)) url)))
-
-(defn header-render
- [own]
- (letfn [(toggle-pagesbar [e]
- (rs/emit! (dw/toggle-pagesbar)))
- (toggle-grid [e]
- (rs/emit! (dw/toggle-grid)))]
- (let [page (rum/react page-state)]
- (html
- [:header#workspace-bar.workspace-bar
- [:div.main-icon
- (nav/link (r/route-for :dashboard/projects) i/logo-icon)]
- [:div.project-tree-btn
- {:on-click toggle-pagesbar}
- i/project-tree
- [:span (:name page)]]
- [:div.workspace-options
- [:ul.options-btn
- [:li.tooltip.tooltip-bottom {:alt "Undo (Ctrl + Z)"}
- i/undo]
- [:li.tooltip.tooltip-bottom {:alt "Redo (Ctrl + Shift + Z)"}
- i/redo]]
- [:ul.options-btn
- ;; TODO: refactor
- [:li.tooltip.tooltip-bottom
- {:alt "Export (Ctrl + E)"}
- ;; page-title
- [:a {:download (str (:name page) ".svg")
- :href "#" :on-click on-download-clicked}
- i/export]]
- [:li.tooltip.tooltip-bottom
- {:alt "Image (Ctrl + I)"}
- i/image]]
- [:ul.options-btn
- [:li.tooltip.tooltip-bottom
- {:alt "Ruler (Ctrl + R)"}
- i/ruler]
- [:li.tooltip.tooltip-bottom
- {:alt "Grid (Ctrl + G)"
- :class (when false "selected")
- :on-click toggle-grid}
- i/grid]
- [:li.tooltip.tooltip-bottom
- {:alt "Align (Ctrl + A)"}
- i/alignment]
- [:li.tooltip.tooltip-bottom
- {:alt "Organize (Ctrl + O)"}
- i/organize]]]
- (ui.u/user)]))))
-
-(def header
- (util/component
- {:render header-render
- :name "workspace-header"
- :mixins [rum/reactive]}))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Toolbar
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(def ^:static toolbar-state
- (as-> (l/in [:workspace :toolbars]) $
- (l/focus-atom $ s/state)))
-
-(defn- toggle-toolbox
- [state item]
- (update state item (fnil not false)))
-
-(defn toolbar-render
- [own]
- (let [state (rum/react toolbar-state)]
- (html
- [:div#tool-bar.tool-bar
- [:div.tool-bar-inside
- [:ul.main-tools
- [:li.tooltip
- {:alt "Shapes (Ctrl + Shift + F)"
- :class (when (:tools state) "current")
- :on-click #(swap! toolbar-state toggle-toolbox :tools)}
- i/shapes]
- [:li.tooltip
- {:alt "Icons (Ctrl + Shift + I)"
- :class (when (:icons state) "current")
- :on-click #(swap! toolbar-state toggle-toolbox :icons)}
- i/icon-set]
- [:li.tooltip
- {:alt "Elements (Ctrl + Shift + L)"
- :class (when (:layers state)
- "current")
- :on-click #(swap! toolbar-state toggle-toolbox :layers)}
- i/layers]
- [:li.tooltip
- {:alt "Feedback (Ctrl + Shift + M)"}
- i/chat]]]])))
-
-(def ^:static toolbar
- (util/component
- {:render toolbar-render
- :name "toolbar"
- :mixins [rum/reactive]}))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Project Bar
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(defn- project-sidebar-pageitem-render
- [own parent page numpages]
- (letfn [(on-edit [e]
- (let [data {:edit true :form page}]
- (reset! parent data)))]
- (let [curpage (rum/react page-state)
- active? (= (:id curpage) (:id page))
- deletable? (> numpages 1)
- navigate #(rs/emit! (dp/go-to-project (:project page) (:id page)))
- delete #(rs/emit! (dp/delete-page (:id page)))]
- (html
- [:li.single-page
- {:class (when active? "current")
- :on-click navigate}
- [:div.tree-icon i/page]
- [:span (:name page)]
- [:div.options
- [:div {:on-click on-edit} i/pencil]
- [:div {:class (when-not deletable? "hide")
- :on-click delete}
- i/trash]]]))))
-
-(def project-sidebar-pageitem
- (util/component
- {:render project-sidebar-pageitem-render
- :name "project-sidebar-pageitem"
- :mixins [rum/reactive]}))
-
-(defn- project-sidebar-pagelist-render
- [own parent]
- (let [project (rum/react project-state)
- pages (rum/react pages-state)
- name (:name project)]
- (html
- [:div.project-bar-inside
- [:span.project-name name]
- [:ul.tree-view
- (for [page pages]
- (let [component (project-sidebar-pageitem parent page (count pages))]
- (rum/with-key component (str (:id page)))))]
- [:button.btn-primary.btn-small
- {:on-click #(reset! parent {:edit true :form {}})}
- "+ Add new page"]])))
-
-(def project-sidebar-pagelist
- (util/component
- {:render project-sidebar-pagelist-render
- :name "project-sidebar-pagelist"
- :mixins [rum/reactive]}))
-
-(defn- project-sidebar-form-render
- [own parent]
- (let [form (:form @parent)
- project @project-state]
- (letfn [(on-change [e]
- (let [value (dom/event->value e)]
- (swap! parent assoc-in [:form :name] value)))
- (persist []
- (if (nil? (:id form))
- (let [data {:project (:id project)
- :width (:width project)
- :height (:height project)
- :name (:name form)}]
- (rs/emit! (dp/create-page data))
- (reset! parent {:edit false}))
- (do
- (rs/emit! (dp/update-page-name (:id form) (:name form)))
- (reset! parent {:edit false}))))
- (on-save [e]
- (persist))
- (on-key-up [e]
- (when (k/enter? e)
- (persist)))
- (on-cancel [e]
- (reset! parent {:edit false}))]
- (html
- [:div.project-bar-inside
- [:input.input-text
- {:name "test"
- :auto-focus true
- :placeholder "Page title"
- :type "text"
- :value (get-in @parent [:form :name] "")
- :on-change on-change
- :on-key-up on-key-up}]
- [:button.btn-primary.btn-small
- {:disabled (str/empty? (str/trim (get-in @parent [:form :name] "")))
- :on-click on-save}
- "Save"]
- [:button.btn-delete.btn-small
- {:on-click on-cancel}
- "Cancel"]]))))
-
-(def project-sidebar-form
- (util/component
- {:render project-sidebar-form-render
- :name "project-sidebar-form"
- :mixins [rum/reactive]}))
-
-(defn project-sidebar-render
- [own]
- (let [local (:rum/local own)
- workspace (rum/react workspace-state)
- project (rum/react project-state)]
- (html
- [:div#project-bar.project-bar
- (when-not (:pagesbar-enabled workspace false)
- {:class "toggle"})
- (if (:edit @local)
- (project-sidebar-form local)
- (project-sidebar-pagelist local))])))
-
-(def project-sidebar
- (util/component
- {:render project-sidebar-render
- :name "project-sidebar"
- :mixins [rum/reactive (rum/local {:edit false :form {}})]}))
diff --git a/frontend/uxbox/ui/workspace/header.cljs b/frontend/uxbox/ui/workspace/header.cljs
new file mode 100644
index 000000000..f1ad0f1b0
--- /dev/null
+++ b/frontend/uxbox/ui/workspace/header.cljs
@@ -0,0 +1,79 @@
+(ns uxbox.ui.workspace.header
+ (:require [sablono.core :as html :refer-macros [html]]
+ [rum.core :as rum]
+ [beicon.core :as rx]
+ [uxbox.router :as r]
+ [uxbox.rstore :as rs]
+ [uxbox.data.workspace :as dw]
+ [uxbox.ui.workspace.base :as wb]
+ [uxbox.ui.icons :as i]
+ [uxbox.ui.users :as ui.u]
+ [uxbox.ui.navigation :as nav]
+ [uxbox.ui.util :as util]))
+
+(defn on-download-clicked
+ [event page]
+ (let [content (.-innerHTML (.getElementById js/document "page-layout"))
+ width (:width page)
+ height (:height page)
+ html (str "")
+ data (js/Blob. #js [html] #js {:type "application/octet-stream"})
+ url (.createObjectURL (.-URL js/window) data)]
+ (set! (.-href (.-currentTarget event)) url)))
+
+(defn header-render
+ [own]
+ (letfn [(toggle-pagesbar [e]
+ (rs/emit! (dw/toggle-pagesbar)))
+ (toggle-grid [e]
+ (rs/emit! (dw/toggle-grid)))]
+ (let [page (rum/react wb/page-state)
+ workspace (rum/react wb/workspace-state)]
+ (html
+ [:header#workspace-bar.workspace-bar
+ [:div.main-icon
+ (nav/link (r/route-for :dashboard/projects) i/logo-icon)]
+ [:div.project-tree-btn
+ {:on-click toggle-pagesbar}
+ i/project-tree
+ [:span (:name page)]]
+ [:div.workspace-options
+ [:ul.options-btn
+ [:li.tooltip.tooltip-bottom {:alt "Undo (Ctrl + Z)"}
+ i/undo]
+ [:li.tooltip.tooltip-bottom {:alt "Redo (Ctrl + Shift + Z)"}
+ i/redo]]
+ [:ul.options-btn
+ ;; TODO: refactor
+ [:li.tooltip.tooltip-bottom
+ {:alt "Export (Ctrl + E)"}
+ ;; page-title
+ [:a {:download (str (:name page) ".svg")
+ :href "#" :on-click on-download-clicked}
+ i/export]]
+ [:li.tooltip.tooltip-bottom
+ {:alt "Image (Ctrl + I)"}
+ i/image]]
+ [:ul.options-btn
+ [:li.tooltip.tooltip-bottom
+ {:alt "Ruler (Ctrl + R)"}
+ i/ruler]
+ [:li.tooltip.tooltip-bottom
+ {:alt "Grid (Ctrl + G)"
+ :class (when (:grid-enabled workspace) "selected")
+ :on-click toggle-grid}
+ i/grid]
+ [:li.tooltip.tooltip-bottom
+ {:alt "Align (Ctrl + A)"}
+ i/alignment]
+ [:li.tooltip.tooltip-bottom
+ {:alt "Organize (Ctrl + O)"}
+ i/organize]]]
+ (ui.u/user)]))))
+
+(def header
+ (util/component
+ {:render header-render
+ :name "workspace-header"
+ :mixins [rum/reactive]}))
+
diff --git a/frontend/uxbox/ui/workspace/leftsidebar.cljs b/frontend/uxbox/ui/workspace/leftsidebar.cljs
new file mode 100644
index 000000000..dad3aba9d
--- /dev/null
+++ b/frontend/uxbox/ui/workspace/leftsidebar.cljs
@@ -0,0 +1,131 @@
+(ns uxbox.ui.workspace.leftsidebar
+ (:require [sablono.core :as html :refer-macros [html]]
+ [rum.core :as rum]
+ [cuerdas.core :as str]
+ [uxbox.rstore :as rs]
+ [uxbox.data.projects :as dp]
+ [uxbox.ui.icons :as i]
+ [uxbox.ui.keyboard :as k]
+ [uxbox.ui.mixins :as mx]
+ [uxbox.ui.workspace.base :as wb]
+ [uxbox.ui.dom :as dom]
+ [uxbox.ui.util :as util]))
+
+(defn- project-sidebar-pageitem-render
+ [own parent page numpages]
+ (letfn [(on-edit [e]
+ (let [data {:edit true :form page}]
+ (reset! parent data)))]
+
+ (let [curpage (rum/react wb/page-state)
+ active? (= (:id curpage) (:id page))
+ deletable? (> numpages 1)
+ navigate #(rs/emit! (dp/go-to-project (:project page) (:id page)))
+ delete #(rs/emit! (dp/delete-page (:id page)))]
+ (html
+ [:li.single-page
+ {:class (when active? "current")
+ :on-click navigate}
+ [:div.tree-icon i/page]
+ [:span (:name page)]
+ [:div.options
+ [:div {:on-click on-edit} i/pencil]
+ [:div {:class (when-not deletable? "hide")
+ :on-click delete}
+ i/trash]]]))))
+
+(def project-sidebar-pageitem
+ (util/component
+ {:render project-sidebar-pageitem-render
+ :name "project-sidebar-pageitem"
+ :mixins [rum/reactive]}))
+
+(defn- project-sidebar-pagelist-render
+ [own parent]
+ (let [project (rum/react wb/project-state)
+ pages (rum/react wb/pages-state)
+ name (:name project)]
+ (html
+ [:div.project-bar-inside
+ [:span.project-name name]
+ [:ul.tree-view
+ (for [page pages]
+ (let [component (project-sidebar-pageitem parent page (count pages))]
+ (rum/with-key component (str (:id page)))))]
+ [:button.btn-primary.btn-small
+ {:on-click #(reset! parent {:edit true :form {}})}
+ "+ Add new page"]])))
+
+(def project-sidebar-pagelist
+ (util/component
+ {:render project-sidebar-pagelist-render
+ :name "project-sidebar-pagelist"
+ :mixins [rum/reactive]}))
+
+(defn- project-sidebar-form-render
+ [own parent]
+ (let [form (:form @parent)
+ project @wb/project-state]
+ (letfn [(on-change [e]
+ (let [value (dom/event->value e)]
+ (swap! parent assoc-in [:form :name] value)))
+ (persist []
+ (if (nil? (:id form))
+ (let [data {:project (:id project)
+ :width (:width project)
+ :height (:height project)
+ :name (:name form)}]
+ (rs/emit! (dp/create-page data))
+ (reset! parent {:edit false}))
+ (do
+ (rs/emit! (dp/update-page-name (:id form) (:name form)))
+ (reset! parent {:edit false}))))
+ (on-save [e]
+ (persist))
+ (on-key-up [e]
+ (when (k/enter? e)
+ (persist)))
+ (on-cancel [e]
+ (reset! parent {:edit false}))]
+ (html
+ [:div.project-bar-inside
+ [:input.input-text
+ {:name "test"
+ :auto-focus true
+ :placeholder "Page title"
+ :type "text"
+ :value (get-in @parent [:form :name] "")
+ :on-change on-change
+ :on-key-up on-key-up}]
+ [:button.btn-primary.btn-small
+ {:disabled (str/empty? (str/trim (get-in @parent [:form :name] "")))
+ :on-click on-save}
+ "Save"]
+ [:button.btn-delete.btn-small
+ {:on-click on-cancel}
+ "Cancel"]]))))
+
+(def project-sidebar-form
+ (util/component
+ {:render project-sidebar-form-render
+ :name "project-sidebar-form"
+ :mixins [rum/reactive]}))
+
+(defn left-sidebar-render
+ [own]
+ (let [local (:rum/local own)
+ workspace (rum/react wb/workspace-state)
+ project (rum/react wb/project-state)]
+ (html
+ [:div#project-bar.project-bar
+ (when-not (:pagesbar-enabled workspace false)
+ {:class "toggle"})
+ (if (:edit @local)
+ (project-sidebar-form local)
+ (project-sidebar-pagelist local))])))
+
+(def left-sidebar
+ (util/component
+ {:render left-sidebar-render
+ :name "left-sidebar"
+ :mixins [rum/reactive (mx/local {:edit false :form {}})]}))
diff --git a/frontend/uxbox/ui/workspace/toolbar.cljs b/frontend/uxbox/ui/workspace/toolbar.cljs
new file mode 100644
index 000000000..d559b006f
--- /dev/null
+++ b/frontend/uxbox/ui/workspace/toolbar.cljs
@@ -0,0 +1,53 @@
+(ns uxbox.ui.workspace.toolbar
+ (:require [sablono.core :as html :refer-macros [html]]
+ [rum.core :as rum]
+ [cats.labs.lens :as l]
+ [uxbox.rstore :as rs]
+ [uxbox.state :as s]
+ [uxbox.ui.icons :as i]
+ [uxbox.ui.util :as util]))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Toolbar
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(def ^:static toolbar-state
+ (as-> (l/in [:workspace :toolbars]) $
+ (l/focus-atom $ s/state)))
+
+(defn- toggle-toolbox
+ [state item]
+ (update state item (fnil not false)))
+
+(defn toolbar-render
+ [own]
+ (let [state (rum/react toolbar-state)]
+ (html
+ [:div#tool-bar.tool-bar
+ [:div.tool-bar-inside
+ [:ul.main-tools
+ [:li.tooltip
+ {:alt "Shapes (Ctrl + Shift + F)"
+ :class (when (:tools state) "current")
+ :on-click #(swap! toolbar-state toggle-toolbox :tools)}
+ i/shapes]
+ [:li.tooltip
+ {:alt "Icons (Ctrl + Shift + I)"
+ :class (when (:icons state) "current")
+ :on-click #(swap! toolbar-state toggle-toolbox :icons)}
+ i/icon-set]
+ [:li.tooltip
+ {:alt "Elements (Ctrl + Shift + L)"
+ :class (when (:layers state)
+ "current")
+ :on-click #(swap! toolbar-state toggle-toolbox :layers)}
+ i/layers]
+ [:li.tooltip
+ {:alt "Feedback (Ctrl + Shift + M)"}
+ i/chat]]]])))
+
+(def ^:static toolbar
+ (util/component
+ {:render toolbar-render
+ :name "toolbar"
+ :mixins [rum/reactive]}))
diff --git a/frontend/uxbox/ui/workspace/workarea.cljs b/frontend/uxbox/ui/workspace/workarea.cljs
index 9dfbff67b..9b519da60 100644
--- a/frontend/uxbox/ui/workspace/workarea.cljs
+++ b/frontend/uxbox/ui/workspace/workarea.cljs
@@ -58,7 +58,6 @@
(defn grid-render
[own enabled? width height start-width start-height zoom]
- (println "grid-render")
(letfn [(vertical-line [position value padding]
(let [ticks-mod (/ 100 zoom)
step-size (/ 10 zoom)]
@@ -193,7 +192,6 @@
[]
(let [workspace (rum/react wb/workspace-state)
zoom 1]
- (println "viewport-render" (:grid-enabled workspace true))
(html
[:svg#viewport
{:width wb/viewport-height
@@ -208,7 +206,7 @@
:viewport-width wb/viewport-width
:document-start-x wb/document-start-x
:document-start-y wb/document-start-y})
- (grid (:grid-enabled workspace true)
+ (grid (:grid-enabled workspace false)
wb/viewport-width
wb/viewport-height
wb/document-start-x
@@ -227,7 +225,6 @@
(defn working-area-render
[own]
- (println "working-area-render")
(html
[:section.workspace-canvas
{:class "no-tool-bar"}