0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-11 23:31:21 -05:00

🎉 Allow to edit text properties of multiple shapes

This commit is contained in:
Andrés Moya 2020-07-08 10:21:18 +02:00
parent 0951ba95f0
commit 6020cc797d
6 changed files with 471 additions and 252 deletions

View file

@ -856,26 +856,28 @@
:else srect)))) :else srect))))
(defn get-attrs-multi (defn get-attrs-multi
[shapes attrs] [values attrs]
;; Extract some attributes of a list of shapes. ;; Extract some attributes of a list of shape values.
;; 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.
;; ;;
;; Example: ;; Example:
;; (def shapes [{:stroke-color "#ff0000' ;; (def values [{:stroke-color "#ff0000'
;; :stroke-width 3 ;; :stroke-width 3
;; :x 1000 :y 2000} ;; :x 1000 :y 2000}
;; {:stroke-width "#ff0000' ;; {:stroke-width "#ff0000'
;; :stroke-width 5 ;; :stroke-width 5
;; :x 1500 :y 2000}]) ;; :x 1500 :y 2000}])
;; ;;
;; (get-attrs-multi shapes [:stroke-color :stroke-width :fill-color]) ;; (get-attrs-multi values [:stroke-color :stroke-width :fill-color])
;; >>> {:stroke-color "#ff0000' ;; >>> {:stroke-color "#ff0000'
;; :stroke-width :multiple ;; :stroke-width :multiple
;; :fill-color nil} ;; :fill-color nil}
;; ;;
(let [combine-value #(if (= %1 %2) %1 :multiple) (let [defined-values (filter some? values)
combine-value #(if (= %1 %2) %1 :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 %) (get values %)) attrs))
@ -883,5 +885,5 @@
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 shapes) attrs) (rest shapes)))) (reduce reducer (select-keys (first defined-values) attrs) (rest defined-values))))

View file

