♻️ Use a DS icon in the grid editor track options button (#12486)

* ♻️ Use a DS icon in the grid editor track options button

The options button of each grid track on the canvas drew a deprecated
icon and had no accessible name. Use the DS menu icon and label the
button "Track options". The button stays raw: it lives on the canvas,
where the track editor keeps a fixed screen size at any zoom.

The DS icon has a fixed 16px size, so its class scales it down with the
zoom (transform: scale(1 / zoom)), as the old svg rule did with its
width. It looks the same, but for a few antialiasing pixels.

Add the workspace.layout-grid.editor.track-options key (en, es) and a
visual test of a track at two zoom levels.

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

* ♻️ Move grid editor styles off the deprecated styles

Move grid_layout_editor.scss to DS sizes, borders, spacing tokens,
colors and logical properties, and drop the refactor import. The canvas
sizes keep their division by the zoom. The grid editor color aliases
resolve to their DS tokens, and the unused close-btn class, the last
user of the deprecated button placeholders here, goes away.

The track editor and the editing bar look the same as before.

AI-assisted-by: claude-opus-5-5
This commit is contained in:
Eva Marco 2026-10-26 10:32:06 +01:00 committed by GitHub
parent 7ff8df6ffb
commit 9911f82087
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 128 additions and 55 deletions

View File

@ -136,6 +136,63 @@ test.describe("Grid layout", () => {
});
});
test.describe("Grid editor", () => {
test("Shows the track options button on the canvas", async ({ page }) => {
const workspace = new WorkspacePage(page);
await workspace.setupEmptyFile();
await workspace.mockRPC(/get\-file\?/, "workspace/get-file-9042.json");
await workspace.mockRPC(
"get-file-fragment?file-id=*&fragment-id=*",
"workspace/get-file-fragment-9042.json",
);
await workspace.goToWorkspace({
fileId: "af2494d0-39ba-8184-8005-230696f6df5c",
pageId: "af2494d0-39ba-8184-8005-230696f6df5d",
});
await workspace.clickLeafLayer("Board");
// Tracks need 110px or more on screen to show their options button.
await page.keyboard.press("Control+=");
await page.keyboard.press("Control+=");
await page
.getByTestId("inspect-layout")
.getByRole("button", { name: "Edit grid" })
.click();
const shotTrack = async () => {
const track = page.getByTestId("grid-track-editor-wrapper").first();
await track.hover();
await expect(
page.getByTestId("grid-track-options-btn").first(),
).toBeVisible();
// Wait until the zoom animation leaves the track in place.
let box = await track.boundingBox();
await expect
.poll(async () => {
const prev = box;
box = await track.boundingBox();
return prev.x === box.x && prev.width === box.width;
})
.toBe(true);
await expect(page).toHaveScreenshot({
clip: {
x: Math.floor(box.x) - 8,
y: Math.floor(box.y) - 8,
width: Math.ceil(box.width) + 16,
height: Math.ceil(box.height) + 16,
},
maxDiffPixelRatio: 0,
threshold: 0,
});
};
// The track editors draw at a fixed screen size at any zoom.
await shotTrack();
await page.keyboard.press("Control+=");
await shotTrack();
});
});
test.describe("Design tab", () => {
test("Shows the boolean options when selecting two shapes", async ({
page,

View File

@ -29,8 +29,8 @@
[app.main.store :as st]
[app.main.ui.css-cursors :as cur]
[app.main.ui.ds.buttons.button :refer [button*]]
[app.main.ui.ds.foundations.assets.icon :as i :refer [icon*]]
[app.main.ui.formats :as fmt]
[app.main.ui.icons :as deprecated-icon]
[app.main.ui.workspace.viewport.viewport-ref :as uwvv]
[app.util.debug :as dbg]
[app.util.dom :as dom]
@ -918,9 +918,15 @@
:on-key-down handle-keydown-track-input
:on-blur handle-blur-track-input}]
(when (and (not medium?) (not small?))
[:button {:class (stl/css :grid-editor-button)
;; Raw button on purpose: it lives on the canvas and keeps a
;; fixed screen size at any zoom.
[:button {:type "button"
:class (stl/css :grid-editor-button)
:data-testid "grid-track-options-btn"
:on-click handle-show-track-menu} deprecated-icon/menu])]])]
:aria-label (tr "workspace.layout-grid.editor.track-options")
:on-click handle-show-track-menu}
[:> icon* {:icon-id i/menu
:class (stl/css :grid-editor-button-icon)}]])]])]
[:g {:transform (when (= type :row) (dm/fmt "rotate(-90 % %)" (:x marker-p) (:y marker-p)))}
[:& track-marker

View File

@ -4,17 +4,23 @@
//
// 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 *;
@use "ds/colors.scss" as *;
@use "ds/z-index.scss" as *;
// The track editor lives on the canvas: its sizes are divided by the zoom
// so it keeps the same size on screen.
.grid-track-marker {
.marker-shape {
fill: var(--grid-editor-marker-color);
fill: var(--color-accent-quaternary);
}
.marker-text {
fill: var(--app-white);
font-size: calc(deprecated.$s-12 / var(--zoom));
fill: $white;
font-size: calc(#{px2rem(12)} / var(--zoom));
font-family: "worksans", "vazirmatn", sans-serif;
}
}
@ -22,8 +28,8 @@
.grid-editor-wrapper {
cursor: grab;
position: relative;
width: 100%;
height: 80%;
inline-size: 100%;
block-size: 80%;
display: flex;
flex-direction: column;
justify-content: center;
@ -31,21 +37,20 @@
}
.grid-editor-header-hover {
fill: var(--grid-editor-marker-color);
fill: var(--color-accent-quaternary);
}
.grid-editor-label {
flex: 1;
background: none;
border: 0;
color: var(--grid-editor-marker-text);
color: var(--color-accent-quaternary);
font-family: "worksans", "vazirmatn", sans-serif;
font-size: calc(deprecated.$fs-12 / var(--zoom));
font-size: calc(#{px2rem(12)} / var(--zoom));
font-weight: 400;
margin: 0;
max-width: calc(deprecated.$s-60 / var(--zoom));
padding: 0;
padding: calc(deprecated.$s-4 / var(--zoom));
max-inline-size: calc(#{px2rem(60)} / var(--zoom));
padding: calc(var(--sp-xs) / var(--zoom));
text-align: center;
&:focus {
@ -60,21 +65,23 @@
margin: 0;
padding: 0;
position: absolute;
top: calc(deprecated.$s-6 / var(--zoom));
right: calc(deprecated.$s-20 / var(--zoom));
width: calc(deprecated.$s-20 / var(--zoom));
height: calc(deprecated.$s-20 / var(--zoom));
inset-block-start: calc(#{px2rem(6)} / var(--zoom));
inset-inline-end: calc(#{px2rem(20)} / var(--zoom));
inline-size: calc(#{px2rem(20)} / var(--zoom));
block-size: calc(#{px2rem(20)} / var(--zoom));
opacity: 0;
pointer-events: none;
}
svg {
position: absolute;
top: 0;
left: 0;
width: calc(deprecated.$s-16 / var(--zoom));
height: auto;
stroke: var(--grid-editor-marker-color);
}
// The DS icon has a fixed 16px size: scale it down with the zoom, as the
// rest of the track editor, so it keeps the same size on screen.
.grid-editor-button-icon {
position: absolute;
inset-block-start: 0;
inset-inline-start: 0;
transform: scale(calc(1 / var(--zoom)));
transform-origin: top left;
color: var(--color-accent-quaternary);
}
.grid-editor-wrapper:hover .grid-editor-button {
@ -83,7 +90,7 @@
}
.grid-frame {
fill: var(--grid-editor-marker-color);
fill: var(--color-accent-quaternary);
fill-opacity: 0.1;
}
@ -92,13 +99,13 @@
opacity: 0.5;
.grid-plus-shape {
fill: var(--grid-editor-plus-btn-background);
stroke: var(--grid-editor-plus-btn-background);
stroke-width: calc(deprecated.$s-1 / var(--zoom));
fill: var(--color-accent-quaternary);
stroke: var(--color-accent-quaternary);
stroke-width: calc(#{px2rem(1)} / var(--zoom));
}
.grid-plus-icon {
stroke: var(--grid-editor-plus-btn-foreground);
stroke: $white;
}
&:hover {
@ -108,7 +115,7 @@
.grid-cell-outline {
fill: transparent;
stroke: var(--grid-editor-line-color);
stroke: var(--color-accent-quaternary);
stroke-opacity: 0.5;
stroke-width: calc(1 / var(--zoom));
@ -122,37 +129,32 @@
.grid-actions {
pointer-events: none;
position: absolute;
top: deprecated.$s-44;
left: 50%;
inset-block-start: px2rem(44);
inset-inline-start: 50%;
z-index: var(--z-index-notifications);
}
.grid-actions-container {
@include deprecated.flex-row;
background: var(--panel-background-color);
border-radius: deprecated.$br-12;
box-shadow: 0 0 deprecated.$s-12 0 var(--menu-shadow-color);
gap: deprecated.$s-8;
height: deprecated.$s-48;
margin-left: -50%;
padding: deprecated.$s-8;
display: flex;
align-items: center;
gap: var(--sp-s);
background: var(--color-background-primary);
border-radius: $br-12;
box-shadow: 0 0 px2rem(12) 0 var(--color-shadow-dark);
block-size: $sz-48;
margin-inline-start: -50%;
padding: var(--sp-s);
cursor: initial;
pointer-events: initial;
width: deprecated.$s-512;
inline-size: $sz-512;
}
.grid-actions-title {
flex: 1;
font-size: deprecated.$fs-12;
// TODO: No exact DS typography match found.
// Closest match: body-small.
font-size: px2rem(12);
color: var(--color-foreground-secondary);
padding-left: deprecated.$s-8;
}
.close-btn {
@extend %button-tertiary;
svg {
@extend %button-icon;
}
padding-inline-start: var(--sp-s);
}

View File

@ -6791,6 +6791,10 @@ msgstr "Top padding"
msgid "workspace.layout-grid.editor.padding.vertical"
msgstr "Vertical padding"
#: src/app/main/ui/workspace/viewport/grid_layout_editor.cljs
msgid "workspace.layout-grid.editor.track-options"
msgstr "Track options"
#: src/app/main/ui/workspace/viewport/grid_layout_editor.cljs:61
msgid "workspace.layout-grid.editor.title"
msgstr "Editing grid"

View File

@ -6875,6 +6875,10 @@ msgstr "Padding superior"
msgid "workspace.layout-grid.editor.padding.vertical"
msgstr "Padding vertical"
#: src/app/main/ui/workspace/viewport/grid_layout_editor.cljs
msgid "workspace.layout-grid.editor.track-options"
msgstr "Opciones de la pista"
#: src/app/main/ui/workspace/viewport/grid_layout_editor.cljs:61
msgid "workspace.layout-grid.editor.title"
msgstr "Editando rejilla"