Skip to content

Commit 823978d

Browse files
committed
ALFA 011 status bar journey progress context
1 parent 2e74990 commit 823978d

9 files changed

Lines changed: 1002 additions & 720 deletions

assets/theme-v2/css/status.css

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
.toolbox-status-bar {
3939
--toolbox-status-bar-height: var(--space-52);
4040
--toolbox-status-game-max: 220px;
41+
--toolbox-status-progress-max: 34vw;
4142
width: 100%;
4243
min-block-size: var(--toolbox-status-bar-height);
4344
border-block: var(--border-standard);
@@ -50,7 +51,7 @@
5051
margin: var(--space-0) auto;
5152
padding: var(--space-10) var(--space-0);
5253
display: grid;
53-
grid-template-columns: minmax(var(--space-0), max-content) minmax(var(--space-0), 1fr);
54+
grid-template-columns: minmax(var(--space-0), max-content) minmax(var(--space-0), 1fr) minmax(var(--space-0), max-content);
5455
gap: var(--space-16);
5556
align-items: center
5657
}
@@ -90,6 +91,19 @@
9091
overflow-wrap: anywhere
9192
}
9293

94+
.toolbox-status-bar__progress {
95+
min-width: var(--space-0);
96+
max-width: var(--toolbox-status-progress-max);
97+
margin: var(--space-0);
98+
color: var(--muted);
99+
font-size: var(--font-size-sm);
100+
line-height: var(--line-height-tight);
101+
overflow: hidden;
102+
text-align: right;
103+
text-overflow: ellipsis;
104+
white-space: nowrap
105+
}
106+
93107
.toolbox-status-bar[data-selected-game-state="active"] {
94108
border-color: color-mix(in srgb, var(--green) 52%, var(--line))
95109
}
@@ -249,16 +263,21 @@ body.tool-focus-mode .tool-center-panel {
249263
@media (max-width: 720px) {
250264
.toolbox-status-bar__inner {
251265
width: var(--container-width);
252-
grid-template-columns: minmax(var(--space-0), max-content) minmax(var(--space-0), 1fr);
266+
grid-template-columns: minmax(var(--space-0), max-content) minmax(var(--space-0), 1fr) minmax(var(--space-0), max-content);
253267
gap: var(--space-10);
254268
text-align: center
255269
}
256270

257271
.toolbox-status-bar__game-name {
258-
max-width: 34vw
272+
max-width: 24vw
259273
}
260274

261-
.toolbox-status-bar__message {
275+
.toolbox-status-bar__message,
276+
.toolbox-status-bar__progress {
262277
font-size: var(--font-size-sm)
263278
}
279+
280+
.toolbox-status-bar__progress {
281+
max-width: 30vw
282+
}
264283
}

assets/theme-v2/js/toolbox-status-bar.js

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,39 @@
1+
import { readGameJourneyCompletionMetrics } from "/src/api/game-journey-completion-api-client.js";
12
import { createServerRepositoryClient } from "/src/api/server-api-client.js";
3+
import { getToolBySlug } from "/src/shared/toolbox/tool-metadata-inventory.js";
24

35
const EXCLUDED_SELECTED_GAME_TOOLS = new Set(["idea-board"]);
46
const STATUS_BAR_SELECTOR = "[data-toolbox-status-bar]";
7+
const TOOL_PROGRESS_BUCKET_BY_SLUG = Object.freeze({
8+
"achievements": "Progression",
9+
"assets": "Graphics",
10+
"audio": "Audio",
11+
"audio-effects": "Audio",
12+
"characters": "Objects",
13+
"colors": "Graphics",
14+
"community": "Share",
15+
"controls": "Controls",
16+
"events": "Rules",
17+
"game-configuration": "Create",
18+
"game-design": "Design",
19+
"game-hub": "Create",
20+
"game-testing": "Play Test",
21+
"hitboxes": "Objects",
22+
"idea-board": "Idea",
23+
"input-mapping-v2": "Controls",
24+
"marketplace": "Share",
25+
"messages": "Interface",
26+
"music": "Audio",
27+
"objects": "Objects",
28+
"publish": "Publish",
29+
"ratings": "Share",
30+
"sprites": "Graphics",
31+
"tags": "Progression",
32+
"text-to-speech": "Audio",
33+
"videos": "Graphics",
34+
"voices": "Audio",
35+
"worlds": "Worlds",
36+
});
537

638
let repository = null;
739
let messageObserver = null;
@@ -101,7 +133,10 @@ function createStatusBar() {
101133
message.setAttribute("role", "status");
102134
center.append(message);
103135

104-
inner.append(game, center);
136+
const progress = createText("p", "toolbox-status-bar__progress", "toolboxStatusProgress");
137+
progress.setAttribute("aria-label", "Tool and journey progress");
138+
139+
inner.append(game, center, progress);
105140
bar.append(inner);
106141
return bar;
107142
}
@@ -233,6 +268,107 @@ function classifyToolContext(messageText, state, required) {
233268
return { kind: "action" };
234269
}
235270

271+
function normalizeTextKey(value) {
272+
return String(value || "")
273+
.toLowerCase()
274+
.replace(/[^a-z0-9]+/g, "");
275+
}
276+
277+
function formatToolSlug(slug) {
278+
return String(slug || "Tool")
279+
.split(/[-_\s]+/)
280+
.filter(Boolean)
281+
.map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
282+
.join(" ") || "Tool";
283+
}
284+
285+
function currentToolContext() {
286+
const slug = toolSlugFromPath(mountOptions.pagePath);
287+
const tool = getToolBySlug(slug);
288+
return {
289+
label: tool?.shortLabel || tool?.displayName || tool?.name || formatToolSlug(slug),
290+
slug,
291+
};
292+
}
293+
294+
function normalizeProgressRecord(record) {
295+
const total = Math.max(0, Number(record?.plannedCount) || 0);
296+
const complete = Math.max(0, Math.min(Number(record?.completedCount) || 0, total));
297+
const percent = Number.isFinite(Number(record?.percentComplete))
298+
? Math.max(0, Math.min(Number(record.percentComplete), 100))
299+
: total > 0
300+
? Math.round((complete / total) * 100)
301+
: 0;
302+
return {
303+
complete,
304+
percent,
305+
total,
306+
};
307+
}
308+
309+
function formatProgressRecord(label, record) {
310+
const progress = normalizeProgressRecord(record);
311+
return `${label} ${progress.complete}/${progress.total} (${progress.percent}%)`;
312+
}
313+
314+
function findMetricForCurrentTool(snapshot, toolContext) {
315+
if (toolContext.slug === "game-journey") {
316+
return snapshot;
317+
}
318+
319+
const records = Array.isArray(snapshot?.records) ? snapshot.records : [];
320+
const explicitBucketName = TOOL_PROGRESS_BUCKET_BY_SLUG[toolContext.slug];
321+
const explicitBucket = normalizeTextKey(explicitBucketName);
322+
const toolLabel = normalizeTextKey(toolContext.label);
323+
const toolSlug = normalizeTextKey(toolContext.slug);
324+
325+
return records.find((metric) => {
326+
const bucketName = normalizeTextKey(metric?.bucketName);
327+
return bucketName && (
328+
bucketName === explicitBucket ||
329+
bucketName === toolLabel ||
330+
bucketName === toolSlug
331+
);
332+
}) || null;
333+
}
334+
335+
function resolveProgressContext() {
336+
const toolContext = currentToolContext();
337+
const snapshot = readGameJourneyCompletionMetrics();
338+
const currentMetric = findMetricForCurrentTool(snapshot, toolContext);
339+
const journeyText = formatProgressRecord("Journey", snapshot);
340+
341+
if (!currentMetric) {
342+
return {
343+
state: "unmapped",
344+
text: `${toolContext.label} progress unavailable | ${journeyText}`,
345+
};
346+
}
347+
348+
return {
349+
state: "active",
350+
text: `${formatProgressRecord(toolContext.label, currentMetric)} | ${journeyText}`,
351+
};
352+
}
353+
354+
function renderProgressContext(bar) {
355+
const progress = bar.querySelector("[data-toolbox-status-progress]");
356+
if (!progress) {
357+
return;
358+
}
359+
360+
try {
361+
const context = resolveProgressContext();
362+
bar.dataset.toolboxProgressState = context.state;
363+
progress.textContent = context.text;
364+
progress.removeAttribute("title");
365+
} catch (error) {
366+
bar.dataset.toolboxProgressState = "error";
367+
progress.textContent = "Progress unavailable";
368+
progress.removeAttribute("title");
369+
}
370+
}
371+
236372
function renderSelectedGame(bar, selectedGame, state, messageText) {
237373
const required = pageRequiresSelectedGame();
238374
const name = bar.querySelector("[data-toolbox-selected-game-name]");
@@ -247,6 +383,7 @@ function renderSelectedGame(bar, selectedGame, state, messageText) {
247383
bar.dataset.selectedGameState = state;
248384
bar.dataset.selectedGameRequired = String(required);
249385
bar.dataset.toolboxStatusContextKind = context.kind;
386+
renderProgressContext(bar);
250387

251388
if (selectedGame) {
252389
name.textContent = selectedGame.name;

docs_build/dev/BUILD_PR.md

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,54 @@
1-
# PR_26175_ALFA_009-status-bar-single-row-rebuild
1+
# PR_26175_ALFA_011-status-bar-journey-progress-context
22

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

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

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

2424
## Exact Targets
2525
- `docs_build/dev/BUILD_PR.md`
2626
- `assets/theme-v2/js/toolbox-status-bar.js`
2727
- `assets/theme-v2/css/status.css`
28-
- `assets/theme-v2/css/layout.css`
2928
- `tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs`
30-
- `docs_build/dev/reports/PR_26175_ALFA_009-status-bar-single-row-rebuild_report.md`
31-
- `docs_build/dev/reports/PR_26175_ALFA_009-status-bar-single-row-rebuild_validation-lane.md`
32-
- `docs_build/dev/reports/PR_26175_ALFA_009-status-bar-single-row-rebuild_requirements-checklist.md`
29+
- `docs_build/dev/reports/PR_26175_ALFA_011-status-bar-journey-progress-context_report.md`
30+
- `docs_build/dev/reports/PR_26175_ALFA_011-status-bar-journey-progress-context_validation-lane.md`
31+
- `docs_build/dev/reports/PR_26175_ALFA_011-status-bar-journey-progress-context_requirements-checklist.md`
3332
- `docs_build/dev/reports/codex_review.diff`
3433
- `docs_build/dev/reports/codex_changed_files.txt`
3534

35+
## Evidence Sources
36+
- `assets/js/shared/game-journey-api-client.js`
37+
- `src/api/game-journey-completion-api-client.js`
38+
- `src/dev-runtime/server/local-api-router.mjs`
39+
- `src/dev-runtime/persistence/game-journey-completion-metrics-store.mjs`
40+
3641
## Out Of Scope
37-
- No merge of PR #120.
38-
- No reuse of stale ALFA_003 branch.
42+
- No Game Journey API/service/repository contract changes.
43+
- No new persistence/storage.
44+
- No browser-owned product data as source of truth.
45+
- No silent fallback data.
3946
- No environment/server details in the status bar.
4047
- No selected game purpose in the visible status bar.
4148
- No visible status category labels in the status bar.
42-
- No status action links in the visible status bar.
4349
- No large banners.
4450
- No modal messages or modal-style status messages.
4551
- No row highlights.
46-
- No API/service/repository contract changes.
47-
- No browser-owned product data as source of truth.
4852
- No inline styles, style blocks, or page-local CSS.
4953
- No engine core changes.
5054
- No `start_of_day` folder changes.
@@ -59,12 +63,12 @@ npx playwright test tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs
5963
Also verify changed source does not introduce inline styles or style blocks:
6064

6165
```powershell
62-
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
66+
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
6367
```
6468

6569
## Artifact
6670
Create repo-structured delta ZIP:
6771

6872
```text
69-
tmp/PR_26175_ALFA_009-status-bar-single-row-rebuild_delta.zip
73+
tmp/PR_26175_ALFA_011-status-bar-journey-progress-context_delta.zip
7074
```
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# PR_26175_ALFA_011-status-bar-journey-progress-context Report
2+
3+
## Status
4+
PASS
5+
6+
Added right-anchored progress context to the shared toolbox status bar while preserving the ALFA_009 left and center behavior.
7+
8+
## Changes
9+
- `assets/theme-v2/js/toolbox-status-bar.js`
10+
- Imports the existing Game Journey completion metrics API client at line 1.
11+
- Adds current-tool-to-Journey-bucket matching at lines 7-35.
12+
- Adds the right progress node at line 136.
13+
- Formats progress as `{CurrentTool} {complete}/{total} ({percent}%) | Journey {complete}/{total} ({percent}%)` at lines 309-350.
14+
- Renders visible unavailable progress state without raw environment/server details at lines 354-370.
15+
- `assets/theme-v2/css/status.css`
16+
- Adds a three-column shared status bar grid at line 54.
17+
- Adds right-aligned single-line progress styling at lines 94-106.
18+
- Preserves existing fullscreen anchoring and bottom reserve rules at lines 119-150.
19+
- `tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs`
20+
- Routes `/api/game-journey/completion-metrics` through the existing server API response shape at lines 76-83.
21+
- Verifies Game Design progress at lines 239 and 253.
22+
- Verifies the requested Objects example at lines 275 and 279.
23+
- Verifies right anchoring at lines 260 and 280.
24+
- Verifies Game Hub, missing-game, Idea Board, and fullscreen behavior at lines 304, 328, 353, 371, and 398.
25+
26+
## Contract Notes
27+
- No storage was added.
28+
- No API/service/repository contract was changed.
29+
- Progress data is read from the existing Game Journey completion metrics API pipeline.
30+
- Browser state is not used as authoritative progress data.
31+
- Existing selected-game ownership and left/center status bar behavior are preserved.
32+
33+
## Validation
34+
- PASS: `npx playwright test tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs --workers=1`
35+
- 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`
36+
37+
## Artifact
38+
- `tmp/PR_26175_ALFA_011-status-bar-journey-progress-context_delta.zip`
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# PR_26175_ALFA_011 Requirements Checklist
2+
3+
| Requirement | Status | Evidence |
4+
| --- | --- | --- |
5+
| 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`. |
6+
| 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`. |
7+
| 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`. |
8+
| Do not add new storage. | PASS | No persistence files changed. |
9+
| Do not use browser-owned authoritative progress data. | PASS | Progress is read from `readGameJourneyCompletionMetrics()` and not local/session storage. |
10+
| Keep existing left status bar behavior from ALFA_009. | PASS | Selected game assertions remain at `tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs:237`, `:302`, `:391`. |
11+
| Keep existing center status bar behavior from ALFA_009. | PASS | Message assertions remain at `tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs:238`, `:303`, `:370`, `:397`. |
12+
| 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`. |
13+
| Preserve normal placement above footer. | PASS | Existing status bar placement test remains at `tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs:224`. |
14+
| No inline styles, style blocks, or page-local CSS. | PASS | Style scan returned no matches. |
15+
| Use Theme V2 shared CSS/classes. | PASS | Styling changes are limited to `assets/theme-v2/css/status.css`. |
16+
| Update targeted Playwright coverage. | PASS | `tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs` now validates right progress text and anchoring. |
17+
| 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`. |

0 commit comments

Comments
 (0)