diff --git a/frontend/playwright/ui/specs/inspect-tab.spec.js b/frontend/playwright/ui/specs/inspect-tab.spec.js index f458dc1ed3..bf8e160242 100644 --- a/frontend/playwright/ui/specs/inspect-tab.spec.js +++ b/frontend/playwright/ui/specs/inspect-tab.spec.js @@ -120,6 +120,16 @@ const openInspectTab = async (workspacePage) => { await inspectButton.click(); }; +const selectColorSpace = async (workspacePage, colorSpace) => { + const sidebar = workspacePage.page.getByTestId("right-sidebar"); + const colorSpaceSelector = sidebar.getByLabel("Select color space"); + await colorSpaceSelector.click(); + const colorSpaceOption = sidebar.getByRole("option", { + name: colorSpace, + }); + await colorSpaceOption.click(); +}; + test.describe("Inspect tab - Styles", () => { test("Open Inspect tab", async ({ page }) => { const workspacePage = new WorkspacePage(page); @@ -383,6 +393,46 @@ test.describe("Inspect tab - Styles", () => { expect(propertyRowCount).toBeGreaterThanOrEqual(1); }); + test("Change color space and ensure fill and shorthand changes", async ({ + page, + }) => { + const workspacePage = new WorkspacePage(page); + await setupFile(workspacePage); + + await selectLayer(workspacePage, shapeToLayerName.fill.solid); + await openInspectTab(workspacePage); + const panel = await getPanelByTitle(workspacePage, "Fill"); + await expect(panel).toBeVisible(); + + const propertyRow = panel.getByTestId("property-row"); + const backgroundRow = propertyRow.filter({ + hasText: "Background", + }); + await expect(backgroundRow).toBeVisible(); + + // Ensure initial value and copied value are in HEX format + expect(backgroundRow).toContainText("#0438d5 100%"); + + await copyPropertyFromPropertyRow(panel, "Background"); + + const backgroundHEX = await page.evaluate(() => + navigator.clipboard.readText(), + ); + expect(backgroundHEX).toContain("background: #0438d5FF;"); + + // Change color space to RGBA + await selectColorSpace(workspacePage, "rgba"); + + // Ensure new value and copied value are in RGBA format + expect(backgroundRow).toContainText("4, 56, 213, 1"); + + await copyPropertyFromPropertyRow(panel, "Background"); + const backgroundRGBA = await page.evaluate(() => + navigator.clipboard.readText(), + ); + expect(backgroundRGBA).toContain("background: rgba(4, 56, 213, 1);"); + }); + test("Shape - Fill - Gradient", async ({ page }) => { const workspacePage = new WorkspacePage(page); await setupFile(workspacePage); diff --git a/frontend/src/app/main/ui/inspect/right_sidebar.cljs b/frontend/src/app/main/ui/inspect/right_sidebar.cljs index 08ac1c5bd4..8ad37c1535 100644 --- a/frontend/src/app/main/ui/inspect/right_sidebar.cljs +++ b/frontend/src/app/main/ui/inspect/right_sidebar.cljs @@ -122,7 +122,8 @@ (fn [] (if (seq shapes) (st/emit! (ptk/event ::ev/event {::ev/name "inspect-mode-click-element"})) - (handle-change-tab (if (contains? cf/flags :inspect-styles) :styles :info))))) + (handle-change-tab (if (contains? cf/flags :inspect-styles) :styles :info))) + (reset! color-space* "hex"))) [:aside {:class (stl/css-case :settings-bar-right true :viewer-code (= from :viewer))} @@ -166,12 +167,14 @@ [:div {:class (stl/css :inspect-tab-switcher-controls)} [:div {:class (stl/css :inspect-tab-switcher-controls-color-space)} [:> select* {:class (stl/css :inspect-tab-switcher-controls-color-space-select) + :aria-label (tr "inspect.tabs.switcher.color-space.label") :options color-spaces :default-selected "hex" :variant "ghost" :on-change handle-change-color-space}]] [:div {:class (stl/css :inspect-tab-switcher-controls-tab)} [:> select* {:options tabs + :aria-label (tr "inspect.tabs.switcher.inspect-tab.label") :default-selected (name @section) :on-change handle-change-tab}]]]] nil) 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 9fa32e245e..3b1727920a 100644 --- a/frontend/src/app/main/ui/inspect/styles/panels/fill.cljs +++ b/frontend/src/app/main/ui/inspect/styles/panels/fill.cljs @@ -7,7 +7,6 @@ (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] @@ -36,20 +35,14 @@ (= 0 idx))) (defn- generate-fill-shorthand - [shape] + [shape color-space] (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: ") + (let [color (types.fills/fill->color fill) + prefix (if (:color color) "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) "\")") + (or (:color color) (:gradient color)) (uc/color->format->background color (keyword color-space)) + (:image color) (str "url('" (cfg/resolve-file-media (:image color)) "')") :else "") full-value (str prefix value ";")] (if (empty? acc) @@ -60,12 +53,12 @@ (mf/defc fill-panel* [{:keys [shapes resolved-tokens color-space on-fill-shorthand]}] - (let [shorthand* (mf/use-state #(generate-fill-shorthand (first shapes))) + (let [shorthand* (mf/use-state #(generate-fill-shorthand (first shapes) color-space)) shorthand (deref shorthand*)] (mf/use-effect (mf/deps shorthand on-fill-shorthand shapes) (fn [] - (reset! shorthand* (generate-fill-shorthand (first shapes))) + (reset! shorthand* (generate-fill-shorthand (first shapes) color-space)) (on-fill-shorthand {:panel :fill :property shorthand}))) [:div {:class (stl/css :fill-panel)} 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 18c6a9e72c..6e28190d5e 100644 --- a/frontend/src/app/main/ui/inspect/styles/panels/stroke.cljs +++ b/frontend/src/app/main/ui/inspect/styles/panels/stroke.cljs @@ -53,7 +53,7 @@ (is-first-element? idx))) (defn- generate-stroke-shorthand - [shapes] + [shapes color-space] (when (= (count shapes) 1) (let [shape (first shapes)] (reduce @@ -62,12 +62,13 @@ stroke-width (:stroke-width stroke) stroke-style (:stroke-style stroke) color-value (:color stroke-type) + formatted-color-value (uc/color->format->background stroke-type (keyword color-space)) 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-value (dm/str "border: " stroke-width "px " (d/name stroke-style) " " formatted-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 "")] @@ -79,12 +80,12 @@ (mf/defc stroke-panel* [{:keys [shapes objects resolved-tokens color-space on-stroke-shorthand]}] - (let [shorthand* (mf/use-state #(generate-stroke-shorthand shapes)) + (let [shorthand* (mf/use-state #(generate-stroke-shorthand shapes color-space)) shorthand (deref shorthand*)] (mf/use-effect (mf/deps shorthand on-stroke-shorthand shapes) (fn [] - (reset! shorthand* (generate-stroke-shorthand shapes)) + (reset! shorthand* (generate-stroke-shorthand shapes color-space)) (on-stroke-shorthand {:panel :stroke :property shorthand}))) [:div {:class (stl/css :stroke-panel)} 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 8d8c4833c5..3b8272c5e0 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 @@ -6,6 +6,7 @@ (ns app.main.ui.inspect.styles.rows.color-properties-row (:require-macros [app.main.style :as stl]) (:require + [app.common.data :as d] [app.common.data.macros :as dm] [app.common.types.color :as cc] @@ -51,15 +52,16 @@ formatted-color-value (mf/use-memo (mf/deps color format color-opacity) #(cond - (some? (:color color)) (case format - "hex" (dm/str color-value " " color-opacity) - "rgba" (let [[r g b a] (cc/hex->rgba color-value color-opacity) - result (cc/format-rgba [r g b a])] - result) - "hsla" (let [[h s l a] (cc/hex->hsla color-value color-opacity) - result (cc/format-hsla [h s l a])] - result) - color-value) + (some? (:color color)) + (case format + "hex" (dm/str color-value " " color-opacity) + "rgba" (let [[r g b a] (cc/hex->rgba color-value color-opacity) + result (cc/format-rgba [r g b a])] + result) + "hsla" (let [[h s l a] (cc/hex->hsla color-value color-opacity) + result (cc/format-hsla [h s l a])] + result) + color-value) (some? (:gradient color)) (uc/gradient-type->string (:type color-gradient)) (some? (:image color)) (tr "media.image") :else "none")) @@ -71,13 +73,11 @@ (str/replace #"^-" "")) copiable-value (mf/use-memo - (mf/deps color formatted-color-value color-opacity color-image-url token) + (mf/deps color token format color-opacity) #(if (some? token) (:name token) (cond - (:color color) (if (= format "hex") - (dm/str css-term ": " color-value "; opacity: " color-opacity ";") - (dm/str css-term ": " formatted-color-value ";")) + (:color color) (dm/str css-term ": " (uc/color->format->background color (keyword format)) ";") (:gradient color) (dm/str css-term ": " (uc/color->background color) ";") (:image color) (dm/str css-term ": url(" color-image-url ") no-repeat center center / cover;") :else "none"))) 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 6251d647ea..30d2513b7b 100644 --- a/frontend/src/app/main/ui/inspect/styles/style_box.cljs +++ b/frontend/src/app/main/ui/inspect/styles/style_box.cljs @@ -64,6 +64,7 @@ [:span {:class (stl/css :panel-title)} title] (when shorthand [:> icon-button* {:variant "ghost" + :tooltip-placement "top-left" :aria-label (tr "inspect.tabs.styles.panel.copy-style-shorthand") :on-click copy-shorthand :icon i/clipboard}])] diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 6b41a73f31..ed9a4afb14 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -1999,6 +1999,14 @@ msgstr "Resolved value:" msgid "inspect.tabs.switcher.label" msgstr "Layer info" +#: src/app/main/ui/inspect/right_sidebar.cljs:165 +msgid "inspect.tabs.switcher.color-space.label" +msgstr "Select color space" + +#: src/app/main/ui/inspect/right_sidebar.cljs:165 +msgid "inspect.tabs.switcher.inspect-tab.label" +msgstr "Select inspect tab" + #: src/app/main/ui/dashboard/comments.cljs:96 msgid "label.mark-all-as-read" msgstr "Mark all as read"