From 3dd77c9e14bc2af6754987b29e6ea0cfb27b51ed Mon Sep 17 00:00:00 2001 From: Alfa Team Date: Thu, 25 Jun 2026 16:29:10 -0400 Subject: [PATCH] Finalize Tool Display Mode single-line layout --- assets/theme-v2/css/accordion.css | 6 +- assets/theme-v2/css/layout.css | 5 +- assets/theme-v2/css/panels.css | 120 ++--- assets/theme-v2/css/status.css | 8 +- assets/theme-v2/js/tool-display-mode.js | 80 +--- ...de-single-line-layout_branch-validation.md | 12 + ...gle-line-layout_manual-validation-notes.md | 22 + ...-display-mode-single-line-layout_report.md | 49 ++ ...ngle-line-layout_requirements-checklist.md | 31 ++ ...mode-single-line-layout_validation-lane.md | 35 ++ .../dev/reports/codex_changed_files.txt | 36 +- docs_build/dev/reports/codex_review.diff | Bin 212382 -> 52543 bytes .../ToolDisplayModeSingleLineLayout.spec.mjs | 419 ++++++++++++++++++ 13 files changed, 634 insertions(+), 189 deletions(-) create mode 100644 docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_branch-validation.md create mode 100644 docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_manual-validation-notes.md create mode 100644 docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_report.md create mode 100644 docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_requirements-checklist.md create mode 100644 docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_validation-lane.md create mode 100644 tests/playwright/tools/ToolDisplayModeSingleLineLayout.spec.mjs diff --git a/assets/theme-v2/css/accordion.css b/assets/theme-v2/css/accordion.css index b650f518e..df65a0332 100644 --- a/assets/theme-v2/css/accordion.css +++ b/assets/theme-v2/css/accordion.css @@ -75,8 +75,7 @@ details.vertical-accordion summary::-webkit-details-marker { } .horizontal-accordion-toggle__icon, -.vertical-accordion__chevron, -.tool-display-mode__chevron { +.vertical-accordion__chevron { --accordion-button-border: var(--line); --accordion-button-background: var(--panel-soft); --accordion-button-color: var(--gold); @@ -109,8 +108,7 @@ details.vertical-accordion summary::-webkit-details-marker { margin-left: auto } -.vertical-accordion__chevron .theme-icon, -.tool-display-mode__chevron .theme-icon { +.vertical-accordion__chevron .theme-icon { height: var(--space-14); width: var(--space-14) } diff --git a/assets/theme-v2/css/layout.css b/assets/theme-v2/css/layout.css index b392b3306..be0dab165 100644 --- a/assets/theme-v2/css/layout.css +++ b/assets/theme-v2/css/layout.css @@ -196,7 +196,6 @@ div { min-width: var(--space-0) } -body.tool-focus-mode .site-header, body.tool-focus-mode .page-title, body.tool-focus-mode .footer { display: none !important @@ -313,6 +312,10 @@ body.tool-focus-mode:has(.tool-workspace--fullscreen-chrome) .site-header { z-index: var(--z-index-lg) } +body.tool-focus-mode .site-header > .container.nav { + display: none !important +} + body.tool-focus-mode:has(.tool-workspace--fullscreen-chrome) .footer { inset-block-end: var(--space-0); inset-inline: var(--space-0); diff --git a/assets/theme-v2/css/panels.css b/assets/theme-v2/css/panels.css index 74f68f0c0..901895252 100644 --- a/assets/theme-v2/css/panels.css +++ b/assets/theme-v2/css/panels.css @@ -274,11 +274,7 @@ body.tool-focus-mode .tool-center-panel:has(>details.vertical-accordion)>p { border-radius: var(--radius-lg); background: var(--panel); box-shadow: var(--shadow-lg); - overflow: hidden; - display: flex; - align-items: center; - justify-content: center; - gap: var(--space-12) + overflow: hidden } .tool-display-mode summary { @@ -286,12 +282,15 @@ body.tool-focus-mode .tool-center-panel:has(>details.vertical-accordion)>p { font-weight: var(--font-weight-heavy); cursor: pointer; list-style: none; - padding: var(--space-10) var(--space-44) var(--space-10) var(--space-10); + padding: var(--space-10); display: flex; align-items: center; - justify-content: center; - gap: var(--space-10); - flex: 0 0 auto + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + gap: var(--space-8) var(--space-10); + min-width: var(--space-0); + width: 100% } .tool-display-mode summary::-webkit-details-marker { @@ -299,20 +298,17 @@ body.tool-focus-mode .tool-center-panel:has(>details.vertical-accordion)>p { } .tool-display-mode__mode-icon { - color: var(--cyan) -} - -.tool-display-mode__chevron { - position: absolute; - right: var(--space-12); - top: 50%; - transform: translateY(-50%); - z-index: var(--z-index-sm) + color: var(--gold); + flex: 0 0 auto; + height: calc(var(--icon-size-sm) * 2.6); + margin-left: auto; + width: calc(var(--icon-size-sm) * 2.6) } .tool-display-mode__badge { - width: 64px; - height: 64px; + flex: 0 0 auto; + width: 128px; + height: 128px; object-fit: contain; object-position: center; border: 0; @@ -320,71 +316,19 @@ body.tool-focus-mode .tool-center-panel:has(>details.vertical-accordion)>p { background: transparent } -.tool-display-mode__body { - display: grid; - grid-template-columns: auto minmax(var(--space-0), 1fr); - grid-template-rows: auto auto; - align-items: center; - column-gap: var(--space-15); - row-gap: var(--space-8); - min-width: var(--space-0); - padding: var(--space-10) var(--space-14) var(--space-10) var(--space-0) -} - -.tool-display-mode__identity-row { - display: contents -} - -.tool-display-mode__navigation-row { - grid-column: 2; - grid-row: 2; - display: flex; - align-items: center; - gap: var(--space-14); - flex-wrap: wrap -} - -.tool-display-mode__navigation-link { - align-items: center; - color: var(--text); - display: inline-flex; - gap: var(--space-6); - line-height: var(--line-height-tight) -} - -.tool-display-mode__navigation-link:hover, -.tool-display-mode__navigation-link:focus-visible { - color: var(--gold) -} - -.tool-display-mode__navigation-link--disabled { - color: var(--muted) -} - -.tool-display-mode__navigation-icon { - color: currentColor -} - .tool-display-mode__character { - grid-column: 1; - grid-row: 1 / span 2; - width: 225px; - height: 127px; + width: min(224px, 100%); + height: auto; object-fit: contain; display: block; - flex: 0 0 auto + flex: 0 0 min(224px, 100%); + min-width: min(144px, 100%) } .tool-display-mode__fullscreen-name { - display: none; - white-space: nowrap -} - -.tool-display-mode__description { - grid-column: 2; - grid-row: 1; - color: var(--gold); - font-weight: var(--font-weight-heavy); + display: inline-flex; + flex: 1 1 4rem; + min-width: var(--space-0); overflow: hidden; text-overflow: ellipsis; white-space: nowrap @@ -393,17 +337,21 @@ body.tool-focus-mode .tool-center-panel:has(>details.vertical-accordion)>p { body.tool-focus-mode .tool-display-mode { border-color: var(--line); background: var(--panel); - box-shadow: var(--shadow-lg); - justify-content: center + box-shadow: var(--shadow-lg) } -body.tool-focus-mode .tool-display-mode__fullscreen-name { - display: inline +body.tool-focus-mode .tool-display-mode__badge { + width: 64px; + height: 64px } -body.tool-focus-mode .tool-display-mode__badge { - width: 32px; - height: 32px +body.tool-focus-mode .tool-display-mode__character { + display: none +} + +body.tool-focus-mode .tool-display-mode__fullscreen-name { + justify-content: center; + text-align: center } .side-menu a { diff --git a/assets/theme-v2/css/status.css b/assets/theme-v2/css/status.css index a82c83065..81af7d308 100644 --- a/assets/theme-v2/css/status.css +++ b/assets/theme-v2/css/status.css @@ -135,11 +135,11 @@ body.tool-focus-mode .toolbox-status-bar { body.tool-focus-mode { --toolbox-status-bar-height: var(--space-52); - --toolbox-status-top-reserve: var(--space-0) + --toolbox-status-top-reserve: var(--space-78) } body.tool-focus-mode:has(.platform-banner) { - --toolbox-status-top-reserve: var(--space-52) + --toolbox-status-top-reserve: var(--space-78) } body.tool-focus-mode .tool-workspace { @@ -165,6 +165,10 @@ body.tool-focus-mode .tool-center-panel { color: var(--text) } +body.tool-focus-mode [data-platform-banner-placement="footer"] { + display: none !important +} + .platform-banner__inner { width: var(--container-width); margin: var(--space-0) auto; diff --git a/assets/theme-v2/js/tool-display-mode.js b/assets/theme-v2/js/tool-display-mode.js index cae5febcf..f35aa06e9 100644 --- a/assets/theme-v2/js/tool-display-mode.js +++ b/assets/theme-v2/js/tool-display-mode.js @@ -73,14 +73,8 @@ document.querySelectorAll("details.vertical-accordion").forEach(wireVerticalAccordionChevron); } - function updateToolDisplayModeChevron() { - const iconName = displayMode.open ? "chevron-up" : "chevron-down"; - const shell = createChevronShell(iconName, "tool-display-mode__chevron", "tool-display-mode__chevron-icon"); - replaceIconNode(summary, ":scope > .tool-display-mode__chevron", shell); - } - function updateToolDisplayModeModeIcon() { - const iconName = document.body.classList.contains("tool-focus-mode") || document.fullscreenElement + const iconName = document.body.classList.contains("tool-focus-mode") ? "exit-fullscreen" : "fullscreen"; const icon = createThemeIconNode(iconName, "layout-icon tool-display-mode__mode-icon"); @@ -107,7 +101,6 @@ function refreshThemeIcons() { refreshVerticalAccordionChevrons(); updateToolDisplayModeModeIcon(); - updateToolDisplayModeChevron(); refreshHorizontalToggleIcons(); } @@ -146,68 +139,24 @@ const summary = document.createElement("summary"); summary.setAttribute("aria-label", "Tool Display Mode"); summary.title = "Tool Display Mode"; - summary.appendChild(createThemeIconNode("fullscreen", "layout-icon tool-display-mode__mode-icon")); const badge = document.createElement("img"); badge.className = "tool-display-mode__badge"; badge.src = publicImageSource(slot.dataset.toolIconSrc, "badges"); badge.alt = toolName + " badge"; - summary.appendChild(badge); const fullscreenName = document.createElement("span"); fullscreenName.className = "tool-display-mode__fullscreen-name"; fullscreenName.textContent = toolName; - summary.appendChild(fullscreenName); - displayMode.appendChild(summary); - displayMode.addEventListener("toggle", updateToolDisplayModeChevron); - - const body = document.createElement("div"); - body.className = "tool-display-mode__body"; - - const identityRow = document.createElement("div"); - identityRow.className = "tool-display-mode__identity-row content-cluster"; - identityRow.dataset.toolDisplayModeRow = "identity"; const character = document.createElement("img"); character.className = "tool-display-mode__character"; character.src = publicImageSource(slot.dataset.toolCharacterSrc, "characters"); character.alt = toolName + " character"; - identityRow.appendChild(character); - - const description = document.createElement("span"); - description.className = "tool-display-mode__description"; - description.textContent = toolName; - identityRow.appendChild(description); - body.appendChild(identityRow); - displayMode.appendChild(body); + summary.append(badge, fullscreenName, character, createThemeIconNode("fullscreen", "layout-icon tool-display-mode__mode-icon")); + displayMode.append(summary); slot.replaceWith(displayMode); - function createNavigationControl(direction, target) { - const controlLabel = direction === "previous" ? "Previous" : "Next"; - const dataAttribute = direction === "previous" ? "toolNavPrevious" : "toolNavNext"; - const iconName = direction === "previous" ? "chevron-left" : "chevron-right"; - const icon = createThemeIconNode(iconName, "layout-icon tool-display-mode__navigation-icon"); - const label = document.createTextNode(controlLabel + ": " + (target?.label || "Unavailable")); - - if (!target || target.disabled) { - const disabledText = document.createElement("span"); - disabledText.className = "pill tool-display-mode__navigation-link tool-display-mode__navigation-link--disabled"; - disabledText.dataset[dataAttribute] = "disabled"; - disabledText.append(icon, label); - return disabledText; - } - - const link = document.createElement("a"); - link.className = "tool-display-mode__navigation-link"; - link.href = target.href; - link.dataset[dataAttribute] = target.kind; - if (target.group) { - link.dataset.toolNavGroup = target.group; - } - link.append(icon, label); - return link; - } - function applyRegistryImages(registry) { const registryTool = registry.getToolBySlug(toolSlug); if (!registryTool) { @@ -240,35 +189,24 @@ badge.alt = registryName + " badge"; fullscreenName.textContent = registryName; character.alt = registryName + " character"; - description.textContent = registryName; badge.src = registry.getToolImageSource(registryTool, "badge"); character.src = registry.getToolImageSource(registryTool, "tool"); } - async function renderToolNavigation() { + async function renderToolDisplayMetadata() { try { const registry = await import("/toolbox/tool-registry-api-client.js"); const registryDiagnostic = registry.getToolRegistryApiDiagnostic(); if (registryDiagnostic) { throw new Error(registryDiagnostic); } - const navigation = registry.getToolNavigationTargets(toolSlug); applyRegistryImages(registry); - const navigationRow = document.createElement("nav"); - navigationRow.className = "tool-display-mode__navigation-row content-cluster"; - navigationRow.dataset.toolDisplayModeRow = "navigation"; - navigationRow.setAttribute("aria-label", "Tool build-order navigation"); - navigationRow.append( - createNavigationControl("previous", navigation.previous), - createNavigationControl("next", navigation.next) - ); - body.appendChild(navigationRow); } catch (error) { - console.warn("Tool navigation could not be loaded.", error); + console.warn("Tool display metadata could not be loaded.", error); } } - renderToolNavigation(); + renderToolDisplayMetadata(); async function enterToolMode() { document.body.classList.add("tool-focus-mode"); @@ -296,6 +234,7 @@ } catch (error) { console.warn("Exit fullscreen failed.", error); } + updateToolDisplayModeModeIcon(); } summary.addEventListener("click", function (event) { @@ -309,15 +248,14 @@ }); document.addEventListener("fullscreenchange", function () { - if (!document.fullscreenElement && document.body.classList.contains("tool-focus-mode")) { + if (!document.fullscreenElement) { document.body.classList.remove("tool-focus-mode"); displayMode.open = true; - refreshThemeIcons(); } + refreshThemeIcons(); }); refreshVerticalAccordionChevrons(); - updateToolDisplayModeChevron(); document.querySelectorAll(".tool-workspace").forEach(function (workspace) { const columns = workspace.querySelectorAll(":scope > .tool-column"); diff --git a/docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_branch-validation.md b/docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_branch-validation.md new file mode 100644 index 000000000..9ae1a604c --- /dev/null +++ b/docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_branch-validation.md @@ -0,0 +1,12 @@ +# PR_26176_005 Branch Validation + +| Check | Status | Notes | +| --- | --- | --- | +| Active branch is `PR_26176_005-tool-display-mode-single-line-layout` | PASS | Confirmed with `git branch --show-current`. | +| Worktree reviewed before final packaging | PASS | Modified and untracked files were reviewed before report/ZIP regeneration. | +| No `PR_26176_006` branch created | PASS | User explicitly cancelled stacked PR creation; this pass stayed on PR_26176_005. | +| No `PR_26176_007` branch created | PASS | User explicitly cancelled stacked PR creation; this pass stayed on PR_26176_005. | +| Accidental/unneeded PR_26176_001-004 artifacts removed | PASS | Untracked PR_26176_001 through PR_26176_004 report files were deleted from the worktree. | +| Remaining changed files are PR_26176_005 scoped | PASS | Final changed-files report lists shared Tool Display Mode/layout code, focused Tool Display Mode validation, and required PR_26176_005 reports. | +| Fullscreen platform banner correction stayed in PR_26176_005 | PASS | Shared CSS keeps the header placement banner visible and hides only `[data-platform-banner-placement="footer"]` in focus mode. | +| Game Journey completion metrics storage warning handled | PASS | No SQLite/Postgres behavior changed; warning documented as Golf-owned external storage migration work. | diff --git a/docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_manual-validation-notes.md b/docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_manual-validation-notes.md new file mode 100644 index 000000000..5ca28c801 --- /dev/null +++ b/docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_manual-validation-notes.md @@ -0,0 +1,22 @@ +# PR_26176_005 Manual Validation Notes + +## Manual Review +- Confirmed the active branch is `PR_26176_005-tool-display-mode-single-line-layout`. +- Reviewed modified and untracked files and removed accidental/unneeded PR_26176_001 through PR_26176_004 untracked report artifacts. +- Reviewed `assets/theme-v2/js/tool-display-mode.js` to confirm the shared summary template directly renders badge, title, character image, and mode icon. +- Reviewed `assets/theme-v2/css/panels.css`, `accordion.css`, `layout.css`, and `status.css` for shared-only Tool Display Mode/layout changes. +- Confirmed no individual toolbox pages were modified. + +## Observations +- The shared Tool Display Mode no longer renders the navigation row or `Previous:` / `Next:` labels. +- The fullscreen/exit icon remains the final direct child of ``, uses the shared theme icon registry, and returns to the fullscreen SVG after exiting focus mode. +- Normal mode displays both shared platform banner placements, header and footer, including the `Development Environment` message. +- Fullscreen mode keeps the site header and header-placement platform banner visible, including `.platform-banner__inner` and the `Development Environment` message. +- Fullscreen mode hides the footer-placement platform banner using `[data-platform-banner-placement="footer"]`. +- Shared fullscreen CSS does not target `.platform-banner__inner` because both placement banners use the same inner structure. +- Fullscreen mode hides the main `.site-header > div.container.nav` navigation container, including the brand/home navigation. +- At the focused desktop Playwright width, the badge, title, character image, and fullscreen icon stay on one visual row without overlap or clipping. +- Normal mode renders the shared character image at 224px wide with `height: auto`, and the badge at 128x128. +- Fullscreen mode hides the shared character image, renders the badge at 64x64, centers the growing tool name, and keeps the exit-fullscreen icon anchored to the far right. +- Older PR_26176_001/002 horizontal accordion color and footer status icon validation/styling were removed from this branch during final cleanup. +- Game Journey completion metrics SQLite/Postgres behavior was not changed; the warning is Golf-owned external storage migration work outside this PR. diff --git a/docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_report.md b/docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_report.md new file mode 100644 index 000000000..63f915949 --- /dev/null +++ b/docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_report.md @@ -0,0 +1,49 @@ +# PR_26176_005-tool-display-mode-single-line-layout Report + +## Scope Source +- Active request: finalize existing branch `PR_26176_005-tool-display-mode-single-line-layout`. +- Branch gate: current branch confirmed as `PR_26176_005-tool-display-mode-single-line-layout`; no `PR_26176_006` or `PR_26176_007` branch was created. +- Worktree review: modified and untracked files were reviewed; accidental/unneeded `PR_26176_001` through `PR_26176_004` untracked report artifacts were removed. +- Note: `docs_build/dev/BUILD_PR.md` still describes `PR_26175_ALFA_047-theme-v2-svg-icon-registry`, so the user prompt was treated as the operative BUILD scope for this PR. + +## Summary +- Updated the shared Tool Display Mode template so the `` directly owns the badge, tool name, character image, and fullscreen/exit-fullscreen icon in that order. +- Kept the fullscreen/exit-fullscreen theme icon as the final direct child of ``, gold, 2.6x the base layout icon, and anchored to the far right with `margin-left: auto`. +- Removed the old Tool Display Mode chevron, stacked body/identity/description layout, and rendered navigation row UI. +- Removed `nav.tool-display-mode__navigation-row`, `Previous: {tool}`, `Next: {tool}`, and CSS/JS used solely to render or populate that row. +- Normal mode now displays both shared platform banner placements, `data-platform-banner-placement="header"` and `data-platform-banner-placement="footer"`. +- Fullscreen mode keeps the header-placement platform banner visible, including `.platform-banner__inner` and the `Development Environment` message. +- Fullscreen mode hides the footer-placement platform banner with `data-platform-banner-placement="footer"`. +- Fullscreen mode hides the main site navigation container, `.site-header > div.container.nav`, including the brand/home navigation. +- Shared fullscreen CSS targets the banner placement attribute and does not target `.platform-banner__inner`. +- Fullscreen mode hides the character image, renders the badge at 64x64, centers the growing tool name, and keeps the exit icon anchored far right. +- Narrowed the focused Playwright validation to Tool Display Mode behavior only and renamed it to `ToolDisplayModeSingleLineLayout.spec.mjs`. +- Removed older PR_26176_001/002 validation assertions and style changes for horizontal accordion color and footer status icon sizing from this branch. + +## Changed Files +- `assets/theme-v2/js/tool-display-mode.js` +- `assets/theme-v2/css/accordion.css` +- `assets/theme-v2/css/layout.css` +- `assets/theme-v2/css/panels.css` +- `assets/theme-v2/css/status.css` +- `tests/playwright/tools/ToolDisplayModeSingleLineLayout.spec.mjs` +- `docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_report.md` +- `docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_branch-validation.md` +- `docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_validation-lane.md` +- `docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_requirements-checklist.md` +- `docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_manual-validation-notes.md` +- `docs_build/dev/reports/codex_changed_files.txt` +- `docs_build/dev/reports/codex_review.diff` + +## Validation +- `node --check assets/theme-v2/js/tool-display-mode.js` +- `node --check tests/playwright/tools/ToolDisplayModeSingleLineLayout.spec.mjs` +- `npx playwright test tests/playwright/tools/ToolDisplayModeSingleLineLayout.spec.mjs --workers=1` +- `git diff --check` + +## Notes +- No individual toolbox pages were modified. +- The previous fullscreen rule that hid `.platform-banner__inner` was removed. +- No `PR_26176_006` or `PR_26176_007` branch/artifact was created during this finalization pass. +- Game Journey completion metrics SQLite/Postgres behavior was not changed; that warning is documented as Golf-owned external storage migration work outside this PR. +- The focused Playwright run uses deterministic route fixtures for public config, platform banner settings, registry metadata, game-design constants, and minimal game-design repository calls. diff --git a/docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_requirements-checklist.md b/docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_requirements-checklist.md new file mode 100644 index 000000000..5fe70f5a0 --- /dev/null +++ b/docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_requirements-checklist.md @@ -0,0 +1,31 @@ +# PR_26176_005 Requirements Checklist + +| Requirement | Status | Evidence | +| --- | --- | --- | +| Continue only on `PR_26176_005-tool-display-mode-single-line-layout` | PASS | Branch confirmed before cleanup and validation. | +| Do not create `PR_26176_006` or `PR_26176_007` | PASS | No new branch was created during finalization. | +| Review modified and untracked files | PASS | Dirty set was reviewed; final dirty set is scoped to PR_26176_005 files. | +| Remove accidental/unneeded PR_26176_001-004 artifacts | PASS | Untracked PR_26176_001 through PR_26176_004 report files were removed. | +| Preserve PR_26176_005 reports/specs | PASS | PR_26176_005 report, checklist, validation lane, branch validation, manual notes, diff, changed-files list, and focused spec were updated. | +| Use shared Theme V2/tool display CSS/JS only unless required | PASS | Runtime changes are limited to shared Theme V2 CSS and `tool-display-mode.js`; no individual toolbox pages changed. | +| Badge, title, character/image content, and fullscreen/exit icon align in one horizontal row where practical | PASS | Playwright geometry asserts one visual row at the focused desktop width with no overlap or clipping. | +| Fullscreen/exit icon remains anchored far right | PASS | Shared CSS uses `margin-left: auto`; Playwright verifies right-edge anchoring in normal, fullscreen, and restored states. | +| Remove old Tool Display Mode chevron | PASS | JS no longer renders `.tool-display-mode__chevron`; obsolete CSS selectors were removed. | +| Remove `nav.tool-display-mode__navigation-row` from all toolbox pages | PASS | Shared component no longer creates the navigation row. | +| Remove rendered `Previous: {tool}` and `Next: {tool}` UI | PASS | Playwright and static assertions verify those labels are not rendered by Tool Display Mode. | +| Remove CSS/JS used solely for the navigation row | PASS | Shared navigation-row, navigation-link, navigation-icon CSS and JS construction were removed. | +| Normal mode displays both platform banner placements | PASS | Playwright verifies header and footer `data-platform-banner-placement` banners are visible in normal mode. | +| Fullscreen keeps header-placement platform banner visible | PASS | Playwright verifies the header-placement banner, `.platform-banner__inner`, and `Development Environment` remain visible in focus mode. | +| Fullscreen hides footer-placement platform banner | PASS | Shared focus CSS targets `[data-platform-banner-placement="footer"]`; Playwright verifies the footer-placement banner is `display: none` in focus mode. | +| Fullscreen hides main site navigation container | PASS | Shared focus CSS hides `.site-header > div.container.nav`; Playwright verifies it is `display: none` in focus mode. | +| Do not target `.platform-banner__inner` for fullscreen banner hiding | PASS | Shared status CSS no longer contains a focus-mode rule for `.platform-banner__inner`; the footer placement is targeted by data attribute instead. | +| Normal mode character image renders at final requested size with aspect ratio preserved | PASS | Playwright verifies the character image is 224px wide with natural aspect ratio. | +| Normal mode badge is larger | PASS | Playwright verifies the badge is 128x128. | +| Fullscreen hides character image | PASS | Playwright verifies `.tool-display-mode__character` is not displayed in focus mode. | +| Fullscreen badge remains larger than the original focus badge | PASS | Playwright verifies the focus badge is 64x64. | +| Fullscreen badge left, tool name centered/growing, exit icon far right | PASS | Playwright verifies badge left alignment, centered title styling, flex growth, and icon right anchoring. | +| Preserve fullscreen icon state restoration | PASS | Playwright verifies the icon switches to exit-fullscreen in focus mode and returns to fullscreen after exit. | +| Do not change Game Journey completion metrics SQLite/Postgres behavior | PASS | No storage/runtime metrics files were changed; warning is documented as Golf-owned external storage migration work. | +| No unrelated cleanup | PASS | Older accordion color/footer status icon changes were removed from this branch; only PR_26176_005 files remain. | +| Produce reports under `docs_build/dev/reports/` | PASS | Required PR_26176_005 reports were generated/updated. | +| Produce repo-structured ZIP under `tmp/` | PASS | `tmp/PR_26176_005-tool-display-mode-single-line-layout_delta.zip` generated after validation. | diff --git a/docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_validation-lane.md b/docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_validation-lane.md new file mode 100644 index 000000000..1b1c467c9 --- /dev/null +++ b/docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_validation-lane.md @@ -0,0 +1,35 @@ +# PR_26176_005 Validation Lane + +## Commands + +```powershell +node --check assets/theme-v2/js/tool-display-mode.js +node --check tests/playwright/tools/ToolDisplayModeSingleLineLayout.spec.mjs +npx playwright test tests/playwright/tools/ToolDisplayModeSingleLineLayout.spec.mjs --workers=1 +git diff --check +``` + +## Results +- `node --check assets/theme-v2/js/tool-display-mode.js`: PASS. +- `node --check tests/playwright/tools/ToolDisplayModeSingleLineLayout.spec.mjs`: PASS. +- `npx playwright test tests/playwright/tools/ToolDisplayModeSingleLineLayout.spec.mjs --workers=1`: PASS, `1 passed`. +- `git diff --check`: PASS. + +## Browser Coverage +- Loaded `/toolbox/game-design/index.html`. +- Used deterministic Playwright route fixtures for public config environment banner, platform banner settings, game-design constants, registry metadata, and minimal repository responses. +- Verified normal mode displays both shared platform banner placements, `data-platform-banner-placement="header"` and `data-platform-banner-placement="footer"`. +- Verified the header and footer placement banners both carry the `Development Environment` message in normal mode. +- Verified normal mode keeps `.site-header > div.container.nav` visible. +- Verified fullscreen mode keeps `header.site-header` and the header-placement platform banner visible, including `.platform-banner__inner` and `Development Environment`. +- Verified fullscreen mode hides the footer-placement platform banner with `[data-platform-banner-placement="footer"]`. +- Verified fullscreen mode hides `.site-header > div.container.nav`, including the brand/home navigation. +- Verified shared status CSS targets `[data-platform-banner-placement="footer"]` and no longer contains a focus-mode rule that hides `.platform-banner__inner`. +- Verified exiting fullscreen restores the complete platform banner and returns the icon to `fullscreen`. +- Verified Tool Display Mode summary children are badge, tool name, character image, and fullscreen/exit icon in that order. +- Verified the fullscreen/exit icon is gold, 2.6x the base layout icon, and anchored to the far right using shared flexbox. +- Verified normal mode badge is 128x128 and character image is 224px wide with natural aspect ratio. +- Verified fullscreen mode hides the character image, keeps the badge visible at 64x64, centers/grows the title, and anchors the exit icon far right. +- Verified the row is a single visual line at the focused desktop width with no overlap or clipping. +- Verified `nav.tool-display-mode__navigation-row`, `Previous: {tool}`, and `Next: {tool}` are not rendered. +- Verified shared CSS/JS no longer contain the removed Tool Display Mode navigation/body/description selectors or navigation construction helpers. diff --git a/docs_build/dev/reports/codex_changed_files.txt b/docs_build/dev/reports/codex_changed_files.txt index 4cb4ab3d9..4694f15e5 100644 --- a/docs_build/dev/reports/codex_changed_files.txt +++ b/docs_build/dev/reports/codex_changed_files.txt @@ -1,27 +1,13 @@ -assets/theme-v2/js/gamefoundry-partials.js -assets/theme-v2/js/legal-document-page.js -assets/theme-v2/partials/footer.html -docs_build/dev/reports/PR_26175_OWNER_054-legal-corrected-package.md +assets/theme-v2/css/accordion.css +assets/theme-v2/css/layout.css +assets/theme-v2/css/panels.css +assets/theme-v2/css/status.css +assets/theme-v2/js/tool-display-mode.js +tests/playwright/tools/ToolDisplayModeSingleLineLayout.spec.mjs +docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_report.md +docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_branch-validation.md +docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_validation-lane.md +docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_requirements-checklist.md +docs_build/dev/reports/PR_26176_005-tool-display-mode-single-line-layout_manual-validation-notes.md docs_build/dev/reports/codex_changed_files.txt docs_build/dev/reports/codex_review.diff -docs_build/dev/reports/coverage_changed_js_guardrail.txt -docs_build/dev/reports/playwright_v8_coverage_report.txt -legal/community-guidelines.html -legal/community-guidelines.md -legal/cookie-policy.html -legal/cookie-policy.md -legal/cookies-policy.html -legal/copyright-policy.html -legal/copyright-policy.md -legal/disclaimer.html -legal/dmca-policy.html -legal/dmca-policy.md -legal/index.html -legal/index.md -legal/legal-nav.js -legal/privacy-policy.html -legal/privacy-policy.md -legal/terms.html -legal/terms-of-service.html -legal/terms-of-service.md -tests/playwright/tools/RemainingLegalPages.spec.mjs \ No newline at end of file diff --git a/docs_build/dev/reports/codex_review.diff b/docs_build/dev/reports/codex_review.diff index fdfeac55a30526c21627c2184b6692766d4426d7..84053786ac371d3208abd0b6f4105dca06b7e9d8 100644 GIT binary patch literal 52543 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 TbXg~Y2(?9^FhM@&{KfwTVHhb4 literal 212382 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 { + pageErrors.push(error.message); + }); + + await page.route("**/api/toolbox/game-design/constants", async (route) => { + await route.fulfill({ json: { data: GAME_DESIGN_CONSTANTS, ok: true } }); + }); + await page.route("**/api/public/config", async (route) => { + await route.fulfill({ + json: { + data: { + environmentBanner: { + active: true, + message: "Development Environment", + tone: "warning", + }, + publicConfig: {}, + }, + ok: true, + }, + }); + }); + await page.route("**/api/platform-settings/banner", async (route) => { + await route.fulfill({ + json: { + data: { + banner: { + active: false, + message: "", + tone: "info", + }, + diagnostics: { active: false }, + }, + ok: true, + }, + }); + }); + await page.route("**/api/toolbox/registry/snapshot", async (route) => { + await route.fulfill({ json: { data: TOOL_REGISTRY_SNAPSHOT, ok: true } }); + }); + await page.route("**/api/toolbox/game-design/repositories", async (route) => { + await route.fulfill({ json: { data: { repositoryId: "tool-display-mode-fixture" }, ok: true } }); + }); + await page.route("**/api/toolbox/game-design/repositories/**/methods/**", async (route) => { + const methodName = decodeURIComponent(route.request().url().split("/methods/").pop() || ""); + const resultByMethod = { + getSnapshot: GAME_DESIGN_SNAPSHOT, + openGameContext: { message: "Opened fixture game." }, + saveDesign: { message: "Saved fixture design." }, + validateDesign: GAME_DESIGN_VALIDATION, + }; + await route.fulfill({ + json: { + data: { result: resultByMethod[methodName] || null }, + ok: true, + }, + }); + }); + + await page.goto(`${server.baseUrl}${pathName}`, { waitUntil: "networkidle" }); + return { pageErrors, server }; +} + +function expectNoRuntimeErrors(failures) { + expect(failures.pageErrors).toEqual([]); +} + +async function platformBannerSnapshot(page) { + await expect(page.locator("header.site-header")).toBeVisible(); + await expect(page.locator("[data-platform-banner-source='environment-config'][data-platform-banner-placement='header']")).toHaveCount(1); + await expect(page.locator("[data-platform-banner-source='environment-config'][data-platform-banner-placement='footer']")).toHaveCount(1); + return page.evaluate(() => { + const header = document.querySelector("header.site-header"); + const headerBanner = document.querySelector("[data-platform-banner-source='environment-config'][data-platform-banner-placement='header']"); + const footerBanner = document.querySelector("[data-platform-banner-source='environment-config'][data-platform-banner-placement='footer']"); + const headerInner = headerBanner?.querySelector(".platform-banner__inner") || null; + const headerMessage = headerBanner?.querySelector(".platform-banner__message") || null; + const footerMessage = footerBanner?.querySelector(".platform-banner__message") || null; + const nav = header?.querySelector(":scope > .container.nav") || null; + const headerBox = header?.getBoundingClientRect(); + const headerBannerBox = headerBanner?.getBoundingClientRect(); + const footerBannerBox = footerBanner?.getBoundingClientRect(); + const headerInnerBox = headerInner?.getBoundingClientRect(); + const navBox = nav?.getBoundingClientRect(); + return { + footerBannerDisplay: footerBanner ? getComputedStyle(footerBanner).display : "", + footerBannerHeight: Number((footerBannerBox?.height || 0).toFixed(2)), + footerBannerVisible: Boolean(footerBannerBox && footerBannerBox.width > 0 && footerBannerBox.height > 0), + footerMessageText: footerMessage?.textContent?.trim() || "", + headerBannerDisplay: headerBanner ? getComputedStyle(headerBanner).display : "", + headerBannerHeight: Number((headerBannerBox?.height || 0).toFixed(2)), + headerBannerVisible: Boolean(headerBannerBox && headerBannerBox.width > 0 && headerBannerBox.height > 0), + headerVisible: Boolean(headerBox && headerBox.width > 0 && headerBox.height > 0), + headerInnerDisplay: headerInner ? getComputedStyle(headerInner).display : "", + headerInnerHeight: Number((headerInnerBox?.height || 0).toFixed(2)), + headerInnerVisible: Boolean(headerInnerBox && headerInnerBox.width > 0 && headerInnerBox.height > 0), + headerMessageText: headerMessage?.textContent?.trim() || "", + navDisplay: nav ? getComputedStyle(nav).display : "", + navVisible: Boolean(navBox && navBox.width > 0 && navBox.height > 0), + }; + }); +} + +async function expectPlatformBannerMode(page, { focusMode }) { + const snapshot = await platformBannerSnapshot(page); + expect(snapshot.headerVisible).toBe(true); + expect(snapshot.headerBannerDisplay).toBe("block"); + expect(snapshot.headerBannerVisible).toBe(true); + expect(snapshot.headerMessageText).toBe("Development Environment"); + expect(snapshot.headerInnerDisplay).toBe("flex"); + expect(snapshot.headerInnerHeight).toBeGreaterThan(0); + expect(snapshot.headerInnerVisible).toBe(true); + expect(snapshot.footerMessageText).toBe("Development Environment"); + if (focusMode) { + expect(snapshot.footerBannerDisplay).toBe("none"); + expect(snapshot.footerBannerHeight).toBe(0); + expect(snapshot.footerBannerVisible).toBe(false); + expect(snapshot.navDisplay).toBe("none"); + expect(snapshot.navVisible).toBe(false); + } else { + expect(snapshot.footerBannerDisplay).toBe("block"); + expect(snapshot.footerBannerHeight).toBeGreaterThan(0); + expect(snapshot.footerBannerVisible).toBe(true); + expect(snapshot.navDisplay).toBe("flex"); + expect(snapshot.navVisible).toBe(true); + } +} + +async function toolDisplayControlSnapshot(page) { + return page.locator("#toolDisplayMode").evaluate((displayMode) => { + const summary = displayMode.querySelector("summary"); + const badge = summary.querySelector(".tool-display-mode__badge"); + const fullscreenName = summary.querySelector(".tool-display-mode__fullscreen-name"); + const character = summary.querySelector(".tool-display-mode__character"); + const modeIcon = summary.querySelector(".tool-display-mode__mode-icon"); + const baseIcon = document.createElement("span"); + baseIcon.className = "layout-icon"; + baseIcon.style.display = "inline-block"; + baseIcon.style.position = "absolute"; + baseIcon.style.visibility = "hidden"; + const goldProbe = document.createElement("span"); + goldProbe.style.color = "var(--gold)"; + goldProbe.style.position = "absolute"; + goldProbe.style.visibility = "hidden"; + document.body.append(baseIcon, goldProbe); + + const displayModeBox = displayMode.getBoundingClientRect(); + const summaryBox = summary.getBoundingClientRect(); + const badgeBox = badge.getBoundingClientRect(); + const nameBox = fullscreenName.getBoundingClientRect(); + const characterBox = character.getBoundingClientRect(); + const iconBox = modeIcon.getBoundingClientRect(); + const baseBox = baseIcon.getBoundingClientRect(); + const summaryStyle = getComputedStyle(summary); + const summaryContentRight = summaryBox.right - (parseFloat(summaryStyle.paddingRight) || 0); + const summaryContentBox = { + bottom: summaryBox.bottom - (parseFloat(summaryStyle.paddingBottom) || 0), + left: summaryBox.left + (parseFloat(summaryStyle.paddingLeft) || 0), + right: summaryBox.right - (parseFloat(summaryStyle.paddingRight) || 0), + top: summaryBox.top + (parseFloat(summaryStyle.paddingTop) || 0), + }; + const characterStyle = getComputedStyle(character); + const characterVisible = characterStyle.display !== "none" && characterBox.width > 0 && characterBox.height > 0; + const contentBoxes = [badgeBox, nameBox, iconBox]; + if (characterVisible) { + contentBoxes.splice(2, 0, characterBox); + } + const boxesOverlap = (first, second) => !( + first.right <= second.left || + second.right <= first.left || + first.bottom <= second.top || + second.bottom <= first.top + ); + const contentContained = contentBoxes.every((box) => ( + box.left >= summaryContentBox.left - 1 && + box.right <= summaryContentBox.right + 1 && + box.top >= summaryContentBox.top - 1 && + box.bottom <= summaryContentBox.bottom + 1 + )); + const contentDoesNotOverlap = contentBoxes.every((box, index) => ( + contentBoxes.slice(index + 1).every((otherBox) => !boxesOverlap(box, otherBox)) + )); + const characterNaturalRatio = character.naturalWidth / character.naturalHeight; + const sameVisualRow = contentBoxes.every((box) => { + const itemCenter = box.top + (box.height / 2); + const iconCenter = iconBox.top + (iconBox.height / 2); + return Math.abs(itemCenter - iconCenter) <= 4; + }); + const result = { + badgeHeight: Number(badgeBox.height.toFixed(2)), + badgeLeftAligned: Math.abs(badgeBox.left - summaryContentBox.left) <= 1, + badgeWidth: Number(badgeBox.width.toFixed(2)), + characterAfterName: characterBox.left >= nameBox.right - 1, + characterDisplay: characterStyle.display, + characterHeight: Number(characterBox.height.toFixed(2)), + characterNaturalRatio: Number(characterNaturalRatio.toFixed(2)), + characterRatio: Number((characterBox.width / characterBox.height).toFixed(2)), + characterVisible, + characterWidth: Number(characterBox.width.toFixed(2)), + chevronCount: summary.querySelectorAll(".tool-display-mode__chevron").length, + contentContained, + contentDoesNotOverlap, + controlRightAligned: Math.abs(summaryBox.right - displayModeBox.right) <= 3, + displayModeChildren: Array.from(displayMode.children).map((child) => child.tagName.toLowerCase()), + fullscreenNameDisplay: getComputedStyle(fullscreenName).display, + fullscreenNameFlexGrow: getComputedStyle(fullscreenName).flexGrow, + fullscreenNameJustifyContent: getComputedStyle(fullscreenName).justifyContent, + fullscreenNameMinWidth: getComputedStyle(fullscreenName).minWidth, + fullscreenNameTextAlign: getComputedStyle(fullscreenName).textAlign, + goldColor: getComputedStyle(goldProbe).color, + iconColor: getComputedStyle(modeIcon).color, + iconFile: modeIcon.dataset.themeIconFile, + iconHeightScale: Number((iconBox.height / baseBox.height).toFixed(2)), + iconName: modeIcon.dataset.themeIcon, + iconAnchoredToSummaryRight: Math.abs(iconBox.right - summaryContentRight) <= 3, + iconWidthScale: Number((iconBox.width / baseBox.width).toFixed(2)), + navigationRowCount: summary.querySelectorAll(".tool-display-mode__navigation-row").length, + navigationTextRemoved: !/Previous:|Next:/.test(summary.textContent || ""), + sameVisualRow, + summaryDisplay: summaryStyle.display, + summaryFlexDirection: summaryStyle.flexDirection, + summaryFlexWrap: summaryStyle.flexWrap, + summaryChildren: Array.from(summary.children).map((child) => ({ + className: child.className, + tagName: child.tagName.toLowerCase(), + themeIcon: child.dataset.themeIcon || "", + })), + summaryOrder: getComputedStyle(summary).order, + }; + + baseIcon.remove(); + goldProbe.remove(); + return result; + }); +} + +async function expectToolDisplayControl(page, { badgeSize, characterVisible, characterWidth = 0, focusMode = false, iconFile, iconName }) { + await expect(page.locator("#toolDisplayMode summary .tool-display-mode__navigation-row")).toHaveCount(0); + await expect(page.locator("#toolDisplayMode summary")).not.toContainText(/Previous:|Next:/); + const snapshot = await toolDisplayControlSnapshot(page); + expect(snapshot.badgeHeight).toBeCloseTo(badgeSize, 0); + expect(snapshot.badgeLeftAligned).toBe(true); + expect(snapshot.badgeWidth).toBeCloseTo(badgeSize, 0); + expect(snapshot.characterVisible).toBe(characterVisible); + if (characterVisible) { + expect(snapshot.characterDisplay).toBe("block"); + expect(snapshot.characterHeight).toBeCloseTo(characterWidth / snapshot.characterNaturalRatio, 0); + expect(snapshot.characterRatio).toBeCloseTo(snapshot.characterNaturalRatio, 1); + expect(snapshot.characterWidth).toBeCloseTo(characterWidth, 0); + } else { + expect(snapshot.characterDisplay).toBe("none"); + expect(snapshot.characterHeight).toBe(0); + expect(snapshot.characterWidth).toBe(0); + } + expect(snapshot.chevronCount).toBe(0); + expect(snapshot.contentContained).toBe(true); + expect(snapshot.contentDoesNotOverlap).toBe(true); + expect(snapshot.controlRightAligned).toBe(true); + expect(snapshot.displayModeChildren).toEqual(["summary"]); + expect(snapshot.fullscreenNameDisplay).toBe("flex"); + expect(snapshot.fullscreenNameFlexGrow).toBe("1"); + expect(snapshot.fullscreenNameMinWidth).toBe("0px"); + if (focusMode) { + expect(snapshot.fullscreenNameJustifyContent).toBe("center"); + expect(snapshot.fullscreenNameTextAlign).toBe("center"); + } + expect(snapshot.iconColor).toBe(snapshot.goldColor); + expect(snapshot.iconFile).toBe(iconFile); + expect(snapshot.iconName).toBe(iconName); + expect(snapshot.iconAnchoredToSummaryRight).toBe(true); + expect(snapshot.iconHeightScale).toBeGreaterThanOrEqual(2.55); + expect(snapshot.iconHeightScale).toBeLessThanOrEqual(2.65); + expect(snapshot.iconWidthScale).toBeGreaterThanOrEqual(2.55); + expect(snapshot.iconWidthScale).toBeLessThanOrEqual(2.65); + expect(snapshot.navigationRowCount).toBe(0); + expect(snapshot.navigationTextRemoved).toBe(true); + expect(snapshot.sameVisualRow).toBe(true); + expect(snapshot.summaryDisplay).toBe("flex"); + expect(snapshot.summaryFlexDirection).toBe("row"); + expect(snapshot.summaryFlexWrap).toBe("wrap"); + expect(snapshot.summaryChildren).toEqual([ + { className: "tool-display-mode__badge", tagName: "img", themeIcon: "" }, + { className: "tool-display-mode__fullscreen-name", tagName: "span", themeIcon: "" }, + { className: "tool-display-mode__character", tagName: "img", themeIcon: "" }, + { + className: `theme-icon theme-icon--${iconName} layout-icon tool-display-mode__mode-icon`, + tagName: "span", + themeIcon: iconName, + }, + ]); + expect(snapshot.summaryOrder).toBe("0"); +} + +async function expectModeIconUsesAutoMargin() { + const css = await fs.readFile("assets/theme-v2/css/panels.css", "utf8"); + const layoutCss = await fs.readFile("assets/theme-v2/css/layout.css", "utf8"); + const statusCss = await fs.readFile("assets/theme-v2/css/status.css", "utf8"); + const js = await fs.readFile("assets/theme-v2/js/tool-display-mode.js", "utf8"); + expect(css).toMatch(/\.tool-display-mode__mode-icon\s*{[^}]*margin-left:\s*auto;/s); + expect(css).not.toMatch(/\.tool-display-mode__(body|identity-row|description|navigation-row|navigation-link|navigation-icon)\b/); + expect(layoutCss).toMatch(/body\.tool-focus-mode\s+\.site-header\s*>\s*\.container\.nav\s*{[^}]*display:\s*none\s*!important/s); + expect(statusCss).not.toMatch(/tool-focus-mode\s+\.platform-banner__inner/); + expect(statusCss).toMatch(/body\.tool-focus-mode\s+\[data-platform-banner-placement="footer"\]\s*{[^}]*display:\s*none\s*!important/s); + expect(js).not.toMatch(/tool-display-mode__navigation-row|Previous:|Next:|getToolNavigationTargets|createNavigationControl/); +} + +test("shared Tool Display Mode uses the final single-line layout behavior", async ({ page }) => { + const failures = await openRepoPage(page, "/toolbox/game-design/index.html"); + + try { + await expectPlatformBannerMode(page, { focusMode: false }); + await expect(page.locator("#toolDisplayMode summary [data-theme-icon='fullscreen']")).toBeVisible(); + await expectToolDisplayControl(page, { + badgeSize: 128, + characterVisible: true, + characterWidth: 224, + iconFile: "gfs-fullscreen.svg", + iconName: "fullscreen", + }); + await expectModeIconUsesAutoMargin(); + + await page.locator("#toolDisplayMode summary").click(); + await expect(page.locator("body")).toHaveClass(/tool-focus-mode/); + await expectPlatformBannerMode(page, { focusMode: true }); + await expectToolDisplayControl(page, { + badgeSize: 64, + characterVisible: false, + focusMode: true, + iconFile: "gfs-exit-fullscreen.svg", + iconName: "exit-fullscreen", + }); + + await page.locator("#toolDisplayMode summary").click(); + await expect(page.locator("body")).not.toHaveClass(/tool-focus-mode/); + await expectPlatformBannerMode(page, { focusMode: false }); + await expectToolDisplayControl(page, { + badgeSize: 128, + characterVisible: true, + characterWidth: 224, + iconFile: "gfs-fullscreen.svg", + iconName: "fullscreen", + }); + + expectNoRuntimeErrors(failures); + } finally { + await failures.server.close(); + } +});