0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-04 13:50:12 -05:00

Merge pull request #5443 from penpot/niwinz-enhancements-1

 Several improvements
This commit is contained in:
Alejandro 2024-12-11 07:29:14 +01:00 committed by GitHub
commit 25a672b958
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
39 changed files with 420 additions and 410 deletions

View file

@ -20,8 +20,8 @@
:git/url "https://github.com/funcool/beicon.git"}
funcool/rumext
{:git/tag "v2.14"
:git/sha "0016623"
{:git/tag "v2.15"
:git/sha "28783a7"
:git/url "https://github.com/funcool/rumext.git"}
instaparse/instaparse {:mvn/version "1.5.0"}

View file

@ -23,7 +23,6 @@
[app.main.ui.confirm]
[app.main.ui.css-cursors :as cur]
[app.main.ui.delete-shared]
[app.main.ui.modal :refer [modal]]
[app.main.ui.routes :as rt]
[app.main.worker :as worker]
[app.plugins :as plugins]
@ -52,14 +51,9 @@
(let [el (dom/get-element "app")]
(mf/create-root el)))
(defonce modal-root
(let [el (dom/get-element "modal")]
(mf/create-root el)))
(defn init-ui
[]
(mf/render! app-root (mf/element ui/app))
(mf/render! modal-root (mf/element modal)))
(mf/render! app-root (mf/element ui/app)))
(defn- initialize-profile
"Event used mainly on application bootstrap; it fetches the profile
@ -132,9 +126,7 @@
;; The hard flag will force to unmount the whole UI and will redraw every component
(when hard?
(mf/unmount! app-root)
(mf/unmount! modal-root)
(set! app-root (mf/create-root (dom/get-element "app")))
(set! modal-root (mf/create-root (dom/get-element "modal"))))
(set! app-root (mf/create-root (dom/get-element "app"))))
(st/emit! (ev/initialize))
(init-ui)))

View file

@ -79,7 +79,7 @@
(let [current-file-id (get state :current-file-id)
path (if (= file-id current-file-id)
[:workspace-data]
[:workspace-libraries file-id :data])
[:libraries file-id :data])
undo-changes (if pending
(->> pending
@ -159,14 +159,14 @@
(let [file (:workspace-file state)]
(if (= (:id file) file-id)
(:revn file)
(dm/get-in state [:workspace-libraries file-id :revn]))))
(dm/get-in state [:libraries file-id :revn]))))
(defn- resolve-file-vern
[state file-id]
(let [file (:workspace-file state)]
(if (= (:id file) file-id)
(:vern file)
(dm/get-in state [:workspace-libraries file-id :vern]))))
(dm/get-in state [:libraries file-id :vern]))))
(defn commit-changes
"Schedules a list of changes to execute now, and add the corresponding undo changes to

View file

@ -52,7 +52,7 @@
(if-let [current-file-id (:current-file-id state)]
(if (= file-id current-file-id)
(update-in state [:workspace-file :revn] max revn)
(d/update-in-when state [:workspace-libraries file-id :revn] max revn))
(d/update-in-when state [:libraries file-id :revn] max revn))
state))
ptk/EffectEvent

View file

