@bongos/core 1.19.412 → 1.19.414
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 +57 -42
- package/clients/bongos-client/index.d.ts +4 -4
- package/docs/adr/0204-the-apex-is-dark-only.md +36 -0
- package/docs/adr/README.md +1 -0
- package/docs/api/openapi.json +25 -10
- package/docs/api-reference.md +2 -2
- package/docs/copy-inventory.md +405 -403
- package/docs/copy-registry.json +538 -520
- package/docs/design/landing-page-direction-v2.md +2 -0
- package/docs/design/projects-hub-direction-v2.md +4 -0
- package/docs/module-api-changelog.md +4 -0
- package/docs/recipes/ui-look-before-you-ship.md +4 -1
- package/modules/hall-ui/public/settings.html +18 -0
- package/modules/hall-ui/public/settings.js +93 -10
- package/modules/platform-identity/migrations/platform_identity_012_account_privacy.sql +59 -0
- package/modules/platform-identity/platform-identity.js +91 -1
- package/modules/platform-identity/routes/profile.js +68 -17
- package/modules/ui-design/kit/lib.js +3 -1
- package/modules/ui-design/kit/render.js +5 -4
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/public-landing/assets/cosmos.css +3 -17
- package/public-landing/contact.html +2 -6
- package/public-landing/index.html +5 -44
- package/public-landing/index.states.json +3 -2
- package/public-landing/privacy.html +2 -6
- package/public-landing/projects.html +4 -41
- package/public-landing/projects.probes.json +0 -3
- package/public-landing/projects.states.json +3 -2
- package/public-landing/terms.html +2 -6
- package/scripts/gds/worktree.js +11 -0
- package/src/module-api.js +1 -1
- package/tests/account_privacy_flags.mjs +299 -0
- package/tests/landing_legal_pages.mjs +10 -0
- package/tests/landing_page.mjs +16 -19
- package/tests/projects_hub.mjs +1 -1
- package/tests/projects_hub_pre_uat.mjs +4 -3
- package/tests/ui_design_kit.mjs +10 -0
|
@@ -160,3 +160,13 @@ for (const p of PAGES) {
|
|
|
160
160
|
}
|
|
161
161
|
});
|
|
162
162
|
}
|
|
163
|
+
|
|
164
|
+
// ── dark only (task 1003336) ──────────────────────────────────────────────
|
|
165
|
+
|
|
166
|
+
test('the legal pages are dark only — data-mode="dark" fixed on <html>, no mode script (task 1003336)', () => {
|
|
167
|
+
for (const p of PAGES) {
|
|
168
|
+
const html = read(p.file);
|
|
169
|
+
assert.match(html, /^<html lang="en" data-mode="dark">/m, `${p.file}: dark is fixed on <html>`);
|
|
170
|
+
assert.doesNotMatch(html, /cb-color-mode|setAttribute\('data-mode'/, `${p.file}: nothing reads or writes a mode`);
|
|
171
|
+
}
|
|
172
|
+
});
|
package/tests/landing_page.mjs
CHANGED
|
@@ -55,8 +55,6 @@ const PAGE_CSS = PAGE_STYLES.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
|
55
55
|
// The page script minus its comments — these assertions are about what the code
|
|
56
56
|
// DOES, and the comments quote the very shapes being ruled out.
|
|
57
57
|
const CODE = HTML.split('<script>').pop().replace(/\/\*[\s\S]*?\*\//g, '');
|
|
58
|
-
// The pre-paint mode script, which is the FIRST <script> in <head>.
|
|
59
|
-
const PREPAINT = HTML.split('<script>')[1].split('</script>')[0];
|
|
60
58
|
|
|
61
59
|
// ── (1) the apex conditional ───────────────────────────────────────────────
|
|
62
60
|
|
|
@@ -255,11 +253,11 @@ test('every dark-mode rule is written twice — the block and its media twin (C2
|
|
|
255
253
|
const explicit = (PAGE_CSS.match(/:root\[data-mode="dark"\]/g) || []).length;
|
|
256
254
|
const media = (PAGE_CSS.match(/:root:not\(\[data-mode="light"\]\)/g) || []).length;
|
|
257
255
|
assert.equal(explicit, media, 'a dark rule with no prefers-color-scheme twin only half-works');
|
|
258
|
-
// the shipped page writes
|
|
259
|
-
// one
|
|
260
|
-
//
|
|
261
|
-
//
|
|
262
|
-
assert.ok(explicit >=
|
|
256
|
+
// the shipped page writes two: the wide plate/geometry token block and the
|
|
257
|
+
// narrow one (the mode-toggle icon swap left with the toggle, task 1003336).
|
|
258
|
+
// The floor is the count observed at the build, so deleting a twin fails even
|
|
259
|
+
// when the pair stays balanced.
|
|
260
|
+
assert.ok(explicit >= 2, `expected at least 2 dark rules, found ${explicit}`);
|
|
263
261
|
});
|
|
264
262
|
|
|
265
263
|
test('the page links world.css root-absolute, and does not fork the hub sheet', () => {
|
|
@@ -504,16 +502,15 @@ test('the tagline is one server-stamped string, split for the composition only',
|
|
|
504
502
|
assert.match(PAGE_CSS, /h1 \.whole\{[^}]*white-space:normal/, 'the whole-tagline fallback must wrap');
|
|
505
503
|
});
|
|
506
504
|
|
|
507
|
-
test('the mode is
|
|
508
|
-
//
|
|
509
|
-
//
|
|
510
|
-
//
|
|
511
|
-
assert.match(
|
|
512
|
-
assert.
|
|
513
|
-
assert.
|
|
514
|
-
|
|
515
|
-
assert.
|
|
516
|
-
assert.match(CODE, /localStorage\.setItem\('cb-color-mode', next\)/, 'the toggle persists the choice');
|
|
505
|
+
test('the apex is dark only: data-mode="dark" is fixed on <html>, nothing reads or writes a mode (task 1003336)', () => {
|
|
506
|
+
// The owner's call on the planets review: light stays the builders' hall's.
|
|
507
|
+
// A fixed attribute beats a script — nothing to flash, nothing to persist,
|
|
508
|
+
// and the OS preference never reaches the page.
|
|
509
|
+
assert.match(HTML, /^<html lang="en" data-mode="dark">/m);
|
|
510
|
+
assert.doesNotMatch(HTML, /cb-color-mode/, 'no persisted choice is read or written');
|
|
511
|
+
assert.doesNotMatch(HTML, /URLSearchParams\(location\.search\)\.get\('mode'\)/, '?mode= no longer walks a second mode');
|
|
512
|
+
assert.doesNotMatch(HTML, /matchMedia\('\(prefers-color-scheme: dark\)'\)/, 'no OS-preference read in script');
|
|
513
|
+
assert.doesNotMatch(CODE, /setAttribute\('data-mode'/, 'nothing flips the mode');
|
|
517
514
|
});
|
|
518
515
|
|
|
519
516
|
// ── the assertions tests/platform_boot.mjs will make once the apex flips ───
|
|
@@ -530,13 +527,13 @@ test('the page satisfies the parked platform_boot assertions', () => {
|
|
|
530
527
|
// the profile band. Everything a visitor can reach is markup; the script only
|
|
531
528
|
// opens and closes. These pin the shape the grader could not see from a diff.
|
|
532
529
|
|
|
533
|
-
test('the bar is markup: the mark, the Projects trigger, the
|
|
530
|
+
test('the bar is markup: the mark, the Projects trigger, the sign-in door — and no mode glyph (tasks 1003300, 1003336)', () => {
|
|
534
531
|
const body = HTML.split('<body>')[1].split('<script>')[0];
|
|
535
532
|
assert.match(body, /<header class="topbar bar">/, 'one bar, the hub\'s class beside the page\'s');
|
|
536
533
|
assert.match(body, /<a class="barMark" href="\/" aria-label="\{\{productName\}\}">\s*<svg viewBox="0 0 26 20"/, 'the static mark is the way home, labelled from the stamped name');
|
|
537
534
|
assert.match(body, /<span class="mark-word">\{\{productName\}\}<\/span>/, 'the product name as plain type, folded away under 900');
|
|
538
535
|
assert.match(body, /<button class="trig" type="button" id="projTrig" data-menu="projects" aria-expanded="false" aria-controls="menuProjects">Projects<svg class="cv"/);
|
|
539
|
-
assert.
|
|
536
|
+
assert.doesNotMatch(body, /modeBtn|id="mode"|class="moon"|class="sun"/, 'the mode glyph left the bar — the apex is dark only (task 1003336)');
|
|
540
537
|
assert.match(body, /<span class="whoSlot" id="who">\s*<a class="pill signin" href="\/api\/bongos\/auth\/web\/start\?return=\/">Sign in<\/a>\s*<\/span>/, 'the door stands in the identity slot until the session resolves');
|
|
541
538
|
// what left with the pill bar
|
|
542
539
|
assert.doesNotMatch(body, /class="pill nav-pill"|class="right-pills"|class="pill mark-pill"|data-nav="home"/, 'no nav pill, no right pills, no Home');
|
package/tests/projects_hub.mjs
CHANGED
|
@@ -297,7 +297,7 @@ test('no id is declared twice — the wizard merge had four collisions to clear'
|
|
|
297
297
|
// id makes the second node unreachable by getElementById and the first
|
|
298
298
|
// silently wins. Scan the real markup only (JS builds ids like `dom-<iid>`
|
|
299
299
|
// from fragments that would false-positive here).
|
|
300
|
-
const afterHead = HUB.slice(HUB.indexOf('
|
|
300
|
+
const afterHead = HUB.slice(HUB.indexOf('<body'));
|
|
301
301
|
const markup = afterHead.slice(0, afterHead.indexOf('<script>'));
|
|
302
302
|
assert.ok(markup.includes('id="view-new"'), 'the markup slice must span the views');
|
|
303
303
|
const ids = [...markup.matchAll(/\sid="([^"]+)"/g)].map((m) => m[1]);
|
|
@@ -581,13 +581,14 @@ test('completed rail steps are a way back, the repo picker is honest ARIA, the c
|
|
|
581
581
|
assert.equal((HUB.match(/aria-controls="projectsList"/g) || []).length, 5, 'the five state filters name the list they filter');
|
|
582
582
|
});
|
|
583
583
|
|
|
584
|
-
test('control nits: orb cursor, caret under reduced motion, mode
|
|
584
|
+
test('control nits: orb cursor, caret under reduced motion, no mode switch, home label, held reduce-motion query, target sizes', () => {
|
|
585
585
|
assert.doesNotMatch(COSMOS, /\.orb\{flex:0 0 54px;[^}]*cursor:pointer/, 'the base orb is not a pointer');
|
|
586
586
|
assert.match(COSMOS, /\na\.orb\{cursor:pointer;\}/, 'only the linked orb is');
|
|
587
587
|
assert.doesNotMatch(COSMOS, /\.orb\.ghost\{[^}]*cursor:default/);
|
|
588
588
|
assert.doesNotMatch(HUB, /\.shell \.caret/, 'no caret to hide — the hub mark is static (task 1003300)');
|
|
589
|
-
assert.
|
|
590
|
-
assert.doesNotMatch(
|
|
589
|
+
assert.doesNotMatch(SCRIPT, /modeToggle|paintModeToggle|resolvedMode|cb-color-mode/, 'the mode switch left the hub — the apex is dark only (task 1003336)');
|
|
590
|
+
assert.doesNotMatch(HUB, /id="modeToggle"|class="modeBtn"/);
|
|
591
|
+
assert.match(HUB, /^<html lang="en" data-mode="dark">/m, 'dark is fixed on <html>');
|
|
591
592
|
assert.match(SCRIPT, /\$\('barMark'\)\.setAttribute\('aria-label', productName \+ ' — home'\);/, 'the mark — the only way home — is labelled from the product name');
|
|
592
593
|
assert.match(SCRIPT, /var REDUCED_MQ = window\.matchMedia \? window\.matchMedia\('\(prefers-reduced-motion: reduce\)'\) : null;/);
|
|
593
594
|
assert.match(SCRIPT, /if \(REDUCED\) stopSky\(\); else startSky\(\);/, 'a mid-session flip stops or restarts the sky');
|
package/tests/ui_design_kit.mjs
CHANGED
|
@@ -39,6 +39,12 @@ test('the shipped states files validate and sit beside the page they name', () =
|
|
|
39
39
|
assert.deepEqual(v.errors, [], `${rel}: ${v.errors.join('; ')}`);
|
|
40
40
|
assert.equal(path.basename(rel), `${lib.pageName(json.page)}.states.json`, `${rel} is named for its page`);
|
|
41
41
|
}
|
|
42
|
+
// the apex is dark only (task 1003336): its states files name the one mode, and
|
|
43
|
+
// render.js reads it as the default so a plain `--page /` never renders light
|
|
44
|
+
for (const rel of ['public-landing/projects.states.json', 'public-landing/index.states.json']) {
|
|
45
|
+
assert.deepEqual(readJson(rel).modes, ['dark'], `${rel}: the apex renders dark only`);
|
|
46
|
+
assert.equal(readJson(rel).modeQuery, false, `${rel}: no query walks a second mode`);
|
|
47
|
+
}
|
|
42
48
|
});
|
|
43
49
|
|
|
44
50
|
test('the shipped probes files validate', () => {
|
|
@@ -60,6 +66,10 @@ test('a states file that breaks the contract is refused with the reason named',
|
|
|
60
66
|
assert.ok(bad.errors.some((e) => /states\.ok\.auth/.test(e)));
|
|
61
67
|
const stub = lib.validateStatesFile({ page: '/x', stub: { prefix: 'builders' }, states: { a: {} } });
|
|
62
68
|
assert.ok(stub.errors.some((e) => /stub\.prefix/.test(e)));
|
|
69
|
+
const modes = lib.validateStatesFile({ page: '/x', modes: ['sepia'], states: { a: {} } });
|
|
70
|
+
assert.ok(modes.errors.some((e) => e.startsWith('modes:')), 'an unknown mode is refused');
|
|
71
|
+
assert.ok(lib.validateStatesFile({ page: '/x', modes: [], states: { a: {} } }).errors.some((e) => e.startsWith('modes:')), 'an empty modes list is refused');
|
|
72
|
+
assert.deepEqual(lib.validateStatesFile({ page: '/x', modes: ['dark'], states: { a: {} } }).errors, [], 'one declared mode is the dark-only shape');
|
|
63
73
|
});
|
|
64
74
|
|
|
65
75
|
test('a probes file needs a name and an expectation per probe, and cannot continue from nothing', () => {
|