Skip to content

Commit 3557b13

Browse files
committed
ALFA 002 toolbox status bar context polish
1 parent 359d48c commit 3557b13

9 files changed

Lines changed: 837 additions & 169 deletions

assets/theme-v2/css/status.css

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,19 @@
5454

5555
.toolbox-status-bar__game {
5656
min-width: var(--space-0);
57-
display: grid;
58-
gap: var(--space-3);
57+
display: flex;
58+
align-items: center;
59+
flex-wrap: wrap;
60+
gap: var(--space-14);
5961
text-align: left
6062
}
6163

64+
.toolbox-status-bar__field {
65+
min-width: var(--space-0);
66+
display: grid;
67+
gap: var(--space-3)
68+
}
69+
6270
.toolbox-status-bar__label {
6371
color: var(--muted);
6472
font-size: var(--font-size-xs);
@@ -73,7 +81,7 @@
7381
overflow-wrap: anywhere
7482
}
7583

76-
.toolbox-status-bar__meta {
84+
.toolbox-status-bar__purpose {
7785
color: var(--muted);
7886
font-size: var(--font-size-sm);
7987
overflow-wrap: anywhere
@@ -89,6 +97,10 @@
8997
text-align: center
9098
}
9199

100+
.toolbox-status-bar__context-type {
101+
flex: 0 0 auto
102+
}
103+
92104
.toolbox-status-bar__message {
93105
margin: var(--space-0);
94106
max-width: var(--measure-lg);
@@ -104,13 +116,27 @@
104116
}
105117

106118
.toolbox-status-bar[data-selected-game-state="missing"] {
107-
border-color: var(--gold-border-muted);
108-
background: var(--gold-soft)
119+
border-color: var(--gold-border-muted)
109120
}
110121

111122
.toolbox-status-bar[data-selected-game-state="error"] {
112-
border-color: color-mix(in srgb, var(--red) 52%, var(--line));
113-
background: color-mix(in srgb, var(--red) 14%, var(--panel))
123+
border-color: color-mix(in srgb, var(--red) 52%, var(--line))
124+
}
125+
126+
.toolbox-status-bar[data-toolbox-status-context-kind="error"] .toolbox-status-bar__context-type {
127+
border-color: color-mix(in srgb, var(--red) 62%, var(--line));
128+
color: var(--red)
129+
}
130+
131+
.toolbox-status-bar[data-toolbox-status-context-kind="warning"] .toolbox-status-bar__context-type,
132+
.toolbox-status-bar[data-toolbox-status-context-kind="validation"] .toolbox-status-bar__context-type {
133+
border-color: var(--gold-border-muted);
134+
color: var(--gold)
135+
}
136+
137+
.toolbox-status-bar[data-toolbox-status-context-kind="save"] .toolbox-status-bar__context-type {
138+
border-color: color-mix(in srgb, var(--green) 62%, var(--line));
139+
color: var(--green)
114140
}
115141

116142
body.tool-focus-mode .toolbox-status-bar {
@@ -240,6 +266,7 @@ body.tool-focus-mode .toolbox-status-bar {
240266
}
241267

242268
.toolbox-status-bar__game {
269+
justify-content: center;
243270
text-align: center
244271
}
245272
}

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

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ let repository = null;
77
let messageObserver = null;
88
let listenersInstalled = false;
99
let latestToolMessage = "";
10+
let pendingToolMessageRefresh = 0;
1011
let mountOptions = {
1112
gameHubHref: "toolbox/game-hub/index.html",
1213
pagePath: "",
@@ -89,24 +90,37 @@ function createStatusBar() {
8990
game.className = "toolbox-status-bar__game";
9091
game.dataset.toolboxSelectedGame = "";
9192

92-
const label = createText("span", "toolbox-status-bar__label", "toolboxSelectedGameLabel");
93-
label.textContent = "Selected Game";
93+
const nameField = document.createElement("div");
94+
nameField.className = "toolbox-status-bar__field";
95+
nameField.dataset.toolboxSelectedGameNameField = "";
96+
const nameLabel = createText("span", "toolbox-status-bar__label", "toolboxSelectedGameNameLabel");
97+
nameLabel.textContent = "Selected Game Name";
9498
const name = createText("strong", "toolbox-status-bar__game-name", "toolboxSelectedGameName");
95-
const meta = createText("span", "toolbox-status-bar__meta", "toolboxSelectedGameMeta");
96-
game.append(label, name, meta);
99+
nameField.append(nameLabel, name);
100+
101+
const purposeField = document.createElement("div");
102+
purposeField.className = "toolbox-status-bar__field";
103+
purposeField.dataset.toolboxSelectedGamePurposeField = "";
104+
const purposeLabel = createText("span", "toolbox-status-bar__label", "toolboxSelectedGamePurposeLabel");
105+
purposeLabel.textContent = "Selected Game Purpose";
106+
const purpose = createText("span", "toolbox-status-bar__purpose", "toolboxSelectedGamePurpose");
107+
purpose.dataset.toolboxSelectedGameMeta = "";
108+
purposeField.append(purposeLabel, purpose);
109+
game.append(nameField, purposeField);
97110

98111
const center = document.createElement("div");
99112
center.className = "toolbox-status-bar__center";
100113
center.dataset.toolboxStatusCenter = "";
101114

115+
const contextType = createText("span", "pill toolbox-status-bar__context-type", "toolboxStatusContextType");
102116
const message = createText("p", "toolbox-status-bar__message status", "toolboxStatusMessage");
103117
message.setAttribute("role", "status");
104118
const action = document.createElement("a");
105119
action.className = "btn btn--compact toolbox-status-bar__action";
106120
action.dataset.toolboxStatusAction = "";
107121
action.href = mountOptions.gameHubHref;
108122
action.textContent = "Open Game Hub";
109-
center.append(message, action);
123+
center.append(contextType, message, action);
110124

111125
inner.append(game, center);
112126
bar.append(inner);
@@ -172,6 +186,12 @@ function updateLatestToolMessage() {
172186
}
173187
}
174188

189+
function scheduleToolMessageRefresh() {
190+
window.clearTimeout(pendingToolMessageRefresh);
191+
pendingToolMessageRefresh = window.setTimeout(updateLatestToolMessage, 0);
192+
window.setTimeout(updateLatestToolMessage, 120);
193+
}
194+
175195
function observeToolMessages() {
176196
messageObserver?.disconnect();
177197
const main = document.querySelector("main");
@@ -211,51 +231,76 @@ function publishSelectedGameContext(selectedGame, state) {
211231
}));
212232
}
213233

