0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-02-01 11:59:17 -05:00

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! ::color-attrs schema:color-attrs)
(def valid-color?
(sm/lazy-validator schema:color))
(def check-color!
(sm/check-fn schema:color :hint "expected valid color struct"))

View file

@ -89,7 +89,7 @@
text-ids (filter is-text? ids)
shape-ids (remove is-text? ids)
undo-id (js/Symbol)
undo-id (js/Symbol)
attrs
(cond-> {}
@ -146,7 +146,8 @@
(rx/of (dwsh/update-shapes shape-ids transform-attrs)))))))
(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]
(ptk/reify ::change-fill
ptk/WatchEvent

View file

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

View file

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

View file

@ -19,7 +19,7 @@
[app.main.ui.hooks :as h]
[app.main.ui.hooks.resize :as r]
[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.text-palette :refer [text-palette]]
[app.main.ui.workspace.text-palette-ctx-menu :refer [text-palette-ctx-menu]]
@ -195,13 +195,14 @@
:selected selected-text
:width vport-width}]])
(when color-palette?
[:* [:& color-palette-ctx-menu {:show-menu? show-menu?
:close-menu on-close-menu
:on-select-palette on-select-palette
:selected @selected}]
[:& color-palette {:size size
:selected @selected
:width vport-width}]])]]
[:*
[:& color-palette-ctx-menu {:show-menu? show-menu?
:close-menu on-close-menu
:on-select-palette on-select-palette
:selected @selected}]
[:> color-palette* {:size size
:selected @selected
:width vport-width}]])]]
[:div {:class (stl/css :handler)
:on-click toggle-palettes
:data-testid "toggle-palettes-visibility"}

View file

@ -19,7 +19,6 @@
[app.main.ui.components.color-input :refer [color-input*]]
[app.main.ui.components.numeric-input :refer [numeric-input*]]
[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.formats :as fmt]
[app.main.ui.hooks :as h]
@ -49,24 +48,23 @@
[{:keys [index color disable-gradient disable-opacity disable-image disable-picker on-change
on-reorder on-detach on-open on-close on-remove
disable-drag on-focus on-blur select-only select-on-focus]}]
(let [current-file-id (mf/use-ctx ctx/current-file-id)
shared-libs (mf/deref refs/libraries)
hover-detach (mf/use-state false)
on-change (h/use-ref-callback on-change)
(let [shared-libs (mf/deref refs/libraries)
hover-detach (mf/use-state false)
on-change (h/use-ref-callback on-change)
src-colors (dm/get-in shared-libs [(:ref-file color) :data :colors])
color-name (dm/get-in src-colors [(:ref-id color) :name])
src-colors (dm/get-in shared-libs [(:ref-file color) :data :colors])
color-name (dm/get-in src-colors [(:ref-id color) :name])
multiple-colors? (uc/multiple? color)
library-color? (and (:ref-id color) color-name (not multiple-colors?))
gradient-color? (and (not multiple-colors?)
(:gradient color)
(dm/get-in color [:gradient :type]))
image-color? (and (not multiple-colors?)
(:image color))
image-color? (and (not multiple-colors?)
(:image color))
editing-text* (mf/use-state false)
editing-text? (deref editing-text*)
editing-text* (mf/use-state false)
editing-text? (deref editing-text*)
opacity?
(and (not multiple-colors?)