@bongos/core 1.25.7 → 1.25.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.bongos-core.json +23 -23
- package/docs/copy-inventory.md +402 -402
- package/docs/copy-registry.json +497 -497
- package/docs/module-api-changelog.md +4 -0
- package/docs/page-readings.json +284 -284
- package/modules/hall-ui/public/style.css +2 -2
- package/modules/hall-ui/public/visor.css +33 -5
- package/modules/hall-ui/records/options-menu.md +1 -1
- package/modules/hall-ui/records/visor.md +8 -0
- package/modules/provisioning/github-setup.js +3 -0
- package/modules/public-landing/public/projects.html +11 -3
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +7 -0
- package/src/module-api.js +1 -1
- package/tests/github_one_trip.mjs +8 -1
- package/tests/github_sign_in_seen.mjs +1 -1
- package/tests/hall_game_menu.mjs +29 -0
- package/tests/hall_visor_profile.mjs +40 -1
|
@@ -895,7 +895,7 @@ html[data-theme="dark"] .brand-mark__mark { --mark-ink: #e2e1e4; }
|
|
|
895
895
|
and the shell’s corner buttons, so the top arc, its notch and the place all step aside. The foot row keeps its three parts in one line and nothing leans: the sprite
|
|
896
896
|
with the count over its word, the one accent button (its name may take two lines; its key is in the sheet), and of
|
|
897
897
|
the key hints only Actions, as its dots (every other hint is a row in its sheet). */
|
|
898
|
-
|
|
898
|
+
:root[data-game="on"] { --visor-inset-bottom: 52px; --visor-foot-room: 112px; }
|
|
899
899
|
html[data-game="on"] .visor__place, html[data-game="on"] .visor__progress, html[data-game="on"] .visor__notch, html[data-game="on"] .visor__frame--top, html[data-game="on"] .visor__name { display: none; }
|
|
900
900
|
html[data-game="on"] .visor__foot { grid-template-columns: auto minmax(0, 1fr) auto; column-gap: var(--ds-space-hair); }
|
|
901
901
|
html[data-game="on"] .visor__me, html[data-game="on"] .visor__hints { transform: none; }
|
|
@@ -914,7 +914,7 @@ html[data-theme="dark"] .brand-mark__mark { --mark-ink: #e2e1e4; }
|
|
|
914
914
|
html[data-game="on"] .visor__who, html[data-game="on"] .visor__hint { background: var(--night-plate); box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
|
|
915
915
|
html[data-game="on"] .visor__hint--sheet > :not(.visor__dots) { position: absolute; width: 1px; height: 1px; padding: 0; border: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
|
|
916
916
|
html[data-game="on"] .visor__main .visor__key { display: none; }
|
|
917
|
-
html[data-game="on"] .visor__sheet {
|
|
917
|
+
html[data-game="on"] .visor__sheet { max-height: 60vh; }
|
|
918
918
|
}
|
|
919
919
|
/* task 1004424 (BV2.PS10): THE FOUNDING MARK. A pill in .rank-badge's grammar (same
|
|
920
920
|
height, type and radius) so it sits beside a rank without competing with it; the
|
|
@@ -10,11 +10,15 @@
|
|
|
10
10
|
the night, and the place, each hint and your credits stand on a small night plate. Colours, sizes and corners
|
|
11
11
|
are the hall tier's tokens; nothing here is typed in. Record: modules/hall-ui/records/visor.md. */
|
|
12
12
|
.visor { display: none; }
|
|
13
|
+
/* where the glass sits, so a scene's pop-up, and a window the glass opens, can keep clear of
|
|
14
|
+
it (ADR 0399 §2.3). On the root, not the visor, because the options window is not inside
|
|
15
|
+
it. --visor-foot-room is the foot row's height with the hints wrapped onto a second line. */
|
|
16
|
+
html[data-game="on"] {
|
|
17
|
+
--visor-arc: 64px; --visor-inset-top: 88px; --visor-inset-bottom: 76px; --visor-foot-room: 100px;
|
|
18
|
+
--visor-inset-right: max(var(--ds-space-gutter-narrow), var(--helm-inset)); --visor-inset-left: var(--visor-inset-right);
|
|
19
|
+
}
|
|
13
20
|
html[data-game="on"] .visor:not([hidden]) {
|
|
14
21
|
display: block; position: fixed; inset: 0; z-index: 4; pointer-events: none;
|
|
15
|
-
/* where the glass sits, so a scene's pop-up can keep clear of it (ADR 0399 §2.3) */
|
|
16
|
-
--visor-arc: 64px; --visor-inset-top: 88px; --visor-inset-bottom: 76px;
|
|
17
|
-
--visor-inset-right: max(var(--ds-space-gutter-narrow), var(--helm-inset)); --visor-inset-left: var(--visor-inset-right);
|
|
18
22
|
color: var(--ink); font-family: var(--font-body);
|
|
19
23
|
}
|
|
20
24
|
|
|
@@ -187,9 +191,9 @@ html[data-game="on"] .visor:not([hidden]) {
|
|
|
187
191
|
panel between two strong hairlines, standing over the hints that opened it, clear of the foot
|
|
188
192
|
row even when the hints have wrapped onto a second line. */
|
|
189
193
|
.visor__sheet {
|
|
190
|
-
position: absolute; right: var(--visor-inset-right); bottom: calc(var(--visor-inset-bottom) +
|
|
194
|
+
position: absolute; right: var(--visor-inset-right); bottom: calc(var(--visor-inset-bottom) + var(--visor-foot-room)); z-index: 1;
|
|
191
195
|
pointer-events: auto; box-sizing: border-box; width: min(18rem, calc(100vw - 2 * var(--ds-space-gutter-narrow)));
|
|
192
|
-
max-height: calc(100% - var(--visor-inset-top) - var(--visor-inset-bottom) -
|
|
196
|
+
max-height: calc(100% - var(--visor-inset-top) - var(--visor-inset-bottom) - var(--visor-foot-room)); overflow-y: auto;
|
|
193
197
|
padding: var(--ds-space-sm); background: var(--bg-card);
|
|
194
198
|
border: 0 solid var(--rule); border-left-width: var(--line-strong); border-right-width: var(--line-strong);
|
|
195
199
|
}
|
|
@@ -237,5 +241,29 @@ html[data-game="on"] .visor:not([hidden]) {
|
|
|
237
241
|
.visor__focus .visor__key { color: var(--ink-soft); background: none; }
|
|
238
242
|
.visor__main--lead[aria-busy="true"] { cursor: progress; background: var(--accent-lift); }
|
|
239
243
|
|
|
244
|
+
/* A WINDOW THE GLASS OPENS OPENS IN THE GLASS (task 1005253, ADR 0403; owner 2026-11-13). The
|
|
245
|
+
options window and your profile (shell-game.js openOverlay, .opt-window) and the game menu
|
|
246
|
+
(openMenu, .game-menu) are reached from the visor, so they never cover it: in game mode each
|
|
247
|
+
fits between the top arc and the foot row, and the visor is drawn over its scrim, undimmed,
|
|
248
|
+
as the frame you see it through. While one is up the glass is a picture: nothing on it takes
|
|
249
|
+
a pointer (the window is modal and keeps the keyboard), the sight leaves the window's middle,
|
|
250
|
+
and the glass's own pop-ups (the sheet, the scene's pick, your card) step aside. */
|
|
251
|
+
html.visor-on .opt-window, html.visor-on .game-menu {
|
|
252
|
+
box-sizing: border-box;
|
|
253
|
+
padding: var(--visor-inset-top) var(--visor-inset-right) calc(var(--visor-inset-bottom) + var(--visor-foot-room)) var(--visor-inset-left);
|
|
254
|
+
}
|
|
255
|
+
html.visor-on .opt-window__box { width: min(1040px, 100%); height: min(720px, 100%); }
|
|
256
|
+
html.visor-on .game-menu__box { max-height: 100%; }
|
|
257
|
+
html.visor-on:is(.opt-window-open, .game-menu-open) .visor:not([hidden]) { z-index: calc(var(--ds-z-modal, 160) + 1); }
|
|
258
|
+
html.visor-on:is(.opt-window-open, .game-menu-open) .visor * { pointer-events: none; }
|
|
259
|
+
html.visor-on:is(.opt-window-open, .game-menu-open) :is(.visor__sight, .visor__sheet, .visor__focus, .visor__card) { visibility: hidden; }
|
|
260
|
+
/* THE GAME MENU IS THE ONE THING IN FOCUS (owner 2026-11-13): the place behind it is frosted
|
|
261
|
+
(the hall's glass blur, under the glass, so the visor's lines stay sharp), and everything on
|
|
262
|
+
the glass but its two arcs steps back, so the eye goes to the menu. The arcs stay as the frame
|
|
263
|
+
the menu is held in. */
|
|
264
|
+
html.visor-on .game-menu { -webkit-backdrop-filter: blur(var(--glass-blur)); backdrop-filter: blur(var(--glass-blur)); }
|
|
265
|
+
html.visor-on .visor > :not(.visor__frame, .visor__notch) { transition: opacity var(--ds-dur-fast) var(--ds-ease); }
|
|
266
|
+
html.visor-on.game-menu-open .visor > :not(.visor__frame, .visor__notch) { opacity: .25; }
|
|
267
|
+
|
|
240
268
|
/* a phone (640px and narrower): the rules live in style.css’s shared phone block, so the
|
|
241
269
|
visor adds no breakpoint of its own (the design-count ratchet). */
|
|
@@ -28,6 +28,6 @@ The menu is a Helm screen, written from the hall tier's tokens alone (`settings.
|
|
|
28
28
|
## The options window (owner, 2026-11-11: "WoW sizing, an overlay")
|
|
29
29
|
|
|
30
30
|
- **In game mode the menu opens over the place, not as a page.** The game menu's Options row (task 1005250, `records/game-menu.md`; until then Escape itself), or a click on any link to `/settings` (the profile chip), draws one window (`shell-game.js` `openOverlay`, `window.OTBOptionsOverlay`), built on the shared dialog (`OTBDialog.bind`: Escape, scrim, close button, focus trap and return), with the page behind made `inert` while it is up, holding the menu framed with `?embed=1`; the place stays drawn behind it. Escape, the scrim or the × shuts it; `options-menu.js` `close()` shuts the window when it is in one. A page that cannot draw it falls back to the menu page. A plain visit to `/settings` is the page, as before.
|
|
31
|
-
- **Window sized, see-through.** The window is `min(1040px, …) × min(720px, …)` of glass at 48% of the ground with a light blur, over the shared `--scrim` at a third. Every embedded screen is drawn at `zoom: 0.82` with no ground of its own (`style.css`), and the menu inside it takes smaller words (`settings.css`, `html[data-embed="on"]`); a window-high length divides by the zoom (`--opt-vh`).
|
|
31
|
+
- **Window sized, see-through.** The window is `min(1040px, …) × min(720px, …)` of glass at 48% of the ground with a light blur, over the shared `--scrim` at a third. Every embedded screen is drawn at `zoom: 0.82` with no ground of its own (`style.css`), and the menu inside it takes smaller words (`settings.css`, `html[data-embed="on"]`); a window-high length divides by the zoom (`--opt-vh`). In game mode with the visor up the window fits inside the glass, between the top arc and the foot row, and never covers the visor (task 1005253, `records/visor.md`).
|
|
32
32
|
- **One review palette.** A framed screen docks no artist palette of its own (`craft-mode.js` `applyDocked`); the page around it has one.
|
|
33
33
|
- **Tests:** `tests/hall_options_menu.mjs` ("away from the menu, Escape opens the options as a window…"), `tests/page_notes_panel.mjs` (the frame docks no panel).
|
|
@@ -6,6 +6,14 @@ Covers: `visor.js` + `visor.css`, loaded on Home, `/city`, `/goal-map` and `/thi
|
|
|
6
6
|
|
|
7
7
|
The visor is the control and the scene is the view: every main call to action in game mode is on the glass (the accent button, the key hints, the Actions sheet), and a scene carries none of its own. A scene that has something to do registers it with `OTBVisor.scene({ actions, keys })`. ADR 0403 §3 lists the scenes that do not keep it yet; the Governor City keeps it since task 1005209 the sky since task 1005210, and Home's gallery since task 1005211 (below).
|
|
8
8
|
|
|
9
|
+
## A window the glass opens opens in the glass (task 1005253, owner 2026-11-13)
|
|
10
|
+
|
|
11
|
+
- **The bug.** The options window and your profile window (`shell-game.js` `openOverlay`, `.opt-window`), and the game menu (`openMenu`, `.game-menu`, task 1005250), are reached from the visor, yet they opened as a box over the whole screen and covered the visor itself: the arcs, the place, your credits, the accent button and the hints.
|
|
12
|
+
- **The rule.** A menu or window the visor opens never covers the visor. In game mode (`html.visor-on`) the window fits between the top arc (`--visor-inset-top`) and the foot row (`--visor-inset-bottom` + `--visor-foot-room`), inside the side insets, and the visor is drawn over the window's scrim, undimmed, as the frame it is seen through (`visor.css`). While a window is up the glass is a picture: none of it takes a pointer (the window is modal and keeps the keyboard), the sight leaves the window's middle, and the glass's own pop-ups (the sheet, the scene's pick, your card) step aside. Shut, the glass goes back to z 4.
|
|
13
|
+
- **The game menu is the one thing in focus** (owner, same day: "a frosted glass or blur… so the user focuses specifically on the game menu"). While it is up the place behind it is frosted (`backdrop-filter` with the hall's `--glass-blur`, on `.game-menu`, so it is under the glass and the visor's lines stay sharp), and everything on the glass but its two arcs and the notch fades to a quarter. The options and profile windows are glass of their own and keep the visor whole around them.
|
|
14
|
+
- **The glass's measures are on the root now** (`html[data-game="on"]`, and the phone block's `:root[data-game="on"]`), not on `#visor`, because the window is not inside the visor. The sheet reads `--visor-foot-room` too, so the sheet and a window keep the same clearance over the foot row. Classic mode keeps the centred window.
|
|
15
|
+
- **Tests:** `tests/hall_visor_profile.mjs` ("a window the visor opens sits inside the glass…", at a desk and a phone width).
|
|
16
|
+
|
|
9
17
|
## One owner per key (task 1005248, owner 2026-11-12)
|
|
10
18
|
|
|
11
19
|
- **The bug.** The Artist saw Esc twice: "Options" on the glass, then in the Actions sheet both Close and the Options row said Esc.
|
|
@@ -134,6 +134,9 @@ function githubChecklist(status, appSlug, facts = {}) {
|
|
|
134
134
|
// what "is alive" waits for — device flow is optional by design
|
|
135
135
|
connected: approve === 'done' && install === 'done' && signIn === 'done',
|
|
136
136
|
wired_elsewhere: elsewhere,
|
|
137
|
+
// GitHub sent the founder back from the install page (or they asked for a check) and
|
|
138
|
+
// the runner has not confirmed it yet: the page shows the step as being checked
|
|
139
|
+
install_checking: install !== 'done' && !!(facts.installReportedAt || facts.checkRequestedAt),
|
|
137
140
|
};
|
|
138
141
|
}
|
|
139
142
|
|
|
@@ -533,7 +533,10 @@ body:has(#view-new:not([hidden])) footer.foot{position:relative;z-index:1;backgr
|
|
|
533
533
|
.setFact .optional{margin-left:8px;font-family:var(--label-face);font-size:var(--label-size);letter-spacing:var(--label-space);text-transform:uppercase;color:var(--ink-faint);}
|
|
534
534
|
.setFact.done .d{background:color-mix(in srgb,var(--ok) 12%,transparent);color:var(--ok);border-color:var(--ok);}
|
|
535
535
|
.setFact.done .t,.setFact.now .t,.setFact.you .t{color:var(--ink);}
|
|
536
|
-
.setFact.now .d{border:2px solid var(--accent);}
|
|
536
|
+
.setFact.now .d{border:2px solid var(--accent);border-top-color:transparent;animation:factSpin 1s linear infinite;}
|
|
537
|
+
/* a loading wheel is essential, so it turns even with reduced motion (slower, no pulse) */
|
|
538
|
+
@media (prefers-reduced-motion:reduce){.setFact.now .d{animation-duration:2s;}}
|
|
539
|
+
@keyframes factSpin{to{transform:rotate(360deg)}}
|
|
537
540
|
.setFact.you .d{background:color-mix(in srgb,var(--accent) 16%,transparent);border-color:color-mix(in srgb,var(--accent) 60%,transparent);color:var(--ink);}
|
|
538
541
|
.setFact.bad .d{background:color-mix(in srgb,var(--err) 10%,transparent);color:var(--err);border-color:var(--err);}
|
|
539
542
|
.setFact.bad .t{color:var(--err);}
|
|
@@ -548,8 +551,7 @@ body:has(#view-new:not([hidden])) footer.foot{position:relative;z-index:1;backgr
|
|
|
548
551
|
.setFact .acctPick .acctTyped{margin-top:10px;}
|
|
549
552
|
.setFact .acctPick .hint{min-height:0;}
|
|
550
553
|
@media (prefers-reduced-motion:no-preference){
|
|
551
|
-
.setFact.now .d{animation:factBreathe 1.4s ease-in-out infinite,factSpin 1s linear infinite;
|
|
552
|
-
@keyframes factSpin{to{transform:rotate(360deg)}}
|
|
554
|
+
.setFact.now .d{animation:factBreathe 1.4s ease-in-out infinite,factSpin 1s linear infinite;}
|
|
553
555
|
.setNow.working::after{content:"";display:inline-block;width:1.2em;text-align:left;animation:workDots 1.4s steps(4,end) infinite;}
|
|
554
556
|
@keyframes workDots{0%{content:""}25%{content:"."}50%{content:".."}75%{content:"..."}}
|
|
555
557
|
@keyframes factBreathe{0%,100%{border-color:var(--accent)}50%{border-color:color-mix(in srgb,var(--accent) 35%,transparent)}}
|
|
@@ -6933,6 +6935,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6933
6935
|
sentence and carries the action that fixes it, with the app GitHub already made, never a
|
|
6934
6936
|
second one. live.pickUp is the server's word for what that action does (github-setup.js
|
|
6935
6937
|
pickUpFor); live.verifying is whether the runner is still checking. */
|
|
6938
|
+
var installOpened = false; /* this page sent the founder to GitHub's install page */
|
|
6936
6939
|
var ghTabTrouble = null; /* 'behind' | 'closed': what this page saw of the GitHub tab it opened */
|
|
6937
6940
|
var NO_SECOND_APP = 'Nothing is lost, and no second app will be made.';
|
|
6938
6941
|
function projectName() { return state.name || state.slug || 'your project'; }
|
|
@@ -7067,6 +7070,10 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
7067
7070
|
/* the runner stopped checking and GitHub never confirmed the install: the link opens the
|
|
7068
7071
|
SAME app's install page, and the click asks the runner to look again */
|
|
7069
7072
|
else if (live.pickUp === 'check') { install.state = 'bad'; install.sub = 'GitHub stopped before the app was on ' + (repo || 'your repo') + '.'; install.right = checked; install.act = 'pick-up-link'; install.href = installUrl; }
|
|
7073
|
+
/* the founder came back from GitHub's install page (GitHub reported it, or they pressed
|
|
7074
|
+
the link here): the runner is checking with GitHub, so the step spins until it ticks,
|
|
7075
|
+
and the link stays in case they never finished */
|
|
7076
|
+
else if ((live.setup && live.setup.install_checking) || installOpened) { install.state = 'now'; install.sub = (repo ? repo + '. ' : '') + 'Checking with GitHub. This ticks by itself.'; install.right = checked; install.act = 'install-link'; install.href = installUrl; }
|
|
7070
7077
|
else { install.state = 'you'; install.right = 'not yet seen'; install.act = 'install-link'; install.href = installUrl; }
|
|
7071
7078
|
|
|
7072
7079
|
var signIn = { key: 'sign_in', title: 'Builders can sign in' };
|
|
@@ -7313,6 +7320,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
7313
7320
|
var ib = $('installBtn'), instRow = gh[1];
|
|
7314
7321
|
var instHref = instRow && instRow.state !== 'done' && homeUp && (instRow.act === 'install-link' || instRow.act === 'pick-up-link') ? installHrefOf(instRow) : '';
|
|
7315
7322
|
if (instHref) ib.setAttribute('href', instHref); else ib.removeAttribute('href');
|
|
7323
|
+
if (!ib.getAttribute('data-wired')) { ib.setAttribute('data-wired', '1'); ib.addEventListener('click', function () { installOpened = true; paintFacts(); }); }
|
|
7316
7324
|
ib.hidden = !instHref;
|
|
7317
7325
|
paintSetDone(ready, home, gh);
|
|
7318
7326
|
tipsRun(!ready);
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.25.
|
|
3
|
+
"version": "1.25.9",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.25.
|
|
9
|
+
"version": "1.25.9",
|
|
10
10
|
"license": "AGPL-3.0-or-later",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^4.21.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.25.
|
|
3
|
+
"version": "1.25.9",
|
|
4
4
|
"description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"main": "src/platform-server.js",
|
package/release-notes.json
CHANGED
|
@@ -11753,5 +11753,12 @@
|
|
|
11753
11753
|
"id": "1005219",
|
|
11754
11754
|
"text": "Opening the builders' hall now starts on the Game or Classic choice. Signed out, your pick takes you to sign in and then straight to that menu."
|
|
11755
11755
|
}
|
|
11756
|
+
],
|
|
11757
|
+
"1.25.8": [],
|
|
11758
|
+
"1.25.9": [
|
|
11759
|
+
{
|
|
11760
|
+
"id": "1005253",
|
|
11761
|
+
"text": "In game mode, the windows the visor opens (Options, your profile, the game menu) now open inside the visor instead of covering it, and the game menu blurs the place behind it and quiets the visor so it is the one thing in focu"
|
|
11762
|
+
}
|
|
11756
11763
|
]
|
|
11757
11764
|
}
|
package/src/module-api.js
CHANGED
|
@@ -81,7 +81,7 @@ const { sleep } = require('./sleep');
|
|
|
81
81
|
// MAJOR (see allowBoxScope below): passes the request through untouched.
|
|
82
82
|
function deprecatedNoopMiddleware(_req, _res, next) { next(); }
|
|
83
83
|
|
|
84
|
-
const CORE_VERSION = '1.25.
|
|
84
|
+
const CORE_VERSION = '1.25.9'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
85
85
|
|
|
86
86
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
87
87
|
// Usage: const log = api.logger('discord'); log.info('mounted');
|
|
@@ -35,7 +35,7 @@ const SCRIPT = HUB.slice(HUB.lastIndexOf('<script>'), HUB.lastIndexOf('</script>
|
|
|
35
35
|
|
|
36
36
|
test('each step reads only what the server has seen — the honest "not yet" states included', () => {
|
|
37
37
|
const none = GS.githubChecklist(null, null);
|
|
38
|
-
assert.deepEqual(none, { approve: 'todo', install: 'todo', sign_in: 'todo', device_flow: 'todo', connected: false, wired_elsewhere: false }, 'never started');
|
|
38
|
+
assert.deepEqual(none, { approve: 'todo', install: 'todo', sign_in: 'todo', device_flow: 'todo', connected: false, wired_elsewhere: false, install_checking: false }, 'never started');
|
|
39
39
|
assert.equal(GS.githubChecklist('pending', null).approve, 'now', 'waiting for the approval on GitHub');
|
|
40
40
|
for (const s of ['code_received', 'converting']) {
|
|
41
41
|
const c = GS.githubChecklist(s, null);
|
|
@@ -327,3 +327,10 @@ test('the device-flow finding lives in the direction doc, and the code points at
|
|
|
327
327
|
assert.match(doc, /Device flow cannot be switched on for the founder \(spike, task 1004649\)/);
|
|
328
328
|
assert.match(fs.readFileSync(path.join(ROOT, 'modules', 'provisioning', 'github-setup.js'), 'utf8'), /docs\/design\/project-startup-direction\.md/);
|
|
329
329
|
});
|
|
330
|
+
|
|
331
|
+
test('back from the install page, the install step reads as being checked until GitHub confirms it', () => {
|
|
332
|
+
const { githubChecklist } = require('../modules/provisioning/github-setup.js');
|
|
333
|
+
assert.equal(githubChecklist('done', 'kestrel', {}).install_checking, false, 'not reported yet');
|
|
334
|
+
assert.equal(githubChecklist('done', 'kestrel', { installReportedAt: '2026-10-25T10:00:00Z' }).install_checking, true, 'reported, not yet seen');
|
|
335
|
+
assert.equal(githubChecklist('done', 'kestrel', { installReportedAt: '2026-10-25T10:00:00Z', installedAt: '2026-10-25T10:01:00Z' }).install_checking, false, 'seen: done');
|
|
336
|
+
});
|
|
@@ -53,7 +53,7 @@ test('the project saying sign-in works ticks sign-in, whatever the attempt row s
|
|
|
53
53
|
|
|
54
54
|
test('without that answer, nothing changes: a pending attempt still waits on GitHub', () => {
|
|
55
55
|
const c = gs.githubChecklist('pending', null, {});
|
|
56
|
-
assert.deepEqual(c, { approve: 'now', install: 'todo', sign_in: 'todo', device_flow: 'todo', connected: false, wired_elsewhere: false });
|
|
56
|
+
assert.deepEqual(c, { approve: 'now', install: 'todo', sign_in: 'todo', device_flow: 'todo', connected: false, wired_elsewhere: false, install_checking: false });
|
|
57
57
|
});
|
|
58
58
|
|
|
59
59
|
test('with our app recorded, the answer ticks sign-in and the install keeps its own fact', () => {
|
package/tests/hall_game_menu.mjs
CHANGED
|
@@ -93,6 +93,35 @@ test('Escape in a game place opens the game menu, not the options; Escape again
|
|
|
93
93
|
await ctx.close();
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
+
// task 1005253 (owner, 2026-11-13): the menu is in the glass and is the one thing in focus. The
|
|
97
|
+
// place behind it is frosted, the visor stays over it with only its arcs at full strength, and
|
|
98
|
+
// it ends above the foot row.
|
|
99
|
+
test('the game menu is the one thing in focus: the place frosted, the glass quiet but for its arcs', { skip }, async () => {
|
|
100
|
+
const { ctx, page, errors } = await open();
|
|
101
|
+
await escape(page);
|
|
102
|
+
assert.equal(await menuUp(page), true);
|
|
103
|
+
await page.waitForTimeout(300); // the glass's fade
|
|
104
|
+
const f = await page.evaluate(() => {
|
|
105
|
+
const cs = (s) => getComputedStyle(document.querySelector(s));
|
|
106
|
+
return {
|
|
107
|
+
blur: cs('.game-menu').backdropFilter,
|
|
108
|
+
visorOver: Number(cs('#visor').zIndex) > Number(cs('.game-menu').zIndex),
|
|
109
|
+
foot: Number(cs('.visor__foot').opacity), arc: Number(cs('.visor__frame--top').opacity),
|
|
110
|
+
clear: document.querySelector('.game-menu__box').getBoundingClientRect().bottom <= document.querySelector('.visor__foot').getBoundingClientRect().top,
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
assert.match(f.blur, /^blur\(\d/, 'the place behind is frosted');
|
|
114
|
+
assert.ok(f.visorOver, 'the glass stays over the menu\'s scrim');
|
|
115
|
+
assert.ok(f.foot < 0.5, 'the buttons and words on the glass step back');
|
|
116
|
+
assert.equal(f.arc, 1, 'the arcs hold the menu at full strength');
|
|
117
|
+
assert.ok(f.clear, 'the menu ends above the foot row');
|
|
118
|
+
await escape(page);
|
|
119
|
+
await page.waitForTimeout(300);
|
|
120
|
+
assert.equal(await page.evaluate(() => Number(getComputedStyle(document.querySelector('.visor__foot')).opacity)), 1, 'shut, the glass is whole again');
|
|
121
|
+
assert.deepEqual(errors, []);
|
|
122
|
+
await ctx.close();
|
|
123
|
+
});
|
|
124
|
+
|
|
96
125
|
test('Return to game shuts the menu; Options opens the options window in its place', { skip }, async () => {
|
|
97
126
|
const { ctx, page, errors } = await open();
|
|
98
127
|
await escape(page);
|
|
@@ -65,7 +65,7 @@ const SCENE = `<script>
|
|
|
65
65
|
window.__visorScene = { name: 'test', place: 'Test city', actions: [], keys: [] };
|
|
66
66
|
</script>`;
|
|
67
67
|
const PAGE = (withWindow) => `<!doctype html><html data-theme="dark" data-faces="helm"><head><meta charset="utf-8">
|
|
68
|
-
<link rel="stylesheet" href="/builders/style.css"><link rel="stylesheet" href="/builders/visor.css"></head>
|
|
68
|
+
<link rel="stylesheet" href="/tokens.css"><link rel="stylesheet" href="/builders/style.css"><link rel="stylesheet" href="/builders/visor.css"></head>
|
|
69
69
|
<body>${SCENE}<script src="/builders/hall-dialog.js"></script>${withWindow ? '<script src="/builders/shell-game.js"></script>' : ''}<script src="/builders/visor.js"></script></body></html>`;
|
|
70
70
|
|
|
71
71
|
async function open({ withWindow = true } = {}) {
|
|
@@ -73,6 +73,7 @@ async function open({ withWindow = true } = {}) {
|
|
|
73
73
|
await ctx.route(ORIGIN + '/**', (route) => {
|
|
74
74
|
const p = new URL(route.request().url()).pathname;
|
|
75
75
|
if (p === '/') return route.fulfill({ contentType: 'text/html', body: PAGE(withWindow) });
|
|
76
|
+
if (p === '/tokens.css') return route.fulfill({ contentType: 'text/css', body: fs.readFileSync(path.join(ROOT, 'modules/ui-design/public/tokens.css')) }); // the design tokens the hall loads first
|
|
76
77
|
if (p === '/profile') return route.fulfill({ contentType: 'text/html', body: '<!doctype html><title>profile</title><p id="pp">your profile</p><script src="/builders/shell-game.js"></script>' }); // the real page carries the game shell, which hands an Escape up
|
|
77
78
|
const f = path.join(HALL, p.replace(/^\/builders\//, ''));
|
|
78
79
|
if (p.startsWith('/builders/') && TYPES[path.extname(p)] && fs.existsSync(f)) return route.fulfill({ contentType: TYPES[path.extname(p)], body: fs.readFileSync(f) });
|
|
@@ -133,6 +134,44 @@ test('clicking you opens your whole profile in the window over the place; Escape
|
|
|
133
134
|
await ctx.close();
|
|
134
135
|
});
|
|
135
136
|
|
|
137
|
+
// task 1005253 (owner, 2026-11-13): a window the glass opens opens IN the glass. It never covers
|
|
138
|
+
// the visor: it sits under the top arc and above the foot row, the visor is drawn over its scrim,
|
|
139
|
+
// and while it is up nothing on the glass takes a pointer and the glass's own pop-ups step aside.
|
|
140
|
+
test('a window the visor opens sits inside the glass, and the visor stays drawn around it', { skip }, async () => {
|
|
141
|
+
for (const viewport of [{ width: 1280, height: 800 }, { width: 390, height: 844 }]) {
|
|
142
|
+
const { ctx, page, errors } = await open();
|
|
143
|
+
await page.setViewportSize(viewport);
|
|
144
|
+
await page.evaluate(() => window.OTBOptionsOverlay.open(''));
|
|
145
|
+
await page.waitForFunction(() => window.OTBOptionsOverlay.isOpen());
|
|
146
|
+
const g = await page.evaluate(() => {
|
|
147
|
+
const r = (s) => document.querySelector(s).getBoundingClientRect();
|
|
148
|
+
const box = r('.opt-window__box'); const foot = r('.visor__foot'); const main = r('.visor__main');
|
|
149
|
+
const z = (s) => Number(getComputedStyle(document.querySelector(s)).zIndex);
|
|
150
|
+
// what is on top at the centre of the accent button: the glass, not the window
|
|
151
|
+
const hit = document.elementsFromPoint(main.left + main.width / 2, main.top + main.height / 2);
|
|
152
|
+
return {
|
|
153
|
+
top: box.top, bottom: box.bottom, footTop: foot.top, place: getComputedStyle(document.documentElement).getPropertyValue('--visor-inset-top').trim(),
|
|
154
|
+
visorOver: z('#visor') > z('.opt-window'),
|
|
155
|
+
buttonUnder: hit.some((el) => el.closest && el.closest('.opt-window__box')),
|
|
156
|
+
mainPointer: getComputedStyle(document.querySelector('.visor__main')).pointerEvents,
|
|
157
|
+
sight: getComputedStyle(document.querySelector('.visor__sight')).visibility,
|
|
158
|
+
};
|
|
159
|
+
});
|
|
160
|
+
assert.ok(g.bottom <= g.footTop, `${viewport.width}px: the window ends above the foot row (${g.bottom} > ${g.footTop})`);
|
|
161
|
+
assert.equal(g.top, parseFloat(g.place), `${viewport.width}px: the window starts under the top arc`);
|
|
162
|
+
assert.ok(g.visorOver, 'the glass is drawn over the window\'s scrim');
|
|
163
|
+
assert.ok(!g.buttonUnder, 'the window covers none of the foot row');
|
|
164
|
+
assert.equal(g.mainPointer, 'none', 'the glass is a picture while the window is up');
|
|
165
|
+
assert.equal(g.sight, 'hidden', 'the sight leaves the window\'s middle');
|
|
166
|
+
await page.evaluate(() => window.OTBOptionsOverlay.close());
|
|
167
|
+
await page.waitForFunction(() => !window.OTBOptionsOverlay.isOpen());
|
|
168
|
+
assert.equal(await page.evaluate(() => getComputedStyle(document.querySelector('#visor')).zIndex), '4', 'shut, the glass goes back under the pop-ups');
|
|
169
|
+
assert.equal(await page.evaluate(() => getComputedStyle(document.querySelector('.visor__main')).pointerEvents), 'auto');
|
|
170
|
+
assert.deepEqual(errors, []);
|
|
171
|
+
await ctx.close();
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
136
175
|
test('with no window to draw, you are still a link to your profile', { skip }, async () => {
|
|
137
176
|
const { ctx, page, errors } = await open({ withWindow: false });
|
|
138
177
|
const r = await page.evaluate(() => {
|