diff --git a/frontend/playwright/data/workspace/get-file-inspect-tab.json b/frontend/playwright/data/workspace/get-file-inspect-tab.json index f696bc4135..765631ae8a 100644 --- a/frontend/playwright/data/workspace/get-file-inspect-tab.json +++ b/frontend/playwright/data/workspace/get-file-inspect-tab.json @@ -25,8 +25,8 @@ "~:has-media-trimmed": false, "~:comment-thread-seqn": 0, "~:name": "Fitxer nou 4 (còpia)", - "~:revn": 161, - "~:modified-at": "~m1762259088973", + "~:revn": 169, + "~:modified-at": "~m1762429557622", "~:vern": 0, "~:id": "~u7b2da435-6186-815a-8007-0daa95d2f26d", "~:is-shared": false, @@ -314,7 +314,7 @@ }, "~u5403f14e-eb02-80be-8007-048a9fb2671a": { "~#shape": { - "~:y": 702, + "~:y": 1038, "~:transform": { "~#matrix": { "~:a": 1.0, @@ -381,10 +381,10 @@ "~:width": 37, "~:type": "~:text", "~:points": [ - { "~#point": { "~:x": 770, "~:y": 702 } }, - { "~#point": { "~:x": 807, "~:y": 702 } }, - { "~#point": { "~:x": 807, "~:y": 724 } }, - { "~#point": { "~:x": 770, "~:y": 724 } } + { "~#point": { "~:x": 1327, "~:y": 1038 } }, + { "~#point": { "~:x": 1364, "~:y": 1038 } }, + { "~#point": { "~:x": 1364, "~:y": 1060 } }, + { "~#point": { "~:x": 1327, "~:y": 1060 } } ], "~:transform-inverse": { "~#matrix": { @@ -402,7 +402,7 @@ "~:position-data": [ { "~#rect": { - "~:y": 723.3000030517578, + "~:y": 1059.3000030517578, "~:font-style": "normal", "~:text-transform": "none", "~:font-size": "18px", @@ -411,7 +411,7 @@ "~:width": 36.366668701171875, "~:text-decoration": "none", "~:letter-spacing": "normal", - "~:x": 770, + "~:x": 1327, "~:x1": 0, "~:y2": 21.300003051757812, "~:fills": [ @@ -427,17 +427,17 @@ ], "~:frame-id": "~u5403f14e-eb02-80be-8007-0487afa26386", "~:strokes": [], - "~:x": 770, + "~:x": 1327, "~:selrect": { "~#rect": { - "~:x": 770, - "~:y": 702, + "~:x": 1327, + "~:y": 1038, "~:width": 37, "~:height": 22, - "~:x1": 770, - "~:y1": 702, - "~:x2": 807, - "~:y2": 724 + "~:x1": 1327, + "~:y1": 1038, + "~:x2": 1364, + "~:y2": 1060 } }, "~:fills": [], @@ -1259,6 +1259,83 @@ "~:flip-y": null } }, + "~u63c623e4-0e89-80ce-8007-1168f74c90c0": { + "~#shape": { + "~:y": 717, + "~:transform": { + "~#matrix": { + "~:a": 1.0, + "~:b": 0.0, + "~:c": 0.0, + "~:d": 1.0, + "~:e": 0.0, + "~:f": 0.0 + } + }, + "~:rotation": 0, + "~:grow-type": "~:fixed", + "~:hide-in-viewer": false, + "~:name": "shape - shadow - composite", + "~:width": 221, + "~:type": "~:rect", + "~:points": [ + { "~#point": { "~:x": 695, "~:y": 717 } }, + { "~#point": { "~:x": 916, "~:y": 717 } }, + { "~#point": { "~:x": 916, "~:y": 866 } }, + { "~#point": { "~:x": 695, "~:y": 866 } } + ], + "~:r2": 0, + "~:proportion-lock": false, + "~:transform-inverse": { + "~#matrix": { + "~:a": 1.0, + "~:b": 0.0, + "~:c": 0.0, + "~:d": 1.0, + "~:e": 0.0, + "~:f": 0.0 + } + }, + "~:r3": 0, + "~:r1": 0, + "~:id": "~u63c623e4-0e89-80ce-8007-1168f74c90c0", + "~:parent-id": "~u5403f14e-eb02-80be-8007-0487afa26386", + "~:applied-tokens": { "~:shadow": "shadowToken" }, + "~:frame-id": "~u5403f14e-eb02-80be-8007-0487afa26386", + "~:strokes": [], + "~:x": 695, + "~:proportion": 1, + "~:shadow": [ + { + "~:id": "~u5d50013d-dbc4-4ee8-b35a-3eb331840bf1", + "~:hidden": false, + "~:offset-x": 10, + "~:offset-y": 10, + "~:blur": 4, + "~:color": { "~:color": "#a04949", "~:opacity": 1 }, + "~:spread": 10, + "~:style": "~:inner-shadow" + } + ], + "~:r4": 0, + "~:selrect": { + "~#rect": { + "~:x": 695, + "~:y": 717, + "~:width": 221, + "~:height": 149, + "~:x1": 695, + "~:y1": 717, + "~:x2": 916, + "~:y2": 866 + } + }, + "~:fills": [{ "~:fill-color": "#B1B2B5", "~:fill-opacity": 1 }], + "~:flip-x": null, + "~:height": 149, + "~:flip-y": null + } + }, "~u6ce76eb4-b183-804e-8007-04b4a3dbb14c": { "~#shape": { "~:y": 1751, @@ -3443,6 +3520,140 @@ "~:flip-y": null } }, + "~u63c623e4-0e89-80ce-8007-1168fbe0e852": { + "~#shape": { + "~:y": 692, + "~:transform": { + "~#matrix": { + "~:a": 1.0, + "~:b": 0.0, + "~:c": 0.0, + "~:d": 1.0, + "~:e": 0.0, + "~:f": 0.0 + } + }, + "~:rotation": 0, + "~:grow-type": "~:auto-width", + "~:content": { + "~:type": "root", + "~:children": [ + { + "~:type": "paragraph-set", + "~:children": [ + { + "~:line-height": "1.2", + "~:font-style": "normal", + "~:children": [ + { + "~:line-height": "1.2", + "~:font-style": "normal", + "~:text-transform": "none", + "~:text-align": "left", + "~:font-id": "gfont-albert-sans", + "~:font-size": "18", + "~:font-weight": "400", + "~:text-direction": "ltr", + "~:font-variant-id": "regular", + "~:text-decoration": "none", + "~:letter-spacing": "0", + "~:fills": [ + { "~:fill-color": "#000000", "~:fill-opacity": 1 } + ], + "~:font-family": "Albert Sans", + "~:text": "composite" + } + ], + "~:text-transform": "none", + "~:text-align": "left", + "~:font-id": "gfont-albert-sans", + "~:key": "1tgq4", + "~:font-size": "18", + "~:font-weight": "400", + "~:text-direction": "ltr", + "~:type": "paragraph", + "~:font-variant-id": "regular", + "~:text-decoration": "none", + "~:letter-spacing": "0", + "~:fills": [ + { "~:fill-color": "#000000", "~:fill-opacity": 1 } + ], + "~:font-family": "Albert Sans" + } + ] + } + ] + }, + "~:hide-in-viewer": false, + "~:name": "composite", + "~:width": 88, + "~:type": "~:text", + "~:points": [ + { "~#point": { "~:x": 695, "~:y": 692 } }, + { "~#point": { "~:x": 783, "~:y": 692 } }, + { "~#point": { "~:x": 783, "~:y": 714 } }, + { "~#point": { "~:x": 695, "~:y": 714 } } + ], + "~:transform-inverse": { + "~#matrix": { + "~:a": 1.0, + "~:b": 0.0, + "~:c": 0.0, + "~:d": 1.0, + "~:e": 0.0, + "~:f": 0.0 + } + }, + "~:id": "~u63c623e4-0e89-80ce-8007-1168fbe0e852", + "~:parent-id": "~u5403f14e-eb02-80be-8007-0487afa26386", + "~:applied-tokens": { "~:typography": "body" }, + "~:position-data": [ + { + "~#rect": { + "~:y": 713.3000030517578, + "~:font-style": "normal", + "~:text-transform": "none", + "~:font-size": "18px", + "~:font-weight": "400", + "~:y1": 0.3000030517578125, + "~:width": 87.94999694824219, + "~:text-decoration": "none", + "~:letter-spacing": "normal", + "~:x": 695, + "~:x1": 0, + "~:y2": 21.300003051757812, + "~:fills": [ + { "~:fill-color": "#000000", "~:fill-opacity": 1 } + ], + "~:x2": 87.94999694824219, + "~:direction": "ltr", + "~:font-family": "\"Albert Sans\"", + "~:height": 21, + "~:text": "composite" + } + } + ], + "~:frame-id": "~u5403f14e-eb02-80be-8007-0487afa26386", + "~:strokes": [], + "~:x": 695, + "~:selrect": { + "~#rect": { + "~:x": 695, + "~:y": 692, + "~:width": 88, + "~:height": 22, + "~:x1": 695, + "~:y1": 692, + "~:x2": 783, + "~:y2": 714 + } + }, + "~:fills": [], + "~:flip-x": null, + "~:height": 22, + "~:flip-y": null + } + }, "~u6ce76eb4-b183-804e-8007-04b05cc6d7db": { "~#shape": { "~:y": 924, @@ -3658,6 +3869,7 @@ "~u6ce76eb4-b183-804e-8007-04b07bc58c4a", "~u6ce76eb4-b183-804e-8007-04b258ecdfff", "~u6ce76eb4-b183-804e-8007-04b261218dbe", + "~u63c623e4-0e89-80ce-8007-1168fbe0e852", "~u6ce76eb4-b183-804e-8007-04b14cc0b236", "~u6ce76eb4-b183-804e-8007-04b1541dd680", "~u6ce76eb4-b183-804e-8007-04b15b636f6a", @@ -3665,6 +3877,7 @@ "~u5403f14e-eb02-80be-8007-0487bbc6ea5e", "~u5403f14e-eb02-80be-8007-048a7f80ca80", "~u6ce76eb4-b183-804e-8007-04b25da1d244", + "~u63c623e4-0e89-80ce-8007-1168f74c90c0", "~u5403f14e-eb02-80be-8007-048a99988f3d", "~u6ce76eb4-b183-804e-8007-04b035b88460", "~u6ce76eb4-b183-804e-8007-04b69f6ca2af", @@ -3691,7 +3904,7 @@ }, "~u5403f14e-eb02-80be-8007-048a9fb22a88": { "~#shape": { - "~:y": 733, + "~:y": 1069, "~:transform": { "~#matrix": { "~:a": 1.0, @@ -3709,10 +3922,10 @@ "~:width": 221, "~:type": "~:rect", "~:points": [ - { "~#point": { "~:x": 770, "~:y": 733 } }, - { "~#point": { "~:x": 991, "~:y": 733 } }, - { "~#point": { "~:x": 991, "~:y": 882 } }, - { "~#point": { "~:x": 770, "~:y": 882 } } + { "~#point": { "~:x": 1327, "~:y": 1069 } }, + { "~#point": { "~:x": 1548, "~:y": 1069 } }, + { "~#point": { "~:x": 1548, "~:y": 1218 } }, + { "~#point": { "~:x": 1327, "~:y": 1218 } } ], "~:r2": 0, "~:proportion-lock": false, @@ -3738,20 +3951,20 @@ "~:parent-id": "~u5403f14e-eb02-80be-8007-0487afa26386", "~:frame-id": "~u5403f14e-eb02-80be-8007-0487afa26386", "~:strokes": [], - "~:x": 770, + "~:x": 1327, "~:proportion": 1, "~:shadow": [], "~:r4": 0, "~:selrect": { "~#rect": { - "~:x": 770, - "~:y": 733, + "~:x": 1327, + "~:y": 1069, "~:width": 221, "~:height": 149, - "~:x1": 770, - "~:y1": 733, - "~:x2": 991, - "~:y2": 882 + "~:x1": 1327, + "~:y1": 1069, + "~:x2": 1548, + "~:y2": 1218 } }, "~:fills": [{ "~:fill-color": "#B1B2B5", "~:fill-opacity": 1 }], @@ -5569,7 +5782,7 @@ "~:id": "~u5403f14e-eb02-80be-8007-0494f09cefca", "~:name": "Global", "~:description": "", - "~:modified-at": "~m1761570802864", + "~:modified-at": "~m1762429549085", "~:tokens": { "~#ordered-map": [ [ @@ -5720,6 +5933,28 @@ "~:modified-at": "~m1761570799828" } } + ], + [ + "shadowToken", + { + "~#penpot/token": { + "~:id": "~u63c623e4-0e89-80ce-8007-1168ea143ca8", + "~:name": "shadowToken", + "~:type": "~:shadow", + "~:value": [ + { + "~:blur": "4", + "~:spread": "10", + "~:color": "rgb(160, 73, 73)", + "~:inset": true, + "~:offsetX": "10", + "~:offsetY": "10" + } + ], + "~:description": "", + "~:modified-at": "~m1762429549085" + } + } ] ] } diff --git a/frontend/playwright/ui/specs/inspect-tab.spec.js b/frontend/playwright/ui/specs/inspect-tab.spec.js index e2035bd637..f458dc1ed3 100644 --- a/frontend/playwright/ui/specs/inspect-tab.spec.js +++ b/frontend/playwright/ui/specs/inspect-tab.spec.js @@ -27,6 +27,7 @@ const shapeToLayerName = { gridElement: "shape - layout - grid - element", shadow: "shape - shadow - single", shadowMultiple: "shape - shadow - multiple", + shadowComposite: "shape - shadow - composite", blur: "shape - blur", borderRadius: { main: "shape - borderRadius", @@ -219,6 +220,31 @@ test.describe("Inspect tab - Styles", () => { expect(propertyRowCount).toBeGreaterThanOrEqual(4); }); + + test("Shape Shadow - Composite shadow", async ({ page }) => { + const workspacePage = new WorkspacePage(page); + await setupFile(workspacePage); + + await selectLayer(workspacePage, shapeToLayerName.shadowComposite); + await openInspectTab(workspacePage); + + const panel = await getPanelByTitle(workspacePage, "Shadow"); + await expect(panel).toBeVisible(); + + const propertyRow = panel.getByTestId("property-row"); + const propertyRowCount = await propertyRow.count(); + + expect(propertyRowCount).toBeGreaterThanOrEqual(3); + + const compositeShadowRow = propertyRow.first(); + await expect(compositeShadowRow).toBeVisible(); + + const compositeShadowTerm = compositeShadowRow.locator("dt"); + const compositeShadowDefinition = compositeShadowRow.locator("dd"); + + expect(compositeShadowTerm).toHaveText("Shadow", { exact: true }); + expect(compositeShadowDefinition).toContainText("shadowToken"); + }); }); test("Shape - Blur", async ({ page }) => { diff --git a/frontend/src/app/main/ui/inspect/styles.cljs b/frontend/src/app/main/ui/inspect/styles.cljs index 510c54bb80..b9f0092bd8 100644 --- a/frontend/src/app/main/ui/inspect/styles.cljs +++ b/frontend/src/app/main/ui/inspect/styles.cljs @@ -250,6 +250,7 @@ [:> 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}]])) diff --git a/frontend/src/app/main/ui/inspect/styles/panels/shadow.cljs b/frontend/src/app/main/ui/inspect/styles/panels/shadow.cljs index c062e68131..12113aa1b1 100644 --- a/frontend/src/app/main/ui/inspect/styles/panels/shadow.cljs +++ b/frontend/src/app/main/ui/inspect/styles/panels/shadow.cljs @@ -15,6 +15,17 @@ [app.util.code-gen.style-css-formats :as scf] [rumext.v2 :as mf])) +(defn- get-applied-tokens-in-shape + [shape-tokens property] + (get shape-tokens property)) + +(defn- get-resolved-token + [property shape resolved-tokens] + (let [shape-tokens (:applied-tokens shape) + applied-tokens-in-shape (get-applied-tokens-in-shape shape-tokens property) + token (get resolved-tokens applied-tokens-in-shape)] + token)) + (defn- generate-shadow-shorthand [shapes] (when (= (count shapes) 1) @@ -30,7 +41,7 @@ (dm/str shorthand-property shorthand-value ";")))) (mf/defc shadow-panel* - [{:keys [shapes color-space on-shadow-shorthand]}] + [{:keys [shapes resolved-tokens color-space on-shadow-shorthand]}] (let [shorthand* (mf/use-state #(generate-shadow-shorthand shapes)) shorthand (deref shorthand*)] (mf/use-effect @@ -41,16 +52,25 @@ :property shorthand}))) [:div {:class (stl/css :shadow-panel)} (for [shape shapes] - (for [[idx shadow] (map-indexed vector (:shadow shape))] - [:div {:key (dm/str idx) :class (stl/css :shadow-shape)} - [:> color-properties-row* {:term "Shadow Color" - :color (:color shadow) - :format color-space - :copiable true}] - (let [value (dm/str (:offset-x shadow) "px" " " (:offset-y shadow) "px" " " (:blur shadow) "px" " " (:spread shadow) "px") - property-name (cmm/get-css-rule-humanized (:style shadow)) - property-value (css/shadow->css shadow)] - [:> properties-row* {:term property-name - :detail (dm/str value) - :property property-value - :copiable true}])]))])) + (let [composite-shadow-token (get-resolved-token :shadow shape resolved-tokens)] + (for [[idx shadow] (map-indexed vector (:shadow shape))] + [:div {:key (dm/str idx) :class (stl/css :shadow-shape)} + (when composite-shadow-token + [:> properties-row* {:term "Shadow" + :detail (:name composite-shadow-token) + :token composite-shadow-token + :property (:name composite-shadow-token) + :copiable true}]) + [:> color-properties-row* {:term "Shadow Color" + :color (:color shadow) + :format color-space + :copiable true}] + + (let [value (dm/str (:offset-x shadow) "px" " " (:offset-y shadow) "px" " " (:blur shadow) "px" " " (:spread shadow) "px") + property-name (cmm/get-css-rule-humanized (:style shadow)) + property-value (css/shadow->css shadow)] + + [:> properties-row* {:term property-name + :detail (dm/str value) + :property property-value + :copiable true}])])))])) diff --git a/frontend/src/app/main/ui/inspect/styles/panels/text.cljs b/frontend/src/app/main/ui/inspect/styles/panels/text.cljs index 21e28b82be..25508e5f16 100644 --- a/frontend/src/app/main/ui/inspect/styles/panels/text.cljs +++ b/frontend/src/app/main/ui/inspect/styles/panels/text.cljs @@ -62,7 +62,7 @@ property-value (:name typography)] (when typography [:> properties-row* {:term "Typography" - :detail (:name typography) + :detail property-value :property property-value :copiable true}]))) diff --git a/frontend/src/app/main/ui/inspect/styles/rows/properties_row.cljs b/frontend/src/app/main/ui/inspect/styles/rows/properties_row.cljs index abac5c7eee..1ffc5a0b88 100644 --- a/frontend/src/app/main/ui/inspect/styles/rows/properties_row.cljs +++ b/frontend/src/app/main/ui/inspect/styles/rows/properties_row.cljs @@ -51,19 +51,31 @@ [:dd {:class (stl/css :property-detail)} (if copiable? (if token - [:> tooltip* {:id (:name token) - :class (stl/css :tooltip-token-wrapper) - :content #(mf/html - [:div {:class (stl/css :tooltip-token)} - [:div {:class (stl/css :tooltip-token-title)} (tr "inspect.tabs.styles.token.resolved-value")] - [:div {:class (stl/css :tooltip-token-value)} (if (= :typography (:type token)) - [:ul {:class (stl/css :tooltip-token-resolved-values)} - (for [[property value] (:resolved-value token)] - [:li {:key property} (str (category-dictionary property) ": " (format-token-value value))])] - (:resolved-value token))]])} - [:> property-detail-copiable* {:token token - :copied copied - :on-click copy-attr} detail]] + (let [token-type (:type token)] + [:> tooltip* {:id (:name token) + :class (stl/css :tooltip-token-wrapper) + :content #(mf/html + [:div {:class (stl/css :tooltip-token)} + [:div {:class (stl/css :tooltip-token-title)} + (tr "inspect.tabs.styles.token.resolved-value")] + [:div {:class (stl/css :tooltip-token-value)} + (cond + (= :typography token-type) + [:ul {:class (stl/css :tooltip-token-resolved-values)} + (for [[property value] (:resolved-value token)] + [:li {:key property} + (str (category-dictionary property) ": " (format-token-value value))])] + (= :shadow token-type) + [:ul {:class (stl/css :tooltip-token-resolved-values)} + (for [property (:resolved-value token) + [key value] property] + [:li {:key key} + (str (category-dictionary key) ": " (format-token-value value))])] + :else + (:resolved-value token))]])} + [:> property-detail-copiable* {:token token + :copied copied + :on-click copy-attr} detail]]) [:> property-detail-copiable* {:copied copied :on-click copy-attr} detail]) detail)]]))