diff --git a/frontend/playwright/ui/visual-specs/workspace.spec.js b/frontend/playwright/ui/visual-specs/workspace.spec.js index a9a4ef2bf3..5893ae0d80 100644 --- a/frontend/playwright/ui/visual-specs/workspace.spec.js +++ b/frontend/playwright/ui/visual-specs/workspace.spec.js @@ -599,6 +599,68 @@ test.describe("Layers panel", () => { }); }); +test.describe("Layers", () => { + test("Shows the buttons of the layer rows", async ({ page }) => { + const workspace = new WorkspacePage(page); + await workspace.setupEmptyFile(); + await workspace.mockRPC(/get\-file\?/, "workspace/get-file-9066.json"); + await workspace.mockRPC( + "update-file?id=*", + "workspace/update-file-empty.json", + ); + await workspace.goToWorkspace({ + fileId: "e179d9df-de35-80bf-8005-283bbd5516b0", + pageId: "e179d9df-de35-80bf-8005-283bbd5516b1", + }); + + await workspace.clickToggableLayer("Board"); + await workspace.clickToggableLayer("Group"); + const layer = workspace.layers.getByText("A", { exact: true }); + await layer.click(); + await layer.hover(); + await workspace.layers.getByRole("button", { name: "Hide" }).click(); + await workspace.layers.getByRole("button", { name: "Lock" }).click(); + await expect( + workspace.layers.getByRole("button", { name: "Show" }), + ).toBeVisible(); + await expect( + workspace.layers.getByRole("button", { name: "Unlock" }), + ).toBeVisible(); + + // Selected, hidden and blocked layer, with the pointer on its row. + await expect(workspace.layers).toHaveScreenshot({ + maxDiffPixelRatio: 0, + threshold: 0, + }); + + // The pointer on a collapsed group, away from the selected layer. + await workspace.layers.getByText("Board", { exact: true }).hover(); + await expect(workspace.layers).toHaveScreenshot({ + maxDiffPixelRatio: 0, + threshold: 0, + }); + }); + + test("Shows the rename input of a layer", async ({ page }) => { + const workspace = new WorkspacePage(page); + await workspace.setupEmptyFile(); + await workspace.mockRPC(/get\-file\?/, "workspace/get-file-9066.json"); + await workspace.goToWorkspace({ + fileId: "e179d9df-de35-80bf-8005-283bbd5516b0", + pageId: "e179d9df-de35-80bf-8005-283bbd5516b1", + }); + + await workspace.layers.getByText("Board", { exact: true }).dblclick(); + const input = workspace.layers.getByRole("textbox"); + await expect(input).toBeVisible(); + await page.mouse.move(0, 0); + await expect(workspace.layers).toHaveScreenshot({ + maxDiffPixelRatio: 0, + threshold: 0, + }); + }); +}); + test.describe("Guides", () => { test("Shows the advanced options of a square guide", async ({ page }) => { // A taller window keeps the whole Design tab visible: a scrolled diff --git a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs index 5733b8c3ce..6438e63914 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs @@ -21,9 +21,8 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.context :as ctx] - [app.main.ui.ds.foundations.assets.icon :refer [icon*]] + [app.main.ui.ds.foundations.assets.icon :as i :refer [icon*]] [app.main.ui.hooks :as hooks] - [app.main.ui.icons :as deprecated-icon] [app.main.ui.workspace.sidebar.layer-name :refer [layer-name*]] [app.util.dom :as dom] [app.util.i18n :refer [tr]] @@ -138,7 +137,9 @@ :data-testid "toggle-content" :aria-expanded is-expanded :on-click on-toggle-collapse} - deprecated-icon/arrow]) + [:> icon* {:icon-id i/arrow + :size "s" + :class (stl/css :toggle-content-icon)}]]) [:div {:class (stl/css :icon-shape) :on-double-click on-zoom-to-selected} @@ -189,7 +190,9 @@ (tr "workspace.shape.menu.show") (tr "workspace.shape.menu.hide")) :on-click on-toggle-visibility} - (if ^boolean hidden? deprecated-icon/hide deprecated-icon/shown)] + [:> icon* {:icon-id (if ^boolean hidden? i/hide i/shown) + :size "s" + :class (stl/css :element-action-icon)}]] [:button {:class (stl/css-case :block-element true :selected blocked?) @@ -197,7 +200,9 @@ (tr "workspace.shape.menu.unlock") (tr "workspace.shape.menu.lock")) :on-click on-toggle-blocking} - (if ^boolean blocked? deprecated-icon/lock deprecated-icon/unlock)]])] + [:> icon* {:icon-id (if ^boolean blocked? i/lock i/unlock) + :size "s" + :class (stl/css :element-action-icon)}]]])] children])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/layer_item.scss b/frontend/src/app/main/ui/workspace/sidebar/layer_item.scss index 445b8e5bc9..d7cbad6289 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layer_item.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/layer_item.scss @@ -27,9 +27,9 @@ &:hover { --layer-background-color: var(--color-background-secondary); --shadow-color: var(--color-background-secondary); - --context-hover-color: var(--layer-row-foreground-color-hover); + --context-hover-color: var(--color-accent-primary); --context-hover-opacity: 1; - --layer-foreground-color: var(--layer-row-foreground-color-hover); + --layer-foreground-color: var(--color-accent-primary); &.hidden { opacity: 1; @@ -200,43 +200,40 @@ align-items: center; block-size: 100%; inline-size: $sz-24; - padding-inline-start: var(--sp-s); - svg { - display: flex; - justify-content: center; - align-items: center; - color: transparent; - fill: none; - block-size: $sz-12; - inline-size: $sz-12; - stroke-width: 1.33px; - stroke: var(--color-foreground-secondary); - - .layer-row.hidden & { - opacity: 0.7; - } - - .layer-row.selected & { - stroke: var(--color-accent-primary); - } - - .layer-row.type-comp & { - stroke: var(--color-accent-secondary); - } - - .layer-row.highlight &, - .layer-row:hover & { - opacity: 1; - stroke: var(--color-accent-primary); - } - } + // The DS icon draws 12px inside a 16px box: 2px less start padding + // keeps the arrow where the old 12px icon was. + padding-inline-start: px2rem(6); .layer-row.selected & { background-color: var(--color-background-quaternary); } +} - &.inverse svg { +.toggle-content-icon { + // Same stroke weight as the old 12px icons. + stroke-width: 1.33px; + color: var(--color-foreground-secondary); + + .layer-row.hidden & { + opacity: 0.7; + } + + .layer-row.selected & { + color: var(--color-accent-primary); + } + + .layer-row.type-comp & { + color: var(--color-accent-secondary); + } + + .layer-row.highlight &, + .layer-row:hover & { + opacity: 1; + color: var(--color-accent-primary); + } + + .toggle-content.inverse & { transform: rotate(90deg); } } @@ -256,26 +253,6 @@ background: var(--layer-row-action-btn-background); padding-inline-end: px2rem(6); - svg { - display: flex; - justify-content: center; - align-items: center; - color: transparent; - fill: none; - block-size: $sz-12; - inline-size: $sz-12; - stroke-width: 1.33px; - stroke: var(--color-foreground-secondary); - - .layer-row.hidden & { - opacity: 0.7; - } - - .type-comp & { - stroke: var(--color-accent-secondary); - } - } - .element-actions.selected & { display: flex; opacity: 0; @@ -294,21 +271,40 @@ display: flex; --layer-row-action-btn-background: var(--color-background-secondary); - - svg { - opacity: 1; - stroke: var(--color-accent-primary); - } } .layer-row.selected & { display: flex; --layer-row-action-btn-background: var(--color-background-quaternary); + } +} - svg { - stroke: var(--color-accent-primary); - } +.element-action-icon { + // The DS icon box is 16px and the button leaves 12px: keep the box + // whole, centered, instead of letting it shrink and cut the icon. + flex-shrink: 0; + + // Same stroke weight as the old 12px icons. + stroke-width: 1.33px; + color: var(--color-foreground-secondary); + + .layer-row.hidden & { + opacity: 0.7; + } + + .type-comp & { + color: var(--color-accent-secondary); + } + + .layer-row.highlight &, + .layer-row:hover & { + opacity: 1; + color: var(--color-accent-primary); + } + + .layer-row.selected & { + color: var(--color-accent-primary); } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/layer_name.scss b/frontend/src/app/main/ui/workspace/sidebar/layer_name.scss index 23a36b1d1b..6d6fc10fff 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layer_name.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/layer_name.scss @@ -4,16 +4,22 @@ // // Copyright (c) KALEIDOS SUBSIDIARY SL -@use "refactor/common-refactor.scss" as deprecated; +@use "ds/_utils.scss" as *; +@use "ds/_borders.scss" as *; +@use "ds/_sizes.scss" as *; +@use "ds/typography.scss" as *; .element-name { - --element-name-color: var(--context-hover-color, var(--layer-row-foreground-color)); - --element-name-comp-color: var(--context-hover-color, var(--layer-row-component-foreground-color)); - --element-name-opacity: var(--context-hover-opacity, deprecated.$op-7); + --element-name-color: var(--context-hover-color, var(--color-foreground-secondary)); + --element-name-opacity: var(--context-hover-opacity, 0.7); - @include deprecated.text-ellipsis; - @include deprecated.body-small-typography; + @include use-typography("body-small"); + display: block; + max-inline-size: 99%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; color: var(--element-name-color); flex-grow: 1; block-size: 100%; @@ -21,15 +27,11 @@ min-inline-size: var(--sp-xl); &.selected { - color: var(--layer-row-foreground-color-selected); + --element-name-color: var(--color-accent-primary); } &.type-comp { - color: var(--element-name-comp-color); - - &.hidden { - opacity: var(--element-name-opacity); - } + --element-name-color: var(--context-hover-color, var(--color-accent-secondary)); } &.hidden { @@ -37,30 +39,26 @@ } } +// The rename input also carries .element-name, so it takes its typography, +// ellipsis and color from there. .element-name-input { - --element-name-input-border-color: var(--input-border-color-focus); - --element-name-input-color: var(--layer-row-foreground-color); - - @include deprecated.text-ellipsis; - @include deprecated.body-small-typography; - @include deprecated.remove-input-style; + --element-name-color: var(--color-foreground-secondary); + background: none; + outline: none; flex-grow: 1; - height: deprecated.$s-28; + block-size: $sz-28; max-inline-size: calc(var(--parent-size) - (var(--depth) * var(--layer-indentation-size))); margin: 0; - padding-inline-start: deprecated.$s-6; - border-radius: deprecated.$br-8; - border: deprecated.$s-1 solid var(--element-name-input-border-color); - color: var(--element-name-input-color); + padding-inline-start: px2rem(6); + border-radius: $br-8; + border: $b-1 solid var(--color-accent-primary); &.selected { - min-inline-size: deprecated.$s-100; + min-inline-size: px2rem(100); } } .element-name-touched { - --element-name-touched-color: var(--layer-row-component-foreground-color); - - color: var(--element-name-touched-color); + color: var(--color-accent-secondary); }