Skip to content

Commit 1e893db

Browse files
committed
PR_26171_034 style idea board chevrons inline
1 parent 7036188 commit 1e893db

4 files changed

Lines changed: 107 additions & 11 deletions

File tree

assets/theme-v2/css/tables.css

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,44 @@ td {
5050
text-transform: none
5151
}
5252

53+
.data-table [data-idea-board-idea-cell] {
54+
cursor: pointer
55+
}
56+
57+
.idea-board-idea-label {
58+
display: inline-flex;
59+
align-items: center;
60+
gap: .35em;
61+
color: inherit;
62+
font: inherit;
63+
line-height: inherit;
64+
vertical-align: baseline
65+
}
66+
67+
.idea-board-idea-chevron {
68+
display: inline-block;
69+
width: 1em;
70+
height: 1em;
71+
flex: 0 0 1em;
72+
background: currentColor;
73+
-webkit-mask-position: center;
74+
mask-position: center;
75+
-webkit-mask-repeat: no-repeat;
76+
mask-repeat: no-repeat;
77+
-webkit-mask-size: contain;
78+
mask-size: contain
79+
}
80+
81+
.idea-board-idea-chevron--down {
82+
-webkit-mask-image: url("../images/gfs-chevron-down.svg");
83+
mask-image: url("../images/gfs-chevron-down.svg")
84+
}
85+
86+
.idea-board-idea-chevron--up {
87+
-webkit-mask-image: url("../images/gfs-chevron-up.svg");
88+
mask-image: url("../images/gfs-chevron-up.svg")
89+
}
90+
5391
.tool-form-table {
5492
table-layout: fixed;
5593
width: 100%

tests/playwright/tools/IdeaBoardTableNotes.spec.mjs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,32 @@ function restoreEnvValue(key, value) {
1010
process.env[key] = value;
1111
}
1212

13+
async function expectIdeaChevron(page, ideaId, iconName) {
14+
const metrics = await page.locator(`[data-idea-board-idea-row='${ideaId}'] th`).evaluate((cell, targetIdeaId) => {
15+
const label = cell.querySelector(".idea-board-idea-label");
16+
const icon = cell.querySelector(`[data-idea-board-chevron='${targetIdeaId}']`);
17+
const cellStyles = getComputedStyle(cell);
18+
const labelStyles = getComputedStyle(label);
19+
const iconStyles = getComputedStyle(icon);
20+
return {
21+
iconName: icon.dataset.ideaBoardChevronIcon,
22+
labelDisplay: labelStyles.display,
23+
iconWidth: Number.parseFloat(iconStyles.width),
24+
iconHeight: Number.parseFloat(iconStyles.height),
25+
fontSize: Number.parseFloat(cellStyles.fontSize),
26+
iconColor: iconStyles.backgroundColor,
27+
textColor: cellStyles.color,
28+
maskImage: iconStyles.getPropertyValue("-webkit-mask-image") || iconStyles.maskImage,
29+
};
30+
}, ideaId);
31+
expect(metrics.iconName).toBe(iconName);
32+
expect(metrics.labelDisplay).toBe("inline-flex");
33+
expect(Math.abs(metrics.iconWidth - metrics.fontSize)).toBeLessThanOrEqual(1);
34+
expect(Math.abs(metrics.iconHeight - metrics.fontSize)).toBeLessThanOrEqual(1);
35+
expect(metrics.iconColor).toBe(metrics.textColor);
36+
expect(metrics.maskImage).toContain(iconName);
37+
}
38+
1339
test("Idea Board uses DB-shaped accordion table ideas and notes", async ({ page }) => {
1440
const server = await startRepoServer();
1541
const previousApiUrl = process.env.GAMEFOUNDRY_API_URL;
@@ -58,15 +84,15 @@ test("Idea Board uses DB-shaped accordion table ideas and notes", async ({ page
5884
await expect(page.getByText("Selected")).toHaveCount(0);
5985

6086
await expect(page.locator("[data-idea-board-idea-row='top-thoughts'] th")).toHaveText("Top Thoughts");
61-
await expect(page.locator("[data-idea-board-chevron='top-thoughts']")).toHaveAttribute("src", /gfs-chevron-down\.svg$/);
87+
await expectIdeaChevron(page, "top-thoughts", "gfs-chevron-down.svg");
6288
await expect(page.locator("[data-idea-board-idea-row='top-thoughts'] td").nth(0)).toHaveText("Smartest person wins...");
6389
await expect(page.locator("[data-idea-board-idea-row='top-thoughts'] td").nth(1)).toHaveText("Exploring");
6490
await expect(page.locator("[data-idea-board-idea-row='top-thoughts'] td").nth(2)).toHaveText("2026-06-20");
6591
await expect(page.locator("[data-idea-board-notes-count='top-thoughts']")).toHaveText("3 Notes");
6692
await expect(page.locator("[data-idea-board-idea-row='top-thoughts'] [data-idea-board-idea-action]")).toHaveText(["Edit", "Delete"]);
6793

6894
await expect(page.locator("[data-idea-board-idea-row='sky-orchard'] th")).toHaveText("Sky Orchard");
69-
await expect(page.locator("[data-idea-board-chevron='sky-orchard']")).toHaveAttribute("src", /gfs-chevron-down\.svg$/);
95+
await expectIdeaChevron(page, "sky-orchard", "gfs-chevron-down.svg");
7096
await expect(page.locator("[data-idea-board-idea-row='sky-orchard'] td").nth(0)).toHaveText("Grow floating islands...");
7197
await expect(page.locator("[data-idea-board-notes-count='sky-orchard']")).toHaveText("3 Notes");
7298
await expect(page.locator("[data-idea-board-idea-row='clockwork-courier'] th")).toHaveText("Clockwork Courier");
@@ -77,7 +103,7 @@ test("Idea Board uses DB-shaped accordion table ideas and notes", async ({ page
77103
await expect(page.locator("[data-idea-board-expanded-row]")).toHaveCount(0);
78104
await page.locator("[data-idea-board-idea-cell='top-thoughts']").click();
79105
await expect(page.locator("[data-idea-board-expanded-row='top-thoughts']")).toBeVisible();
80-
await expect(page.locator("[data-idea-board-chevron='top-thoughts']")).toHaveAttribute("src", /gfs-chevron-up\.svg$/);
106+
await expectIdeaChevron(page, "top-thoughts", "gfs-chevron-up.svg");
81107
await expect(page.locator("[data-idea-board-expanded-row='top-thoughts'] [data-idea-board-notes-header='top-thoughts']")).toHaveText("Notes");
82108
await expect(page.locator("[data-idea-board-notes-table='top-thoughts'] th[scope='col']")).toHaveText(["Note", "Actions"]);
83109
await expect(page.locator("[data-idea-board-notes-table] th[scope='col']", { hasText: "Type" })).toHaveCount(0);
@@ -113,12 +139,12 @@ test("Idea Board uses DB-shaped accordion table ideas and notes", async ({ page
113139
await page.locator("[data-idea-board-idea-cell='sky-orchard']").click();
114140
await expect(page.locator("[data-idea-board-expanded-row='top-thoughts']")).toHaveCount(0);
115141
await expect(page.locator("[data-idea-board-expanded-row='sky-orchard']")).toBeVisible();
116-
await expect(page.locator("[data-idea-board-chevron='sky-orchard']")).toHaveAttribute("src", /gfs-chevron-up\.svg$/);
142+
await expectIdeaChevron(page, "sky-orchard", "gfs-chevron-up.svg");
117143
await page.locator("[data-idea-board-notes-count='sky-orchard']").click();
118144
await expect(page.locator("[data-idea-board-expanded-row='sky-orchard']")).toBeVisible();
119145
await page.locator("[data-idea-board-idea-cell='sky-orchard']").click();
120146
await expect(page.locator("[data-idea-board-expanded-row]")).toHaveCount(0);
121-
await expect(page.locator("[data-idea-board-chevron='sky-orchard']")).toHaveAttribute("src", /gfs-chevron-down\.svg$/);
147+
await expectIdeaChevron(page, "sky-orchard", "gfs-chevron-down.svg");
122148

123149
await page.locator("[data-idea-board-add-idea]").click();
124150
const ideaInputRow = page.locator("[data-idea-board-idea-input-row]").last();

tests/playwright/tools/ToolboxRoutePages.spec.mjs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,32 @@ function restoreEnvValue(key, value) {
112112
process.env[key] = value;
113113
}
114114

115+
async function expectIdeaChevron(page, ideaId, iconName) {
116+
const metrics = await page.locator(`[data-idea-board-idea-row='${ideaId}'] th`).evaluate((cell, targetIdeaId) => {
117+
const label = cell.querySelector(".idea-board-idea-label");
118+
const icon = cell.querySelector(`[data-idea-board-chevron='${targetIdeaId}']`);
119+
const cellStyles = getComputedStyle(cell);
120+
const labelStyles = getComputedStyle(label);
121+
const iconStyles = getComputedStyle(icon);
122+
return {
123+
iconName: icon.dataset.ideaBoardChevronIcon,
124+
labelDisplay: labelStyles.display,
125+
iconWidth: Number.parseFloat(iconStyles.width),
126+
iconHeight: Number.parseFloat(iconStyles.height),
127+
fontSize: Number.parseFloat(cellStyles.fontSize),
128+
iconColor: iconStyles.backgroundColor,
129+
textColor: cellStyles.color,
130+
maskImage: iconStyles.getPropertyValue("-webkit-mask-image") || iconStyles.maskImage,
131+
};
132+
}, ideaId);
133+
expect(metrics.iconName).toBe(iconName);
134+
expect(metrics.labelDisplay).toBe("inline-flex");
135+
expect(Math.abs(metrics.iconWidth - metrics.fontSize)).toBeLessThanOrEqual(1);
136+
expect(Math.abs(metrics.iconHeight - metrics.fontSize)).toBeLessThanOrEqual(1);
137+
expect(metrics.iconColor).toBe(metrics.textColor);
138+
expect(metrics.maskImage).toContain(iconName);
139+
}
140+
115141
test("tools route aliases render toolbox tool pages", async ({ page }) => {
116142
const server = await startRepoServer();
117143
const failedRequests = [];
@@ -226,13 +252,13 @@ test("Idea Board launches from Toolbox with accordion table notes model", async
226252
await expect(page.locator("[data-idea-board-notes-count='top-thoughts']")).toHaveText("3 Notes");
227253
await expect(page.locator("[data-idea-board-notes-count='sky-orchard']")).toHaveText("3 Notes");
228254
await expect(page.locator("[data-idea-board-notes-count='clockwork-courier']")).toHaveText("0 Notes");
229-
await expect(page.locator("[data-idea-board-chevron='top-thoughts']")).toHaveAttribute("src", /gfs-chevron-down\.svg$/);
255+
await expectIdeaChevron(page, "top-thoughts", "gfs-chevron-down.svg");
230256
await expect(page.locator("[data-idea-board-status]")).toHaveText("Idea Board table edits are in-page only. No project records, auth, AI, or database behavior is connected.");
231257
await page.locator("[data-idea-board-notes-count='top-thoughts']").click();
232258
await expect(page.locator("[data-idea-board-expanded-row]")).toHaveCount(0);
233259
await page.locator("[data-idea-board-idea-cell='top-thoughts']").click();
234260
await expect(page.locator("[data-idea-board-expanded-row='top-thoughts']")).toBeVisible();
235-
await expect(page.locator("[data-idea-board-chevron='top-thoughts']")).toHaveAttribute("src", /gfs-chevron-up\.svg$/);
261+
await expectIdeaChevron(page, "top-thoughts", "gfs-chevron-up.svg");
236262
await expect(page.locator("[data-idea-board-notes-header='top-thoughts']")).toHaveText("Notes");
237263
await expect(page.locator("[data-idea-board-notes-table='top-thoughts'] th[scope='col']")).toHaveText(["Note", "Actions"]);
238264
await expect(page.getByText("Notes for Sky Orchard")).toHaveCount(0);

toolbox/idea-board/index.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,13 +188,19 @@ function renderIdeaRow(tbody, record) {
188188
idea.setAttribute("aria-expanded", String(expanded));
189189
idea.setAttribute("role", "button");
190190
idea.setAttribute("aria-label", `${expanded ? "Collapse" : "Expand"} notes for ${record.idea}`);
191+
const ideaLabel = document.createElement("span");
192+
ideaLabel.className = "idea-board-idea-label";
191193
const ideaText = document.createElement("span");
194+
ideaText.className = "idea-board-idea-label__text";
192195
ideaText.textContent = record.idea;
193-
const chevron = document.createElement("img");
194-
chevron.alt = "";
196+
const chevron = document.createElement("span");
197+
const chevronIcon = expanded ? "gfs-chevron-up.svg" : "gfs-chevron-down.svg";
198+
chevron.className = `idea-board-idea-chevron idea-board-idea-chevron--${expanded ? "up" : "down"}`;
199+
chevron.setAttribute("aria-hidden", "true");
195200
chevron.dataset.ideaBoardChevron = record.ideaId;
196-
chevron.src = expanded ? "assets/theme-v2/images/gfs-chevron-up.svg" : "assets/theme-v2/images/gfs-chevron-down.svg";
197-
idea.append(ideaText, " ", chevron);
201+
chevron.dataset.ideaBoardChevronIcon = chevronIcon;
202+
ideaLabel.append(ideaText, chevron);
203+
idea.append(ideaLabel);
198204
row.append(idea);
199205
row.append(cell(record.pitch));
200206
row.append(cell(record.status));

0 commit comments

Comments
 (0)