♻️ Use DS icons in the copy button (#12558)

* ♻️ Use DS icons in the copy button

The shared copy button (Inspect attribute rows and code blocks, share
link, integrations) draws its clipboard and tick icons with the DS
icons at the small size, colored through the color property. The
button itself stays: it wraps whole rows. The icons are the same
drawings, so nothing changes on screen.

A visual test covers an Inspect computed attribute row and the code
block copy button, at rest, on hover and after copying.

AI-assisted-by: claude-opus-5-5

* ♻️ Move copy button styles off the deprecated styles

The copy button stylesheet no longer imports refactor/: the
button-style, flex-center and copy-wrapper-base mixins are inlined with
DS values, the tertiary button and icon color aliases resolve to their
DS tokens, and physical properties become logical ones. No visual
change (whole viewer visual spec compared; the code tab syntax
highlighting loads late on a cold first run, with either stylesheet).

AI-assisted-by: claude-opus-5-5
This commit is contained in:
Eva Marco 2026-10-27 11:41:36 +01:00 committed by GitHub
parent 8800ff4bc9
commit 112e6dedd7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 105 additions and 52 deletions

View File

@ -395,3 +395,50 @@ test.describe("Interactions menu", () => {
});
});
});
test.describe("Copy buttons", () => {
const shot = { maxDiffPixelRatio: 0, threshold: 0 };
const openInspectTab = async (page, name) => {
const viewerPage = new ViewerPage(page);
await viewerPage.setupLoggedInUser();
await viewerPage.setupFileWithComments();
await viewerPage.goToViewer({
fileId: singleBoardFileId,
pageId: singleBoardPageId,
});
await viewerPage.showCode();
await page.getByRole("combobox").filter({ hasText: "Styles" }).click();
await page.getByRole("option", { name }).click();
};
test("Computed attribute rows", async ({ page }) => {
await openInspectTab(page, "Computed");
const row = page.locator("[class*='copy-wrapper']").first();
await expect(row).toBeVisible();
await page.mouse.move(10, 700);
await expect(row).toHaveScreenshot(shot);
await row.hover();
await expect(row).toHaveScreenshot(shot);
await row.click();
await expect(row).toHaveAttribute("data-active", "true");
await expect(row).toHaveScreenshot(shot);
});
test("Code block copy button", async ({ page }) => {
await openInspectTab(page, "Code");
const copy = page.locator("[class*='css-copy-btn']");
await expect(copy).toBeVisible();
await page.mouse.move(10, 700);
await expect(copy).toHaveScreenshot(shot);
await copy.hover();
await expect(copy).toHaveScreenshot(shot);
await copy.click();
await expect(copy).toHaveAttribute("data-active", "true");
await expect(copy).toHaveScreenshot(shot);
});
});

View File

@ -9,7 +9,7 @@
(:require
[app.common.data.macros :as dm]
[app.main.data.event :as-alias ev]
[app.main.ui.icons :as deprecated-icon]
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
[app.util.clipboard :as clipboard]
[app.util.dom :as dom]
[app.util.i18n :refer [tr]]
@ -43,6 +43,6 @@
:on-click on-click}
children
[:span {:class (stl/css :icon-btn)}
(if active?
deprecated-icon/tick
deprecated-icon/clipboard)]]))
[:> icon* {:icon-id (if active? i/tick i/clipboard)
:size "s"
:class (stl/css :icon)}]]]))

View File

@ -4,89 +4,95 @@
//
// Copyright (c) KALEIDOS SUBSIDIARY SL
@use "refactor/common-refactor.scss" as deprecated;
@use "ds/_borders.scss" as *;
@use "ds/_sizes.scss" as *;
@use "ds/_utils.scss" as *;
.copy-button {
@include deprecated.button-style;
width: 100%;
height: deprecated.$s-32;
border: deprecated.$s-1 solid transparent;
border-radius: deprecated.$br-8;
border: $b-1 solid transparent;
background: none;
cursor: pointer;
inline-size: 100%;
block-size: $sz-32;
border-radius: $br-8;
background-color: transparent;
box-sizing: border-box;
.icon-btn {
@include deprecated.flex-center;
display: flex;
justify-content: center;
align-items: center;
block-size: $sz-32;
min-inline-size: $sz-28;
inline-size: $sz-28;
height: deprecated.$s-32;
min-width: deprecated.$s-28;
width: deprecated.$s-28;
svg {
@extend %button-icon-small;
stroke: var(--icon-foreground);
.icon {
flex-shrink: 0;
stroke-width: 1.33px;
color: var(--color-foreground-secondary);
}
}
&:hover {
background-color: var(--color-background-tertiary);
color: var(--color-foreground-primary);
border: deprecated.$s-1 solid var(--color-background-tertiary);
border: $b-1 solid var(--color-background-tertiary);
.icon-btn {
svg {
stroke: var(--button-tertiary-foreground-color-active);
}
.icon-btn .icon {
color: var(--color-accent-primary);
}
}
&:focus,
&:focus-visible {
outline: none;
border: deprecated.$s-1 solid var(--button-tertiary-border-color-focus);
border: $b-1 solid var(--color-accent-primary);
background-color: transparent;
color: var(--button-tertiary-foreground-color-focus);
color: var(--color-foreground-primary);
.icon-btn svg {
stroke: var(--button-tertiary-foreground-color-active);
.icon-btn .icon {
color: var(--color-accent-primary);
}
}
}
.copy-wrapper {
@include deprecated.button-style;
@include deprecated.copy-wrapper-base;
width: 100%;
height: fit-content;
text-align: left;
border: deprecated.$s-1 solid transparent;
position: relative;
min-block-size: $sz-32;
inline-size: 100%;
block-size: fit-content;
padding: px2rem(7) 0 px2rem(7) px2rem(7);
border: $b-1 solid transparent;
border-radius: $br-8;
background: none;
box-sizing: border-box;
cursor: pointer;
text-align: start;
.icon-btn {
@include deprecated.flex-center;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
right: 0;
height: deprecated.$s-32;
width: deprecated.$s-28;
inset-block-start: 0;
inset-inline-end: 0;
block-size: $sz-32;
inline-size: $sz-28;
svg {
@extend %button-icon-small;
stroke: var(--button-tertiary-foreground-color-focus);
.icon {
flex-shrink: 0;
stroke-width: 1.33px;
color: var(--color-foreground-primary);
display: none;
}
}
&:hover {
background-color: var(--button-tertiary-background-color-focus);
color: var(--button-tertiary-foreground-color-focus);
border: deprecated.$s-1 solid var(--button-tertiary-background-color-focus);
background-color: var(--color-background-tertiary);
color: var(--color-foreground-primary);
border: $b-1 solid var(--color-background-tertiary);
.icon-btn svg {
.icon-btn .icon {
display: flex;
}
}
@ -94,8 +100,8 @@
&:focus,
&:focus-visible {
outline: none;
border: deprecated.$s-1 solid var(--button-tertiary-border-color-focus);
border: $b-1 solid var(--color-accent-primary);
background-color: transparent;
color: var(--button-tertiary-foreground-color-focus);
color: var(--color-foreground-primary);
}
}