diff --git a/common/src/app/common/types/color.cljc b/common/src/app/common/types/color.cljc index ab50f4be0..c5cbb888b 100644 --- a/common/src/app/common/types/color.cljc +++ b/common/src/app/common/types/color.cljc @@ -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")) diff --git a/frontend/src/app/main/data/workspace/colors.cljs b/frontend/src/app/main/data/workspace/colors.cljs index 85c096a46..cdcc683a7 100644 --- a/frontend/src/app/main/data/workspace/colors.cljs +++ b/frontend/src/app/main/data/workspace/colors.cljs @@ -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 diff --git a/frontend/src/app/main/ui/workspace/color_palette.cljs b/frontend/src/app/main/ui/workspace/color_palette.cljs index 6d4c2c9c9..37a9bf4be 100644 --- a/frontend/src/app/main/ui/workspace/color_palette.cljs +++ b/frontend/src/app/main/ui/workspace/color_palette.cljs @@ -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])))) diff --git a/frontend/src/app/main/ui/workspace/color_palette.scss b/frontend/src/app/main/ui/workspace/color_palette.scss index 396245369..f8f3ed244 100644 --- a/frontend/src/app/main/ui/workspace/color_palette.scss +++ b/frontend/src/app/main/ui/workspace/color_palette.scss @@ -74,6 +74,8 @@ .color-palette-content { overflow: hidden; + display: flex; + align-items: center; } .color-palette-inside { diff --git a/frontend/src/app/main/ui/workspace/palette.cljs b/frontend/src/app/main/ui/workspace/palette.cljs index 37085382c..5fc91d538 100644 --- a/frontend/src/app/main/ui/workspace/palette.cljs +++ b/frontend/src/app/main/ui/workspace/palette.cljs @@ -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"} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs index 3766cbb52..a6beaa797 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs @@ -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?)