214-
function selectedGameMeta(selectedGame) {
215-
return [selectedGame.purpose, selectedGame.status]
216-
.map((value) => String(value || "").trim())
217-
.filter(Boolean)
218-
.join(" - ");
234+
function classifyToolContext(messageText, state, required) {
235+
const text = String(messageText || "").trim();
236+
if (state === "error") {
237+
return { kind: "error", label: "Error" };
238+
}
239+
if (required && state === "missing") {
240+
return { kind: "action", label: "Tool Action" };
241+
}
242+
if (/\b(error|failed|malformed|unavailable|could not)\b/i.test(text)) {
243+
return { kind: "error", label: "Error" };
244+
}
245+
if (/\b(sign in|refresh|try again|temporarily|blocked)\b/i.test(text)) {
246+
return { kind: "warning", label: "Warning" };
247+
}
248+
if (/\b(validation|requirement|requirements|missing|required|open or seed)\b/i.test(text)) {
249+
return { kind: "validation", label: "Validation" };
250+
}
251+
if (/\b(saved|created|deleted|updated|loaded|save changes)\b/i.test(text)) {
252+
return { kind: "save", label: "Save State" };
253+
}
254+
return { kind: "action", label: "Tool Action" };
219255
}
220256

221257
function renderSelectedGame(bar, selectedGame, state, messageText) {
222258
const required = pageRequiresSelectedGame();
223259
const name = bar.querySelector("[data-toolbox-selected-game-name]");
224-
const meta = bar.querySelector("[data-toolbox-selected-game-meta]");
260+
const purpose = bar.querySelector("[data-toolbox-selected-game-purpose]");
261+
const contextType = bar.querySelector("[data-toolbox-status-context-type]");
225262
const message = bar.querySelector("[data-toolbox-status-message]");
226263
const action = bar.querySelector("[data-toolbox-status-action]");
264+
const nextMessage = messageText || latestToolMessage || (selectedGame
265+
? `Tool context is filtered to ${selectedGame.name}.`
266+
: required
267+
? "Select or create a game in Game Hub before using this toolbox page."
268+
: "Idea Board can capture ideas before a Game Hub game exists.");
269+
const context = classifyToolContext(nextMessage, state, required);
227270

228271
bar.dataset.selectedGameState = state;
229272
bar.dataset.selectedGameRequired = String(required);
273+
bar.dataset.toolboxStatusContextKind = context.kind;
274+
contextType.textContent = context.label;
230275
action.hidden = false;
231276
action.href = mountOptions.gameHubHref;
232277

233278
if (selectedGame) {
234279
name.textContent = selectedGame.name;
235-
meta.textContent = selectedGameMeta(selectedGame) || "Game Hub selected game";
236-
message.textContent = messageText || latestToolMessage || `Data filtered to ${selectedGame.name}.`;
280+
purpose.textContent = selectedGame.purpose || "Game";
281+
message.textContent = nextMessage;
237282
action.textContent = "Open Game Hub";
238283
return;
239284
}
240285

241286
if (!required) {
242-
name.textContent = "Optional";
243-
meta.textContent = "Idea Board can start before Game Hub creation";
244-
message.textContent = latestToolMessage || "Idea Board can capture ideas before a Game Hub game exists.";
287+
name.textContent = "No game selected";
288+
purpose.textContent = "Idea Board optional";
289+
message.textContent = nextMessage;
245290
action.textContent = "Open Game Hub";
246291
return;
247292
}
248293

249294
if (state === "error") {
250295
name.textContent = "Unavailable";
251-
meta.textContent = "Game Hub selected game could not be read";
252-
message.textContent = messageText || "Game Hub selected game is unavailable. Refresh or restore the Local API.";
296+
purpose.textContent = "Game Hub selected game could not be read";
297+
message.textContent = nextMessage;
253298
action.textContent = "Open Game Hub";
254299
return;
255300
}
256301

257302
name.textContent = "No game selected";
258-
meta.textContent = "Game Hub owns game selection";
303+
purpose.textContent = "Game Hub owns game selection";
259304
message.textContent = "Select or create a game in Game Hub before using this toolbox page.";
260305
action.textContent = "Select or Create in Game Hub";
261306
}
@@ -284,6 +329,9 @@ function installEventListeners() {
284329
return;
285330
}
286331
listenersInstalled = true;
332+
document.addEventListener("click", scheduleToolMessageRefresh, true);
333+
document.addEventListener("submit", scheduleToolMessageRefresh, true);
334+
document.addEventListener("change", scheduleToolMessageRefresh, true);
287335
window.addEventListener("gamefoundry:toolbox-selected-game-changed", refreshToolboxStatusBar);
288336
window.addEventListener("gamefoundry:data-changed", refreshToolboxStatusBar);
289337
}

