Skip to content
Merged
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
8 changes: 7 additions & 1 deletion assets/theme-v2/css/buttons.css
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,16 @@
transition: opacity var(--transition-duration-fast) ease, transform var(--transition-duration-fast) ease, color var(--transition-duration-fast) ease, border-color var(--transition-duration-fast) ease, background var(--transition-duration-fast) ease
}

.return-to-top span {
.return-to-top span,
.return-to-top__icon {
transform: translateY(var(--return-to-top-glyph-shift))
}

.return-to-top__icon {
height: var(--icon-size-sm);
width: var(--icon-size-sm)
}

.return-to-top.is-visible {
opacity: 1;
pointer-events: auto;
Expand Down
5 changes: 5 additions & 0 deletions assets/theme-v2/css/icons.css
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@
--theme-v2-icon-url: url("/assets/theme-v2/svg/gfs-warning.svg")
}

.layout-icon {
height: var(--icon-size-sm);
width: var(--icon-size-sm)
}

.status-icon {
height: var(--icon-size-sm);
width: var(--icon-size-sm)
Expand Down
25 changes: 25 additions & 0 deletions assets/theme-v2/css/panels.css
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,10 @@ body.tool-focus-mode .tool-center-panel:has(>details.vertical-accordion)>p {
display: none
}

.tool-display-mode__mode-icon {
color: var(--cyan)
}

.tool-display-mode__chevron {
position: absolute;
right: var(--space-12);
Expand Down Expand Up @@ -340,6 +344,27 @@ body.tool-focus-mode .tool-center-panel:has(>details.vertical-accordion)>p {
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;
Expand Down
55 changes: 53 additions & 2 deletions assets/theme-v2/js/gamefoundry-partials.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@

const currentScript = document.currentScript || document.querySelector("script[src*='gamefoundry-partials.js']");
const assetRoot = currentScript ? new URL("../", currentScript.src) : null;
let themeIconRegistry = window.ThemeV2Icons || null;
let navigationAdminMenuCache = null;
let publicConfigCache = null;
let publicConfigDataCache = null;
Expand Down Expand Up @@ -325,6 +326,54 @@
return new URL(path.replace(/^assets\//, ""), assetRoot).href;
}

function fallbackThemeIconFileName(name) {
return "gfs-" + name + ".svg";
}

function createThemeIconNode(name, className) {
if (themeIconRegistry && typeof themeIconRegistry.createThemeIcon === "function") {
return themeIconRegistry.createThemeIcon(name, { className });
}

const icon = document.createElement("span");
icon.className = ["theme-icon", "theme-icon--" + name, className].filter(Boolean).join(" ");
icon.dataset.themeIcon = name;
icon.dataset.themeIconFile = fallbackThemeIconFileName(name);
icon.setAttribute("aria-hidden", "true");
return icon;
}

function horizontalToggleIconName(button) {
const expanded = button.getAttribute("aria-expanded") !== "false";
const isLeft = button.classList.contains("horizontal-accordion-toggle--left");
if (isLeft) {
return expanded ? "chevron-left" : "chevron-right";
}
return expanded ? "chevron-right" : "chevron-left";
}

function updateHorizontalToggleIcon(button) {
button.replaceChildren(createThemeIconNode(horizontalToggleIconName(button), "layout-icon horizontal-accordion-toggle__icon"));
}

function updateReturnToTopIcon(button) {
button.replaceChildren(createThemeIconNode("chevron-up", "layout-icon return-to-top__icon"));
}

function refreshUtilityIcons(root) {
(root || document).querySelectorAll(".horizontal-accordion-toggle").forEach(updateHorizontalToggleIcon);
(root || document).querySelectorAll("[data-return-to-top]").forEach(updateReturnToTopIcon);
}

function loadThemeIcons() {
import(assetUrl("js/theme-icons.js")).then(function (module) {
themeIconRegistry = module;
refreshUtilityIcons(document);
}).catch(function () {
themeIconRegistry = window.ThemeV2Icons || themeIconRegistry;
});
}

function currentPagePath() {
const parts = window.location.pathname.split("/").filter(Boolean);
const rootIndex = parts.findIndex(function (part) {
Expand Down Expand Up @@ -934,7 +983,7 @@
button.dataset.accountSideNavCollapse = "";
button.setAttribute("aria-label", "Collapse " + label);
button.setAttribute("aria-expanded", "true");
button.textContent = "<";
updateHorizontalToggleIcon(button);
header.insertBefore(button, header.firstChild);

button.addEventListener("click", function () {
Expand All @@ -943,15 +992,16 @@
if (accountPanel) {
accountPanel.classList.toggle("is-left-collapsed", collapsed);
}
button.textContent = collapsed ? ">" : "<";
button.setAttribute("aria-expanded", collapsed ? "false" : "true");
button.setAttribute("aria-label", (collapsed ? "Expand " : "Collapse ") + label);
updateHorizontalToggleIcon(button);
});
}

function wireReturnToTop(root) {
const button = root.querySelector("[data-return-to-top]");
if (!button) return;
updateReturnToTopIcon(button);

function updateVisibility() {
button.classList.toggle("is-visible", window.scrollY > 280);
Expand Down Expand Up @@ -1075,6 +1125,7 @@
}

enforcePageProtection();
loadThemeIcons();
document.addEventListener("DOMContentLoaded", function () {
enforcePageProtection();
const slots = Array.from(document.querySelectorAll("[data-partial]"));
Expand Down
23 changes: 20 additions & 3 deletions assets/theme-v2/js/tool-display-mode.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@
replaceIconNode(summary, ":scope > .tool-display-mode__chevron", shell);
}

function updateToolDisplayModeModeIcon() {
const iconName = document.body.classList.contains("tool-focus-mode") || document.fullscreenElement
? "exit-fullscreen"
: "fullscreen";
const icon = createThemeIconNode(iconName, "layout-icon tool-display-mode__mode-icon");
replaceIconNode(summary, ":scope > .tool-display-mode__mode-icon", icon);
}

function horizontalToggleIconName(button) {
const expanded = button.getAttribute("aria-expanded") !== "false";
const isLeft = button.classList.contains("horizontal-accordion-toggle--left");
Expand All @@ -98,6 +106,7 @@

function refreshThemeIcons() {
refreshVerticalAccordionChevrons();
updateToolDisplayModeModeIcon();
updateToolDisplayModeChevron();
refreshHorizontalToggleIcons();
}
Expand Down Expand Up @@ -137,6 +146,7 @@
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";
Expand Down Expand Up @@ -175,22 +185,26 @@
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";
disabledText.className = "pill tool-display-mode__navigation-link tool-display-mode__navigation-link--disabled";
disabledText.dataset[dataAttribute] = "disabled";
disabledText.textContent = controlLabel + ": " + (target?.label || "Unavailable");
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.textContent = controlLabel + ": " + target.label;
link.append(icon, label);
return link;
}

Expand Down Expand Up @@ -259,6 +273,7 @@
async function enterToolMode() {
document.body.classList.add("tool-focus-mode");
displayMode.open = false;
updateToolDisplayModeModeIcon();

try {
if (!document.fullscreenElement && document.documentElement.requestFullscreen) {
Expand All @@ -272,6 +287,7 @@
async function exitToolMode() {
document.body.classList.remove("tool-focus-mode");
displayMode.open = true;
updateToolDisplayModeModeIcon();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Refresh the mode icon after fullscreen exit

When the browser Fullscreen API succeeds, this call runs before exitFullscreen() resolves, so document.fullscreenElement is still set and updateToolDisplayModeModeIcon() keeps rendering the exit-fullscreen icon even though tool-focus-mode has already been removed. The fullscreenchange handler does not refresh this click path because the body class is gone by then, so users who exit via the control keep seeing the wrong mode icon until they re-enter focus mode.

Useful? React with 👍 / 👎.


try {
if (document.fullscreenElement && document.exitFullscreen) {
Expand All @@ -296,6 +312,7 @@
if (!document.fullscreenElement && document.body.classList.contains("tool-focus-mode")) {
document.body.classList.remove("tool-focus-mode");
displayMode.open = true;
refreshThemeIcons();
}
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# PR_26175_ALFA_050 Manual Validation Notes

## Notes
- Manual validation was performed through the required targeted Playwright lanes rather than an ad hoc browser session.
- Route tests pin the API/site URL to the repo test server so the pages do not drift to a local dev endpoint.
- Toolbox vote route assertions were made deterministic against the configured product-data provider by reading current vote state, asserting state transitions, and restoring touched Colors metadata/order.
- No visual redesign was performed; changes are limited to replacing utility text/placeholders with shared Theme V2 SVG icon nodes and matching compact CSS.
- No files under `start_of_day` were read or modified.

## Residual Risk
- Full cross-browser or mobile manual review was not run beyond the existing targeted Playwright coverage.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# PR_26175_ALFA_050-theme-v2-layout-utility-icons Report

## Summary
- Branch validation: PASS.
- Base branch state: `5426785fc` (`Merge PR #168: PR_26175_CHARLIE_028-team-charlie-final-closeout`).
- Scope: Theme V2 layout utility controls now use shared registry SVG icons for fullscreen mode, previous/next navigation, horizontal column toggles, and return-to-top.
- Runtime/UI scope: no broad redesign, no engine core changes, no `start_of_day` changes, and no page-local inline styles or style blocks introduced.

## Changed Files
- `assets/theme-v2/css/buttons.css`
- `assets/theme-v2/css/icons.css`
- `assets/theme-v2/css/panels.css`
- `assets/theme-v2/js/gamefoundry-partials.js`
- `assets/theme-v2/js/tool-display-mode.js`
- `tests/playwright/tools/ThemeV2SvgIconRegistry.spec.mjs`
- `tests/playwright/tools/ToolboxRoutePages.spec.mjs`
- `tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs`
- `docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_report.md`
- `docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_validation-lane.md`
- `docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_requirements-checklist.md`
- `docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_manual-validation-notes.md`
- `docs_build/dev/reports/codex_review.diff`
- `docs_build/dev/reports/codex_changed_files.txt`

## Implementation Notes
- `tool-display-mode.js` renders shared fullscreen/exit-fullscreen icons in the mode summary and shared chevron icons for previous/next controls while preserving existing labels and links.
- `gamefoundry-partials.js` loads the Theme V2 icon registry for shared partial utilities, replacing account side-nav text glyphs and return-to-top placeholders with registry icons.
- `icons.css`, `buttons.css`, and `panels.css` add compact shared layout-icon sizing and layout utility presentation without inline styles.
- Tests assert the new layout utility icons and keep route coverage deterministic against the configured product-data provider.

## Validation Summary
- PASS: syntax checks for the touched Theme V2 scripts.
- PASS: targeted Playwright registry, selected-game status bar, and route suites.
- PASS: inline style/style-block scan returned no matches.
- PASS: `git diff --check`.

## Branch Validation
- PASS: Branch is `codex/pr-26175-alfa-050-theme-v2-layout-utility-icons`.
- PASS: Changes are limited to ALFA_050 target implementation, tests, and required reports.
- PASS: Repo-structured ZIP will be emitted under `tmp/` and not staged.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# PR_26175_ALFA_050 Requirements Checklist

| Requirement | Status | Evidence |
| --- | --- | --- |
| Use shared icons for fullscreen enter/exit controls. | PASS | `tool-display-mode.js` adds fullscreen and exit-fullscreen registry icons; status-bar Playwright asserts both files. |
| Use shared icons for previous/next navigation. | PASS | Tool display navigation prepends shared chevron-left/chevron-right icons; Playwright asserts both files. |
| Use shared icons for column collapse/expand controls. | PASS | Horizontal accordion toggles render shared chevron icons through the Theme V2 helper path. |
| Use shared icons for return-to-top controls. | PASS | Shared partials replace return-to-top content with the registry chevron-up icon; route Playwright asserts it. |
| Preserve accessible names, roles, and keyboard behavior. | PASS | Existing button/link labels and aria attributes are retained while icons are `aria-hidden`. |
| Preserve fullscreen bottom status bar anchoring and content reserve. | PASS | Selected-game status bar Playwright suite passed. |
| Keep utility controls compact and stable. | PASS | Shared `.layout-icon` sizing and navigation-link styles were added without layout refactors. |
| Avoid page-local utility icon markup when shared helpers can own it. | PASS | Shared partial/helper paths own return-to-top and horizontal toggle icon replacement. |
| No inline styles, style blocks, or page-local CSS introduced. | PASS | Targeted `rg` scan returned no matches. |
| No unrelated page/tool redesign. | PASS | Changes are limited to layout utility icon rendering, compact CSS, tests, and reports. |
| No engine core or `start_of_day` changes. | PASS | No engine or `start_of_day` files changed. |
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# PR_26175_ALFA_050 Validation Lane

## Static Checks
- PASS: `node --check assets/theme-v2/js/theme-icons.js`
- PASS: `node --check assets/theme-v2/js/tool-display-mode.js`
- PASS: `node --check assets/theme-v2/js/gamefoundry-partials.js`
- PASS: `rg -n "<[s]tyle|[s]tyle=" assets/theme-v2/js/theme-icons.js assets/theme-v2/js/tool-display-mode.js assets/theme-v2/js/gamefoundry-partials.js assets/theme-v2/css/icons.css assets/theme-v2/css/layout.css assets/theme-v2/css/buttons.css assets/theme-v2/css/panels.css tests/playwright/tools/ThemeV2SvgIconRegistry.spec.mjs tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs tests/playwright/tools/ToolboxRoutePages.spec.mjs` returned no matches.
- PASS: `git diff --check`

## Playwright
- PASS: `npx playwright test tests/playwright/tools/ThemeV2SvgIconRegistry.spec.mjs --workers=1` (8 passed)
- PASS: `npx playwright test tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs --workers=1` (7 passed)
- PASS: `npx playwright test tests/playwright/tools/ToolboxRoutePages.spec.mjs --workers=1` (11 passed)

## Branch Validation
- PASS: Built from refreshed main after latest main refresh (`5426785fc`).
- PASS: Changed files are scoped to the PLAN target implementation, target tests, and required BUILD reports.
- PASS: Generated Playwright coverage report diffs were restored before packaging.
19 changes: 13 additions & 6 deletions docs_build/dev/reports/codex_changed_files.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
docs_build/dev/reports/codex_changed_files.txt
assets/theme-v2/css/buttons.css
assets/theme-v2/css/icons.css
assets/theme-v2/css/panels.css
assets/theme-v2/js/gamefoundry-partials.js
assets/theme-v2/js/tool-display-mode.js
docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_manual-validation-notes.md
docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_report.md
docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_requirements-checklist.md
docs_build/dev/reports/PR_26175_ALFA_050-theme-v2-layout-utility-icons_validation-lane.md
docs_build/dev/reports/codex_changed_files.txt
docs_build/dev/reports/codex_review.diff
docs_build/dev/reports/PR_26175_CHARLIE_028-team-charlie-final-closeout.md
docs_build/dev/reports/PR_26175_CHARLIE_028-team-charlie-final-closeout-branch-validation.md
docs_build/dev/reports/PR_26175_CHARLIE_028-team-charlie-final-closeout-manual-validation-notes.md
docs_build/dev/reports/PR_26175_CHARLIE_028-team-charlie-final-closeout-requirement-checklist.md
docs_build/dev/reports/PR_26175_CHARLIE_028-team-charlie-final-closeout-validation.md
tests/playwright/tools/ThemeV2SvgIconRegistry.spec.mjs
tests/playwright/tools/ToolboxRoutePages.spec.mjs
tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs
Binary file modified docs_build/dev/reports/codex_review.diff
Binary file not shown.
9 changes: 8 additions & 1 deletion tests/playwright/tools/ThemeV2SvgIconRegistry.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,9 @@ test("supports semantic status and action aliases with shared CSS classes", asyn
const statusIcon = themeIcons.createThemeIcon("validation", {
className: "status-icon status-icon--validation",
});
const layoutIcon = themeIcons.createThemeIcon("fullscreen", { className: "layout-icon" });

document.body.append(saveButton, deleteButton, statusIcon);
document.body.append(saveButton, deleteButton, statusIcon, layoutIcon);

const saveIcon = saveButton.querySelector("[data-theme-icon]");
const deleteIcon = deleteButton.querySelector("[data-theme-icon]");
Expand All @@ -234,6 +235,9 @@ test("supports semantic status and action aliases with shared CSS classes", asyn
statusIconColor: statusStyles.color,
statusIconFile: statusIcon.dataset.themeIconFile,
statusIconName: statusIcon.dataset.themeIcon,
layoutIconFile: layoutIcon.dataset.themeIconFile,
layoutIconName: layoutIcon.dataset.themeIcon,
layoutIconWidth: getComputedStyle(layoutIcon).width,
};
});

Expand All @@ -250,6 +254,9 @@ test("supports semantic status and action aliases with shared CSS classes", asyn
statusIconColor: "rgb(255, 200, 87)",
statusIconFile: "gfs-warning.svg",
statusIconName: "validation",
layoutIconFile: "gfs-fullscreen.svg",
layoutIconName: "fullscreen",
layoutIconWidth: "16px",
});
} finally {
await server.close();
Expand Down
Loading
Loading