@ -172,7 +172,7 @@
(ptk/reify ::libraries-fetched
ptk/UpdateEvent
(update [_ state]
(assoc state :workspace-libraries (d/index-by :id libraries)))
(assoc state :libraries (d/index-by :id libraries)))
ptk/WatchEvent
(watch [_ state _]
@ -363,7 +363,7 @@
:workspace-data
:workspace-editor-state
:workspace-file
:workspace-libraries
:libraries
:workspace-media-objects
:workspace-persistence
:workspace-presence
@ -572,7 +572,7 @@
(let [file-data
(if (= file-id (:current-file-id state))
(:workspace-data state)
(get-in state [:workspace-libraries file-id :data]))
(get-in state [:libraries file-id :data]))
changes
(-> (pcb/empty-changes it)

View file

@ -59,11 +59,11 @@
;; Change this to :info :debug or :trace to debug this module, or :warn to reset to default
(log/set-level! :warn)
(defn- pretty-file
(defn- debug-pretty-file
[file-id state]
(if (= file-id (:current-file-id state))
"<local>"
(str "<" (get-in state [:workspace-libraries file-id :name]) ">")))
(str "<" (get-in state [:libraries file-id :name]) ">")))
(defn- log-changes
[changes file]
@ -760,9 +760,9 @@
ptk/UpdateEvent
(update [_ state]
(-> state
(update-in [:workspace-libraries library-id]
(update-in [:libraries library-id]
assoc :modified-at modified-at :revn revn)
(d/update-in-when [:workspace-libraries library-id :data]
(d/update-in-when [:libraries library-id :data]
ch/process-changes changes)))
ptk/WatchEvent
@ -898,7 +898,7 @@
current-file? (= current-file-id file-id)
data (if current-file?
(get state :workspace-data)
(get-in state [:workspace-libraries file-id :data]))
(get-in state [:libraries file-id :data]))
component (ctkl/get-component data component-id)
page-id (:main-instance-page component)
root-id (:main-instance-id component)]
@ -1022,7 +1022,7 @@
(watch [_ state _]
(let [undo-id (js/Symbol)]
(log/info :msg "COMPONENT-SWAP"
:file (pretty-file file-id state)
:file (debug-pretty-file file-id state)
:id-new-component id-new-component
:undo-id undo-id)
(rx/concat
@ -1068,15 +1068,15 @@
(update [_ state]
(if (and (not= library-id (:current-file-id state))
(nil? asset-id))
(d/assoc-in-when state [:workspace-libraries library-id :synced-at] (dt/now))
(d/assoc-in-when state [:libraries library-id :synced-at] (dt/now))
state))
ptk/WatchEvent
(watch [it state _]
(when (and (some? file-id) (some? library-id)) ; Prevent race conditions while navigating out of the file
(log/info :msg "SYNC-FILE"
:file (pretty-file file-id state)
:library (pretty-file library-id state)
:file (debug-pretty-file file-id state)
:library (debug-pretty-file library-id state)
:asset-type asset-type
:asset-id asset-id
:undo-group undo-group)
@ -1172,7 +1172,7 @@
(let [file-data (:workspace-data state)
ignore-until (dm/get-in state [:workspace-file :ignore-sync-until])
libraries-need-sync (filter #(seq (assets-need-sync % file-data ignore-until))
(vals (get state :workspace-libraries)))
(vals (get state :libraries)))
do-more-info #(modal/show! :libraries-dialog {:starting-tab "updates"})
do-update #(do (apply st/emit! (map (fn [library]
(sync-file (:current-file-id state)
@ -1359,7 +1359,7 @@
(let [libraries (:workspace-shared-files state)
library (d/seek #(= (:id %) library-id) libraries)]
(if library
(update state :workspace-libraries assoc library-id (dissoc library :library-summary))
(update state :libraries assoc library-id (dissoc library :library-summary))
state)))
ptk/WatchEvent
@ -1373,7 +1373,7 @@
(rx/merge-map fpmap/resolve-file)
(rx/map (fn [file]
(fn [state]
(assoc-in state [:workspace-libraries library-id] file)))))
(assoc-in state [:libraries library-id] file)))))
(->> (rp/cmd! :get-file-object-thumbnails {:file-id library-id :tag "component"})
(rx/map (fn [thumbnails]
(fn [state]
@ -1391,7 +1391,7 @@
ptk/UpdateEvent
(update [_ state]
(d/dissoc-in state [:workspace-libraries library-id]))
(d/dissoc-in state [:libraries library-id]))
ptk/WatchEvent
(watch [_ _ _]

View file

@ -314,6 +314,6 @@
(ptk/reify ::handle-library-change
ptk/WatchEvent
(watch [_ state _]
(when (contains? (:workspace-libraries state) file-id)
(when (contains? (:libraries state) file-id)
(rx/of (dwl/ext-library-changed file-id modified-at revn changes)
(dwl/notify-sync-file file-id))))))

View file

@ -29,7 +29,7 @@
(defn lookup-library-objects
[state file-id page-id]
(dm/get-in state [:workspace-libraries file-id :data :pages-index page-id :objects]))
(dm/get-in state [:libraries file-id :data :pages-index page-id :objects]))
(defn lookup-objects
[state file-id page-id]
@ -108,7 +108,7 @@
[state file-id]
(if (= file-id (:current-file-id state))
(get state :workspace-data)
(dm/get-in state [:workspace-libraries file-id :data])))
(dm/get-in state [:libraries file-id :data])))
(defn get-file-full
"Get the data content of the given file (it may be the current file
@ -117,13 +117,13 @@
(if (= file-id (:current-file-id state))
(-> (get state :workspace-file)
(assoc :data (get state :workspace-data)))
(dm/get-in state [:workspace-libraries file-id :data])))
(dm/get-in state [:libraries file-id :data])))
(defn get-libraries
"Retrieve all libraries, including the local file."
[state]
(let [{:keys [id] :as local} (:workspace-data state)]
(-> (:workspace-libraries state)
(-> (:libraries state)
(assoc id {:id id
:data local}))))

View file

@ -233,10 +233,8 @@
(l/derived :workspace-data st/state))
(def workspace-file-colors
(l/derived (fn [data]
(when data
(->> (:colors data)
(d/mapm #(assoc %2 :file-id (:id data))))))
(l/derived (fn [{:keys [id] :as data}]
(some-> (:colors data) (update-vals #(assoc % :file-id id))))
workspace-data
=))
@ -246,6 +244,8 @@
(dm/get-in state [:recent-colors file-id])))
st/state))
;; FIXME: fonts are not prefixed, so the recent font list is shared
;; across all teams. This may not be expected behavior
(def workspace-recent-fonts
(l/derived (fn [data]
(get data :recent-fonts []))
@ -254,25 +254,9 @@
(def workspace-file-typography
(l/derived :typographies workspace-data))
(def workspace-local-library
(l/derived (fn [state]
(select-keys (:workspace-data state)
[:id
:colors
:media
:typographies
:components]))
st/state =))
(def workspace-libraries
(l/derived :workspace-libraries st/state))
(def workspace-presence
(l/derived :workspace-presence st/state))
(def workspace-snap-data
(l/derived :workspace-snap-data st/state))
(def workspace-page
(l/derived (fn [state]
(let [page-id (:current-page-id state)
@ -618,13 +602,6 @@
[id]
(l/derived #(get % id) workspace-grid-edition))
;; FIXME: remove
(def current-file-id
(l/derived :current-file-id st/state))
(def current-project-id
(l/derived :current-project-id st/state))
(def workspace-preview-blend
(l/derived :workspace-preview-blend st/state))

View file

@ -29,6 +29,7 @@
[app.main.ui.dashboard.team :refer [team-settings-page* team-members-page* team-invitations-page* webhooks-page*]]
[app.main.ui.dashboard.templates :refer [templates-section*]]
[app.main.ui.hooks :as hooks]
[app.main.ui.modal :refer [modal-container*]]
[app.main.ui.workspace.plugins]
[app.plugins.register :as preg]
[app.util.dom :as dom]
@ -240,6 +241,7 @@
(use-plugin-register plugin-url team-id (:id default-project))
[:& (mf/provider ctx/current-project-id) {:value project-id}
[:> modal-container*]
;; NOTE: dashboard events and other related functions assumes
;; that the team is a implicit context variable that is
;; available using react context or accessing

View file

@ -7,7 +7,8 @@
(ns app.main.ui.modal
(:require-macros [app.main.style :as stl])
(:require
[app.main.data.modal :as dm]
[app.common.data.macros :as dm]
[app.main.data.modal :as modal]
[app.main.store :as st]
[app.util.dom :as dom]
[app.util.keyboard :as k]
@ -20,13 +21,13 @@
[event allow-click-outside]
(when (and (k/esc? event) (not allow-click-outside))
(dom/stop-propagation event)
(st/emit! (dm/hide))))
(st/emit! (modal/hide))))
(defn- on-pop-state
[event]
(dom/prevent-default event)
(dom/stop-propagation event)
(st/emit! (dm/hide))
(st/emit! (modal/hide))
(.forward js/history))
(defn- on-click-outside
@ -41,15 +42,14 @@
(= (.-button event) 0))
(dom/stop-propagation event)
(dom/prevent-default event)
(st/emit! (dm/hide)))))
(st/emit! (modal/hide)))))
(mf/defc modal-wrapper
{::mf/wrap-props false
(mf/defc modal-wrapper*
{::mf/props :obj
::mf/wrap [mf/memo]}
[props]
(let [data (unchecked-get props "data")
wrapper-ref (mf/use-ref nil)
components (mf/deref dm/components)
[{:keys [data]}]
(let [wrapper-ref (mf/use-ref nil)
components (mf/deref modal/components)
allow-click-outside (:allow-click-outside data)
@ -61,31 +61,29 @@
(fn [event]
(on-esc-clicked event allow-click-outside))]
(mf/use-layout-effect
(mf/deps allow-click-outside)
(fn []
(let [keys [(events/listen js/window EventType.POPSTATE on-pop-state)
(events/listen js/document EventType.KEYDOWN handle-keydown)
(mf/with-effect [allow-click-outside]
(let [keys [(events/listen js/window EventType.POPSTATE on-pop-state)
(events/listen js/document EventType.KEYDOWN handle-keydown)
;; Changing to js/document breaks the color picker
(events/listen (dom/get-root) EventType.POINTERDOWN handle-click-outside)
;; Changing to js/document breaks the color picker
(events/listen (dom/get-root) EventType.POINTERDOWN handle-click-outside)
(events/listen js/document EventType.CONTEXTMENU handle-click-outside)]]
#(doseq [key keys]
(events/unlistenByKey key)))))
(events/listen js/document EventType.CONTEXTMENU handle-click-outside)]]
(fn []
(run! events/unlistenByKey keys))))
(when-let [component (get components (:type data))]
[:div {:ref wrapper-ref
:class (stl/css :modal-wrapper)}
(mf/element component (:props data))])))
(def modal-ref
(l/derived ::dm/modal st/state))
(def ^:private ref:modal
(l/derived ::modal/modal st/state))
(mf/defc modal
{::mf/wrap-props false}
(mf/defc modal-container*
{::mf/props :obj}
[]
(let [modal (mf/deref modal-ref)]
(when modal
[:& modal-wrapper {:data modal
:key (:id modal)}])))
(when-let [modal (mf/deref ref:modal)]
(mf/portal
(mf/html [:> modal-wrapper* {:data modal :key (dm/str (:id modal))}])
(.-body js/document))))

View file

@ -12,6 +12,7 @@
[app.main.router :as rt]
[app.main.store :as st]
[app.main.ui.hooks :as hooks]
[app.main.ui.modal :refer [modal-container*]]
[app.main.ui.settings.access-tokens :refer [access-tokens-page]]
[app.main.ui.settings.change-email]
[app.main.ui.settings.delete-account]
@ -41,25 +42,29 @@
(when (nil? profile)
(st/emit! (rt/nav :auth-login))))
[:section {:class (stl/css :dashboard-layout-refactor :dashboard)}
[:& sidebar {:profile profile
:section section}]
[:*
[:> modal-container*]
[:section {:class (stl/css :dashboard-layout-refactor :dashboard)}
[:div {:class (stl/css :dashboard-content)}
[:& header]
[:section {:class (stl/css :dashboard-container)}
(case section
:settings-profile
[:& profile-page]
:settings-feedback
[:& feedback-page]
[:& sidebar {:profile profile
:section section}]
:settings-password
[:& password-page]
[:div {:class (stl/css :dashboard-content)}
[:& header]
[:section {:class (stl/css :dashboard-container)}
(case section
:settings-profile
[:& profile-page]
:settings-options
[:& options-page]
:settings-feedback
[:& feedback-page]
:settings-access-tokens
[:& access-tokens-page])]]]))
:settings-password
[:& password-page]
:settings-options
[:& options-page]
:settings-access-tokens
[:& access-tokens-page])]]]]))

View file

@ -25,6 +25,7 @@
[app.main.ui.ds.product.loader :refer [loader*]]
[app.main.ui.hooks :as hooks]
[app.main.ui.icons :as i]
[app.main.ui.modal :refer [modal-container*]]
[app.main.ui.viewer.comments :refer [comments-layer comments-sidebar*]]
[app.main.ui.viewer.header :as header]
[app.main.ui.viewer.inspect :as inspect]
@ -633,7 +634,9 @@
(if-let [data (mf/deref refs/viewer-data)]
(let [props (obj/merge props #js {:data data :key (dm/str file-id)})]
[:> viewer-content* props])
[:*
[:> modal-container*]
[:> viewer-content* props]])
[:> loader* {:title (tr "labels.loading")
:overlay true}]))

View file

@ -39,7 +39,7 @@
mf/deref)
colors-library-ws (-> (mf/use-memo
(mf/deps (:file-id color))
#(make-colors-library-ref :workspace-libraries (:file-id color)))
#(make-colors-library-ref :libraries (:file-id color)))
mf/deref)]
(or colors-library-v colors-library-ws)))

View file

@ -59,7 +59,7 @@
file-typographies-viewer (mf/deref file-typographies-ref)
file-typographies-workspace (mf/deref refs/workspace-file-typography)
file-library-workspace (get (mf/deref refs/workspace-libraries) (:typography-ref-file style))
file-library-workspace (get (mf/deref refs/libraries) (:typography-ref-file style))
typography-external-lib (get-in file-library-workspace [:data :typographies (:typography-ref-id style)])
color-format (mf/use-state :hex)

View file

@ -7,7 +7,6 @@
(ns app.main.ui.viewer.inspect.right-sidebar
(:require-macros [app.main.style :as stl])
(:require
[app.common.data.macros :as dm]
[app.common.types.component :as ctk]
[app.main.data.event :as ev]
[app.main.refs :as refs]
@ -29,14 +28,14 @@
(if (= from :workspace)
(let [workspace-data (deref refs/workspace-data)
{:keys [id] :as local} workspace-data
libraries (deref refs/workspace-libraries)]
libraries (deref refs/libraries)]
(-> libraries
(assoc id {:id id
:data local})))
(let [viewer-data (deref refs/viewer-data)
local (get-in viewer-data [:file :data])
id (deref refs/current-file-id)
libraries (:libraries viewer-data)]
id (get local :id)
libraries (:libraries viewer-data)]
(-> libraries
(assoc id {:id id
:data local})))))
@ -48,17 +47,13 @@
objects (or objects (:objects page))
shapes (or shapes
(resolve-shapes objects selected))
first-shape (first shapes)
page-id (or page-id (:id page))
file-id (or file-id (:id file))
libraries (get-libraries from)
file (mf/deref refs/viewer-file)
components-v2 (dm/get-in file [:data :options :components-v2])
main-instance? (if components-v2
(ctk/main-instance? first-shape)
true)
main-instance? (ctk/main-instance? first-shape)
handle-change-tab
(mf/use-fn

View file

@ -19,6 +19,7 @@
[app.main.ui.ds.product.loader :refer [loader*]]
[app.main.ui.hooks :as hooks]
[app.main.ui.hooks.resize :refer [use-resize-observer]]
[app.main.ui.modal :refer [modal-container*]]
[app.main.ui.workspace.colorpicker]
[app.main.ui.workspace.context-menu :refer [context-menu]]
[app.main.ui.workspace.coordinates :as coordinates]
@ -162,7 +163,7 @@
(mf/defc workspace*
{::mf/wrap-props false
{::mf/props :obj
::mf/wrap [mf/memo]}
[{:keys [project-id file-id page-id layout-name]}]
@ -211,6 +212,7 @@
[:& (mf/provider ctx/components-v2) {:value components-v2?}
[:& (mf/provider ctx/design-tokens) {:value design-tokens?}
[:& (mf/provider ctx/workspace-read-only?) {:value read-only?}
[:> modal-container*]
[:section {:class (stl/css :workspace)
:style {:background-color background-color
:touch-action "none"}}

View file

@ -157,7 +157,7 @@
[{:keys [size width selected] :as props}]
(let [recent-colors (mf/deref refs/workspace-recent-colors)
file-colors (mf/deref refs/workspace-file-colors)
shared-libs (mf/deref refs/workspace-libraries)
shared-libs (mf/deref refs/libraries)
colors (mf/use-state [])]
(mf/with-effect [selected shared-libs]

View file

@ -19,7 +19,7 @@
[{:keys [show-menu? close-menu on-select-palette selected]}]
(let [recent-colors (mf/deref refs/workspace-recent-colors)
file-colors (mf/deref refs/workspace-file-colors)
shared-libs (mf/deref refs/workspace-libraries)]
shared-libs (mf/deref refs/libraries)]
[:& dropdown {:show show-menu?
:on-close close-menu}
[:ul {:class (stl/css :palette-menu)}

View file

@ -30,7 +30,7 @@
(let [selected (h/use-shared-state mdc/colorpicker-selected-broadcast-key :recent)
current-colors (mf/use-state [])
shared-libs (mf/deref refs/workspace-libraries)
shared-libs (mf/deref refs/libraries)
file-colors (mf/deref refs/workspace-file-colors)
recent-colors (mf/deref refs/workspace-recent-colors)
recent-colors (h/use-equal-memo (filter #(or (:gradient %) (:color %) (:image %)) recent-colors))

View file

@ -49,14 +49,15 @@
(dom/prevent-default event)
(dom/stop-propagation event))
(mf/defc menu-entry
{::mf/props :obj}
(mf/defc menu-entry*
{::mf/props :obj
::mf/private true}
[{:keys [title shortcut on-click on-pointer-enter on-pointer-leave
on-unmount children selected? icon disabled value]}]
on-unmount children is-selected icon disabled value]}]
(let [submenu-ref (mf/use-ref nil)
hovering? (mf/use-ref false)
on-pointer-enter
(mf/use-callback
(mf/use-fn
(fn []
(mf/set-ref-val! hovering? true)
(let [submenu-node (mf/ref-val submenu-ref)]
@ -65,7 +66,7 @@
(when on-pointer-enter (on-pointer-enter))))
on-pointer-leave
(mf/use-callback
(mf/use-fn
(fn []
(mf/set-ref-val! hovering? false)
(let [submenu-node (mf/ref-val submenu-ref)]
@ -77,7 +78,7 @@
(when on-pointer-leave (on-pointer-leave))))
set-dom-node
(mf/use-callback
(mf/use-fn
(fn [dom]
(let [submenu-node (mf/ref-val submenu-ref)]
(when (and (some? dom) (some? submenu-node))
@ -97,8 +98,8 @@
:on-pointer-leave on-pointer-leave}
[:span
{:class (stl/css :icon-wrapper)}
(if selected? [:span {:class (stl/css :selected-icon)}
i/tick]
(if is-selected [:span {:class (stl/css :selected-icon)}
i/tick]
[:span {:class (stl/css :selected-icon)}])
[:span {:class (stl/css :shape-icon)} icon]]
[:span {:class (stl/css :title)} title]]
@ -126,34 +127,40 @@
:on-context-menu prevent-default}
children])])))
(mf/defc menu-separator
(mf/defc menu-separator*
{::mf/props :obj
::mf/private true}
[]
[:li {:class (stl/css :separator)}])
(mf/defc context-menu-edit
[_]
(mf/defc context-menu-edit*
{::mf/props :obj
::mf/private true}
[]
(let [do-copy #(st/emit! (dw/copy-selected))
do-cut #(st/emit! (dw/copy-selected)
(dw/delete-selected))
do-paste #(st/emit! (dw/paste-from-clipboard))
do-duplicate #(st/emit! (dw/duplicate-selected true))]
[:*
[:& menu-entry {:title (tr "workspace.shape.menu.copy")
:shortcut (sc/get-tooltip :copy)
:on-click do-copy}]
[:& menu-entry {:title (tr "workspace.shape.menu.cut")
:shortcut (sc/get-tooltip :cut)
:on-click do-cut}]
[:& menu-entry {:title (tr "workspace.shape.menu.paste")
:shortcut (sc/get-tooltip :paste)
:on-click do-paste}]
[:& menu-entry {:title (tr "workspace.shape.menu.duplicate")
:shortcut (sc/get-tooltip :duplicate)
:on-click do-duplicate}]
[:> menu-entry* {:title (tr "workspace.shape.menu.copy")
:shortcut (sc/get-tooltip :copy)
:on-click do-copy}]
[:> menu-entry* {:title (tr "workspace.shape.menu.cut")
:shortcut (sc/get-tooltip :cut)
:on-click do-cut}]
[:> menu-entry* {:title (tr "workspace.shape.menu.paste")
:shortcut (sc/get-tooltip :paste)
:on-click do-paste}]
[:> menu-entry* {:title (tr "workspace.shape.menu.duplicate")
:shortcut (sc/get-tooltip :duplicate)
:on-click do-duplicate}]
[:& menu-separator]]))
[:> menu-separator* {}]]))
(mf/defc context-menu-layer-position
(mf/defc context-menu-layer-position*
{::mf/props :obj
::mf/private true}
[{:keys [shapes]}]
(let [do-bring-forward (mf/use-fn #(st/emit! (dw/vertical-order-selected :up)))
do-bring-to-front (mf/use-fn #(st/emit! (dw/vertical-order-selected :top)))
@ -173,46 +180,50 @@
[:*
(when (> (count hover-objs) 1)
[:& menu-entry {:title (tr "workspace.shape.menu.select-layer")}
[:> menu-entry* {:title (tr "workspace.shape.menu.select-layer")}
(for [object hover-objs]
[:& menu-entry {:title (:name object)
:key (dm/str (:id object))
:selected? (some #(= object %) shapes)
:on-click (select-shapes (:id object))
:on-pointer-enter (on-pointer-enter (:id object))
:on-pointer-leave (on-pointer-leave (:id object))
:on-unmount (on-unmount (:id object))
:icon (sic/element-icon {:shape object})}])])
[:& menu-entry {:title (tr "workspace.shape.menu.forward")
:shortcut (sc/get-tooltip :bring-forward)
:on-click do-bring-forward}]
[:& menu-entry {:title (tr "workspace.shape.menu.front")
:shortcut (sc/get-tooltip :bring-front)
:on-click do-bring-to-front}]
[:& menu-entry {:title (tr "workspace.shape.menu.backward")
:shortcut (sc/get-tooltip :bring-backward)
:on-click do-send-backward}]
[:& menu-entry {:title (tr "workspace.shape.menu.back")
:shortcut (sc/get-tooltip :bring-back)
:on-click do-send-to-back}]
[:> menu-entry* {:title (:name object)
:key (dm/str (:id object))
:is-selected (some #(= object %) shapes)
:on-click (select-shapes (:id object))
:on-pointer-enter (on-pointer-enter (:id object))
:on-pointer-leave (on-pointer-leave (:id object))
:on-unmount (on-unmount (:id object))
:icon (sic/element-icon {:shape object})}])])
[:> menu-entry* {:title (tr "workspace.shape.menu.forward")
:shortcut (sc/get-tooltip :bring-forward)
:on-click do-bring-forward}]
[:> menu-entry* {:title (tr "workspace.shape.menu.front")
:shortcut (sc/get-tooltip :bring-front)
:on-click do-bring-to-front}]
[:> menu-entry* {:title (tr "workspace.shape.menu.backward")
:shortcut (sc/get-tooltip :bring-backward)
:on-click do-send-backward}]
[:> menu-entry* {:title (tr "workspace.shape.menu.back")
:shortcut (sc/get-tooltip :bring-back)
:on-click do-send-to-back}]
[:& menu-separator]]))
[:> menu-separator* {}]]))
(mf/defc context-menu-flip
(mf/defc context-menu-flip*
{::mf/props :obj
::mf/private true}
[]
(let [do-flip-vertical #(st/emit! (dw/flip-vertical-selected))
do-flip-horizontal #(st/emit! (dw/flip-horizontal-selected))]
[:*
[:& menu-entry {:title (tr "workspace.shape.menu.flip-vertical")
:shortcut (sc/get-tooltip :flip-vertical)
:on-click do-flip-vertical}]
[:> menu-entry* {:title (tr "workspace.shape.menu.flip-vertical")
:shortcut (sc/get-tooltip :flip-vertical)
:on-click do-flip-vertical}]
[:& menu-entry {:title (tr "workspace.shape.menu.flip-horizontal")
:shortcut (sc/get-tooltip :flip-horizontal)
:on-click do-flip-horizontal}]
[:& menu-separator]]))
[:> menu-entry* {:title (tr "workspace.shape.menu.flip-horizontal")
:shortcut (sc/get-tooltip :flip-horizontal)
:on-click do-flip-horizontal}]
[:> menu-separator* {}]]))
(mf/defc context-menu-thumbnail
(mf/defc context-menu-thumbnail*
{::mf/props :obj
::mf/private true}
[{:keys [shapes]}]
(let [single? (= (count shapes) 1)
has-frame? (some cfh/frame-shape? shapes)
@ -220,26 +231,29 @@
(when (and single? has-frame?)
[:*
(if (every? :use-for-thumbnail shapes)
[:& menu-entry {:title (tr "workspace.shape.menu.thumbnail-remove")
:on-click do-toggle-thumbnail}]
[:& menu-entry {:title (tr "workspace.shape.menu.thumbnail-set")
:shortcut (sc/get-tooltip :thumbnail-set)
:on-click do-toggle-thumbnail}])
[:& menu-separator]])))
[:> menu-entry* {:title (tr "workspace.shape.menu.thumbnail-remove")
:on-click do-toggle-thumbnail}]
[:> menu-entry* {:title (tr "workspace.shape.menu.thumbnail-set")
:shortcut (sc/get-tooltip :thumbnail-set)
:on-click do-toggle-thumbnail}])
[:> menu-separator* {}]])))
(mf/defc context-menu-rename
(mf/defc context-menu-rename*
{::mf/props :obj
::mf/private true}
[{:keys [shapes]}]
(let [do-rename #(st/emit! (dw/start-rename-selected))]
(when (= (count shapes) 1)
[:*
[:& menu-separator]
[:& menu-entry {:title (tr "workspace.shape.menu.rename")
:shortcut (sc/get-tooltip :rename)
:on-click do-rename}]])))
[:> menu-separator* {}]
[:> menu-entry* {:title (tr "workspace.shape.menu.rename")
:shortcut (sc/get-tooltip :rename)
:on-click do-rename}]])))
(mf/defc context-menu-group
(mf/defc context-menu-group*
{::mf/props :obj
::mf/private true}
[{:keys [shapes]}]
(let [multiple? (> (count shapes) 1)
single? (= (count shapes) 1)
@ -266,42 +280,46 @@
(when (not any-in-copy?)
[:*
(when (or has-bool? has-group? has-mask? has-frame?)
[:& menu-entry {:title (tr "workspace.shape.menu.ungroup")
:shortcut (sc/get-tooltip :ungroup)
:on-click do-remove-group}])
[:> menu-entry* {:title (tr "workspace.shape.menu.ungroup")
:shortcut (sc/get-tooltip :ungroup)
:on-click do-remove-group}])
[:& menu-entry {:title (tr "workspace.shape.menu.group")
:shortcut (sc/get-tooltip :group)
:on-click do-create-group}]
[:> menu-entry* {:title (tr "workspace.shape.menu.group")
:shortcut (sc/get-tooltip :group)
:on-click do-create-group}]
(when (or multiple? (and is-group? (not has-mask?)) is-bool?)
[:& menu-entry {:title (tr "workspace.shape.menu.mask")
:shortcut (sc/get-tooltip :mask)
:on-click do-mask-group}])
[:> menu-entry* {:title (tr "workspace.shape.menu.mask")
:shortcut (sc/get-tooltip :mask)
:on-click do-mask-group}])
(when has-mask?
[:& menu-entry {:title (tr "workspace.shape.menu.unmask")
:shortcut (sc/get-tooltip :unmask)
:on-click do-unmask-group}])
[:> menu-entry* {:title (tr "workspace.shape.menu.unmask")
:shortcut (sc/get-tooltip :unmask)
:on-click do-unmask-group}])
[:& menu-entry {:title (tr "workspace.shape.menu.create-artboard-from-selection")
:shortcut (sc/get-tooltip :artboard-selection)
:on-click do-create-artboard-from-selection}]
[:& menu-separator]])]))
[:> menu-entry* {:title (tr "workspace.shape.menu.create-artboard-from-selection")
:shortcut (sc/get-tooltip :artboard-selection)
:on-click do-create-artboard-from-selection}]
[:> menu-separator* {}]])]))
(mf/defc context-focus-mode-menu
[{:keys []}]
(mf/defc context-focus-mode-menu*
{::mf/props :obj
::mf/private true}
[]
(let [focus (mf/deref refs/workspace-focus-selected)
do-toggle-focus-mode #(st/emit! (dw/toggle-focus-mode))]
[:& menu-entry {:title (if (empty? focus)
(tr "workspace.focus.focus-on")
(tr "workspace.focus.focus-off"))
:shortcut (sc/get-tooltip :toggle-focus-mode)
:on-click do-toggle-focus-mode}]))
[:> menu-entry* {:title (if (empty? focus)
(tr "workspace.focus.focus-on")
(tr "workspace.focus.focus-off"))
:shortcut (sc/get-tooltip :toggle-focus-mode)
:on-click do-toggle-focus-mode}]))
(mf/defc context-menu-path
[{:keys [shapes disable-flatten? disable-booleans?]}]
(mf/defc context-menu-path*
{::mf/props :obj
::mf/private true}
[{:keys [shapes disable-flatten disable-booleans]}]
(let [multiple? (> (count shapes) 1)
single? (= (count shapes) 1)
@ -330,37 +348,39 @@
(st/emit! (dw/change-bool-type (-> shapes first :id) bool-type))))]
[:*
(when (and single? (not is-frame?))
[:& menu-entry {:title (tr "workspace.shape.menu.edit")
:shortcut (sc/get-tooltip :start-editing)
:on-click do-start-editing}])
[:> menu-entry* {:title (tr "workspace.shape.menu.edit")
:shortcut (sc/get-tooltip :start-editing)
:on-click do-start-editing}])
(when-not (or disable-flatten? has-frame? has-path?)
[:& menu-entry {:title (tr "workspace.shape.menu.transform-to-path")
:on-click do-transform-to-path}])
(when-not (or disable-flatten has-frame? has-path?)
[:> menu-entry* {:title (tr "workspace.shape.menu.transform-to-path")
:on-click do-transform-to-path}])
(when (and (not disable-booleans?)
(when (and (not disable-booleans)
(or multiple? (and single? (or is-group? is-bool?))))
[:& menu-entry {:title (tr "workspace.shape.menu.path")}
[:& menu-entry {:title (tr "workspace.shape.menu.union")
:shortcut (sc/get-tooltip :bool-union)
:on-click (make-do-bool :union)}]
[:& menu-entry {:title (tr "workspace.shape.menu.difference")
:shortcut (sc/get-tooltip :bool-difference)
:on-click (make-do-bool :difference)}]
[:& menu-entry {:title (tr "workspace.shape.menu.intersection")
:shortcut (sc/get-tooltip :bool-intersection)
:on-click (make-do-bool :intersection)}]
[:& menu-entry {:title (tr "workspace.shape.menu.exclude")
:shortcut (sc/get-tooltip :bool-exclude)
:on-click (make-do-bool :exclude)}]
[:> menu-entry* {:title (tr "workspace.shape.menu.path")}
[:> menu-entry* {:title (tr "workspace.shape.menu.union")
:shortcut (sc/get-tooltip :bool-union)
:on-click (make-do-bool :union)}]
[:> menu-entry* {:title (tr "workspace.shape.menu.difference")
:shortcut (sc/get-tooltip :bool-difference)
:on-click (make-do-bool :difference)}]
[:> menu-entry* {:title (tr "workspace.shape.menu.intersection")
:shortcut (sc/get-tooltip :bool-intersection)
:on-click (make-do-bool :intersection)}]
[:> menu-entry* {:title (tr "workspace.shape.menu.exclude")
:shortcut (sc/get-tooltip :bool-exclude)
:on-click (make-do-bool :exclude)}]
(when (and single? is-bool? (not disable-flatten?))
(when (and single? is-bool? (not disable-flatten))
[:*
[:& menu-separator]
[:& menu-entry {:title (tr "workspace.shape.menu.flatten")
:on-click do-transform-to-path}]])])]))
[:> menu-separator* {}]
[:> menu-entry* {:title (tr "workspace.shape.menu.flatten")
:on-click do-transform-to-path}]])])]))
(mf/defc context-menu-layer-options
(mf/defc context-menu-layer-options*
{::mf/props :obj
::mf/private true}
[{:keys [shapes]}]
(let [ids (mapv :id shapes)
do-show-shape #(st/emit! (dw/update-shape-flags ids {:hidden false}))
@ -369,23 +389,24 @@
do-unlock-shape #(st/emit! (dw/update-shape-flags ids {:blocked false}))]
[:*
(if (every? :hidden shapes)
[:& menu-entry {:title (tr "workspace.shape.menu.show")
:shortcut (sc/get-tooltip :toggle-visibility)
:on-click do-show-shape}]
[:& menu-entry {:title (tr "workspace.shape.menu.hide")
:shortcut (sc/get-tooltip :toggle-visibility)
:on-click do-hide-shape}])
[:> menu-entry* {:title (tr "workspace.shape.menu.show")
:shortcut (sc/get-tooltip :toggle-visibility)
:on-click do-show-shape}]
[:> menu-entry* {:title (tr "workspace.shape.menu.hide")
:shortcut (sc/get-tooltip :toggle-visibility)
:on-click do-hide-shape}])
(if (every? :blocked shapes)
[:& menu-entry {:title (tr "workspace.shape.menu.unlock")
:shortcut (sc/get-tooltip :toggle-lock)
:on-click do-unlock-shape}]
[:& menu-entry {:title (tr "workspace.shape.menu.lock")
:shortcut (sc/get-tooltip :toggle-lock)
:on-click do-lock-shape}])]))
[:> menu-entry* {:title (tr "workspace.shape.menu.unlock")
:shortcut (sc/get-tooltip :toggle-lock)
:on-click do-unlock-shape}]
[:> menu-entry* {:title (tr "workspace.shape.menu.lock")
:shortcut (sc/get-tooltip :toggle-lock)
:on-click do-lock-shape}])]))
(mf/defc context-menu-prototype
{::mf/props :obj}
(mf/defc context-menu-prototype*
{::mf/props :obj
::mf/private true}
[{:keys [shapes]}]
(let [flows (mf/deref refs/workspace-page-flows)
options-mode (mf/deref refs/options-mode-global)
@ -400,13 +421,14 @@
(when (and prototype? is-frame?)
(if-let [flow (ctp/get-frame-flow flows (-> shapes first :id))]
[:& menu-entry {:title (tr "workspace.shape.menu.delete-flow-start")
:on-click (do-remove-flow flow)}]
[:& menu-entry {:title (tr "workspace.shape.menu.flow-start")
:on-click do-add-flow}]))))
[:> menu-entry* {:title (tr "workspace.shape.menu.delete-flow-start")
:on-click (do-remove-flow flow)}]
[:> menu-entry* {:title (tr "workspace.shape.menu.flow-start")
:on-click do-add-flow}]))))
(mf/defc context-menu-layout
{::mf/props :obj}
(mf/defc context-menu-layout*
{::mf/props :obj
::mf/private true}
[{:keys [shapes]}]
(let [single? (= (count shapes) 1)
objects (deref refs/workspace-page-objects)
@ -438,27 +460,29 @@
(if (or ^boolean has-flex?
^boolean has-grid?)
[:div
[:& menu-separator]
[:> menu-separator* {}]
(if has-flex?
[:& menu-entry {:title (tr "workspace.shape.menu.remove-flex")
:shortcut (sc/get-tooltip :toggle-layout-flex)
:on-click on-remove-layout}]
[:& menu-entry {:title (tr "workspace.shape.menu.remove-grid")
:shortcut (sc/get-tooltip :toggle-layout-grid)
:on-click on-remove-layout}])]
[:> menu-entry* {:title (tr "workspace.shape.menu.remove-flex")
:shortcut (sc/get-tooltip :toggle-layout-flex)
:on-click on-remove-layout}]
[:> menu-entry* {:title (tr "workspace.shape.menu.remove-grid")
:shortcut (sc/get-tooltip :toggle-layout-grid)
:on-click on-remove-layout}])]
[:div
[:& menu-separator]
[:& menu-entry {:title (tr "workspace.shape.menu.add-flex")
:shortcut (sc/get-tooltip :toggle-layout-flex)
:value "flex"
:on-click on-add-layout}]
[:& menu-entry {:title (tr "workspace.shape.menu.add-grid")
:shortcut (sc/get-tooltip :toggle-layout-grid)
:value "grid"
:on-click on-add-layout}]]))]))
[:> menu-separator* {}]
[:> menu-entry* {:title (tr "workspace.shape.menu.add-flex")
:shortcut (sc/get-tooltip :toggle-layout-flex)
:value "flex"
:on-click on-add-layout}]
[:> menu-entry* {:title (tr "workspace.shape.menu.add-grid")
:shortcut (sc/get-tooltip :toggle-layout-grid)
:value "grid"
:on-click on-add-layout}]]))]))
(mf/defc context-menu-component
(mf/defc context-menu-component*
{::mf/props :obj
::mf/private true}
[{:keys [shapes]}]
(let [components-v2 (features/use-feature "components/v2")
single? (= (count shapes) 1)
@ -471,59 +495,66 @@
[:*
(when can-make-component ;; We don't want to change the structure of component copies
[:*
[:& menu-separator]
[:> menu-separator* {}]
[:& menu-entry {:title (tr "workspace.shape.menu.create-component")
:shortcut (sc/get-tooltip :create-component)
:on-click do-add-component}]
[:> menu-entry* {:title (tr "workspace.shape.menu.create-component")
:shortcut (sc/get-tooltip :create-component)
:on-click do-add-component}]
(when (not single?)
[:& menu-entry {:title (tr "workspace.shape.menu.create-multiple-components")
:on-click do-add-multiple-components}])])
[:> menu-entry* {:title (tr "workspace.shape.menu.create-multiple-components")
:on-click do-add-multiple-components}])])
(when (seq components-menu-entries)
[:*
[:& menu-separator]
[:> menu-separator* {}]
(for [entry components-menu-entries :when (not (nil? entry))]
[:& menu-entry {:key (uuid/next)
:title (:title entry)
:shortcut (when (contains? entry :shortcut) (sc/get-tooltip (:shortcut entry)))
:on-click (:action entry)}])])]))
[:> menu-entry* {:key (uuid/next)
:title (:title entry)
:shortcut (when (contains? entry :shortcut) (sc/get-tooltip (:shortcut entry)))
:on-click (:action entry)}])])]))
(mf/defc context-menu-delete
(mf/defc context-menu-delete*
{::mf/props :obj
::mf/private true}
[]
(let [do-delete #(st/emit! (dw/delete-selected))]
[:*
[:& menu-separator]
[:& menu-entry {:title (tr "workspace.shape.menu.delete")
:shortcut (sc/get-tooltip :delete)
:on-click do-delete}]]))
[:> menu-separator* {}]
[:> menu-entry* {:title (tr "workspace.shape.menu.delete")
:shortcut (sc/get-tooltip :delete)
:on-click do-delete}]]))
(mf/defc shape-context-menu
{::mf/wrap [mf/memo]}
[{:keys [mdata] :as props}]
(let [{:keys [disable-booleans? disable-flatten?]} mdata
(mf/defc shape-context-menu*
{::mf/wrap [mf/memo]
::mf/private true
::mf/props :obj}
[{:keys [mdata]}]
(let [{:keys [disable-booleans disable-flatten]} mdata
shapes (mf/deref refs/selected-objects)
props #js {:shapes shapes
:disable-booleans? disable-booleans?
:disable-flatten? disable-flatten?}]
props (mf/spread-props
{:shapes shapes
:disable-booleans disable-booleans
:disable-flatten disable-flatten})]
(when-not (empty? shapes)
[:*
[:> context-menu-edit props]
[:> context-menu-layer-position props]
[:> context-menu-flip props]
[:> context-menu-thumbnail props]
[:> context-menu-rename props]
[:> context-menu-group props]
[:> context-focus-mode-menu props]
[:> context-menu-path props]
[:> context-menu-layer-options props]
[:> context-menu-prototype props]
[:> context-menu-layout props]
[:> context-menu-component props]
[:> context-menu-delete props]])))
[:> context-menu-edit* props]
[:> context-menu-layer-position* props]
[:> context-menu-flip* props]
[:> context-menu-thumbnail* props]
[:> context-menu-rename* props]
[:> context-menu-group* props]
[:> context-focus-mode-menu* props]
[:> context-menu-path* props]
[:> context-menu-layer-options* props]
[:> context-menu-prototype* props]
[:> context-menu-layout* props]
[:> context-menu-component* props]
[:> context-menu-delete* props]])))
(mf/defc page-item-context-menu
[{:keys [mdata] :as props}]
(mf/defc page-item-context-menu*
{::mf/props :obj
::mf/private true}
[{:keys [mdata]}]
(let [page (:page mdata)
deletable? (:deletable? mdata)
id (:id page)
@ -540,13 +571,13 @@
[:*
(when deletable?
[:& menu-entry {:title (tr "workspace.assets.delete")
:on-click do-delete}])
[:> menu-entry* {:title (tr "workspace.assets.delete")
:on-click do-delete}])
[:& menu-entry {:title (tr "workspace.assets.rename")
:on-click do-rename}]
[:& menu-entry {:title (tr "workspace.assets.duplicate")
:on-click do-duplicate}]]))
[:> menu-entry* {:title (tr "workspace.assets.rename")
:on-click do-rename}]
[:> menu-entry* {:title (tr "workspace.assets.duplicate")
:on-click do-duplicate}]]))
(mf/defc viewport-context-menu*
{::mf/props :obj}
@ -559,68 +590,72 @@
do-toggle-focus-mode #(st/emit! (dw/toggle-focus-mode))]
[:*
(when-not ^boolean read-only?
[:& menu-entry {:title (tr "workspace.shape.menu.paste")
:shortcut (sc/get-tooltip :paste)
:on-click do-paste}])
[:& menu-entry {:title (tr "workspace.shape.menu.hide-ui")
:shortcut (sc/get-tooltip :hide-ui)
:on-click do-hide-ui}]
[:> menu-entry* {:title (tr "workspace.shape.menu.paste")
:shortcut (sc/get-tooltip :paste)
:on-click do-paste}])
[:> menu-entry* {:title (tr "workspace.shape.menu.hide-ui")
:shortcut (sc/get-tooltip :hide-ui)
:on-click do-hide-ui}]
(when (d/not-empty? focus)
[:& menu-entry {:title (tr "workspace.focus.focus-off")
:shortcut (sc/get-tooltip :toggle-focus-mode)
:on-click do-toggle-focus-mode}])]))
[:> menu-entry* {:title (tr "workspace.focus.focus-off")
:shortcut (sc/get-tooltip :toggle-focus-mode)
:on-click do-toggle-focus-mode}])]))
(mf/defc grid-track-context-menu
[{:keys [mdata] :as props}]
(mf/defc grid-track-context-menu*
{::mf/props :obj
::mf/private true}
[{:keys [mdata]}]
(let [{:keys [type index grid-id]} mdata
do-delete-track
(mf/use-callback
(mf/use-fn
(mf/deps grid-id type index)
(fn []
(st/emit! (dwsl/remove-layout-track [grid-id] type index))))
do-add-track-before
(mf/use-callback
(mf/use-fn
(mf/deps grid-id type index)
(fn []
(st/emit! (dwsl/add-layout-track [grid-id] type ctl/default-track-value index))))
do-add-track-after
(mf/use-callback
(mf/use-fn
(mf/deps grid-id type index)
(fn []
(st/emit! (dwsl/add-layout-track [grid-id] type ctl/default-track-value (inc index)))))
do-duplicate-track
(mf/use-callback
(mf/use-fn
(mf/deps grid-id type index)
(fn []
(st/emit! (dwsl/duplicate-layout-track [grid-id] type index))))
do-delete-track-shapes
(mf/use-callback
(mf/use-fn
(mf/deps grid-id type index)
(fn []
(st/emit! (dwsl/remove-layout-track [grid-id] type index {:with-shapes? true}))))]
(if (= type :column)
[:*
[:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.duplicate") :on-click do-duplicate-track}]
[:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.add-before") :on-click do-add-track-before}]
[:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.add-after") :on-click do-add-track-after}]
[:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.delete") :on-click do-delete-track}]
[:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.delete-shapes") :on-click do-delete-track-shapes}]]
[:> menu-entry* {:title (tr "workspace.context-menu.grid-track.column.duplicate") :on-click do-duplicate-track}]
[:> menu-entry* {:title (tr "workspace.context-menu.grid-track.column.add-before") :on-click do-add-track-before}]
[:> menu-entry* {:title (tr "workspace.context-menu.grid-track.column.add-after") :on-click do-add-track-after}]
[:> menu-entry* {:title (tr "workspace.context-menu.grid-track.column.delete") :on-click do-delete-track}]
[:> menu-entry* {:title (tr "workspace.context-menu.grid-track.column.delete-shapes") :on-click do-delete-track-shapes}]]
[:*
[:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.duplicate") :on-click do-duplicate-track}]
[:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.add-before") :on-click do-add-track-before}]
[:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.add-after") :on-click do-add-track-after}]
[:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.delete") :on-click do-delete-track}]
[:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.delete-shapes") :on-click do-delete-track-shapes}]])))
[:> menu-entry* {:title (tr "workspace.context-menu.grid-track.row.duplicate") :on-click do-duplicate-track}]
[:> menu-entry* {:title (tr "workspace.context-menu.grid-track.row.add-before") :on-click do-add-track-before}]
[:> menu-entry* {:title (tr "workspace.context-menu.grid-track.row.add-after") :on-click do-add-track-after}]
[:> menu-entry* {:title (tr "workspace.context-menu.grid-track.row.delete") :on-click do-delete-track}]
[:> menu-entry* {:title (tr "workspace.context-menu.grid-track.row.delete-shapes") :on-click do-delete-track-shapes}]])))
(mf/defc grid-cells-context-menu
[{:keys [mdata] :as props}]
(mf/defc grid-cells-context-menu*
{::mf/props :obj
::mf/private true}
[{:keys [mdata]}]
(let [{:keys [grid cells]} mdata
single? (= (count cells) 1)
@ -631,29 +666,29 @@
#(ctl/valid-area-cells? cells))
do-merge-cells
(mf/use-callback
(mf/use-fn
(mf/deps grid cells)
(fn []
(st/emit! (dwsl/merge-cells (:id grid) (map :id cells)))))
do-create-board
(mf/use-callback
(mf/use-fn
(mf/deps grid cells)
(fn []
(st/emit! (dwsl/create-cell-board (:id grid) (map :id cells)))))]
[:*
(when (not single?)
[:& menu-entry {:title (tr "workspace.context-menu.grid-cells.merge")
:on-click do-merge-cells
:disabled (not can-merge?)}])
[:> menu-entry* {:title (tr "workspace.context-menu.grid-cells.merge")
:on-click do-merge-cells
:disabled (not can-merge?)}])
(when single?
[:& menu-entry {:title (tr "workspace.context-menu.grid-cells.area")
:on-click do-merge-cells}])
[:> menu-entry* {:title (tr "workspace.context-menu.grid-cells.area")
:on-click do-merge-cells}])
[:& menu-entry {:title (tr "workspace.context-menu.grid-cells.create-board")
:on-click do-create-board
:disabled (and (not single?) (not can-merge?))}]]))
[:> menu-entry* {:title (tr "workspace.context-menu.grid-cells.create-board")
:on-click do-create-board
:disabled (and (not single?) (not can-merge?))}]]))
;; FIXME: optimize because it is rendered always
@ -688,8 +723,8 @@
(if ^boolean read-only?
[:> viewport-context-menu* {:mdata mdata}]
(case (:kind mdata)
:shape [:& shape-context-menu {:mdata mdata}]
:page [:& page-item-context-menu {:mdata mdata}]
:grid-track [:& grid-track-context-menu {:mdata mdata}]
:grid-cells [:& grid-cells-context-menu {:mdata mdata}]
[:& viewport-context-menu* {:mdata mdata}]))]]]))
:shape [:> shape-context-menu* {:mdata mdata}]
:page [:> page-item-context-menu* {:mdata mdata}]
:grid-track [:> grid-track-context-menu* {:mdata mdata}]
:grid-cells [:> grid-cells-context-menu* {:mdata mdata}]
[:> viewport-context-menu* {:mdata mdata}]))]]]))

View file

@ -62,7 +62,7 @@
(let [fdata (let [{:keys [id] :as wfile} (:workspace-data state)]
(if (= id library-id)
wfile
(dm/get-in state [:workspace-libraries library-id :data])))]
(dm/get-in state [:libraries library-id :data])))]
{:colors (-> fdata :colors vals)
:media (-> fdata :media vals)
:components (ctkl/components-seq fdata)
@ -557,7 +557,7 @@
file-id (:id file)
shared? (:is-shared file)
libraries (mf/deref refs/workspace-libraries)
libraries (mf/deref refs/libraries)
libraries (mf/with-memo [libraries]
(d/removem (fn [[_ val]] (:is-indirect val)) libraries))

View file

@ -31,7 +31,7 @@
::mf/props :obj
::mf/private true}
[{:keys [filters]}]
(let [libraries (mf/deref refs/workspace-libraries)
(let [libraries (mf/deref refs/libraries)
libraries (mf/with-memo [libraries]
(->> (vals libraries)
(remove :is-indirect)
@ -88,7 +88,7 @@
section (:section filters)
ordering (:ordering filters)
reverse-sort? (= :desc ordering)
num-libs (count (mf/deref refs/workspace-libraries))
num-libs (count (mf/deref refs/libraries))
toggle-ordering
(mf/use-fn

View file

@ -315,17 +315,17 @@
current-file-id (mf/use-ctx ctx/current-file-id)
objects (deref refs/workspace-page-objects)
workspace-data (deref refs/workspace-data)
workspace-libraries (deref refs/workspace-libraries)
libraries (deref refs/libraries)
current-file {:id current-file-id :data workspace-data}
find-component (fn [shape include-deleted?]
(ctf/resolve-component
shape current-file workspace-libraries {:include-deleted? include-deleted?}))
shape current-file libraries {:include-deleted? include-deleted?}))
local-or-exists (fn [shape]
(let [library-id (:component-file shape)]
(or (= library-id current-file-id)
(some? (get workspace-libraries library-id)))))
(some? (get libraries library-id)))))
restorable-copies (->> copies
(filter #(nil? (find-component % false)))

View file

@ -50,7 +50,7 @@
(if components-v2
(ctf/get-component-page data component)
component)])
(let [data (dm/get-in @refs/workspace-libraries [file-id :data])
(let [data (dm/get-in @refs/libraries [file-id :data])
root-shape (ctf/get-component-root data component)
container (if components-v2
(ctf/get-component-page data component)
@ -466,7 +466,7 @@
(fn [component event]
(let [file-data
(d/nilv (dm/get-in @refs/workspace-libraries [file-id :data]) @refs/workspace-data)
(d/nilv (dm/get-in @refs/libraries [file-id :data]) @refs/workspace-data)
shape-main
(ctf/get-component-root file-data component)]

View file

@ -78,7 +78,7 @@
[{:keys [selected objects page-id file-id selected-shapes shapes-with-children]}]
(let [sp-panel (mf/deref refs/specialized-panel)
drawing (mf/deref refs/workspace-drawing)
shared-libs (mf/deref refs/workspace-libraries)
shared-libs (mf/deref refs/libraries)
edition (mf/deref refs/selected-edition)
edit-grid? (ctl/grid-layout? objects edition)
grid-edition (mf/deref refs/workspace-grid-edition)

View file

@ -272,7 +272,7 @@
(letfn [(get-libraries [state]
(let [file (:workspace-file state)
data (:workspace-data state)
libs (:workspace-libraries state)]
libs (:libraries state)]
(assoc libs (:id file)
(assoc file :data data))))]
(l/derived get-libraries st/state)))
@ -524,7 +524,7 @@
(let [current-file-id (mf/use-ctx ctx/current-file-id)
components-v2 (mf/use-ctx ctx/components-v2)
workspace-data (deref refs/workspace-data)
workspace-libraries (deref refs/workspace-libraries)
libraries (deref refs/libraries)
state* (mf/use-state {:show-content true
:menu-open false})
@ -544,7 +544,7 @@
component (ctf/resolve-component shape
{:id current-file-id
:data workspace-data}
workspace-libraries
libraries
{:include-deleted? true})
main-instance? (if components-v2 (ctk/main-instance? shape) true)

View file

@ -184,7 +184,7 @@
(let [file-id (mf/use-ctx ctx/current-file-id)
typographies (mf/deref refs/workspace-file-typography)
shared-libs (mf/deref refs/workspace-libraries)
shared-libs (mf/deref refs/libraries)
label (case type
:multiple (tr "workspace.options.text-options.title-selection")
:group (tr "workspace.options.text-options.title-group")

View file

@ -51,7 +51,7 @@
disable-drag on-focus on-blur select-only select-on-focus]}]
(let [current-file-id (mf/use-ctx ctx/current-file-id)
file-colors (mf/deref refs/workspace-file-colors)
shared-libs (mf/deref refs/workspace-libraries)
shared-libs (mf/deref refs/libraries)
hover-detach (mf/use-state false)
on-change (h/use-ref-callback on-change)
src-colors (if (= (:file-id color) current-file-id)

View file

@ -53,7 +53,7 @@
(mf/deref refs/workspace-v2-editor-state)
(mf/deref refs/workspace-editor-state))
shared-libs (mf/deref refs/workspace-libraries)
shared-libs (mf/deref refs/libraries)
editor-state (when (not (features/active-feature? @st/state "text-editor/v2"))
(get state-map (:id shape)))

View file

@ -183,7 +183,7 @@
[{:keys [size width selected] :as props}]
(let [selected-ids (mf/deref refs/selected-shapes)
file-typographies (mf/deref refs/workspace-file-typography)
shared-libs (mf/deref refs/workspace-libraries)
shared-libs (mf/deref refs/libraries)
current-file-id (mf/use-ctx ctx/current-file-id)]
[:& palette {:current-file-id current-file-id
:selected-ids selected-ids

View file

@ -14,11 +14,10 @@
[app.util.i18n :refer [tr]]
[rumext.v2 :as mf]))
(mf/defc text-palette-ctx-menu
[{:keys [show-menu? close-menu on-select-palette selected]}]
(let [file-typographies (mf/deref refs/workspace-file-typography)
shared-libs (mf/deref refs/workspace-libraries)]
(let [typographies (mf/deref refs/workspace-file-typography)
shared-libs (mf/deref refs/libraries)]
[:& dropdown {:show show-menu?
:on-close close-menu}
[:ul {:class (stl/css :text-context-menu)}
@ -49,7 +48,7 @@
[:span {:class (stl/css :lib-name)}
(tr "workspace.libraries.colors.file-library")]
[:span {:class (stl/css :lib-num)}
(dm/str "(" (count file-typographies) ")")]]
(dm/str "(" (count typographies) ")")]]
(when (= selected :file)
[:span {:class (stl/css :icon-wrapper)}
i/tick])]]]))

View file

@ -622,7 +622,7 @@
:hover-disabled? hover-disabled?}])])
(when show-gradient-handlers?
[:& gradients/gradient-handlers
[:> gradients/gradient-handlers*
{:id (first selected)
:zoom zoom}])

View file

@ -441,8 +441,9 @@
:r (/ 4 zoom)
:fill "var(--app-white)"}]))]))
(mf/defc gradient-handlers*
[{:keys [zoom stops gradient editing shape] :as kk}]
(mf/defc gradient-handlers-impl*
{::mf/props :obj}
[{:keys [zoom stops gradient editing shape]}]
(let [transform (gsh/transform-matrix shape)
transform-inverse (gsh/inverse-transform-matrix shape)
@ -509,8 +510,9 @@
:on-change-finish on-change-finish
:on-change-width on-change-width}]))
(mf/defc gradient-handlers
{::mf/wrap [mf/memo]}
(mf/defc gradient-handlers*
{::mf/wrap [mf/memo]
::mf/props :obj}
[{:keys [id zoom]}]
(let [shape-ref (mf/use-memo (mf/deps id) #(refs/object-by-id id))
shape (mf/deref shape-ref)
@ -520,7 +522,7 @@
editing-stop (:editing-stop state)]
(when (and (some? gradient) (= id (:shape-id gradient)))
[:& gradient-handlers*
[:> gradient-handlers-impl*
{:zoom zoom
:gradient gradient
:stops stops

View file

@ -617,7 +617,7 @@
:hover-disabled? hover-disabled?}])])
(when show-gradient-handlers?
[:& gradients/gradient-handlers
[:> gradients/gradient-handlers*
{:id (first selected)
:zoom zoom}])

View file

@ -160,7 +160,7 @@
(map #(obj/get % "$id"))
(mapcat #(cfh/get-children-with-self objects %)))
file-id (:current-file-id @st/state)
shared-libs (:workspace-libraries @st/state)]
shared-libs (:libraries @st/state)]
(->> (ctc/extract-all-colors shapes file-id shared-libs)
(group-by :attrs)
@ -182,7 +182,7 @@
:else
(let [file-id (:current-file-id @st/state)
shared-libs (:workspace-libraries @st/state)
shared-libs (:libraries @st/state)
objects (u/locate-objects)
shapes
(->> shapes

View file

@ -929,7 +929,7 @@
:connected
{:get
(fn []
(let [libraries (get @st/state :workspace-libraries)]
(let [libraries (get @st/state :libraries)]
(apply array (->> libraries keys (map (partial library-proxy plugin-id))))))}
:availableLibraries
@ -937,7 +937,7 @@
(let [team-id (:current-team-id @st/state)]
(js/Promise.
(fn [resolve reject]
(let [current-libs (into #{} (map first) (get @st/state :workspace-libraries))]
(let [current-libs (into #{} (map first) (get @st/state :libraries))]
(->> (rp/cmd! :get-team-shared-files {:team-id team-id})
(rx/map (fn [result]
(->> result

View file

@ -20,7 +20,7 @@
(if (= id (:current-file-id @st/state))
(-> (:workspace-file @st/state)
(assoc :data (:workspace-data @st/state)))
(dm/get-in @st/state [:workspace-libraries id])))
(dm/get-in @st/state [:libraries id])))
(defn locate-page
[file-id id]
@ -65,10 +65,10 @@
(defn locate-component
[objects shape]
(let [current-file-id (:current-file-id @st/state)
workspace-data (:workspace-data @st/state)
workspace-libraries (:workspace-libraries @st/state)
root (ctn/get-instance-root objects shape)]
[root (ctf/resolve-component root {:id current-file-id :data workspace-data} workspace-libraries {:include-deleted? true})]))
workspace-data (:workspace-data @st/state)
libraries (:libraries @st/state)
root (ctn/get-instance-root objects shape)]
[root (ctf/resolve-component root {:id current-file-id :data workspace-data} libraries {:include-deleted? true})]))
(defn proxy->file
[proxy]

View file

@ -248,7 +248,7 @@
(let [page-id (get state :current-page-id)
file (assoc (get state :workspace-file)
:data (get state :workspace-data))
libraries (get state :workspace-libraries)]
libraries (get state :libraries)]
(ctf/dump-tree file page-id libraries {:show-ids show-ids
:show-touched show-touched
:show-modified show-modified}))))
@ -266,7 +266,7 @@
(let [page-id (get state :current-page-id)
file (assoc (get state :workspace-file)
:data (get state :workspace-data))
libraries (get state :workspace-libraries)
libraries (get state :libraries)
shape-id (if (some? shape-id)
(uuid/uuid shape-id)
(let [objects (get-in state [:workspace-data :pages-index page-id :objects])
@ -383,7 +383,7 @@
([shape-id]
(let [file (assoc (get @st/state :workspace-file)
:data (get @st/state :workspace-data))
libraries (get @st/state :workspace-libraries)]
libraries (get @st/state :libraries)]
(try
(->> (if-let [shape-id (some-> shape-id parse-uuid)]
@ -417,7 +417,7 @@
fdata (get state :workspace-data)
file (assoc file :data fdata)
libs (get state :workspace-libraries)
libs (get state :libraries)
errors (cfv/validate-file file libs)
_ (l/dbg :hint "repair current file" :errors (count errors))