Merge pull request #5605 from penpot/niwinz-enhancements-2

 Add performance enhacements
This commit is contained in:
Aitor Moreno 2025-01-20 13:22:07 +01:00 committed by GitHub
commit 013a8c95df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 547 additions and 485 deletions

View file

@ -79,7 +79,6 @@
[component new-component-id library-data]
(let [components-v2 (dm/get-in library-data [:options :components-v2])]
(if components-v2
(let [main-instance-page (ctf/get-component-page library-data component)
main-instance-shape (ctf/get-component-root library-data component)
delta (gpt/point (+ (:width main-instance-shape) 50) 0)
@ -205,21 +204,23 @@
(cond-> {}
force-frame? (assoc :force-frame-id frame-id)))
first-shape (cond-> (first new-shapes)
(not (nil? parent-id))
(assoc :parent-id parent-id)
(and (not (nil? parent)) (= :frame (:type parent)))
(assoc :frame-id (:id parent))
(and (not (nil? parent)) (not= :frame (:type parent)))
(assoc :frame-id (:frame-id parent))
(and (not (nil? parent)) (ctn/in-any-component? objects parent))
(dissoc :component-root)
(and (nil? parent) (not (nil? frame-id)))
(assoc :frame-id frame-id))
first-shape
(cond-> (first new-shapes)
(not (nil? parent-id))
(assoc :parent-id parent-id)
(and (not (nil? parent)) (= :frame (:type parent)))
(assoc :frame-id (:id parent))
(and (not (nil? parent)) (not= :frame (:type parent)))
(assoc :frame-id (:frame-id parent))
(and (not (nil? parent)) (ctn/in-any-component? objects parent))
(dissoc :component-root)
(and (nil? parent) (not (nil? frame-id)))
(assoc :frame-id frame-id))
;; on copy/paste old id is used later to reorder the paster layers
changes (cond-> (pcb/add-object changes first-shape {:ignore-touched true})
(some? old-id) (pcb/amend-last-change #(assoc % :old-id old-id)))
changes
(cond-> (pcb/add-object changes first-shape {:ignore-touched true})
(some? old-id) (pcb/amend-last-change #(assoc % :old-id old-id)))
changes
(if (ctl/grid-layout? objects (:parent-id first-shape))
@ -240,9 +241,10 @@
(pcb/reorder-grid-children [(:parent-id first-shape)])))
changes)
changes (reduce #(pcb/add-object %1 %2 {:ignore-touched true})
changes
(rest new-shapes))]
changes
(reduce #(pcb/add-object %1 %2 {:ignore-touched true})
changes
(rest new-shapes))]
[new-shape changes])))
@ -1488,7 +1490,7 @@
(defn- update-tokens
"Token synchronization algorithm. Copy the applied tokens that have changed
in the origin shape to the dest shape (applying or removing as necessary).
Only the given token attributes are synced."
[changes container dest-shape orig-shape token-attrs]
(let [orig-tokens (get orig-shape :applied-tokens {})

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"))
@ -143,7 +146,6 @@
;; --- fill
;; FIXME: revisit, this generates invalid colors
(defn fill->shape-color
[fill]
(d/without-nils
@ -154,16 +156,6 @@
:ref-id (:fill-color-ref-id fill)
:ref-file (:fill-color-ref-file fill)}))
(defn fill->color
[fill]
(d/without-nils
{:color (:fill-color fill)
:opacity (:fill-opacity fill)
:gradient (:fill-color-gradient fill)
:image (:fill-image fill)
:id (:fill-color-ref-id fill)
:file-id (:fill-color-ref-file fill)}))
(defn set-fill-color
[shape position color opacity gradient image]
(update-in shape [:fills position]

View file

@ -464,8 +464,8 @@
Returns a list ((asset ((container shapes) (container shapes)...))...)"
[file-data library-data asset-type]
(let [assets-seq (case asset-type
:component (ctkl/components-seq library-data)
:color (ctcl/colors-seq library-data)
:component (ctkl/components-seq library-data)
:color (ctcl/colors-seq library-data)
:typography (ctyl/typographies-seq library-data))
find-usages-in-container

View file

@ -0,0 +1,65 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns common-tests.helpers-test
(:require
[app.common.data :as d]
[app.common.test-helpers.components :as thc]
[app.common.test-helpers.compositions :as tho]
[app.common.test-helpers.files :as thf]
[app.common.test-helpers.ids-map :as thi]
[app.common.test-helpers.shapes :as ths]
[clojure.test :as t]))
(t/use-fixtures :each thi/test-fixture)
(t/deftest create-file
(let [f1 (thf/sample-file :file1)
f2 (thf/sample-file :file2 :page-label :page1)
f3 (thf/sample-file :file3 :name "testing file")
f4 (-> (thf/sample-file :file4 :page-label :page2)
(thf/add-sample-page :page3 :name "testing page")
(ths/add-sample-shape :shape1))
f5 (-> f4
(ths/add-sample-shape :shape2)
(thf/switch-to-page :page2)
(ths/add-sample-shape :shape3 :name "testing shape" :width 100))
s1 (ths/get-shape f4 :shape1)
s2 (ths/get-shape f5 :shape2 :page-label :page3)
s3 (ths/get-shape f5 :shape3)]
;; (thf/pprint-file f4)
(t/is (= (:name f1) "Test file"))
(t/is (= (:name f3) "testing file"))
(t/is (= (:id f2) (thi/id :file2)))
(t/is (= (:id f4) (thi/id :file4)))
(t/is (= (-> f4 :data :pages-index vals first :id) (thi/id :page2)))
(t/is (= (-> f4 :data :pages-index vals first :name) "Page 1"))
(t/is (= (-> f4 :data :pages-index vals second :id) (thi/id :page3)))
(t/is (= (-> f4 :data :pages-index vals second :name) "testing page"))
(t/is (= (:id (thf/current-page f2)) (thi/id :page1)))
(t/is (= (:id (thf/current-page f4)) (thi/id :page3)))
(t/is (= (:id (thf/current-page f5)) (thi/id :page2)))
(t/is (= (:id s1) (thi/id :shape1)))
(t/is (= (:name s1) "Rectangle"))
(t/is (= (:id s2) (thi/id :shape2)))
(t/is (= (:name s2) "Rectangle"))
(t/is (= (:id s3) (thi/id :shape3)))
(t/is (= (:name s3) "testing shape"))
(t/is (= (:width s3) 100))
(t/is (= (:width (:selrect s3)) 100))))
(t/deftest create-components
(let [f1 (-> (thf/sample-file :file1)
(tho/add-simple-component-with-copy :component1 :main-root :main-child :copy-root))]
#_(thf/dump-file f1)
#_(thf/pprint-file f4)
(t/is (= (:name f1) "Test file"))))

View file

@ -35,12 +35,12 @@
[common-tests.svg-test]
[common-tests.text-test]
[common-tests.time-test]
[common-tests.types-modifiers-test]
[common-tests.types-shape-interactions-test]
[common-tests.types.absorb-assets-test]
[common-tests.types.components-test]
[common-tests.types.modifiers-test]
[common-tests.types.shape-decode-encode-test]
[common-tests.types.shape-interactions-test]
[common-tests.types.tokens-lib-test]
[common-tests.types.types-component-test]
[common-tests.types.types-libraries-test]
[common-tests.uuid-test]))
#?(:cljs (enable-console-print!))
@ -82,10 +82,10 @@
'common-tests.svg-test
'common-tests.text-test
'common-tests.time-test
'common-tests.types-modifiers-test
'common-tests.types-shape-interactions-test
'common-tests.types.modifiers-test
'common-tests.types.shape-interactions-test
'common-tests.types.shape-decode-encode-test
'common-tests.types.tokens-lib-test
'common-tests.types.types-component-test
'common-tests.types.types-libraries-test
'common-tests.types.components-test
'common-tests.types.absorb-assets-test
'common-tests.uuid-test))

View file

@ -4,7 +4,7 @@
;;
;; Copyright (c) KALEIDOS INC
(ns common-tests.types.types-libraries-test
(ns common-tests.types.absorb-assets-test
(:require
[app.common.data :as d]
[app.common.test-helpers.components :as thc]
@ -23,55 +23,7 @@
(t/use-fixtures :each thi/test-fixture)
(t/deftest test-create-file
(let [f1 (thf/sample-file :file1)
f2 (thf/sample-file :file2 :page-label :page1)
f3 (thf/sample-file :file3 :name "testing file")
f4 (-> (thf/sample-file :file4 :page-label :page2)
(thf/add-sample-page :page3 :name "testing page")
(ths/add-sample-shape :shape1))
f5 (-> f4
(ths/add-sample-shape :shape2)
(thf/switch-to-page :page2)
(ths/add-sample-shape :shape3 :name "testing shape" :width 100))
s1 (ths/get-shape f4 :shape1)
s2 (ths/get-shape f5 :shape2 :page-label :page3)
s3 (ths/get-shape f5 :shape3)]
;; (thf/pprint-file f4)
(t/is (= (:name f1) "Test file"))
(t/is (= (:name f3) "testing file"))
(t/is (= (:id f2) (thi/id :file2)))
(t/is (= (:id f4) (thi/id :file4)))
(t/is (= (-> f4 :data :pages-index vals first :id) (thi/id :page2)))
(t/is (= (-> f4 :data :pages-index vals first :name) "Page 1"))
(t/is (= (-> f4 :data :pages-index vals second :id) (thi/id :page3)))
(t/is (= (-> f4 :data :pages-index vals second :name) "testing page"))
(t/is (= (:id (thf/current-page f2)) (thi/id :page1)))
(t/is (= (:id (thf/current-page f4)) (thi/id :page3)))
(t/is (= (:id (thf/current-page f5)) (thi/id :page2)))
(t/is (= (:id s1) (thi/id :shape1)))
(t/is (= (:name s1) "Rectangle"))
(t/is (= (:id s2) (thi/id :shape2)))
(t/is (= (:name s2) "Rectangle"))
(t/is (= (:id s3) (thi/id :shape3)))
(t/is (= (:name s3) "testing shape"))
(t/is (= (:width s3) 100))
(t/is (= (:width (:selrect s3)) 100))))
(t/deftest test-create-components
(let [f1 (-> (thf/sample-file :file1)
(tho/add-simple-component-with-copy :component1 :main-root :main-child :copy-root))]
#_(thf/dump-file f1)
#_(thf/pprint-file f4)
(t/is (= (:name f1) "Test file"))))
(t/deftest test-absorb-components
(t/deftest absorb-components
(let [;; Setup
library (-> (thf/sample-file :library :is-shared true)
(tho/add-simple-component :component1 :main-root :rect1))
@ -105,7 +57,7 @@
(t/is (ctk/is-main-of? main-root' copy-root' true))
(t/is (ctk/main-instance-of? (:id main-root') (:id (second pages')) component'))))
(t/deftest test-absorb-colors
(t/deftest absorb-colors
(let [;; Setup
library (-> (thf/sample-file :library :is-shared true)
(ths/add-sample-library-color :color1 {:name "Test color"
@ -142,7 +94,7 @@
(t/is (= (:fill-color-ref-id fill') (thi/id :color1)))
(t/is (= (:fill-color-ref-file fill') (:id file')))))
(t/deftest test-absorb-typographies
(t/deftest absorb-typographies
(let [;; Setup
library (-> (thf/sample-file :library :is-shared true)
(ths/add-sample-typography :typography1 {:name "Test typography"}))

View file

@ -4,7 +4,7 @@
;;
;; Copyright (c) KALEIDOS INC
(ns common-tests.types.types-component-test
(ns common-tests.types.components-test
(:require
[app.common.test-helpers.ids-map :as thi]
[app.common.test-helpers.shapes :as ths]

View file

@ -4,14 +4,14 @@
;;
;; Copyright (c) KALEIDOS INC
(ns common-tests.types-modifiers-test
(ns common-tests.types.modifiers-test
(:require
[app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt]
[app.common.types.modifiers :as ctm]
[clojure.test :as t]))
(t/deftest test-modifiers->transform
(t/deftest modifiers->transform
(let [modifiers
(-> (ctm/empty)
(ctm/move (gpt/point 100 200))

View file

@ -4,7 +4,7 @@
;;
;; Copyright (c) KALEIDOS INC
(ns common-tests.types-shape-interactions-test
(ns common-tests.types.shape-interactions-test
(:require
[app.common.exceptions :as ex]
[app.common.geom.point :as gpt]
@ -50,7 +50,6 @@
(t/is (= :after-delay (:event-type new-interaction)))
(t/is (= 300 (:delay new-interaction)))))))
(t/deftest set-action-type
(let [interaction ctsi/default-interaction]

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

@ -29,7 +29,7 @@
[app.main.ui.workspace.nudge]
[app.main.ui.workspace.palette :refer [palette]]
[app.main.ui.workspace.plugins]
[app.main.ui.workspace.sidebar :refer [left-sidebar right-sidebar]]
[app.main.ui.workspace.sidebar :refer [left-sidebar* right-sidebar*]]
[app.main.ui.workspace.sidebar.collapsable-button :refer [collapsed-button]]
[app.main.ui.workspace.sidebar.history :refer [history-toolbox*]]
[app.main.ui.workspace.tokens.modals]
@ -111,14 +111,14 @@
[:*
(if (:collapse-left-sidebar layout)
[:& collapsed-button]
[:& left-sidebar {:layout layout
[:> left-sidebar* {:layout layout
:file file
:page-id page-id}])
[:> right-sidebar* {:section options-mode
:selected selected
:layout layout
:file file
:page-id page-id}])
[:& right-sidebar {:section options-mode
:selected selected
:layout layout
:file file
:page-id page-id}]])]))
:page-id page-id}]])]))
(mf/defc workspace-loader*
{::mf/private true}

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

@ -11,45 +11,73 @@
[app.main.refs :as refs]
[app.main.ui.components.color-bullet :as cb]
[app.main.ui.components.dropdown :refer [dropdown]]
[app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.util.i18n :refer [tr]]
[rumext.v2 :as mf]))
(mf/defc color-palette-ctx-menu
[{:keys [show-menu? close-menu on-select-palette selected]}]
(let [recent-colors (mf/deref refs/recent-colors)
file-colors (mf/deref refs/workspace-file-colors)
shared-libs (mf/deref refs/libraries)]
[:& dropdown {:show show-menu?
:on-close close-menu}
[:ul {:class (stl/css :palette-menu)}
(for [{:keys [data id] :as library} (vals shared-libs)]
(let [colors (-> data :colors vals)]
[:li {:class (stl/css-case :palette-library true
:selected (= selected id))
:key (dm/str "library-" id)
:on-click on-select-palette
:data-palette (dm/str id)}
[:div {:class (stl/css :option-wrapper)}
[:div {:class (stl/css :library-name)}
[:div {:class (stl/css :lib-name-wrapper)}
[:span {:class (stl/css :lib-name)}
(dm/str (:name library))]
[:span {:class (stl/css :lib-num)}
(dm/str "(" (count colors) ")")]]
(when (= selected id)
[:span {:class (stl/css :icon-wrapper)}
i/tick])]
[:div {:class (stl/css :color-sample)
:style #js {"--bullet-size" "20px"}}
(for [[i {:keys [color id gradient]}] (map-indexed vector (take 7 colors))]
[:& cb/color-bullet {:key (dm/str "color-" i)
:mini true
:color {:color color :id id :gradient gradient}}])]]]))
(def ^:private xf:sample-colors
(comp (map val)
(take 7)))
[:li {:class (stl/css-case :file-library true
:selected (= selected :file))
:on-click on-select-palette
(defn- extract-colors
[{:keys [data] :as file}]
(let [colors (into [] xf:sample-colors (:colors data))]
(-> file
(assoc :colors colors)
(dissoc :data))))
(mf/defc color-palette-ctx-menu*
[{:keys [show on-close on-select selected]}]
(let [recent-colors (mf/deref refs/recent-colors)
libraries (mf/deref refs/libraries)
file-id (mf/use-ctx ctx/current-file-id)
local-colors (mf/with-memo [libraries file-id]
(let [colors (dm/get-in libraries [file-id :data :colors])]
(into [] xf:sample-colors colors)))
libraries (mf/with-memo [libraries file-id]
(->> (dissoc libraries file-id)
(vals)
(mapv extract-colors)))
recent-colors (mf/with-memo [recent-colors]
(->> (reverse recent-colors)
(take 7)
(map-indexed (fn [index color]
(assoc color ::id (dm/str index))))
(vec)))]
[:& dropdown {:show show :on-close on-close}
[:ul {:class (stl/css :palette-menu)}
(for [{:keys [id colors] :as library} libraries]
[:li {:class (stl/css-case :palette-library true
:selected (= selected id))
:key (dm/str "library-" id)
:on-click on-select
:data-palette (dm/str id)}
[:div {:class (stl/css :option-wrapper)}
[:div {:class (stl/css :library-name)}
[:div {:class (stl/css :lib-name-wrapper)}
[:span {:class (stl/css :lib-name)}
(dm/str (:name library))]
[:span {:class (stl/css :lib-num)}
(dm/str "(" (count colors) ")")]]
(when (= selected id)
[:span {:class (stl/css :icon-wrapper)}
i/tick])]
[:div {:class (stl/css :color-sample)
:style {:--bullet-size "20px"}}
(for [color colors]
[:& cb/color-bullet {:key (dm/str (:id color))
:mini true
:color color}])]]])
[:li {:class (stl/css-case
:file-library true
:selected (= selected :file))
:on-click on-select
:data-palette "file"}
[:div {:class (stl/css :option-wrapper)}
@ -59,21 +87,22 @@
[:span {:class (stl/css :lib-name)}
(dm/str (tr "workspace.libraries.colors.file-library"))]
[:span {:class (stl/css :lib-num)}
(dm/str "(" (count file-colors) ")")]]
(dm/str "(" (count local-colors) ")")]]
(when (= selected :file)
[:span {:class (stl/css :icon-wrapper)}
i/tick])]
[:div {:class (stl/css :color-sample)
:style #js {"--bullet-size" "20px"}}
(for [[i color] (map-indexed vector (take 7 (vals file-colors)))]
[:& cb/color-bullet {:key (dm/str "color-" i)
:style {:--bullet-size "20px"}}
(for [color local-colors]
[:& cb/color-bullet {:key (dm/str (:id color))
:mini true
:color color}])]]]
[:li {:class (stl/css :recent-colors true
:selected (= selected :recent))
:on-click on-select-palette
[:li {:class (stl/css
:recent-colors true
:selected (= selected :recent))
:on-click on-select
:data-palette "recent"}
[:div {:class (stl/css :option-wrapper)}
[:div {:class (stl/css :library-name)}
@ -87,8 +116,9 @@
[:span {:class (stl/css :icon-wrapper)}
i/tick])]
[:div {:class (stl/css :color-sample)
:style #js {"--bullet-size" "20px"}}
(for [[idx color] (map-indexed vector (take 7 (reverse recent-colors)))]
[:& cb/color-bullet {:key (str "color-" idx)
:style {:--bullet-size "20px"}}
(for [color recent-colors]
[:& cb/color-bullet {:key (dm/str (::id color))
:mini true
:color color}])]]]]]))

View file

@ -10,6 +10,7 @@
[app.common.colors :as c]
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.types.color :as ctc]
[app.main.data.event :as ev]
[app.main.data.workspace :as dw]
[app.main.data.workspace.colors :as mdc]
@ -17,6 +18,7 @@
[app.main.store :as st]
[app.main.ui.components.color-bullet :as cb]
[app.main.ui.components.select :refer [select]]
[app.main.ui.context :as ctx]
[app.main.ui.hooks :as h]
[app.main.ui.hooks.resize :as r]
[app.main.ui.icons :as i]
@ -27,103 +29,107 @@
(mf/defc libraries
[{:keys [state on-select-color on-add-library-color disable-gradient disable-opacity disable-image]}]
(let [selected (h/use-shared-state mdc/colorpicker-selected-broadcast-key :recent)
current-colors (mf/use-state [])
(let [selected* (h/use-shared-state mdc/colorpicker-selected-broadcast-key :recent)
selected (deref selected*)
shared-libs (mf/deref refs/libraries)
file-colors (mf/deref refs/workspace-file-colors)
file-id (mf/use-ctx ctx/current-file-id)
current-colors* (mf/use-state [])
current-colors (deref current-colors*)
libraries (mf/deref refs/libraries)
recent-colors (mf/deref refs/recent-colors)
recent-colors (h/use-equal-memo (filter #(or (:gradient %) (:color %) (:image %)) recent-colors))
recent-colors (mf/with-memo [recent-colors]
(filterv ctc/valid-color? recent-colors))
library-options
(mf/with-memo []
[{:value "recent" :label (tr "workspace.libraries.colors.recent-colors")}
{:value "file" :label (tr "workspace.libraries.colors.file-library")}])
options
(mf/with-memo [library-options file-id]
(into library-options
(comp
(map val)
(map (fn [lib] {:value (d/name (:id lib)) :label (:name lib)})))
(dissoc libraries file-id)))
on-library-change
(mf/use-fn
(fn [event]
(reset! selected
(reset! selected*
(if (or (= event "recent")
(= event "file"))
(keyword event)
(parse-uuid event)))))
check-valid-color?
valid-color?
(mf/use-fn
(mf/deps disable-gradient disable-opacity disable-image)
(fn [color]
(and (or (not disable-gradient) (not (:gradient color)))
(or (not disable-opacity) (= 1 (:opacity color)))
(or (not disable-image) (not (:image color))))))
;; Sort colors by hue and lightness
get-sorted-colors
(mf/use-fn
(fn [colors]
(sort c/sort-colors (into [] (filter check-valid-color?) colors))))
toggle-palette
(mf/use-fn
(mf/deps @selected)
(mf/deps selected)
(fn []
(r/set-resize-type! :bottom)
(dom/add-class! (dom/get-element-by-class "color-palette") "fade-out-down")
(st/emit! (dw/remove-layout-flag :textpalette)
(-> (mdc/show-palette @selected)
(-> (mdc/show-palette selected)
(vary-meta assoc ::ev/origin "workspace-colorpicker")))))
shared-libs-options (mapv (fn [lib] {:value (d/name (:id lib)) :label (:name lib)}) (vals shared-libs))
library-options [{:value "recent" :label (tr "workspace.libraries.colors.recent-colors")}
{:value "file" :label (tr "workspace.libraries.colors.file-library")}]
options (concat library-options shared-libs-options)
on-color-click
(mf/use-fn
(mf/deps state @selected)
(mf/deps state selected on-select-color)
(fn [event]
(when-not (= :recent @selected)
(when-not (= :recent selected)
(st/emit! (ptk/event
::ev/event
{::ev/name "use-library-color"
::ev/origin "colorpicker"
:external-library (not= :file @selected)})))
:external-library (not= :file selected)})))
(on-select-color state event)))]
;; Load library colors when the select is changed
(mf/with-effect [@selected recent-colors file-colors]
(let [colors (cond
(= @selected :recent)
;; The `map?` check is to keep backwards compatibility. We transform from string to map
(map #(if (map? %) % {:color %}) (reverse (or recent-colors [])))
(mf/with-effect [selected recent-colors libraries file-id valid-color?]
(let [file-id (if (= selected :file)
file-id
selected)
(= @selected :file)
(->> (vals file-colors) (sort-by :name))
colors (if (= selected :recent)
;; NOTE: The `map?` check is to keep backwards
;; compatibility We transform from string to map
(->> (reverse recent-colors)
(filter valid-color?)
(map-indexed (fn [index color]
(let [color (if (map? color) color {:color color})]
(assoc color ::id (dm/str index)))))
(sort c/sort-colors))
(->> (dm/get-in libraries [file-id :data :colors])
(vals)
(filter valid-color?)
(map-indexed (fn [index color]
(-> color
(assoc :file-id file-id)
(assoc ::id (dm/str index)))))
(sort-by :name)))]
:else ;; Library UUID
(as-> @selected file-id
(->> (get-in shared-libs [file-id :data :colors])
(vals)
(sort-by :name)
(map #(assoc % :file-id file-id)))))]
(if (not= @selected :recent)
(reset! current-colors (get-sorted-colors colors))
(reset! current-colors (into [] (filter check-valid-color? colors))))))
;; If the file colors change and the file option is selected updates the state
(mf/with-effect [file-colors]
(when (= @selected :file)
(let [colors (vals file-colors)]
(reset! current-colors (get-sorted-colors colors)))))
(reset! current-colors* colors)))
[:div {:class (stl/css :libraries)}
[:div {:class (stl/css :select-wrapper)}
[:& select
{:class (stl/css :shadow-type-select)
:default-value (or (name @selected) "recent")
:default-value (or (d/name selected) "recent")
:options options
:on-change on-library-change}]]
[:div {:class (stl/css :selected-colors)}
(when (= @selected :file)
(when (= selected :file)
[:button {:class (stl/css :add-color-btn)
:on-click on-add-library-color}
i/add])
@ -132,8 +138,8 @@
:on-click toggle-palette}
i/swatches]
(for [[idx color] (map-indexed vector @current-colors)]
(for [color current-colors]
[:& cb/color-bullet
{:key (dm/str "color-" idx)
{:key (dm/str "color-" (::id color))
:color color
:on-click on-color-click}])]]))

View file

@ -19,8 +19,8 @@
[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-ctx-menu :refer [color-palette-ctx-menu]]
[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]]
[app.util.dom :as dom]
@ -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 show-menu?
:on-close on-close-menu
:on-select 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

@ -48,7 +48,7 @@
:size "s"
:aria-label (tr "workspace.sidebar.collapse")}]])
(mf/defc left-sidebar
(mf/defc left-sidebar*
{::mf/wrap [mf/memo]
::mf/props :obj}
[{:keys [layout file page-id] :as props}]
@ -179,9 +179,8 @@
;; --- Right Sidebar (Component)
(mf/defc right-sidebar
{::mf/wrap-props false
::mf/wrap [mf/memo]}
(mf/defc right-sidebar*
{::mf/wrap [mf/memo]}
[{:keys [layout section file page-id] :as props}]
(let [drawing-tool (:tool (mf/deref refs/workspace-drawing))

View file

@ -64,19 +64,6 @@
(:color color) (:color color)
:else (:value color))
apply-color
(mf/use-fn
(mf/deps color)
(fn [event]
(st/emit!
(dwl/add-recent-color color)
(dc/apply-color-from-palette color (kbd/alt? event))
(ptk/event
::ev/event
{::ev/name "use-library-color"
::ev/origin "sidebar"
:external-library (not local?)}))))
rename-color
(mf/use-fn
(mf/deps file-id color-id)
@ -189,10 +176,17 @@
on-click
(mf/use-fn
(mf/deps color-id apply-color on-asset-click read-only?)
(when-not read-only?
(dwl/add-recent-color color)
(partial on-asset-click color-id apply-color)))]
(mf/deps color on-asset-click read-only?)
(fn [event]
(when-not read-only?
(st/emit! (ptk/data-event ::ev/event
{::ev/name "use-library-color"
::ev/origin "sidebar"
:external-library (not local?)}))
(when-not (on-asset-click event (:id color))
(st/emit! (dwl/add-recent-color color)
(dc/apply-color-from-palette color (kbd/alt? event)))))))]
(mf/with-effect [editing?]
(when editing?

View file

@ -71,17 +71,13 @@
[root-shape container]
(get-component-root-and-container file-id component)
unselect-all
(mf/use-fn
(fn []
(st/emit! (dw/unselect-all-assets))))
on-component-click
(mf/use-fn
(mf/deps component-id on-asset-click)
(fn [event]
(dom/stop-propagation event)
(on-asset-click component-id unselect-all event)))
(when-not (on-asset-click event component-id)
(st/emit! (dw/unselect-all-assets)))))
on-component-double-click
(mf/use-fn

View file

@ -196,21 +196,19 @@
on-asset-click
(mf/use-fn
(mf/deps file-id selected)
(fn [asset-type asset-groups asset-id default-click event]
(fn [asset-type asset-groups event asset-id]
(cond
(kbd/mod? event)
(do
(dom/stop-propagation event)
(st/emit! (dw/toggle-selected-assets file-id asset-id asset-type)))
(st/emit! (dw/toggle-selected-assets file-id asset-id asset-type))
true)
(kbd/shift? event)
(do
(dom/stop-propagation event)
(extend-selected selected asset-type asset-groups asset-id file-id))
:else
(when default-click
(default-click event)))))
(extend-selected selected asset-type asset-groups asset-id file-id)
true))))
on-component-click
(mf/use-fn (mf/deps on-asset-click) (partial on-asset-click :components))

View file

@ -82,7 +82,9 @@
on-asset-click
(mf/use-fn
(mf/deps object-id on-asset-click)
(partial on-asset-click object-id nil))]
(fn [event]
(on-asset-click event object-id)))]
[:div {:ref item-ref
:class-name (stl/css-case
:selected (contains? selected-objects object-id)

View file

@ -39,7 +39,7 @@
(mf/defc typography-item
{::mf/wrap-props false}
[{:keys [typography file-id local? handle-change selected apply-typography editing-id renaming-id on-asset-click
[{:keys [typography file-id local? handle-change selected editing-id renaming-id on-asset-click
on-context-menu selected-full selected-paths move-typography rename?]}]
(let [item-ref (mf/use-ref)
typography-id (:id typography)
@ -91,26 +91,17 @@
(mf/deps typography)
(partial handle-change typography))
apply-typography
(mf/use-fn
(mf/deps typography)
(partial apply-typography typography))
on-asset-click
(mf/use-fn
(mf/deps typography apply-typography on-asset-click)
(partial on-asset-click typography-id apply-typography))
on-click
(mf/use-fn
(mf/deps typography apply-typography on-asset-click)
(fn [ev]
(st/emit! (ptk/event
::ev/event
{::ev/name "use-library-typography"
::ev/origin "sidebar"
:external-library (not local?)}))
(on-asset-click ev)))]
(mf/deps typography on-asset-click read-only? local?)
(fn [event]
(when-not read-only?
(st/emit! (ptk/data-event ::ev/event
{::ev/name "use-library-typography"
::ev/origin "sidebar"
:external-library (not local?)}))
(when-not (on-asset-click event (:id typography))
(st/emit! (dwt/apply-typography typography file-id))))))]
[:div {:class (stl/css :typography-item)
:ref item-ref
@ -126,7 +117,7 @@
:typography typography
:local? local?
:selected? (contains? selected typography-id)
:on-click on-click
:on-click on-asset-click
:on-change handle-change
:on-context-menu on-context-menu
:editing? editing?
@ -139,7 +130,7 @@
(mf/defc typographies-group
{::mf/wrap-props false}
[{:keys [file-id prefix groups open-groups force-open? file local? selected local-data
editing-id renaming-id on-asset-click handle-change apply-typography on-rename-group
editing-id renaming-id on-asset-click handle-change on-rename-group
on-ungroup on-context-menu selected-full]}]
(let [group-open? (if (false? (get open-groups prefix)) ;; if the user has closed it specifically, respect that
false
@ -208,7 +199,6 @@
:local? local?
:handle-change handle-change
:selected selected
:apply-typography apply-typography
:editing-id editing-id
:renaming-id renaming-id
:rename? (= (:rename-typography local-data) id)
@ -234,7 +224,6 @@
:local-data local-data
:on-asset-click on-asset-click
:handle-change handle-change
:apply-typography apply-typography
:on-rename-group on-rename-group
:on-ungroup on-ungroup
:on-context-menu on-context-menu
@ -284,13 +273,6 @@
(fn [typography changes]
(st/emit! (dwl/update-typography (merge typography changes) file-id))))
apply-typography
(mf/use-fn
(mf/deps file-id read-only?)
(fn [typography _event]
(when-not read-only?
(st/emit! (dwt/apply-typography typography file-id)))))
create-group
(mf/use-fn
(mf/deps typographies selected on-clear-selection file-id (:id @state))
@ -438,7 +420,6 @@
:local-data local-data
:on-asset-click on-asset-click
:handle-change handle-change
:apply-typography apply-typography
:on-rename-group on-rename-group
:on-ungroup on-ungroup
:on-context-menu on-context-menu

View file

@ -42,15 +42,20 @@
;; --- Options
(mf/defc shape-options
(mf/defc shape-options*
{::mf/wrap [#(mf/throttle % 60)]}
[{:keys [shape shapes-with-children page-id file-id shared-libs]}]
(let [workspace-modifiers (mf/deref refs/workspace-modifiers)
modifiers (get-in workspace-modifiers [(:id shape) :modifiers])
shape (gsh/transform-shape shape modifiers)]
[{:keys [shape shapes-with-children page-id file-id shared-libs] :as props}]
(let [shape-type (dm/get-prop shape :type)
shape-id (dm/get-prop shape :id)
modifiers (mf/deref refs/workspace-modifiers)
modifiers (dm/get-in modifiers [shape-id :modifiers])
shape (gsh/transform-shape shape modifiers)]
[:*
(case (:type shape)
:frame [:& frame/options {:shape shape :shape-with-children shapes-with-children :file-id file-id :shared-libs shared-libs}]
(case shape-type
:frame [:> frame/options* props]
:group [:& group/options {:shape shape :shape-with-children shapes-with-children :file-id file-id :shared-libs shared-libs}]
:text [:& text/options {:shape shape :file-id file-id :shared-libs shared-libs}]
:rect [:& rect/options {:shape shape}]
@ -73,7 +78,7 @@
(when (= (:type panel) :component-swap)
[:& component-menu {:shapes (:shapes panel) :swap-opened? true}]))
(mf/defc design-menu
(mf/defc design-menu*
{::mf/wrap [mf/memo]}
[{:keys [selected objects page-id file-id selected-shapes shapes-with-children]}]
(let [sp-panel (mf/deref refs/specialized-panel)
@ -104,7 +109,7 @@
[:& specialized-panel {:panel sp-panel}]
(d/not-empty? drawing)
[:& shape-options
[:> shape-options*
{:shape (:object drawing)
:page-id page-id
:file-id file-id
@ -114,7 +119,7 @@
[:& page/options]
(= 1 (count selected))
[:& shape-options
[:> shape-options*
{:shape (first selected-shapes)
:page-id page-id
:file-id file-id
@ -151,12 +156,13 @@
(st/emit! :interrupt (dwc/set-workspace-read-only false)))))
design-content
(mf/html [:& design-menu {:selected selected
:objects objects
:page-id page-id
:file-id file-id
:selected-shapes selected-shapes
:shapes-with-children shapes-with-children}])
(mf/html [:> design-menu*
{:selected selected
:objects objects
:page-id page-id
:file-id file-id
:selected-shapes selected-shapes
:shapes-with-children shapes-with-children}])
inspect-content
(mf/html [:div {:class (stl/css :element-options :inspect-options)}

View file

@ -168,7 +168,7 @@
(seq fills)
[:& h/sortable-container {}
(for [[index value] (d/enumerate (:fills values []))]
[:& color-row {:color (ctc/fill->color value)
[:& color-row {:color (ctc/fill->shape-color value)
:key index
:index index
:title (tr "workspace.options.fill")

View file

@ -33,7 +33,7 @@
[app.main.ui.workspace.tokens.token-types :as wtty]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
[clojure.set :refer [rename-keys union]]
[clojure.set :as set]
[rumext.v2 :as mf]))
(def measure-attrs
@ -48,16 +48,27 @@
:show-content
:hide-in-viewer])
(def ^:private type->options
{:bool #{:size :position :rotation}
:circle #{:size :position :rotation}
:frame #{:presets :size :position :rotation :radius :clip-content :show-in-viewer}
:group #{:size :position :rotation}
:image #{:size :position :rotation :radius}
:path #{:size :position :rotation}
:rect #{:size :position :rotation :radius}
:svg-raw #{:size :position :rotation}
:text #{:size :position :rotation}})
(def ^:private generic-options
#{:size :position :rotation})
(def ^:private rect-options
#{:size :position :rotation :radius})
(def ^:private frame-options
#{:presets :size :position :rotation :radius :clip-content :show-in-viewer})
(defn- type->options
[type]
(case type
:bool generic-options
:circle generic-options
:frame frame-options
:group generic-options
:image rect-options
:path generic-options
:rect rect-options
:svg-raw generic-options
:text generic-options))
(def ^:private clip-content-icon (i/icon-xref :clip-content (stl/css :checkbox-button)))
(def ^:private play-icon (i/icon-xref :play (stl/css :checkbox-button)))
@ -67,37 +78,45 @@
(defn select-measure-keys
"Consider some shapes can be drawn from bottom to top or from left to right"
[shape]
(let [shape (cond
(and (:flip-x shape) (:flip-y shape))
(rename-keys shape {:r1 :r3 :r2 :r4 :r3 :r1 :r4 :r2})
(let [flip-x (get shape :flip-x)
flip-y (get shape :flip-y)
(:flip-x shape)
(rename-keys shape {:r1 :r2 :r2 :r1 :r3 :r4 :r4 :r3})
shape (cond
(and flip-x flip-y)
(set/rename-keys shape {:r1 :r3 :r2 :r4 :r3 :r1 :r4 :r2})
(:flip-y shape)
(rename-keys shape {:r1 :r4 :r2 :r3 :r3 :r2 :r4 :r1})
flip-x
(set/rename-keys shape {:r1 :r2 :r2 :r1 :r3 :r4 :r4 :r3})
:else
shape)]
flip-y
(set/rename-keys shape {:r1 :r4 :r2 :r3 :r3 :r2 :r4 :r1})
:else
shape)]
(select-keys shape measure-attrs)))
;; -- User/drawing coords
(mf/defc measures-menu
{::mf/wrap-props false
(mf/defc measures-menu*
{::mf/props :obj
::mf/wrap [mf/memo]}
[{:keys [ids ids-with-children values type all-types shape]}]
(let [options (if (= type :multiple)
(reduce #(union %1 %2) (map #(get type->options %) all-types))
(get type->options type))
(let [design-tokens? (mf/use-ctx muc/design-tokens)
design-tokens? (mf/use-ctx muc/design-tokens)
options
(mf/with-memo [type all-types]
(if (= type :multiple)
(into #{} (mapcat type->options) all-types)
(type->options type)))
ids-with-children (or ids-with-children ids)
ids-with-children
(or ids-with-children ids)
old-shapes (if (= type :multiple)
(deref (refs/objects-by-id ids))
[shape])
frames (map #(deref (refs/object-by-id (:frame-id %))) old-shapes)
old-shapes
(if (= type :multiple)
(deref (refs/objects-by-id ids))
[shape])
frames
(map #(deref (refs/object-by-id (:frame-id %))) old-shapes)
ids (hooks/use-equal-memo ids)

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,27 +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)
file-colors (mf/deref refs/workspace-file-colors)
shared-libs (mf/deref refs/libraries)
hover-detach (mf/use-state false)
on-change (h/use-ref-callback on-change)
src-colors (if (= (:file-id color) current-file-id)
file-colors
(dm/get-in shared-libs [(:file-id color) :data :colors]))
(let [shared-libs (mf/deref refs/libraries)
hover-detach (mf/use-state false)
on-change (h/use-ref-callback on-change)
color-name (dm/get-in src-colors [(: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 (:id color) color-name (not multiple-colors?))
gradient-color? (and (not multiple-colors?)
(:gradient color)
(get-in color [:gradient :type]))
image-color? (and (not multiple-colors?)
(:image 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))
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?)
@ -124,10 +119,9 @@
(mf/use-fn
(mf/deps color on-change)
(fn [value]
(let [color (assoc color
:opacity (/ value 100)
:id nil
:file-id nil)]
(let [color (-> color
(assoc :opacity (/ value 100))
(dissoc :ref-id :ref-file))]
(st/emit! (dwl/add-recent-color color)
(on-change color)))))
@ -209,13 +203,11 @@
:gradient-name-wrapper gradient-color?)}
[:div {:class (stl/css :color-bullet-wrapper)}
[:& cb/color-bullet {:color (cond-> color
(nil? color-name) (assoc
:id nil
:file-id nil))
(nil? color-name) (dissoc :ref-id :ref-file))
:mini true
:on-click handle-click-color}]]
(cond
;; Rendering a color with ID
;; Rendering a color with ID
library-color?
[:*
[:div {:class (stl/css :color-name)
@ -235,7 +227,7 @@
gradient-color?
[:*
[:div {:class (stl/css :color-name)}
(uc/gradient-type->string (get-in color [:gradient :type]))]]
(uc/gradient-type->string (dm/get-in color [:gradient :type]))]]
;; Rendering an image
image-color?
@ -250,7 +242,7 @@
""
(-> color :color cc/remove-hash))
:placeholder (tr "settings.multiple")
:className (stl/css :color-input)
:class (stl/css :color-input)
:on-focus on-focus
:on-blur on-blur
:on-change handle-value-change}]])]

View file

@ -8,6 +8,7 @@
(:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.types.color :as ctc]
[app.main.ui.components.numeric-input :refer [numeric-input*]]
[app.main.ui.components.reorder-handler :refer [reorder-handler]]
[app.main.ui.components.select :refer [select]]
@ -147,12 +148,7 @@
[:& reorder-handler {:ref dref}])
;; Stroke Color
[:& color-row {:color {:color (:stroke-color stroke)
:opacity (:stroke-opacity stroke)
:id (:stroke-color-ref-id stroke)
:file-id (:stroke-color-ref-file stroke)
:gradient (:stroke-color-gradient stroke)
:image (:stroke-image stroke)}
[:& color-row {:color (ctc/stroke->shape-color stroke)
:index index
:title title
:on-change on-color-change-refactor

View file

@ -16,7 +16,7 @@
[app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-container :refer [layout-container-flex-attrs layout-container-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[rumext.v2 :as mf]))
@ -51,10 +51,10 @@
:type type
:values layer-values}]
[:& measures-menu {:ids ids
:type type
:values measure-values
:shape shape}]
[:> measures-menu* {:ids ids
:type type
:values measure-values
:shape shape}]
[:& layout-container-menu
{:type type

View file

@ -16,7 +16,7 @@
[app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-container :refer [layout-container-flex-attrs layout-container-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]]
@ -53,10 +53,10 @@
:type type
:values layer-values}]
[:& measures-menu {:ids ids
:type type
:values measure-values
:shape shape}]
[:> measures-menu* {:ids ids
:type type
:values measure-values
:shape shape}]
[:& layout-container-menu
{:type type

View file

@ -6,10 +6,9 @@
(ns app.main.ui.workspace.sidebar.options.shapes.frame
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.types.shape.layout :as ctl]
[app.main.refs :as refs]
[app.main.ui.hooks :as hooks]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.color-selection :refer [color-selection-menu]]
[app.main.ui.workspace.sidebar.options.menus.component :refer [component-menu]]
@ -20,55 +19,68 @@
[app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-container :refer [layout-container-flex-attrs layout-container-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [select-measure-keys measures-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [select-measure-keys measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[rumext.v2 :as mf]))
(mf/defc options
[{:keys [shape file-id shape-with-children shared-libs] :as props}]
(let [ids [(:id shape)]
type (:type shape)
objects (->> shape-with-children (group-by :id) (d/mapm (fn [_ v] (first v))))
stroke-values (select-keys shape stroke-attrs)
layer-values (select-keys shape layer-attrs)
measure-values (select-measure-keys shape)
constraint-values (select-keys shape constraint-attrs)
(mf/defc options*
[{:keys [shape file-id shapes-with-children shared-libs] :as props}]
(let [shape-id (dm/get-prop shape :id)
shape-type (dm/get-prop shape :type)
ids (mf/with-memo [shape-id]
[shape-id])
stroke-values (select-keys shape stroke-attrs)
layer-values (select-keys shape layer-attrs)
measure-values (select-measure-keys shape)
constraint-values (select-keys shape constraint-attrs)
layout-container-values (select-keys shape layout-container-flex-attrs)
layout-item-values (select-keys shape layout-item-attrs)
layout-item-values (select-keys shape layout-item-attrs)
ids (hooks/use-equal-memo ids)
is-layout-child-ref
(mf/with-memo [ids]
(refs/is-layout-child? ids))
is-layout-child?
(mf/deref is-layout-child-ref)
is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids))
is-layout-child? (mf/deref is-layout-child-ref)
is-flex-parent-ref
(mf/with-memo [ids]
(refs/flex-layout-child? ids))
is-flex-parent?
(mf/deref is-flex-parent-ref)
is-flex-parent-ref (mf/use-memo (mf/deps ids) #(refs/flex-layout-child? ids))
is-flex-parent? (mf/deref is-flex-parent-ref)
is-grid-parent-ref
(mf/with-memo [ids]
(refs/grid-layout-child? ids))
is-grid-parent?
(mf/deref is-grid-parent-ref)
is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids))
is-grid-parent? (mf/deref is-grid-parent-ref)
parents-by-ids-ref
(mf/with-memo [ids]
(refs/parents-by-ids ids))
parents
(mf/deref parents-by-ids-ref)
is-layout-container? (ctl/any-layout? shape)
is-flex-layout? (ctl/flex-layout? shape)
is-grid-layout? (ctl/grid-layout? shape)
is-layout-child-absolute? (ctl/item-absolute? shape)
is-layout-container? (ctl/any-layout? shape)
is-flex-layout? (ctl/flex-layout? shape)
is-grid-layout? (ctl/grid-layout? shape)
is-layout-child-absolute? (ctl/item-absolute? shape)]
ids (hooks/use-equal-memo ids)
parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))
parents (mf/deref parents-by-ids-ref)]
[:*
[:& layer-menu {:ids ids
:type type
:type shape-type
:values layer-values}]
[:& measures-menu {:ids [(:id shape)]
:values measure-values
:type type
:shape shape}]
[:> measures-menu* {:ids ids
:values measure-values
:type shape-type
:shape shape}]
[:& component-menu {:shapes [shape]}]
[:& layout-container-menu
{:type type
{:type shape-type
:ids [(:id shape)]
:values layout-container-values
:multiple false}]
@ -81,7 +93,7 @@
(when (or is-layout-child? is-layout-container?)
[:& layout-item-menu
{:ids ids
:type type
:type shape-type
:values layout-item-values
:is-flex-parent? is-flex-parent?
:is-grid-parent? is-grid-parent?
@ -96,13 +108,13 @@
:values constraint-values}])
[:& fill-menu {:ids ids
:type type
:type shape-type
:values (select-keys shape fill-attrs-shape)}]
[:& stroke-menu {:ids ids
:type type
:type shape-type
:values stroke-values}]
[:& color-selection-menu {:type type
:shapes (vals objects)
[:& color-selection-menu {:type shape-type
:shapes shapes-with-children
:file-id file-id
:shared-libs shared-libs}]
[:& shadow-menu {:ids ids

View file

@ -20,7 +20,7 @@
[app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-container :refer [layout-container-flex-attrs layout-container-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measures-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-menu]]
[app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]]
@ -69,7 +69,7 @@
[:div {:class (stl/css :options)}
[:& layer-menu {:type type :ids layer-ids :values layer-values}]
[:& measures-menu {:type type :ids measure-ids :values measure-values :shape shape}]
[:> measures-menu* {:type type :ids measure-ids :values measure-values :shape shape}]
[:& component-menu {:shapes [shape]}] ;;remove this in components-v2
[:& layout-container-menu

View file

@ -16,7 +16,7 @@
[app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-container :refer [layout-container-flex-attrs layout-container-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[rumext.v2 :as mf]))
@ -53,10 +53,10 @@
:type type
:values layer-values}]
[:& measures-menu {:ids ids
:type type
:values measure-values
:shape shape}]
[:> measures-menu* {:ids ids
:type type
:values measure-values
:shape shape}]
[:& layout-container-menu
{:type type

View file

@ -25,7 +25,7 @@
[app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-container :refer [layout-container-flex-attrs layout-container-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [select-measure-keys measure-attrs measures-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [select-measure-keys measure-attrs measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-attrs shadow-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[app.main.ui.workspace.sidebar.options.menus.text :as ot]
@ -359,7 +359,7 @@
[:& layer-menu {:type type :ids layer-ids :values layer-values}])
(when-not (empty? measure-ids)
[:& measures-menu {:type type :all-types all-types :ids measure-ids :values measure-values :shape shapes}])
[:> measures-menu* {:type type :all-types all-types :ids measure-ids :values measure-values :shape shapes}])
(when-not (empty? components)
[:& component-menu {:shapes components}])

View file

@ -16,7 +16,7 @@
[app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-container :refer [layout-container-flex-attrs layout-container-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]]
@ -52,10 +52,10 @@
[:& layer-menu {:ids ids
:type type
:values layer-values}]
[:& measures-menu {:ids ids
:type type
:values measure-values
:shape shape}]
[:> measures-menu* {:ids ids
:type type
:values measure-values
:shape shape}]
[:& layout-container-menu
{:type type

View file

@ -16,7 +16,7 @@
[app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-container :refer [layout-container-flex-attrs layout-container-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [select-measure-keys measures-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [select-measure-keys measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]]
@ -55,10 +55,10 @@
[:& layer-menu {:ids ids
:type type
:values layer-values}]
[:& measures-menu {:ids ids
:type type
:values measure-values
:shape shape}]
[:> measures-menu* {:ids ids
:type type
:values measure-values
:shape shape}]
[:& layout-container-menu
{:type type

View file

@ -17,7 +17,7 @@
[app.main.ui.workspace.sidebar.options.menus.grid-cell :as grid-cell]
[app.main.ui.workspace.sidebar.options.menus.layout-container :refer [layout-container-flex-attrs layout-container-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]]
@ -124,10 +124,10 @@
(when (contains? svg-elements tag)
[:*
[:& measures-menu {:ids ids
:type type
:values measure-values
:shape shape}]
[:> measures-menu* {:ids ids
:type type
:values measure-values
:shape shape}]
[:& layout-container-menu
{:type type

View file

@ -22,7 +22,7 @@
[app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-container :refer [layout-container-flex-attrs layout-container-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[app.main.ui.workspace.sidebar.options.menus.text :refer [text-menu]]
@ -98,7 +98,7 @@
[:& layer-menu {:ids ids
:type type
:values layer-values}]
[:& measures-menu
[:> measures-menu*
{:ids ids
:type type
:values (select-keys shape measure-attrs)