From 18ca25518e61a1c59d1bc46baaa80cd6f1cbf544 Mon Sep 17 00:00:00 2001 From: Eva Marco Date: Mon, 19 Oct 2026 14:28:03 +0200 Subject: [PATCH] :recycle: Use a DS icon button to close the nudge amount modal (#12439) * :recycle: Use a DS icon button to close the nudge amount modal The close button of the nudge amount modal (main menu, Preferences) was a raw button with a deprecated icon and no accessible name. Replace it with a DS ghost icon button labeled "Close", shown in its DS tooltip. The class that places it in the corner goes on the tooltip wrapper, so the tooltip anchors to the button. The numeric inputs stay for the inputs group. Add a visual test that opens the modal from the main menu. AI-assisted-by: claude-opus-5-5 * :recycle: Move nudge modal styles off the deprecated styles The close button is a DS icon button, so its placeholder goes away; it is now 32px wide instead of 28px, and sits 4px from the edge instead of 6px so the icon stays in the same place. Spacing, sizes and the color aliases move to DS tokens and logical properties, the flex mixin is inlined, and the label rule targets its class instead of the label element. The title matches the DS headline-medium typography exactly. The content and labels use body-large and the wrapper body-small, whose line-heights differ by 0.1 from the legacy ones; the labels keep their 1.5 override, so nothing visible changes. refactor/ stays only for the shared modal and labeled input placeholders. AI-assisted-by: claude-opus-5-5 --- .../ui/visual-specs/workspace.spec.js | 19 ++++++++++ frontend/src/app/main/ui/workspace/nudge.cljs | 10 ++++-- frontend/src/app/main/ui/workspace/nudge.scss | 36 +++++++++++-------- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/frontend/playwright/ui/visual-specs/workspace.spec.js b/frontend/playwright/ui/visual-specs/workspace.spec.js index f074bc20a2..e67e97ce97 100644 --- a/frontend/playwright/ui/visual-specs/workspace.spec.js +++ b/frontend/playwright/ui/visual-specs/workspace.spec.js @@ -219,6 +219,25 @@ test.describe("Palette", () => { }); }); +test.describe("Nudge modal", () => { + test("Shows the nudge amount modal", async ({ page }) => { + const workspace = new WorkspacePage(page); + await workspace.setupEmptyFile(); + await workspace.goToWorkspace(); + + await page.getByRole("button", { name: "Main menu" }).click(); + await page.locator("#file-menu-preferences").click(); + await page.locator("#file-menu-nudge").click(); + + await expect(page.getByText("Nudge amount")).toBeVisible(); + await page.mouse.move(0, 0); + await expect(workspace.page).toHaveScreenshot("nudge-modal.png", { + maxDiffPixelRatio: 0, + threshold: 0, + }); + }); +}); + test.describe("Selected colors", () => { test("Shows the more colors button", async ({ page }) => { const workspace = new WorkspacePage(page); diff --git a/frontend/src/app/main/ui/workspace/nudge.cljs b/frontend/src/app/main/ui/workspace/nudge.cljs index 7c2ee4f01c..fb44f4435d 100644 --- a/frontend/src/app/main/ui/workspace/nudge.cljs +++ b/frontend/src/app/main/ui/workspace/nudge.cljs @@ -12,7 +12,8 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.numeric-input :as deprecated-input] - [app.main.ui.icons :as deprecated-icon] + [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] + [app.main.ui.ds.foundations.assets.icon :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as k] @@ -44,8 +45,11 @@ [:div {:class (stl/css :modal-container)} [:div {:class (stl/css :modal-header)} [:h2 {:class (stl/css :modal-title)} (tr "modals.nudge-title")] - [:button {:class (stl/css :modal-close-btn) - :on-click modal/hide!} deprecated-icon/close]] + [:> icon-button* {:variant "ghost" + :tooltip-class (stl/css :modal-close-btn) + :aria-label (tr "labels.close") + :icon i/close + :on-click modal/hide!}]] [:div {:class (stl/css :modal-content)} [:div {:class (stl/css :input-wrapper)} [:label {:class (stl/css :modal-msg) diff --git a/frontend/src/app/main/ui/workspace/nudge.scss b/frontend/src/app/main/ui/workspace/nudge.scss index 892de2576d..2fe8b7739a 100644 --- a/frontend/src/app/main/ui/workspace/nudge.scss +++ b/frontend/src/app/main/ui/workspace/nudge.scss @@ -4,7 +4,11 @@ // // Copyright (c) KALEIDOS SUBSIDIARY SL +// Only for the shared modal and labeled input placeholders, which move to +// the DS with the modals and the inputs. @use "refactor/common-refactor.scss" as deprecated; +@use "ds/_utils.scss" as *; +@use "ds/typography.scss" as *; .modal-overlay { @extend %modal-overlay-base; @@ -13,45 +17,47 @@ .modal-container { @extend %modal-container-base; - min-width: deprecated.$s-408; + min-inline-size: px2rem(408); } .modal-header { - margin-bottom: deprecated.$s-24; + margin-block-end: var(--sp-xxl); } .modal-title { - @include deprecated.headline-medium-typography; + @include use-typography("headline-medium"); - color: var(--modal-title-foreground-color); + color: var(--color-foreground-primary); } .modal-close-btn { - @extend %modal-close-btn-base; + position: absolute; + inset-block-start: var(--sp-s); + inset-inline-end: var(--sp-xs); } .modal-content { - @include deprecated.flex-column; + @include use-typography("body-large"); - gap: deprecated.$s-24; - - @include deprecated.body-large-typography; - - margin-bottom: deprecated.$s-24; + display: flex; + flex-direction: column; + gap: var(--sp-xxl); + margin-block-end: var(--sp-xxl); } .input-wrapper { @extend %input-with-label; - @include deprecated.body-small-typography; + @include use-typography("body-small"); - label { + // Nested so it wins over the label rule of %input-with-label. + .modal-msg { text-transform: none; } } .modal-msg { - @include deprecated.body-large-typography; + @include use-typography("body-large"); - color: var(--modal-text-foreground-color); + color: var(--color-foreground-secondary); line-height: 1.5; }