From 4290bce718f2e95eaf56fc18917131b5cb594078 Mon Sep 17 00:00:00 2001 From: Xaviju Date: Wed, 27 Aug 2025 13:01:01 +0200 Subject: [PATCH] :tada: Inspect tab layout switcher and computed feature (#7166) --- common/src/app/common/flags.cljc | 3 +- .../app/main/ui/inspect/right_sidebar.cljs | 117 ++++++++++++++---- .../app/main/ui/inspect/right_sidebar.scss | 33 +++++ frontend/src/app/main/ui/inspect/styles.cljs | 61 +++++++++ .../app/main/ui/inspect/styles/style_box.cljs | 26 ++++ frontend/translations/en.po | 12 +- frontend/translations/es.po | 12 ++ 7 files changed, 234 insertions(+), 30 deletions(-) create mode 100644 frontend/src/app/main/ui/inspect/styles.cljs create mode 100644 frontend/src/app/main/ui/inspect/styles/style_box.cljs diff --git a/common/src/app/common/flags.cljc b/common/src/app/common/flags.cljc index 49a71cd04e..c395be0e41 100644 --- a/common/src/app/common/flags.cljc +++ b/common/src/app/common/flags.cljc @@ -131,7 +131,8 @@ :hide-release-modal :subscriptions :subscriptions-old - :frontend-binary-fills}) + :frontend-binary-fills + :inspect-styles}) (def all-flags (set/union email login varia)) diff --git a/frontend/src/app/main/ui/inspect/right_sidebar.cljs b/frontend/src/app/main/ui/inspect/right_sidebar.cljs index 649a532d6f..4c25d5c3cc 100644 --- a/frontend/src/app/main/ui/inspect/right_sidebar.cljs +++ b/frontend/src/app/main/ui/inspect/right_sidebar.cljs @@ -8,15 +8,18 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.types.component :as ctk] + [app.config :as cf] [app.main.data.event :as ev] [app.main.refs :as refs] [app.main.store :as st] + [app.main.ui.ds.controls.select :refer [select*]] [app.main.ui.ds.foundations.assets.icon :refer [icon*]] [app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]] [app.main.ui.icons :as i] [app.main.ui.inspect.attributes :refer [attributes]] [app.main.ui.inspect.code :refer [code]] [app.main.ui.inspect.selection-feedback :refer [resolve-shapes]] + [app.main.ui.inspect.styles :refer [styles-tab*]] [app.util.dom :as dom] [app.util.i18n :refer [tr]] [app.util.shape-icon :as usi] @@ -39,11 +42,13 @@ (mf/defc right-sidebar [{:keys [frame page objects file selected shapes page-id file-id share-id from on-change-section on-expand] :or {from :viewer}}] - (let [section (mf/use-state #(do :info)) + (let [color-space* (mf/use-state "hex") + color-space (deref color-space*) + + section (mf/use-state #(if (contains? cf/flags :inspect-styles) :styles :info)) objects (or objects (:objects page)) shapes (or shapes (resolve-shapes objects selected)) - first-shape (first shapes) page-id (or page-id (:id page)) file-id (or file-id (:id file)) @@ -82,20 +87,42 @@ (fn [] (dom/open-new-window "https://help.penpot.app/user-guide/inspect/"))) + handle-change-color-space + (mf/use-fn + (fn [color-space] + (reset! color-space* color-space))) + + color-spaces + (mf/with-memo [] + [{:label (tr "inspect.attributes.color.hex") + :id "hex"} + {:label (tr "inspect.attributes.color.rgba") + :id "rgba"} + {:label (tr "inspect.attributes.color.hsla") + :id "hsla"}]) + tabs (mf/with-memo [] - [{:label (tr "inspect.tabs.info") - :id "info"} - {:label (tr "inspect.tabs.code") - :data-testid "code" - :id "code"}])] + (if (contains? cf/flags :inspect-styles) + [{:label (tr "inspect.tabs.styles") + :id "styles"} + {:label (tr "inspect.tabs.computed") + :id "computed"} + {:label (tr "inspect.tabs.code") + :data-testid "code" + :id "code"}] + [{:label (tr "inspect.tabs.info") + :id "info"} + {:label (tr "inspect.tabs.code") + :data-testid "code" + :id "code"}]))] (mf/use-effect (mf/deps shapes handle-change-tab) (fn [] (if (seq shapes) (st/emit! (ptk/event ::ev/event {::ev/name "inspect-mode-click-element"})) - (handle-change-tab :info)))) + (handle-change-tab (if (contains? cf/flags :inspect-styles) :styles :info))))) [:aside {:class (stl/css-case :settings-bar-right true :viewer-code (= from :viewer))} @@ -133,27 +160,63 @@ [:div {:class (stl/css :layer-title)} (:name first-shape)]])]])] [:div {:class (stl/css :inspect-content)} + (if (contains? cf/flags :inspect-styles) + [:div {:class (stl/css :inspect-tab-switcher)} + [:span {:class (stl/css :inspect-tab-switcher-label)} (tr "inspect.tabs.switcher.label")] + [:div {:class (stl/css :inspect-tab-switcher-controls)} + [:div {:class (stl/css :inspect-tab-switcher-controls-color-space)} + [:> select* {:options color-spaces + :default-selected "hex" + :on-change handle-change-color-space}]] + [:div {:class (stl/css :inspect-tab-switcher-controls-tab)} + [:> select* {:options tabs + :default-selected (name @section) + :on-change handle-change-tab}]]]] + nil) - [:> tab-switcher* {:tabs tabs - :selected (name @section) - :on-change handle-change-tab - :class (stl/css :viewer-tab-switcher)} - (case @section - :info - [:& attributes {:page-id page-id - :objects objects - :file-id file-id - :frame frame - :shapes shapes - :from from - :libraries libraries - :share-id share-id}] + (if (contains? cf/flags :inspect-styles) + [:div {:class (stl/css :inspect-tab :viewer-tab-switcher :viewer-tab-switcher-layout)} + (case @section + :styles + [:> styles-tab* {:color-space color-space + :shapes shapes + :libraries libraries + :file-id file-id}] + :computed + [:& attributes {:page-id page-id + :objects objects + :file-id file-id + :frame frame + :shapes shapes + :from from + :libraries libraries + :share-id share-id}] - :code - [:& code {:frame frame - :shapes shapes - :on-expand handle-expand - :from from}])]]] + :code + [:& code {:frame frame + :shapes shapes + :on-expand handle-expand + :from from}])] + [:> tab-switcher* {:tabs tabs + :selected (name @section) + :on-change handle-change-tab + :class (stl/css :viewer-tab-switcher)} + (case @section + :info + [:& attributes {:page-id page-id + :objects objects + :file-id file-id + :frame frame + :shapes shapes + :from from + :libraries libraries + :share-id share-id}] + + :code + [:& code {:frame frame + :shapes shapes + :on-expand handle-expand + :from from}])])]] [:div {:class (stl/css :empty)} [:div {:class (stl/css :code-info)} [:span {:class (stl/css :placeholder-icon)} diff --git a/frontend/src/app/main/ui/inspect/right_sidebar.scss b/frontend/src/app/main/ui/inspect/right_sidebar.scss index ca3815ef96..a222bf7dd2 100644 --- a/frontend/src/app/main/ui/inspect/right_sidebar.scss +++ b/frontend/src/app/main/ui/inspect/right_sidebar.scss @@ -4,6 +4,7 @@ // // Copyright (c) KALEIDOS INC +@use "../ds/typography.scss" as *; @import "refactor/common-refactor.scss"; .settings-bar-right { @@ -106,6 +107,34 @@ padding: $s-8 $s-24; } +.inspect-tab-switcher { + display: flex; + justify-content: space-between; + align-items: center; + padding-block: var(--sp-s); + padding-inline-end: var(--sp-m); +} + +.inspect-tab-switcher-label { + @include use-typography("body-medium"); + flex: 1; +} + +.inspect-tab-switcher-controls { + display: flex; + align-items: center; + flex: 2; + gap: var(--sp-s); +} + +.inspect-tab-switcher-controls-color-space { + flex: 1; +} + +.inspect-tab-switcher-controls-tab { + flex: 2; +} + .inspect-content { flex: 1; overflow: hidden; @@ -115,3 +144,7 @@ --tabs-nav-padding-inline-start: 0; --tabs-nav-padding-inline-end: var(--sp-m); } + +.viewer-tab-switcher-layout { + display: grid; +} diff --git a/frontend/src/app/main/ui/inspect/styles.cljs b/frontend/src/app/main/ui/inspect/styles.cljs new file mode 100644 index 0000000000..2b9417f9b7 --- /dev/null +++ b/frontend/src/app/main/ui/inspect/styles.cljs @@ -0,0 +1,61 @@ +(ns app.main.ui.inspect.styles + (:require-macros [app.main.style :as stl]) + (:require + [app.common.data.macros :as dm] + [app.common.types.component :as ctc] + [app.common.types.components-list :as ctkl] + [app.main.ui.inspect.styles.style-box :refer [style-box*]] + [rumext.v2 :as mf])) + + +(def type->options + {:multiple [:fill :stroke :text :shadow :blur :layout-element] + :frame [:visibility :geometry :fill :stroke :shadow :blur :layout :layout-element] + :group [:visibility :geometry :svg :layout-element] + :rect [:visibility :geometry :fill :stroke :shadow :blur :svg :layout-element] + :circle [:visibility :geometry :fill :stroke :shadow :blur :svg :layout-element] + :path [:visibility :geometry :fill :stroke :shadow :blur :svg :layout-element] + :text [:visibility :geometry :text :shadow :blur :stroke :layout-element] + :variant [:variant :geometry :fill :stroke :shadow :blur :layout :layout-element]}) + +(defn- get-shape-type + [shapes first-shape first-component] + (cond + (and (= (count shapes) 1) + (or (ctc/is-variant-container? first-shape) + (ctc/is-variant? first-component))) + :variant + + (= (count shapes) 1) + (:type first-shape) + + :else + :multiple)) + +(mf/defc styles-tab* + [{:keys [color-space shapes libraries file-id]}] + (let [data (dm/get-in libraries [file-id :data]) + first-shape (first shapes) + first-component (ctkl/get-component data (:component-id first-shape)) + type (get-shape-type shapes first-shape first-component) + options (type->options type)] + + [:div {:class (stl/css :element-options)} + (for [[idx option] (map-indexed vector options)] + [:> style-box* {:key idx :attribute option} color-space])])) + + +;; WIP +;; Panel list as stylebox children +#_(case option + :geometry [:> geometry-panel {}] + :layout [:> layout-panel {}] + :layout-element [:> layout-element-panel {}] + :fill [:> fill-panel {:color-space color-space}] + :stroke [:> stroke-panel {:color-space color-space}] + :text [:> text-panel {:color-space color-space}] + :shadow [:> shadow-panel {}] + :blur [:> blur-panel {}] + :svg [:> svg-panel {}] + :variant [:> variant-panel* {}] + :visibility [:> visibility-panel* {}]) diff --git a/frontend/src/app/main/ui/inspect/styles/style_box.cljs b/frontend/src/app/main/ui/inspect/styles/style_box.cljs new file mode 100644 index 0000000000..8e0956bb81 --- /dev/null +++ b/frontend/src/app/main/ui/inspect/styles/style_box.cljs @@ -0,0 +1,26 @@ +(ns app.main.ui.inspect.styles.style-box + (:require-macros [app.main.style :as stl]) + (:require + [rumext.v2 :as mf])) + +(defn- attribute->title + [type] + (case type + :variant "Variant properties" + :token "Token Sets & Themes" + :geometry "Size & Position" + :fill "Fill" + :stroke "Stroke" + :text "Text" + :shadow "Shadow" + :layout "Layout" + :layout-element "Layout Element" + :visibility "Visibility" + :svg "SVG" + nil)) + +(mf/defc style-box* + [{:keys [attribute children]}] + [:div {:class (stl/css :style-box)} + [:h3 {:class (stl/css :style-box-header)} (attribute->title attribute)] + [:div {:class (stl/css :style-box-content)} children]]) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index bffb2269d1..4a626ebaec 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -1761,8 +1761,12 @@ msgid "inspect.subtitle.main" msgstr "Main component" #: src/app/main/ui/inspect/right_sidebar.cljs:59 -msgid "inspect.subtitle.variant" -msgstr "Variant" +msgid "inspect.tabs.switcher.label" +msgstr "Layer info" + +#: src/app/main/ui/inspect/right_sidebar.cljs:101 +msgid "inspect.tabs.computed" +msgstr "Computed" #: src/app/main/ui/inspect/right_sidebar.cljs:105 msgid "inspect.tabs.code" @@ -1820,6 +1824,10 @@ msgstr "Text" msgid "inspect.tabs.info" msgstr "Info" +#: src/app/main/ui/inspect/right_sidebar.cljs:101 +msgid "inspect.tabs.styles" +msgstr "Styles" + #: src/app/main/ui/dashboard/comments.cljs:95 msgid "label.mark-all-as-read" msgstr "Mark all as read" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index df51cb83cc..88f9f41f2d 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -1768,6 +1768,14 @@ msgstr "Componente principal" msgid "inspect.subtitle.variant" msgstr "Variante" +#: src/app/main/ui/inspect/right_sidebar.cljs:59 +msgid "inspect.tabs.switcher.label" +msgstr "Información sobre la capa" + +#: src/app/main/ui/inspect/right_sidebar.cljs:101 +msgid "inspect.tabs.computed" +msgstr "Calculado" + #: src/app/main/ui/inspect/right_sidebar.cljs:105 msgid "inspect.tabs.code" msgstr "Código" @@ -1824,6 +1832,10 @@ msgstr "Texto" msgid "inspect.tabs.info" msgstr "Información" +#: src/app/main/ui/inspect/right_sidebar.cljs:101 +msgid "inspect.tabs.styles" +msgstr "Estilos" + #: src/app/main/ui/dashboard/comments.cljs:95 msgid "label.mark-all-as-read" msgstr "Marcar todo como leído"