@bongos/core 1.24.80 → 1.24.82
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 +154 -124
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +4 -0
- package/clients/bongos-client/index.cjs +4 -0
- package/clients/bongos-client/index.d.ts +5 -0
- package/clients/bongos-client/index.mjs +4 -0
- package/docs/adr/0402-helm-is-the-halls-look-and-the-hall-is-dark-only.md +142 -0
- package/docs/adr/README.md +1 -0
- package/docs/api/openapi.json +86 -2
- package/docs/api-reference.md +4 -2
- package/docs/copy-inventory.md +51 -50
- package/docs/copy-registry.json +121 -123
- package/docs/module-api-changelog.md +4 -0
- package/docs/page-inventory.json +2 -3
- package/docs/page-readings.json +226 -220
- package/modules/builder-settings/hall-view-prefs.js +50 -0
- package/modules/builder-settings/routes/settings.js +32 -0
- package/modules/hall-ui/public/ai-studio.html +5 -3
- package/modules/hall-ui/public/ai-studio.states.json +1 -0
- package/modules/hall-ui/public/atlas.html +3 -3
- package/modules/hall-ui/public/atlas.states.json +1 -0
- package/modules/hall-ui/public/blockers.html +3 -3
- package/modules/hall-ui/public/board-room.html +3 -3
- package/modules/hall-ui/public/board-room.states.json +1 -0
- package/modules/hall-ui/public/city.css +1 -3
- package/modules/hall-ui/public/city.html +6 -9
- package/modules/hall-ui/public/city.js +10 -55
- package/modules/hall-ui/public/city.states.json +7 -32
- package/modules/hall-ui/public/collab.html +3 -3
- package/modules/hall-ui/public/collab.states.json +1 -0
- package/modules/hall-ui/public/commands.html +3 -3
- package/modules/hall-ui/public/commands.states.json +1 -0
- package/modules/hall-ui/public/controls.css +63 -11
- package/modules/hall-ui/public/copy-desk.html +3 -3
- package/modules/hall-ui/public/copy-desk.states.json +1 -0
- package/modules/hall-ui/public/deploy.html +3 -3
- package/modules/hall-ui/public/deploy.states.json +1 -0
- package/modules/hall-ui/public/goal-map.html +4 -4
- package/modules/hall-ui/public/goals.html +3 -3
- package/modules/hall-ui/public/goals.states.json +1 -0
- package/modules/hall-ui/public/government.html +3 -3
- package/modules/hall-ui/public/government.states.json +1 -0
- package/modules/hall-ui/public/idea.html +3 -3
- package/modules/hall-ui/public/idea.states.json +1 -0
- package/modules/hall-ui/public/ideas.html +3 -3
- package/modules/hall-ui/public/ideas.states.json +1 -0
- package/modules/hall-ui/public/index-founding.states.json +1 -0
- package/modules/hall-ui/public/index-genesis-decide.states.json +1 -0
- package/modules/hall-ui/public/index-genesis-demo.states.json +1 -0
- package/modules/hall-ui/public/index-genesis.states.json +1 -0
- package/modules/hall-ui/public/index.html +5 -5
- package/modules/hall-ui/public/index.states.json +1 -0
- package/modules/hall-ui/public/market-watch-item.html +3 -3
- package/modules/hall-ui/public/market-watch-item.states.json +1 -0
- package/modules/hall-ui/public/market-watch-rules.html +3 -3
- package/modules/hall-ui/public/market-watch-rules.states.json +1 -0
- package/modules/hall-ui/public/market-watch.html +3 -3
- package/modules/hall-ui/public/market-watch.states.json +1 -0
- package/modules/hall-ui/public/modules.html +3 -3
- package/modules/hall-ui/public/modules.states.json +1 -0
- package/modules/hall-ui/public/money.html +3 -3
- package/modules/hall-ui/public/money.states.json +1 -0
- package/modules/hall-ui/public/my-agents.html +3 -3
- package/modules/hall-ui/public/my-agents.states.json +1 -0
- package/modules/hall-ui/public/options-menu.js +2 -1
- package/modules/hall-ui/public/primer.html +3 -3
- package/modules/hall-ui/public/primer.states.json +1 -0
- package/modules/hall-ui/public/profile.html +3 -3
- package/modules/hall-ui/public/profile.states.json +1 -0
- package/modules/hall-ui/public/project-settings.html +3 -3
- package/modules/hall-ui/public/roster.html +3 -3
- package/modules/hall-ui/public/roster.states.json +1 -0
- package/modules/hall-ui/public/settings-view.js +75 -0
- package/modules/hall-ui/public/settings.html +17 -4
- package/modules/hall-ui/public/settings.states.json +1 -0
- package/modules/hall-ui/public/shell-game.css +97 -42
- package/modules/hall-ui/public/shell-game.js +138 -40
- package/modules/hall-ui/public/shell.js +12 -43
- package/modules/hall-ui/public/street-card.states.json +1 -0
- package/modules/hall-ui/public/street.css +1 -5
- package/modules/hall-ui/public/street.html +5 -9
- package/modules/hall-ui/public/street.js +8 -59
- package/modules/hall-ui/public/street.states.json +7 -32
- package/modules/hall-ui/public/studio.html +3 -3
- package/modules/hall-ui/public/studio.states.json +1 -0
- package/modules/hall-ui/public/style.css +126 -65
- package/modules/hall-ui/public/task.html +3 -3
- package/modules/hall-ui/public/task.states.json +1 -0
- package/modules/hall-ui/public/thinking.html +4 -4
- package/modules/hall-ui/public/thinking.states.json +1 -0
- package/modules/hall-ui/public/tweak-editor.html +3 -3
- package/modules/hall-ui/public/tweak-editor.states.json +1 -0
- package/modules/hall-ui/public/visor.js +7 -1
- package/modules/hall-ui/public/watch.html +3 -3
- package/modules/hall-ui/public/watch.states.json +1 -0
- package/modules/hall-ui/public/work-founding.states.json +1 -0
- package/modules/hall-ui/public/work.html +3 -3
- package/modules/hall-ui/public/work.states.json +1 -0
- package/modules/hall-ui/records/game-mode.md +5 -4
- package/modules/hall-ui/records/start-screen.md +10 -2
- package/modules/hall-ui/specimens/components.states.json +2 -1
- package/modules/ui-design/public/brand.html +2 -2
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +12 -0
- package/scripts/hall-preview/README.md +2 -3
- package/scripts/hall-preview/pref-writes.js +8 -1
- package/src/bongos/serve-internal.js +7 -2
- package/src/hall-helm.js +79 -0
- package/src/module-api.js +1 -1
- package/tests/design_reference.mjs +1 -1
- package/tests/hall_builders_page_pass.mjs +2 -1
- package/tests/hall_city.mjs +15 -29
- package/tests/hall_controls.mjs +52 -4
- package/tests/hall_fullscreen.mjs +42 -21
- package/tests/hall_helm.mjs +187 -0
- package/tests/hall_record_world.mjs +4 -2
- package/tests/hall_start_screen.mjs +103 -5
- package/tests/hall_street.mjs +13 -26
- package/tests/hall_topbar_320.mjs +4 -2
- package/tests/hall_view_prefs.mjs +42 -0
- package/tests/hall_visor.mjs +3 -2
- package/tests/nav_permission_atoms.mjs +1 -1
|
@@ -7,18 +7,25 @@
|
|
|
7
7
|
// the same html[data-fullscreen="on"] state, the same corner button and the same
|
|
8
8
|
// Escape hand-off (a page listener that calls preventDefault keeps the press).
|
|
9
9
|
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
10
|
+
// GAME OR CLASSIC, never both (task 1005200; owner, 2026-11-11). Classic is the hall
|
|
11
|
+
// as it always was; game is full screen with NO way back to the bars inside it (no
|
|
12
|
+
// corner button, no Escape-to-leave: shell.js) and only the game PLACES below, so any
|
|
13
|
+
// other hall page sends you to the city. The view is chosen at every sign-in (the
|
|
14
|
+
// chooser in front of the start screen) and switched only in Options → Preferences →
|
|
15
|
+
// View. It is kept on the ACCOUNT (GET/PATCH /api/bongos/me/hall-view, builder-settings
|
|
16
|
+
// hall-view-prefs.js) so it follows the builder to any browser; one localStorage key
|
|
17
|
+
// (`hall-game`) is only the copy a page paints from before that read answers, and one
|
|
18
|
+
// attribute, html[data-game="on"], is what a sheet or script reads.
|
|
16
19
|
// Loaded BEFORE shell.js on every hall page; a page without this file is simply
|
|
17
20
|
// never in game mode.
|
|
18
21
|
(function () {
|
|
19
22
|
'use strict';
|
|
20
23
|
var KEY = 'hall-game';
|
|
21
|
-
var
|
|
24
|
+
var VIEW_API = '/api/bongos/me/hall-view';
|
|
25
|
+
// The game's places, by page id (body data-page). Every other page is classic and is
|
|
26
|
+
// not reachable in game mode; a page joins this list when it has a game version.
|
|
27
|
+
var PLACES = ['home', 'city', 'goal-map', 'thinking', 'atlas', 'settings', 'profile'];
|
|
28
|
+
var embedded = false; // set below, once: inside the options menu's frame
|
|
22
29
|
function read(store, key) { try { return window[store].getItem(key); } catch (_) { return null; } }
|
|
23
30
|
function write(store, key, value) { try { window[store].setItem(key, value); } catch (_) { /* private mode */ } }
|
|
24
31
|
function on() { return read('localStorage', KEY) === 'on'; }
|
|
@@ -26,21 +33,57 @@
|
|
|
26
33
|
var root = document.documentElement;
|
|
27
34
|
if (on()) root.dataset.game = 'on'; else delete root.dataset.game;
|
|
28
35
|
}
|
|
29
|
-
//
|
|
30
|
-
function
|
|
36
|
+
// '/builders' on the apex, '' on the builders host: the hall's own base.
|
|
37
|
+
function base() {
|
|
38
|
+
var p = String((window.location && window.location.pathname) || '');
|
|
39
|
+
return p.indexOf('/builders/') === 0 || p === '/builders' ? '/builders' : '';
|
|
40
|
+
}
|
|
41
|
+
// The page id an in-hall path names ('/city' → 'city', '/' → 'home'), or null.
|
|
42
|
+
function pageOf(path) {
|
|
43
|
+
var p = String(path || '').split(/[?#]/)[0].replace(/^\/builders(?=\/|$)/, '').replace(/\.html$/, '');
|
|
44
|
+
p = p.replace(/^\/+|\/+$/g, '');
|
|
45
|
+
if (p === '' || p === 'index') return 'home';
|
|
46
|
+
return p.indexOf('/') >= 0 ? null : p;
|
|
47
|
+
}
|
|
48
|
+
function isPlace(path) { return PLACES.indexOf(pageOf(path)) >= 0; }
|
|
49
|
+
function herePage() {
|
|
50
|
+
var b = document.body;
|
|
51
|
+
return (b && b.getAttribute && b.getAttribute('data-page')) || pageOf(window.location.pathname);
|
|
52
|
+
}
|
|
53
|
+
// In game mode a classic page is not there: go to the city. True when leaving.
|
|
54
|
+
function keepToPlaces() {
|
|
55
|
+
if (!on() || embedded) return false;
|
|
56
|
+
var page = herePage();
|
|
57
|
+
if (!page || PLACES.indexOf(page) >= 0) return false;
|
|
58
|
+
window.location.replace(base() + '/');
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
function save(view) {
|
|
62
|
+
if (typeof fetch !== 'function') return;
|
|
63
|
+
fetch(VIEW_API, { method: 'PATCH', credentials: 'same-origin', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ view: view }) })
|
|
64
|
+
.catch(function () { /* the browser's copy stands; the next choice saves again */ });
|
|
65
|
+
}
|
|
66
|
+
// Switch views: the browser's copy, the account (unless o.local: the account said so),
|
|
67
|
+
// then what this page shows. A classic page switched to game goes to the city.
|
|
68
|
+
function set(value, o) {
|
|
31
69
|
write('localStorage', KEY, value ? 'on' : 'off');
|
|
70
|
+
if (!(o && o.local)) save(value ? 'game' : 'classic');
|
|
32
71
|
stamp();
|
|
72
|
+
if (keepToPlaces()) return;
|
|
33
73
|
if (window.OTBShell && window.OTBShell.setFullscreen) window.OTBShell.setFullscreen(null);
|
|
34
74
|
}
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
75
|
+
// The account's view wins over the browser's copy (another browser may have switched).
|
|
76
|
+
// Never chosen (null), signed out, or no answer: the copy stands.
|
|
77
|
+
function sync() {
|
|
78
|
+
if (embedded || typeof fetch !== 'function') return;
|
|
79
|
+
fetch(VIEW_API, { credentials: 'same-origin' }).then(function (r) { return r.ok ? r.json() : null; }).then(function (d) {
|
|
80
|
+
var view = d && d.view;
|
|
81
|
+
if (view !== 'game' && view !== 'classic') return;
|
|
82
|
+
if ((view === 'game') !== on()) set(view === 'game', { local: true });
|
|
83
|
+
}, function () { /* offline: the copy stands */ });
|
|
43
84
|
}
|
|
85
|
+
// The shell's "how to leave full screen" line. Game mode has no way to leave it.
|
|
86
|
+
function hint() { return !on(); }
|
|
44
87
|
|
|
45
88
|
// ---------- the start screen and the load screen (task 1005143, BONGOS-V3 R03) ----------
|
|
46
89
|
// A fresh sign-in opens on the start screen: Start, Options, Achievements, Extras, Quit over a
|
|
@@ -58,7 +101,6 @@
|
|
|
58
101
|
var EXTRAS = [
|
|
59
102
|
{ label: 'The thinking sky', href: '/thinking' },
|
|
60
103
|
{ label: 'The atlas', href: '/atlas' },
|
|
61
|
-
{ label: 'The docs', href: '/docs' },
|
|
62
104
|
];
|
|
63
105
|
var TIPS = [
|
|
64
106
|
'Escape opens the options menu, where every setting lives.',
|
|
@@ -91,22 +133,69 @@
|
|
|
91
133
|
if (m.href) return '<li><a' + inner + ' href="' + esc(m.href) + '">' + esc(m.label) + '</a></li>';
|
|
92
134
|
return '<li><button type="button"' + inner + (m.id === 'extras' ? ' aria-expanded="false" aria-controls="gs-extras"' : '') + '>' + esc(m.label) + '</button></li>';
|
|
93
135
|
}
|
|
136
|
+
// The chooser in front of the start screen (task 1005200): game or classic, the view
|
|
137
|
+
// chosen last time marked and focused, so Enter keeps it.
|
|
138
|
+
var VIEWS = [
|
|
139
|
+
{ id: 'game', label: 'Game', sub: 'The city, full screen' },
|
|
140
|
+
{ id: 'classic', label: 'Classic', sub: 'The hall with its sidebar' },
|
|
141
|
+
];
|
|
142
|
+
function lastView() { var v = read('localStorage', KEY); return v === 'on' ? 'game' : v === 'off' ? 'classic' : null; }
|
|
143
|
+
function viewHtml(v) {
|
|
144
|
+
var last = lastView() === v.id;
|
|
145
|
+
return '<li><button type="button" class="gs__item gs__item--view' + (last ? ' gs__item--last' : '') + '" data-gs="view-' + v.id + '">' +
|
|
146
|
+
'<span class="gs__view">' + esc(v.label) + (last ? '<span class="gs__last">Last time</span>' : '') + '</span>' +
|
|
147
|
+
'<span class="gs__sub">' + esc(v.sub) + '</span></button></li>';
|
|
148
|
+
}
|
|
149
|
+
// The project's own logo where it has one (ADR 0358), else the shared mark, as the sidebar draws it.
|
|
150
|
+
function markHtml() {
|
|
151
|
+
var theme = (window.__BRANDING__ && window.__BRANDING__.theme) || {};
|
|
152
|
+
if (theme.logo) return '<img class="gs__mark" src="' + esc(theme.logo) + '" alt="" decoding="async">';
|
|
153
|
+
return '<svg class="gs__mark" viewBox="0 0 200 200" aria-hidden="true"><use href="/modules/ui-design/public/brand/mark.svg#mark"/></svg>';
|
|
154
|
+
}
|
|
155
|
+
// The Helm panel (task 1005192, ADR 0402): the mark and the name, the choices, one line at the foot.
|
|
94
156
|
function screenHtml(o) {
|
|
95
157
|
return '<div class="gs__art" aria-hidden="true">' + (o.art ? '<img class="gs__img" alt="" src="' + esc(o.art) + '" decoding="async">' : '') + '</div>' +
|
|
96
158
|
'<div class="gs__menu">' +
|
|
97
|
-
'<
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
159
|
+
'<div class="gs__top">' +
|
|
160
|
+
'<div class="gs__head">' + markHtml() +
|
|
161
|
+
'<h2 class="gs__title" id="gs-title">' + esc(o.name || 'This project') + '</h2>' +
|
|
162
|
+
'</div>' +
|
|
163
|
+
'<div class="gs__list">' +
|
|
164
|
+
'<p class="gs__ask" id="gs-ask">How do you want to see it?</p>' +
|
|
165
|
+
'<ul class="gs__items" id="gs-views">' + VIEWS.map(viewHtml).join('') + '</ul>' +
|
|
166
|
+
'<ul class="gs__items" id="gs-items" hidden>' + MENU.map(itemHtml).join('') + '</ul>' +
|
|
167
|
+
'<ul class="gs__items gs__items--extras" id="gs-extras" hidden>' + EXTRAS.map(function (x) {
|
|
168
|
+
return '<li><a class="gs__item gs__item--extra" href="' + esc(x.href) + '">' + esc(x.label) + '</a></li>';
|
|
169
|
+
}).join('') + '</ul>' +
|
|
170
|
+
'</div>' +
|
|
171
|
+
'</div>' +
|
|
172
|
+
'<div class="gs__foot">' +
|
|
173
|
+
'<p class="gs__line" id="gs-line">' + esc(tipAt(read('localStorage', TIP_KEY))) + '</p>' +
|
|
174
|
+
'<p class="gs__note" id="gs-note" role="status" hidden></p>' +
|
|
175
|
+
'</div>' +
|
|
103
176
|
'</div>' +
|
|
104
177
|
'<div class="gs__load" id="gs-load" role="status" hidden>' +
|
|
105
|
-
'<svg class="gs__city" id="gs-city" role="img" aria-label="The project city building up, week by week" hidden></svg>' +
|
|
106
178
|
'<p class="gs__when" id="gs-when" hidden></p>' +
|
|
179
|
+
'<ol class="gs__segs segs" id="gs-segs" aria-hidden="true" hidden></ol>' +
|
|
180
|
+
'<svg class="gs__city" id="gs-city" role="img" aria-label="The project city building up, week by week" hidden></svg>' +
|
|
107
181
|
'<p class="gs__tip"><b>Tip</b><span id="gs-tip"></span></p>' +
|
|
108
182
|
'</div>';
|
|
109
183
|
}
|
|
184
|
+
// One segment per week of the history: filled up to the week being shown. The words beside
|
|
185
|
+
// them (#gs-when) say the same thing, so the row is hidden from a screen reader.
|
|
186
|
+
// Counted the way whenLabel words it, so the row and the sentence never disagree.
|
|
187
|
+
function segsDone(weeks, t) {
|
|
188
|
+
var n = Math.max(0, Math.round(Number(weeks) || 0));
|
|
189
|
+
return Math.max(0, n - Math.round(Math.max(0, n - 1 - (Number(t) || 0))));
|
|
190
|
+
}
|
|
191
|
+
function drawSegs(weeks, t) {
|
|
192
|
+
var box = root && root.querySelector('#gs-segs'), n = Math.max(0, Math.round(Number(weeks) || 0));
|
|
193
|
+
if (!box || n < 2) return;
|
|
194
|
+
while (box.children.length < n) box.appendChild(document.createElement('li'));
|
|
195
|
+
var done = segsDone(n, t);
|
|
196
|
+
for (var i = 0; i < box.children.length; i++) box.children[i].className = i < done ? 'seg seg--done' : 'seg';
|
|
197
|
+
box.hidden = false;
|
|
198
|
+
}
|
|
110
199
|
|
|
111
200
|
var root = null, opts = null, timers = [], phase = null;
|
|
112
201
|
function later(ms, fn) { timers.push(setTimeout(fn, ms)); }
|
|
@@ -159,6 +248,7 @@
|
|
|
159
248
|
svg.removeAttribute('hidden');
|
|
160
249
|
when.textContent = whenLabel(model.W, t);
|
|
161
250
|
when.hidden = false;
|
|
251
|
+
drawSegs(model.W, t);
|
|
162
252
|
}
|
|
163
253
|
// One week after another, as state: each stop is a whole drawing, so nothing here animates.
|
|
164
254
|
function runHistory(model) {
|
|
@@ -211,10 +301,24 @@
|
|
|
211
301
|
btn.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
212
302
|
if (open) box.querySelector('a').focus();
|
|
213
303
|
}
|
|
304
|
+
// Game: on to the start screen. Classic: the screen goes and the hall is as it always was.
|
|
305
|
+
function choose(view) {
|
|
306
|
+
if (phase !== 'choose') return;
|
|
307
|
+
if (view === 'classic') { set(false); close(); return; }
|
|
308
|
+
set(true);
|
|
309
|
+
phase = 'menu';
|
|
310
|
+
root.querySelector('#gs-ask').hidden = true;
|
|
311
|
+
root.querySelector('#gs-views').hidden = true;
|
|
312
|
+
root.querySelector('#gs-items').hidden = false;
|
|
313
|
+
var first = root.querySelector('[data-gs="start"]');
|
|
314
|
+
if (first && first.focus) first.focus();
|
|
315
|
+
}
|
|
214
316
|
function onClick(e) {
|
|
215
317
|
var el = e.target.closest && e.target.closest('.gs__item');
|
|
216
|
-
if (!el
|
|
318
|
+
if (!el) return;
|
|
217
319
|
var id = el.getAttribute('data-gs');
|
|
320
|
+
if (id === 'view-game' || id === 'view-classic') { choose(id.slice(5)); return; }
|
|
321
|
+
if (phase !== 'menu') return;
|
|
218
322
|
if (id === 'start') load();
|
|
219
323
|
else if (id === 'extras') toggleExtras(el);
|
|
220
324
|
else if (id === 'quit') quit();
|
|
@@ -229,7 +333,7 @@
|
|
|
229
333
|
if (phase === 'menu' && !box.hidden) { var b = root.querySelector('[data-gs="extras"]'); toggleExtras(b); b.focus(); }
|
|
230
334
|
return;
|
|
231
335
|
}
|
|
232
|
-
if (phase !== 'menu') return;
|
|
336
|
+
if (phase !== 'menu' && phase !== 'choose') return;
|
|
233
337
|
var f = items(), at = f.indexOf(document.activeElement), step = 0;
|
|
234
338
|
if (e.key === 'ArrowDown') step = 1;
|
|
235
339
|
else if (e.key === 'ArrowUp') step = -1;
|
|
@@ -244,7 +348,7 @@
|
|
|
244
348
|
function start(o) {
|
|
245
349
|
if (root || !document.body) return !!root;
|
|
246
350
|
opts = o || {};
|
|
247
|
-
phase = '
|
|
351
|
+
phase = 'choose';
|
|
248
352
|
root = document.createElement('div');
|
|
249
353
|
root.className = 'gs';
|
|
250
354
|
root.id = 'game-start';
|
|
@@ -256,15 +360,11 @@
|
|
|
256
360
|
document.addEventListener('keydown', onKey, true);
|
|
257
361
|
document.body.appendChild(root);
|
|
258
362
|
document.documentElement.classList.add('gs-open');
|
|
259
|
-
var first = root.querySelector('.gs__item');
|
|
363
|
+
var first = root.querySelector('.gs__item--last') || root.querySelector('.gs__item');
|
|
260
364
|
if (first && first.focus) first.focus();
|
|
261
365
|
return true;
|
|
262
366
|
}
|
|
263
367
|
|
|
264
|
-
try {
|
|
265
|
-
var asked = new URLSearchParams(window.location.search || '').get('game');
|
|
266
|
-
if (asked === 'on' || asked === 'off') write('localStorage', KEY, asked);
|
|
267
|
-
} catch (_) { /* old engine: the stored value stands */ }
|
|
268
368
|
stamp();
|
|
269
369
|
|
|
270
370
|
// ---------- the options menu (task 1005144, BONGOS-V3 R04, ADR 0401) ----------
|
|
@@ -276,7 +376,6 @@
|
|
|
276
376
|
// Escape nobody used goes to the menu. Only inside a frame: the same URL opened
|
|
277
377
|
// on its own is the page with its chrome (the server sends a plain visit of the
|
|
278
378
|
// old address to the menu, serve-internal.js).
|
|
279
|
-
var embedded = false;
|
|
280
379
|
try {
|
|
281
380
|
embedded = new URLSearchParams(window.location.search || '').get('embed') === '1'
|
|
282
381
|
&& !!window.parent && window.parent !== window;
|
|
@@ -287,10 +386,9 @@
|
|
|
287
386
|
if (document.body && document.body.setAttribute) document.body.setAttribute('data-fullscreen-switch', 'off');
|
|
288
387
|
}
|
|
289
388
|
// The hall's address for the menu: '/settings' on the builders host, '/builders/settings' on the apex.
|
|
290
|
-
function menuPath() {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
}
|
|
389
|
+
function menuPath() { return base() + '/settings'; }
|
|
390
|
+
keepToPlaces();
|
|
391
|
+
sync();
|
|
294
392
|
function inField(el) {
|
|
295
393
|
var tag = el && el.tagName ? String(el.tagName).toLowerCase() : '';
|
|
296
394
|
return tag === 'input' || tag === 'textarea' || tag === 'select' || !!(el && el.isContentEditable);
|
|
@@ -325,6 +423,6 @@
|
|
|
325
423
|
} catch (_) { /* a href the browser cannot read: leave it alone */ }
|
|
326
424
|
}, true);
|
|
327
425
|
}
|
|
328
|
-
window.OTBShellGame = { on: on, set: set, hint: hint, start: start, tipAt: tipAt, historySteps: historySteps, whenLabel: whenLabel, MENU: MENU, TIPS: TIPS,
|
|
329
|
-
embedded: function () { return embedded; }, menuPath: menuPath };
|
|
426
|
+
window.OTBShellGame = { on: on, set: set, hint: hint, start: start, tipAt: tipAt, historySteps: historySteps, whenLabel: whenLabel, segsDone: segsDone, MENU: MENU, TIPS: TIPS,
|
|
427
|
+
embedded: function () { return embedded; }, menuPath: menuPath, PLACES: PLACES, pageOf: pageOf, isPlace: isPlace };
|
|
330
428
|
})();
|
|
@@ -538,7 +538,6 @@
|
|
|
538
538
|
'</button>' +
|
|
539
539
|
(CRAFT ? CRAFT.switchHtml() : '') +
|
|
540
540
|
'<button class="zoom-toggle" id="zoom-toggle" type="button" aria-label="Text size"></button>' +
|
|
541
|
-
'<button class="theme-toggle" id="theme-toggle" type="button" aria-label="Switch theme"></button>' +
|
|
542
541
|
// task 1004327: the full-screen switch, LAST so it sits in the corner the
|
|
543
542
|
// collapsed bar keeps in full screen — the one control that stays put.
|
|
544
543
|
// task 1004430: on every page now, unless the page opts out.
|
|
@@ -561,7 +560,8 @@
|
|
|
561
560
|
// button and Escape bring them back. Opt out with <body data-fullscreen-switch="off">;
|
|
562
561
|
// the bare attribute means the page lays itself out for it, else it is `plain`.
|
|
563
562
|
// State: html[data-fullscreen="on"], remembered PER PAGE (`hall-fullscreen:<data-page>`).
|
|
564
|
-
// task 1005142: in game mode (shell-game.js) EVERY page opens in it, whatever it remembers
|
|
563
|
+
// task 1005142: in game mode (shell-game.js) EVERY page opens in it, whatever it remembers,
|
|
564
|
+
// and since task 1005200 it STAYS in it: no button (style.css), no Escape-to-leave.
|
|
565
565
|
var GAME = window.OTBShellGame || { on: function () { return false; }, hint: function () { return true; } };
|
|
566
566
|
var FULLSCREEN_KEY = 'hall-fullscreen:';
|
|
567
567
|
function fullscreenAttr() {
|
|
@@ -605,7 +605,7 @@
|
|
|
605
605
|
leave: '<svg viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 3v4H3M15 7h-4V3M11 15v-4h4M3 11h4v4"/></svg>',
|
|
606
606
|
};
|
|
607
607
|
function applyFullscreen(on) {
|
|
608
|
-
if (!fullscreenPage()) on = false;
|
|
608
|
+
if (!fullscreenPage()) on = false; else if (GAME.on()) on = true;
|
|
609
609
|
var root = document.documentElement;
|
|
610
610
|
if (on) root.dataset.fullscreen = 'on'; else delete root.dataset.fullscreen;
|
|
611
611
|
if (on && fullscreenAttr() === null) root.dataset.fullscreenPlain = 'on'; else delete root.dataset.fullscreenPlain;
|
|
@@ -642,48 +642,25 @@
|
|
|
642
642
|
// a text field, where Escape belongs to the field. Page listeners may be on
|
|
643
643
|
// the window AFTER this one, so the verdict waits for the dispatch to finish.
|
|
644
644
|
function onFullscreenKey(e) {
|
|
645
|
-
if (e.key !== 'Escape' || !isFullscreen() || e.defaultPrevented || inTextField(e.target)) return;
|
|
645
|
+
if (e.key !== 'Escape' || !isFullscreen() || GAME.on() || e.defaultPrevented || inTextField(e.target)) return;
|
|
646
646
|
window.setTimeout(function () { if (!e.defaultPrevented && isFullscreen()) setFullscreen(false); }, 0);
|
|
647
647
|
}
|
|
648
648
|
|
|
649
|
-
// ---------- theme (
|
|
650
|
-
//
|
|
651
|
-
//
|
|
652
|
-
//
|
|
653
|
-
//
|
|
654
|
-
|
|
655
|
-
var themeMedia = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null;
|
|
656
|
-
|
|
657
|
-
function storedTheme() {
|
|
658
|
-
try { var v = window.localStorage.getItem(THEME_KEY); return v === 'dark' || v === 'light' ? v : null; } catch (_) { return null; }
|
|
659
|
-
}
|
|
660
|
-
function effectiveTheme() {
|
|
661
|
-
return storedTheme() || (themeMedia && themeMedia.matches ? 'dark' : 'light');
|
|
662
|
-
}
|
|
649
|
+
// ---------- theme: the hall is dark only (task 1005192, ADR 0402) ----------
|
|
650
|
+
// Helm is the hall's one look, so there is no light/dark switch and no stored
|
|
651
|
+
// choice: the server stamps html[data-theme="dark"] on every hall page
|
|
652
|
+
// (src/hall-helm.js) and this sets it again, for a page read without that stamp.
|
|
653
|
+
// The old 'hall-theme' preference is never read. Scripts that only READ the
|
|
654
|
+
// attribute (the city, the sky, the atlas) keep working: they always read dark.
|
|
663
655
|
function applyTheme() {
|
|
664
|
-
|
|
665
|
-
document.documentElement.dataset.theme = t;
|
|
666
|
-
var btn = document.getElementById('theme-toggle');
|
|
667
|
-
if (btn) {
|
|
668
|
-
var toDark = t !== 'dark';
|
|
669
|
-
btn.setAttribute('aria-label', toDark ? 'Switch to dark theme' : 'Switch to light theme');
|
|
670
|
-
btn.title = btn.getAttribute('aria-label');
|
|
671
|
-
btn.innerHTML = toDark
|
|
672
|
-
? '<svg viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M14.5 10.8A6 6 0 0 1 7.2 3.5a6 6 0 1 0 7.3 7.3Z"/></svg>'
|
|
673
|
-
: '<svg viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><circle cx="9" cy="9" r="3.5"/><path d="M9 1.5v2m0 11v2M1.5 9h2m11 0h2M3.7 3.7l1.4 1.4m7.8 7.8 1.4 1.4m0-10.6-1.4 1.4M5.1 12.9l-1.4 1.4"/></svg>';
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
function toggleTheme() {
|
|
677
|
-
var next = effectiveTheme() === 'dark' ? 'light' : 'dark';
|
|
678
|
-
try { window.localStorage.setItem(THEME_KEY, next); } catch (_) { /* private mode */ }
|
|
679
|
-
applyTheme();
|
|
656
|
+
document.documentElement.dataset.theme = 'dark';
|
|
680
657
|
}
|
|
681
658
|
|
|
682
659
|
// ---------- zoom (accessibility: enlarge the whole page) ----------
|
|
683
660
|
// task 1475 (idea 280): a one-click "make everything bigger" control for
|
|
684
661
|
// readability. Cycles 100% -> 125% -> 150% -> 100% via CSS `zoom` on <html>,
|
|
685
662
|
// which enlarges px AND rem sizes uniformly (a font-size bump would miss the
|
|
686
|
-
// hall's many px values). Persisted per-browser
|
|
663
|
+
// hall's many px values). Persisted per-browser.
|
|
687
664
|
var ZOOM_KEY = 'hall-zoom';
|
|
688
665
|
var ZOOM_STEPS = [1, 1.25, 1.5];
|
|
689
666
|
function storedZoom() {
|
|
@@ -1326,8 +1303,6 @@
|
|
|
1326
1303
|
if (document.documentElement.classList.contains('drawer-open')) closeDrawer();
|
|
1327
1304
|
else openDrawer();
|
|
1328
1305
|
});
|
|
1329
|
-
var theme = document.getElementById('theme-toggle');
|
|
1330
|
-
if (theme) theme.addEventListener('click', toggleTheme);
|
|
1331
1306
|
var zoom = document.getElementById('zoom-toggle');
|
|
1332
1307
|
if (zoom) zoom.addEventListener('click', cycleZoom);
|
|
1333
1308
|
var full = document.getElementById('fullscreen-toggle');
|
|
@@ -1335,9 +1310,6 @@
|
|
|
1335
1310
|
full.addEventListener('click', function () { setFullscreen(!isFullscreen()); });
|
|
1336
1311
|
window.addEventListener('keydown', onFullscreenKey);
|
|
1337
1312
|
}
|
|
1338
|
-
if (themeMedia && themeMedia.addEventListener) {
|
|
1339
|
-
themeMedia.addEventListener('change', function () { if (!storedTheme()) applyTheme(); });
|
|
1340
|
-
}
|
|
1341
1313
|
var scrim = document.getElementById('app-scrim');
|
|
1342
1314
|
if (scrim) scrim.addEventListener('click', closeDrawer);
|
|
1343
1315
|
var sidebar = document.getElementById('app-sidebar');
|
|
@@ -1469,9 +1441,6 @@
|
|
|
1469
1441
|
closeDrawer: closeDrawer,
|
|
1470
1442
|
isFullscreen: isFullscreen,
|
|
1471
1443
|
setFullscreen: setFullscreen,
|
|
1472
|
-
// task 1004544: a page with its own light/dark switch (the governor city
|
|
1473
|
-
// and street) repaints the top bar's after writing 'hall-theme'.
|
|
1474
|
-
applyTheme: applyTheme,
|
|
1475
1444
|
// task 1004477: a page that renders an exit after boot asks the shell to fill it.
|
|
1476
1445
|
fillExits: TRAIL.fillExits,
|
|
1477
1446
|
positions: function () { return access.positions; }, // task 1004713: seats held (null while unknown)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_": "THE MATTER CARD THAT ACTS (task 1004528, goal 1000125) on the street page, through modules/ui-design/kit/render.js. Kept beside street.states.json rather than inside it, so the street and its interiors (task 1004526) and the card each own their states. The populated card needs the hall-preview harness, whose government__docket.json puts the review-seat amendment on the board source (board:47) and whose government__board__items.json carries its ballot (item 47), with a canned answer for a vote:\n\n node scripts/hall-preview/server.js --port 4625 --fixture-me\n node modules/ui-design/kit/render.js --states modules/hall-ui/public/street-card.states.json --base-in http://localhost:4625 --base-out http://localhost:4625\n\nTask 1004566 adds a card per kind the docket carries (blocker, red-team report, core update, module re-check, a Full Idea and the review queue), each compact and with \"more\" open; the harness fixture carries them. Against the kit stub there is no docket and no pin, so these states are for the harness.",
|
|
3
3
|
"page": "/builders/street",
|
|
4
|
+
"modes": ["dark"],
|
|
4
5
|
"_storage": "The hall asks a first-visit question (the session mode picker, craft-mode.js) over every page; seeding \"already asked\" renders the page a returning builder sees (task 1005080).",
|
|
5
6
|
"storage": { "session": { "hall-craft-asked": "1" } },
|
|
6
7
|
"surface": "hall-ui",
|
|
@@ -128,8 +128,6 @@ html[data-fullscreen="on"] .street-top { padding-right: 184px; }
|
|
|
128
128
|
.street-hud__dot--hot { background: var(--accent); }
|
|
129
129
|
.street-hud__dot--moving { width: 6px; height: 6px; border: 0; background: var(--ink); }
|
|
130
130
|
.street-hud__n { font-size: 24px; font-weight: 300; font-variant-numeric: tabular-nums; }
|
|
131
|
-
.street-mode { margin-left: 36px; flex: none; background: none; border: 1px solid var(--street-rule-strong); border-radius: 999px; height: 36px; padding: 0 14px; display: flex; align-items: center; gap: 8px; cursor: pointer; color: var(--ink); font-family: var(--font-body); font-size: 13px; text-transform: lowercase; }
|
|
132
|
-
.street-mode svg { display: block; stroke-width: 1.4; }
|
|
133
131
|
|
|
134
132
|
/* the street band: the prototype's 1440-wide artboard, scaled by street.js */
|
|
135
133
|
/* The living street's parallax (task 1004685) is Keith Clark's, sideways and
|
|
@@ -309,20 +307,18 @@ html[data-fullscreen="on"] .street-top { padding-right: 184px; }
|
|
|
309
307
|
.street-card__lines li { padding: 8px 0; border-top: 1px solid var(--street-rule); font-size: 14px; line-height: 1.4; }
|
|
310
308
|
.street-card__result { margin: 0; font-size: 15px; line-height: 1.45; }
|
|
311
309
|
|
|
312
|
-
.street-mark:focus-visible, .street-
|
|
310
|
+
.street-mark:focus-visible, .street-pin:focus-visible, .street-door:focus-visible, .street-sign:focus-visible, .street-card__close:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
|
|
313
311
|
|
|
314
312
|
/* narrower: the strip tightens, then wraps; the readings scroll sideways */
|
|
315
313
|
@media (max-width: 1180px) {
|
|
316
314
|
.street-hud { gap: 20px; }
|
|
317
315
|
.street-hud__n { font-size: 20px; }
|
|
318
|
-
.street-mode { margin-left: 20px; }
|
|
319
316
|
}
|
|
320
317
|
/* narrow: two rows inside the 80 px top-bar floor, the wordmark and the switch
|
|
321
318
|
on the first, the three figures on the second as their own sideways strip */
|
|
322
319
|
@media (max-width: 900px) {
|
|
323
320
|
.street-top { height: auto; max-height: 80px; display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "brand mode" "hud hud"; row-gap: 2px; padding: 5px 16px; }
|
|
324
321
|
.street-top__brand { grid-area: brand; }
|
|
325
|
-
.street-mode { grid-area: mode; margin-left: 0; height: 34px; }
|
|
326
322
|
.street-hud { grid-area: hud; margin-left: 0; gap: 18px; min-width: 0; overflow-x: auto; overflow-y: hidden; white-space: nowrap; height: 30px; }
|
|
327
323
|
.street-hud__item { gap: 6px; flex: none; }
|
|
328
324
|
.street-hud .street-label { font-size: 11px; }
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
<!-- The faces (Manrope, JetBrains Mono) come from the branding pack's font
|
|
11
11
|
links, injected into this head by the server like every hall page's
|
|
12
12
|
(tests/hall_tokens.mjs: no hall page hardcodes a web-font stylesheet). -->
|
|
13
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-11-
|
|
14
|
-
<link rel="stylesheet" href="/builders/street.css?v=2026-
|
|
13
|
+
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-view2">
|
|
14
|
+
<link rel="stylesheet" href="/builders/street.css?v=2026-11-11-helm">
|
|
15
15
|
<link rel="stylesheet" href="/builders/street-card.css?v=2026-10-04-record1">
|
|
16
16
|
<link rel="stylesheet" href="/builders/street-deck.css?v=2026-10-17-tidy">
|
|
17
17
|
</head>
|
|
@@ -92,10 +92,6 @@
|
|
|
92
92
|
<span class="street-hud__n" id="hudShare">—</span>
|
|
93
93
|
</div>
|
|
94
94
|
</div>
|
|
95
|
-
<button type="button" class="street-mode" id="streetMode" aria-label="Switch to light mode" title="Switch to light mode">
|
|
96
|
-
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" aria-hidden="true"><path id="streetModeIcon" d=""></path></svg>
|
|
97
|
-
<span id="streetModeWord">light</span>
|
|
98
|
-
</button>
|
|
99
95
|
</div>
|
|
100
96
|
|
|
101
97
|
<div class="street-window" id="streetWindow">
|
|
@@ -229,10 +225,10 @@
|
|
|
229
225
|
</div>
|
|
230
226
|
|
|
231
227
|
<script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
|
|
232
|
-
<script src="/builders/shell-game.js?v=2026-11-
|
|
228
|
+
<script src="/builders/shell-game.js?v=2026-11-11-view2"></script>
|
|
233
229
|
<script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
|
|
234
230
|
<script src="/builders/craft-mode.js?v=2026-11-10-visor"></script>
|
|
235
|
-
<script src="/builders/shell.js?v=2026-11-
|
|
231
|
+
<script src="/builders/shell.js?v=2026-11-11-view2"></script>
|
|
236
232
|
<script src="/builders/hall-dialog.js"></script>
|
|
237
233
|
<script src="/builders/palette.js" defer></script>
|
|
238
234
|
<script src="/builders/gov-living.js?v=2026-10-09-positions1"></script>
|
|
@@ -246,6 +242,6 @@
|
|
|
246
242
|
<script src="/builders/street-amend.js?v=2026-10-02-amend1"></script>
|
|
247
243
|
<script src="/builders/street-deck.js?v=2026-10-13-glass1"></script>
|
|
248
244
|
<script src="/builders/street-office.js?v=2026-10-17-tidy"></script>
|
|
249
|
-
<script src="/builders/street.js?v=2026-
|
|
245
|
+
<script src="/builders/street.js?v=2026-11-11-helm"></script>
|
|
250
246
|
</body>
|
|
251
247
|
</html>
|
|
@@ -28,10 +28,8 @@
|
|
|
28
28
|
// A feed that fails leaves its part out (no pins, no districts, "—" for the
|
|
29
29
|
// share) and the page says the docket could not be read; it never draws sample data.
|
|
30
30
|
//
|
|
31
|
-
// THE
|
|
32
|
-
//
|
|
33
|
-
// hall page. The drawing's faces are drawing data in the mode, so a toggle
|
|
34
|
-
// redraws the street from the last feeds (no refetch).
|
|
31
|
+
// THE MODE. The hall is dark only (task 1005192, ADR 0402), so the street has
|
|
32
|
+
// no light/dark switch and reads no stored choice: it draws its night faces.
|
|
35
33
|
//
|
|
36
34
|
// MOTION is CSS only (street.css); nothing here animates. The scale write on
|
|
37
35
|
// resize is layout, not motion.
|
|
@@ -64,9 +62,6 @@
|
|
|
64
62
|
'use strict';
|
|
65
63
|
var S = window.GovStreet;
|
|
66
64
|
var SVG_NS = 'http://www.w3.org/2000/svg';
|
|
67
|
-
var THEME_KEY = 'hall-theme';
|
|
68
|
-
var SUN = 'M7 1.5V3M7 11v1.5M1.5 7H3M11 7h1.5M3.1 3.1l1 1M9.9 9.9l1 1M3.1 10.9l1-1M9.9 4.1l1-1M9.5 7A2.5 2.5 0 1 1 4.5 7A2.5 2.5 0 1 1 9.5 7Z';
|
|
69
|
-
var MOON = 'M11.5 8.6A5 5 0 0 1 5.4 2.5A5 5 0 1 0 11.5 8.6Z';
|
|
70
65
|
var FEEDS = {
|
|
71
66
|
docket: '/api/bongos/government/docket',
|
|
72
67
|
goals: '/api/bongos/goals',
|
|
@@ -88,7 +83,6 @@
|
|
|
88
83
|
var CARD_W = 390;
|
|
89
84
|
|
|
90
85
|
var $ = function (id) { return document.getElementById(id); };
|
|
91
|
-
var media = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null;
|
|
92
86
|
var data = { docket: null, goals: [], rollups: [], earnings: null, loaded: false, tasks: {}, room: null, constitution: null };
|
|
93
87
|
// ask: the act whose chips stand open; more: the detail is open in place;
|
|
94
88
|
// pick: which of the review queue the queue's card shows (task 1004566)
|
|
@@ -108,52 +102,12 @@
|
|
|
108
102
|
var today = { day: '', n: 0 };
|
|
109
103
|
var todayDrawn = null; // the count the meter's pips last drew: they are rebuilt only when it moves
|
|
110
104
|
|
|
111
|
-
// ----------
|
|
112
|
-
var chosen = null;
|
|
113
|
-
function storedTheme() {
|
|
114
|
-
try { var v = window.localStorage.getItem(THEME_KEY); if (v === 'dark' || v === 'light') return v; } catch (_) { /* blocked */ }
|
|
115
|
-
return chosen;
|
|
116
|
-
}
|
|
117
|
-
function effectiveTheme() { return storedTheme() || (media && media.matches ? 'dark' : 'light'); }
|
|
118
|
-
function paintSwitch(t) {
|
|
119
|
-
var btn = $('streetMode');
|
|
120
|
-
var label = t === 'dark' ? 'Switch to light mode' : 'Switch to dark mode';
|
|
121
|
-
if (btn) { btn.setAttribute('aria-label', label); btn.setAttribute('title', label); }
|
|
122
|
-
var icon = $('streetModeIcon');
|
|
123
|
-
if (icon) icon.setAttribute('d', t === 'dark' ? SUN : MOON);
|
|
124
|
-
var word = $('streetModeWord');
|
|
125
|
-
if (word) word.textContent = t === 'dark' ? 'light' : 'dark';
|
|
126
|
-
}
|
|
105
|
+
// ---------- the mode: dark only (task 1005192, ADR 0402) ----------
|
|
127
106
|
function applyTheme() {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
paintSwitch(t);
|
|
131
|
-
return t;
|
|
132
|
-
}
|
|
133
|
-
function toggleTheme() {
|
|
134
|
-
var next = effectiveTheme() === 'dark' ? 'light' : 'dark';
|
|
135
|
-
chosen = next;
|
|
136
|
-
try { window.localStorage.setItem(THEME_KEY, next); } catch (_) { /* private mode: this page only */ }
|
|
137
|
-
painted = applyTheme();
|
|
138
|
-
draw();
|
|
139
|
-
var shell = window.OTBShell;
|
|
140
|
-
if (shell && typeof shell.applyTheme === 'function' && storedTheme() === painted) shell.applyTheme();
|
|
141
|
-
}
|
|
142
|
-
// IN THE HALL (task 1004544) the shell's top bar carries the hall's own theme
|
|
143
|
-
// switch beside this one, as on the city. Both write the same 'hall-theme'
|
|
144
|
-
// preference and html[data-theme]; each repaints when the other flips it.
|
|
145
|
-
var painted = null;
|
|
146
|
-
function watchShellTheme() {
|
|
147
|
-
if (typeof MutationObserver !== 'function') return;
|
|
148
|
-
new MutationObserver(function () {
|
|
149
|
-
var t = document.documentElement.getAttribute('data-theme');
|
|
150
|
-
if ((t === 'dark' || t === 'light') && t !== painted) { painted = t; chosen = t; paintSwitch(t); draw(); }
|
|
151
|
-
}).observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] });
|
|
152
|
-
}
|
|
153
|
-
function currentMode() {
|
|
154
|
-
var t = document.documentElement.getAttribute('data-theme');
|
|
155
|
-
return t === 'light' || t === 'dark' ? t : effectiveTheme();
|
|
107
|
+
document.documentElement.setAttribute('data-theme', 'dark');
|
|
108
|
+
return 'dark';
|
|
156
109
|
}
|
|
110
|
+
function currentMode() { return 'dark'; }
|
|
157
111
|
|
|
158
112
|
// ---------- the address ----------
|
|
159
113
|
function here() { return S.parseHash(window.location && window.location.hash); }
|
|
@@ -316,7 +270,6 @@
|
|
|
316
270
|
function draw() {
|
|
317
271
|
var mode = currentMode();
|
|
318
272
|
view.mode = mode;
|
|
319
|
-
paintSwitch(mode);
|
|
320
273
|
var h = here();
|
|
321
274
|
var inside = $('streetInside');
|
|
322
275
|
var sizerEl = $('streetSizer');
|
|
@@ -1465,8 +1418,6 @@
|
|
|
1465
1418
|
}
|
|
1466
1419
|
|
|
1467
1420
|
function boot() {
|
|
1468
|
-
var btn = $('streetMode');
|
|
1469
|
-
if (btn) btn.addEventListener('click', toggleTheme);
|
|
1470
1421
|
var close = $('streetCardClose');
|
|
1471
1422
|
if (close) close.addEventListener('click', function () { closeCard(true); });
|
|
1472
1423
|
window.addEventListener('keydown', onKey);
|
|
@@ -1479,8 +1430,7 @@
|
|
|
1479
1430
|
if (am) am.addEventListener('click', amend);
|
|
1480
1431
|
var win = $('streetWindow');
|
|
1481
1432
|
if (win) win.addEventListener('scroll', placeCard);
|
|
1482
|
-
|
|
1483
|
-
painted = applyTheme();
|
|
1433
|
+
applyTheme();
|
|
1484
1434
|
today = readToday();
|
|
1485
1435
|
// the decision deck (#deck) and the government inside each building, over the
|
|
1486
1436
|
// street's own senders (street-deck.js, street-office.js; task 1004685)
|
|
@@ -1490,10 +1440,9 @@
|
|
|
1490
1440
|
// an answer in the deck moves the header's counts as it moves the deck's
|
|
1491
1441
|
if (window.GovFeeds) window.GovFeeds.onChange(function () { if (data.loaded) draw(); });
|
|
1492
1442
|
draw();
|
|
1493
|
-
watchShellTheme();
|
|
1494
1443
|
return load();
|
|
1495
1444
|
}
|
|
1496
1445
|
|
|
1497
|
-
window.GovStreetPage = { boot: boot, draw: draw, load: load, fit: fit, openCard: openCard, closeCard: closeCard, actOn: actOn, pickFloor: pickFloor, deskAct: deskAct, goStreet: goStreet, amend: amend, fileDraft: fileDraft, FEEDS: FEEDS
|
|
1446
|
+
window.GovStreetPage = { boot: boot, draw: draw, load: load, fit: fit, openCard: openCard, closeCard: closeCard, actOn: actOn, pickFloor: pickFloor, deskAct: deskAct, goStreet: goStreet, amend: amend, fileDraft: fileDraft, FEEDS: FEEDS };
|
|
1498
1447
|
window.GovStreetPage.ready = boot();
|
|
1499
1448
|
}());
|