Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions assets/theme-v2/css/tables.css
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,10 @@ td {
cursor: pointer
}

.data-table [data-game-active-cell="true"] {
box-shadow: inset var(--space-3) 0 0 var(--gold);
border-bottom-color: var(--gold-border-muted)
.data-table [data-game-toggle][aria-current="true"] {
border-color: var(--gold);
background: color-mix(in srgb, var(--gold) 18%, var(--panel-soft));
box-shadow: inset 0 0 0 1px var(--gold-border-muted)
}

.idea-board-idea-label {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# PR_26174_ALFA_018-game-selection-button-state

## Summary

Moved Game Hub selected-game indication to the game button only.

## Implementation

- Removed active-game markers from parent rows.
- Removed active-game markers from parent table cells.
- Replaced the left-border cell highlight with selected styling on the game button.
- Removed the `Selected {game}.` status log update when selecting a game row.
- Preserved child row behavior so Source Idea and Readiness Output follow the selected game.
- Added targeted Playwright assertions for one selected button, unchanged sibling columns, child row movement, and no selected status copy.

## Scope Control

- Preserved the existing API/service contract.
- Preserved the Game row parent structure.
- Preserved Source Idea and Readiness Output child rows/tables.
- Did not add browser-owned product data.
- Did not introduce silent fallbacks.

## ZIP

- `tmp/PR_26174_ALFA_018-game-selection-button-state_delta.zip`
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Branch validation: PASS

Branch:
pr/26174-ALFA-018-game-selection-button-state

Base stack branch:
pr/26174-ALFA-017-game-hub-guest-save-and-crew-cleanup

Checks:
- Current branch is the ALFA_018 branch: PASS
- Worktree was clean before ALFA_018 edits: PASS
- Scope limited to Game Hub selection state, targeted Playwright coverage, and required reports: PASS
- No protected Project Instructions changes: PASS
- No merge to main performed: PASS
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Manual validation notes: PASS

- Reviewed `docs_build/dev/ProjectInstructions/addendums/table_first_ui.md`.
- Confirmed selected state remains on the game button through `aria-current`.
- Confirmed parent rows no longer receive active attributes.
- Confirmed cells no longer receive active markers.
- Confirmed the old left-border cell selector was removed.
- Confirmed selecting another game leaves only one selected game button.
- Confirmed Source Idea and Readiness Output child rows move with the selected game.
- Confirmed the bottom status area no longer receives `Selected {game}.` when a game row is selected.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Requirement checklist: PASS

- Selected game is indicated only by the Game button: PASS
- Row-level selection indicators removed: PASS
- Left border highlight removed: PASS
- Row background highlight removed: PASS
- Cell background highlights removed: PASS
- Purpose, Status, and Actions columns remain visually identical for all rows: PASS
- Only one game may be selected at a time: PASS
- Selecting a different game moves selected styling to that game button: PASS
- Child rows continue to follow the selected game: PASS
- Follow table_first_ui.md: PASS
- Removed selected-game status copy from bottom status area: PASS
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Validation lane: PASS

Commands:
- `git diff --check -- toolbox/game-hub/game-hub.js assets/theme-v2/css/tables.css tests/playwright/tools/GameHubMockRepository.spec.mjs`
- PASS
- `node --check toolbox/game-hub/game-hub.js`
- PASS
- `npx playwright test tests/playwright/tools/GameHubMockRepository.spec.mjs -g "Game Hub"`
- PASS, 11 passed

Generated coverage reports were restored after Playwright validation to keep this PR scoped.
12 changes: 6 additions & 6 deletions docs_build/dev/reports/codex_changed_files.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
docs_build/dev/reports/PR_26174_ALFA_017-game-hub-guest-save-and-crew-cleanup.md
docs_build/dev/reports/PR_26174_ALFA_017-game-hub-guest-save-and-crew-cleanup_branch-validation.txt
docs_build/dev/reports/PR_26174_ALFA_017-game-hub-guest-save-and-crew-cleanup_manual-validation-notes.txt
docs_build/dev/reports/PR_26174_ALFA_017-game-hub-guest-save-and-crew-cleanup_requirement-checklist.txt
docs_build/dev/reports/PR_26174_ALFA_017-game-hub-guest-save-and-crew-cleanup_validation-lane.txt
assets/theme-v2/css/tables.css
docs_build/dev/reports/PR_26174_ALFA_018-game-selection-button-state.md
docs_build/dev/reports/PR_26174_ALFA_018-game-selection-button-state_branch-validation.txt
docs_build/dev/reports/PR_26174_ALFA_018-game-selection-button-state_manual-validation-notes.txt
docs_build/dev/reports/PR_26174_ALFA_018-game-selection-button-state_requirement-checklist.txt
docs_build/dev/reports/PR_26174_ALFA_018-game-selection-button-state_validation-lane.txt
docs_build/dev/reports/codex_changed_files.txt
docs_build/dev/reports/codex_review.diff
tests/playwright/tools/GameHubMockRepository.spec.mjs
toolbox/game-hub/game-hub.js
toolbox/game-hub/index.html
Binary file modified docs_build/dev/reports/codex_review.diff
Binary file not shown.
68 changes: 51 additions & 17 deletions tests/playwright/tools/GameHubMockRepository.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -290,24 +290,48 @@ test("Game Hub creates, opens, and deletes mock games", async ({ page }) => {
const demoGameRow = page.locator("[data-game-row='demo-game']");
await expect(demoGameRow.locator("td")).toHaveText(["Game", "Under Construction", "Edit"]);
await expect(demoGameRow).not.toContainText("User 1");
await expect(demoGameRow).toHaveAttribute("data-game-active", "true");
await expect(demoGameRow).toHaveAttribute("aria-current", "true");
await expect(demoGameRow.locator("th[data-game-active-cell='true']")).toContainText("Demo Game");
const activeCellStyle = await demoGameRow.locator("th[data-game-active-cell='true']").evaluate((cell) => {
const styles = getComputedStyle(cell);
return {
backgroundColor: styles.backgroundColor,
boxShadow: styles.boxShadow,
};
});
const inactiveCellBackground = await page.locator("[data-game-row='gravity-demo'] th").evaluate((cell) => getComputedStyle(cell).backgroundColor);
expect(activeCellStyle.backgroundColor).toBe(inactiveCellBackground);
expect(activeCellStyle.boxShadow).not.toBe("none");
await expect(demoGameRow).not.toHaveAttribute("data-game-active", "true");
await expect(demoGameRow).not.toHaveAttribute("aria-current", "true");
await expect(demoGameRow.locator("th[data-game-active-cell='true']")).toHaveCount(0);
await expect(page.locator("[data-game-row][data-game-active='true']")).toHaveCount(0);
await expect(page.locator("[data-game-row][aria-current='true']")).toHaveCount(0);
await expect(page.locator("[data-game-active-cell='true']")).toHaveCount(0);
const rowVisuals = await page.locator("[data-game-row]").evaluateAll((rows) => rows.map((row) => {
const cells = Array.from(row.children).slice(1);
return cells.map((cell) => {
const styles = getComputedStyle(cell);
return {
backgroundColor: styles.backgroundColor,
boxShadow: styles.boxShadow,
};
});
}));
expect(rowVisuals[0]).toEqual(rowVisuals[1]);
await expect(demoGameRow.locator("> .status")).toHaveCount(0);
await expect(demoGameRow.locator("[data-game-toggle='demo-game']")).toHaveAttribute("aria-expanded", "false");
await expect(demoGameRow.locator("[data-game-toggle='demo-game']")).not.toHaveClass(/primary/);
await expect(demoGameRow.locator("[data-game-toggle='demo-game']")).toHaveClass(/\bbtn--compact\b/);
await expect(demoGameRow.locator("[data-game-toggle='demo-game']")).toHaveAttribute("data-game-active", "true");
await expect(demoGameRow.locator("[data-game-toggle='demo-game']")).toHaveAttribute("aria-current", "true");
await expect(page.locator("[data-game-toggle][aria-current='true']")).toHaveCount(1);
await expect(page.locator("[data-game-toggle][data-game-active='true']")).toHaveCount(1);
const activeButtonStyle = await demoGameRow.locator("[data-game-toggle='demo-game']").evaluate((button) => {
const styles = getComputedStyle(button);
return {
backgroundColor: styles.backgroundColor,
borderColor: styles.borderColor,
boxShadow: styles.boxShadow,
};
});
const inactiveButtonStyle = await page.locator("[data-game-row='gravity-demo'] [data-game-toggle='gravity-demo']").evaluate((button) => {
const styles = getComputedStyle(button);
return {
backgroundColor: styles.backgroundColor,
borderColor: styles.borderColor,
boxShadow: styles.boxShadow,
};
});
expect(activeButtonStyle).not.toEqual(inactiveButtonStyle);
await expect(demoGameRow.getByRole("button", { name: "Edit Demo Game" })).toHaveText("Edit");
await expect(demoGameRow.getByRole("button", { name: "Edit Demo Game" })).not.toHaveClass(/primary/);
await expect(demoGameRow.getByRole("button", { name: "Edit Demo Game" })).toHaveClass(/\bbtn--compact\b/);
Expand Down Expand Up @@ -348,7 +372,10 @@ test("Game Hub creates, opens, and deletes mock games", async ({ page }) => {
await addGameRow.getByLabel("Status").selectOption("Ready for Testing");
await addGameRow.getByRole("button", { name: "Save" }).click();
await expect(page.locator("[data-game-list]")).toContainText("Launch Test Game");
await expect(page.locator("[data-game-row='launch-test-game-1']")).toHaveAttribute("data-game-active", "true");
await expect(page.locator("[data-game-row='launch-test-game-1']")).not.toHaveAttribute("data-game-active", "true");
await expect(page.locator("[data-game-row='launch-test-game-1']")).not.toHaveAttribute("aria-current", "true");
await expect(page.locator("[data-game-toggle][aria-current='true']")).toHaveCount(1);
await expect(page.locator("[data-game-row='launch-test-game-1'] [data-game-toggle='launch-test-game-1']")).toHaveAttribute("aria-current", "true");
await expect(page.locator("[data-game-row='launch-test-game-1'] [data-game-toggle='launch-test-game-1']")).not.toHaveClass(/primary/);
await expect(page.locator("[data-game-row='launch-test-game-1']").getByRole("button", { name: "Edit Launch Test Game" })).not.toHaveClass(/primary/);
await expect(page.locator("[data-game-row='launch-test-game-1'] td").nth(0)).toHaveText("Learning Game");
Expand Down Expand Up @@ -376,14 +403,21 @@ test("Game Hub creates, opens, and deletes mock games", async ({ page }) => {
await page.getByRole("button", { name: "Add Game" }).click();
await page.locator("[data-game-add-row='input']").getByLabel("Game").fill("Archive Game");
await page.locator("[data-game-add-row='input']").getByRole("button", { name: "Save" }).click();
await expect(page.locator("[data-game-row='archive-game-2']")).toHaveAttribute("data-game-active", "true");
await expect(page.locator("[data-game-row='archive-game-2']")).not.toHaveAttribute("data-game-active", "true");
await expect(page.locator("[data-game-row='archive-game-2'] [data-game-toggle='archive-game-2']")).toHaveAttribute("aria-current", "true");
await expect(page.locator("[data-game-row='archive-game-2'] [data-game-toggle='archive-game-2']")).not.toHaveClass(/primary/);

await page.locator("[data-game-row='launch-test-game-1'] [data-game-toggle='launch-test-game-1']").click();
await expect(page.locator("[data-game-row='launch-test-game-1']")).toHaveAttribute("data-game-active", "true");
await expect(page.locator("[data-game-row='launch-test-game-1']")).not.toHaveAttribute("data-game-active", "true");
await expect(page.locator("[data-game-row='launch-test-game-1'] [data-game-toggle='launch-test-game-1']")).toHaveAttribute("aria-current", "true");
await expect(page.locator("[data-game-row='archive-game-2'] [data-game-toggle='archive-game-2']")).not.toHaveAttribute("aria-current", "true");
await expect(page.locator("[data-game-toggle][aria-current='true']")).toHaveCount(1);
await expect(page.locator("[data-game-toggle][data-game-active='true']")).toHaveCount(1);
await expect(page.locator("[data-game-expanded-row='launch-test-game-1']")).toHaveCount(2);
await expect(page.locator("[data-game-expanded-row='archive-game-2']")).toHaveCount(0);
await expect(page.locator("[data-game-row='launch-test-game-1'] [data-game-toggle='launch-test-game-1']")).not.toHaveClass(/primary/);
await expect(page.locator("[data-game-row='launch-test-game-1']").getByRole("button", { name: "Edit Launch Test Game" })).not.toHaveClass(/primary/);
await expect(page.locator("[data-game-hub-log]")).toHaveText("Selected Launch Test Game.");
await expect(page.locator("[data-game-hub-log]")).not.toHaveText("Selected Launch Test Game.");

await page.getByRole("button", { name: "Delete Open Game" }).click();
await expect(page.locator("[data-game-row='launch-test-game-1']")).toHaveCount(0);
Expand Down
10 changes: 0 additions & 10 deletions toolbox/game-hub/game-hub.js
Original file line number Diff line number Diff line change
Expand Up @@ -482,16 +482,9 @@ function renderGameParentRow(tbody, game, activeGame, progress) {

const row = document.createElement("tr");
row.dataset.gameRow = game.id;
if (active) {
row.dataset.gameActive = "true";
row.setAttribute("aria-current", "true");
}

const nameCell = document.createElement("th");
nameCell.scope = "row";
if (active) {
nameCell.dataset.gameActiveCell = "true";
}
nameCell.append(createGameToggleButton(game, expanded, active));
row.append(
nameCell,
Expand Down Expand Up @@ -731,9 +724,6 @@ elements.gameList?.addEventListener("click", (event) => {
renderWorkspace();
return;
}
if (game) {
setStatusLog(`Selected ${game.name}.`);
}
state.expandedGameId = state.expandedGameId === toggle.dataset.gameToggle ? "" : toggle.dataset.gameToggle;
renderWorkspace();
return;
Expand Down
Loading