docs_build/dev/BUILD_PR.md

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,42 @@
1-
# PR_26175_ALFA_001-toolbox-selected-game-status-bar
1+
# PR_26175_ALFA_002-toolbox-status-bar-context-polish
22

33
## Purpose
4-
Add one shared Theme V2 toolbox status bar that surfaces the Game Hub selected game and current tool messages across toolbox pages.
4+
Polish the shared toolbox status bar context display so it shows only selected-game name/purpose on the left and categorized tool context in the center.
55

66
## Source Of Truth
7-
This `BUILD_PR.md` is the source of truth for `PR_26175_ALFA_001-toolbox-selected-game-status-bar`.
7+
This `BUILD_PR.md` is the source of truth for `PR_26175_ALFA_002-toolbox-status-bar-context-polish`.
88

99
## Exact Scope
10-
- Add a shared toolbox status bar renderer loaded through Theme V2 shared partial bootstrapping.
11-
- Render the status bar above the footer in normal page mode.
12-
- Anchor the status bar to the viewport bottom while `body.tool-focus-mode` is active.
13-
- Read the selected game only from the Game Hub repository through the existing Local API/service contract.
14-
- Display the selected Game Hub game on the left side of the status bar.
15-
- Display tool actions, warnings, errors, save state, validation messages, or the missing-game prompt in the center of the status bar.
16-
- Expose the selected Game Hub game as derived page context for toolbox pages without persisting browser-owned product data.
17-
- Require selected-game context on toolbox pages except Idea Board, which remains excluded because ideas can exist before game creation.
18-
- Show a creator-safe prompt to select or create a game in Game Hub when no selected game exists.
19-
- Notify the shared status bar when Game Hub changes the selected game.
20-
- Add targeted Playwright coverage for placement, fullscreen anchoring, selected-game display/update, missing-game prompt, and Idea Board exclusion.
10+
- Do not include environment text in the status bar because environment already appears in the platform banner.
11+
- On the left side, display the selected Game Hub game name and selected Game Hub game purpose.
12+
- On the center side, display tool context messages for tool actions, save state, validation messages, warnings, or errors.
13+
- Preserve normal placement above the footer.
14+
- Preserve fullscreen/tool display mode bottom anchoring.
15+
- Preserve Idea Board selected-game filtering exclusion.
16+
- Preserve Game Hub as selected-game owner through the existing repository contract.
17+
- Keep the shared Theme V2 toolbox component model.
18+
- Update targeted Playwright coverage for the polished left and center context.
2119

