mirror of
https://github.com/penpot/penpot.git
synced 2025-02-10 09:08:31 -05:00
⚡ Add performance improvements to use-search hook on layers
This commit is contained in:
parent
0102ca1bcf
commit
b65452cb73
3 changed files with 328 additions and 291 deletions
|
@ -15,13 +15,13 @@
|
|||
(mf/defc search-bar
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
(let [children (unchecked-get props "children")
|
||||
on-change (unchecked-get props "on-change")
|
||||
value (unchecked-get props "value")
|
||||
on-clear (unchecked-get props "clear-action")
|
||||
(let [children (unchecked-get props "children")
|
||||
on-change (unchecked-get props "on-change")
|
||||
value (unchecked-get props "value")
|
||||
on-clear (unchecked-get props "clear-action")
|
||||
placeholder (unchecked-get props "placeholder")
|
||||
icon (unchecked-get props "icon")
|
||||
|
||||
icon (unchecked-get props "icon")
|
||||
|
||||
handle-change
|
||||
(mf/use-fn
|
||||
(mf/deps on-change)
|
||||
|
@ -57,4 +57,4 @@
|
|||
(when (not= "" value)
|
||||
[:button {:class (dom/classnames (css :clear) true)
|
||||
:on-click handle-clear}
|
||||
i/delete-text-refactor])]]))
|
||||
i/delete-text-refactor])]]))
|
||||
|
|
|
@ -30,7 +30,8 @@
|
|||
|
||||
|
||||
(mf/defc layer-item
|
||||
[{:keys [index item selected objects sortable? filtered? recieved-depth parent-size component-child?] :as props}]
|
||||
{::mf/wrap-props false}
|
||||
[{:keys [index item selected objects sortable? filtered? recieved-depth parent-size component-child?]}]
|
||||
(let [id (:id item)
|
||||
blocked? (:blocked item)
|
||||
hidden? (:hidden item)
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.refs :as refs]
|
||||
|
@ -101,7 +102,6 @@
|
|||
|
||||
(defn calc-reparented-objects
|
||||
[objects]
|
||||
|
||||
(let [reparented-objects
|
||||
(d/mapm (fn [_ val]
|
||||
(assoc val :parent-id uuid/zero :shapes nil))
|
||||
|
@ -116,314 +116,351 @@
|
|||
|
||||
;; --- Layers Toolbox
|
||||
|
||||
;; FIXME: optimize
|
||||
(defn- match-filters?
|
||||
[state [id shape]]
|
||||
(let [search (:search-text state)
|
||||
filters (:filters state)
|
||||
filters (cond-> filters
|
||||
(contains? filters :shape)
|
||||
(conj :rect :circle :path :bool))]
|
||||
(or (= uuid/zero id)
|
||||
(and (or (str/includes? (str/lower (:name shape)) (str/lower search))
|
||||
(str/includes? (dm/str (:id shape)) (str/lower search)))
|
||||
(or (empty? filters)
|
||||
(and (contains? filters :component)
|
||||
(contains? shape :component-id))
|
||||
(let [direct-filters (filter #{:frame :rect :circle :path :bool :image :text} filters)]
|
||||
(some #{(:type shape)} direct-filters))
|
||||
(and (contains? filters :group)
|
||||
(and (cph/group-shape? shape)
|
||||
(not (contains? shape :component-id))
|
||||
(or (not (contains? shape :masked-group))
|
||||
(false? (:masked-group shape)))))
|
||||
(and (contains? filters :mask)
|
||||
(true? (:masked-group shape))))))))
|
||||
|
||||
(defn use-search
|
||||
[page objects]
|
||||
(let [filter-state (mf/use-state {:show-search-box false
|
||||
:show-filters-menu false
|
||||
:search-text ""
|
||||
:active-filters #{}
|
||||
:num-items 100})
|
||||
new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
state* (mf/use-state
|
||||
{:show-search false
|
||||
:show-menu false
|
||||
:search-text ""
|
||||
:filters #{}
|
||||
:num-items 100})
|
||||
state (deref state*)
|
||||
|
||||
current-filters (:filters state)
|
||||
current-items (:num-items state)
|
||||
current-search (:search-text state)
|
||||
show-menu? (:show-menu state)
|
||||
show-search? (:show-search state)
|
||||
|
||||
clear-search-text
|
||||
(mf/use-callback
|
||||
(fn []
|
||||
(swap! filter-state assoc :search-text "" :num-items 100)))
|
||||
|
||||
update-search-text
|
||||
(mf/use-fn
|
||||
(mf/deps new-css-system)
|
||||
(fn [event]
|
||||
;; NOTE: When old-css-system is removed this function will recibe value and event
|
||||
;; Let won't be necessary any more
|
||||
(let [value (if new-css-system
|
||||
event
|
||||
(dom/get-target-val event))]
|
||||
(swap! filter-state assoc :search-text value :num-items 100))))
|
||||
#(swap! state* assoc :search-text "" :num-items 100))
|
||||
|
||||
toggle-search
|
||||
(mf/use-callback
|
||||
(fn [event]
|
||||
(let [node (dom/get-current-target event)]
|
||||
(swap! filter-state assoc :search-text "")
|
||||
(swap! filter-state assoc :active-filters #{})
|
||||
(swap! filter-state assoc :show-filters-menu false)
|
||||
(swap! filter-state assoc :num-items 100)
|
||||
(swap! filter-state update :show-search-box not)
|
||||
(dom/blur! node))))
|
||||
|
||||
toggle-filters
|
||||
(mf/use-callback
|
||||
(fn []
|
||||
(swap! filter-state update :show-filters-menu not)))
|
||||
(mf/use-fn
|
||||
#(swap! state* update :show-menu not))
|
||||
|
||||
update-search-text-v1
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(let [value (-> event dom/get-target dom/get-value)]
|
||||
(swap! state* assoc :search-text value :num-items 100))))
|
||||
|
||||
update-search-text-v2
|
||||
(mf/use-fn
|
||||
(fn [value _event]
|
||||
(swap! state* assoc :search-text value :num-items 100)))
|
||||
|
||||
toggle-search
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(let [node (dom/get-current-target event)]
|
||||
(dom/blur! node)
|
||||
(swap! state* (fn [state]
|
||||
(-> state
|
||||
(assoc :search-text "")
|
||||
(assoc :filters #{})
|
||||
(assoc :show-menu false)
|
||||
(assoc :num-items 100)
|
||||
(update :show-search not)))))))
|
||||
|
||||
remove-filter
|
||||
(mf/use-callback
|
||||
(mf/deps @filter-state)
|
||||
(fn [key]
|
||||
(fn [_]
|
||||
(swap! filter-state update :active-filters disj key)
|
||||
(swap! filter-state assoc :num-items 100))))
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(let [fkey (-> (dom/get-current-target event)
|
||||
(dom/get-data "filter")
|
||||
(keyword))]
|
||||
(swap! state* (fn [state]
|
||||
(-> state
|
||||
(update :filters disj fkey)
|
||||
(assoc :num-items 100)))))))
|
||||
|
||||
add-filter
|
||||
(mf/use-callback
|
||||
(mf/deps @filter-state (:show-filters-menu @filter-state))
|
||||
(fn [key]
|
||||
(fn [_]
|
||||
(swap! filter-state update :active-filters conj key)
|
||||
(swap! filter-state assoc :num-items 100)
|
||||
(toggle-filters))))
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(let [key (-> (dom/get-current-target event)
|
||||
(dom/get-data "filter")
|
||||
(keyword))]
|
||||
(swap! state* (fn [state]
|
||||
(-> state
|
||||
(update :filters conj key)
|
||||
(update :show-menu not)
|
||||
(assoc :num-items 100)))))))
|
||||
|
||||
active?
|
||||
(and
|
||||
(:show-search-box @filter-state)
|
||||
(or (d/not-empty? (:search-text @filter-state))
|
||||
(d/not-empty? (:active-filters @filter-state))))
|
||||
(and ^boolean show-search?
|
||||
(or ^boolean (d/not-empty? current-search)
|
||||
^boolean (d/not-empty? current-filters)))
|
||||
|
||||
search-and-filters
|
||||
(fn [[id shape]]
|
||||
(let [search (:search-text @filter-state)
|
||||
filters (:active-filters @filter-state)
|
||||
filters (cond-> filters
|
||||
(some #{:shape} filters)
|
||||
(conj :rect :circle :path :bool))]
|
||||
(or
|
||||
(= uuid/zero id)
|
||||
(and
|
||||
(or (str/includes? (str/lower (:name shape)) (str/lower search))
|
||||
(str/includes? (dm/str (:id shape)) (str/lower search)))
|
||||
(or
|
||||
(empty? filters)
|
||||
(and
|
||||
(some #{:component} filters)
|
||||
(contains? shape :component-id))
|
||||
(let [direct_filters (filter #{:frame :rect :circle :path :bool :image :text} filters)]
|
||||
(some #{(:type shape)} direct_filters))
|
||||
(and
|
||||
(some #{:group} filters)
|
||||
(and (= :group (:type shape))
|
||||
(not (contains? shape :component-id))
|
||||
(or (not (contains? shape :masked-group)) (false? (:masked-group shape)))))
|
||||
(and
|
||||
(some #{:mask} filters)
|
||||
(true? (:masked-group shape))))))))
|
||||
filtered-objects-all
|
||||
(mf/with-memo [active? objects state]
|
||||
(when active?
|
||||
(into [] (filter (partial match-filters? state)) objects)))
|
||||
|
||||
filtered-objects-total
|
||||
(mf/use-memo
|
||||
(mf/deps objects active? @filter-state)
|
||||
#(when active?
|
||||
;; filterv so count is constant time
|
||||
(filterv search-and-filters objects)))
|
||||
(count filtered-objects-all)
|
||||
|
||||
filtered-objects
|
||||
(mf/use-memo
|
||||
(mf/deps filtered-objects-total)
|
||||
#(when active?
|
||||
(calc-reparented-objects
|
||||
(into {}
|
||||
(take (:num-items @filter-state))
|
||||
filtered-objects-total))))
|
||||
(mf/with-memo [active? filtered-objects-all current-items]
|
||||
(when active?
|
||||
(->> filtered-objects-all
|
||||
(into {} (take current-items))
|
||||
(calc-reparented-objects))))
|
||||
|
||||
handle-show-more
|
||||
(fn []
|
||||
(when (<= (:num-items @filter-state) (count filtered-objects-total))
|
||||
(swap! filter-state update :num-items + 100)))
|
||||
(mf/use-fn
|
||||
(mf/deps filtered-objects-total current-items)
|
||||
(fn [_]
|
||||
(when (<= current-items filtered-objects-total)
|
||||
(swap! state* update :num-items + 100))))
|
||||
|
||||
handle-key-down
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(let [enter? (kbd/enter? event)
|
||||
esc? (kbd/esc? event)
|
||||
node (dom/event->target event)]
|
||||
(when ^boolean enter? (dom/blur! node))
|
||||
(when ^boolean esc? (dom/blur! node)))))]
|
||||
(when-let [node (dom/event->target event)]
|
||||
(when (kbd/enter? event)
|
||||
(dom/blur! node))
|
||||
(when (kbd/esc? event)
|
||||
(dom/blur! node)))))]
|
||||
|
||||
[filtered-objects
|
||||
handle-show-more
|
||||
(mf/html
|
||||
(if (:show-search-box @filter-state)
|
||||
[:*
|
||||
[:div {:class (if new-css-system
|
||||
(dom/classnames (css :tool-window-bar) true
|
||||
(css :search) true)
|
||||
(dom/classnames :tool-window-bar true
|
||||
:search true))}
|
||||
(if new-css-system
|
||||
[:& search-bar
|
||||
{:on-change update-search-text
|
||||
:value (:search-text @filter-state)
|
||||
:on-clear clear-search-text
|
||||
:placeholder (tr "workspace.sidebar.layers.search")}
|
||||
[:button
|
||||
{:on-click toggle-filters
|
||||
:class (dom/classnames :active active?
|
||||
(css :filter-button) true)}
|
||||
i/filter-refactor]]
|
||||
#(mf/html
|
||||
(if show-search?
|
||||
[:*
|
||||
[:div {:class (if ^boolean new-css-system
|
||||
(dom/classnames (css :tool-window-bar) true
|
||||
(css :search) true)
|
||||
(dom/classnames :tool-window-bar true
|
||||
:search true))}
|
||||
|
||||
[:span.search-box
|
||||
[:button.filter
|
||||
{:on-click toggle-filters
|
||||
:class (dom/classnames :active active?)}
|
||||
i/icon-filter]
|
||||
[:div
|
||||
[:input {:on-change update-search-text
|
||||
:value (:search-text @filter-state)
|
||||
:auto-focus (:show-search-box @filter-state)
|
||||
:placeholder (tr "workspace.sidebar.layers.search")
|
||||
:on-key-down handle-key-down}]
|
||||
(when (not (= "" (:search-text @filter-state)))
|
||||
[:button.clear {:on-click clear-search-text}
|
||||
i/exclude])]])
|
||||
(if ^boolean new-css-system
|
||||
[:& search-bar
|
||||
{:on-change update-search-text-v2
|
||||
:value current-search
|
||||
:on-clear clear-search-text
|
||||
:placeholder (tr "workspace.sidebar.layers.search")}
|
||||
[:button
|
||||
{:on-click toggle-filters
|
||||
:class (dom/classnames :active active?
|
||||
(css :filter-button) true)}
|
||||
i/filter-refactor]]
|
||||
|
||||
[:button {:class (dom/classnames (css :close-search) new-css-system)
|
||||
:on-click toggle-search}
|
||||
(if new-css-system
|
||||
i/close-refactor
|
||||
i/cross)]]
|
||||
[:div {:class (if new-css-system
|
||||
(dom/classnames (css :active-filters) true)
|
||||
(dom/classnames :active-filters true))}
|
||||
(for [f (:active-filters @filter-state)]
|
||||
(let [name (case f
|
||||
:frame (tr "workspace.sidebar.layers.frames")
|
||||
:group (tr "workspace.sidebar.layers.groups")
|
||||
:mask (tr "workspace.sidebar.layers.masks")
|
||||
:component (tr "workspace.sidebar.layers.components")
|
||||
:text (tr "workspace.sidebar.layers.texts")
|
||||
:image (tr "workspace.sidebar.layers.images")
|
||||
:shape (tr "workspace.sidebar.layers.shapes")
|
||||
(tr f))]
|
||||
(if new-css-system
|
||||
[:button {:class (dom/classnames (css :layer-filter) true)
|
||||
:on-click (remove-filter f)}
|
||||
[:span {:class (dom/classnames (css :layer-filter-icon) true)}
|
||||
[:& sic/element-icon-refactor-by-type {:type f
|
||||
:main-instance? (= f :component)}]]
|
||||
[:span {:class (dom/classnames (css :layer-filter-name) true)}
|
||||
name]
|
||||
[:span {:class (dom/classnames (css :layer-filter-close) true)}
|
||||
i/close-small-refactor]]
|
||||
[:span {:on-click (remove-filter f)}
|
||||
name i/cross])))]
|
||||
[:span.search-box
|
||||
[:button.filter
|
||||
{:on-click toggle-filters
|
||||
:class (dom/classnames :active active?)}
|
||||
i/icon-filter]
|
||||
[:div
|
||||
[:input {:on-change update-search-text-v1
|
||||
:value current-search
|
||||
:auto-focus show-search?
|
||||
:placeholder (tr "workspace.sidebar.layers.search")
|
||||
:on-key-down handle-key-down}]
|
||||
(when (not (= "" current-search))
|
||||
[:button.clear {:on-click clear-search-text} i/exclude])]])
|
||||
|
||||
(when (:show-filters-menu @filter-state)
|
||||
(if new-css-system
|
||||
[:ul {:class (dom/classnames (css :filters-container) true)}
|
||||
[:li {:key "frames-filter-item"
|
||||
:class (dom/classnames (css :filter-menu-item) true
|
||||
(css :selected) (contains? (:active-filters @filter-state) :frame))
|
||||
:on-click (add-filter :frame)}
|
||||
[:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-icon) true)}
|
||||
i/board-refactor]
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-name) true)}
|
||||
(tr "workspace.sidebar.layers.frames")]]
|
||||
(when (contains? (:active-filters @filter-state) :frame)
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-tick) true)}
|
||||
i/tick-refactor])]
|
||||
[:li {:key "groups-filter-item"
|
||||
:class (dom/classnames (css :filter-menu-item) true
|
||||
(css :selected) (contains? (:active-filters @filter-state) :group))
|
||||
:on-click (add-filter :group)}
|
||||
[:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-icon) true)}
|
||||
i/group-refactor]
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-name) true)}
|
||||
(tr "workspace.sidebar.layers.groups")]]
|
||||
(when (contains? (:active-filters @filter-state) :group)
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-tick) true)}
|
||||
i/tick-refactor])]
|
||||
[:li {:key "masks-filter-item"
|
||||
:class (dom/classnames (css :filter-menu-item) true
|
||||
(css :selected) (contains? (:active-filters @filter-state) :mask))
|
||||
:on-click (add-filter :mask)}
|
||||
[:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-icon) true)}
|
||||
i/mask-refactor]
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-name) true)}
|
||||
(tr "workspace.sidebar.layers.masks")]]
|
||||
(when (contains? (:active-filters @filter-state) :mask)
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-tick) true)}
|
||||
i/tick-refactor])]
|
||||
[:li {:key "components-filter-item"
|
||||
:class (dom/classnames (css :filter-menu-item) true
|
||||
(css :selected) (contains? (:active-filters @filter-state) :component))
|
||||
:on-click (add-filter :component)}
|
||||
[:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-icon) true)}
|
||||
i/component-refactor]
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-name) true)}
|
||||
(tr "workspace.sidebar.layers.components")]]
|
||||
(when (contains? (:active-filters @filter-state) :component)
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-tick) true)}
|
||||
i/tick-refactor])]
|
||||
[:li {:key "texts-filter-item"
|
||||
:class (dom/classnames (css :filter-menu-item) true
|
||||
(css :selected) (contains? (:active-filters @filter-state) :text))
|
||||
:on-click (add-filter :text)}
|
||||
[:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-icon) true)}
|
||||
i/text-refactor]
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-name) true)}
|
||||
(tr "workspace.sidebar.layers.texts")]]
|
||||
(when (contains? (:active-filters @filter-state) :text)
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-tick) true)}
|
||||
i/tick-refactor])]
|
||||
[:li {:key "images-filter-item"
|
||||
:class (dom/classnames (css :filter-menu-item) true
|
||||
(css :selected) (contains? (:active-filters @filter-state) :image))
|
||||
:on-click (add-filter :image)}
|
||||
[:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-icon) true)}
|
||||
i/img-refactor]
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-name) true)}
|
||||
(tr "workspace.sidebar.layers.images")]]
|
||||
(when (contains? (:active-filters @filter-state) :image)
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-tick) true)}
|
||||
i/tick-refactor])]
|
||||
[:li {:key "shapes-filter-item"
|
||||
:class (dom/classnames (css :filter-menu-item) true
|
||||
(css :selected) (contains? (:active-filters @filter-state) :shape))
|
||||
:on-click (add-filter :shape)}
|
||||
[:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-icon) true)}
|
||||
i/path-refactor]
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-name) true)}
|
||||
(tr "workspace.sidebar.layers.shapes")]]
|
||||
(when (contains? (:active-filters @filter-state) :shape)
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-tick) true)}
|
||||
i/tick-refactor])]]
|
||||
[:button {:class (dom/classnames (css :close-search) new-css-system)
|
||||
:on-click toggle-search}
|
||||
(if ^boolean new-css-system
|
||||
i/close-refactor
|
||||
i/cross)]]
|
||||
|
||||
[:div.filters-container
|
||||
[:span {:on-click (add-filter :frame)} i/artboard (tr "workspace.sidebar.layers.frames")]
|
||||
[:span {:on-click (add-filter :group)} i/folder (tr "workspace.sidebar.layers.groups")]
|
||||
[:span {:on-click (add-filter :mask)} i/mask (tr "workspace.sidebar.layers.masks")]
|
||||
[:span {:on-click (add-filter :component)} i/component (tr "workspace.sidebar.layers.components")]
|
||||
[:span {:on-click (add-filter :text)} i/text (tr "workspace.sidebar.layers.texts")]
|
||||
[:span {:on-click (add-filter :image)} i/image (tr "workspace.sidebar.layers.images")]
|
||||
[:span {:on-click (add-filter :shape)} i/curve (tr "workspace.sidebar.layers.shapes")]]))]
|
||||
[:div {:class (if ^boolean new-css-system
|
||||
(dom/classnames (css :active-filters) true)
|
||||
(dom/classnames :active-filters true))}
|
||||
(for [fkey current-filters]
|
||||
(let [fname (d/name fkey)
|
||||
name (case fkey
|
||||
:frame (tr "workspace.sidebar.layers.frames")
|
||||
:group (tr "workspace.sidebar.layers.groups")
|
||||
:mask (tr "workspace.sidebar.layers.masks")
|
||||
:component (tr "workspace.sidebar.layers.components")
|
||||
:text (tr "workspace.sidebar.layers.texts")
|
||||
:image (tr "workspace.sidebar.layers.images")
|
||||
:shape (tr "workspace.sidebar.layers.shapes")
|
||||
(tr fkey))]
|
||||
(if ^boolean new-css-system
|
||||
[:button {:class (dom/classnames (css :layer-filter) true)
|
||||
:key fname
|
||||
:data-filter fname
|
||||
:on-click remove-filter}
|
||||
[:span {:class (dom/classnames (css :layer-filter-icon) true)}
|
||||
[:& sic/element-icon-refactor-by-type
|
||||
{:type fkey
|
||||
:main-instance? (= fkey :component)}]]
|
||||
[:span {:class (dom/classnames (css :layer-filter-name) true)}
|
||||
name]
|
||||
[:span {:class (dom/classnames (css :layer-filter-close) true)}
|
||||
i/close-small-refactor]]
|
||||
|
||||
(if new-css-system
|
||||
[:div {:class (dom/classnames (css :tool-window-bar) true)}
|
||||
[:& title-bar {:collapsable? false
|
||||
:title (:name page)
|
||||
:on-btn-click toggle-search
|
||||
:btn-children i/search-refactor}]]
|
||||
[:div.tool-window-bar
|
||||
[:span.page-name
|
||||
(:name page)]
|
||||
[:button.icon-search {:on-click toggle-search}
|
||||
i/search]])))]))
|
||||
[:span {:on-click remove-filter
|
||||
:data-filter fname
|
||||
:key fname}
|
||||
name i/cross])))]
|
||||
|
||||
(when ^boolean show-menu?
|
||||
(if ^boolean new-css-system
|
||||
[:ul {:class (css :filters-container)}
|
||||
[:li {:class (dom/classnames
|
||||
(css :filter-menu-item) true
|
||||
(css :selected) (contains? current-filters :frame))
|
||||
:data-filter "frame"
|
||||
:on-click add-filter}
|
||||
[:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-icon) true)} i/board-refactor]
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-name) true)}
|
||||
(tr "workspace.sidebar.layers.frames")]]
|
||||
(when (contains? current-filters :frame)
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-tick) true)} i/tick-refactor])]
|
||||
|
||||
[:li {:class (dom/classnames
|
||||
(css :filter-menu-item) true
|
||||
(css :selected) (contains? current-filters :group))
|
||||
:data-filter "group"
|
||||
:on-click add-filter}
|
||||
[:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-icon) true)} i/group-refactor]
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-name) true)}
|
||||
(tr "workspace.sidebar.layers.groups")]]
|
||||
|
||||
(when (contains? current-filters :group)
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-tick) true)} i/tick-refactor])]
|
||||
|
||||
[:li {:class (dom/classnames
|
||||
(css :filter-menu-item) true
|
||||
(css :selected) (contains? current-filters :mask))
|
||||
:data-filter "mask"
|
||||
:on-click add-filter}
|
||||
[:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-icon) true)} i/mask-refactor]
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-name) true)}
|
||||
(tr "workspace.sidebar.layers.masks")]]
|
||||
(when (contains? current-filters :mask)
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-tick) true)} i/tick-refactor])]
|
||||
|
||||
[:li {:class (dom/classnames
|
||||
(css :filter-menu-item) true
|
||||
(css :selected) (contains? current-filters :component))
|
||||
:data-filter "component"
|
||||
:on-click add-filter}
|
||||
[:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-icon) true)} i/component-refactor]
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-name) true)}
|
||||
(tr "workspace.sidebar.layers.components")]]
|
||||
(when (contains? current-filters :component)
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-tick) true)} i/tick-refactor])]
|
||||
[:li {:class (dom/classnames
|
||||
(css :filter-menu-item) true
|
||||
(css :selected) (contains? current-filters :text))
|
||||
:data-filter "text"
|
||||
:on-click add-filter}
|
||||
[:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-icon) true)} i/text-refactor]
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-name) true)}
|
||||
(tr "workspace.sidebar.layers.texts")]]
|
||||
(when (contains? current-filters :text)
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-tick) true)} i/tick-refactor])]
|
||||
|
||||
[:li {:class (dom/classnames
|
||||
(css :filter-menu-item) true
|
||||
(css :selected) (contains? current-filters :image))
|
||||
:data-filter "image"
|
||||
:on-click add-filter}
|
||||
[:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-icon) true)} i/img-refactor]
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-name) true)}
|
||||
(tr "workspace.sidebar.layers.images")]]
|
||||
(when (contains? current-filters :image)
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-tick) true)} i/tick-refactor])]
|
||||
[:li {:class (dom/classnames
|
||||
(css :filter-menu-item) true
|
||||
(css :selected) (contains? current-filters :shape))
|
||||
:data-filter "shape"
|
||||
:on-click add-filter}
|
||||
[:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-icon) true)} i/path-refactor]
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-name) true)}
|
||||
(tr "workspace.sidebar.layers.shapes")]]
|
||||
(when (contains? current-filters :shape)
|
||||
[:span {:class (dom/classnames (css :filter-menu-item-tick) true)} i/tick-refactor])]]
|
||||
|
||||
[:div.filters-container
|
||||
[:span {:data-filter "frame"
|
||||
:on-click add-filter}
|
||||
i/artboard (tr "workspace.sidebar.layers.frames")]
|
||||
[:span {:data-filter "group"
|
||||
:on-click add-filter}
|
||||
i/folder (tr "workspace.sidebar.layers.groups")]
|
||||
[:span {:data-filter "mask"
|
||||
:on-click add-filter}
|
||||
i/mask (tr "workspace.sidebar.layers.masks")]
|
||||
[:span {:data-filter "component"
|
||||
:on-click add-filter}
|
||||
i/component (tr "workspace.sidebar.layers.components")]
|
||||
[:span {:data-filter "text"
|
||||
:on-click add-filter}
|
||||
i/text (tr "workspace.sidebar.layers.texts")]
|
||||
[:span {:data-filter "image"
|
||||
:on-click add-filter}
|
||||
i/image (tr "workspace.sidebar.layers.images")]
|
||||
[:span {:data-filter "shape"
|
||||
:on-click add-filter}
|
||||
i/curve (tr "workspace.sidebar.layers.shapes")]]))]
|
||||
|
||||
(if ^boolean new-css-system
|
||||
[:div {:class (dom/classnames (css :tool-window-bar) true)}
|
||||
[:& title-bar {:collapsable? false
|
||||
:title (:name page)
|
||||
:on-btn-click toggle-search
|
||||
:btn-children i/search-refactor}]]
|
||||
|
||||
[:div.tool-window-bar
|
||||
[:span.page-name
|
||||
(:name page)]
|
||||
[:button.icon-search {:on-click toggle-search}
|
||||
i/search]])))]))
|
||||
|
||||
(mf/defc layers-toolbox
|
||||
{:wrap [mf/memo]}
|
||||
[{:keys [size-parent] :as props}]
|
||||
(let [page (mf/deref refs/workspace-page)
|
||||
focus (mf/deref refs/workspace-focus-selected)
|
||||
objects (hooks/with-focus-objects (:objects page) focus)
|
||||
title (when (= 1 (count focus)) (get-in objects [(first focus) :name]))
|
||||
{::mf/wrap [mf/memo]
|
||||
::mf/wrap-props false}
|
||||
[{:keys [size-parent]}]
|
||||
(let [page (mf/deref refs/workspace-page)
|
||||
focus (mf/deref refs/workspace-focus-selected)
|
||||
|
||||
objects (hooks/with-focus-objects (:objects page) focus)
|
||||
title (when (= 1 (count focus))
|
||||
(dm/get-in objects [(first focus) :name]))
|
||||
|
||||
new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
observer-var (mf/use-var nil)
|
||||
lazy-load-ref (mf/use-ref nil)
|
||||
observer-var (mf/use-var nil)
|
||||
lazy-load-ref (mf/use-ref nil)
|
||||
|
||||
[filtered-objects show-more filter-component] (use-search page objects)
|
||||
|
||||
|
@ -434,16 +471,16 @@
|
|||
|
||||
on-render-container
|
||||
(fn [element]
|
||||
(let [options #js {:root element}
|
||||
lazy-el (mf/ref-val lazy-load-ref)]
|
||||
(when-let [lazy-node (mf/ref-val lazy-load-ref)]
|
||||
(cond
|
||||
(and (some? element) (not (some? @observer-var)))
|
||||
(let [observer (js/IntersectionObserver. intersection-callback options)]
|
||||
(.observe observer lazy-el)
|
||||
(let [observer (js/IntersectionObserver. intersection-callback
|
||||
#js {:root element})]
|
||||
(.observe observer lazy-node)
|
||||
(reset! observer-var observer))
|
||||
|
||||
(and (nil? element) (some? @observer-var))
|
||||
(do (.disconnect @observer-var)
|
||||
(do (.disconnect ^js @observer-var)
|
||||
(reset! observer-var nil)))))
|
||||
|
||||
on-scroll
|
||||
|
@ -505,18 +542,17 @@
|
|||
[:div {:class (dom/classnames (css :focus-mode-tag-wrapper) true)}
|
||||
[:div {:class (dom/classnames (css :focus-mode-tag) true)} (tr "workspace.focus.focus-mode")]]
|
||||
[:div.focus-mode (tr "workspace.focus.focus-mode")])]]
|
||||
filter-component)
|
||||
(filter-component))
|
||||
(if (some? filtered-objects)
|
||||
[:*
|
||||
[:div {:class (if new-css-system
|
||||
(dom/classnames (css :tool-window-content) true)
|
||||
(dom/classnames :tool-window-content true))
|
||||
:ref on-render-container :key "filters"}
|
||||
:ref on-render-container}
|
||||
[:& filters-tree {:objects filtered-objects
|
||||
:key (dm/str (:id page))
|
||||
:parent-size size-parent}]
|
||||
[:div.lazy {:ref lazy-load-ref
|
||||
:key "lazy-load"
|
||||
:style {:min-height 16}}]]
|
||||
[:div {:on-scroll on-scroll
|
||||
:class (if new-css-system
|
||||
|
|
Loading…
Add table
Reference in a new issue