0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-10 00:40:30 -05:00
penpot/frontend/uxbox/ui/workspace.cljs

313 lines
9.8 KiB
Text
Raw Normal View History

2015-12-14 13:31:21 -05:00
(ns uxbox.ui.workspace
(:require [sablono.core :as html :refer-macros [html]]
[rum.core :as rum]
[cats.labs.lens :as l]
[cuerdas.core :as str]
[uxbox.util :as util]
[uxbox.router :as r]
[uxbox.rstore :as rs]
[uxbox.state :as s]
[uxbox.data.projects :as dp]
[uxbox.ui.icons.dashboard :as icons]
[uxbox.ui.icons :as i]
[uxbox.ui.lightbox :as lightbox]
2015-12-15 16:54:50 -05:00
[uxbox.ui.keyboard :as k]
[uxbox.ui.users :as ui.u]
[uxbox.ui.navigation :as nav]
[uxbox.ui.dom :as dom]))
(def ^:static project-state
(as-> (util/dep-in [:projects-by-id] [:workspace :project]) $
(l/focus-atom $ s/state)))
(def ^:static page-state
(as-> (util/dep-in [:pages-by-id] [:workspace :page]) $
(l/focus-atom $ s/state)))
2015-12-14 13:31:21 -05:00
(def ^:static pages-state
(as-> (util/getter #(let [pid (get-in % [:workspace :project])]
(dp/project-pages % pid))) $
(l/focus-atom $ s/state)))
2015-12-14 13:31:21 -05:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Header
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn on-download-clicked
[event page]
(let [content (.-innerHTML (.getElementById js/document "page-layout"))
width (:width page)
height (:height page)
html (str "<svg width='" width "' height='" height "'>" content "</svg>")
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]
(let [page (rum/react page-state)]
(html
[:header#workspace-bar.workspace-bar
[:div.main-icon
2015-12-16 04:55:24 -05:00
(nav/link (r/route-for :main/dashboard) i/logo-icon)]
[:div.project-tree-btn
{:on-click (constantly nil)}
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 (constantly nil)}
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]}))
2015-12-14 13:31:21 -05:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Toolbar
2015-12-14 13:31:21 -05:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def ^:static toolbar-state
(as-> (l/in [:workspace :toolbars]) $
2015-12-14 13:31:21 -05:00
(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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2015-12-15 15:42:02 -05:00
(defn- project-sidebar-pageitem-render
2015-12-15 16:54:50 -05:00
[own parent page numpages]
2015-12-15 17:40:14 -05:00
(println "pageitem-render" (:id page))
2015-12-15 16:54:50 -05:00
(letfn [(on-edit [e]
(let [data {:edit true :form page}]
(reset! parent data)))]
2015-12-15 17:40:14 -05:00
(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]]]))))
2015-12-15 15:42:02 -05:00
(def project-sidebar-pageitem
(util/component
2015-12-15 15:42:02 -05:00
{:render project-sidebar-pageitem-render
:name "project-sidebar-pageitem"
2015-12-15 17:40:14 -05:00
:mixins [rum/reactive]}))
2015-12-15 15:42:02 -05:00
(defn- project-sidebar-pagelist-render
2015-12-15 17:40:14 -05:00
[own parent]
2015-12-15 15:42:02 -05:00
(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
2015-12-15 16:54:50 -05:00
(for [page pages]
2015-12-15 17:40:14 -05:00
(let [component (project-sidebar-pageitem parent page (count pages))]
2015-12-15 16:54:50 -05:00
(rum/with-key component (str (:id page)))))]
2015-12-15 15:42:02 -05:00
[:button.btn-primary.btn-small
2015-12-15 17:40:14 -05:00
{:on-click #(reset! parent {:edit true :form {}})}
2015-12-15 15:42:02 -05:00
"+ Add new page"]])))
2015-12-15 17:40:14 -05:00
(def project-sidebar-pagelist
(util/component
{:render project-sidebar-pagelist-render
:name "project-sidebar-pagelist"
:mixins [rum/reactive]}))
2015-12-15 15:42:02 -05:00
(defn- project-sidebar-form-render
[own parent]
2015-12-15 16:54:50 -05:00
(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-primary.btn-small
{:on-click on-cancel}
"Cancel"]]))))
2015-12-15 15:42:02 -05:00
(def project-sidebar-form
(util/component
{:render project-sidebar-form-render
:name "project-sidebar-form"
:mixins [rum/reactive]}))
(defn project-sidebar-render
[own]
2015-12-15 15:42:02 -05:00
(let [local (:rum/local own)
2015-12-15 17:40:14 -05:00
page (rum/react page-state)
2015-12-15 15:42:02 -05:00
project (rum/react project-state)]
(html
[:div#project-bar.project-bar
(when-not (:visible project true)
{:class "toggle"})
2015-12-15 15:42:02 -05:00
(if (:edit @local)
(project-sidebar-form local)
(project-sidebar-pagelist local))])))
(def project-sidebar
(util/component
{:render project-sidebar-render
:name "project-sidebar"
2015-12-15 15:42:02 -05:00
:mixins [rum/reactive (rum/local {:edit false :form {}})]}))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Workspace
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2015-12-14 13:31:21 -05:00
(defn workspace-render
[own projectid]
(html
[:div
(header)
[:main.main-content
[:section.workspace-content
;; Toolbar
(toolbar)
;; Project bar
(project-sidebar)
2015-12-14 13:31:21 -05:00
;; ;; Rules
;; (horizontal-rule (rum/react ws/zoom))
;; (vertical-rule (rum/react ws/zoom))
;; ;; Working area
;; (working-area conn @open-toolboxes page project shapes (rum/react ws/zoom) (rum/react ws/grid?))
;; ;; Aside
;; (when-not (empty? @open-toolboxes)
;; (aside conn open-toolboxes page shapes))
]]]))
(defn workspace-will-mount
[own]
(let [[projectid pageid] (:rum/props own)]
(println "workspace-will-mount" projectid pageid)
(rs/emit! (dp/initialize-workspace projectid pageid))
own))
2015-12-14 13:31:21 -05:00
2015-12-15 17:40:14 -05:00
(defn workspace-transfer-state
[old-state state]
(let [[projectid pageid] (:rum/props state)]
(println "workspace-transfer-state" old-state)
(println "workspace-transfer-state" state)
(rs/emit! (dp/initialize-workspace projectid pageid))))
2015-12-14 13:31:21 -05:00
(def ^:static workspace
(util/component
{:render workspace-render
:will-mount workspace-will-mount
2015-12-15 17:40:14 -05:00
:transfer-state workspace-transfer-state
2015-12-14 13:31:21 -05:00
:name "workspace"
:mixins [rum/static]}))