2220
## Exact Targets
23-
- `assets/theme-v2/js/gamefoundry-partials.js`
21+
- `docs_build/dev/BUILD_PR.md`
2422
- `assets/theme-v2/js/toolbox-status-bar.js`
2523
- `assets/theme-v2/css/status.css`
26-
- `toolbox/game-hub/game-hub.js`
2724
- `tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs`
28-
- `docs_build/dev/reports/PR_26175_ALFA_001-toolbox-selected-game-status-bar_report.md`
29-
- `docs_build/dev/reports/PR_26175_ALFA_001-toolbox-selected-game-status-bar_validation-lane.md`
30-
- `docs_build/dev/reports/PR_26175_ALFA_001-toolbox-selected-game-status-bar_requirements-checklist.md`
25+
- `docs_build/dev/reports/PR_26175_ALFA_002-toolbox-status-bar-context-polish_report.md`
26+
- `docs_build/dev/reports/PR_26175_ALFA_002-toolbox-status-bar-context-polish_validation-lane.md`
27+
- `docs_build/dev/reports/PR_26175_ALFA_002-toolbox-status-bar-context-polish_requirements-checklist.md`
28+
- `docs_build/dev/reports/codex_review.diff`
29+
- `docs_build/dev/reports/codex_changed_files.txt`
3130

3231
## Out Of Scope
32+
- No environment status in the toolbox status bar.
33+
- No row highlights.
34+
- No large banners.
35+
- No modal-style status messages.
36+
- No inline styles, style blocks, or page-local CSS.
37+
- No API/service contract changes.
3338
- No engine core changes.
3439
- No `start_of_day` folder changes.
35-
- No API/service contract changes.
36-
- No page-local CSS, inline styles, or style blocks.
37-
- No browser storage or browser-owned product data as selected-game source of truth.
38-
- No Idea Board selected-game filtering.
3940

4041
## Validation
4142
Run:
@@ -47,12 +48,12 @@ npx playwright test tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs
4748
Also verify the changed source does not introduce inline styles or style blocks:
4849

4950
```powershell
50-
rg -n "<style|style=" assets/theme-v2/js/gamefoundry-partials.js assets/theme-v2/js/toolbox-status-bar.js assets/theme-v2/css/status.css toolbox/game-hub/game-hub.js tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs
51+
rg -n "<style|style=" assets/theme-v2/js/toolbox-status-bar.js assets/theme-v2/css/status.css tests/playwright/tools/ToolboxSelectedGameStatusBar.spec.mjs
5152
```
5253

5354
## Artifact
5455
Create repo-structured delta ZIP:
5556

5657
```text
57-
tmp/PR_26175_ALFA_001-toolbox-selected-game-status-bar_delta.zip
58+
tmp/PR_26175_ALFA_002-toolbox-status-bar-context-polish_delta.zip
5859
```
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# PR_26175_ALFA_002-toolbox-status-bar-context-polish Report
2+
3+
## Summary
4+
Polished the shared toolbox status bar context display without changing ownership or placement behavior.
5+
6+
## Changes
7+
- Updated the left side to show `Selected Game Name` and `Selected Game Purpose`.
8+
- Removed selected-game status from the left-side display so environment/status context stays outside the bar.
9+
- Added a compact center context label for `Tool Action`, `Save State`, `Validation`, `Warning`, and `Error`.
10+
- Kept the status bar as a compact shared Theme V2 component, not a large banner or modal-style message.
11+
- Preserved normal placement above the footer and fullscreen bottom anchoring.
12+
- Preserved Idea Board selected-game filtering exclusion.
13+
14+
## Contract Notes
15+
- Game Hub remains the selected-game owner through the existing repository contract.
16+
- No API/service contract changes were made.
17+
- No browser-owned product data is used as selected-game source of truth.
18+
- Environment text is not displayed in the status bar.
19+
20+
## EOD Review
21+
- Reviewed all ALFA_002 modified files before commit.
22+
- Re-ran the targeted Playwright status bar coverage.
23+
- Re-ran the inline style/style block guardrail.
24+
- Updated the Codex review diff and changed-file report for closeout.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# PR_26175_ALFA_002-toolbox-status-bar-context-polish Requirements Checklist
2+
3+
- PASS: Active `BUILD_PR.md` is the source of truth for ALFA_002.
4+
- PASS: Environment is not included in the status bar.
5+
- PASS: Left side displays selected game name.
6+
- PASS: Left side displays selected game purpose.
7+
- PASS: Center displays tool action context.
8+
- PASS: Center displays save state context.
9+
- PASS: Center supports validation, warning, and error context categories.
10+
- PASS: Fullscreen bottom anchoring is preserved.
11+
- PASS: Normal placement above the footer is preserved.
12+
- PASS: Idea Board exclusion is preserved.
13+
- PASS: Game Hub remains selected-game owner.
14+
- PASS: No large banners were added.
15+
- PASS: No modal-style status messages were added.
16+
- PASS: No inline styles or style blocks were added.
17+
- PASS: Theme V2 shared CSS/classes are used.
18+
- PASS: Targeted Playwright coverage was updated and passed.

0 commit comments

Comments
 (0)