mirror of
https://github.com/penpot/penpot.git
synced 2025-01-06 14:50:20 -05:00
WIP: workspace toolbar and project/page state management.
This commit is contained in:
parent
c62425cbc8
commit
688d94c1da
6 changed files with 264 additions and 141 deletions
|
@ -3,6 +3,7 @@
|
|||
[uxbox.router :as r]
|
||||
[uxbox.state :as st]
|
||||
[uxbox.schema :as sc]
|
||||
[uxbox.time :as time]
|
||||
[bouncer.validators :as v]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -39,14 +40,14 @@
|
|||
(let [uuid (:id page)]
|
||||
(update-in state [:pages-by-id] assoc uuid page)))
|
||||
|
||||
;; (defn project-pages
|
||||
;; "Get a ordered list of pages that
|
||||
;; belongs to a specified project."
|
||||
;; [state projectid]
|
||||
;; (let [xf (comp
|
||||
;; (filter #(= projectid (:project %)))
|
||||
;; (map #(get-in state [:pages-by-id %])))]
|
||||
;; (into [] xf (:pages state))))
|
||||
(defn project-pages
|
||||
"Get a ordered list of pages that
|
||||
belongs to a specified project."
|
||||
[state projectid]
|
||||
(->> (vals (:pages-by-id state))
|
||||
(filter #(= projectid (:project %)))
|
||||
(sort-by :created)
|
||||
(into [])))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Events
|
||||
|
@ -60,6 +61,7 @@
|
|||
(-apply-update [_ state]
|
||||
(let [page {:id (random-uuid)
|
||||
:project project
|
||||
:created (time/now :unix)
|
||||
:name name
|
||||
:width width
|
||||
:height height}]
|
||||
|
@ -79,6 +81,7 @@
|
|||
(let [proj {:id uuid
|
||||
:name name
|
||||
:width width
|
||||
:created (time/now :unix)
|
||||
:height height
|
||||
:layout layout}]
|
||||
(assoc-project state proj)))
|
||||
|
@ -99,7 +102,9 @@
|
|||
(reify
|
||||
rs/UpdateEvent
|
||||
(-apply-update [_ state]
|
||||
(assoc state :workspace {:project projectid :page pageid}))
|
||||
(assoc state :workspace {:project projectid
|
||||
:page pageid
|
||||
:toolboxes {}}))
|
||||
|
||||
IPrintWithWriter
|
||||
(-pr-writer [mv writer _]
|
||||
|
@ -117,9 +122,10 @@
|
|||
(if pageid
|
||||
(rs/emit! (r/navigate :main/page {:project-uuid projectid
|
||||
:page-uuid pageid}))
|
||||
(let [pages (get-in state [:projects-by-id projectid :pages])]
|
||||
(let [pages (project-pages state projectid)
|
||||
pageid (:id (first pages))]
|
||||
(rs/emit! (r/navigate :main/page {:project-uuid projectid
|
||||
:page-uuid (first pages)})))))
|
||||
:page-uuid pageid})))))
|
||||
IPrintWithWriter
|
||||
(-pr-writer [mv writer _]
|
||||
(-write writer "#<event:u.s.p/go-to-project")))))
|
||||
|
|
|
@ -82,3 +82,13 @@
|
|||
"Redirect the user to other url."
|
||||
([name] (go name nil))
|
||||
([name params] (rs/emit! (navigate name params))))
|
||||
|
||||
(defn route-for
|
||||
"Given a location handler and optional parameter map, return the URI
|
||||
for such handler and parameters."
|
||||
([location]
|
||||
(bidi/path-for routes location))
|
||||
([location params]
|
||||
(apply bidi/path-for routes location (into []
|
||||
(mapcat (fn [[k v]] [k v]))
|
||||
params))))
|
||||
|
|
|
@ -1,13 +1,37 @@
|
|||
(ns uxbox.time
|
||||
(:require cljsjs.moment))
|
||||
(:require [cljsjs.moment]))
|
||||
|
||||
(defn parse
|
||||
([v]
|
||||
(js/moment v))
|
||||
([v format]
|
||||
(case format
|
||||
:unix (js/moment.unix v)
|
||||
(js/moment v format))))
|
||||
|
||||
(defn iso
|
||||
[v]
|
||||
(.toISOString v))
|
||||
|
||||
(defn unix
|
||||
[v]
|
||||
(.unix v))
|
||||
|
||||
(defn now
|
||||
([]
|
||||
(js/moment))
|
||||
([format]
|
||||
(case format
|
||||
:unix (unix (now))
|
||||
:iso (iso (now)))))
|
||||
|
||||
(defn ago
|
||||
[time]
|
||||
(.fromNow (js/moment time)))
|
||||
(.fromNow (parse time)))
|
||||
|
||||
(defn day
|
||||
[time]
|
||||
(.calendar (js/moment. time)
|
||||
(.calendar (parse time)
|
||||
nil
|
||||
#js {:sameDay "[Today]"
|
||||
:sameElse "[Today]"
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
:main/colors (ui.elements/colors)
|
||||
:main/page (let [projectid (:project-uuid location-params)
|
||||
pageid (:page-uuid location-params)]
|
||||
(rs/emit! (dp/initialize-workspace projectid pageid))
|
||||
(ui.w/workspace projectid pageid))
|
||||
nil
|
||||
)])))
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -10,92 +10,143 @@
|
|||
[uxbox.data.projects :as dp]
|
||||
[uxbox.ui.icons.dashboard :as icons]
|
||||
[uxbox.ui.icons :as i]
|
||||
[uxbox.ui.dom :as dom]
|
||||
[uxbox.ui.header :as ui.h]
|
||||
[uxbox.ui.lightbox :as lightbox]
|
||||
[uxbox.time :refer [ago]]))
|
||||
[uxbox.ui.header :as ui.h]
|
||||
[uxbox.ui.users :as ui.u]
|
||||
[uxbox.ui.navigation :as nav]
|
||||
[uxbox.ui.dom :as dom]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Header
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; (defn header-render
|
||||
;; [conn page grid? project-bar-visible?]
|
||||
;; (let [{page-title :page/title
|
||||
;; page-width :page/width
|
||||
;; page-height :page/height} page]
|
||||
;; [:header#workspace-bar.workspace-bar
|
||||
;; [:div.main-icon
|
||||
;; (nav/link (nav/route-for :dashboard) icons/logo-icon)]
|
||||
;; (project-tree page-title project-bar-visible?)
|
||||
;; [:div.workspace-options
|
||||
;; [:ul.options-btn
|
||||
;; [:li.tooltip.tooltip-bottom {:alt "Undo (Ctrl + Z)"}
|
||||
;; icons/undo]
|
||||
;; [:li.tooltip.tooltip-bottom {:alt "Redo (Ctrl + Shift + Z)"}
|
||||
;; icons/redo]]
|
||||
;; [:ul.options-btn
|
||||
;; ;; TODO: refactor
|
||||
;; [:li.tooltip.tooltip-bottom
|
||||
;; {:alt "Export (Ctrl + E)"}
|
||||
;; ;; page-title
|
||||
;; [:a {:download (str page-title ".svg")
|
||||
;; :href "#"
|
||||
;; :on-click (fn [e]
|
||||
;; (let [innerHTML (.-innerHTML (.getElementById js/document "page-layout"))
|
||||
;; width page-width
|
||||
;; height page-height
|
||||
;; html (str "<svg width='" width "' height='" height "'>" innerHTML "</svg>")
|
||||
;; data (js/Blob. #js [html] #js {:type "application/octet-stream"})
|
||||
;; url (.createObjectURL (.-URL js/window) data)]
|
||||
;; (set! (.-href (.-currentTarget e)) url)))}
|
||||
;; icons/export]]
|
||||
;; [:li.tooltip.tooltip-bottom
|
||||
;; {:alt "Image (Ctrl + I)"}
|
||||
;; icons/image]]
|
||||
;; [:ul.options-btn
|
||||
;; [:li.tooltip.tooltip-bottom
|
||||
;; {:alt "Ruler (Ctrl + R)"}
|
||||
;; icons/ruler]
|
||||
;; [:li.tooltip.tooltip-bottom
|
||||
;; {:alt "Grid (Ctrl + G)"
|
||||
;; :class (when (rum/react ws/grid?) "selected")
|
||||
;; :on-click ws/toggle-grid!}
|
||||
;; icons/grid]
|
||||
;; [:li.tooltip.tooltip-bottom
|
||||
;; {:alt "Align (Ctrl + A)"}
|
||||
;; icons/alignment]
|
||||
;; [:li.tooltip.tooltip-bottom
|
||||
;; {:alt "Organize (Ctrl + O)"}
|
||||
;; icons/organize]]]
|
||||
;; (user conn)]))
|
||||
|
||||
;; (def header
|
||||
;; (util/component
|
||||
;; {:render header-render
|
||||
;; :name "header"}))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Header
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(def project-state
|
||||
(def ^:static project-state
|
||||
(as-> (util/dep-in [:projects-by-id] [:workspace :project]) $
|
||||
(l/focus-atom $ s/state)))
|
||||
|
||||
(def page-state
|
||||
(def ^:static page-state
|
||||
(as-> (util/dep-in [:pages-by-id] [:workspace :page]) $
|
||||
(l/focus-atom $ s/state)))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; 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
|
||||
(nav/link (r/route-for :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 "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]}))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Header
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn workspace-render
|
||||
[own projectid]
|
||||
(html
|
||||
[:div "hello world"
|
||||
;; (header conn page ws/grid? project-bar-visible?)
|
||||
;; [:main.main-content
|
||||
;; [:section.workspace-content
|
||||
;; ;; Toolbar
|
||||
;; (toolbar open-toolboxes)
|
||||
[:div
|
||||
(header)
|
||||
[:main.main-content
|
||||
[:section.workspace-content
|
||||
;; Toolbar
|
||||
(toolbar)
|
||||
;; ;; Project bar
|
||||
;; (project-bar conn project page pages @project-bar-visible?)
|
||||
;; ;; Rules
|
||||
|
@ -106,11 +157,19 @@
|
|||
;; ;; 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))
|
||||
|
||||
(def ^:static workspace
|
||||
(util/component
|
||||
{:render workspace-render
|
||||
:will-mount workspace-will-mount
|
||||
:name "workspace"
|
||||
:mixins [rum/static]}))
|
||||
|
||||
|
|
Loading…
Reference in a new issue