diff --git a/frontend/src/app/main/ui/inspect/styles.cljs b/frontend/src/app/main/ui/inspect/styles.cljs index 99267d04cb..510c54bb80 100644 --- a/frontend/src/app/main/ui/inspect/styles.cljs +++ b/frontend/src/app/main/ui/inspect/styles.cljs @@ -77,7 +77,7 @@ (:content shape)) (defn- has-shadow? [shape] - (:shadow shape)) + (seq (:shadow shape))) (defn- get-shape-type [shapes first-shape first-component] @@ -111,7 +111,26 @@ (not (or (= shape-type :text) (= shape-type :group))) (or (:opacity shape) (:blend-mode shape) - (:visibility shape))))))] + (:visibility shape)))))) + shorthands* (mf/use-state #(do {:fill nil + :stroke nil + :text nil + :shadow nil + :blur nil + :layout nil + :layout-element nil + :geometry nil + :svg nil + :visibility nil + :variant nil + :grid-element nil})) + shorthands (deref shorthands*) + set-shorthands + ;; This fn must receive an object `shorthand` with :panel and :property (the shorthand string) keys + (mf/use-fn + (mf/deps shorthands*) + (fn [shorthand] + (swap! shorthands* assoc (:panel shorthand) (:property shorthand))))] [:ol {:class (stl/css :styles-tab) :aria-label (tr "labels.styles")} ;; TOKENS PANEL (when (or active-themes active-sets) @@ -130,18 +149,22 @@ :data data}]] ;; GEOMETRY PANEL :geometry - [:> style-box* {:panel :geometry} + [:> style-box* {:panel :geometry + :shorthand (:geometry shorthands)} [:> geometry-panel* {:shapes shapes :objects objects - :resolved-tokens resolved-active-tokens}]] + :resolved-tokens resolved-active-tokens + :on-geometry-shorthand set-shorthands}]] ;; LAYOUT PANEL :layout (let [layout-shapes (->> shapes (filter ctl/any-layout?))] (when (seq layout-shapes) - [:> style-box* {:panel :layout} + [:> style-box* {:panel :layout + :shorthand (:layout shorthands)} [:> layout-panel* {:shapes layout-shapes :objects objects - :resolved-tokens resolved-active-tokens}]])) + :resolved-tokens resolved-active-tokens + :on-layout-shorthand set-shorthands}]])) ;; LAYOUT ELEMENT PANEL :layout-element (let [shapes (->> shapes (filter #(ctl/any-layout-immediate-child? objects %))) @@ -157,29 +180,35 @@ (if only-grid? :grid-element :layout-element))] - [:> style-box* {:panel panel} + [:> style-box* {:panel panel + :shorthand (:layout-element shorthands)} [:> layout-element-panel* {:shapes shapes :objects objects :resolved-tokens resolved-active-tokens - :layout-element-properties layout-element-properties}]]))) + :layout-element-properties layout-element-properties + :on-layout-element-shorthand set-shorthands}]]))) ;; FILL PANEL :fill (let [shapes (filter has-fill? shapes)] (when (seq shapes) - [:> style-box* {:panel :fill} + [:> style-box* {:panel :fill + :shorthand (:fill shorthands)} [:> fill-panel* {:color-space color-space :shapes shapes - :resolved-tokens resolved-active-tokens}]])) + :resolved-tokens resolved-active-tokens + :on-fill-shorthand set-shorthands}]])) ;; STROKE PANEL :stroke (let [shapes (filter has-stroke? shapes)] (when (seq shapes) - [:> style-box* {:panel :stroke} + [:> style-box* {:panel :stroke + :shorthand (:stroke shorthands)} [:> stroke-panel* {:color-space color-space :shapes shapes :objects objects - :resolved-tokens resolved-active-tokens}]])) + :resolved-tokens resolved-active-tokens + :on-stroke-shorthand set-shorthands}]])) ;; VISIBILITY PANEL :visibility @@ -207,18 +236,23 @@ :text (let [shapes (filter has-text? shapes)] (when (seq shapes) - [:> style-box* {:panel :text} + [:> style-box* {:panel :text + :shorthand (:text shorthands)} [:> text-panel* {:shapes shapes :color-space color-space - :objects objects - :resolved-tokens resolved-active-tokens}]])) + :resolved-tokens resolved-active-tokens + :on-font-shorthand set-shorthands}]])) + ;; SHADOW PANEL :shadow (let [shapes (filter has-shadow? shapes)] (when (seq shapes) - [:> style-box* {:panel :shadow} + [:> style-box* {:panel :shadow + :shorthand (:shadow shorthands)} [:> shadow-panel* {:shapes shapes - :color-space color-space}]])) + :color-space color-space + :on-shadow-shorthand set-shorthands}]])) + ;; DEFAULT WIP [:> style-box* {:panel panel} [:div color-space]])])])) diff --git a/frontend/src/app/main/ui/inspect/styles/panels/blur.cljs b/frontend/src/app/main/ui/inspect/styles/panels/blur.cljs index 61e97e0ec2..f84dbf8633 100644 --- a/frontend/src/app/main/ui/inspect/styles/panels/blur.cljs +++ b/frontend/src/app/main/ui/inspect/styles/panels/blur.cljs @@ -17,7 +17,7 @@ [{:keys [shapes objects]}] [:div {:class (stl/css :blur-panel)} (for [shape shapes] - [:div {:key (:id shape) :class "blur-shape"} + [:div {:key (:id shape) :class (stl/css :blur-shape)} (let [property :filter value (css/get-css-value objects shape property) property-name (cmm/get-css-rule-humanized property) diff --git a/frontend/src/app/main/ui/inspect/styles/panels/fill.cljs b/frontend/src/app/main/ui/inspect/styles/panels/fill.cljs index 76111195c9..9fa32e245e 100644 --- a/frontend/src/app/main/ui/inspect/styles/panels/fill.cljs +++ b/frontend/src/app/main/ui/inspect/styles/panels/fill.cljs @@ -7,9 +7,12 @@ (ns app.main.ui.inspect.styles.panels.fill (:require-macros [app.main.style :as stl]) (:require + [app.common.data.macros :as dm] [app.common.types.fills :as types.fills] + [app.config :as cfg] [app.main.ui.inspect.attributes.common :as cmm] [app.main.ui.inspect.styles.rows.color-properties-row :refer [color-properties-row*]] + [app.util.color :as uc] [rumext.v2 :as mf])) (defn- get-applied-tokens-in-shape @@ -32,28 +35,56 @@ (and (= (:resolved-value resolved-token) (:color color-type)) (= 0 idx))) -(mf/defc fill-panel* - [{:keys [shapes resolved-tokens color-space]}] - [:div {:class (stl/css :fill-panel)} - (for [shape shapes] - [:div {:key (:id shape) :class "fill-shape"} - (for [[idx fill] (map-indexed vector (:fills shape))] - (let [property :background - color-type (types.fills/fill->color fill) ;; can be :color, :gradient or :image - property-name (cmm/get-css-rule-humanized property) - resolved-token (get-resolved-token shape resolved-tokens) - has-token (has-token? resolved-token color-type idx)] +(defn- generate-fill-shorthand + [shape] + (reduce + (fn [acc fill] + (let [color-type (types.fills/fill->color fill) + color-value (:color color-type) + color-gradient (:gradient color-type) + gradient-data {:type color-type + :stops (:stops color-gradient)} + color-image (:image color-type) + prefix (if color-value "background-color: " "background-image: ") + value (cond + (:color color-type) (dm/str color-value) + color-gradient (uc/gradient->css gradient-data) + color-image (str "url(\"" (cfg/resolve-file-media color-image) "\")") + :else "") + full-value (str prefix value ";")] + (if (empty? acc) + full-value + (str acc " " full-value)))) + "" + (:fills shape))) - (if (:color color-type) - [:> color-properties-row* {:key idx - :term property-name - :color color-type - :token (when has-token resolved-token) - :format color-space - :copiable true}] - (if (or (:gradient color-type) (:image color-type)) +(mf/defc fill-panel* + [{:keys [shapes resolved-tokens color-space on-fill-shorthand]}] + (let [shorthand* (mf/use-state #(generate-fill-shorthand (first shapes))) + shorthand (deref shorthand*)] + (mf/use-effect + (mf/deps shorthand on-fill-shorthand shapes) + (fn [] + (reset! shorthand* (generate-fill-shorthand (first shapes))) + (on-fill-shorthand {:panel :fill + :property shorthand}))) + [:div {:class (stl/css :fill-panel)} + (for [shape shapes] + [:div {:key (:id shape) :class (stl/css :fill-shape)} + (for [[idx fill] (map-indexed vector (:fills shape))] + (let [property :background + color-type (types.fills/fill->color fill) ;; can be :color, :gradient or :image + property-name (cmm/get-css-rule-humanized property) + resolved-token (get-resolved-token shape resolved-tokens) + has-token (has-token? resolved-token color-type idx)] + (if (:color color-type) [:> color-properties-row* {:key idx :term property-name :color color-type + :token (when has-token resolved-token) + :format color-space :copiable true}] - [:span "background-image"]))))])]) + [:> color-properties-row* {:key idx + :term property-name + :color color-type + :copiable true}])))])])) diff --git a/frontend/src/app/main/ui/inspect/styles/panels/geometry.cljs b/frontend/src/app/main/ui/inspect/styles/panels/geometry.cljs index d49d3bdc9b..8f13b9fabe 100644 --- a/frontend/src/app/main/ui/inspect/styles/panels/geometry.cljs +++ b/frontend/src/app/main/ui/inspect/styles/panels/geometry.cljs @@ -30,6 +30,15 @@ :border-end-start-radius :r3 :border-end-end-radius :r4}) +(defn- has-border-radius? + "Returns true if the shape has any non-zero border radius values." + [shape] + (let [radius-keys [:r1 :r2 :r3 :r4]] + (some (fn [key] + (and (contains? shape key) + (not= 0 (get shape key)))) + radius-keys))) + (defn- get-applied-tokens-in-shape [shape-tokens property] (let [border-prop (get shape-prop->border-radius-prop property)] @@ -44,19 +53,33 @@ token (get resolved-tokens applied-tokens-in-shape)] token)) +(defn- generate-geometry-shorthand + [shapes objects] + (when (and (= (count shapes) 1) (has-border-radius? (first shapes))) + (css/get-css-property objects (first shapes) :border-radius))) + (mf/defc geometry-panel* - [{:keys [shapes objects resolved-tokens]}] - [:div {:class (stl/css :geometry-panel)} - (for [shape shapes] - [:div {:key (:id shape) :class "geometry-shape"} - (for [property properties] - (when-let [value (css/get-css-value objects shape property)] - (let [property-name (cmm/get-css-rule-humanized property) - resolved-token (get-resolved-token property shape resolved-tokens) - property-value (if (not resolved-token) (css/get-css-property objects shape property) "")] - [:> properties-row* {:key (dm/str "geometry-property-" property) - :term property-name - :detail value - :token resolved-token - :property property-value - :copiable true}])))])]) + [{:keys [shapes objects resolved-tokens on-geometry-shorthand]}] + (let [shorthand* (mf/use-state #(generate-geometry-shorthand shapes objects)) + shorthand (deref shorthand*)] + (mf/use-effect + (mf/deps shorthand on-geometry-shorthand shapes objects) + (fn [] + (reset! shorthand* (generate-geometry-shorthand shapes objects)) + (on-geometry-shorthand {:panel :geometry + :property shorthand}))) + [:div {:class (stl/css :geometry-panel)} + (for [shape shapes] + [:div {:key (:id shape) :class (stl/css :geometry-shape)} + + (for [property properties] + (when-let [value (css/get-css-value objects shape property)] + (let [property-name (cmm/get-css-rule-humanized property) + resolved-token (get-resolved-token property shape resolved-tokens) + property-value (if (not resolved-token) (css/get-css-property objects shape property) "")] + [:> properties-row* {:key (dm/str "geometry-property-" property) + :term property-name + :detail value + :token resolved-token + :property property-value + :copiable true}])))])])) diff --git a/frontend/src/app/main/ui/inspect/styles/panels/layout.cljs b/frontend/src/app/main/ui/inspect/styles/panels/layout.cljs index bac0c70a1c..bb790e8f58 100644 --- a/frontend/src/app/main/ui/inspect/styles/panels/layout.cljs +++ b/frontend/src/app/main/ui/inspect/styles/panels/layout.cljs @@ -37,6 +37,15 @@ :padding-block-end :p3 :padding-inline-start :p4}) +(defn- has-padding? + [shape] + (let [padding (:layout-padding shape) + padding-keys [:p1 :p2 :p3 :p4]] + (some (fn [key] + (and (contains? padding key) + (not= 0 (get padding key)))) + padding-keys))) + (defn- get-applied-tokens-in-shape [shape-tokens property] (let [padding-prop (get shape-prop->padding-prop property)] @@ -51,19 +60,43 @@ token (get resolved-tokens applied-tokens-in-shape)] token)) +(defn- generate-layout-shorthand + [shapes objects] + (let [shape (first shapes) + shorthand-padding (when (and (= (count shapes) 1) (has-padding? shape)) + (css/get-css-property objects shape :padding)) + shorthand-grid (when (and (= (count shapes) 1) + (= :grid (:layout shape))) + (str "grid: " + (css/get-css-value objects shape :grid-template-rows) + " / " + (css/get-css-value objects shape :grid-template-columns) + ";")) + shorthand (when (or shorthand-padding shorthand-grid) + (str shorthand-grid " " shorthand-padding))] + shorthand)) + (mf/defc layout-panel* - [{:keys [shapes objects resolved-tokens]}] - [:div {:class (stl/css :variants-panel)} - (for [shape shapes] - [:div {:key (:id shape) :class "layout-shape"} - (for [property properties] - (when-let [value (css/get-css-value objects shape property)] - (let [property-name (cmm/get-css-rule-humanized property) - resolved-token (get-resolved-token property shape resolved-tokens) - property-value (if (not resolved-token) (css/get-css-property objects shape property) "")] - [:> properties-row* {:key (dm/str "layout-property-" property) - :term property-name - :detail value - :token resolved-token - :property property-value - :copiable true}])))])]) + [{:keys [shapes objects resolved-tokens on-layout-shorthand]}] + (let [shorthand* (mf/use-state #(generate-layout-shorthand shapes objects)) + shorthand (deref shorthand*)] + (mf/use-effect + (mf/deps shorthand on-layout-shorthand shapes objects) + (fn [] + (reset! shorthand* (generate-layout-shorthand shapes objects)) + (on-layout-shorthand {:panel :layout + :property shorthand}))) + [:div {:class (stl/css :variants-panel)} + (for [shape shapes] + [:div {:key (:id shape) :class (stl/css :layout-shape)} + (for [property properties] + (when-let [value (css/get-css-value objects shape property)] + (let [property-name (cmm/get-css-rule-humanized property) + resolved-token (get-resolved-token property shape resolved-tokens) + property-value (if (not resolved-token) (css/get-css-property objects shape property) "")] + [:> properties-row* {:key (dm/str "layout-property-" property) + :term property-name + :detail value + :token resolved-token + :property property-value + :copiable true}])))])])) diff --git a/frontend/src/app/main/ui/inspect/styles/panels/layout_element.cljs b/frontend/src/app/main/ui/inspect/styles/panels/layout_element.cljs index 4ebf9b393a..95149b90f7 100644 --- a/frontend/src/app/main/ui/inspect/styles/panels/layout_element.cljs +++ b/frontend/src/app/main/ui/inspect/styles/panels/layout_element.cljs @@ -25,6 +25,15 @@ :min-inline-size :layout-item-min-w ;; :min-width }) +(defn- has-margin? + [shape] + (let [margin (:layout-item-margin shape) + margin-keys [:m1 :m2 :m3 :m4]] + (some (fn [key] + (and (contains? margin key) + (not= 0 (get margin key)))) + margin-keys))) + (defn- get-applied-margins-in-shape [shape-tokens property] (if-let [margin-prop (get shape-prop->margin-prop property)] @@ -38,12 +47,40 @@ token (get resolved-tokens applied-tokens-in-shape)] token))) +(defn- generate-layout-element-shorthand + [shapes objects] + (let [shape (first shapes) + shorthand-margin (when (and (= (count shapes) 1) (has-margin? shape)) + (css/get-css-property objects shape :margin)) + shorthand-grow (when (and (= (count shapes) 1) + (ctl/flex-layout-immediate-child? objects shape)) + (if-let [flex-value (css/get-css-value objects shape :flex)] + flex-value + 0)) + shorthand-basis 0 ;; Default-value. Currently not supported in the UI + shorthand-shrink (when (and (= (count shapes) 1) + (ctl/flex-layout-immediate-child? objects shape)) + (if-let [flex-shrink-value (css/get-css-value objects shape :flex-shrink)] + flex-shrink-value + 0)) + shorthand-flex (dm/str "flex: " shorthand-grow " " shorthand-basis " " shorthand-shrink ";") + shorthand (dm/str shorthand-margin " " shorthand-flex)] + shorthand)) + (mf/defc layout-element-panel* - [{:keys [shapes objects resolved-tokens layout-element-properties]}] - (let [shapes (->> shapes (filter #(ctl/any-layout-immediate-child? objects %)))] + [{:keys [shapes objects resolved-tokens layout-element-properties on-layout-element-shorthand]}] + (let [shapes (->> shapes (filter #(ctl/any-layout-immediate-child? objects %))) + shorthand* (mf/use-state #(generate-layout-element-shorthand shapes objects)) + shorthand (deref shorthand*)] + (mf/use-effect + (mf/deps shorthand on-layout-element-shorthand shapes objects) + (fn [] + (reset! shorthand* (generate-layout-element-shorthand shapes objects)) + (on-layout-element-shorthand {:panel :layout-element + :property shorthand}))) [:div {:class (stl/css :layout-element-panel)} (for [shape shapes] - [:div {:key (:id shape) :class "layout-element-shape"} + [:div {:key (:id shape) :class (stl/css :layout-element-shape)} (for [property layout-element-properties] (when-let [value (css/get-css-value objects shape property)] (let [property-name (cmm/get-css-rule-humanized property) diff --git a/frontend/src/app/main/ui/inspect/styles/panels/shadow.cljs b/frontend/src/app/main/ui/inspect/styles/panels/shadow.cljs index d69a7186b1..c062e68131 100644 --- a/frontend/src/app/main/ui/inspect/styles/panels/shadow.cljs +++ b/frontend/src/app/main/ui/inspect/styles/panels/shadow.cljs @@ -12,22 +12,45 @@ [app.main.ui.inspect.styles.rows.color-properties-row :refer [color-properties-row*]] [app.main.ui.inspect.styles.rows.properties-row :refer [properties-row*]] [app.util.code-gen.style-css :as css] + [app.util.code-gen.style-css-formats :as scf] [rumext.v2 :as mf])) +(defn- generate-shadow-shorthand + [shapes] + (when (= (count shapes) 1) + (let [shorthand-property (dm/str "box-shadow: ") + shorthand-value (reduce + (fn [acc shadow] + (let [value (scf/format-shadow->css shadow {})] + (if (empty? acc) + value + (dm/str acc ", " value)))) + "" + (:shadow (first shapes)))] + (dm/str shorthand-property shorthand-value ";")))) + (mf/defc shadow-panel* - [{:keys [shapes color-space]}] - [:div {:class (stl/css :shadow-panel)} - (for [shape shapes] - (for [shadow (:shadow shape)] - [:div {:key (dm/str (:id shape) (:type shadow)) :class "shadow-shape"} - [:> color-properties-row* {:term "Shadow Color" - :color (:color shadow) - :format color-space - :copiable true}] - (let [value (dm/str (:offset-x shadow) "px" " " (:offset-y shadow) "px" " " (:blur shadow) "px" " " (:spread shadow) "px") - property-name (cmm/get-css-rule-humanized (:style shadow)) - property-value (css/shadow->css shadow)] - [:> properties-row* {:term property-name - :detail (dm/str value) - :property property-value - :copiable true}])]))]) + [{:keys [shapes color-space on-shadow-shorthand]}] + (let [shorthand* (mf/use-state #(generate-shadow-shorthand shapes)) + shorthand (deref shorthand*)] + (mf/use-effect + (mf/deps shorthand on-shadow-shorthand shapes) + (fn [] + (reset! shorthand* (generate-shadow-shorthand shapes)) + (on-shadow-shorthand {:panel :shadow + :property shorthand}))) + [:div {:class (stl/css :shadow-panel)} + (for [shape shapes] + (for [[idx shadow] (map-indexed vector (:shadow shape))] + [:div {:key (dm/str idx) :class (stl/css :shadow-shape)} + [:> color-properties-row* {:term "Shadow Color" + :color (:color shadow) + :format color-space + :copiable true}] + (let [value (dm/str (:offset-x shadow) "px" " " (:offset-y shadow) "px" " " (:blur shadow) "px" " " (:spread shadow) "px") + property-name (cmm/get-css-rule-humanized (:style shadow)) + property-value (css/shadow->css shadow)] + [:> properties-row* {:term property-name + :detail (dm/str value) + :property property-value + :copiable true}])]))])) diff --git a/frontend/src/app/main/ui/inspect/styles/panels/stroke.cljs b/frontend/src/app/main/ui/inspect/styles/panels/stroke.cljs index 798320c093..18c6a9e72c 100644 --- a/frontend/src/app/main/ui/inspect/styles/panels/stroke.cljs +++ b/frontend/src/app/main/ui/inspect/styles/panels/stroke.cljs @@ -9,22 +9,17 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.types.color :as ctc] + [app.config :as cfg] [app.main.ui.inspect.attributes.common :as cmm] [app.main.ui.inspect.styles.rows.color-properties-row :refer [color-properties-row*]] [app.main.ui.inspect.styles.rows.properties-row :refer [properties-row*]] [app.util.code-gen.style-css :as css] + [app.util.color :as uc] [rumext.v2 :as mf])) (def ^:private properties [:border-color :border-style :border-width]) -(defn- stroke->color [shape] - {:color (:stroke-color shape) - :opacity (:stroke-opacity shape) - :gradient (:stroke-color-gradient shape) - :id (:stroke-color-ref-id shape) - :file-id (:stroke-color-ref-file shape) - :image (:stroke-image shape)}) - (def ^:private shape-prop->stroke-prop {:border-style :stroke-style :border-width :stroke-width @@ -57,29 +52,62 @@ (and (= (:resolved-value resolved-token) (:color stroke-type)) (is-first-element? idx))) +(defn- generate-stroke-shorthand + [shapes] + (when (= (count shapes) 1) + (let [shape (first shapes)] + (reduce + (fn [acc stroke] + (let [stroke-type (ctc/stroke->color stroke) + stroke-width (:stroke-width stroke) + stroke-style (:stroke-style stroke) + color-value (:color stroke-type) + color-gradient (:gradient stroke-type) + gradient-data {:type (get-in stroke-type [:gradient :type]) + :stops (get-in stroke-type [:gradient :stops])} + color-image (:image stroke-type) + value (cond + color-value (dm/str "border: " stroke-width "px " (d/name stroke-style) " " color-value ";") + color-gradient (dm/str "border-image: " (uc/gradient->css gradient-data) " 100 / " stroke-width "px;") + color-image (dm/str "border-image: url(" (cfg/resolve-file-media color-image) ") 100 / " stroke-width "px;") + :else "")] + (if (empty? acc) + value + (str acc " " value)))) + "" + (:strokes shape))))) + (mf/defc stroke-panel* - [{:keys [shapes objects resolved-tokens color-space]}] - [:div {:class (stl/css :stroke-panel)} - (for [shape shapes] - [:div {:key (:id shape) :class "stroke-shape"} - (for [[idx stroke] (map-indexed vector (:strokes shape))] - (for [property properties] - (let [value (css/get-css-value objects stroke property) - stroke-type (stroke->color stroke) - property-name (cmm/get-css-rule-humanized property) - property-value (css/get-css-property objects stroke property) - resolved-token (when (is-first-element? idx) (get-resolved-token property shape resolved-tokens)) - has-color-token (has-color-token? resolved-token stroke-type idx)] - (if (= property :border-color) - [:> color-properties-row* {:key (str idx property) - :term property-name - :color stroke-type - :token (when has-color-token resolved-token) - :format color-space - :copiable true}] - [:> properties-row* {:key (str idx property) - :term (d/name property-name) - :detail (dm/str value) - :token resolved-token - :property property-value - :copiable true}]))))])]) + [{:keys [shapes objects resolved-tokens color-space on-stroke-shorthand]}] + (let [shorthand* (mf/use-state #(generate-stroke-shorthand shapes)) + shorthand (deref shorthand*)] + (mf/use-effect + (mf/deps shorthand on-stroke-shorthand shapes) + (fn [] + (reset! shorthand* (generate-stroke-shorthand shapes)) + (on-stroke-shorthand {:panel :stroke + :property shorthand}))) + [:div {:class (stl/css :stroke-panel)} + (for [shape shapes] + [:div {:key (:id shape) :class (stl/css :stroke-shape)} + (for [[idx stroke] (map-indexed vector (:strokes shape))] + (for [property properties] + (let [value (css/get-css-value objects stroke property) + stroke-type (ctc/stroke->color stroke) + property-name (cmm/get-css-rule-humanized property) + property-value (css/get-css-property objects stroke property) + resolved-token (when (is-first-element? idx) (get-resolved-token property shape resolved-tokens)) + has-color-token (has-color-token? resolved-token stroke-type idx)] + (if (= property :border-color) + [:> color-properties-row* {:key (str idx property) + :term property-name + :color stroke-type + :token (when has-color-token resolved-token) + :format color-space + :copiable true}] + [:> properties-row* {:key (str idx property) + :term (d/name property-name) + :detail (dm/str value) + :token resolved-token + :property property-value + :copiable true}]))))])])) diff --git a/frontend/src/app/main/ui/inspect/styles/panels/text.cljs b/frontend/src/app/main/ui/inspect/styles/panels/text.cljs index 14f2e9e4fe..eaa957ee35 100644 --- a/frontend/src/app/main/ui/inspect/styles/panels/text.cljs +++ b/frontend/src/app/main/ui/inspect/styles/panels/text.cljs @@ -7,6 +7,7 @@ (ns app.main.ui.inspect.styles.panels.text (:require-macros [app.main.style :as stl]) (:require + [app.common.data.macros :as dm] [app.common.types.fills :as types.fills] [app.common.types.text :as txt] [app.main.fonts :as fonts] @@ -38,6 +39,23 @@ (remove (fn [[_ text]] (str/empty? (str/trim text)))) (mapv (fn [[style text]] (vector (merge (txt/get-default-text-attrs) style) text))))) +(defn- generate-typography-shorthand + [shapes] + (when (= (count shapes) 1) + (let [shape (first shapes) + style-text-blocks (get-style-text shape)] + (reduce + (fn [acc [style _]] + (let [font-style (:font-style style) + font-family (dm/str (:font-family style)) + font-size (:font-size style) + font-weight (:font-weight style) + line-height (:line-height style) + text-transform (:text-transform style)] + (dm/str acc "font:" font-style " " text-transform " " font-weight " " font-size "/" line-height " " \" font-family \" ";"))) + "" + style-text-blocks)))) + (mf/defc typography-name-block* [{:keys [style]}] (let [typography (ict/get-typography style) @@ -59,126 +77,133 @@ :copiable true}])) (mf/defc text-panel* - [{:keys [shapes _ resolved-tokens color-space]}] - [:div {:class (stl/css :text-panel)} - (for [shape shapes] - (let [style-text-blocks (get-style-text shape) - composite-typography-token (get-resolved-token :typography shape resolved-tokens)] + [{:keys [shapes resolved-tokens color-space on-font-shorthand]}] + (let [shorthand* (mf/use-state #(generate-typography-shorthand shapes)) + shorthand (deref shorthand*)] + (mf/use-effect + (mf/deps shorthand on-font-shorthand shapes) + (fn [] + (reset! shorthand* (generate-typography-shorthand shapes)) + (on-font-shorthand {:panel :text + :property shorthand}))) + [:div {:class (stl/css :text-panel)} + (for [shape shapes] + (let [style-text-blocks (get-style-text shape) + composite-typography-token (get-resolved-token :typography shape resolved-tokens)] + [:div {:key (:id shape) :class (stl/css :text-shape)} + (for [[style text] style-text-blocks] - [:div {:key (:id shape) :class "text-shape"} - (for [[style text] style-text-blocks] + [:div {:key (:id shape) :class (stl/css :text-properties)} - [:div {:key (:id shape) :class "text-properties"} - - (when (:fills style) - (for [[idx fill] (map-indexed vector (:fills style))] - [:> typography-color-row* {:key idx - :fill fill - :shape shape - :resolved-tokens resolved-tokens - :color-space color-space}])) + (when (:fills style) + (for [[idx fill] (map-indexed vector (:fills style))] + [:> typography-color-row* {:key idx + :fill fill + :shape shape + :resolved-tokens resolved-tokens + :color-space color-space}])) ;; Typography style - (when (and (not composite-typography-token) - (:typography-ref-id style)) - [:> typography-name-block* {:style style}]) + (when (and (not composite-typography-token) + (:typography-ref-id style)) + [:> typography-name-block* {:style style}]) ;; Composite Typography token - (when (and (not (:typography-ref-id style)) - composite-typography-token) - [:> properties-row* {:term "Typography" - :detail (:name composite-typography-token) - :token composite-typography-token - :property (:name composite-typography-token) - :copiable true}]) + (when (and (not (:typography-ref-id style)) + composite-typography-token) + [:> properties-row* {:term "Typography" + :detail (:name composite-typography-token) + :token composite-typography-token + :property (:name composite-typography-token) + :copiable true}]) - (when (:font-id style) - (let [name (get (fonts/get-font-data (:font-id style)) :name) - resolved-token (get-resolved-token :font-family shape resolved-tokens)] - [:> properties-row* {:term "Font Family" - :detail name - :token resolved-token - :property (str "font-family: \"" name "\";") - :copiable true}])) + (when (:font-id style) + (let [name (get (fonts/get-font-data (:font-id style)) :name) + resolved-token (get-resolved-token :font-family shape resolved-tokens)] + [:> properties-row* {:term "Font Family" + :detail name + :token resolved-token + :property (str "font-family: \"" name "\";") + :copiable true}])) - (when (:font-style style) - [:> properties-row* {:term "Font Style" - :detail (:font-style style) - :property (str "font-style: " (:font-style style) ";") - :copiable true}]) + (when (:font-style style) + [:> properties-row* {:term "Font Style" + :detail (:font-style style) + :property (str "font-style: " (:font-style style) ";") + :copiable true}]) - (when (:font-size style) - (let [font-size (fmt/format-pixels (:font-size style)) - resolved-token (get-resolved-token :font-size shape resolved-tokens)] - [:> properties-row* {:term "Font Size" - :detail font-size - :token resolved-token - :property (str "font-size: " font-size ";") - :copiable true}])) - (when (:font-weight style) - (let [resolved-token (get-resolved-token :font-weight shape resolved-tokens)] - [:> properties-row* {:term "Font Weight" - :detail (:font-weight style) - :token resolved-token - :property (str "font-weight: " (:font-weight style) ";") - :copiable true}])) + (when (:font-size style) + (let [font-size (fmt/format-pixels (:font-size style)) + resolved-token (get-resolved-token :font-size shape resolved-tokens)] + [:> properties-row* {:term "Font Size" + :detail font-size + :token resolved-token + :property (str "font-size: " font-size ";") + :copiable true}])) + (when (:font-weight style) + (let [resolved-token (get-resolved-token :font-weight shape resolved-tokens)] + [:> properties-row* {:term "Font Weight" + :detail (:font-weight style) + :token resolved-token + :property (str "font-weight: " (:font-weight style) ";") + :copiable true}])) - (when (:line-height style) - (let [line-height (:line-height style) - resolved-token (get-resolved-token :line-height shape resolved-tokens)] - [:> properties-row* {:term "Line Height" - :detail (str line-height) - :token resolved-token - :property (str "line-height: " line-height ";") - :copiable true}])) + (when (:line-height style) + (let [line-height (:line-height style) + resolved-token (get-resolved-token :line-height shape resolved-tokens)] + [:> properties-row* {:term "Line Height" + :detail (str line-height) + :token resolved-token + :property (str "line-height: " line-height ";") + :copiable true}])) - (when (:letter-spacing style) - (let [letter-spacing (fmt/format-pixels (:letter-spacing style)) - resolved-token (get-resolved-token :letter-spacing shape resolved-tokens)] - [:> properties-row* {:term "Letter Spacing" - :detail letter-spacing - :token resolved-token - :property (str "letter-spacing: " letter-spacing ";") - :copiable true}])) + (when (:letter-spacing style) + (let [letter-spacing (fmt/format-pixels (:letter-spacing style)) + resolved-token (get-resolved-token :letter-spacing shape resolved-tokens)] + [:> properties-row* {:term "Letter Spacing" + :detail letter-spacing + :token resolved-token + :property (str "letter-spacing: " letter-spacing ";") + :copiable true}])) - (when (:text-decoration style) - (let [resolved-token (get-resolved-token :text-decoration shape resolved-tokens)] - [:> properties-row* {:term "Text Decoration" - :detail (:text-decoration style) - :token resolved-token - :property (str "text-decoration: " (:text-decoration style) ";") - :copiable true}])) + (when (:text-decoration style) + (let [resolved-token (get-resolved-token :text-decoration shape resolved-tokens)] + [:> properties-row* {:term "Text Decoration" + :detail (:text-decoration style) + :token resolved-token + :property (str "text-decoration: " (:text-decoration style) ";") + :copiable true}])) - (when (:text-transform style) - (let [resolved-token (get-resolved-token :text-case shape resolved-tokens)] - [:> properties-row* {:term "Text Transform" - :detail (:text-transform style) - :token resolved-token - :property (str "text-transform: " (:text-transform style) ";") - :copiable true}])) - (when text - (let [copied* (mf/use-state false) - copied (deref copied*) + (when (:text-transform style) + (let [resolved-token (get-resolved-token :text-case shape resolved-tokens)] + [:> properties-row* {:term "Text Transform" + :detail (:text-transform style) + :token resolved-token + :property (str "text-transform: " (:text-transform style) ";") + :copiable true}])) + (when text + (let [copied* (mf/use-state false) + copied (deref copied*) - text (str/trim text) + text (str/trim text) - copy-text - (mf/use-fn - (mf/deps copied) - (fn [] - (let [formatted-text (if (= (:text-transform style) "uppercase") - (.toUpperCase text) - text)] - (reset! copied* true) - (wapi/write-to-clipboard formatted-text) - (tm/schedule 1000 #(reset! copied* false)))))] - [:div {:class (stl/css :text-content-wrapper)} - [:> property-detail-copiable* {:copied copied - :on-click copy-text} - [:span {:class (stl/css :text-content) - :style {:font-family (:font-family style) - :font-weight (:font-weight style) - :text-transform (:text-transform style) - :letter-spacing (fmt/format-pixels (:letter-spacing style)) - :font-style (:font-style style)}} - text]]]))])]))]) + copy-text + (mf/use-fn + (mf/deps copied) + (fn [] + (let [formatted-text (if (= (:text-transform style) "uppercase") + (.toUpperCase text) + text)] + (reset! copied* true) + (wapi/write-to-clipboard formatted-text) + (tm/schedule 1000 #(reset! copied* false)))))] + [:div {:class (stl/css :text-content-wrapper)} + [:> property-detail-copiable* {:copied copied + :on-click copy-text} + [:span {:class (stl/css :text-content) + :style {:font-family (:font-family style) + :font-weight (:font-weight style) + :text-transform (:text-transform style) + :letter-spacing (fmt/format-pixels (:letter-spacing style)) + :font-style (:font-style style)}} + text]]]))])]))])) diff --git a/frontend/src/app/main/ui/inspect/styles/rows/color_properties_row.cljs b/frontend/src/app/main/ui/inspect/styles/rows/color_properties_row.cljs index a651b428cb..8c7553f27e 100644 --- a/frontend/src/app/main/ui/inspect/styles/rows/color_properties_row.cljs +++ b/frontend/src/app/main/ui/inspect/styles/rows/color_properties_row.cljs @@ -34,7 +34,6 @@ [{:keys [class term color format token]}] (let [copied* (mf/use-state false) copied (deref copied*) - color-value (:color color) color-gradient (:gradient color) color-image (:image color) diff --git a/frontend/src/app/main/ui/inspect/styles/style_box.cljs b/frontend/src/app/main/ui/inspect/styles/style_box.cljs index 404404c9c6..af63cacf39 100644 --- a/frontend/src/app/main/ui/inspect/styles/style_box.cljs +++ b/frontend/src/app/main/ui/inspect/styles/style_box.cljs @@ -48,8 +48,9 @@ copy-shorthand (mf/use-fn + (mf/deps shorthand) (fn [] - (wapi/write-to-clipboard (str "Style: " title))))] + (wapi/write-to-clipboard (str shorthand))))] [:article {:class (stl/css :style-box)} [:header {:class (stl/css :disclosure-header)} [:button {:class (stl/css :disclosure-button) diff --git a/frontend/src/app/main/ui/inspect/styles/style_box.scss b/frontend/src/app/main/ui/inspect/styles/style_box.scss index 25370d973c..5ca14f8977 100644 --- a/frontend/src/app/main/ui/inspect/styles/style_box.scss +++ b/frontend/src/app/main/ui/inspect/styles/style_box.scss @@ -17,6 +17,7 @@ .disclosure-header { display: flex; + align-items: center; gap: var(--title-gap); padding-block: var(--title-padding); } diff --git a/frontend/translations/en.po b/frontend/translations/en.po index cbb979218d..c6c97f8ca7 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -1904,7 +1904,7 @@ msgstr "Info" #: src/app/main/ui/inspect/styles/style_box.cljs:66 #, fuzzy msgid "inspect.tabs.styles.panel.copy-style-shorthand" -msgstr "" +msgstr "Copy CSS shorthand to clipboard" #: src/app/main/ui/inspect/styles/property_detail_copiable.cljs:52 msgid "inspect.tabs.styles.panel.copy-to-clipboard" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 6f4ec82e6a..a55026d4dd 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -1896,6 +1896,23 @@ msgstr "Calculado" msgid "inspect.tabs.info" msgstr "Información" +#: src/app/main/ui/inspect/styles/style_box.cljs:66 +#, fuzzy +msgid "inspect.tabs.styles.panel.copy-style-shorthand" +msgstr "Copiar CSS shorthand al portapapeles" + +#: src/app/main/ui/inspect/styles/property_detail_copiable.cljs:52 +msgid "inspect.tabs.styles.panel.copy-to-clipboard" +msgstr "Copiar al portapapeles" + +#: src/app/main/ui/inspect/styles/panels/tokens_panel.cljs:26 +msgid "inspect.tabs.styles.panel.tokens.active-sets" +msgstr "Sets activos" + +#: src/app/main/ui/inspect/styles/panels/tokens_panel.cljs:21 +msgid "inspect.tabs.styles.panel.tokens.active-themes" +msgstr "Temas activos" + #: src/app/main/ui/inspect/styles/style_box.cljs:22 msgid "inspect.tabs.styles.panel.geometry" msgstr "Tamaño y posición"