aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/features/messages.js27
1 files changed, 26 insertions, 1 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index ca55334..94e8909 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -626,6 +626,11 @@ export function messagesFeature(ctx) {
// the unlock screen (ui.pubProf gates that surface) — nostr profiles are
// public data, and Back lands on the app's own front door.
if (urlProfile) {
+ // Claim the first paint synchronously: these are set before the boot
+ // render, so the visitor sees a profile shell from the first frame —
+ // never a flash of the front door while the registrar lookup runs.
+ ui.pubProf = true;
+ ui.pubProfPending = urlProfile;
(async () => {
await new Promise((r) => setTimeout(r, 0)); // never render mid-boot
let pk = parseNostrPubkey(urlProfile);
@@ -638,10 +643,22 @@ export function messagesFeature(ctx) {
.then((r) => r.json());
pk = (j.names || {})[name] || null;
} catch {}
+ // The username is real display material: seed the light cache (stale,
+ // t:0, so the kind 0 still gets fetched) and the page paints the name
+ // and fallback avatar art immediately instead of an npub prefix and
+ // an empty circle while the relays answer.
+ if (pk && /^[0-9a-f]{64}$/.test(pk)) {
+ warmProfiles();
+ if (!profiles.has(pk)) profiles.set(pk, { name, t: 0 });
+ }
}
+ ui.pubProfPending = null;
if (pk && /^[0-9a-f]{64}$/.test(pk)) {
- if (ui.screen !== 'wallet') ui.pubProf = true;
+ if (ui.screen === 'wallet') ui.pubProf = null; // wallet chrome owns it
openProfile(pk);
+ } else {
+ ui.pubProf = null; // unknown name: fall through to the front door
+ render();
}
})();
}
@@ -2374,6 +2391,14 @@ export function messagesFeature(ctx) {
if (ui.pubProf) {
if (ui.noteThread) return threadScreen();
if (ui.profilePk) return profileScreen();
+ // resolution in flight: the shell holds the layout with the name
+ // straight off the URL — no spinner, the empty beat reads calmer
+ if (ui.pubProfPending) return h('div', { class: 'col', style: 'gap:16px' },
+ ctx.brandHeader(false),
+ h('div', { class: 'card col', style: 'gap:12px' },
+ h('div', { class: 'row gap6', style: 'align-items:center' },
+ h('div', { class: 'chat-avatar profile-avatar fallback loading' }),
+ h('div', { class: 'chat-title' }, ui.pubProfPending))));
}
return null;
}