@bongos/core 1.21.42 → 1.21.44
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 +72 -72
- package/docs/copy-inventory.md +21 -22
- package/docs/copy-registry.json +24 -33
- package/docs/design/craft-mode-direction.md +1 -1
- package/docs/module-api-changelog.md +4 -0
- package/docs/page-inventory.json +5 -2
- package/docs/page-readings.json +3459 -3536
- package/modules/hall-ui/public/atlas.html +3 -3
- package/modules/hall-ui/public/blockers.html +3 -3
- package/modules/hall-ui/public/board-room.html +3 -3
- package/modules/hall-ui/public/city-draw.js +51 -13
- package/modules/hall-ui/public/city.css +9 -2
- package/modules/hall-ui/public/city.html +6 -6
- package/modules/hall-ui/public/city.js +23 -12
- package/modules/hall-ui/public/city.states.json +146 -12
- package/modules/hall-ui/public/collab.html +3 -3
- package/modules/hall-ui/public/commands.html +3 -3
- package/modules/hall-ui/public/copy-desk.html +3 -3
- package/modules/hall-ui/public/craft-mode.js +10 -15
- package/modules/hall-ui/public/deploy.html +3 -3
- package/modules/hall-ui/public/diagrams.html +3 -3
- package/modules/hall-ui/public/drachmae.html +3 -3
- package/modules/hall-ui/public/fleet.html +3 -3
- package/modules/hall-ui/public/gate.html +3 -3
- package/modules/hall-ui/public/goal-map.html +3 -3
- package/modules/hall-ui/public/goals.html +3 -3
- package/modules/hall-ui/public/government.html +3 -3
- package/modules/hall-ui/public/idea.html +3 -3
- package/modules/hall-ui/public/ideas.html +3 -3
- package/modules/hall-ui/public/index.html +3 -3
- package/modules/hall-ui/public/modules.html +3 -3
- package/modules/hall-ui/public/primer.html +3 -3
- package/modules/hall-ui/public/profile.html +3 -3
- package/modules/hall-ui/public/project-settings.html +3 -3
- package/modules/hall-ui/public/ranks.html +3 -3
- package/modules/hall-ui/public/roadmap.html +3 -3
- package/modules/hall-ui/public/roster.html +3 -3
- package/modules/hall-ui/public/sessions.html +3 -3
- package/modules/hall-ui/public/settings.html +3 -3
- package/modules/hall-ui/public/street-card.css +6 -0
- package/modules/hall-ui/public/street-card.js +31 -3
- package/modules/hall-ui/public/street-draw.js +96 -19
- package/modules/hall-ui/public/street.css +23 -7
- package/modules/hall-ui/public/street.html +11 -10
- package/modules/hall-ui/public/street.js +45 -13
- package/modules/hall-ui/public/street.states.json +68 -0
- package/modules/hall-ui/public/studio.html +3 -3
- package/modules/hall-ui/public/style.css +4 -22
- package/modules/hall-ui/public/task.html +3 -3
- package/modules/hall-ui/public/thinking.html +3 -3
- package/modules/hall-ui/public/tweak-editor.html +3 -3
- package/modules/hall-ui/public/watch.html +3 -3
- package/modules/hall-ui/public/work.html +3 -3
- package/modules/hall-ui/records/craft-mode.md +5 -5
- package/modules/hall-ui/records/governor-street.md +1 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +12 -0
- package/scripts/hall-preview/server.js +5 -2
- package/src/module-api.js +1 -1
- package/tests/craft_mode.mjs +27 -10
- package/tests/craft_mode_looks.mjs +5 -5
- package/tests/craft_mode_nav.mjs +7 -7
- package/tests/hall_city.mjs +42 -11
- package/tests/hall_matter_card.mjs +17 -0
- package/tests/hall_street.mjs +185 -12
- package/tests/hall_tweak_editor.mjs +1 -1
- package/tests/page_notes_panel.mjs +1 -1
|
@@ -91,9 +91,9 @@
|
|
|
91
91
|
|
|
92
92
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
93
93
|
|
|
94
|
-
<script src="/builders/shell-trail.js?v=2026-10-04-
|
|
95
|
-
<script src="/builders/craft-mode.js?v=2026-10-04-
|
|
96
|
-
<script src="/builders/shell.js?v=2026-10-04-
|
|
94
|
+
<script src="/builders/shell-trail.js?v=2026-10-04-nolegacy"></script>
|
|
95
|
+
<script src="/builders/craft-mode.js?v=2026-10-04-nolegacy"></script>
|
|
96
|
+
<script src="/builders/shell.js?v=2026-10-04-nolegacy"></script>
|
|
97
97
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
98
98
|
<script src="/builders/palette.js" defer></script>
|
|
99
99
|
<script src="/builders/atlas.js?v=2026-09-02-index" defer></script>
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
|
|
51
51
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
52
52
|
chrome exists before the page script runs. -->
|
|
53
|
-
<script src="/builders/shell-trail.js?v=2026-10-04-
|
|
54
|
-
<script src="/builders/craft-mode.js?v=2026-10-04-
|
|
55
|
-
<script src="/builders/shell.js?v=2026-10-04-
|
|
53
|
+
<script src="/builders/shell-trail.js?v=2026-10-04-nolegacy"></script>
|
|
54
|
+
<script src="/builders/craft-mode.js?v=2026-10-04-nolegacy"></script>
|
|
55
|
+
<script src="/builders/shell.js?v=2026-10-04-nolegacy"></script>
|
|
56
56
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
57
57
|
<script src="/builders/palette.js" defer></script>
|
|
58
58
|
<!-- shared frontend toolkit (window.OTB — rank labels, number formats) + the
|
|
@@ -60,9 +60,9 @@
|
|
|
60
60
|
|
|
61
61
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
62
62
|
|
|
63
|
-
<script src="/builders/shell-trail.js?v=2026-10-04-
|
|
64
|
-
<script src="/builders/craft-mode.js?v=2026-10-04-
|
|
65
|
-
<script src="/builders/shell.js?v=2026-10-04-
|
|
63
|
+
<script src="/builders/shell-trail.js?v=2026-10-04-nolegacy"></script>
|
|
64
|
+
<script src="/builders/craft-mode.js?v=2026-10-04-nolegacy"></script>
|
|
65
|
+
<script src="/builders/shell.js?v=2026-10-04-nolegacy"></script>
|
|
66
66
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
67
67
|
<script src="/builders/palette.js" defer></script>
|
|
68
68
|
<script src="/builders/dom-utils.js?v=2026-06-16-board"></script>
|
|
@@ -40,9 +40,11 @@
|
|
|
40
40
|
// * Review. The prototype's story opens with Review a vacant lot; in this
|
|
41
41
|
// project Review is held (the grader and the testers sign work off), so the
|
|
42
42
|
// held recipe is drawn and the parcels leave through Release.
|
|
43
|
-
// * Pins. A building can hold more matters than the prototype's
|
|
44
|
-
// three pins
|
|
45
|
-
//
|
|
43
|
+
// * Pins (task 1004569). A building can hold more matters than the prototype's
|
|
44
|
+
// one, and three pins abreast crowded each other; now ONE pin stands over a
|
|
45
|
+
// building, where the prototype stands its pin, in the importance tier of
|
|
46
|
+
// its most important matter (buildingPin below, shared with the street so
|
|
47
|
+
// both views agree), with a count when more than one matter is open there.
|
|
46
48
|
|
|
47
49
|
(function (root) {
|
|
48
50
|
'use strict';
|
|
@@ -244,7 +246,6 @@
|
|
|
244
246
|
Object.freeze({ x0: 12, x1: 15, y0: 12, y1: 15, tall: 60, route: null }),
|
|
245
247
|
]);
|
|
246
248
|
const MAX_DISTRICTS = BASE_LOTS.length * 2;
|
|
247
|
-
const MAX_PINS_PER_BUILDING = 3;
|
|
248
249
|
|
|
249
250
|
function halve(L) {
|
|
250
251
|
const w = L.x1 - L.x0 + 1, h = L.y1 - L.y0 + 1;
|
|
@@ -327,6 +328,39 @@
|
|
|
327
328
|
return state === 'needs' || state === 'moving' || state === 'settled' ? state : 'moving';
|
|
328
329
|
}
|
|
329
330
|
|
|
331
|
+
// ---------- importance tiers (task 1004569) ----------
|
|
332
|
+
// One pin per building, in the tier of its most important matter, so the city
|
|
333
|
+
// and the street read the same at a glance. Colour AND size carry the tier
|
|
334
|
+
// (city.css, street.css), so it also reads without colour:
|
|
335
|
+
// urgent needs you and due within 24 hours (or overdue): largest, orange, pulsing
|
|
336
|
+
// needs needs you: orange, medium (the prototype's pin)
|
|
337
|
+
// moving others are deciding: ink, small
|
|
338
|
+
// settled settled recently: a small grey dot, no label, no count
|
|
339
|
+
const TIERS = Object.freeze(['urgent', 'needs', 'moving', 'settled']);
|
|
340
|
+
const URGENT_MS = 24 * 3600 * 1000;
|
|
341
|
+
function matterTier(m, now) {
|
|
342
|
+
const st = pinState(m && m.state);
|
|
343
|
+
if (st !== 'needs') return st;
|
|
344
|
+
const t = m.deadline ? Date.parse(m.deadline) : NaN;
|
|
345
|
+
return Number(now) > 0 && isFinite(t) && t - Number(now) <= URGENT_MS ? 'urgent' : 'needs';
|
|
346
|
+
}
|
|
347
|
+
// A building's matters → its one pin: the tier of the most important, the
|
|
348
|
+
// count of the open ones (settled is not open), and every matter, most
|
|
349
|
+
// important first (the docket's own order inside a tier), for the card pager.
|
|
350
|
+
function buildingPin(matters, now) {
|
|
351
|
+
const ranked = (Array.isArray(matters) ? matters : []).filter(Boolean)
|
|
352
|
+
.map((m, i) => ({ m: m, t: matterTier(m, now), i: i }))
|
|
353
|
+
.sort((a, b) => TIERS.indexOf(a.t) - TIERS.indexOf(b.t) || a.i - b.i);
|
|
354
|
+
if (!ranked.length) return null;
|
|
355
|
+
return { tier: ranked[0].t, top: ranked[0].m, count: ranked.filter((r) => r.t !== 'settled').length, matters: ranked.map((r) => r.m) };
|
|
356
|
+
}
|
|
357
|
+
// What a pin says to a screen reader: '3 open at charter, the first needs you within a day'.
|
|
358
|
+
const TIER_WORDS = Object.freeze({ urgent: 'needs you within a day', needs: 'needs you', moving: 'is moving without you', settled: 'is settled' });
|
|
359
|
+
function pinAria(building, bp) {
|
|
360
|
+
const lead = bp.count > 1 ? bp.count + ' open at ' + building + ', the first ' : bp.count === 1 ? 'One open at ' + building + ': it ' : 'At ' + building + ': ';
|
|
361
|
+
return lead + TIER_WORDS[bp.tier] + '. ' + String(bp.top.title || bp.top.short || '');
|
|
362
|
+
}
|
|
363
|
+
|
|
330
364
|
// The home line, when the docket could not be read.
|
|
331
365
|
const FALLBACK_LINE = 'the docket could not be read just now';
|
|
332
366
|
|
|
@@ -335,6 +369,7 @@
|
|
|
335
369
|
// goals GET /goals goals[] (any status; only 'open' ones are drawn)
|
|
336
370
|
// rollups GET /goals/rollups rollups[] (goal_id → task counts)
|
|
337
371
|
// mode 'dark' | 'light'
|
|
372
|
+
// now ms since the epoch (a deadline inside a day is urgent)
|
|
338
373
|
function cityModel(input) {
|
|
339
374
|
const opts = input || {};
|
|
340
375
|
const docket = opts.docket && typeof opts.docket === 'object' ? opts.docket : null;
|
|
@@ -385,7 +420,7 @@
|
|
|
385
420
|
});
|
|
386
421
|
blds.sort((a, b) => a.depth - b.depth);
|
|
387
422
|
|
|
388
|
-
//
|
|
423
|
+
// one pin over each building with a matter, in its most important matter's tier
|
|
389
424
|
const slotOf = {};
|
|
390
425
|
CIVIC_SLOTS.forEach((s) => { slotOf[s[0]] = s; });
|
|
391
426
|
const matters = docket && Array.isArray(docket.matters) ? docket.matters : [];
|
|
@@ -397,14 +432,16 @@
|
|
|
397
432
|
const pins = [];
|
|
398
433
|
let n = 0;
|
|
399
434
|
CIVIC_SLOTS.forEach((s) => {
|
|
400
|
-
const
|
|
435
|
+
const bp = buildingPin(atBuilding[s[0]], opts.now);
|
|
436
|
+
if (!bp) return;
|
|
401
437
|
const top = P(s[1] + 1, s[2] + 1, ROOF[s[0]] + 8);
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
n
|
|
438
|
+
const m = bp.top;
|
|
439
|
+
const g = glyph(m.rule, 7, 7, 13);
|
|
440
|
+
pins.push({
|
|
441
|
+
key: String(m.id), building: s[0], state: bp.tier, count: bp.tier === 'settled' ? 0 : bp.count, matters: bp.matters.map((x) => String(x.id)),
|
|
442
|
+
title: String(m.short || m.title || ''), aria: pinAria(s[0], bp), x: r1(top[0] - 15), y: r1(top[1] - 52), h: 52, gf: g.fill, gl: g.line, delay: -(n * 0.9),
|
|
407
443
|
});
|
|
444
|
+
n += 1;
|
|
408
445
|
});
|
|
409
446
|
|
|
410
447
|
// work on the move: parcels ride the ring road to Review, and leave through Release
|
|
@@ -423,7 +460,7 @@
|
|
|
423
460
|
|
|
424
461
|
const line = docket && docket.line ? String(docket.line) : FALLBACK_LINE;
|
|
425
462
|
const pinCount = { needs: 0, moving: 0, settled: 0 };
|
|
426
|
-
pins.forEach((p) => { pinCount[p.state] += 1; });
|
|
463
|
+
pins.forEach((p) => { pinCount[p.state === 'urgent' ? 'needs' : p.state] += 1; });
|
|
427
464
|
const label = 'The governor city: the nine civic buildings round the plaza and '
|
|
428
465
|
+ (districts.length === 1 ? 'one district' : districts.length + ' districts') + ', one for each open goal'
|
|
429
466
|
+ (pins.length ? '. Pins: ' + pinCount.needs + ' need you, ' + pinCount.moving + ' moving, ' + pinCount.settled + ' settled.' : '.');
|
|
@@ -439,7 +476,8 @@
|
|
|
439
476
|
isoTheme: isoTheme, isoKit: isoKit, isoBox: isoBox, isoGable: isoGable, isoHip: isoHip, isoSaw: isoSaw,
|
|
440
477
|
isoTree: isoTree, isoLight: isoLight, isoInstitution: isoInstitution, isoWork: isoWork, glyph: glyph, rnd: rnd,
|
|
441
478
|
lotsFor: lotsFor, districtWork: districtWork, cityModel: cityModel, rulesAtWork: rulesAtWork,
|
|
442
|
-
|
|
479
|
+
matterTier: matterTier, buildingPin: buildingPin, pinAria: pinAria, TIERS: TIERS, URGENT_MS: URGENT_MS,
|
|
480
|
+
CIVIC_SLOTS: CIVIC_SLOTS, ROOF: ROOF, BASE_LOTS: BASE_LOTS, MAX_DISTRICTS: MAX_DISTRICTS,
|
|
443
481
|
FALLBACK_LINE: FALLBACK_LINE, STREET_HREF: STREET_HREF,
|
|
444
482
|
};
|
|
445
483
|
root.GovCity = api;
|
|
@@ -84,8 +84,15 @@ html[data-fullscreen="on"] .city-top { right: 184px; }
|
|
|
84
84
|
.city-pin__head path + path { fill: none; stroke: currentColor; stroke-width: 1.2; }
|
|
85
85
|
.city-pin__stem { width: 0; flex-grow: 1; border-left: 1px solid transparent; }
|
|
86
86
|
.city-pin__ring { position: absolute; inset: -1px; border-radius: 999px; border: 1px solid var(--accent); }
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
/* importance tiers (task 1004569): colour AND size, so a tier reads without colour.
|
|
88
|
+
urgent 26 > needs 22 (the prototype's) > moving 16 > settled 8, a plain dot */
|
|
89
|
+
.city-pin--urgent .city-pin__head, .city-pin--needs .city-pin__head { background: var(--accent); color: var(--accent-on); box-shadow: var(--city-glow); }
|
|
90
|
+
.city-pin--urgent .city-pin__head { width: 26px; height: 26px; }
|
|
91
|
+
.city-pin--urgent .city-pin__stem, .city-pin--needs .city-pin__stem { border-left-color: color-mix(in srgb, var(--accent) 60%, transparent); }
|
|
92
|
+
.city-pin--moving .city-pin__head { width: 16px; height: 16px; }
|
|
93
|
+
.city-pin--moving .city-pin__head svg { width: 10px; height: 10px; }
|
|
94
|
+
.city-pin--settled .city-pin__head { width: 8px; height: 8px; margin-top: 14px; }
|
|
95
|
+
.city-pin__count { position: absolute; top: -6px; right: -9px; min-width: 14px; height: 14px; padding: 0 3px; box-sizing: border-box; border-radius: 999px; background: var(--bg-card); color: var(--ink); border: 1px solid currentColor; font-size: 9.5px; font-weight: 600; line-height: 12px; text-align: center; font-variant-numeric: tabular-nums; }
|
|
89
96
|
.city-pin--moving .city-pin__head { background: var(--ink); color: var(--bg-card); }
|
|
90
97
|
.city-pin--moving .city-pin__stem { border-left-color: color-mix(in srgb, var(--ink) 45%, transparent); }
|
|
91
98
|
.city-pin--settled .city-pin__head { background: color-mix(in srgb, var(--ink) 10%, var(--bg)); border: 1px solid color-mix(in srgb, var(--ink) 22%, transparent); color: var(--ink-faint); }
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
(tests/hall_tokens.mjs: no hall page hardcodes a web-font stylesheet).
|
|
13
13
|
The prototype carried its own Google Fonts link for the same two faces. -->
|
|
14
14
|
<link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
|
|
15
|
-
<link rel="stylesheet" href="/builders/city.css?v=2026-10-
|
|
15
|
+
<link rel="stylesheet" href="/builders/city.css?v=2026-10-04-pins1">
|
|
16
16
|
</head>
|
|
17
17
|
<!-- THE GOVERNOR CITY, HOME (task 1004524, goal 1000125, R02). The home view
|
|
18
18
|
of docs/design/mocks/governor-city/Street.dc.html (homeView and the home
|
|
@@ -83,11 +83,11 @@
|
|
|
83
83
|
</div>
|
|
84
84
|
</div>
|
|
85
85
|
|
|
86
|
-
<script src="/builders/shell-trail.js?v=2026-10-04-
|
|
87
|
-
<script src="/builders/craft-mode.js?v=2026-10-04-
|
|
88
|
-
<script src="/builders/shell.js?v=2026-10-04-
|
|
86
|
+
<script src="/builders/shell-trail.js?v=2026-10-04-nolegacy"></script>
|
|
87
|
+
<script src="/builders/craft-mode.js?v=2026-10-04-nolegacy"></script>
|
|
88
|
+
<script src="/builders/shell.js?v=2026-10-04-nolegacy"></script>
|
|
89
89
|
<script src="/builders/palette.js" defer></script>
|
|
90
|
-
<script src="/builders/city-draw.js?v=2026-10-
|
|
91
|
-
<script src="/builders/city.js?v=2026-10-
|
|
90
|
+
<script src="/builders/city-draw.js?v=2026-10-04-pins1"></script>
|
|
91
|
+
<script src="/builders/city.js?v=2026-10-04-pins1"></script>
|
|
92
92
|
</body>
|
|
93
93
|
</html>
|
|
@@ -132,22 +132,33 @@
|
|
|
132
132
|
var el = span('city-pin city-pin--' + pin.state);
|
|
133
133
|
el.setAttribute('data-matter', pin.key);
|
|
134
134
|
el.setAttribute('data-building', pin.building);
|
|
135
|
+
if (pin.aria) el.setAttribute('title', pin.aria);
|
|
135
136
|
el.style.left = pin.x + 'px';
|
|
136
137
|
el.style.top = pin.y + 'px';
|
|
137
138
|
el.style.height = pin.h + 'px';
|
|
138
139
|
el.style.animationDelay = pin.delay + 's';
|
|
139
140
|
var head = span('city-pin__head');
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
141
|
+
// only the urgent tier pulses; a settled pin is a plain grey dot, no mark (task 1004569)
|
|
142
|
+
if (pin.state === 'urgent') head.appendChild(span('city-pin__ring'));
|
|
143
|
+
if (pin.state !== 'settled') {
|
|
144
|
+
var svg = document.createElementNS(SVG_NS, 'svg');
|
|
145
|
+
svg.setAttribute('width', '14');
|
|
146
|
+
svg.setAttribute('height', '14');
|
|
147
|
+
svg.setAttribute('viewBox', '0 0 14 14');
|
|
148
|
+
var fill = document.createElementNS(SVG_NS, 'path');
|
|
149
|
+
fill.setAttribute('d', pin.gf || '');
|
|
150
|
+
var line = document.createElementNS(SVG_NS, 'path');
|
|
151
|
+
line.setAttribute('d', pin.gl || '');
|
|
152
|
+
svg.appendChild(fill);
|
|
153
|
+
svg.appendChild(line);
|
|
154
|
+
head.appendChild(svg);
|
|
155
|
+
}
|
|
156
|
+
// the count of the building's open matters, when there is more than one
|
|
157
|
+
if (pin.count > 1) {
|
|
158
|
+
var badge = span('city-pin__count');
|
|
159
|
+
badge.textContent = String(pin.count);
|
|
160
|
+
head.appendChild(badge);
|
|
161
|
+
}
|
|
151
162
|
el.appendChild(head);
|
|
152
163
|
el.appendChild(span('city-pin__stem'));
|
|
153
164
|
return el;
|
|
@@ -162,7 +173,7 @@
|
|
|
162
173
|
}
|
|
163
174
|
|
|
164
175
|
function draw(mode) {
|
|
165
|
-
var model = City.cityModel({ docket: data.docket, goals: data.goals, rollups: data.rollups, mode: mode });
|
|
176
|
+
var model = City.cityModel({ docket: data.docket, goals: data.goals, rollups: data.rollups, mode: mode, now: Date.now() });
|
|
166
177
|
var flat = $('cityFlat'), blds = $('cityBlds'), parcels = $('cityParcels'), pins = $('cityPins');
|
|
167
178
|
clear(flat); clear(blds); clear(parcels); clear(pins);
|
|
168
179
|
model.flat.forEach(function (p) { flat.appendChild(pathEl(p)); });
|
|
@@ -2,35 +2,169 @@
|
|
|
2
2
|
"_": "THE GOVERNOR CITY's home (task 1004524, goal 1000125) through modules/ui-design/kit/render.js. The page draws GET /government/docket, GET /goals and GET /goals/rollups; against the kit's own stub none exists, so every state renders the city with no districts and no pins and the line saying the docket could not be read: a real state the floors must hold in. To look at the populated city, run it against the hall-preview harness, whose government__docket.json fixture carries the reference design's seven sample matters (3 need you, 2 moving, 2 settled) and whose goals fixtures carry the open goals:\n\n node scripts/hall-preview/server.js --port 4624 --fixture-me\n node modules/ui-design/kit/render.js --states modules/hall-ui/public/city.states.json --base-in http://localhost:4624 --base-out http://localhost:4624\n\nThe page follows the OS mode until the switch is pressed (then the hall's own 'hall-theme' preference), so the kit's dark/light emulation renders both modes.",
|
|
3
3
|
"page": "/builders/city",
|
|
4
4
|
"surface": "hall-ui",
|
|
5
|
-
"stub": {
|
|
5
|
+
"stub": {
|
|
6
|
+
"prefix": "/builders/"
|
|
7
|
+
},
|
|
6
8
|
"modeQuery": false,
|
|
7
|
-
"ignoreRequests": [
|
|
8
|
-
|
|
9
|
+
"ignoreRequests": [
|
|
10
|
+
"/api/(gds|bongos)/",
|
|
11
|
+
"fonts\\.g(oogleapis|static)\\.com"
|
|
12
|
+
],
|
|
13
|
+
"ignoreConsole": [
|
|
14
|
+
"/api/(gds|bongos)/",
|
|
15
|
+
"\\b401\\b",
|
|
16
|
+
"\\b403\\b",
|
|
17
|
+
"\\b404\\b",
|
|
18
|
+
"Unauthorized",
|
|
19
|
+
"Forbidden",
|
|
20
|
+
"Not Found",
|
|
21
|
+
"load failed",
|
|
22
|
+
"fonts\\.g(oogleapis|static)\\.com"
|
|
23
|
+
],
|
|
9
24
|
"states": {
|
|
10
25
|
"city": {
|
|
11
26
|
"auth": true,
|
|
12
27
|
"_": "The home: the wordmark, the switch, the city, start governing and the one line.",
|
|
13
|
-
"actions": [
|
|
14
|
-
|
|
28
|
+
"actions": [
|
|
29
|
+
[
|
|
30
|
+
"wait",
|
|
31
|
+
900
|
|
32
|
+
]
|
|
33
|
+
],
|
|
34
|
+
"expect": {
|
|
35
|
+
"visible": [
|
|
36
|
+
"#cityStage",
|
|
37
|
+
"#cityStart",
|
|
38
|
+
"#cityLine",
|
|
39
|
+
"#cityMode",
|
|
40
|
+
"#app-topbar",
|
|
41
|
+
"#fullscreen-toggle"
|
|
42
|
+
],
|
|
43
|
+
"href": [
|
|
44
|
+
[
|
|
45
|
+
"#cityStart",
|
|
46
|
+
"/builders/street"
|
|
47
|
+
]
|
|
48
|
+
]
|
|
49
|
+
}
|
|
15
50
|
},
|
|
16
51
|
"fullscreen": {
|
|
17
52
|
"auth": true,
|
|
18
53
|
"_": "In the hall since task 1004544: the shell's full-screen switch pressed, the sidebar and the top bar gone, the city filling the window and the one exit in the corner (the sky's mechanism, task 1004327).",
|
|
19
|
-
"actions": [
|
|
20
|
-
|
|
54
|
+
"actions": [
|
|
55
|
+
[
|
|
56
|
+
"wait",
|
|
57
|
+
900
|
|
58
|
+
],
|
|
59
|
+
[
|
|
60
|
+
"click",
|
|
61
|
+
"#fullscreen-toggle"
|
|
62
|
+
],
|
|
63
|
+
[
|
|
64
|
+
"wait",
|
|
65
|
+
500
|
|
66
|
+
]
|
|
67
|
+
],
|
|
68
|
+
"expect": {
|
|
69
|
+
"visible": [
|
|
70
|
+
"#cityStage",
|
|
71
|
+
"#cityStart",
|
|
72
|
+
"#cityMode",
|
|
73
|
+
"#fullscreen-toggle"
|
|
74
|
+
],
|
|
75
|
+
"hidden": [
|
|
76
|
+
"#app-sidebar",
|
|
77
|
+
"#topbar-title"
|
|
78
|
+
],
|
|
79
|
+
"attr": [
|
|
80
|
+
[
|
|
81
|
+
"#fullscreen-toggle",
|
|
82
|
+
"aria-pressed",
|
|
83
|
+
"true"
|
|
84
|
+
]
|
|
85
|
+
]
|
|
86
|
+
}
|
|
21
87
|
},
|
|
22
88
|
"switched": {
|
|
23
89
|
"auth": true,
|
|
24
90
|
"_": "The sun/moon switch pressed once: the other mode, the city redrawn in it.",
|
|
25
|
-
"actions": [
|
|
26
|
-
|
|
91
|
+
"actions": [
|
|
92
|
+
[
|
|
93
|
+
"wait",
|
|
94
|
+
600
|
|
95
|
+
],
|
|
96
|
+
[
|
|
97
|
+
"click",
|
|
98
|
+
"#cityMode"
|
|
99
|
+
],
|
|
100
|
+
[
|
|
101
|
+
"wait",
|
|
102
|
+
400
|
|
103
|
+
]
|
|
104
|
+
],
|
|
105
|
+
"expect": {
|
|
106
|
+
"visible": [
|
|
107
|
+
"#cityStage",
|
|
108
|
+
"#cityStart"
|
|
109
|
+
]
|
|
110
|
+
}
|
|
27
111
|
},
|
|
28
112
|
"focus": {
|
|
29
113
|
"auth": true,
|
|
30
114
|
"_": "Keyboard: the start button focused, its ring drawn.",
|
|
31
|
-
"actions": [
|
|
32
|
-
|
|
115
|
+
"actions": [
|
|
116
|
+
[
|
|
117
|
+
"wait",
|
|
118
|
+
600
|
|
119
|
+
],
|
|
120
|
+
[
|
|
121
|
+
"focus",
|
|
122
|
+
"#cityStart"
|
|
123
|
+
],
|
|
124
|
+
[
|
|
125
|
+
"wait",
|
|
126
|
+
100
|
|
127
|
+
]
|
|
128
|
+
],
|
|
129
|
+
"expect": {
|
|
130
|
+
"activeId": "cityStart"
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
"pins": {
|
|
134
|
+
"auth": true,
|
|
135
|
+
"_": "The home city over the dense docket with the same pin tiers as the street (task 1004569): one pin per building, urgent largest and pulsing, needs you orange, moving small and ink, a count where a building holds more than one open matter.",
|
|
136
|
+
"actions": [
|
|
137
|
+
[
|
|
138
|
+
"wait",
|
|
139
|
+
900
|
|
140
|
+
],
|
|
141
|
+
[
|
|
142
|
+
"clickIfVisible",
|
|
143
|
+
"[data-craft-close]"
|
|
144
|
+
],
|
|
145
|
+
[
|
|
146
|
+
"wait",
|
|
147
|
+
300
|
|
148
|
+
]
|
|
149
|
+
],
|
|
150
|
+
"expect": {
|
|
151
|
+
"visible": [
|
|
152
|
+
"#cityPins",
|
|
153
|
+
".city-pin--urgent",
|
|
154
|
+
".city-pin--needs",
|
|
155
|
+
".city-pin--moving",
|
|
156
|
+
".city-pin__count"
|
|
157
|
+
]
|
|
158
|
+
}
|
|
33
159
|
}
|
|
34
160
|
},
|
|
35
|
-
"reducedMotion": {
|
|
161
|
+
"reducedMotion": {
|
|
162
|
+
"auth": true,
|
|
163
|
+
"actions": [
|
|
164
|
+
[
|
|
165
|
+
"wait",
|
|
166
|
+
600
|
|
167
|
+
]
|
|
168
|
+
]
|
|
169
|
+
}
|
|
36
170
|
}
|
|
@@ -148,9 +148,9 @@
|
|
|
148
148
|
|
|
149
149
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
150
150
|
|
|
151
|
-
<script src="/builders/shell-trail.js?v=2026-10-04-
|
|
152
|
-
<script src="/builders/craft-mode.js?v=2026-10-04-
|
|
153
|
-
<script src="/builders/shell.js?v=2026-10-04-
|
|
151
|
+
<script src="/builders/shell-trail.js?v=2026-10-04-nolegacy"></script>
|
|
152
|
+
<script src="/builders/craft-mode.js?v=2026-10-04-nolegacy"></script>
|
|
153
|
+
<script src="/builders/shell.js?v=2026-10-04-nolegacy"></script>
|
|
154
154
|
<script src="/builders/palette.js" defer></script>
|
|
155
155
|
<script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
|
|
156
156
|
<script src="/builders/collab-lib.js?v=2026-09-24-archive"></script>
|
|
@@ -54,9 +54,9 @@
|
|
|
54
54
|
|
|
55
55
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
56
56
|
|
|
57
|
-
<script src="/builders/shell-trail.js?v=2026-10-04-
|
|
58
|
-
<script src="/builders/craft-mode.js?v=2026-10-04-
|
|
59
|
-
<script src="/builders/shell.js?v=2026-10-04-
|
|
57
|
+
<script src="/builders/shell-trail.js?v=2026-10-04-nolegacy"></script>
|
|
58
|
+
<script src="/builders/craft-mode.js?v=2026-10-04-nolegacy"></script>
|
|
59
|
+
<script src="/builders/shell.js?v=2026-10-04-nolegacy"></script>
|
|
60
60
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
61
61
|
<script src="/builders/palette.js" defer></script>
|
|
62
62
|
<script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>
|
|
@@ -177,9 +177,9 @@
|
|
|
177
177
|
|
|
178
178
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
179
179
|
|
|
180
|
-
<script src="/builders/shell-trail.js?v=2026-10-04-
|
|
181
|
-
<script src="/builders/craft-mode.js?v=2026-10-04-
|
|
182
|
-
<script src="/builders/shell.js?v=2026-10-04-
|
|
180
|
+
<script src="/builders/shell-trail.js?v=2026-10-04-nolegacy"></script>
|
|
181
|
+
<script src="/builders/craft-mode.js?v=2026-10-04-nolegacy"></script>
|
|
182
|
+
<script src="/builders/shell.js?v=2026-10-04-nolegacy"></script>
|
|
183
183
|
<script src="/builders/palette.js" defer></script>
|
|
184
184
|
<script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
|
|
185
185
|
<script src="/builders/hall-kit.js"></script>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// craft-mode.js — the hall's craft mode (task 1004492, goal 1000095 WA6).
|
|
2
2
|
//
|
|
3
3
|
// On entering the hall (once per browser session) a picker asks "What are you
|
|
4
|
-
// doing now?": Building, Artistry, Ideating
|
|
4
|
+
// doing now?": Building, Artistry, Ideating or Governing. The
|
|
5
5
|
// answer is ONE attribute, html[data-craft="<mode>"], that every hall page can
|
|
6
6
|
// read, and a switch in the top bar changes it at any time without a reload.
|
|
7
7
|
// Each change also fires `otb:craft` on document ({ detail: { mode } }).
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
// It is a MODE the existing hall wears, never a second hall (the founding-mode
|
|
10
10
|
// precedent, docs/design/project-startup-direction.md). The nav follows the mode
|
|
11
11
|
// (task 1004493, MODE_TABS below), and so does the look (task 1004495, LOOKS
|
|
12
|
-
// below); the mode tools are their own tasks (1004496 onward). Legacy mode
|
|
13
|
-
//
|
|
12
|
+
// below); the mode tools are their own tasks (1004496 onward). Legacy mode, a
|
|
13
|
+
// fifth choice, was removed (task 1004567): Building already shows every tab,
|
|
14
|
+
// and a stored 'legacy' now reads as no mode.
|
|
14
15
|
//
|
|
15
16
|
// NO MODE is the default and the fallback: a reader who closes the picker, a
|
|
16
17
|
// browser whose storage throws, a page that opts out — none of them get the
|
|
@@ -29,25 +30,23 @@
|
|
|
29
30
|
artistry: '<path d="M8 2a6 6 0 1 0 0 12c.9 0 1.4-.6 1.4-1.3 0-.8-.6-1-.6-1.7 0-.6.5-1 1.2-1h1.6A2.4 2.4 0 0 0 14 7.6C14 4.5 11.3 2 8 2Z"/><path d="M5 6.2h.01M7.6 4.6h.01M10.4 5.2h.01M4.6 9h.01" stroke-width="2.2"/>',
|
|
30
31
|
ideating: '<path d="M6 12.5h4M6.6 14.5h2.8M8 1.8a4.2 4.2 0 0 0-2.6 7.5c.6.5 1 1.2 1 2h3.2c0-.8.4-1.5 1-2A4.2 4.2 0 0 0 8 1.8Z"/>',
|
|
31
32
|
governing: '<path d="M2 6 8 2.5 14 6M3.5 6.5v6M6.5 6.5v6M9.5 6.5v6M12.5 6.5v6M2 13.5h12"/>',
|
|
32
|
-
legacy: '<path d="M3 3.5h10v9H3z"/><path d="M3 6.5h10M6 6.5v6"/>',
|
|
33
33
|
modes: '<rect x="2.5" y="2.5" width="4.5" height="4.5" rx="1"/><rect x="9" y="2.5" width="4.5" height="4.5" rx="1"/><rect x="2.5" y="9" width="4.5" height="4.5" rx="1"/><rect x="9" y="9" width="4.5" height="4.5" rx="1"/>',
|
|
34
34
|
};
|
|
35
|
-
// The four crafts
|
|
35
|
+
// The four crafts. `short` is the switch's label; `line` is the
|
|
36
36
|
// picker's one sentence — what you do in the mode, never a feature not built yet.
|
|
37
37
|
var MODES = [
|
|
38
38
|
{ id: 'building', label: 'Building', short: 'Building', line: 'Claim tasks and ship code.' },
|
|
39
39
|
{ id: 'artistry', label: 'Artistry', short: 'Artistry', line: 'Review how pages look and read.' },
|
|
40
40
|
{ id: 'ideating', label: 'Ideating', short: 'Ideating', line: 'Turn thoughts into ideas.' },
|
|
41
41
|
{ id: 'governing', label: 'Governing', short: 'Governing', line: 'Decide, approve and keep it healthy.' },
|
|
42
|
-
{ id: 'legacy', label: 'Legacy mode', short: 'Legacy', line: 'The hall as it was: every tab, no mode tools or colour.' },
|
|
43
42
|
];
|
|
44
43
|
var IDS = MODES.map(function (m) { return m.id; });
|
|
45
44
|
|
|
46
45
|
// ---------- each mode's tabs (task 1004493) ----------
|
|
47
46
|
// A mode shows only the nav items its craft needs, by NAV id (shell.js). ALWAYS
|
|
48
47
|
// is the owner's list of tabs no mode may hide (2026-10-01: Builders first;
|
|
49
|
-
// 2026-10-03: Collab and Profile too), and every mode's list is ALWAYS plus its own.
|
|
50
|
-
//
|
|
48
|
+
// 2026-10-03: Collab and Profile too), and every mode's list is ALWAYS plus its own. With no mode at all, every tab
|
|
49
|
+
// shows, exactly as the hall did before.
|
|
51
50
|
// Government lives in Governing alone, and Governing is the shortest list.
|
|
52
51
|
// Hiding is cosmetic: a hidden tab's page still opens by its URL (ADR 0016).
|
|
53
52
|
var ALWAYS_TABS = ['roster', 'collab', 'profile'];
|
|
@@ -97,7 +96,7 @@
|
|
|
97
96
|
// style.css (keyed on html[data-craft]), plus two things only this script can
|
|
98
97
|
// draw — the mode's words beside the page title, and its door's scene framed
|
|
99
98
|
// under the brand (artHtml, the picker's own art, so the two never drift).
|
|
100
|
-
// Building
|
|
99
|
+
// Building and no mode have no entry here and wear nothing.
|
|
101
100
|
var LOOKS = { artistry: 'the studio · night', ideating: 'the sky', governing: 'the city' };
|
|
102
101
|
function remove(el) { if (el && el.parentNode) el.parentNode.removeChild(el); }
|
|
103
102
|
function applyLook(mode) {
|
|
@@ -328,13 +327,12 @@
|
|
|
328
327
|
return '<span class="craft-art craft-art--' + id + '" aria-hidden="true">' + html + '</span>';
|
|
329
328
|
}
|
|
330
329
|
function pickerHtml(preselect) {
|
|
331
|
-
var doors = MODES.
|
|
330
|
+
var doors = MODES.map(function (m) {
|
|
332
331
|
return '<button class="craft-door craft-door--' + m.id + (m.id === preselect ? ' craft-door--pre' : '') + '" type="button" data-craft-pick="' + m.id + '">' +
|
|
333
332
|
artHtml(m.id) +
|
|
334
333
|
'<span class="craft-door__head">' + icon(m.id, 'craft-door__icon') + '<span class="craft-door__name">' + esc(m.label) + '</span></span>' +
|
|
335
334
|
'<span class="craft-door__line">' + esc(m.line) + '</span></button>';
|
|
336
335
|
}).join('');
|
|
337
|
-
var legacy = MODES[MODES.length - 1];
|
|
338
336
|
return '<div class="craft-picker__panel" role="dialog" aria-modal="true" aria-labelledby="craft-picker-title" aria-describedby="craft-picker-lede">' +
|
|
339
337
|
'<button class="craft-picker__close" type="button" data-craft-close aria-label="Close without choosing">' +
|
|
340
338
|
'<svg viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" aria-hidden="true"><path d="M5 5l8 8M13 5l-8 8"/></svg></button>' +
|
|
@@ -344,10 +342,7 @@
|
|
|
344
342
|
'<div class="craft-picker__doors">' + doors + '</div>' +
|
|
345
343
|
'<div class="craft-picker__foot">' +
|
|
346
344
|
'<label class="craft-picker__again"><input type="checkbox" data-craft-again checked> Ask me again next session</label>' +
|
|
347
|
-
'<span class="craft-
|
|
348
|
-
(preselect === 'artistry' ? '<span class="craft-picker__hint">Artists start on Artistry.</span>' : '') +
|
|
349
|
-
'<button class="craft-picker__legacy" type="button" data-craft-pick="legacy" title="' + esc(legacy.line) + '">Legacy mode · the hall as it was</button>' +
|
|
350
|
-
'</span>' +
|
|
345
|
+
(preselect === 'artistry' ? '<span class="craft-picker__hint">Artists start on Artistry.</span>' : '') +
|
|
351
346
|
'</div>' +
|
|
352
347
|
'</div>';
|
|
353
348
|
}
|
|
@@ -74,9 +74,9 @@
|
|
|
74
74
|
|
|
75
75
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
76
76
|
|
|
77
|
-
<script src="/builders/shell-trail.js?v=2026-10-04-
|
|
78
|
-
<script src="/builders/craft-mode.js?v=2026-10-04-
|
|
79
|
-
<script src="/builders/shell.js?v=2026-10-04-
|
|
77
|
+
<script src="/builders/shell-trail.js?v=2026-10-04-nolegacy"></script>
|
|
78
|
+
<script src="/builders/craft-mode.js?v=2026-10-04-nolegacy"></script>
|
|
79
|
+
<script src="/builders/shell.js?v=2026-10-04-nolegacy"></script>
|
|
80
80
|
<script src="/builders/palette.js" defer></script>
|
|
81
81
|
<script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
|
|
82
82
|
<script src="/builders/hall-kit.js"></script>
|
|
@@ -97,9 +97,9 @@
|
|
|
97
97
|
|
|
98
98
|
<!-- The app shell (sidebar + top bar + footer). Dependency-free; runs at parse
|
|
99
99
|
time so the chrome exists before the deferred page scripts execute. -->
|
|
100
|
-
<script src="/builders/shell-trail.js?v=2026-10-04-
|
|
101
|
-
<script src="/builders/craft-mode.js?v=2026-10-04-
|
|
102
|
-
<script src="/builders/shell.js?v=2026-10-04-
|
|
100
|
+
<script src="/builders/shell-trail.js?v=2026-10-04-nolegacy"></script>
|
|
101
|
+
<script src="/builders/craft-mode.js?v=2026-10-04-nolegacy"></script>
|
|
102
|
+
<script src="/builders/shell.js?v=2026-10-04-nolegacy"></script>
|
|
103
103
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
104
104
|
<script src="/builders/palette.js" defer></script>
|
|
105
105
|
<script src="/builders/diagram-viewer.js?v=2026-06-14-diagviewer-1" defer></script>
|
|
@@ -98,9 +98,9 @@
|
|
|
98
98
|
|
|
99
99
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
100
100
|
|
|
101
|
-
<script src="/builders/shell-trail.js?v=2026-10-04-
|
|
102
|
-
<script src="/builders/craft-mode.js?v=2026-10-04-
|
|
103
|
-
<script src="/builders/shell.js?v=2026-10-04-
|
|
101
|
+
<script src="/builders/shell-trail.js?v=2026-10-04-nolegacy"></script>
|
|
102
|
+
<script src="/builders/craft-mode.js?v=2026-10-04-nolegacy"></script>
|
|
103
|
+
<script src="/builders/shell.js?v=2026-10-04-nolegacy"></script>
|
|
104
104
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
105
105
|
<script src="/builders/palette.js" defer></script>
|
|
106
106
|
<script src="/builders/md-reader.js?v=2026-09-02-mdreader-2"></script>
|