mirror of
https://github.com/penpot/penpot.git
synced 2025-02-23 23:35:58 -05:00
♻️ Refactor workspace layout initialization and persistence
This commit is contained in:
parent
965148f3a6
commit
19f4faa03f
4 changed files with 229 additions and 144 deletions
|
@ -34,6 +34,7 @@
|
|||
[app.main.data.workspace.guides :as dwgu]
|
||||
[app.main.data.workspace.interactions :as dwi]
|
||||
[app.main.data.workspace.layers :as dwly]
|
||||
[app.main.data.workspace.layout :as layout]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.data.workspace.notifications :as dwn]
|
||||
[app.main.data.workspace.path :as dwdp]
|
||||
|
@ -53,12 +54,10 @@
|
|||
[app.util.http :as http]
|
||||
[app.util.i18n :as i18n]
|
||||
[app.util.router :as rt]
|
||||
[app.util.storage :refer [storage]]
|
||||
[app.util.timers :as tm]
|
||||
[app.util.webapi :as wapi]
|
||||
[beicon.core :as rx]
|
||||
[cljs.spec.alpha :as s]
|
||||
[clojure.set :as set]
|
||||
[cuerdas.core :as str]
|
||||
[potok.core :as ptk]))
|
||||
|
||||
|
@ -74,69 +73,9 @@
|
|||
|
||||
;; --- Initialize Workspace
|
||||
|
||||
(s/def ::layout-flag
|
||||
#{:sitemap
|
||||
:layers
|
||||
:comments
|
||||
:assets
|
||||
:document-history
|
||||
:colorpalette
|
||||
:element-options
|
||||
:rules
|
||||
:display-grid
|
||||
:snap-grid
|
||||
:scale-text
|
||||
:dynamic-alignment
|
||||
:display-artboard-names
|
||||
:snap-guides})
|
||||
|
||||
(s/def ::layout-flags (s/coll-of ::layout-flag))
|
||||
|
||||
(def default-workspace-layout
|
||||
#{:sitemap
|
||||
:layers
|
||||
:element-options
|
||||
:rules
|
||||
:display-grid
|
||||
:snap-grid
|
||||
:dynamic-alignment
|
||||
:display-artboard-names
|
||||
:snap-guides})
|
||||
|
||||
(def layout-presets
|
||||
{:assets
|
||||
{:del #{:sitemap :layers :document-history}
|
||||
:add #{:assets}}
|
||||
|
||||
:document-history
|
||||
{:del #{:assets :layers :sitemap}
|
||||
:add #{:document-history}}
|
||||
|
||||
:layers
|
||||
{:del #{:document-history :assets}
|
||||
:add #{:sitemap :layers}}})
|
||||
|
||||
(s/def ::options-mode #{:design :prototype})
|
||||
|
||||
(def default-workspace-global
|
||||
{:options-mode :design})
|
||||
|
||||
(def default-workspace-local
|
||||
{:zoom 1})
|
||||
|
||||
(defn ensure-layout
|
||||
[lname]
|
||||
(ptk/reify ::ensure-layout
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :workspace-layout
|
||||
(fn [stored]
|
||||
(let [todel (get-in layout-presets [lname :del] #{})
|
||||
toadd (get-in layout-presets [lname :add] #{})]
|
||||
(-> stored
|
||||
(set/difference todel)
|
||||
(set/union toadd))))))))
|
||||
|
||||
(defn initialize
|
||||
[lname]
|
||||
(us/verify (s/nilable ::us/keyword) lname)
|
||||
|
@ -144,14 +83,14 @@
|
|||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update :workspace-layout #(or % default-workspace-layout))
|
||||
(update :workspace-global #(or % default-workspace-global))))
|
||||
(update :workspace-layout #(or % layout/default-layout))
|
||||
(update :workspace-global #(or % layout/default-global))))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(if (and lname (contains? layout-presets lname))
|
||||
(rx/of (ensure-layout lname))
|
||||
(rx/of (ensure-layout :layers))))))
|
||||
(if (and lname (contains? layout/presets lname))
|
||||
(rx/of (layout/ensure-layout lname))
|
||||
(rx/of (layout/ensure-layout :layers))))))
|
||||
|
||||
(defn initialize-file
|
||||
[project-id file-id]
|
||||
|
@ -247,7 +186,6 @@
|
|||
(rx/observe-on :async))))))
|
||||
|
||||
(declare go-to-page)
|
||||
(declare load-flag)
|
||||
|
||||
(defn initialize-page
|
||||
[page-id]
|
||||
|
@ -272,12 +210,8 @@
|
|||
(assoc :current-page-id id)
|
||||
(assoc :trimmed-page (dm/select-keys page [:id :name]))
|
||||
(assoc :workspace-local local)
|
||||
(update :workspace-layout
|
||||
#(if (load-flag :colorpalette false)
|
||||
(conj % :colorpalette)
|
||||
(disj % :colorpalette)))
|
||||
(assoc-in [:workspace-local :selected-palette] (load-flag :selected-palette :recent))
|
||||
(assoc-in [:workspace-local :selected-palette-colorpicker] (load-flag :selected-palette-colorpicker :recent))
|
||||
(update :workspace-layout layout/load-layout-flags)
|
||||
(update :workspace-global layout/load-layout-state)
|
||||
(update :workspace-global assoc :background-color (-> page :options :background))
|
||||
(update-in [:route :params :query] assoc :page-id (dm/str id))))
|
||||
state))))
|
||||
|
@ -395,76 +329,39 @@
|
|||
(->> (rp/mutation :rename-file params)
|
||||
(rx/ignore))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Local storage Flags Manipulation
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(def storeable-layout-flags #{:colorpalette})
|
||||
(def storeable-workspace-local-flags #{:selected-palette :selected-palette-colorpicker})
|
||||
|
||||
(defn store-layout-flags!
|
||||
[state flags]
|
||||
(doseq [item (filter storeable-layout-flags flags)]
|
||||
(swap! storage assoc item (contains? (:workspace-layout state) item))))
|
||||
|
||||
(defn store-workspace-local-flag!
|
||||
[flag value]
|
||||
(when (contains? storeable-workspace-local-flags flag)
|
||||
(swap! storage assoc flag value)))
|
||||
|
||||
(defn load-flag
|
||||
[flag default]
|
||||
(or (flag @storage) default))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Workspace State Manipulation
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; --- Toggle layout flag
|
||||
;; --- Layout Flags
|
||||
|
||||
(dm/export layout/toggle-layout-flag)
|
||||
(dm/export layout/remove-layout-flag)
|
||||
|
||||
;; --- Nudge
|
||||
|
||||
(defn update-nudge
|
||||
[{:keys [big small] :as params}]
|
||||
(ptk/reify ::update-nudge
|
||||
IDeref
|
||||
(-deref [_] (d/without-nils params))
|
||||
|
||||
(defn toggle-layout-flags
|
||||
[& flags]
|
||||
(ptk/reify ::toggle-layout-flags
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [new-state (update state :workspace-layout
|
||||
(fn [stored]
|
||||
(reduce (fn [flags flag]
|
||||
(if (contains? flags flag)
|
||||
(disj flags flag)
|
||||
(conj flags flag)))
|
||||
stored
|
||||
(d/concat-set flags))))]
|
||||
(store-layout-flags! new-state flags)
|
||||
new-state))))
|
||||
(update-in state [:profile :props :nudge]
|
||||
(fn [nudge]
|
||||
(cond-> nudge
|
||||
(number? big) (assoc :big big)
|
||||
(number? small) (assoc :small small)))))
|
||||
|
||||
(defn remove-layout-flags
|
||||
[& flags]
|
||||
(ptk/reify ::remove-layout-flags
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [new-state (update state :workspace-layout
|
||||
(fn [stored]
|
||||
(reduce disj stored (d/concat-set flags))))]
|
||||
(store-layout-flags! (:workspace-layout new-state) flags)
|
||||
new-state))))
|
||||
|
||||
;; --- Set workspace flag
|
||||
|
||||
(defn set-workspace-local-flag!
|
||||
[state flag value]
|
||||
(store-workspace-local-flag! flag value)
|
||||
(assoc-in state [:workspace-local flag] value))
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [nudge (get-in state [:profile :props :nudge])]
|
||||
(rx/of (du/update-profile-props {:nudge nudge}))))))
|
||||
|
||||
;; --- Set element options mode
|
||||
|
||||
(defn set-options-mode
|
||||
[mode]
|
||||
(us/assert ::options-mode mode)
|
||||
(ptk/reify ::set-options-mode
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:workspace-global :options-mode] mode))))
|
||||
(dm/export layout/set-options-mode)
|
||||
|
||||
;; --- Tooltip
|
||||
|
||||
|
@ -1100,8 +997,8 @@
|
|||
|
||||
(defn go-to-layout
|
||||
[layout]
|
||||
(us/verify ::layout-flag layout)
|
||||
(ptk/reify ::set-workspace-layout
|
||||
(us/verify ::layout/flag layout)
|
||||
(ptk/reify ::go-to-layout
|
||||
IDeref
|
||||
(-deref [_] {:layout layout})
|
||||
|
||||
|
@ -1154,7 +1051,7 @@
|
|||
|
||||
(defn go-to-component
|
||||
[component-id]
|
||||
(ptk/reify ::set-workspace-layout-component
|
||||
(ptk/reify ::go-to-component
|
||||
IDeref
|
||||
(-deref [_] {:layout :assets})
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
[app.common.colors :as clr]
|
||||
[app.common.data :as d]
|
||||
[app.main.data.modal :as md]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.changes :as dch]
|
||||
[app.main.data.workspace.layout :as layout]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
[app.main.data.workspace.texts :as dwt]
|
||||
[app.main.repo :as rp]
|
||||
|
@ -46,7 +46,12 @@
|
|||
(ptk/reify ::change-palette-selected
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(dw/set-workspace-local-flag! state :selected-palette selected))))
|
||||
(assoc-in state [:workspace-global :selected-palette] selected))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ state _]
|
||||
(let [wglobal (:workspace-global state)]
|
||||
(layout/persist-layout-state! wglobal)))))
|
||||
|
||||
(defn change-palette-selected-colorpicker
|
||||
"Change the library used by the color picker"
|
||||
|
@ -54,7 +59,12 @@
|
|||
(ptk/reify ::change-palette-selected-colorpicker
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(dw/set-workspace-local-flag! state :selected-palette-colorpicker selected))))
|
||||
(assoc-in state [:workspace-global :selected-palette-colorpicker] selected))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ state _]
|
||||
(let [wglobal (:workspace-global state)]
|
||||
(layout/persist-layout-state! wglobal)))))
|
||||
|
||||
(defn show-palette
|
||||
"Show the palette tool and change the library it uses"
|
||||
|
@ -62,9 +72,16 @@
|
|||
(ptk/reify ::show-palette
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update :workspace-layout conj :colorpalette)
|
||||
(dw/set-workspace-local-flag! :selected-palette selected)))))
|
||||
(assoc-in state [:workspace-global :selected-palette] selected))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/of (layout/toggle-layout-flag :colorpalette :force? true)))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ state _]
|
||||
(let [wglobal (:workspace-global state)]
|
||||
(layout/persist-layout-state! wglobal)))))
|
||||
|
||||
(defn start-picker
|
||||
[]
|
||||
|
|
171
frontend/src/app/main/data/workspace/layout.cljs
Normal file
171
frontend/src/app/main/data/workspace/layout.cljs
Normal file
|
@ -0,0 +1,171 @@
|
|||
;; 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) UXBOX Labs SL
|
||||
|
||||
(ns app.main.data.workspace.layout
|
||||
"Workspace layout management events and helpers."
|
||||
(:require
|
||||
[app.common.spec :as us]
|
||||
[app.util.storage :refer [storage]]
|
||||
[cljs.spec.alpha :as s]
|
||||
[clojure.set :as set]
|
||||
[potok.core :as ptk]))
|
||||
|
||||
(s/def ::flag
|
||||
#{:sitemap
|
||||
:layers
|
||||
:comments
|
||||
:assets
|
||||
:document-history
|
||||
:colorpalette
|
||||
:element-options
|
||||
:rules
|
||||
:display-grid
|
||||
:snap-grid
|
||||
:scale-text
|
||||
:dynamic-alignment
|
||||
:display-artboard-names
|
||||
:snap-guides})
|
||||
|
||||
(def presets
|
||||
{:assets
|
||||
{:del #{:sitemap :layers :document-history}
|
||||
:add #{:assets}}
|
||||
|
||||
:document-history
|
||||
{:del #{:assets :layers :sitemap}
|
||||
:add #{:document-history}}
|
||||
|
||||
:layers
|
||||
{:del #{:document-history :assets}
|
||||
:add #{:sitemap :layers}}})
|
||||
|
||||
(s/def ::options-mode #{:design :prototype})
|
||||
|
||||
(def default-layout
|
||||
#{:sitemap
|
||||
:layers
|
||||
:element-options
|
||||
:rules
|
||||
:display-grid
|
||||
:snap-grid
|
||||
:dynamic-alignment
|
||||
:display-artboard-names
|
||||
:snap-guides})
|
||||
|
||||
(def default-global
|
||||
{:options-mode :design})
|
||||
|
||||
(defn ensure-layout
|
||||
[name]
|
||||
(ptk/reify ::ensure-layout
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :workspace-layout
|
||||
(fn [stored]
|
||||
(let [todel (get-in presets [name :del] #{})
|
||||
toadd (get-in presets [name :add] #{})]
|
||||
(-> stored
|
||||
(set/difference todel)
|
||||
(set/union toadd))))))))
|
||||
|
||||
(declare persist-layout-flags!)
|
||||
|
||||
(defn toggle-layout-flag
|
||||
[flag & {:keys [force?] :as opts}]
|
||||
(ptk/reify ::toggle-layout-flag
|
||||
IDeref
|
||||
(-deref [_] {:name flag})
|
||||
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :workspace-layout
|
||||
(fn [flags]
|
||||
(if force?
|
||||
(conj flags flag)
|
||||
(if (contains? flags flag)
|
||||
(disj flags flag)
|
||||
(conj flags flag))))))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ state _]
|
||||
(let [flags (:workspace-layout state)]
|
||||
(persist-layout-flags! flags)))))
|
||||
|
||||
(defn remove-layout-flag
|
||||
[flag]
|
||||
(ptk/reify ::remove-layout-flag
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :workspace-layout
|
||||
(fn [flags]
|
||||
(disj flags flag))))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ state _]
|
||||
(let [flags (:workspace-layout state)]
|
||||
(persist-layout-flags! flags)))))
|
||||
|
||||
(defn set-options-mode
|
||||
[mode]
|
||||
(us/assert ::options-mode mode)
|
||||
(ptk/reify ::set-options-mode
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:workspace-global :options-mode] mode))))
|
||||
|
||||
(def layout-flags-persistence-mapping
|
||||
"A map of layout flags that should be persisted in local storage; the
|
||||
value corresponds to the key that will be used for save the data in
|
||||
storage object. It should be namespace qualified."
|
||||
{:colorpalette :app.main.data.workspace/show-colorpalette?
|
||||
:textpalette :app.main.data.workspace/show-textpalette?})
|
||||
|
||||
(defn load-layout-flags
|
||||
"Given the current layout flags, and updates them with the data
|
||||
stored in Storage."
|
||||
[layout]
|
||||
(reduce (fn [layout [flag key]]
|
||||
(condp = (get @storage key ::none)
|
||||
::none layout
|
||||
false (disj layout flag)
|
||||
true (conj layout flag)))
|
||||
layout
|
||||
layout-flags-persistence-mapping))
|
||||
|
||||
(defn persist-layout-flags!
|
||||
"Given a set of layout flags, and persist a subset of them to the Storage."
|
||||
[layout]
|
||||
(doseq [[flag key] layout-flags-persistence-mapping]
|
||||
(swap! storage assoc key (contains? layout flag))))
|
||||
|
||||
(def layout-state-persistence-mapping
|
||||
"A mapping of keys that need to be persisted from `:workspace-global` into Storage."
|
||||
{:selected-palette :app.main.data.workspace/selected-palette
|
||||
:selected-palette-colorpicker :app.main.data.workspace/selected-palette-colorpicker})
|
||||
|
||||
(defn load-layout-state
|
||||
"Given state (the :workspace-global) and update it with layout related
|
||||
props that are previously persisted in the Storage."
|
||||
[state]
|
||||
(reduce (fn [state [key skey]]
|
||||
(let [val (get @storage skey ::none)]
|
||||
(if (= val ::none)
|
||||
state
|
||||
(assoc state key val))))
|
||||
state
|
||||
layout-state-persistence-mapping))
|
||||
|
||||
(defn persist-layout-state!
|
||||
"Given state (the :workspace-global) and persists a subset of layout
|
||||
related props to the Storage."
|
||||
[state]
|
||||
(doseq [[key skey] layout-state-persistence-mapping]
|
||||
(let [val (get state key ::does-not-exist)]
|
||||
(if (= val ::does-not-exist)
|
||||
(swap! storage dissoc skey)
|
||||
(swap! storage assoc skey val)))))
|
||||
|
||||
|
|
@ -81,7 +81,7 @@
|
|||
(update [_ state]
|
||||
(let [text-state (some->> content ted/import-content)
|
||||
attrs (d/merge txt/default-text-attrs
|
||||
(get-in state [:workspace-local :defaults :font]))
|
||||
(get-in state [:workspace-global :default-font]))
|
||||
editor (cond-> (ted/create-editor-state text-state decorator)
|
||||
(and (nil? content) (some? attrs))
|
||||
(ted/update-editor-current-block-data attrs))]
|
||||
|
@ -406,5 +406,5 @@
|
|||
(let [multiple? (->> data vals (d/seek #(= % :multiple)))]
|
||||
(cond-> state
|
||||
(not multiple?)
|
||||
(assoc-in [:workspace-local :defaults :font] data))))))
|
||||
(assoc-in [:workspace-global :default-font] data))))))
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue