@bongos/core 1.19.1050 → 1.19.1052
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 +65 -55
- package/docs/copy-inventory.md +85 -79
- package/docs/copy-registry.json +212 -138
- package/docs/module-api-changelog.md +4 -0
- package/modules/hall-ui/public/atlas.html +1 -1
- package/modules/hall-ui/public/blockers.html +1 -1
- package/modules/hall-ui/public/board-room.html +1 -1
- package/modules/hall-ui/public/collab.html +1 -1
- package/modules/hall-ui/public/copy-desk.html +1 -1
- package/modules/hall-ui/public/deploy.html +1 -1
- package/modules/hall-ui/public/diagrams.html +1 -1
- package/modules/hall-ui/public/drachmae.html +1 -1
- package/modules/hall-ui/public/fleet.html +1 -1
- package/modules/hall-ui/public/gate.html +1 -1
- package/modules/hall-ui/public/goals.html +1 -1
- package/modules/hall-ui/public/government.html +1 -1
- package/modules/hall-ui/public/idea.html +1 -1
- package/modules/hall-ui/public/ideas.html +1 -1
- package/modules/hall-ui/public/index.html +1 -1
- package/modules/hall-ui/public/modules.html +1 -1
- package/modules/hall-ui/public/primer.html +1 -1
- package/modules/hall-ui/public/profile.html +1 -1
- package/modules/hall-ui/public/project-settings.html +1 -1
- package/modules/hall-ui/public/ranks.html +1 -1
- package/modules/hall-ui/public/roadmap.html +1 -1
- package/modules/hall-ui/public/roster.html +1 -1
- package/modules/hall-ui/public/sessions.html +1 -1
- package/modules/hall-ui/public/settings.html +1 -1
- package/modules/hall-ui/public/shell.js +77 -1
- package/modules/hall-ui/public/sky-data.js +13 -2
- package/modules/hall-ui/public/sky-interaction.js +13 -8
- package/modules/hall-ui/public/sky-layout.js +6 -1
- package/modules/hall-ui/public/studio.html +10 -4
- package/modules/hall-ui/public/studio.states.json +76 -1
- package/modules/hall-ui/public/style.css +53 -0
- package/modules/hall-ui/public/task.html +1 -1
- package/modules/hall-ui/public/thinking.css +54 -16
- package/modules/hall-ui/public/thinking.html +38 -18
- package/modules/hall-ui/public/thinking.states.json +19 -2
- package/modules/hall-ui/public/watch.html +1 -1
- package/modules/hall-ui/public/work.html +1 -1
- package/modules/hall-ui/records/sky.md +9 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +12 -0
- package/scripts/gds/seed-bv2-tweak-mode-tasks.js +277 -0
- package/src/module-api.js +1 -1
- package/tests/goal_map_page.mjs +5 -3
- package/tests/hall_audit.mjs +2 -1
- package/tests/hall_fullscreen.mjs +196 -0
- package/tests/nav_permission_atoms.mjs +1 -1
|
@@ -2587,5 +2587,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
2587
2587
|
landed since 1.19.1048 with no explicit bump. run 36323359891. (task 1002620)
|
|
2588
2588
|
1.19.1050 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2589
2589
|
landed since 1.19.1049 with no explicit bump. run 36324195800. (task 1002620)
|
|
2590
|
+
1.19.1051 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2591
|
+
landed since 1.19.1050 with no explicit bump. run 36369343116. (task 1002620)
|
|
2592
|
+
1.19.1052 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2593
|
+
landed since 1.19.1051 with no explicit bump. run 36372902384. (task 1002620)
|
|
2590
2594
|
---------------------------------------------------------------------------
|
|
2591
2595
|
```
|
|
@@ -91,7 +91,7 @@
|
|
|
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.js?v=2026-09-
|
|
94
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
95
95
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
96
96
|
<script src="/builders/palette.js" defer></script>
|
|
97
97
|
<script src="/builders/atlas.js?v=2026-09-02-index" defer></script>
|
|
@@ -50,7 +50,7 @@
|
|
|
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.js?v=2026-09-
|
|
53
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
54
54
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
55
55
|
<script src="/builders/palette.js" defer></script>
|
|
56
56
|
<!-- shared frontend toolkit (window.OTB — rank labels, number formats) + the
|
|
@@ -60,7 +60,7 @@
|
|
|
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.js?v=2026-09-
|
|
63
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
64
64
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
65
65
|
<script src="/builders/palette.js" defer></script>
|
|
66
66
|
<script src="/builders/dom-utils.js?v=2026-06-16-board"></script>
|
|
@@ -148,7 +148,7 @@
|
|
|
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.js?v=2026-09-
|
|
151
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
152
152
|
<script src="/builders/palette.js" defer></script>
|
|
153
153
|
<script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
|
|
154
154
|
<script src="/builders/collab-lib.js?v=2026-09-24-archive"></script>
|
|
@@ -177,7 +177,7 @@
|
|
|
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.js?v=2026-09-
|
|
180
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
181
181
|
<script src="/builders/palette.js" defer></script>
|
|
182
182
|
<script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
|
|
183
183
|
<script src="/builders/hall-kit.js"></script>
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
|
|
70
70
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
71
71
|
|
|
72
|
-
<script src="/builders/shell.js?v=2026-09-
|
|
72
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
73
73
|
<script src="/builders/palette.js" defer></script>
|
|
74
74
|
<script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
|
|
75
75
|
<script src="/builders/hall-kit.js"></script>
|
|
@@ -97,7 +97,7 @@
|
|
|
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.js?v=2026-09-
|
|
100
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
101
101
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
102
102
|
<script src="/builders/palette.js" defer></script>
|
|
103
103
|
<script src="/builders/diagram-viewer.js?v=2026-06-14-diagviewer-1" defer></script>
|
|
@@ -98,7 +98,7 @@
|
|
|
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.js?v=2026-09-
|
|
101
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
102
102
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
103
103
|
<script src="/builders/palette.js" defer></script>
|
|
104
104
|
<script src="/builders/md-reader.js?v=2026-09-02-mdreader-2"></script>
|
|
@@ -54,7 +54,7 @@
|
|
|
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.js?v=2026-09-
|
|
57
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
58
58
|
<script src="/builders/palette.js" defer></script>
|
|
59
59
|
<script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
|
|
60
60
|
<script src="/builders/hall-kit.js"></script>
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
<div id="gate-modal-root"></div>
|
|
77
77
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
78
78
|
|
|
79
|
-
<script src="/builders/shell.js?v=2026-09-
|
|
79
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
80
80
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
81
81
|
<script src="/builders/palette.js" defer></script>
|
|
82
82
|
<script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
|
|
@@ -235,7 +235,7 @@
|
|
|
235
235
|
|
|
236
236
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
237
237
|
|
|
238
|
-
<script src="/builders/shell.js?v=2026-09-
|
|
238
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
239
239
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
240
240
|
<script src="/builders/palette.js" defer></script>
|
|
241
241
|
<script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
|
|
135
135
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
136
136
|
|
|
137
|
-
<script src="/builders/shell.js?v=2026-09-
|
|
137
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
138
138
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
139
139
|
<script src="/builders/palette.js" defer></script>
|
|
140
140
|
<script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
|
|
53
53
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
54
54
|
|
|
55
|
-
<script src="/builders/shell.js?v=2026-09-
|
|
55
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
56
56
|
<script src="/builders/palette.js" defer></script>
|
|
57
57
|
<script src="/builders/dom-utils.js?v=2026-06-23-contrib" defer></script>
|
|
58
58
|
<!-- task-detail.js still owns the #/idea/N and #/blocker/N overlay, so a ref
|
|
@@ -225,7 +225,7 @@
|
|
|
225
225
|
|
|
226
226
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
227
227
|
|
|
228
|
-
<script src="/builders/shell.js?v=2026-09-
|
|
228
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
229
229
|
<script src="/builders/palette.js" defer></script>
|
|
230
230
|
<script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
|
|
231
231
|
<!-- task 1003069 (R08) — the quick-filing form's routed result links a task
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
<script src="/builders/brand-apply.js?v=2026-06-27-r75" defer></script>
|
|
103
103
|
<!-- The app shell (sidebar + top bar + view router). Dependency-free; loaded
|
|
104
104
|
BEFORE builders.js so the chrome ids exist when events are wired. -->
|
|
105
|
-
<script src="/builders/shell.js?v=2026-09-
|
|
105
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen" defer></script>
|
|
106
106
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
107
107
|
<script src="/builders/palette.js" defer></script>
|
|
108
108
|
<!-- task 2166: the shared component kit (window.OTBKit) — pager/ledger/rail.
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
|
|
81
81
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
82
82
|
|
|
83
|
-
<script src="/builders/shell.js?v=2026-09-
|
|
83
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
84
84
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
85
85
|
<script src="/builders/palette.js" defer></script>
|
|
86
86
|
<script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
|
|
116
116
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
117
117
|
|
|
118
|
-
<script src="/builders/shell.js?v=2026-09-
|
|
118
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
119
119
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
120
120
|
<script src="/builders/palette.js" defer></script>
|
|
121
121
|
<!-- the shared markdown reader (window.OTBMdReader) — primer.js renders through
|
|
@@ -187,7 +187,7 @@
|
|
|
187
187
|
|
|
188
188
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
189
189
|
chrome exists before the page script runs. -->
|
|
190
|
-
<script src="/builders/shell.js?v=2026-09-
|
|
190
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
191
191
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
192
192
|
<script src="/builders/palette.js" defer></script>
|
|
193
193
|
<!-- shared frontend toolkit (window.OTB) — loaded before profile.js, which pulls from it. -->
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
|
|
59
59
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
60
60
|
|
|
61
|
-
<script src="/builders/shell.js?v=2026-09-
|
|
61
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
62
62
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
63
63
|
<script src="/builders/palette.js" defer></script>
|
|
64
64
|
<script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
|
|
69
69
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
70
70
|
chrome exists before the page script runs. -->
|
|
71
|
-
<script src="/builders/shell.js?v=2026-09-
|
|
71
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
72
72
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
73
73
|
<script src="/builders/palette.js" defer></script>
|
|
74
74
|
<!-- shared frontend toolkit (window.OTB) — loaded before ranks.js, which pulls from it. -->
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
|
|
42
42
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
43
43
|
|
|
44
|
-
<script src="/builders/shell.js?v=2026-09-
|
|
44
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
45
45
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
46
46
|
<script src="/builders/palette.js" defer></script>
|
|
47
47
|
<script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>
|
|
@@ -50,7 +50,7 @@
|
|
|
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.js?v=2026-09-
|
|
53
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
54
54
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
55
55
|
<script src="/builders/palette.js" defer></script>
|
|
56
56
|
<!-- shared frontend toolkit (window.OTB — rank labels, number formats) + the
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
|
|
100
100
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
101
101
|
chrome exists before the page script runs. -->
|
|
102
|
-
<script src="/builders/shell.js?v=2026-09-
|
|
102
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></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
|
<!-- shared frontend toolkit (window.OTB) — loaded BEFORE sessions.js so it can pull from it. -->
|
|
@@ -436,7 +436,7 @@
|
|
|
436
436
|
|
|
437
437
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
438
438
|
chrome exists before the page scripts run. -->
|
|
439
|
-
<script src="/builders/shell.js?v=2026-09-
|
|
439
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
440
440
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
441
441
|
<script src="/builders/palette.js" defer></script>
|
|
442
442
|
<!-- shared frontend toolkit (window.OTB) — loaded before consuming IIFEs. -->
|
|
@@ -497,11 +497,79 @@
|
|
|
497
497
|
'<kbd class="topbar-jump__kbd" id="topbar-jump-kbd"></kbd>' +
|
|
498
498
|
'</button>' +
|
|
499
499
|
'<button class="zoom-toggle" id="zoom-toggle" type="button" aria-label="Text size"></button>' +
|
|
500
|
-
'<button class="theme-toggle" id="theme-toggle" type="button" aria-label="Switch theme"></button
|
|
500
|
+
'<button class="theme-toggle" id="theme-toggle" type="button" aria-label="Switch theme"></button>' +
|
|
501
|
+
// task 1004327: the full-screen switch, LAST so it sits in the corner the
|
|
502
|
+
// collapsed bar keeps in full screen — the one control that stays put.
|
|
503
|
+
(fullscreenPage() ? '<button class="fullscreen-toggle" id="fullscreen-toggle" type="button" aria-pressed="false"></button>' : '') +
|
|
504
|
+
'</div>';
|
|
501
505
|
var t = document.getElementById('topbar-title');
|
|
502
506
|
if (t) t.textContent = title;
|
|
503
507
|
}
|
|
504
508
|
|
|
509
|
+
// ---------- full screen (task 1004327) ----------
|
|
510
|
+
// One switch any page can opt into with <body data-fullscreen-switch>: it hides
|
|
511
|
+
// the sidebar, the top bar and the foot so the page fills the window, and the
|
|
512
|
+
// same button (the only thing left of the top bar) brings them back. Escape
|
|
513
|
+
// leaves too. The state is html[data-fullscreen="on"] — the data-theme /
|
|
514
|
+
// data-social pattern — so the chrome's hiding is style.css's, and a page that
|
|
515
|
+
// lays itself out against the chrome reads the same attribute.
|
|
516
|
+
//
|
|
517
|
+
// Remembered PER PAGE (`hall-fullscreen:<data-page>`): full screen is a choice
|
|
518
|
+
// about one surface, and the studio's must not follow the reader to the sky.
|
|
519
|
+
// Storage can throw in a private window; the chrome then just shows, which is
|
|
520
|
+
// the honest default.
|
|
521
|
+
var FULLSCREEN_KEY = 'hall-fullscreen:';
|
|
522
|
+
function fullscreenPage() {
|
|
523
|
+
var b = document.body;
|
|
524
|
+
if (!b || !b.hasAttribute || !b.hasAttribute('data-fullscreen-switch')) return null;
|
|
525
|
+
return (b.dataset && b.dataset.page) || 'page';
|
|
526
|
+
}
|
|
527
|
+
function storedFullscreen() {
|
|
528
|
+
var page = fullscreenPage();
|
|
529
|
+
if (!page) return false;
|
|
530
|
+
try { return window.localStorage.getItem(FULLSCREEN_KEY + page) === 'on'; } catch (_) { return false; }
|
|
531
|
+
}
|
|
532
|
+
function isFullscreen() { return document.documentElement.dataset.fullscreen === 'on'; }
|
|
533
|
+
var FULLSCREEN_ICONS = {
|
|
534
|
+
enter: '<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="M3 7V3h4M11 3h4v4M15 11v4h-4M7 15H3v-4"/></svg>',
|
|
535
|
+
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>',
|
|
536
|
+
};
|
|
537
|
+
function applyFullscreen(on) {
|
|
538
|
+
if (!fullscreenPage()) on = false;
|
|
539
|
+
var root = document.documentElement;
|
|
540
|
+
if (on) root.dataset.fullscreen = 'on'; else delete root.dataset.fullscreen;
|
|
541
|
+
var btn = document.getElementById('fullscreen-toggle');
|
|
542
|
+
if (btn) {
|
|
543
|
+
var label = on ? 'Leave full screen (Esc)' : 'Full screen — hide the sidebar and top bar';
|
|
544
|
+
btn.setAttribute('aria-pressed', on ? 'true' : 'false');
|
|
545
|
+
btn.setAttribute('aria-label', on ? 'Leave full screen' : 'Full screen');
|
|
546
|
+
btn.title = label;
|
|
547
|
+
btn.innerHTML = on ? FULLSCREEN_ICONS.leave : FULLSCREEN_ICONS.enter;
|
|
548
|
+
}
|
|
549
|
+
if (on) closeDrawer();
|
|
550
|
+
}
|
|
551
|
+
function setFullscreen(on) {
|
|
552
|
+
var page = fullscreenPage();
|
|
553
|
+
if (!page) return;
|
|
554
|
+
try { window.localStorage.setItem(FULLSCREEN_KEY + page, on ? 'on' : 'off'); } catch (_) { /* private mode */ }
|
|
555
|
+
applyFullscreen(on);
|
|
556
|
+
// A page that sizes itself to its box (the sky's canvas) re-measures on the
|
|
557
|
+
// window's resize; the box just changed without the window doing so.
|
|
558
|
+
try { window.dispatchEvent(new Event('resize')); } catch (_) { /* old engine */ }
|
|
559
|
+
}
|
|
560
|
+
function inTextField(el) {
|
|
561
|
+
var tag = el && el.tagName ? String(el.tagName).toLowerCase() : '';
|
|
562
|
+
return tag === 'input' || tag === 'textarea' || tag === 'select' || !!(el && el.isContentEditable);
|
|
563
|
+
}
|
|
564
|
+
// Escape leaves full screen — unless something on the page used that press
|
|
565
|
+
// (a tour, a menu, the palette: each calls preventDefault) or the reader is in
|
|
566
|
+
// a text field, where Escape belongs to the field. Page listeners may be on
|
|
567
|
+
// the window AFTER this one, so the verdict waits for the dispatch to finish.
|
|
568
|
+
function onFullscreenKey(e) {
|
|
569
|
+
if (e.key !== 'Escape' || !isFullscreen() || e.defaultPrevented || inTextField(e.target)) return;
|
|
570
|
+
window.setTimeout(function () { if (!e.defaultPrevented && isFullscreen()) setFullscreen(false); }, 0);
|
|
571
|
+
}
|
|
572
|
+
|
|
505
573
|
// ---------- theme (light / dark) ----------
|
|
506
574
|
// The pack's :root override carries only light values; the dark neutrals live
|
|
507
575
|
// in style.css under html[data-theme="dark"] (higher specificity than :root,
|
|
@@ -1020,6 +1088,11 @@
|
|
|
1020
1088
|
if (theme) theme.addEventListener('click', toggleTheme);
|
|
1021
1089
|
var zoom = document.getElementById('zoom-toggle');
|
|
1022
1090
|
if (zoom) zoom.addEventListener('click', cycleZoom);
|
|
1091
|
+
var full = document.getElementById('fullscreen-toggle');
|
|
1092
|
+
if (full) {
|
|
1093
|
+
full.addEventListener('click', function () { setFullscreen(!isFullscreen()); });
|
|
1094
|
+
window.addEventListener('keydown', onFullscreenKey);
|
|
1095
|
+
}
|
|
1023
1096
|
if (themeMedia && themeMedia.addEventListener) {
|
|
1024
1097
|
themeMedia.addEventListener('change', function () { if (!storedTheme()) applyTheme(); });
|
|
1025
1098
|
}
|
|
@@ -1098,6 +1171,7 @@
|
|
|
1098
1171
|
renderFoot();
|
|
1099
1172
|
applyTheme();
|
|
1100
1173
|
applyZoom();
|
|
1174
|
+
applyFullscreen(storedFullscreen());
|
|
1101
1175
|
applyAccess(null); // default: everything gated until access is known
|
|
1102
1176
|
wire();
|
|
1103
1177
|
if (IS_INDEX) {
|
|
@@ -1117,5 +1191,7 @@
|
|
|
1117
1191
|
setView: setView,
|
|
1118
1192
|
currentView: function () { return currentView; },
|
|
1119
1193
|
closeDrawer: closeDrawer,
|
|
1194
|
+
isFullscreen: isFullscreen,
|
|
1195
|
+
setFullscreen: setFullscreen,
|
|
1120
1196
|
};
|
|
1121
1197
|
})();
|
|
@@ -64,6 +64,17 @@
|
|
|
64
64
|
const lerp = (a, b, t) => a + (b - a) * t;
|
|
65
65
|
const smooth = (v, a, b) => { const t = clamp((v - a) / (b - a), 0, 1); return t * t * (3 - 2 * t); };
|
|
66
66
|
const ease = (t) => 1 - Math.pow(1 - t, 3);
|
|
67
|
+
// viewport — the box the sky is drawn in (task 1004327). On /thinking that is
|
|
68
|
+
// the hall's STAGE (main.sky-stage: under the top bar, beside the rail, or the
|
|
69
|
+
// whole window in full screen); on /goal-map, which has no stage, it is the
|
|
70
|
+
// window, exactly as the template measured. x/y are the box's offset in the
|
|
71
|
+
// window, which is what turns a pointer's clientX into a canvas coordinate.
|
|
72
|
+
function viewport() {
|
|
73
|
+
const st = document.querySelector('.sky-stage');
|
|
74
|
+
const r = st && st.getBoundingClientRect ? st.getBoundingClientRect() : null;
|
|
75
|
+
if (r && r.width > 0 && r.height > 0) return { x: r.left, y: r.top, w: r.width, h: r.height };
|
|
76
|
+
return { x: 0, y: 0, w: innerWidth, h: innerHeight };
|
|
77
|
+
}
|
|
67
78
|
// esc — the prototype builds HTML strings, and every title, criterion and
|
|
68
79
|
// goal name passes through here first, so a title never becomes markup.
|
|
69
80
|
function esc(s) { return String(s ?? '').replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c])); }
|
|
@@ -196,7 +207,7 @@
|
|
|
196
207
|
// buildWorld — the two reads (plus the versions) into the prototype's world.
|
|
197
208
|
// Called once, after the reads; everything it derives lands on S.
|
|
198
209
|
function buildWorld({ sky, mine, versions }) {
|
|
199
|
-
S.ASPECT = clamp(
|
|
210
|
+
const vp = viewport(); S.ASPECT = clamp(vp.w / Math.max(1, vp.h), 1, 1.8);
|
|
200
211
|
S.BORN = bornFromSky(sky && sky.born);
|
|
201
212
|
const BORN = S.BORN;
|
|
202
213
|
const goals = ((sky && sky.goals) || []).map(goalFromSky).map((g) => ({ ...g, bornOf: BORN.goals[g.id] || null, born: toMs(g.createdAt) }));
|
|
@@ -312,7 +323,7 @@
|
|
|
312
323
|
}
|
|
313
324
|
|
|
314
325
|
Object.assign(SKY, {
|
|
315
|
-
S, $, TAU, GOLDEN, reduce, NOW, hash, rng, clamp, lerp, smooth, ease, esc, fmtDate, fmtDay, ageDays, plain, short, store, tokens, toMs, hallBase, API, api,
|
|
326
|
+
S, $, TAU, GOLDEN, reduce, NOW, hash, rng, clamp, lerp, smooth, ease, viewport, esc, fmtDate, fmtDay, ageDays, plain, short, store, tokens, toMs, hallBase, API, api,
|
|
316
327
|
OBJ, objects, SESSION_VIAS, viaWord, bornFromSky, goalFromSky, ideaFromMine, bandsFor, wellRadius, ringR, taskAt, buildWorld, edgesOf,
|
|
317
328
|
applyRehearsal, inLayer, shown, diameter, positionWord, brightnessWord, reach, became, temp, placeIdeas, touched, load,
|
|
318
329
|
});
|
|
@@ -57,25 +57,30 @@
|
|
|
57
57
|
menu.addEventListener('pointerleave', () => { S.menuTimer = setTimeout(hideMenu, 300); });
|
|
58
58
|
|
|
59
59
|
// ---------------------------------------------------------------- interaction
|
|
60
|
-
|
|
60
|
+
// A pointer's position on the canvas: its client position less the offset of
|
|
61
|
+
// the box the sky is drawn in (zero on /goal-map; the stage's on /thinking).
|
|
62
|
+
const px = (e) => e.clientX - (S.OX || 0); const py = (e) => e.clientY - (S.OY || 0);
|
|
63
|
+
cv.addEventListener('pointerdown', (e) => { S.drag = { x: px(e), y: py(e), cx: S.cam.x, cy: S.cam.y, moved: false }; if (cv.setPointerCapture) cv.setPointerCapture(e.pointerId); cv.classList.add('dragging'); S.flight = null; showCard(null); });
|
|
61
64
|
cv.addEventListener('pointermove', (e) => {
|
|
62
65
|
const { cam } = S;
|
|
63
|
-
if (S.drag) { if (S.lens === 'simple') return; const dx = e
|
|
64
|
-
const h = hit(e
|
|
66
|
+
if (S.drag) { if (S.lens === 'simple') return; const dx = px(e) - S.drag.x, dy = py(e) - S.drag.y; if (Math.hypot(dx, dy) > 3) S.drag.moved = true; cam.x = S.drag.cx - dx / cam.k; cam.y = S.drag.cy - dy / cam.k; S.dirty = true; return; }
|
|
67
|
+
const h = hit(px(e), py(e)); const hover = S.hover; const same = h && hover && h.kind === hover.kind && h.ref === hover.ref && h.index === hover.index && h.goal === hover.goal;
|
|
65
68
|
if (!same) { S.hover = h; S.dirty = true; cv.style.cursor = h && h.kind !== 'band' ? 'pointer' : 'grab'; }
|
|
66
|
-
showCard(h, e
|
|
69
|
+
showCard(h, px(e), py(e));
|
|
67
70
|
if (h && h.kind === 'shuttle') { if (S.menuEdge !== h.ref) showMenu(h.ref, h.x, h.y); } else if (S.menuEdge && menu.hidden === false) { clearTimeout(S.menuTimer); S.menuTimer = setTimeout(hideMenu, 350); }
|
|
68
71
|
});
|
|
69
72
|
cv.addEventListener('pointerleave', () => { S.hover = null; showCard(null); S.dirty = true; });
|
|
70
|
-
cv.addEventListener('pointerup', (e) => { cv.classList.remove('dragging'); if (S.drag && !S.drag.moved) { const h = hit(e
|
|
71
|
-
cv.addEventListener('dblclick', (e) => { const h = hit(e
|
|
72
|
-
cv.addEventListener('wheel', (e) => { e.preventDefault(); if (S.lens === 'simple') return; const { cam } = S; const f = Math.exp(-e.deltaY * 0.0016); const nk = clamp(cam.k * f, 0.015, 9); const [wx, wy] = toWorld(e
|
|
73
|
+
cv.addEventListener('pointerup', (e) => { cv.classList.remove('dragging'); if (S.drag && !S.drag.moved) { const h = hit(px(e), py(e)); if (h && h.kind === 'stub') SKY.chartRoute(h.edge, h.goal); else if (h && h.kind === 'shuttle') showMenu(h.ref, h.x, h.y); else if (h && h.kind === 'ring') pick({ kind: 'goal', ref: h.goal }, false); else if (h && h.kind === 'goal' && !seen(h.ref)) { /* not reached yet */ } else if (h && h.kind === 'band') { pick(null); SKY.fitBand(h.ref); } else pick(h, false); } S.drag = null; });
|
|
74
|
+
cv.addEventListener('dblclick', (e) => { const h = hit(px(e), py(e)); if (h && h.kind === 'stub') SKY.chartAllOf(h.goal); else if (h && (h.kind === 'goal' || h.kind === 'ring') && seen(h.kind === 'goal' ? h.ref : h.goal)) SKY.fitGoal(h.kind === 'goal' ? h.ref : h.goal); else { const [wx, wy] = toWorld(px(e), py(e)); SKY.flyTo(wx, wy, S.cam.k * 2.2, 700); } });
|
|
75
|
+
cv.addEventListener('wheel', (e) => { e.preventDefault(); if (S.lens === 'simple') return; const { cam } = S; const f = Math.exp(-e.deltaY * 0.0016); const nk = clamp(cam.k * f, 0.015, 9); const [wx, wy] = toWorld(px(e), py(e)); cam.x = wx - (px(e) - S.W / 2) / nk; cam.y = wy - (py(e) - S.H / 2) / nk; cam.k = nk; S.flight = null; S.dirty = true; showCard(null); }, { passive: false });
|
|
76
|
+
// An Escape the sky USED (the tour, the menu, a pick) calls preventDefault, so
|
|
77
|
+
// the shell's full-screen switch leaves that press alone (task 1004327).
|
|
73
78
|
addEventListener('keydown', (e) => {
|
|
74
79
|
if (e.target && (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA')) { if (e.key === 'Escape') e.target.blur(); return; }
|
|
75
80
|
const { cam } = S; const step = 60 / cam.k;
|
|
76
81
|
if (e.key === 'ArrowLeft') { cam.x -= step; S.dirty = true; } else if (e.key === 'ArrowRight') { cam.x += step; S.dirty = true; } else if (e.key === 'ArrowUp') { cam.y -= step; S.dirty = true; } else if (e.key === 'ArrowDown') { cam.y += step; S.dirty = true; }
|
|
77
82
|
else if (e.key === '+' || e.key === '=') { cam.k = clamp(cam.k * 1.3, .015, 9); S.dirty = true; } else if (e.key === '-') { cam.k = clamp(cam.k / 1.3, .015, 9); S.dirty = true; }
|
|
78
|
-
else if (e.key === '0') SKY.fitAll(); else if (e.key === 'Escape') { if (!$('tour').hidden) SKY.endTour(); else if (!menu.hidden) hideMenu(); else pick(null); } else if (e.key === '/') { e.preventDefault(); $('thought').focus(); }
|
|
83
|
+
else if (e.key === '0') SKY.fitAll(); else if (e.key === 'Escape') { if (!$('tour').hidden) { e.preventDefault(); SKY.endTour(); } else if (!menu.hidden) { e.preventDefault(); hideMenu(); } else { if (S.picked || !$('panel').hidden) e.preventDefault(); pick(null); } } else if (e.key === '/') { e.preventDefault(); $('thought').focus(); }
|
|
79
84
|
else if (e.key === '?') SKY.startTour(); else if (e.key.toLowerCase() === 'l') SKY.toggleRoom(); else return;
|
|
80
85
|
});
|
|
81
86
|
function pick(h, fly) { if (h && h.kind === 'ltask') { SKY.renderPanel({ kind: 'ltask', ref: h.ref }); S.dirty = true; return; } S.picked = h; SKY.renderPanel(S.picked); SKY.renderRoom(); S.dirty = true; if (fly && S.picked && S.lens !== 'simple') { if (S.picked.kind === 'goal') SKY.fitGoal(S.picked.ref); else if (S.picked.kind === 'idea') SKY.fitThought(S.picked.ref); } }
|
|
@@ -60,8 +60,13 @@
|
|
|
60
60
|
|
|
61
61
|
// ---------------------------------------------------------------- the camera
|
|
62
62
|
const cv = $('sky'); const cam = S.cam;
|
|
63
|
-
|
|
63
|
+
// The canvas fills the sky's box (SKY.viewport: the hall's stage, or the
|
|
64
|
+
// window on /goal-map), and S.OX/S.OY keep where that box sits so a pointer's
|
|
65
|
+
// client coordinates land on the canvas (task 1004327). The stage can change
|
|
66
|
+
// size with no window resize — the full-screen switch — so it is observed too.
|
|
67
|
+
function resize() { const vp = SKY.viewport(); S.OX = vp.x; S.OY = vp.y; S.DPR = Math.min(2, devicePixelRatio || 1); S.W = vp.w; S.H = vp.h; cv.width = Math.round(S.W * S.DPR); cv.height = Math.round(S.H * S.DPR); cv.style.width = S.W + 'px'; cv.style.height = S.H + 'px'; S.dirty = true; }
|
|
64
68
|
addEventListener('resize', resize);
|
|
69
|
+
{ const st = document.querySelector('.sky-stage'); if (st && typeof ResizeObserver === 'function') new ResizeObserver(resize).observe(st); }
|
|
65
70
|
const toScreen = (x, y) => [(x - cam.x) * cam.k + S.W / 2, (y - cam.y) * cam.k + S.H / 2];
|
|
66
71
|
const toWorld = (sx, sy) => [(sx - S.W / 2) / cam.k + cam.x, (sy - S.H / 2) / cam.k + cam.y];
|
|
67
72
|
function flyTo(x, y, k, dur) { if (reduce) { cam.x = x; cam.y = y; cam.k = k; S.dirty = true; return; } S.flight = { x0: cam.x, y0: cam.y, k0: cam.k, x, y, k, t0: performance.now(), ms: dur || 900 }; }
|
|
@@ -15,7 +15,10 @@
|
|
|
15
15
|
<link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
|
|
16
16
|
<link rel="stylesheet" href="/builders/studio.css">
|
|
17
17
|
</head>
|
|
18
|
-
|
|
18
|
+
<!-- data-fullscreen-switch opts into the shell's full-screen switch (task
|
|
19
|
+
1004327): the studio in the hall chrome by default, and one button in the top
|
|
20
|
+
bar that hides it so the room fills the window, remembered for this page. -->
|
|
21
|
+
<body data-page="studio" data-page-title="Studio" data-fullscreen-switch>
|
|
19
22
|
|
|
20
23
|
<div class="app">
|
|
21
24
|
<aside class="app-sidebar" id="app-sidebar" aria-label="Primary"></aside>
|
|
@@ -32,11 +35,14 @@
|
|
|
32
35
|
<main id="hall-main" class="studio">
|
|
33
36
|
<div class="studio-atmos" aria-hidden="true"></div>
|
|
34
37
|
|
|
35
|
-
<header
|
|
38
|
+
<!-- A <div>, not a <header>: the shell's top bar is the page's one
|
|
39
|
+
<header> (the kit's one-header-main-h1 floor), and in full screen it
|
|
40
|
+
stays in the document as the way back (task 1004327). -->
|
|
41
|
+
<div class="studio-head">
|
|
36
42
|
<p class="studio-eyebrow">artist mode</p>
|
|
37
43
|
<h1 class="studio-greet" id="studio-greet">The studio</h1>
|
|
38
44
|
<p class="studio-sub" id="studio-sub">A quiet place to tend the words and art the project shows people.</p>
|
|
39
|
-
</
|
|
45
|
+
</div>
|
|
40
46
|
|
|
41
47
|
<!-- The one thing to tend now. Rendered by studio.js; the markup here is
|
|
42
48
|
the loading state (and the no-JS fallback), never an empty panel. -->
|
|
@@ -66,7 +72,7 @@
|
|
|
66
72
|
|
|
67
73
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
68
74
|
|
|
69
|
-
<script src="/builders/shell.js?v=2026-09-
|
|
75
|
+
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
70
76
|
<script src="/builders/palette.js" defer></script>
|
|
71
77
|
<script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
|
|
72
78
|
<!-- The kit, for its ONE renderer: the full-size ship-time visual figure
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"/api/(gds|bongos)/me$",
|
|
11
11
|
"/api/(gds|bongos)/me/",
|
|
12
12
|
"/api/(gds|bongos)/tasks",
|
|
13
|
-
"/api/(gds|bongos)/copy-desk/"
|
|
13
|
+
"/api/(gds|bongos)/copy-desk/",
|
|
14
|
+
"/api/(gds|bongos)/core-update"
|
|
14
15
|
],
|
|
15
16
|
"ignoreConsole": [
|
|
16
17
|
"/api/(gds|bongos)/",
|
|
@@ -40,6 +41,80 @@
|
|
|
40
41
|
},
|
|
41
42
|
"out": {
|
|
42
43
|
"auth": false
|
|
44
|
+
},
|
|
45
|
+
"full": {
|
|
46
|
+
"auth": true,
|
|
47
|
+
"_": "Full screen (task 1004327): the shell switch pressed — the room fills the window, one button brings the chrome back.",
|
|
48
|
+
"actions": [
|
|
49
|
+
[
|
|
50
|
+
"wait",
|
|
51
|
+
700
|
|
52
|
+
],
|
|
53
|
+
[
|
|
54
|
+
"click",
|
|
55
|
+
"#fullscreen-toggle"
|
|
56
|
+
],
|
|
57
|
+
[
|
|
58
|
+
"wait",
|
|
59
|
+
300
|
|
60
|
+
]
|
|
61
|
+
],
|
|
62
|
+
"expect": {
|
|
63
|
+
"visible": [
|
|
64
|
+
"#studio-focus",
|
|
65
|
+
"#fullscreen-toggle"
|
|
66
|
+
],
|
|
67
|
+
"hidden": [
|
|
68
|
+
"#app-sidebar",
|
|
69
|
+
"#topbar-title"
|
|
70
|
+
],
|
|
71
|
+
"attr": [
|
|
72
|
+
[
|
|
73
|
+
"#fullscreen-toggle",
|
|
74
|
+
"aria-pressed",
|
|
75
|
+
"true"
|
|
76
|
+
]
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"full-back": {
|
|
81
|
+
"auth": true,
|
|
82
|
+
"_": "Escape leaves full screen.",
|
|
83
|
+
"actions": [
|
|
84
|
+
[
|
|
85
|
+
"wait",
|
|
86
|
+
700
|
|
87
|
+
],
|
|
88
|
+
[
|
|
89
|
+
"click",
|
|
90
|
+
"#fullscreen-toggle"
|
|
91
|
+
],
|
|
92
|
+
[
|
|
93
|
+
"wait",
|
|
94
|
+
300
|
|
95
|
+
],
|
|
96
|
+
[
|
|
97
|
+
"press",
|
|
98
|
+
"Escape"
|
|
99
|
+
],
|
|
100
|
+
[
|
|
101
|
+
"wait",
|
|
102
|
+
300
|
|
103
|
+
]
|
|
104
|
+
],
|
|
105
|
+
"expect": {
|
|
106
|
+
"visible": [
|
|
107
|
+
"#app-sidebar",
|
|
108
|
+
"#topbar-title"
|
|
109
|
+
],
|
|
110
|
+
"attr": [
|
|
111
|
+
[
|
|
112
|
+
"#fullscreen-toggle",
|
|
113
|
+
"aria-pressed",
|
|
114
|
+
"false"
|
|
115
|
+
]
|
|
116
|
+
]
|
|
117
|
+
}
|
|
43
118
|
}
|
|
44
119
|
},
|
|
45
120
|
"reducedMotion": {
|