@ -560,7 +560,7 @@
} }
}, },
"errors.email-already-exists" : { "errors.email-already-exists" : {
"used-in" : [ "src/uxbox/main/ui/auth.cljs:87", "src/uxbox/main/ui/settings/change_email.cljs:47" ], "used-in" : [ "src/uxbox/main/ui/settings/change_email.cljs:47", "src/uxbox/main/ui/auth.cljs:87" ],
"translations" : { "translations" : {
"en" : "Email already used", "en" : "Email already used",
"fr" : "Adresse e-mail déjà utilisée", "fr" : "Adresse e-mail déjà utilisée",
@ -576,7 +576,7 @@
} }
}, },
"errors.generic" : { "errors.generic" : {
"used-in" : [ "src/uxbox/main/ui.cljs:202", "src/uxbox/main/ui/auth.cljs:91", "src/uxbox/main/ui/settings/profile.cljs:38" ], "used-in" : [ "src/uxbox/main/ui.cljs:202", "src/uxbox/main/ui/settings/profile.cljs:38", "src/uxbox/main/ui/auth.cljs:91" ],
"translations" : { "translations" : {
"en" : "Something wrong has happened.", "en" : "Something wrong has happened.",
"fr" : "Quelque chose c'est mal passé.", "fr" : "Quelque chose c'est mal passé.",
@ -584,7 +584,7 @@
} }
}, },
"errors.image-format-unsupported" : { "errors.image-format-unsupported" : {
"used-in" : [ "src/uxbox/main/data/images.cljs:376", "src/uxbox/main/data/workspace/persistence.cljs:365", "src/uxbox/main/data/users.cljs:177" ], "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:365", "src/uxbox/main/data/users.cljs:177", "src/uxbox/main/data/images.cljs:376" ],
"translations" : { "translations" : {
"en" : "The image format is not supported (must be svg, jpg or png).", "en" : "The image format is not supported (must be svg, jpg or png).",
"fr" : "Le format d'image n'est pas supporté (doit être svg, jpg ou png).", "fr" : "Le format d'image n'est pas supporté (doit être svg, jpg ou png).",
@ -592,7 +592,7 @@
} }
}, },
"errors.image-too-large" : { "errors.image-too-large" : {
"used-in" : [ "src/uxbox/main/data/images.cljs:374", "src/uxbox/main/data/workspace/persistence.cljs:363", "src/uxbox/main/data/users.cljs:175" ], "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:363", "src/uxbox/main/data/users.cljs:175", "src/uxbox/main/data/images.cljs:374" ],
"translations" : { "translations" : {
"en" : "The image is too large to be inserted (must be under 5mb).", "en" : "The image is too large to be inserted (must be under 5mb).",
"fr" : "L'image est trop grande (doit être inférieure à 5 Mo).", "fr" : "L'image est trop grande (doit être inférieure à 5 Mo).",
@ -632,7 +632,7 @@
} }
}, },
"errors.unexpected-error" : { "errors.unexpected-error" : {
"used-in" : [ "src/uxbox/main/data/images.cljs:385", "src/uxbox/main/data/workspace/persistence.cljs:334", "src/uxbox/main/data/workspace/persistence.cljs:374", "src/uxbox/main/data/users.cljs:185", "src/uxbox/main/ui/auth/register.cljs:54", "src/uxbox/main/ui/settings/change_email.cljs:51", "src/uxbox/main/ui/workspace/sidebar/options/exports.cljs:65" ], "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:334", "src/uxbox/main/data/workspace/persistence.cljs:374", "src/uxbox/main/data/users.cljs:185", "src/uxbox/main/data/images.cljs:385", "src/uxbox/main/ui/settings/change_email.cljs:51", "src/uxbox/main/ui/workspace/sidebar/options/exports.cljs:65", "src/uxbox/main/ui/auth/register.cljs:54" ],
"translations" : { "translations" : {
"en" : "An unexpected error occurred.", "en" : "An unexpected error occurred.",
"fr" : "Une erreur inattendue c'est produite", "fr" : "Une erreur inattendue c'est produite",
@ -672,7 +672,7 @@
} }
}, },
"image.loading" : { "image.loading" : {
"used-in" : [ "src/uxbox/main/data/images.cljs:393", "src/uxbox/main/data/workspace/persistence.cljs:341", "src/uxbox/main/data/workspace/persistence.cljs:382", "src/uxbox/main/data/users.cljs:191" ], "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:341", "src/uxbox/main/data/workspace/persistence.cljs:382", "src/uxbox/main/data/users.cljs:191", "src/uxbox/main/data/images.cljs:393" ],
"translations" : { "translations" : {
"en" : "Loading image...", "en" : "Loading image...",
"fr" : "Chargement de l'image...", "fr" : "Chargement de l'image...",
@ -840,7 +840,7 @@
} }
}, },
"settings.multiple" : { "settings.multiple" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:121", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:251", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:264", "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:132", "src/uxbox/main/ui/workspace/sidebar/options/rows/color_row.cljs:117", "src/uxbox/main/ui/workspace/sidebar/options/rows/color_row.cljs:126" ], "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:132", "src/uxbox/main/ui/workspace/sidebar/options/rows/color_row.cljs:117", "src/uxbox/main/ui/workspace/sidebar/options/rows/color_row.cljs:126", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:124", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:227", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:240" ],
"translations" : { "translations" : {
"en" : "Mixed", "en" : "Mixed",
"fr" : null, "fr" : null,
@ -1394,165 +1394,13 @@
} }
}, },
"workspace.options.fill" : { "workspace.options.fill" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/fill.cljs:40", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:402" ], "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/fill.cljs:50" ],
"translations" : { "translations" : {
"en" : "Fill", "en" : "Fill",
"fr" : "Remplissage", "fr" : "Remplissage",
"es" : "Relleno" "es" : "Relleno"
} }
}, },
"workspace.options.font-options" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:407" ],
"translations" : {
"en" : "Text",
"fr" : "Texte",
"es" : "Texto"
}
},
"workspace.options.font-options.align-bottom" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:311" ],
"translations" : {
"en" : "Align bottom",
"fr" : "Aligner en bas",
"es" : "Alinear abajo"
}
},
"workspace.options.font-options.align-center" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:183" ],
"translations" : {
"en" : "Align center",
"fr" : "Aligner au centre",
"es" : "Aliniear al centro"
}
},
"workspace.options.font-options.align-justify" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:193" ],
"translations" : {
"en" : "Justify",
"fr" : "Justifier",
"es" : "Justificar"
}
},
"workspace.options.font-options.align-left" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:178" ],
"translations" : {
"en" : "Align left",
"fr" : "Aligner à gauche",
"es" : "Alinear a la izquierda"
}
},
"workspace.options.font-options.align-middle" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:306" ],
"translations" : {
"en" : "Align middle",
"fr" : "Aligner au milieu",
"es" : "Alinear al centro"
}
},
"workspace.options.font-options.align-right" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:188" ],
"translations" : {
"en" : "Align right",
"fr" : "Aligner à droite",
"es" : "Alinear a la derecha"
}
},
"workspace.options.font-options.align-top" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:301" ],
"translations" : {
"en" : "Align top",
"fr" : "Aligner en haut",
"es" : "Alinear arriba"
}
},
"workspace.options.font-options.decoration" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:333" ],
"translations" : {
"en" : "Decoration",
"fr" : "Décoration",
"es" : "Decoración"
}
},
"workspace.options.font-options.letter-spacing" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:256" ],
"translations" : {
"en" : "Letter Spacing",
"fr" : "Espacement de caractères",
"es" : "Espaciado entre letras"
}
},
"workspace.options.font-options.line-height" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:243" ],
"translations" : {
"en" : "Line height",
"fr" : "Hauteur de ligne",
"es" : "Altura de línea"
}
},
"workspace.options.font-options.lowercase" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:383" ],
"translations" : {
"en" : "Lowercase",
"fr" : "Minuscule",
"es" : "Minúsculas"
}
},
"workspace.options.font-options.none" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:336", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:373" ],
"translations" : {
"en" : "None",
"fr" : "Aucune",
"es" : "Nada"
}
},
"workspace.options.font-options.strikethrough" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:348" ],
"translations" : {
"en" : "Strikethrough",
"fr" : "Barré",
"es" : "Tachado"
}
},
"workspace.options.font-options.text-case" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:370" ],
"translations" : {
"en" : "Case",
"fr" : "Casse",
"es" : "Mayús/minús"
}
},
"workspace.options.font-options.titlecase" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:388" ],
"translations" : {
"en" : "Titlecase",
"fr" : "Titre",
"es" : "Título"
}
},
"workspace.options.font-options.underline" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:342" ],
"translations" : {
"en" : "Underline",
"fr" : "Souligner",
"es" : "Subrayado"
}
},
"workspace.options.font-options.uppercase" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:378" ],
"translations" : {
"en" : "Uppercase",
"fr" : "Majuscule",
"es" : "Mayúsculas"
}
},
"workspace.options.font-options.vertical-align" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:298" ],
"translations" : {
"en" : "Vertical align",
"fr" : "Alignement vertical",
"es" : "Alineación vertical"
}
},
"workspace.options.grid.auto" : { "workspace.options.grid.auto" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/frame_grid.cljs:40" ], "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/frame_grid.cljs:40" ],
"translations" : { "translations" : {
@ -1722,7 +1570,7 @@
} }
}, },
"workspace.options.group-fill" : { "workspace.options.group-fill" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/fill.cljs:39" ], "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/fill.cljs:49" ],
"translations" : { "translations" : {
"en" : "Group fill", "en" : "Group fill",
"fr" : null, "fr" : null,
@ -1802,7 +1650,7 @@
} }
}, },
"workspace.options.selection-fill" : { "workspace.options.selection-fill" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/fill.cljs:38" ], "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/fill.cljs:48" ],
"translations" : { "translations" : {
"en" : "Selection fill", "en" : "Selection fill",
"fr" : null, "fr" : null,
@ -1897,6 +1745,172 @@
"es" : "Sólido" "es" : "Sólido"
} }
}, },
"workspace.options.text-options.align-bottom" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:284" ],
"translations" : {
"en" : "Align bottom",
"fr" : "Aligner en bas",
"es" : "Alinear abajo"
}
},
"workspace.options.text-options.align-center" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:183" ],
"translations" : {
"en" : "Align center",
"fr" : "Aligner au centre",
"es" : "Aliniear al centro"
}
},
"workspace.options.text-options.align-justify" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:193" ],
"translations" : {
"en" : "Justify",
"fr" : "Justifier",
"es" : "Justificar"
}
},
"workspace.options.text-options.align-left" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:178" ],
"translations" : {
"en" : "Align left",
"fr" : "Aligner à gauche",
"es" : "Alinear a la izquierda"
}
},
"workspace.options.text-options.align-middle" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:279" ],
"translations" : {
"en" : "Align middle",
"fr" : "Aligner au milieu",
"es" : "Alinear al centro"
}
},
"workspace.options.text-options.align-right" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:188" ],
"translations" : {
"en" : "Align right",
"fr" : "Aligner à droite",
"es" : "Alinear a la derecha"
}
},
"workspace.options.text-options.align-top" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:274" ],
"translations" : {
"en" : "Align top",
"fr" : "Aligner en haut",
"es" : "Alinear arriba"
}
},
"workspace.options.text-options.decoration" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:303" ],
"translations" : {
"en" : "Decoration",
"fr" : "Décoration",
"es" : "Decoración"
}
},
"workspace.options.text-options.letter-spacing" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:232" ],
"translations" : {
"en" : "Letter Spacing",
"fr" : "Espacement de caractères",
"es" : "Espaciado entre letras"
}
},
"workspace.options.text-options.line-height" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:219" ],
"translations" : {
"en" : "Line height",
"fr" : "Hauteur de ligne",
"es" : "Altura de línea"
}
},
"workspace.options.text-options.lowercase" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:350" ],
"translations" : {
"en" : "Lowercase",
"fr" : "Minuscule",
"es" : "Minúsculas"
}
},
"workspace.options.text-options.none" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:306", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:340" ],
"translations" : {
"en" : "None",
"fr" : "Aucune",
"es" : "Nada"
}
},
"workspace.options.text-options.strikethrough" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:318" ],
"translations" : {
"en" : "Strikethrough",
"fr" : "Barré",
"es" : "Tachado"
}
},
"workspace.options.text-options.text-case" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:337" ],
"translations" : {
"en" : "Case",
"fr" : "Casse",
"es" : "Mayús/minús"
}
},
"workspace.options.text-options.title" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:375" ],
"translations" : {
"en" : "Text",
"fr" : "Texte",
"es" : "Texto"
}
},
"workspace.options.text-options.title-group" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:374" ],
"translations" : {
"en" : "Group text",
"es" : "Texto de grupo"
}
},
"workspace.options.text-options.title-selection" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:373" ],
"translations" : {
"en" : "Selection text",
"es" : "Texto de selección"
}
},
"workspace.options.text-options.titlecase" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:355" ],
"translations" : {
"en" : "Titlecase",
"fr" : "Titre",
"es" : "Título"
}
},
"workspace.options.text-options.underline" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:312" ],
"translations" : {
"en" : "Underline",
"fr" : "Souligner",
"es" : "Subrayado"
}
},
"workspace.options.text-options.uppercase" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:345" ],
"translations" : {
"en" : "Uppercase",
"fr" : "Majuscule",
"es" : "Mayúsculas"
}
},
"workspace.options.text-options.vertical-align" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:271" ],
"translations" : {
"en" : "Vertical align",
"fr" : "Alignement vertical",
"es" : "Alineación vertical"
}
},
"workspace.options.use-play-button" : { "workspace.options.use-play-button" : {
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs:55" ], "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs:55" ],
"translations" : { "translations" : {

View file

@ -55,9 +55,9 @@
(let [change #(cond-> % (let [change #(cond-> %
value (assoc :fill-color value) value (assoc :fill-color value)
opacity (assoc :fill-opacity opacity)) opacity (assoc :fill-opacity opacity))
new-attrs (cond-> {} converted-attrs (cond-> {}
value (assoc :fill value) value (assoc :fill value)
opacity (assoc :opacity opacity))] opacity (assoc :opacity opacity))]
(when-not (empty? other-ids) (when-not (empty? other-ids)
(st/emit! (dwc/update-shapes ids change))) (st/emit! (dwc/update-shapes ids change)))
@ -65,7 +65,7 @@
(run! #(st/emit! (dwt/update-text-attrs (run! #(st/emit! (dwt/update-text-attrs
{:id % {:id %
:editor editor :editor editor
:attrs new-attrs})) :attrs converted-attrs}))
text-ids))))] text-ids))))]
[:div.element-set [:div.element-set
[:div.element-set-title label] [:div.element-set-title label]

View file

@ -13,26 +13,123 @@
[rumext.alpha :as mf] [rumext.alpha :as mf]
[uxbox.common.geom.shapes :as geom] [uxbox.common.geom.shapes :as geom]
[uxbox.main.refs :as refs] [uxbox.main.refs :as refs]
[uxbox.main.data.workspace.texts :as dwt]
[uxbox.main.ui.workspace.sidebar.options.multiple :refer [get-shape-attrs]]
[uxbox.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]] [uxbox.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]]
[uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]] [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]]
[uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]])) [uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]]
[uxbox.main.ui.workspace.sidebar.options.text :refer [text-fill-attrs
text-font-attrs
text-align-attrs
text-spacing-attrs
text-valign-attrs
text-decoration-attrs
text-transform-attrs
text-menu]]))
(mf/defc options (mf/defc options
[{:keys [shape] :as props}] [{:keys [shape] :as props}]
(let [child-ids (:shapes shape) (let [child-ids (:shapes shape)
children (mf/deref (refs/objects-by-id child-ids)) children (mf/deref (refs/objects-by-id child-ids))
type (:type shape) text-ids (map :id (filter #(= (:type %) :text) children))
measure-values (select-keys shape measure-attrs) other-ids (map :id (filter #(not= (:type %) :text) children))
fill-values (geom/get-attrs-multi children fill-attrs)
stroke-values (geom/get-attrs-multi children stroke-attrs)] type (:type shape)
[:*
[:& measures-menu {:ids [(:id shape)] measure-values
:type type (select-keys shape measure-attrs)
:values measure-values}]
[:& fill-menu {:ids child-ids fill-values
:type type (geom/get-attrs-multi children fill-attrs)
:values fill-values}]
[:& stroke-menu {:ids child-ids stroke-values
:type type (geom/get-attrs-multi (map #(get-shape-attrs
:values stroke-values}]])) %
stroke-attrs
nil
nil
nil)
children)
stroke-attrs)
font-values
(geom/get-attrs-multi (map #(get-shape-attrs
%
nil
text-font-attrs
nil
dwt/current-text-values)
children)
text-font-attrs)
align-values
(geom/get-attrs-multi (map #(get-shape-attrs
%
nil
text-align-attrs
nil
dwt/current-paragraph-values)
children)
text-align-attrs)
spacing-values
(geom/get-attrs-multi (map #(get-shape-attrs
%
nil
text-spacing-attrs
nil
dwt/current-text-values)
children)
text-spacing-attrs)
valign-values
(geom/get-attrs-multi (map #(get-shape-attrs
%
nil
text-valign-attrs
nil
dwt/current-root-values)
children)
text-valign-attrs)
decoration-values
(geom/get-attrs-multi (map #(get-shape-attrs
%
nil
text-decoration-attrs
nil
dwt/current-text-values)
children)
text-decoration-attrs)
transform-values
(geom/get-attrs-multi (map #(get-shape-attrs
%
nil
text-transform-attrs
nil
dwt/current-text-values)
children)
text-transform-attrs)]
[:*
[:& measures-menu {:ids [(:id shape)]
:type type
:values measure-values}]
[:& fill-menu {:ids child-ids
:type type
:values fill-values}]
(when-not (empty? other-ids)
[:& stroke-menu {:ids child-ids
:type type
:values stroke-values}])
(when-not (empty? text-ids)
[:& text-menu {:ids text-ids
:type type
:editor nil
:font-values font-values
:align-values align-values
:spacing-values spacing-values
:valign-values valign-values
:decoration-values decoration-values
:transform-values transform-values}])]))

