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
27 changes: 23 additions & 4 deletions assets/theme-v2/css/status.css
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
.toolbox-status-bar {
--toolbox-status-bar-height: var(--space-52);
--toolbox-status-game-max: 220px;
--toolbox-status-progress-max: 34vw;
width: 100%;
min-block-size: var(--toolbox-status-bar-height);
border-block: var(--border-standard);
Expand All @@ -50,7 +51,7 @@
margin: var(--space-0) auto;
padding: var(--space-10) var(--space-0);
display: grid;
grid-template-columns: minmax(var(--space-0), max-content) minmax(var(--space-0), 1fr);
grid-template-columns: minmax(var(--space-0), max-content) minmax(var(--space-0), 1fr) minmax(var(--space-0), max-content);
gap: var(--space-16);
align-items: center
}
Expand Down Expand Up @@ -90,6 +91,19 @@
overflow-wrap: anywhere
}

.toolbox-status-bar__progress {
min-width: var(--space-0);
max-width: var(--toolbox-status-progress-max);
margin: var(--space-0);
color: var(--muted);
font-size: var(--font-size-sm);
line-height: var(--line-height-tight);
overflow: hidden;
text-align: right;
text-overflow: ellipsis;
white-space: nowrap
}

.toolbox-status-bar[data-selected-game-state="active"] {
border-color: color-mix(in srgb, var(--green) 52%, var(--line))
}
Expand Down Expand Up @@ -249,16 +263,21 @@ body.tool-focus-mode .tool-center-panel {
@media (max-width: 720px) {
.toolbox-status-bar__inner {
width: var(--container-width);
grid-template-columns: minmax(var(--space-0), max-content) minmax(var(--space-0), 1fr);
grid-template-columns: minmax(var(--space-0), max-content) minmax(var(--space-0), 1fr) minmax(var(--space-0), max-content);
gap: var(--space-10);
text-align: center
}

.toolbox-status-bar__game-name {
max-width: 34vw
max-width: 24vw
}

.toolbox-status-bar__message {
.toolbox-status-bar__message,
.toolbox-status-bar__progress {
font-size: var(--font-size-sm)
}

.toolbox-status-bar__progress {
max-width: 30vw
}
}
139 changes: 138 additions & 1 deletion assets/theme-v2/js/toolbox-status-bar.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,39 @@
import { readGameJourneyCompletionMetrics } from "/src/api/game-journey-completion-api-client.js";
import { createServerRepositoryClient } from "/src/api/server-api-client.js";
import { getToolBySlug } from "/src/shared/toolbox/tool-metadata-inventory.js";

const EXCLUDED_SELECTED_GAME_TOOLS = new Set(["idea-board"]);
const STATUS_BAR_SELECTOR = "[data-toolbox-status-bar]";
const TOOL_PROGRESS_BUCKET_BY_SLUG = Object.freeze({
"achievements": "Progression",
"assets": "Graphics",
"audio": "Audio",
"audio-effects": "Audio",
"characters": "Objects",
"colors": "Graphics",
"community": "Share",
"controls": "Controls",
"events": "Rules",
"game-configuration": "Create",
"game-design": "Design",
"game-hub": "Create",
"game-testing": "Play Test",
"hitboxes": "Objects",
"idea-board": "Idea",
"input-mapping-v2": "Controls",
"marketplace": "Share",
"messages": "Interface",
"music": "Audio",
"objects": "Objects",
"publish": "Publish",
"ratings": "Share",
"sprites": "Graphics",
"tags": "Progression",
"text-to-speech": "Audio",
"videos": "Graphics",
"voices": "Audio",
"worlds": "Worlds",
});

let repository = null;
let messageObserver = null;
Expand Down Expand Up @@ -101,7 +133,10 @@ function createStatusBar() {
message.setAttribute("role", "status");
center.append(message);

inner.append(game, center);
const progress = createText("p", "toolbox-status-bar__progress", "toolboxStatusProgress");
progress.setAttribute("aria-label", "Tool and journey progress");

inner.append(game, center, progress);
bar.append(inner);
return bar;
}
Expand Down Expand Up @@ -233,6 +268,107 @@ function classifyToolContext(messageText, state, required) {
return { kind: "action" };
}

function normalizeTextKey(value) {
return String(value || "")
.toLowerCase()
.replace(/[^a-z0-9]+/g, "");
}

function formatToolSlug(slug) {
return String(slug || "Tool")
.split(/[-_\s]+/)
.filter(Boolean)
.map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
.join(" ") || "Tool";
}

function currentToolContext() {
const slug = toolSlugFromPath(mountOptions.pagePath);
const tool = getToolBySlug(slug);
return {
label: tool?.shortLabel || tool?.displayName || tool?.name || formatToolSlug(slug),
slug,
};
}

function normalizeProgressRecord(record) {
const total = Math.max(0, Number(record?.plannedCount) || 0);
const complete = Math.max(0, Math.min(Number(record?.completedCount) || 0, total));
const percent = Number.isFinite(Number(record?.percentComplete))
? Math.max(0, Math.min(Number(record.percentComplete), 100))
: total > 0
? Math.round((complete / total) * 100)
: 0;
return {
complete,
percent,
total,
};
}

function formatProgressRecord(label, record) {
const progress = normalizeProgressRecord(record);
return `${label} ${progress.complete}/${progress.total} (${progress.percent}%)`;
}

function findMetricForCurrentTool(snapshot, toolContext) {
if (toolContext.slug === "game-journey") {
return snapshot;
}

const records = Array.isArray(snapshot?.records) ? snapshot.records : [];
const explicitBucketName = TOOL_PROGRESS_BUCKET_BY_SLUG[toolContext.slug];
const explicitBucket = normalizeTextKey(explicitBucketName);
const toolLabel = normalizeTextKey(toolContext.label);
const toolSlug = normalizeTextKey(toolContext.slug);

return records.find((metric) => {
const bucketName = normalizeTextKey(metric?.bucketName);
return bucketName && (
bucketName === explicitBucket ||
bucketName === toolLabel ||
bucketName === toolSlug
);
}) || null;
}

function resolveProgressContext() {
const toolContext = currentToolContext();
const snapshot = readGameJourneyCompletionMetrics();
const currentMetric = findMetricForCurrentTool(snapshot, toolContext);
const journeyText = formatProgressRecord("Journey", snapshot);

if (!currentMetric) {
return {
state: "unmapped",
text: `${toolContext.label} progress unavailable | ${journeyText}`,
};
}

return {
state: "active",
text: `${formatProgressRecord(toolContext.label, currentMetric)} | ${journeyText}`,
};
}

function renderProgressContext(bar) {
const progress = bar.querySelector("[data-toolbox-status-progress]");
if (!progress) {
return;
}

try {
const context = resolveProgressContext();
bar.dataset.toolboxProgressState = context.state;
progress.textContent = context.text;
progress.removeAttribute("title");
} catch (error) {
bar.dataset.toolboxProgressState = "error";
progress.textContent = "Progress unavailable";
progress.removeAttribute("title");
}
}

function renderSelectedGame(bar, selectedGame, state, messageText) {
const required = pageRequiresSelectedGame();
const name = bar.querySelector("[data-toolbox-selected-game-name]");
Expand All @@ -247,6 +383,7 @@ function renderSelectedGame(bar, selectedGame, state, messageText) {
bar.dataset.selectedGameState = state;
bar.dataset.selectedGameRequired = String(required);
bar.dataset.toolboxStatusContextKind = context.kind;
renderProgressContext(bar);

if (selectedGame) {
name.textContent = selectedGame.name;
Expand Down
56 changes: 30 additions & 26 deletions docs_build/dev/BUILD_PR.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,54 @@
# PR_26175_ALFA_009-status-bar-single-row-rebuild
# PR_26175_ALFA_011-status-bar-journey-progress-context

## Purpose
Rebuild the shared toolbox status bar on current `main` so it is a single-row creator context bar.
Add right-anchored progress context to the shared toolbox status bar using the existing Game Journey completion metrics/API pipeline.

## Source Of Truth
This `BUILD_PR.md` is the source of truth for `PR_26175_ALFA_009-status-bar-single-row-rebuild`.
This `BUILD_PR.md` is the source of truth for `PR_26175_ALFA_011-status-bar-journey-progress-context`.

## Exact Scope
- Display only the selected Game Hub game name on the left side of the toolbox status bar.
- Display only the current status message in the center of the toolbox status bar.
- Remove visible status bar labels: `Selected Game Name`, `Selected Game Purpose`, `Save State`, `Tool Action`, `Warning`, and `Error`.
- Remove selected-game purpose from the visible status bar.
- Preserve normal status bar placement above the footer.
- Remove extra status bar/footer spacing so the shared footer top padding resolves to `0px`.
- Preserve fullscreen/tool display mode bottom anchoring.
- Ensure fullscreen center scrollable content stops above the fixed status bar.
- Ensure fullscreen tool content is not hidden behind the status bar.
- Preserve Idea Board selected-game filtering exclusion.
- Preserve Game Hub as selected-game owner through the existing repository contract.
- Preserve the ALFA_009 single-row toolbox status bar behavior:
- left side displays only the selected Game Hub game name.
- center displays only the current status message.
- Add right-anchored progress text in this format:
- `{CurrentTool} {complete}/{total} ({percent}%) | Journey {complete}/{total} ({percent}%)`
- Use existing Game Journey completion metrics/API pipeline for Journey totals.
- Derive current-tool progress from the existing completion metrics record that matches the current toolbox tool/section.
- Do not add new storage.
- Do not use browser-owned authoritative progress data.
- Preserve fullscreen bottom anchoring and existing fullscreen content bottom reserve.
- Preserve normal placement above the footer.
- Use shared Theme V2 CSS/classes only.
- Update targeted Playwright coverage for the single-row status bar, footer spacing, and fullscreen bottom reserve.
- Update targeted Playwright coverage for the right-anchored progress text and existing left/center behavior.

## Exact Targets
- `docs_build/dev/BUILD_PR.md`
- `assets/theme-v2/js/toolbox-status-bar.js`
- `assets/theme-v2/css/status.css`
- `assets/theme-v2/css/layout.css`
- `tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs`
- `docs_build/dev/reports/PR_26175_ALFA_009-status-bar-single-row-rebuild_report.md`
- `docs_build/dev/reports/PR_26175_ALFA_009-status-bar-single-row-rebuild_validation-lane.md`
- `docs_build/dev/reports/PR_26175_ALFA_009-status-bar-single-row-rebuild_requirements-checklist.md`
- `docs_build/dev/reports/PR_26175_ALFA_011-status-bar-journey-progress-context_report.md`
- `docs_build/dev/reports/PR_26175_ALFA_011-status-bar-journey-progress-context_validation-lane.md`
- `docs_build/dev/reports/PR_26175_ALFA_011-status-bar-journey-progress-context_requirements-checklist.md`
- `docs_build/dev/reports/codex_review.diff`
- `docs_build/dev/reports/codex_changed_files.txt`

## Evidence Sources
- `assets/js/shared/game-journey-api-client.js`
- `src/api/game-journey-completion-api-client.js`
- `src/dev-runtime/server/local-api-router.mjs`
- `src/dev-runtime/persistence/game-journey-completion-metrics-store.mjs`

## Out Of Scope
- No merge of PR #120.
- No reuse of stale ALFA_003 branch.
- No Game Journey API/service/repository contract changes.
- No new persistence/storage.
- No browser-owned product data as source of truth.
- No silent fallback data.
- No environment/server details in the status bar.
- No selected game purpose in the visible status bar.
- No visible status category labels in the status bar.
- No status action links in the visible status bar.
- No large banners.
- No modal messages or modal-style status messages.
- No row highlights.
- No API/service/repository contract changes.
- No browser-owned product data as source of truth.
- No inline styles, style blocks, or page-local CSS.
- No engine core changes.
- No `start_of_day` folder changes.
Expand All @@ -59,12 +63,12 @@ npx playwright test tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs
Also verify changed source does not introduce inline styles or style blocks:

```powershell
rg -n "<[s]tyle|[s]tyle=" assets/theme-v2/js/toolbox-status-bar.js assets/theme-v2/css/status.css assets/theme-v2/css/layout.css tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs
rg -n "<[s]tyle|[s]tyle=" assets/theme-v2/js/toolbox-status-bar.js assets/theme-v2/css/status.css tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs
```

## Artifact
Create repo-structured delta ZIP:

```text
tmp/PR_26175_ALFA_009-status-bar-single-row-rebuild_delta.zip
tmp/PR_26175_ALFA_011-status-bar-journey-progress-context_delta.zip
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# PR_26175_ALFA_011-status-bar-journey-progress-context Report

## Status
PASS

Added right-anchored progress context to the shared toolbox status bar while preserving the ALFA_009 left and center behavior.

## Changes
- `assets/theme-v2/js/toolbox-status-bar.js`
- Imports the existing Game Journey completion metrics API client at line 1.
- Adds current-tool-to-Journey-bucket matching at lines 7-35.
- Adds the right progress node at line 136.
- Formats progress as `{CurrentTool} {complete}/{total} ({percent}%) | Journey {complete}/{total} ({percent}%)` at lines 309-350.
- Renders visible unavailable progress state without raw environment/server details at lines 354-370.
- `assets/theme-v2/css/status.css`
- Adds a three-column shared status bar grid at line 54.
- Adds right-aligned single-line progress styling at lines 94-106.
- Preserves existing fullscreen anchoring and bottom reserve rules at lines 119-150.
- `tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs`
- Routes `/api/game-journey/completion-metrics` through the existing server API response shape at lines 76-83.
- Verifies Game Design progress at lines 239 and 253.
- Verifies the requested Objects example at lines 275 and 279.
- Verifies right anchoring at lines 260 and 280.
- Verifies Game Hub, missing-game, Idea Board, and fullscreen behavior at lines 304, 328, 353, 371, and 398.

## Contract Notes
- No storage was added.
- No API/service/repository contract was changed.
- Progress data is read from the existing Game Journey completion metrics API pipeline.
- Browser state is not used as authoritative progress data.
- Existing selected-game ownership and left/center status bar behavior are preserved.

## Validation
- PASS: `npx playwright test tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs --workers=1`
- PASS: `rg -n "<[s]tyle|[s]tyle=" assets/theme-v2/js/toolbox-status-bar.js assets/theme-v2/css/status.css tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs`

## Artifact
- `tmp/PR_26175_ALFA_011-status-bar-journey-progress-context_delta.zip`
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# PR_26175_ALFA_011 Requirements Checklist

| Requirement | Status | Evidence |
| --- | --- | --- |
| Implement right-anchored progress in the shared toolbox status bar. | PASS | `assets/theme-v2/js/toolbox-status-bar.js:136`, `assets/theme-v2/css/status.css:94`. |
| Use format `{CurrentTool} {complete}/{total} ({percent}%) | Journey {complete}/{total} ({percent}%)`. | PASS | `assets/theme-v2/js/toolbox-status-bar.js:309` and `:350`; tests at `tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs:239`, `:275`. |
| Use existing Game Journey completion metrics/API pipeline. | PASS | `assets/theme-v2/js/toolbox-status-bar.js:1`, `:337`; tests route `/api/game-journey/completion-metrics` at `tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs:76`. |
| Do not add new storage. | PASS | No persistence files changed. |
| Do not use browser-owned authoritative progress data. | PASS | Progress is read from `readGameJourneyCompletionMetrics()` and not local/session storage. |
| Keep existing left status bar behavior from ALFA_009. | PASS | Selected game assertions remain at `tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs:237`, `:302`, `:391`. |
| Keep existing center status bar behavior from ALFA_009. | PASS | Message assertions remain at `tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs:238`, `:303`, `:370`, `:397`. |
| Preserve fullscreen bottom anchoring. | PASS | Existing CSS rules remain at `assets/theme-v2/css/status.css:119`; test coverage at `tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs:315`. |
| Preserve normal placement above footer. | PASS | Existing status bar placement test remains at `tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs:224`. |
| No inline styles, style blocks, or page-local CSS. | PASS | Style scan returned no matches. |
| Use Theme V2 shared CSS/classes. | PASS | Styling changes are limited to `assets/theme-v2/css/status.css`. |
| Update targeted Playwright coverage. | PASS | `tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs` now validates right progress text and anchoring. |
| Produce required reports and repo-structured ZIP. | PASS | PR reports added and ZIP target is `tmp/PR_26175_ALFA_011-status-bar-journey-progress-context_delta.zip`. |
Loading
Loading