@bongos/core 1.24.32 → 1.24.33

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.
@@ -216,20 +216,29 @@
216
216
  // under the brand (artHtml, the picker's own art, so the two never drift).
217
217
  // Building and no mode have no entry here and wear nothing.
218
218
  var LOOKS = { artistry: 'the studio · night', ideating: 'the sky', governing: 'the city' };
219
+ // The plate is the Home button in every mode (owner, 2026-11-04, task 1005065): the
220
+ // mode's scene with a home mark over it. Building wears no look, so its plate shows
221
+ // the city, the scene its Home is.
222
+ var PLATE_ART = { building: 'governing', artistry: 'artistry', ideating: 'ideating', governing: 'governing' };
223
+ var HOME_MARK = '<span class="craft-plate__home" aria-hidden="true"><svg viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round">' +
224
+ '<path d="M3 8.5 9 3l6 5.5V15a1 1 0 0 1-1 1h-3.5v-4h-3v4H4a1 1 0 0 1-1-1V8.5Z"/></svg></span>';
219
225
  function remove(el) { if (el && el.parentNode) el.parentNode.removeChild(el); }
220
226
  function applyLook(mode) {
221
227
  var look = Object.prototype.hasOwnProperty.call(LOOKS, mode) ? LOOKS[mode] : null;
228
+ var art = Object.prototype.hasOwnProperty.call(PLATE_ART, mode) ? PLATE_ART[mode] : null;
222
229
  var plate = document.getElementById('craft-plate');
223
- if (plate && plate.getAttribute('data-plate') !== (look ? mode : null)) { remove(plate); plate = null; }
230
+ if (plate && plate.getAttribute('data-plate') !== (art ? mode : null)) { remove(plate); plate = null; }
224
231
  var nav = document.getElementById('app-sidebar');
225
- var brand = look && nav && nav.querySelector ? nav.querySelector('.app-sidebar__brand') : null;
232
+ var brand = art && nav && nav.querySelector ? nav.querySelector('.app-sidebar__brand') : null;
226
233
  if (!plate && brand && brand.parentNode) {
227
- plate = document.createElement('div');
234
+ plate = document.createElement('a');
228
235
  plate.id = 'craft-plate';
229
236
  plate.className = 'craft-plate';
237
+ plate.setAttribute('href', '/');
238
+ plate.setAttribute('aria-label', 'Home');
239
+ plate.setAttribute('title', 'Home');
230
240
  plate.setAttribute('data-plate', mode);
231
- plate.setAttribute('aria-hidden', 'true');
232
- plate.innerHTML = artHtml(mode);
241
+ plate.innerHTML = artHtml(art) + HOME_MARK;
233
242
  brand.parentNode.insertBefore(plate, brand.nextSibling);
234
243
  }
235
244
  var mark = document.getElementById('craft-eyebrow');
@@ -1614,6 +1614,9 @@ html:is([data-craft="artistry"], [data-craft="ideating"], [data-craft="governing
1614
1614
  never redrawn: each scene's pieces are placed from its edges or its centre. */
1615
1615
  .craft-plate {
1616
1616
  position: relative;
1617
+ display: block;
1618
+ color: inherit;
1619
+ text-decoration: none;
1617
1620
  height: 40px;
1618
1621
  margin: 10px 8px 0;
1619
1622
  border-radius: var(--radius-sm);
@@ -1631,6 +1634,26 @@ html:is([data-craft="artistry"], [data-craft="ideating"], [data-craft="governing
1631
1634
  transform-origin: 0 0;
1632
1635
  }
1633
1636
  .craft-plate .craft-art__city { top: 0; }
1637
+ /* At the plate's size the studio's houses vanished into the night (owner, 2026-11-04):
1638
+ lift them off the sky so the scene reads. The picker's larger door is unchanged. */
1639
+ .craft-plate .craft-art__house { background: #232b4d; }
1640
+ /* The plate is the Home button (task 1005065): a home mark sits over the scene. */
1641
+ .craft-plate__home {
1642
+ position: absolute;
1643
+ left: 50%;
1644
+ top: 50%;
1645
+ width: 24px;
1646
+ height: 24px;
1647
+ margin: -12px 0 0 -12px;
1648
+ display: grid;
1649
+ place-items: center;
1650
+ border-radius: 999px;
1651
+ color: #fff;
1652
+ background: var(--scrim);
1653
+ }
1654
+ .craft-plate__home svg { width: 14px; height: 14px; }
1655
+ .craft-plate:hover .craft-plate__home { background: rgba(0, 0, 0, .8); }
1656
+ .craft-plate:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
1634
1657
  .app-sidebar:hover .craft-plate,
1635
1658
  .app-sidebar:focus-within .craft-plate { height: 64px; margin: 10px 16px 0; }
1636
1659
  .app-sidebar:hover .craft-plate .craft-art,
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.24.32",
3
+ "version": "1.24.33",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.24.32",
9
+ "version": "1.24.33",
10
10
  "license": "AGPL-3.0-or-later",
11
11
  "dependencies": {
12
12
  "express": "^4.21.2",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.24.32",
3
+ "version": "1.24.33",
4
4
  "description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "main": "src/platform-server.js",
@@ -11151,5 +11151,11 @@
11151
11151
  "id": "1005064",
11152
11152
  "text": "The governor's Home is now the street: choosing Owner on Home takes you straight to it, so each of the four crafts has its own Home."
11153
11153
  }
11154
+ ],
11155
+ "1.24.33": [
11156
+ {
11157
+ "id": "1005065",
11158
+ "text": "The small picture at the top of the sidebar is now the Home button in every mode, with a home icon on it."
11159
+ }
11154
11160
  ]
11155
11161
  }
package/src/module-api.js CHANGED
@@ -81,7 +81,7 @@ const { sleep } = require('./sleep');
81
81
  // MAJOR (see allowBoxScope below): passes the request through untouched.
82
82
  function deprecatedNoopMiddleware(_req, _res, next) { next(); }
83
83
 
84
- const CORE_VERSION = '1.24.32'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
84
+ const CORE_VERSION = '1.24.33'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
85
85
 
86
86
  // A namespaced logger so a module's log lines are attributable + consistent.
87
87
  // Usage: const log = api.logger('discord'); log.info('mounted');
@@ -86,25 +86,33 @@ test('each looked mode frames its own door scene under the brand, and names itse
86
86
  const plate = p.plates()[0];
87
87
  assert.equal(p.brand.nextSibling, plate, `${m}: the plate sits right under the brand`);
88
88
  assert.equal(plate.getAttribute('data-plate'), m);
89
- assert.equal(plate.getAttribute('aria-hidden'), 'true', 'the plate is decoration');
90
- assert.equal(plate.innerHTML, p.craft.artHtml(m), `${m}: the plate IS the picker's door art, not a second copy`);
89
+ assert.equal(plate.tagName, 'A', `${m}: the plate is a link`);
90
+ assert.equal(plate.getAttribute('href'), '/', `${m}: the plate goes Home`);
91
+ assert.equal(plate.getAttribute('aria-label'), 'Home', `${m}: named Home for a screen reader`);
92
+ assert.ok(plate.innerHTML.startsWith(p.craft.artHtml(m)), `${m}: the plate IS the picker's door art, not a second copy`);
93
+ assert.match(plate.innerHTML, /class="craft-plate__home" aria-hidden="true"/, `${m}: a home mark sits over the scene`);
91
94
  assert.equal(p.marks().length, 1, `${m}: exactly one eyebrow`);
92
95
  assert.equal(p.title.nextSibling, p.marks()[0], `${m}: the eyebrow sits right after the page title`);
93
96
  assert.equal(p.marks()[0].textContent, WORDS[m], `${m}: in the prototype's own words`);
94
97
  }
95
98
  });
96
99
 
97
- test('BUILDING AND NO MODE WEAR NO LOOK: no plate, no eyebrow, and switching to them takes the look away', () => {
100
+ test('BUILDING AND NO MODE WEAR NO LOOK: no eyebrow; Building keeps only the Home plate, showing the city', () => {
98
101
  const none = boot();
99
102
  assert.equal(none.root.dataset.craft, undefined);
100
103
  assert.equal(none.plates().length + none.marks().length, 0, 'no mode draws nothing');
101
104
  for (const m of ['building']) {
102
105
  const p = boot({ 'hall-craft': m });
103
- assert.equal(p.plates().length + p.marks().length, 0, `${m} at boot draws nothing`);
106
+ assert.equal(p.marks().length, 0, `${m} at boot names no look`);
107
+ assert.equal(p.plates().length, 1, `${m}: the Home plate is there too (task 1005065)`);
108
+ assert.equal(p.plates()[0].getAttribute('data-plate'), m);
109
+ assert.ok(p.plates()[0].innerHTML.startsWith(p.craft.artHtml('governing')), `${m}: its plate shows the city`);
104
110
  p.craft.choose('governing');
105
111
  assert.equal(p.plates().length, 1);
112
+ assert.equal(p.plates()[0].getAttribute('data-plate'), 'governing', 'switching mode swaps the plate');
106
113
  p.craft.choose(m);
107
- assert.equal(p.plates().length + p.marks().length, 0, `switching to ${m} removes the plate and the eyebrow`);
114
+ assert.equal(p.marks().length, 0, `switching to ${m} removes the eyebrow`);
115
+ assert.equal(p.plates()[0].getAttribute('data-plate'), m, 'and swaps the plate back');
108
116
  }
109
117
  assert.deepEqual(Object.keys(none.craft.LOOKS).sort(), [...LOOKED].sort(), 'only the three crafts have a look');
110
118
  });
@@ -112,7 +120,7 @@ test('BUILDING AND NO MODE WEAR NO LOOK: no plate, no eyebrow, and switching to
112
120
  test('the art is drawn once: craft-mode.js has one artHtml and exports it', () => {
113
121
  assert.equal(CRAFT.match(/function artHtml\(/g).length, 1);
114
122
  assert.match(CRAFT, /artHtml: artHtml,/);
115
- assert.match(CRAFT, /plate\.innerHTML = artHtml\(mode\);/);
123
+ assert.match(CRAFT, /plate\.innerHTML = artHtml\(art\) \+ HOME_MARK;/);
116
124
  });
117
125
 
118
126
  // Every selector in style.css that names a craft mode.
@@ -163,6 +171,8 @@ test('the shared treatment, the eyebrow and the plate are written as the directi
163
171
  }
164
172
  assert.match(CSS, /@media \(max-width: 640px\) \{ \.craft-eyebrow \{ display: none; \} \}/, 'the eyebrow is hidden on a phone');
165
173
  assert.match(CSS, /\.craft-plate \{[^}]*height: 40px;/, '40px in the closed rail');
174
+ assert.match(CSS, /\.craft-plate__home \{[^}]*width: 24px;[^}]*height: 24px;/, 'the home mark clears the 24px floor');
175
+ assert.match(CSS, /\.craft-plate:focus-visible \{ outline: 2px solid var\(--focus\);/, 'the Home plate shows keyboard focus');
166
176
  assert.match(CSS, /\.app-sidebar:focus-within \.craft-plate \{ height: 64px;/, '64px when the rail opens');
167
177
  assert.match(CSS, /html\[data-theme="light"\] \.craft-plate \.craft-art__city \{ filter: invert\(1\) hue-rotate\(180deg\); \}/,
168
178
  'the light city is the dark one inverted, not a second drawing');