🐛 Add export menu to inspect styles tab (#8645)

* 🐛 Add export menu to inspect styles tab

* 📎 Add to CHANGES
This commit is contained in:
Xaviju
2026-03-19 23:20:18 +01:00
committed by GitHub
parent f8913c755d
commit 8ad62c6800
4 changed files with 155 additions and 124 deletions

View File

@@ -20,6 +20,8 @@
### :bug: Bugs fixed
- Add export panel to inspect styles tab [Taiga #13582](https://tree.taiga.io/project/penpot/issue/13582)
## 2.15.0 (Unreleased)
### :boom: Breaking changes & Deprecations

View File

@@ -188,7 +188,9 @@
:shapes shapes
:from from
:libraries libraries
:file-id file-id}]
:page-id page-id
:file-id file-id
:share-id share-id}]
:computed
[:> attributes* {:color-space color-space
:page-id page-id

View File

@@ -15,6 +15,7 @@
[app.common.types.tokens-lib :as ctob]
[app.main.data.style-dictionary :as sd]
[app.main.refs :as refs]
[app.main.ui.inspect.exports :as exports]
[app.main.ui.inspect.styles.panels.blur :refer [blur-panel*]]
[app.main.ui.inspect.styles.panels.fill :refer [fill-panel*]]
[app.main.ui.inspect.styles.panels.geometry :refer [geometry-panel*]]
@@ -89,8 +90,20 @@
(:type first-shape))
:multiple))
(def ^:private schema:styles-tab
[:map
[:color-space {:optional true} :string] ;; color format, e.g., "hex", "rgba", etc.
[:shapes :any]
[:libraries :map]
[:objects :map]
[:file-id :uuid]
[:page-id :uuid]
[:share-id {:optional true} [:maybe :uuid]]
[:from {:optional true} [:enum :workspace :viewer]]])
(mf/defc styles-tab*
[{:keys [color-space shapes libraries objects file-id from]}]
{::mf/schema schema:styles-tab}
[{:keys [color-space shapes libraries objects file-id page-id share-id from]}]
(let [data (dm/get-in libraries [file-id :data])
first-shape (first shapes)
first-component (ctkl/get-component data (:component-id first-shape))
@@ -131,130 +144,139 @@
(mf/deps shorthands*)
(fn [shorthand]
(swap! shorthands* assoc (:panel shorthand) (:property shorthand))))]
[:ol {:class (stl/css-case :styles-tab true
:styles-tab-workspace (= from :workspace)) :aria-label (tr "labels.styles")}
;; TOKENS PANEL
(when (or (seq active-themes) (seq active-sets))
[:li
[:> style-box* {:panel :token}
[:> tokens-panel* {:theme-paths active-themes :set-names active-sets}]]])
(for [panel panels]
[:li {:key (d/name panel)}
(case panel
;; VARIANTS PANEL
:variant
[:> style-box* {:panel :variant}
[:> variants-panel* {:component first-component
:objects objects
:shape first-shape
:data data}]]
;; GEOMETRY PANEL
:geometry
[:> style-box* {:panel :geometry
:shorthand (:geometry shorthands)}
[:> geometry-panel* {:shapes shapes
:objects objects
: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
:shorthand (:layout shorthands)}
[:> layout-panel* {:shapes layout-shapes
:objects objects
: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 %)))
some-layout-prop? (->> shapes
(mapcat (fn [shape]
(keep #(css/get-css-value objects shape %) layout-element-properties)))
(seq))]
(when some-layout-prop?
(let [only-flex? (every? #(ctl/flex-layout-immediate-child? objects %) shapes)
only-grid? (every? #(ctl/grid-layout-immediate-child? objects %) shapes)
panel (if only-flex?
:flex-element
(if only-grid?
:grid-element
:layout-element))]
[:> 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
:on-layout-element-shorthand set-shorthands}]])))
;; FILL PANEL
:fill
(let [shapes (filter has-fill? shapes)]
(when (seq shapes)
[:> style-box* {:panel :fill
:shorthand (:fill shorthands)}
[:> fill-panel* {:color-space color-space
:shapes shapes
:resolved-tokens resolved-active-tokens
:on-fill-shorthand set-shorthands}]]))
[:section {:class (stl/css-case :styles-tab true
:styles-tab-workspace (= from :workspace))
:aria-label (tr "labels.styles")}
[:ol
;; TOKENS PANEL
(when (or (seq active-themes) (seq active-sets))
[:li
[:> style-box* {:panel :token}
[:> tokens-panel* {:theme-paths active-themes :set-names active-sets}]]])
(for [panel panels]
[:li {:key (d/name panel)}
(case panel
;; VARIANTS PANEL
:variant
[:> style-box* {:panel :variant}
[:> variants-panel* {:component first-component
:objects objects
:shape first-shape
:data data}]]
;; GEOMETRY PANEL
:geometry
[:> style-box* {:panel :geometry
:shorthand (:geometry shorthands)}
[:> geometry-panel* {:shapes shapes
:objects objects
: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
:shorthand (:layout shorthands)}
[:> layout-panel* {:shapes layout-shapes
:objects objects
: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 %)))
some-layout-prop? (->> shapes
(mapcat (fn [shape]
(keep #(css/get-css-value objects shape %) layout-element-properties)))
(seq))]
(when some-layout-prop?
(let [only-flex? (every? #(ctl/flex-layout-immediate-child? objects %) shapes)
only-grid? (every? #(ctl/grid-layout-immediate-child? objects %) shapes)
panel (if only-flex?
:flex-element
(if only-grid?
:grid-element
:layout-element))]
[:> 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
:on-layout-element-shorthand set-shorthands}]])))
;; FILL PANEL
:fill
(let [shapes (filter has-fill? shapes)]
(when (seq shapes)
[:> style-box* {:panel :fill
:shorthand (:fill shorthands)}
[:> fill-panel* {:color-space color-space
:shapes shapes
: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
:shorthand (:stroke shorthands)}
[:> stroke-panel* {:color-space color-space
:shapes shapes
:objects objects
:resolved-tokens resolved-active-tokens
:on-stroke-shorthand set-shorthands}]]))
;; STROKE PANEL
:stroke
(let [shapes (filter has-stroke? shapes)]
(when (seq shapes)
[:> style-box* {:panel :stroke
:shorthand (:stroke shorthands)}
[:> stroke-panel* {:color-space color-space
:shapes shapes
:objects objects
:resolved-tokens resolved-active-tokens
:on-stroke-shorthand set-shorthands}]]))
;; VISIBILITY PANEL
:visibility
(let [shapes (filter has-visibility-props? shapes)]
(when (seq shapes)
[:> style-box* {:panel :visibility}
[:> visibility-panel* {:shapes shapes
:objects objects
:resolved-tokens resolved-active-tokens}]]))
;; SVG PANEL
:svg
(let [shape (first shapes)]
(when (seq (:svg-attrs shape))
[:> style-box* {:panel :svg}
[:> svg-panel* {:shape shape
:objects objects}]]))
;; BLUR PANEL
:blur
(let [shapes (->> shapes (filter has-blur?))]
(when (seq shapes)
[:> style-box* {:panel :blur}
[:> blur-panel* {:shapes shapes
;; VISIBILITY PANEL
:visibility
(let [shapes (filter has-visibility-props? shapes)]
(when (seq shapes)
[:> style-box* {:panel :visibility}
[:> visibility-panel* {:shapes shapes
:objects objects
:resolved-tokens resolved-active-tokens}]]))
;; SVG PANEL
:svg
(let [shape (first shapes)]
(when (seq (:svg-attrs shape))
[:> style-box* {:panel :svg}
[:> svg-panel* {:shape shape
:objects objects}]]))
;; TEXT PANEL
:text
(let [shapes (filter has-text? shapes)]
(when (seq shapes)
[:> style-box* {:panel :text
:shorthand (:text shorthands)}
[:> text-panel* {:shapes shapes
:color-space color-space
:resolved-tokens resolved-active-tokens
:on-font-shorthand set-shorthands}]]))
;; BLUR PANEL
:blur
(let [shapes (->> shapes (filter has-blur?))]
(when (seq shapes)
[:> style-box* {:panel :blur}
[:> blur-panel* {:shapes shapes
:objects objects}]]))
;; TEXT PANEL
:text
(let [shapes (filter has-text? shapes)]
(when (seq shapes)
[:> style-box* {:panel :text
:shorthand (:text shorthands)}
[:> text-panel* {:shapes shapes
:color-space color-space
: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
:shorthand (:shadow shorthands)}
[:> shadow-panel* {:shapes shapes
:resolved-tokens resolved-active-tokens
:color-space color-space
:on-shadow-shorthand set-shorthands}]]))
;; SHADOW PANEL
:shadow
(let [shapes (filter has-shadow? shapes)]
(when (seq shapes)
[:> style-box* {:panel :shadow
:shorthand (:shadow shorthands)}
[:> shadow-panel* {:shapes shapes
:resolved-tokens resolved-active-tokens
:color-space color-space
:on-shadow-shorthand set-shorthands}]]))
;; DEFAULT WIP
[:> style-box* {:panel panel}
[:div color-space]])])]))
;; DEFAULT WIP
[:> style-box* {:panel panel}
[:div color-space]])])]
[:div {:class (stl/css :exports-wrapper)}
[:& exports/exports
{:shapes shapes
:type type
:page-id page-id
:file-id file-id
:share-id share-id}]]]))

View File

@@ -13,3 +13,8 @@
.styles-tab-workspace {
block-size: calc(100vh - px2rem(180)); // TODO: Fix this hardcoded value
}
.exports-wrapper {
padding-block: var(--sp-s);
padding-inline: var(--sp-m);
}