aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/messages.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/features/messages.js')
-rw-r--r--src/features/messages.js18
1 files changed, 17 insertions, 1 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index d6eacc9..0aa7291 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -1592,9 +1592,25 @@ export function messagesFeature(ctx) {
node.classList.add('clickable');
node.addEventListener('click', (e) => { e.stopPropagation(); openProfile(pk); });
}
- return hook('wrapAvatar', pk, node) || node;
+ return hook('wrapAvatar', pk, node) || hatStamp(pk, node) || node;
};
+ // The hats feature is a deferred chunk — until it lands, replay last
+ // session's boot stamps (hat art + geometry it persisted) so a hat sits on
+ // the head from the FIRST frame instead of popping in a beat later. Once
+ // hatsReady answers, the stamps stand down: a null from wrapAvatar then
+ // genuinely means "bare head".
+ let _hatStamps = null;
+ function hatStamp(pk, node) {
+ if (hook('hatsReady')) return null;
+ if (_hatStamps === null) {
+ try { _hatStamps = JSON.parse(localStorage.getItem('hat-stamps') || '{}'); } catch { _hatStamps = {}; }
+ }
+ const s = _hatStamps[pk];
+ if (!s || !s.a) return null;
+ return h('span', { class: 'hat-wrap' }, node, h('span', { class: 'ava-hat', style: s.s, html: s.a }));
+ }
+
// ---- profiles: view + own kind-0 editor ---------------------------------
const fullProfiles = new Map(); // pk -> { raw kind0 content object, fetched_at }