View file

@ -13,28 +13,122 @@
[uxbox.common.geom.shapes :as geom] [uxbox.common.geom.shapes :as geom]
[uxbox.main.data.workspace.texts :as dwt] [uxbox.main.data.workspace.texts :as dwt]
[uxbox.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]] [uxbox.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]]
[uxbox.main.ui.workspace.sidebar.options.text :refer [text-fill-attrs]]
[uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]] [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]]
[uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]])) [uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]]
[uxbox.main.ui.workspace.sidebar.options.text :refer [text-fill-attrs
text-font-attrs
text-align-attrs
text-spacing-attrs
text-valign-attrs
text-decoration-attrs
text-transform-attrs
text-menu]]))
(defn- get-attrs (defn get-shape-attrs
[shape attrs text-attrs] [shape attrs text-attrs convert-attrs extract-fn]
(if (not= (:type shape) :text) (if (not= (:type shape) :text)
(select-keys shape attrs) (when attrs
(let [text-values (dwt/current-text-values {:editor nil (select-keys shape attrs))
:shape shape (when text-attrs
:attrs text-attrs}) (let [text-values (extract-fn {:editor nil
converted-values (zipmap fill-attrs :shape shape
(map #(% text-values) text-attrs))] :attrs text-attrs})
converted-values)))
converted-values (if convert-attrs
(zipmap convert-attrs
(map #(% text-values) text-attrs))
text-values)]
converted-values))))
(mf/defc options (mf/defc options
{::mf/wrap [mf/memo]} {::mf/wrap [mf/memo]}
[{:keys [shapes] :as props}] [{:keys [shapes] :as props}]
(let [ids (map :id shapes) (let [ids (map :id shapes)
measure-values (geom/get-attrs-multi shapes measure-attrs) text-ids (map :id (filter #(= (:type %) :text) shapes))
fill-values (geom/get-attrs-multi (map #(get-attrs % fill-attrs text-fill-attrs) shapes) fill-attrs) other-ids (map :id (filter #(not= (:type %) :text) shapes))
stroke-values (geom/get-attrs-multi shapes stroke-attrs)]
measure-values
(geom/get-attrs-multi shapes measure-attrs)
fill-values
(geom/get-attrs-multi (map #(get-shape-attrs
%
fill-attrs
text-fill-attrs
fill-attrs
dwt/current-text-values)
shapes)
fill-attrs)
stroke-values
(geom/get-attrs-multi (map #(get-shape-attrs
%
stroke-attrs
nil
nil
nil)
shapes)
stroke-attrs)
font-values
(geom/get-attrs-multi (map #(get-shape-attrs
%
nil
text-font-attrs
nil
dwt/current-text-values)
shapes)
text-font-attrs)
align-values
(geom/get-attrs-multi (map #(get-shape-attrs
%
nil
text-align-attrs
nil
dwt/current-paragraph-values)
shapes)
text-align-attrs)
spacing-values
(geom/get-attrs-multi (map #(get-shape-attrs
%
nil
text-spacing-attrs
nil
dwt/current-text-values)
shapes)
text-spacing-attrs)
valign-values
(geom/get-attrs-multi (map #(get-shape-attrs
%
nil
text-valign-attrs
nil
dwt/current-root-values)
shapes)
text-valign-attrs)
decoration-values
(geom/get-attrs-multi (map #(get-shape-attrs
%
nil
text-decoration-attrs
nil
dwt/current-text-values)
shapes)
text-decoration-attrs)
transform-values
(geom/get-attrs-multi (map #(get-shape-attrs
%
nil
text-transform-attrs
nil
dwt/current-text-values)
shapes)
text-transform-attrs)]
[:* [:*
[:& measures-menu {:ids ids [:& measures-menu {:ids ids
:type :multiple :type :multiple
@ -42,7 +136,18 @@
[:& fill-menu {:ids ids [:& fill-menu {:ids ids
:type :multiple :type :multiple
:values fill-values}] :values fill-values}]
[:& stroke-menu {:ids ids (when-not (empty? other-ids)
[:& stroke-menu {:ids other-ids
:type :multiple
:values stroke-values}])
(when-not (empty? text-ids)
[:& text-menu {:ids text-ids
:type :multiple :type :multiple
:values stroke-values}]])) :editor nil
:font-values font-values
:align-values align-values
:spacing-values spacing-values
:valign-values valign-values
:decoration-values decoration-values
:transform-values transform-values}])]))

View file

@ -26,8 +26,12 @@
["slate" :refer [Transforms]])) ["slate" :refer [Transforms]]))
(def text-fill-attrs [:fill :opacity]) (def text-fill-attrs [:fill :opacity])
(def text-font-attrs [:font-id :font-family :font-variant-id :font-size :font-weight :font-style]) (def text-font-attrs [:font-id :font-family :font-variant-id :font-size :font-weight :font-style])
(def text-align-attrs [:text-align])
(def text-spacing-attrs [:line-height :letter-spacing])
(def text-valign-attrs [:vertical-align])
(def text-decoration-attrs [:text-decoration])
(def text-transform-attrs [:text-transform])
(defn- attr->string [value] (defn- attr->string [value]
(if (= value :multiple) (if (= value :multiple)
@ -171,22 +175,22 @@
;; --- Align ;; --- Align
[:div.row-flex.align-icons [:div.row-flex.align-icons
[:span.tooltip.tooltip-bottom [:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.font-options.align-left") {:alt (t locale "workspace.options.text-options.align-left")
:class (dom/classnames :current (= "left" text-align)) :class (dom/classnames :current (= "left" text-align))
:on-click #(on-change % "left")} :on-click #(on-change % "left")}
i/text-align-left] i/text-align-left]
[:span.tooltip.tooltip-bottom [:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.font-options.align-center") {:alt (t locale "workspace.options.text-options.align-center")
:class (dom/classnames :current (= "center" text-align)) :class (dom/classnames :current (= "center" text-align))
:on-click #(on-change % "center")} :on-click #(on-change % "center")}
i/text-align-center] i/text-align-center]
[:span.tooltip.tooltip-bottom [:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.font-options.align-right") {:alt (t locale "workspace.options.text-options.align-right")
:class (dom/classnames :current (= "right" text-align)) :class (dom/classnames :current (= "right" text-align))
:on-click #(on-change % "right")} :on-click #(on-change % "right")}
i/text-align-right] i/text-align-right]
[:span.tooltip.tooltip-bottom [:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.font-options.align-justify") {:alt (t locale "workspace.options.text-options.align-justify")
:class (dom/classnames :current (= "justify" text-align)) :class (dom/classnames :current (= "justify" text-align))
:on-click #(on-change % "justify")} :on-click #(on-change % "justify")}
i/text-align-justify]])) i/text-align-justify]]))
@ -212,7 +216,7 @@
[:div.row-flex [:div.row-flex
[:div.input-icon [:div.input-icon
[:span.icon-before.tooltip.tooltip-bottom [:span.icon-before.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.font-options.line-height")} {:alt (t locale "workspace.options.text-options.line-height")}
i/line-height] i/line-height]
[:input.input-text [:input.input-text
{:type "number" {:type "number"
@ -225,7 +229,7 @@
[:div.input-icon [:div.input-icon
[:span.icon-before.tooltip.tooltip-bottom [:span.icon-before.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.font-options.letter-spacing")} {:alt (t locale "workspace.options.text-options.letter-spacing")}
i/letter-spacing] i/letter-spacing]
[:input.input-text [:input.input-text
{:type "number" {:type "number"
@ -264,20 +268,20 @@
ids))] ids))]
[:div.row-flex [:div.row-flex
[:span.element-set-subtitle (t locale "workspace.options.font-options.vertical-align")] [:span.element-set-subtitle (t locale "workspace.options.text-options.vertical-align")]
[:div.align-icons [:div.align-icons
[:span.tooltip.tooltip-bottom [:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.font-options.align-top") {:alt (t locale "workspace.options.text-options.align-top")
:class (dom/classnames :current (= "top" vertical-align)) :class (dom/classnames :current (= "top" vertical-align))
:on-click #(on-change % "top")} :on-click #(on-change % "top")}
i/align-top] i/align-top]
[:span.tooltip.tooltip-bottom [:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.font-options.align-middle") {:alt (t locale "workspace.options.text-options.align-middle")
:class (dom/classnames :current (= "center" vertical-align)) :class (dom/classnames :current (= "center" vertical-align))
:on-click #(on-change % "center")} :on-click #(on-change % "center")}
i/align-middle] i/align-middle]
[:span.tooltip.tooltip-bottom [:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.font-options.align-bottom") {:alt (t locale "workspace.options.text-options.align-bottom")
:class (dom/classnames :current (= "bottom" vertical-align)) :class (dom/classnames :current (= "bottom" vertical-align))
:on-click #(on-change % "bottom")} :on-click #(on-change % "bottom")}
i/align-bottom]]])) i/align-bottom]]]))
@ -296,22 +300,22 @@
:attrs {:text-decoration type}})) :attrs {:text-decoration type}}))
ids))] ids))]
[:div.row-flex [:div.row-flex
[:span.element-set-subtitle (t locale "workspace.options.font-options.decoration")] [:span.element-set-subtitle (t locale "workspace.options.text-options.decoration")]
[:div.align-icons [:div.align-icons
[:span.tooltip.tooltip-bottom [:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.font-options.none") {:alt (t locale "workspace.options.text-options.none")
:class (dom/classnames :current (= "none" text-decoration)) :class (dom/classnames :current (= "none" text-decoration))
:on-click #(on-change % "none")} :on-click #(on-change % "none")}
i/minus] i/minus]
[:span.tooltip.tooltip-bottom [:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.font-options.underline") {:alt (t locale "workspace.options.text-options.underline")
:class (dom/classnames :current (= "underline" text-decoration)) :class (dom/classnames :current (= "underline" text-decoration))
:on-click #(on-change % "underline")} :on-click #(on-change % "underline")}
i/underline] i/underline]
[:span.tooltip.tooltip-bottom [:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.font-options.strikethrough") {:alt (t locale "workspace.options.text-options.strikethrough")
:class (dom/classnames :current (= "line-through" text-decoration)) :class (dom/classnames :current (= "line-through" text-decoration))
:on-click #(on-change % "line-through")} :on-click #(on-change % "line-through")}
i/strikethrough]]])) i/strikethrough]]]))
@ -330,25 +334,25 @@
:attrs {:text-transform type}})) :attrs {:text-transform type}}))
ids))] ids))]
[:div.row-flex [:div.row-flex
[:span.element-set-subtitle (t locale "workspace.options.font-options.text-case")] [:span.element-set-subtitle (t locale "workspace.options.text-options.text-case")]
[:div.align-icons [:div.align-icons
[:span.tooltip.tooltip-bottom [:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.font-options.none") {:alt (t locale "workspace.options.text-options.none")
:class (dom/classnames :current (= "none" text-transform)) :class (dom/classnames :current (= "none" text-transform))
:on-click #(on-change % "none")} :on-click #(on-change % "none")}
i/minus] i/minus]
[:span.tooltip.tooltip-bottom [:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.font-options.uppercase") {:alt (t locale "workspace.options.text-options.uppercase")
:class (dom/classnames :current (= "uppercase" text-transform)) :class (dom/classnames :current (= "uppercase" text-transform))
:on-click #(on-change % "uppercase")} :on-click #(on-change % "uppercase")}
i/uppercase] i/uppercase]
[:span.tooltip.tooltip-bottom [:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.font-options.lowercase") {:alt (t locale "workspace.options.text-options.lowercase")
:class (dom/classnames :current (= "lowercase" text-transform)) :class (dom/classnames :current (= "lowercase" text-transform))
:on-click #(on-change % "lowercase")} :on-click #(on-change % "lowercase")}
i/lowercase] i/lowercase]
[:span.tooltip.tooltip-bottom [:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.font-options.titlecase") {:alt (t locale "workspace.options.text-options.titlecase")
:class (dom/classnames :current (= "capitalize" text-transform)) :class (dom/classnames :current (= "capitalize" text-transform))
:on-click #(on-change % "capitalize")} :on-click #(on-change % "capitalize")}
i/titlecase]]])) i/titlecase]]]))
@ -358,26 +362,26 @@
[{:keys [ids [{:keys [ids
type type
editor editor
fill-values
font-values font-values
align-values align-values
spacing-values spacing-values
valign-values valign-values
decoration-values decoration-values
transform-values] :as props}] transform-values] :as props}]
(let [locale (mf/deref i18n/locale)] (let [locale (mf/deref i18n/locale)
[:* label (case type
[:& fill-menu {:ids ids :type type :values fill-values :editor editor}] :multiple (t locale "workspace.options.text-options.title-selection")
:group (t locale "workspace.options.text-options.title-group")
[:div.element-set (t locale "workspace.options.text-options.title"))]
[:div.element-set-title (t locale "workspace.options.font-options")] [:div.element-set
[:div.element-set-content [:div.element-set-title label]
[:& font-options {:editor editor :ids ids :values font-values :locale locale}] [:div.element-set-content
[:& text-align-options {:editor editor :ids ids :values align-values :locale locale}] [:& font-options {:editor editor :ids ids :values font-values :locale locale}]
[:& spacing-options {:editor editor :ids ids :values spacing-values :locale locale}] [:& text-align-options {:editor editor :ids ids :values align-values :locale locale}]
[:& vertical-align-options {:editor editor :ids ids :values valign-values :locale locale}] [:& spacing-options {:editor editor :ids ids :values spacing-values :locale locale}]
[:& text-decoration-options {:editor editor :ids ids :values decoration-values :locale locale}] [:& vertical-align-options {:editor editor :ids ids :values valign-values :locale locale}]
[:& text-transform-options {:editor editor :ids ids :values transform-values :locale locale}]]]])) [:& text-decoration-options {:editor editor :ids ids :values decoration-values :locale locale}]
[:& text-transform-options {:editor editor :ids ids :values transform-values :locale locale}]]]))
(mf/defc options (mf/defc options
[{:keys [shape] :as props}] [{:keys [shape] :as props}]
@ -387,15 +391,12 @@
local (deref refs/workspace-local) local (deref refs/workspace-local)
editor (get-in local [:editors (:id shape)]) editor (get-in local [:editors (:id shape)])
_ (println "hay editor" (clj->js (not (nil? editor))))
measure-values (select-keys shape measure-attrs) measure-values (select-keys shape measure-attrs)
fill-values (dwt/current-text-values fill-values (dwt/current-text-values
{:editor editor {:editor editor
:shape shape :shape shape
:attrs [:fill :attrs text-fill-attrs})
:opacity]})
converted-fill-values {:fill-color (:fill fill-values) converted-fill-values {:fill-color (:fill fill-values)
:fill-opacity (:opacity fill-values)} :fill-opacity (:opacity fill-values)}
@ -403,43 +404,43 @@
font-values (dwt/current-text-values font-values (dwt/current-text-values
{:editor editor {:editor editor
:shape shape :shape shape
:attrs [:font-id :attrs text-font-attrs})
:font-size
:font-variant-id]})
align-values (dwt/current-paragraph-values align-values (dwt/current-paragraph-values
{:editor editor {:editor editor
:shape shape :shape shape
:attrs [:text-align]}) :attrs text-align-attrs})
spacing-values (dwt/current-text-values spacing-values (dwt/current-text-values
{:editor editor {:editor editor
:shape shape :shape shape
:attrs [:line-height :attrs text-spacing-attrs})
:letter-spacing]})
valign-values (dwt/current-root-values valign-values (dwt/current-root-values
{:editor editor {:editor editor
:shape shape :shape shape
:attrs [:vertical-align]}) :attrs text-valign-attrs})
decoration-values (dwt/current-text-values decoration-values (dwt/current-text-values
{:editor editor {:editor editor
:shape shape :shape shape
:attrs [:text-decoration]}) :attrs text-decoration-attrs})
transform-values (dwt/current-text-values transform-values (dwt/current-text-values
{:editor editor {:editor editor
:shape shape :shape shape
:attrs [:text-transform]})] :attrs text-transform-attrs})]
[:div [:*
[:& measures-menu {:ids ids [:& measures-menu {:ids ids
:type type :type type
:values measure-values}] :values measure-values}]
[:& fill-menu {:ids ids
:type type
:values converted-fill-values
:editor editor}]
[:& text-menu {:ids ids [:& text-menu {:ids ids
:type type :type type
:editor editor :editor editor
:fill-values converted-fill-values
:font-values font-values :font-values font-values
:align-values align-values :align-values align-values
:spacing-values spacing-values :spacing-values spacing-values