mirror of
https://github.com/penpot/penpot.git
synced 2025-02-13 18:48:37 -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/defc search-bar
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
(let [children (unchecked-get props "children")
|
(let [children (unchecked-get props "children")
|
||||||
on-change (unchecked-get props "on-change")
|
on-change (unchecked-get props "on-change")
|
||||||
value (unchecked-get props "value")
|
value (unchecked-get props "value")
|
||||||
on-clear (unchecked-get props "clear-action")
|
on-clear (unchecked-get props "clear-action")
|
||||||
placeholder (unchecked-get props "placeholder")
|
placeholder (unchecked-get props "placeholder")
|
||||||
icon (unchecked-get props "icon")
|
icon (unchecked-get props "icon")
|
||||||
|
|
||||||
handle-change
|
handle-change
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps on-change)
|
(mf/deps on-change)
|
||||||
|
@ -57,4 +57,4 @@
|
||||||
(when (not= "" value)
|
(when (not= "" value)
|
||||||
[:button {:class (dom/classnames (css :clear) true)
|
[:button {:class (dom/classnames (css :clear) true)
|
||||||
:on-click handle-clear}
|
:on-click handle-clear}
|
||||||
i/delete-text-refactor])]]))
|
i/delete-text-refactor])]]))
|
||||||
|
|
|
@ -30,7 +30,8 @@
|
||||||
|
|
||||||
|
|
||||||
(mf/defc layer-item
|
(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)
|
(let [id (:id item)
|
||||||
blocked? (:blocked item)
|
blocked? (:blocked item)
|
||||||
hidden? (:hidden item)
|
hidden? (:hidden item)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
|
[app.common.pages.helpers :as cph]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
|
@ -101,7 +102,6 @@
|
||||||
|
|
||||||
(defn calc-reparented-objects
|
(defn calc-reparented-objects
|
||||||
[objects]
|
[objects]
|
||||||
|
|
||||||
(let [reparented-objects
|
(let [reparented-objects
|
||||||
(d/mapm (fn [_ val]
|
(d/mapm (fn [_ val]
|
||||||
(assoc val :parent-id uuid/zero :shapes nil))
|
(assoc val :parent-id uuid/zero :shapes nil))
|
||||||
|
@ -116,314 +116,351 @@
|
||||||
|
|
||||||
;; --- Layers Toolbox
|
;; --- 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
|
(defn use-search
|
||||||
[page objects]
|
[page objects]
|
||||||
(let [filter-state (mf/use-state {:show-search-box false
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
:show-filters-menu false
|
state* (mf/use-state
|
||||||
:search-text ""
|
{:show-search false
|
||||||
:active-filters #{}
|
:show-menu false
|
||||||
:num-items 100})
|
:search-text ""
|
||||||
new-css-system (mf/use-ctx ctx/new-css-system)
|
: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
|
clear-search-text
|
||||||
(mf/use-callback
|
|
||||||
(fn []
|
|
||||||
(swap! filter-state assoc :search-text "" :num-items 100)))
|
|
||||||
|
|
||||||
update-search-text
|
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps new-css-system)
|
#(swap! state* assoc :search-text "" :num-items 100))
|
||||||
(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))))
|
|
||||||
|
|
||||||
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
|
toggle-filters
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(fn []
|
#(swap! state* update :show-menu not))
|
||||||
(swap! filter-state update :show-filters-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
|
remove-filter
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(mf/deps @filter-state)
|
(fn [event]
|
||||||
(fn [key]
|
(let [fkey (-> (dom/get-current-target event)
|
||||||
(fn [_]
|
(dom/get-data "filter")
|
||||||
(swap! filter-state update :active-filters disj key)
|
(keyword))]
|
||||||
(swap! filter-state assoc :num-items 100))))
|
(swap! state* (fn [state]
|
||||||
|
(-> state
|
||||||
|
(update :filters disj fkey)
|
||||||
|
(assoc :num-items 100)))))))
|
||||||
|
|
||||||
add-filter
|
add-filter
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(mf/deps @filter-state (:show-filters-menu @filter-state))
|
(fn [event]
|
||||||
(fn [key]
|
(let [key (-> (dom/get-current-target event)
|
||||||
(fn [_]
|
(dom/get-data "filter")
|
||||||
(swap! filter-state update :active-filters conj key)
|
(keyword))]
|
||||||
(swap! filter-state assoc :num-items 100)
|
(swap! state* (fn [state]
|
||||||
(toggle-filters))))
|
(-> state
|
||||||
|
(update :filters conj key)
|
||||||
|
(update :show-menu not)
|
||||||
|
(assoc :num-items 100)))))))
|
||||||
|
|
||||||
active?
|
active?
|
||||||
(and
|
(and ^boolean show-search?
|
||||||
(:show-search-box @filter-state)
|
(or ^boolean (d/not-empty? current-search)
|
||||||
(or (d/not-empty? (:search-text @filter-state))
|
^boolean (d/not-empty? current-filters)))
|
||||||
(d/not-empty? (:active-filters @filter-state))))
|
|
||||||
|
|
||||||
search-and-filters
|
filtered-objects-all
|
||||||
(fn [[id shape]]
|
(mf/with-memo [active? objects state]
|
||||||
(let [search (:search-text @filter-state)
|
(when active?
|
||||||
filters (:active-filters @filter-state)
|
(into [] (filter (partial match-filters? state)) objects)))
|
||||||
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-total
|
filtered-objects-total
|
||||||
(mf/use-memo
|
(count filtered-objects-all)
|
||||||
(mf/deps objects active? @filter-state)
|
|
||||||
#(when active?
|
|
||||||
;; filterv so count is constant time
|
|
||||||
(filterv search-and-filters objects)))
|
|
||||||
|
|
||||||
filtered-objects
|
filtered-objects
|
||||||
(mf/use-memo
|
(mf/with-memo [active? filtered-objects-all current-items]
|
||||||
(mf/deps filtered-objects-total)
|
(when active?
|
||||||
#(when active?
|
(->> filtered-objects-all
|
||||||
(calc-reparented-objects
|
(into {} (take current-items))
|
||||||
(into {}
|
(calc-reparented-objects))))
|
||||||
(take (:num-items @filter-state))
|
|
||||||
filtered-objects-total))))
|
|
||||||
|
|
||||||
handle-show-more
|
handle-show-more
|
||||||
(fn []
|
(mf/use-fn
|
||||||
(when (<= (:num-items @filter-state) (count filtered-objects-total))
|
(mf/deps filtered-objects-total current-items)
|
||||||
(swap! filter-state update :num-items + 100)))
|
(fn [_]
|
||||||
|
(when (<= current-items filtered-objects-total)
|
||||||
|
(swap! state* update :num-items + 100))))
|
||||||
|
|
||||||
handle-key-down
|
handle-key-down
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [enter? (kbd/enter? event)
|
(when-let [node (dom/event->target event)]
|
||||||
esc? (kbd/esc? event)
|
(when (kbd/enter? event)
|
||||||
node (dom/event->target event)]
|
(dom/blur! node))
|
||||||
(when ^boolean enter? (dom/blur! node))
|
(when (kbd/esc? event)
|
||||||
(when ^boolean esc? (dom/blur! node)))))]
|
(dom/blur! node)))))]
|
||||||
|
|
||||||
[filtered-objects
|
[filtered-objects
|
||||||
handle-show-more
|
handle-show-more
|
||||||
(mf/html
|
#(mf/html
|
||||||
(if (:show-search-box @filter-state)
|
(if show-search?
|
||||||
[:*
|
[:*
|
||||||
[:div {:class (if new-css-system
|
[:div {:class (if ^boolean new-css-system
|
||||||
(dom/classnames (css :tool-window-bar) true
|
(dom/classnames (css :tool-window-bar) true
|
||||||
(css :search) true)
|
(css :search) true)
|
||||||
(dom/classnames :tool-window-bar true
|
(dom/classnames :tool-window-bar true
|
||||||
:search 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]]
|
|
||||||
|
|
||||||
[:span.search-box
|
(if ^boolean new-css-system
|
||||||
[:button.filter
|
[:& search-bar
|
||||||
{:on-click toggle-filters
|
{:on-change update-search-text-v2
|
||||||
:class (dom/classnames :active active?)}
|
:value current-search
|
||||||
i/icon-filter]
|
:on-clear clear-search-text
|
||||||
[:div
|
:placeholder (tr "workspace.sidebar.layers.search")}
|
||||||
[:input {:on-change update-search-text
|
[:button
|
||||||
:value (:search-text @filter-state)
|
{:on-click toggle-filters
|
||||||
:auto-focus (:show-search-box @filter-state)
|
:class (dom/classnames :active active?
|
||||||
:placeholder (tr "workspace.sidebar.layers.search")
|
(css :filter-button) true)}
|
||||||
:on-key-down handle-key-down}]
|
i/filter-refactor]]
|
||||||
(when (not (= "" (:search-text @filter-state)))
|
|
||||||
[:button.clear {:on-click clear-search-text}
|
|
||||||
i/exclude])]])
|
|
||||||
|
|
||||||
[:button {:class (dom/classnames (css :close-search) new-css-system)
|
[:span.search-box
|
||||||
:on-click toggle-search}
|
[:button.filter
|
||||||
(if new-css-system
|
{:on-click toggle-filters
|
||||||
i/close-refactor
|
:class (dom/classnames :active active?)}
|
||||||
i/cross)]]
|
i/icon-filter]
|
||||||
[:div {:class (if new-css-system
|
[:div
|
||||||
(dom/classnames (css :active-filters) true)
|
[:input {:on-change update-search-text-v1
|
||||||
(dom/classnames :active-filters true))}
|
:value current-search
|
||||||
(for [f (:active-filters @filter-state)]
|
:auto-focus show-search?
|
||||||
(let [name (case f
|
:placeholder (tr "workspace.sidebar.layers.search")
|
||||||
:frame (tr "workspace.sidebar.layers.frames")
|
:on-key-down handle-key-down}]
|
||||||
:group (tr "workspace.sidebar.layers.groups")
|
(when (not (= "" current-search))
|
||||||
:mask (tr "workspace.sidebar.layers.masks")
|
[:button.clear {:on-click clear-search-text} i/exclude])]])
|
||||||
: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])))]
|
|
||||||
|
|
||||||
(when (:show-filters-menu @filter-state)
|
[:button {:class (dom/classnames (css :close-search) new-css-system)
|
||||||
(if new-css-system
|
:on-click toggle-search}
|
||||||
[:ul {:class (dom/classnames (css :filters-container) true)}
|
(if ^boolean new-css-system
|
||||||
[:li {:key "frames-filter-item"
|
i/close-refactor
|
||||||
:class (dom/classnames (css :filter-menu-item) true
|
i/cross)]]
|
||||||
(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])]]
|
|
||||||
|
|
||||||
[:div.filters-container
|
[:div {:class (if ^boolean new-css-system
|
||||||
[:span {:on-click (add-filter :frame)} i/artboard (tr "workspace.sidebar.layers.frames")]
|
(dom/classnames (css :active-filters) true)
|
||||||
[:span {:on-click (add-filter :group)} i/folder (tr "workspace.sidebar.layers.groups")]
|
(dom/classnames :active-filters true))}
|
||||||
[:span {:on-click (add-filter :mask)} i/mask (tr "workspace.sidebar.layers.masks")]
|
(for [fkey current-filters]
|
||||||
[:span {:on-click (add-filter :component)} i/component (tr "workspace.sidebar.layers.components")]
|
(let [fname (d/name fkey)
|
||||||
[:span {:on-click (add-filter :text)} i/text (tr "workspace.sidebar.layers.texts")]
|
name (case fkey
|
||||||
[:span {:on-click (add-filter :image)} i/image (tr "workspace.sidebar.layers.images")]
|
:frame (tr "workspace.sidebar.layers.frames")
|
||||||
[:span {:on-click (add-filter :shape)} i/curve (tr "workspace.sidebar.layers.shapes")]]))]
|
: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
|
[:span {:on-click remove-filter
|
||||||
[:div {:class (dom/classnames (css :tool-window-bar) true)}
|
:data-filter fname
|
||||||
[:& title-bar {:collapsable? false
|
:key fname}
|
||||||
:title (:name page)
|
name i/cross])))]
|
||||||
:on-btn-click toggle-search
|
|
||||||
:btn-children i/search-refactor}]]
|
(when ^boolean show-menu?
|
||||||
[:div.tool-window-bar
|
(if ^boolean new-css-system
|
||||||
[:span.page-name
|
[:ul {:class (css :filters-container)}
|
||||||
(:name page)]
|
[:li {:class (dom/classnames
|
||||||
[:button.icon-search {:on-click toggle-search}
|
(css :filter-menu-item) true
|
||||||
i/search]])))]))
|
(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
|
(mf/defc layers-toolbox
|
||||||
{:wrap [mf/memo]}
|
{::mf/wrap [mf/memo]
|
||||||
[{:keys [size-parent] :as props}]
|
::mf/wrap-props false}
|
||||||
(let [page (mf/deref refs/workspace-page)
|
[{:keys [size-parent]}]
|
||||||
focus (mf/deref refs/workspace-focus-selected)
|
(let [page (mf/deref refs/workspace-page)
|
||||||
objects (hooks/with-focus-objects (:objects page) focus)
|
focus (mf/deref refs/workspace-focus-selected)
|
||||||
title (when (= 1 (count focus)) (get-in objects [(first focus) :name]))
|
|
||||||
|
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)
|
new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
observer-var (mf/use-var nil)
|
observer-var (mf/use-var nil)
|
||||||
lazy-load-ref (mf/use-ref nil)
|
lazy-load-ref (mf/use-ref nil)
|
||||||
|
|
||||||
[filtered-objects show-more filter-component] (use-search page objects)
|
[filtered-objects show-more filter-component] (use-search page objects)
|
||||||
|
|
||||||
|
@ -434,16 +471,16 @@
|
||||||
|
|
||||||
on-render-container
|
on-render-container
|
||||||
(fn [element]
|
(fn [element]
|
||||||
(let [options #js {:root element}
|
(when-let [lazy-node (mf/ref-val lazy-load-ref)]
|
||||||
lazy-el (mf/ref-val lazy-load-ref)]
|
|
||||||
(cond
|
(cond
|
||||||
(and (some? element) (not (some? @observer-var)))
|
(and (some? element) (not (some? @observer-var)))
|
||||||
(let [observer (js/IntersectionObserver. intersection-callback options)]
|
(let [observer (js/IntersectionObserver. intersection-callback
|
||||||
(.observe observer lazy-el)
|
#js {:root element})]
|
||||||
|
(.observe observer lazy-node)
|
||||||
(reset! observer-var observer))
|
(reset! observer-var observer))
|
||||||
|
|
||||||
(and (nil? element) (some? @observer-var))
|
(and (nil? element) (some? @observer-var))
|
||||||
(do (.disconnect @observer-var)
|
(do (.disconnect ^js @observer-var)
|
||||||
(reset! observer-var nil)))))
|
(reset! observer-var nil)))))
|
||||||
|
|
||||||
on-scroll
|
on-scroll
|
||||||
|
@ -505,18 +542,17 @@
|
||||||
[:div {:class (dom/classnames (css :focus-mode-tag-wrapper) true)}
|
[: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 {:class (dom/classnames (css :focus-mode-tag) true)} (tr "workspace.focus.focus-mode")]]
|
||||||
[:div.focus-mode (tr "workspace.focus.focus-mode")])]]
|
[:div.focus-mode (tr "workspace.focus.focus-mode")])]]
|
||||||
filter-component)
|
(filter-component))
|
||||||
(if (some? filtered-objects)
|
(if (some? filtered-objects)
|
||||||
[:*
|
[:*
|
||||||
[:div {:class (if new-css-system
|
[:div {:class (if new-css-system
|
||||||
(dom/classnames (css :tool-window-content) true)
|
(dom/classnames (css :tool-window-content) true)
|
||||||
(dom/classnames :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
|
[:& filters-tree {:objects filtered-objects
|
||||||
:key (dm/str (:id page))
|
:key (dm/str (:id page))
|
||||||
:parent-size size-parent}]
|
:parent-size size-parent}]
|
||||||
[:div.lazy {:ref lazy-load-ref
|
[:div.lazy {:ref lazy-load-ref
|
||||||
:key "lazy-load"
|
|
||||||
:style {:min-height 16}}]]
|
:style {:min-height 16}}]]
|
||||||
[:div {:on-scroll on-scroll
|
[:div {:on-scroll on-scroll
|
||||||
:class (if new-css-system
|
:class (if new-css-system
|
||||||
|
|
Loading…
Add table
Reference in a new issue