From 790c6fac78d678832634cedf8c0bd67c4d19e89b Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Mon, 31 Aug 2026 09:03:37 -0700 Subject: A hard hat for the crew that builds this with us: an operator-giftable construction hat joins the catalog (never listed for sale — like the crown it appears only in a rack that holds it), the registrar grows POST /hats/grant behind the admin token (hex or npub, crown excluded), and a gifted hat settles into the rack instead of knocking a paid hat off a bare-headed recipient wears it at once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr --- src/features/hats.js | 16 +++++++++++++--- src/i18n.js | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/features/hats.js b/src/features/hats.js index 11fe400..351ada5 100644 --- a/src/features/hats.js +++ b/src/features/hats.js @@ -80,6 +80,15 @@ const HATS = [ `), }, + { + // Not for sale: gifted by the operator to beta testers (see the + // registrar's /hats/grant). Appears in the shop only once owned. + id: 'construction', nameKey: 'hatConstruction', sat: null, w: 108, b: 71, r: -6, + art: svg(` + + + `), + }, { id: 'crown', nameKey: 'hatCrown', sat: null, w: 86, b: 83, r: -7, art: svg(` @@ -348,9 +357,10 @@ export function hatsFeature(ctx) { d == null ? h('div', { style: 'text-align:center;padding:16px' }, h('span', { class: 'spinner' })) : h('div', { class: 'col', style: 'gap:2px' }, - // the crown is not merchandise — it appears only in the - // collection of the head that owns it, never as a listing - ...HATS.filter((hat) => hat.id !== 'crown' || ((d && d.owned) || []).includes('crown')) + // unpriced hats (the crown, the beta hard hat) are not + // merchandise — they appear only in the collection of a head + // that owns them, never as a listing + ...HATS.filter((hat) => (priceOf(hat) || 0) > 0 || ((d && d.owned) || []).includes(hat.id)) .map((hat) => shopRow(hat, d, me))), d && d.offline ? h('div', { class: 'small faint', style: 'text-align:center' }, t('hatShopOffline')) : null), h('button', { class: 'btn-ghost btn-block', onClick: closeShop }, t('back'))); diff --git a/src/i18n.js b/src/i18n.js index 35a8cdb..f9f8567 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -275,6 +275,7 @@ const STR = { hatBowler: 'Bowler', hatWizard: 'Wizard hat', hatTop: 'Top hat', + hatConstruction: 'Hard hat', hatCrown: 'The Crown', hatCrownWho: "Adam's. Sorry.", hatCrownTaken: 'not for sale', -- cgit v1.2.3