Add performance oriented refactor for color palette components

This commit is contained in:
Andrey Antukh 2025-01-16 21:04:49 +01:00
parent 6d666c4926
commit 068dd5f4bc
6 changed files with 93 additions and 71 deletions

View file

@ -115,6 +115,9 @@
(sm/register! ::recent-color schema:recent-color) (sm/register! ::recent-color schema:recent-color)
(sm/register! ::color-attrs schema:color-attrs) (sm/register! ::color-attrs schema:color-attrs)
(def valid-color?
(sm/lazy-validator schema:color))
(def check-color! (def check-color!
(sm/check-fn schema:color :hint "expected valid color struct")) (sm/check-fn schema:color :hint "expected valid color struct"))

View file

@ -146,7 +146,8 @@
(rx/of (dwsh/update-shapes shape-ids transform-attrs))))))) (rx/of (dwsh/update-shapes shape-ids transform-attrs)))))))
(defn change-fill (defn change-fill
([ids color position] (change-fill ids color position nil)) ([ids color position]
(change-fill ids color position nil))
([ids color position options] ([ids color position options]
(ptk/reify ::change-fill (ptk/reify ::change-fill
ptk/WatchEvent ptk/WatchEvent

View file

@ -8,19 +8,21 @@
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.types.color :as ctc]
[app.main.data.event :as ev] [app.main.data.event :as ev]
[app.main.data.workspace.colors :as mdc] [app.main.data.workspace.colors :as mdc]
[app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.libraries :as dwl]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.color-bullet :as cb] [app.main.ui.components.color-bullet :as cb]
[app.main.ui.hooks :as h] [app.main.ui.context :as ctx]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.util.color :as uc] [app.util.color :as uc]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.i18n :refer [tr]] [app.util.i18n :refer [tr]]
[app.util.keyboard :as kbd] [app.util.keyboard :as kbd]
[app.util.object :as obj] [app.util.object :as obj]
[okulary.core :as l]
[potok.v2.core :as ptk] [potok.v2.core :as ptk]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
@ -48,10 +50,8 @@
[:& cb/color-name {:color color :size size :origin :palette}]])) [:& cb/color-name {:color color :size size :origin :palette}]]))
(mf/defc palette* (mf/defc palette*
[{:keys [current-colors size width selected]}] [{:keys [colors size width selected]}]
(let [;; We had to do this due to a bug that leave some bugged colors (let [state (mf/use-state #(do {:show-menu false}))
current-colors (h/use-equal-memo (filter #(or (:gradient %) (:color %) (:image %)) current-colors))
state (mf/use-state {:show-menu false})
offset-step (cond offset-step (cond
(<= size 64) 40 (<= size 64) 40
(<= size 80) 72 (<= size 80) 72
@ -61,12 +61,12 @@
:else 132) :else 132)
width (- width buttons-size) width (- width buttons-size)
visible (int (/ width offset-step)) visible (int (/ width offset-step))
show-arrows? (> (count current-colors) visible) show-arrows? (> (count colors) visible)
visible (if show-arrows? visible (if show-arrows?
(int (/ (- width 48) offset-step)) (int (/ (- width 48) offset-step))
visible) visible)
offset (:offset @state 0) offset (:offset @state 0)
max-offset (- (count current-colors) max-offset (- (count colors)
visible) visible)
container (mf/use-ref nil) container (mf/use-ref nil)
bullet-size (cond bullet-size (cond
@ -79,7 +79,7 @@
:else 64) :else 64)
on-left-arrow-click on-left-arrow-click
(mf/use-callback (mf/use-fn
(mf/deps max-offset visible) (mf/deps max-offset visible)
(fn [_] (fn [_]
(swap! state update :offset (swap! state update :offset
@ -89,7 +89,7 @@
offset))))) offset)))))
on-right-arrow-click on-right-arrow-click
(mf/use-callback (mf/use-fn
(mf/deps max-offset visible) (mf/deps max-offset visible)
(fn [_] (fn [_]
(swap! state update :offset (swap! state update :offset
@ -99,7 +99,7 @@
offset))))) offset)))))
on-scroll on-scroll
(mf/use-callback (mf/use-fn
(mf/deps max-offset) (mf/deps max-offset)
(fn [event] (fn [event]
(let [event (dom/event->native-event event) (let [event (dom/event->native-event event)
@ -109,12 +109,12 @@
(on-right-arrow-click event) (on-right-arrow-click event)
(on-left-arrow-click event)))))] (on-left-arrow-click event)))))]
(mf/use-layout-effect (mf/with-layout-effect []
#(let [dom (mf/ref-val container) (let [dom (mf/ref-val container)
width (obj/get dom "clientWidth")] width (obj/get dom "clientWidth")]
(swap! state assoc :width width))) (swap! state assoc :width width)))
(mf/with-effect [width current-colors] (mf/with-effect [width colors]
(when (not= 0 (:offset @state)) (when (not= 0 (:offset @state))
(swap! state assoc :offset 0))) (swap! state assoc :offset 0)))
@ -129,7 +129,7 @@
[:div {:class (stl/css :color-palette-content) [:div {:class (stl/css :color-palette-content)
:ref container :ref container
:on-wheel on-scroll} :on-wheel on-scroll}
(if (empty? current-colors) (if (empty? colors)
[:div {:class (stl/css :color-palette-empty) [:div {:class (stl/css :color-palette-empty)
:style {:position "absolute" :style {:position "absolute"
:left "50%" :left "50%"
@ -140,44 +140,61 @@
:style {:position "relative" :style {:position "relative"
:max-width (str width "px") :max-width (str width "px")
:right (str (* offset-step offset) "px")}} :right (str (* offset-step offset) "px")}}
(for [[idx item] (map-indexed vector current-colors)] (for [[idx item] (map-indexed vector colors)]
[:> palette-item* {:color item :key idx :size size :selected selected}])])] [:> palette-item* {:color item :key idx :size size :selected selected}])])]
(when show-arrows? (when show-arrows?
[:button {:class (stl/css :right-arrow) [:button {:class (stl/css :right-arrow)
:disabled (= offset max-offset) :disabled (= offset max-offset)
:on-click on-right-arrow-click} i/arrow])])) :on-click on-right-arrow-click} i/arrow])]))
(defn library->colors [shared-libs selected] (mf/defc recent-colors-palette*
(map #(merge % {:file-id selected}) {::mf/private true}
(-> shared-libs [props]
(get-in [selected :data :colors]) (let [colors (mf/deref refs/recent-colors)
(vals))))
(mf/defc color-palette colors (mf/with-memo [colors]
(->> (reverse colors)
(filter ctc/valid-color?)
(vec)))
props (mf/spread-props props {:colors colors})]
[:> palette* props]))
(defn- make-library-colors-ref
[file-id]
(l/derived (fn [libraries]
(dm/get-in libraries [file-id :data :colors]))
refs/libraries))
(mf/defc file-color-palette*
{::mf/private true}
[{:keys [file-id] :as props}]
(let [colors-ref (mf/with-memo [file-id]
(make-library-colors-ref file-id))
colors (mf/deref colors-ref)
colors (mf/with-memo [colors file-id]
(->> (vals colors)
(filter ctc/valid-color?)
(map #(assoc % :file-id file-id))
(sort-by :name)
(vec)))
props (mf/spread-props props {:colors colors})]
[:> palette* props]))
(mf/defc color-palette*
{::mf/wrap [mf/memo]} {::mf/wrap [mf/memo]}
[{:keys [size width selected] :as props}] [{:keys [selected] :as props}]
(let [recent-colors (mf/deref refs/recent-colors) (let [file-id (mf/use-ctx ctx/current-file-id)]
file-colors (mf/deref refs/workspace-file-colors) (cond
shared-libs (mf/deref refs/libraries) (= selected :recent)
colors (mf/use-state [])] [:> recent-colors-palette* props]
(mf/with-effect [selected shared-libs] (= selected :file)
(let [colors' (cond (let [props (mf/spread-props props {:file-id file-id})]
(= selected :recent) (reverse recent-colors) [:> file-color-palette* props])
(= selected :file) (->> (vals file-colors) (sort-by :name))
:else (->> (library->colors shared-libs selected) (sort-by :name)))]
(reset! colors (into [] colors'))))
(mf/with-effect [recent-colors selected] :else
(when (= selected :recent) (let [props (mf/spread-props props {:file-id selected})]
(reset! colors (reverse recent-colors)))) [:> file-color-palette* props]))))
(mf/with-effect [file-colors selected]
(when (= selected :file)
(reset! colors (into [] (->> (vals file-colors)
(sort-by :name))))))
[:> palette* {:current-colors @colors
:size size
:width width
:selected selected}]))

View file

@ -74,6 +74,8 @@
.color-palette-content { .color-palette-content {
overflow: hidden; overflow: hidden;
display: flex;
align-items: center;
} }
.color-palette-inside { .color-palette-inside {

View file

@ -19,7 +19,7 @@
[app.main.ui.hooks :as h] [app.main.ui.hooks :as h]
[app.main.ui.hooks.resize :as r] [app.main.ui.hooks.resize :as r]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.main.ui.workspace.color-palette :refer [color-palette]] [app.main.ui.workspace.color-palette :refer [color-palette*]]
[app.main.ui.workspace.color-palette-ctx-menu :refer [color-palette-ctx-menu]] [app.main.ui.workspace.color-palette-ctx-menu :refer [color-palette-ctx-menu]]
[app.main.ui.workspace.text-palette :refer [text-palette]] [app.main.ui.workspace.text-palette :refer [text-palette]]
[app.main.ui.workspace.text-palette-ctx-menu :refer [text-palette-ctx-menu]] [app.main.ui.workspace.text-palette-ctx-menu :refer [text-palette-ctx-menu]]
@ -195,11 +195,12 @@
:selected selected-text :selected selected-text
:width vport-width}]]) :width vport-width}]])
(when color-palette? (when color-palette?
[:* [:& color-palette-ctx-menu {:show-menu? show-menu? [:*
[:& color-palette-ctx-menu {:show-menu? show-menu?
:close-menu on-close-menu :close-menu on-close-menu
:on-select-palette on-select-palette :on-select-palette on-select-palette
:selected @selected}] :selected @selected}]
[:& color-palette {:size size [:> color-palette* {:size size
:selected @selected :selected @selected
:width vport-width}]])]] :width vport-width}]])]]
[:div {:class (stl/css :handler) [:div {:class (stl/css :handler)

View file

@ -19,7 +19,6 @@
[app.main.ui.components.color-input :refer [color-input*]] [app.main.ui.components.color-input :refer [color-input*]]
[app.main.ui.components.numeric-input :refer [numeric-input*]] [app.main.ui.components.numeric-input :refer [numeric-input*]]
[app.main.ui.components.reorder-handler :refer [reorder-handler]] [app.main.ui.components.reorder-handler :refer [reorder-handler]]
[app.main.ui.context :as ctx]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.formats :as fmt] [app.main.ui.formats :as fmt]
[app.main.ui.hooks :as h] [app.main.ui.hooks :as h]
@ -49,8 +48,7 @@
[{:keys [index color disable-gradient disable-opacity disable-image disable-picker on-change [{:keys [index color disable-gradient disable-opacity disable-image disable-picker on-change
on-reorder on-detach on-open on-close on-remove on-reorder on-detach on-open on-close on-remove
disable-drag on-focus on-blur select-only select-on-focus]}] disable-drag on-focus on-blur select-only select-on-focus]}]
(let [current-file-id (mf/use-ctx ctx/current-file-id) (let [shared-libs (mf/deref refs/libraries)
shared-libs (mf/deref refs/libraries)
hover-detach (mf/use-state false) hover-detach (mf/use-state false)
on-change (h/use-ref-callback on-change) on-change (h/use-ref-callback on-change)