mirror of https://github.com/penpot/penpot.git
♻️ 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:
parent
04185b3544
commit
64b892f82d
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)}
|
||||
|
|
|
|||
|
|
@ -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)}
|
||||
|
|
|
|||
|
|
@ -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")))
|
||||
|
|
|
|||
|
|
@ -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}])]
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in New Issue