♻️ Copy shorthands using user selected color space (#7752)

* ♻️ Copy shorthands using user selected color space

* ♻️ Add tests to ensure color space changes affect all properties
This commit is contained in:
Xaviju 2025-11-18 10:54:10 +01:00 committed by GitHub
parent 04185b3544
commit 64b892f82d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 88 additions and 32 deletions

View File

@ -120,6 +120,16 @@ const openInspectTab = async (workspacePage) => {
await inspectButton.click(); 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.describe("Inspect tab - Styles", () => {
test("Open Inspect tab", async ({ page }) => { test("Open Inspect tab", async ({ page }) => {
const workspacePage = new WorkspacePage(page); const workspacePage = new WorkspacePage(page);
@ -383,6 +393,46 @@ test.describe("Inspect tab - Styles", () => {
expect(propertyRowCount).toBeGreaterThanOrEqual(1); 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 }) => { test("Shape - Fill - Gradient", async ({ page }) => {
const workspacePage = new WorkspacePage(page); const workspacePage = new WorkspacePage(page);
await setupFile(workspacePage); await setupFile(workspacePage);

View File

@ -122,7 +122,8 @@
(fn [] (fn []
(if (seq shapes) (if (seq shapes)
(st/emit! (ptk/event ::ev/event {::ev/name "inspect-mode-click-element"})) (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 [:aside {:class (stl/css-case :settings-bar-right true
:viewer-code (= from :viewer))} :viewer-code (= from :viewer))}
@ -166,12 +167,14 @@
[:div {:class (stl/css :inspect-tab-switcher-controls)} [:div {:class (stl/css :inspect-tab-switcher-controls)}
[:div {:class (stl/css :inspect-tab-switcher-controls-color-space)} [:div {:class (stl/css :inspect-tab-switcher-controls-color-space)}
[:> select* {:class (stl/css :inspect-tab-switcher-controls-color-space-select) [:> select* {:class (stl/css :inspect-tab-switcher-controls-color-space-select)
:aria-label (tr "inspect.tabs.switcher.color-space.label")
:options color-spaces :options color-spaces
:default-selected "hex" :default-selected "hex"
:variant "ghost" :variant "ghost"
:on-change handle-change-color-space}]] :on-change handle-change-color-space}]]
[:div {:class (stl/css :inspect-tab-switcher-controls-tab)} [:div {:class (stl/css :inspect-tab-switcher-controls-tab)}
[:> select* {:options tabs [:> select* {:options tabs
:aria-label (tr "inspect.tabs.switcher.inspect-tab.label")
:default-selected (name @section) :default-selected (name @section)
:on-change handle-change-tab}]]]] :on-change handle-change-tab}]]]]
nil) nil)

View File

@ -7,7 +7,6 @@
(ns app.main.ui.inspect.styles.panels.fill (ns app.main.ui.inspect.styles.panels.fill
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.data.macros :as dm]
[app.common.types.fills :as types.fills] [app.common.types.fills :as types.fills]
[app.config :as cfg] [app.config :as cfg]
[app.main.ui.inspect.attributes.common :as cmm] [app.main.ui.inspect.attributes.common :as cmm]
@ -36,20 +35,14 @@
(= 0 idx))) (= 0 idx)))
(defn- generate-fill-shorthand (defn- generate-fill-shorthand
[shape] [shape color-space]
(reduce (reduce
(fn [acc fill] (fn [acc fill]
(let [color-type (types.fills/fill->color fill) (let [color (types.fills/fill->color fill)
color-value (:color color-type) prefix (if (:color color) "background-color: " "background-image: ")
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 value (cond
(:color color-type) (dm/str color-value) (or (:color color) (:gradient color)) (uc/color->format->background color (keyword color-space))
color-gradient (uc/gradient->css gradient-data) (:image color) (str "url('" (cfg/resolve-file-media (:image color)) "')")
color-image (str "url(\"" (cfg/resolve-file-media color-image) "\")")
:else "") :else "")
full-value (str prefix value ";")] full-value (str prefix value ";")]
(if (empty? acc) (if (empty? acc)
@ -60,12 +53,12 @@
(mf/defc fill-panel* (mf/defc fill-panel*
[{:keys [shapes resolved-tokens color-space on-fill-shorthand]}] [{: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*)] shorthand (deref shorthand*)]
(mf/use-effect (mf/use-effect
(mf/deps shorthand on-fill-shorthand shapes) (mf/deps shorthand on-fill-shorthand shapes)
(fn [] (fn []
(reset! shorthand* (generate-fill-shorthand (first shapes))) (reset! shorthand* (generate-fill-shorthand (first shapes) color-space))
(on-fill-shorthand {:panel :fill (on-fill-shorthand {:panel :fill
:property shorthand}))) :property shorthand})))
[:div {:class (stl/css :fill-panel)} [:div {:class (stl/css :fill-panel)}

View File

@ -53,7 +53,7 @@
(is-first-element? idx))) (is-first-element? idx)))
(defn- generate-stroke-shorthand (defn- generate-stroke-shorthand
[shapes] [shapes color-space]
(when (= (count shapes) 1) (when (= (count shapes) 1)
(let [shape (first shapes)] (let [shape (first shapes)]
(reduce (reduce
@ -62,12 +62,13 @@
stroke-width (:stroke-width stroke) stroke-width (:stroke-width stroke)
stroke-style (:stroke-style stroke) stroke-style (:stroke-style stroke)
color-value (:color stroke-type) color-value (:color stroke-type)
formatted-color-value (uc/color->format->background stroke-type (keyword color-space))
color-gradient (:gradient stroke-type) color-gradient (:gradient stroke-type)
gradient-data {:type (get-in stroke-type [:gradient :type]) gradient-data {:type (get-in stroke-type [:gradient :type])
:stops (get-in stroke-type [:gradient :stops])} :stops (get-in stroke-type [:gradient :stops])}
color-image (:image stroke-type) color-image (:image stroke-type)
value (cond 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-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;") color-image (dm/str "border-image: url(" (cfg/resolve-file-media color-image) ") 100 / " stroke-width "px;")
:else "")] :else "")]
@ -79,12 +80,12 @@
(mf/defc stroke-panel* (mf/defc stroke-panel*
[{:keys [shapes objects resolved-tokens color-space on-stroke-shorthand]}] [{: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*)] shorthand (deref shorthand*)]
(mf/use-effect (mf/use-effect
(mf/deps shorthand on-stroke-shorthand shapes) (mf/deps shorthand on-stroke-shorthand shapes)
(fn [] (fn []
(reset! shorthand* (generate-stroke-shorthand shapes)) (reset! shorthand* (generate-stroke-shorthand shapes color-space))
(on-stroke-shorthand {:panel :stroke (on-stroke-shorthand {:panel :stroke
:property shorthand}))) :property shorthand})))
[:div {:class (stl/css :stroke-panel)} [:div {:class (stl/css :stroke-panel)}

View File

@ -6,6 +6,7 @@
(ns app.main.ui.inspect.styles.rows.color-properties-row (ns app.main.ui.inspect.styles.rows.color-properties-row
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.types.color :as cc] [app.common.types.color :as cc]
@ -51,15 +52,16 @@
formatted-color-value (mf/use-memo formatted-color-value (mf/use-memo
(mf/deps color format color-opacity) (mf/deps color format color-opacity)
#(cond #(cond
(some? (:color color)) (case format (some? (:color color))
"hex" (dm/str color-value " " color-opacity) (case format
"rgba" (let [[r g b a] (cc/hex->rgba color-value color-opacity) "hex" (dm/str color-value " " color-opacity)
result (cc/format-rgba [r g b a])] "rgba" (let [[r g b a] (cc/hex->rgba color-value color-opacity)
result) result (cc/format-rgba [r g b a])]
"hsla" (let [[h s l a] (cc/hex->hsla color-value color-opacity) result)
result (cc/format-hsla [h s l a])] "hsla" (let [[h s l a] (cc/hex->hsla color-value color-opacity)
result) result (cc/format-hsla [h s l a])]
color-value) result)
color-value)
(some? (:gradient color)) (uc/gradient-type->string (:type color-gradient)) (some? (:gradient color)) (uc/gradient-type->string (:type color-gradient))
(some? (:image color)) (tr "media.image") (some? (:image color)) (tr "media.image")
:else "none")) :else "none"))
@ -71,13 +73,11 @@
(str/replace #"^-" "")) (str/replace #"^-" ""))
copiable-value (mf/use-memo 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) #(if (some? token)
(:name token) (:name token)
(cond (cond
(:color color) (if (= format "hex") (:color color) (dm/str css-term ": " (uc/color->format->background color (keyword format)) ";")
(dm/str css-term ": " color-value "; opacity: " color-opacity ";")
(dm/str css-term ": " formatted-color-value ";"))
(:gradient color) (dm/str css-term ": " (uc/color->background color) ";") (: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;") (:image color) (dm/str css-term ": url(" color-image-url ") no-repeat center center / cover;")
:else "none"))) :else "none")))

View File

@ -64,6 +64,7 @@
[:span {:class (stl/css :panel-title)} title] [:span {:class (stl/css :panel-title)} title]
(when shorthand (when shorthand
[:> icon-button* {:variant "ghost" [:> icon-button* {:variant "ghost"
:tooltip-placement "top-left"
:aria-label (tr "inspect.tabs.styles.panel.copy-style-shorthand") :aria-label (tr "inspect.tabs.styles.panel.copy-style-shorthand")
:on-click copy-shorthand :on-click copy-shorthand
:icon i/clipboard}])] :icon i/clipboard}])]

View File

@ -1999,6 +1999,14 @@ msgstr "Resolved value:"
msgid "inspect.tabs.switcher.label" msgid "inspect.tabs.switcher.label"
msgstr "Layer info" 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 #: src/app/main/ui/dashboard/comments.cljs:96
msgid "label.mark-all-as-read" msgid "label.mark-all-as-read"
msgstr "Mark all as read" msgstr "Mark all as read"