mirror of
https://github.com/penpot/penpot.git
synced 2025-07-29 17:07:29 +02:00
🐛 Fix edit attrs of groups
This commit is contained in:
parent
cf108e110f
commit
8de55ce054
5 changed files with 127 additions and 60 deletions
|
@ -856,34 +856,63 @@
|
||||||
:else srect))))
|
:else srect))))
|
||||||
|
|
||||||
(defn get-attrs-multi
|
(defn get-attrs-multi
|
||||||
[values attrs]
|
[shapes attrs]
|
||||||
;; Extract some attributes of a list of shape values.
|
;; Extract some attributes of a list of shapes.
|
||||||
;; For each attribute, if the value is the same in all shapes,
|
;; For each attribute, if the value is the same in all shapes,
|
||||||
;; wll take this value. If there is any shape that is different,
|
;; wll take this value. If there is any shape that is different,
|
||||||
;; the value of the attribute will be the keyword :multiple.
|
;; the value of the attribute will be the keyword :multiple.
|
||||||
;;
|
;;
|
||||||
|
;; If some shape has the value nil in any attribute, it's
|
||||||
|
;; considered a different value. If the shape does not contain
|
||||||
|
;; the attribute, it's ignored in the final result.
|
||||||
|
;;
|
||||||
;; Example:
|
;; Example:
|
||||||
;; (def values [{:stroke-color "#ff0000'
|
;; (def shapes [{:stroke-color "#ff0000"
|
||||||
;; :stroke-width 3
|
;; :stroke-width 3
|
||||||
;; :x 1000 :y 2000}
|
;; :fill-color "#0000ff"
|
||||||
;; {:stroke-width "#ff0000'
|
;; :x 1000 :y 2000 :rx nil}
|
||||||
|
;; {:stroke-width "#ff0000"
|
||||||
;; :stroke-width 5
|
;; :stroke-width 5
|
||||||
;; :x 1500 :y 2000}])
|
;; :x 1500 :y 2000}])
|
||||||
;;
|
;;
|
||||||
;; (get-attrs-multi values [:stroke-color :stroke-width :fill-color])
|
;; (get-attrs-multi shapes [:stroke-color
|
||||||
;; >>> {:stroke-color "#ff0000'
|
;; :stroke-width
|
||||||
|
;; :fill-color
|
||||||
|
;; :rx
|
||||||
|
;; :ry])
|
||||||
|
;; >>> {:stroke-color "#ff0000"
|
||||||
;; :stroke-width :multiple
|
;; :stroke-width :multiple
|
||||||
;; :fill-color nil}
|
;; :fill-color "#0000ff"
|
||||||
|
;; :rx nil
|
||||||
|
;; :ry nil}
|
||||||
;;
|
;;
|
||||||
(let [defined-values (filter some? values)
|
(let [defined-shapes (filter some? shapes)
|
||||||
|
|
||||||
combine-value #(if (= %1 %2) %1 :multiple)
|
combine-value (fn [v1 v2] (cond
|
||||||
|
(= v1 v2) v1
|
||||||
|
(= v1 :undefined) v2
|
||||||
|
(= v2 :undefined) v1
|
||||||
|
:else :multiple))
|
||||||
|
|
||||||
combine-values (fn [attrs shape values]
|
combine-values (fn [attrs shape values]
|
||||||
(map #(combine-value (get shape %) (get values %)) attrs))
|
(map #(combine-value (get shape % :undefined)
|
||||||
|
(get values % :undefined)) attrs))
|
||||||
|
|
||||||
|
select-attrs (fn [shape attrs]
|
||||||
|
(zipmap attrs (map #(get shape % :undefined) attrs)))
|
||||||
|
|
||||||
reducer (fn [result shape]
|
reducer (fn [result shape]
|
||||||
(zipmap attrs (combine-values attrs shape result)))]
|
(zipmap attrs (combine-values attrs shape result)))
|
||||||
|
|
||||||
(reduce reducer (select-keys (first defined-values) attrs) (rest defined-values))))
|
combined (reduce reducer
|
||||||
|
(select-attrs (first defined-shapes) attrs)
|
||||||
|
(rest defined-shapes))
|
||||||
|
|
||||||
|
cleanup-value (fn [value]
|
||||||
|
(if (= value :undefined) nil value))
|
||||||
|
|
||||||
|
cleanup (fn [result]
|
||||||
|
(zipmap attrs (map #(cleanup-value (get result %)) attrs)))]
|
||||||
|
|
||||||
|
(cleanup combined)))
|
||||||
|
|
||||||
|
|
|
@ -233,36 +233,61 @@
|
||||||
[{:type :rect
|
[{:type :rect
|
||||||
:name "Rect"
|
:name "Rect"
|
||||||
:fill-color default-color
|
:fill-color default-color
|
||||||
:stroke-alignment :center
|
:fill-opacity 1
|
||||||
:rx 0
|
|
||||||
:ry 0}
|
|
||||||
{:type :image}
|
|
||||||
{:type :icon}
|
|
||||||
{:type :circle
|
|
||||||
:name "Circle"
|
|
||||||
:fill-color default-color}
|
|
||||||
{:type :path
|
|
||||||
:name "Path"
|
|
||||||
:stroke-style :solid
|
|
||||||
:stroke-color "#000000"
|
|
||||||
:stroke-width 2
|
|
||||||
:stroke-alignment :center
|
|
||||||
:fill-color "#000000"
|
|
||||||
:fill-opacity 0
|
|
||||||
:segments []}
|
|
||||||
{:type :frame
|
|
||||||
:stroke-style :none
|
:stroke-style :none
|
||||||
:stroke-alignment :center
|
:stroke-alignment :center
|
||||||
:name "Artboard"}
|
:stroke-width 0
|
||||||
{:type :curve
|
|
||||||
:name "Path"
|
|
||||||
:stroke-style :solid
|
|
||||||
:stroke-color "#000000"
|
:stroke-color "#000000"
|
||||||
:stroke-width 2
|
:stroke-opacity 0
|
||||||
|
:rx 0
|
||||||
|
:ry 0}
|
||||||
|
|
||||||
|
{:type :image}
|
||||||
|
|
||||||
|
{:type :icon}
|
||||||
|
|
||||||
|
{:type :circle
|
||||||
|
:name "Circle"
|
||||||
|
:fill-color default-color
|
||||||
|
:fill-opacity 1
|
||||||
|
:stroke-style :none
|
||||||
:stroke-alignment :center
|
:stroke-alignment :center
|
||||||
|
:stroke-width 0
|
||||||
|
:stroke-color "#000000"
|
||||||
|
:stroke-opacity 0}
|
||||||
|
|
||||||
|
{:type :path
|
||||||
|
:name "Path"
|
||||||
:fill-color "#000000"
|
:fill-color "#000000"
|
||||||
:fill-opacity 0
|
:fill-opacity 0
|
||||||
|
:stroke-style :solid
|
||||||
|
:stroke-alignment :center
|
||||||
|
:stroke-width 2
|
||||||
|
:stroke-color "#000000"
|
||||||
|
:stroke-opacity 1
|
||||||
:segments []}
|
:segments []}
|
||||||
|
|
||||||
|
{:type :frame
|
||||||
|
:name "Artboard"
|
||||||
|
:fill-color "#ffffff"
|
||||||
|
:fill-opacity 1
|
||||||
|
:stroke-style :none
|
||||||
|
:stroke-alignment :center
|
||||||
|
:stroke-width 0
|
||||||
|
:stroke-color "#000000"
|
||||||
|
:stroke-opacity 0}
|
||||||
|
|
||||||
|
{:type :curve
|
||||||
|
:name "Path"
|
||||||
|
:fill-color "#000000"
|
||||||
|
:fill-opacity 0
|
||||||
|
:stroke-style :solid
|
||||||
|
:stroke-alignment :center
|
||||||
|
:stroke-width 2
|
||||||
|
:stroke-color "#000000"
|
||||||
|
:stroke-opacity 1
|
||||||
|
:segments []}
|
||||||
|
|
||||||
{:type :text
|
{:type :text
|
||||||
:name "Text"
|
:name "Text"
|
||||||
:content nil}])
|
:content nil}])
|
||||||
|
|
|
@ -136,6 +136,16 @@
|
||||||
(into selected children)))]
|
(into selected children)))]
|
||||||
(l/derived selector st/state)))
|
(l/derived selector st/state)))
|
||||||
|
|
||||||
|
(def selected-objects-with-children
|
||||||
|
(letfn [(selector [state]
|
||||||
|
(let [selected (get-in state [:workspace-local :selected])
|
||||||
|
page-id (get-in state [:workspace-page :id])
|
||||||
|
objects (get-in state [:workspace-data page-id :objects])
|
||||||
|
children (mapcat #(cph/get-children % objects) selected)
|
||||||
|
accumulated (into selected children)]
|
||||||
|
(mapv #(get objects %) accumulated)))]
|
||||||
|
(l/derived selector st/state)))
|
||||||
|
|
||||||
(defn make-selected
|
(defn make-selected
|
||||||
[id]
|
[id]
|
||||||
(l/derived #(contains? % id) selected-shapes))
|
(l/derived #(contains? % id) selected-shapes))
|
||||||
|
|
|
@ -37,11 +37,11 @@
|
||||||
|
|
||||||
(mf/defc shape-options
|
(mf/defc shape-options
|
||||||
{::mf/wrap [#(mf/throttle % 60)]}
|
{::mf/wrap [#(mf/throttle % 60)]}
|
||||||
[{:keys [shape page] :as props}]
|
[{:keys [shape shapes-with-children page] :as props}]
|
||||||
[:*
|
[:*
|
||||||
(case (:type shape)
|
(case (:type shape)
|
||||||
:frame [:& frame/options {:shape shape}]
|
:frame [:& frame/options {:shape shape}]
|
||||||
:group [:& group/options {:shape shape}]
|
:group [:& group/options {:shape shape :shape-with-children shapes-with-children}]
|
||||||
:text [:& text/options {:shape shape}]
|
:text [:& text/options {:shape shape}]
|
||||||
:rect [:& rect/options {:shape shape}]
|
:rect [:& rect/options {:shape shape}]
|
||||||
:icon [:& icon/options {:shape shape}]
|
:icon [:& icon/options {:shape shape}]
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
|
|
||||||
(mf/defc options-content
|
(mf/defc options-content
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [section shapes page] :as props}]
|
[{:keys [section shapes shapes-with-children page] :as props}]
|
||||||
(let [locale (mf/deref i18n/locale)]
|
(let [locale (mf/deref i18n/locale)]
|
||||||
[:div.tool-window
|
[:div.tool-window
|
||||||
[:div.tool-window-content
|
[:div.tool-window-content
|
||||||
|
@ -67,8 +67,8 @@
|
||||||
[:& align-options]
|
[:& align-options]
|
||||||
(case (count shapes)
|
(case (count shapes)
|
||||||
0 [:& page/options {:page page}]
|
0 [:& page/options {:page page}]
|
||||||
1 [:& shape-options {:shape (first shapes)}]
|
1 [:& shape-options {:shape (first shapes) :shapes-with-children shapes-with-children}]
|
||||||
[:& multiple/options {:shapes shapes}])]]
|
[:& multiple/options {:shapes shapes-with-children}])]]
|
||||||
|
|
||||||
[:& tab-element {:id :prototype
|
[:& tab-element {:id :prototype
|
||||||
:title (t locale "workspace.options.prototype")}
|
:title (t locale "workspace.options.prototype")}
|
||||||
|
@ -79,9 +79,11 @@
|
||||||
(mf/defc options-toolbox
|
(mf/defc options-toolbox
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [page local] :as props}]
|
[{:keys [page local] :as props}]
|
||||||
(let [section (:options-mode local)
|
(let [section (:options-mode local)
|
||||||
shapes (mf/deref refs/selected-objects)]
|
shapes (mf/deref refs/selected-objects)
|
||||||
|
shapes-with-children (mf/deref refs/selected-objects-with-children)]
|
||||||
[:& options-content {:shapes shapes
|
[:& options-content {:shapes shapes
|
||||||
|
:shapes-with-children shapes-with-children
|
||||||
:page page
|
:page page
|
||||||
:section section}]))
|
:section section}]))
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
(:require
|
(:require
|
||||||
[rumext.alpha :as mf]
|
[rumext.alpha :as mf]
|
||||||
[uxbox.common.geom.shapes :as geom]
|
[uxbox.common.geom.shapes :as geom]
|
||||||
|
[uxbox.common.pages-helpers :as cph]
|
||||||
[uxbox.main.refs :as refs]
|
[uxbox.main.refs :as refs]
|
||||||
[uxbox.main.data.workspace.texts :as dwt]
|
[uxbox.main.data.workspace.texts :as dwt]
|
||||||
[uxbox.main.ui.workspace.sidebar.options.multiple :refer [get-shape-attrs]]
|
[uxbox.main.ui.workspace.sidebar.options.multiple :refer [get-shape-attrs]]
|
||||||
|
@ -28,19 +29,19 @@
|
||||||
text-menu]]))
|
text-menu]]))
|
||||||
|
|
||||||
(mf/defc options
|
(mf/defc options
|
||||||
[{:keys [shape] :as props}]
|
[{:keys [shape shape-with-children] :as props}]
|
||||||
(let [child-ids (:shapes shape)
|
(let [id (:id shape)
|
||||||
children (mf/deref (refs/objects-by-id child-ids))
|
ids-with-children (map :id shape-with-children)
|
||||||
text-ids (map :id (filter #(= (:type %) :text) children))
|
text-ids (map :id (filter #(= (:type %) :text) shape-with-children))
|
||||||
other-ids (map :id (filter #(not= (:type %) :text) children))
|
other-ids (map :id (filter #(not= (:type %) :text) shape-with-children))
|
||||||
|
|
||||||
type (:type shape)
|
type (:type shape) ; always be :group
|
||||||
|
|
||||||
measure-values
|
measure-values
|
||||||
(select-keys shape measure-attrs)
|
(select-keys shape measure-attrs)
|
||||||
|
|
||||||
fill-values
|
fill-values
|
||||||
(geom/get-attrs-multi children fill-attrs)
|
(geom/get-attrs-multi shape-with-children fill-attrs)
|
||||||
|
|
||||||
stroke-values
|
stroke-values
|
||||||
(geom/get-attrs-multi (map #(get-shape-attrs
|
(geom/get-attrs-multi (map #(get-shape-attrs
|
||||||
|
@ -49,7 +50,7 @@
|
||||||
nil
|
nil
|
||||||
nil
|
nil
|
||||||
nil)
|
nil)
|
||||||
children)
|
shape-with-children)
|
||||||
stroke-attrs)
|
stroke-attrs)
|
||||||
|
|
||||||
font-values
|
font-values
|
||||||
|
@ -59,7 +60,7 @@
|
||||||
text-font-attrs
|
text-font-attrs
|
||||||
nil
|
nil
|
||||||
dwt/current-text-values)
|
dwt/current-text-values)
|
||||||
children)
|
shape-with-children)
|
||||||
text-font-attrs)
|
text-font-attrs)
|
||||||
|
|
||||||
align-values
|
align-values
|
||||||
|
@ -69,7 +70,7 @@
|
||||||
text-align-attrs
|
text-align-attrs
|
||||||
nil
|
nil
|
||||||
dwt/current-paragraph-values)
|
dwt/current-paragraph-values)
|
||||||
children)
|
shape-with-children)
|
||||||
text-align-attrs)
|
text-align-attrs)
|
||||||
|
|
||||||
spacing-values
|
spacing-values
|
||||||
|
@ -79,7 +80,7 @@
|
||||||
text-spacing-attrs
|
text-spacing-attrs
|
||||||
nil
|
nil
|
||||||
dwt/current-text-values)
|
dwt/current-text-values)
|
||||||
children)
|
shape-with-children)
|
||||||
text-spacing-attrs)
|
text-spacing-attrs)
|
||||||
|
|
||||||
valign-values
|
valign-values
|
||||||
|
@ -89,7 +90,7 @@
|
||||||
text-valign-attrs
|
text-valign-attrs
|
||||||
nil
|
nil
|
||||||
dwt/current-root-values)
|
dwt/current-root-values)
|
||||||
children)
|
shape-with-children)
|
||||||
text-valign-attrs)
|
text-valign-attrs)
|
||||||
|
|
||||||
decoration-values
|
decoration-values
|
||||||
|
@ -99,7 +100,7 @@
|
||||||
text-decoration-attrs
|
text-decoration-attrs
|
||||||
nil
|
nil
|
||||||
dwt/current-text-values)
|
dwt/current-text-values)
|
||||||
children)
|
shape-with-children)
|
||||||
text-decoration-attrs)
|
text-decoration-attrs)
|
||||||
|
|
||||||
transform-values
|
transform-values
|
||||||
|
@ -109,17 +110,17 @@
|
||||||
text-transform-attrs
|
text-transform-attrs
|
||||||
nil
|
nil
|
||||||
dwt/current-text-values)
|
dwt/current-text-values)
|
||||||
children)
|
shape-with-children)
|
||||||
text-transform-attrs)]
|
text-transform-attrs)]
|
||||||
[:*
|
[:*
|
||||||
[:& measures-menu {:ids [(:id shape)]
|
[:& measures-menu {:ids [id]
|
||||||
:type type
|
:type type
|
||||||
:values measure-values}]
|
:values measure-values}]
|
||||||
[:& fill-menu {:ids child-ids
|
[:& fill-menu {:ids ids-with-children
|
||||||
:type type
|
:type type
|
||||||
:values fill-values}]
|
:values fill-values}]
|
||||||
(when-not (empty? other-ids)
|
(when-not (empty? other-ids)
|
||||||
[:& stroke-menu {:ids child-ids
|
[:& stroke-menu {:ids other-ids
|
||||||
:type type
|
:type type
|
||||||
:values stroke-values}])
|
:values stroke-values}])
|
||||||
(when-not (empty? text-ids)
|
(when-not (empty? text-ids)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue