diff --git a/client/src/entry.jsx b/client/src/entry.jsx index 3a8d55f..3b78cf0 100644 --- a/client/src/entry.jsx +++ b/client/src/entry.jsx @@ -18,7 +18,7 @@ // size and it is the one thing this seam cannot have. import { registry, coreApiVersion } from './core.js' -import { IconShard } from './icons.jsx' +import { IconShard, IconUser } from './icons.jsx' import { useShardFlags } from './lib/useShardFeatures.js' // Public pages — the twelve that used to live at /site/*. @@ -159,7 +159,7 @@ registry.registerNav(ID, { area: 'player', // Order 0: Characters is the portal's first row today, and with the module // installed it is also what core's `/player` index resolves to. - items: [{ label: 'Characters', to: '/player/uo/characters', order: 0 }], + items: [{ label: 'Characters', to: '/player/uo/characters', icon: IconUser, order: 0 }], }) // ── Feature provider ─────────────────────────────────────────────────────── diff --git a/client/src/icons.jsx b/client/src/icons.jsx index 76242eb..f833945 100644 --- a/client/src/icons.jsx +++ b/client/src/icons.jsx @@ -35,4 +35,32 @@ export const IconShard = () => ( ) +/** + * A figure — the glyph core used for the portal's "Characters" row. + * + * A second icon rather than reusing IconShard, because these two rows sit in + * different navs and each matched its neighbours before the extraction: the + * admin sidebar's UO rows were all gems, and the portal's Characters row was a + * person beside Appeals' shield and Account's gear. Copied from core's + * PlayerPortalLayout, which uses a 16px frame and a heavier stroke than the + * admin one — matching the nav a row lands in is the whole reason `icon` exists. + */ +export const IconUser = () => ( + +) + export default IconShard diff --git a/client/test/registration.test.js b/client/test/registration.test.js index 0a640ad..24e536f 100644 --- a/client/test/registration.test.js +++ b/client/test/registration.test.js @@ -139,9 +139,21 @@ it('every nav row points at a route this module actually registered', () => { } }) -it('admin nav rows carry an icon; core rows all have one and a text-only row reads as breakage', () => { - for (const row of registered.nav.admin) { - assert.equal(typeof row.icon, 'function', `admin nav row "${row.label}" has no icon`) +it('every admin and player nav row carries an icon', () => { + // Both of those navs render a glyph on every core row, so a row without one + // reads as breakage rather than as a design. The PUBLIC header is text + // buttons and is deliberately excluded. + // + // The player half of this assertion is not symmetry for its own sake. Core's + // PlayerPortalLayout rendered `` UNGUARDED — fine for as long as + // every row in it was core's own and had one, and React error #130 with a + // blank portal the moment a module registered one without. Core is guarded + // now, but a missing icon there is still a visible defect and this is the + // cheap place to catch it. + for (const area of ['admin', 'player']) { + for (const row of registered.nav[area]) { + assert.equal(typeof row.icon, 'function', `${area} nav row "${row.label}" has no icon`) + } } })