aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-08-04 01:32:31 -0700
committerAdam Soltys <[email protected]>2026-08-04 01:32:31 -0700
commit8bfec51dd0eb8a4935ad62ce444f1d9d67c8105c (patch)
treecd431c67f4c26e3e5c53c75f05a03d15f57256c8
parentcdbdc9b509d14ba386e01ecb87a80e54ef28addb (diff)
downloadcoinosv3-8bfec51dd0eb8a4935ad62ce444f1d9d67c8105c.tar.gz
coinosv3-8bfec51dd0eb8a4935ad62ce444f1d9d67c8105c.zip
A quieter pen inside the address box; the header avatar stops flashing
The avatar img was recreated on every render — boot's render bursts made it flash; there is exactly one header avatar, so the node is reused until the profile actually changes. Co-Authored-By: Claude Fable 5 <[email protected]>
-rw-r--r--src/features/messages.js14
-rw-r--r--src/features/names.js10
-rw-r--r--src/style.css9
3 files changed, 27 insertions, 6 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index 8fbc27a..3854f26 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -1660,7 +1660,19 @@ export function messagesFeature(ctx) {
// Chat lives behind a header button and takes over the whole screen —
// no balance card, no tabs; each view carries its own way back.
// The bare avatar node for the app header's identity menu.
- headerAvatar(pk) { return avatar(pk, 'chat-avatar header-ava', false); },
+ // The header rebuilds every render; recreating the <img> each time makes
+ // the picture visibly flash during boot's render bursts. There is exactly
+ // one header avatar, so the node itself is reused until the profile
+ // (or account) actually changes.
+ headerAvatar(pk) {
+ const p = profileOf(pk);
+ const key = pk + '|' + (p === null ? 'loading' : p.picture || 'fb:' + (p.name || ''));
+ if (!this._headerAva || this._headerAvaKey !== key) {
+ this._headerAvaKey = key;
+ this._headerAva = avatar(pk, 'chat-avatar header-ava', false);
+ }
+ return this._headerAva;
+ },
// Conversations waiting on us, for the header's message button.
unreadMessages() { return unreadCount(); },
screenView() {
diff --git a/src/features/names.js b/src/features/names.js
index d944957..0de6f66 100644
--- a/src/features/names.js
+++ b/src/features/names.js
@@ -309,13 +309,13 @@ export function namesFeature(ctx) {
return h('div', { class: 'card col', style: 'align-items:center;gap:14px' },
seg,
h('div', { html: qrSvg(addr) }),
- h('div', { class: 'row gap6', style: 'width:100%;align-items:center' },
- h('div', { class: 'addr-box', style: 'flex:1;min-width:0;text-align:center;font-size:16px' }, addr),
- // the pencil is how you change the name — right where the name is
+ h('div', { class: 'addr-box addr-editable', style: 'width:100%;font-size:16px' },
+ addr,
+ // the pen is how you change the name — right where the name is
h('button', {
- class: 'btn-sm', title: t('namesCustom'),
+ class: 'addr-edit', title: t('namesCustom'),
onClick: () => { ui.nameEditOpen = !ui.nameEditOpen; ui.nameClaimError = null; render(); },
- html: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/></svg>',
+ html: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.376 3.622a1 1 0 0 1 3.002 3.002L7.368 18.635a2 2 0 0 1-.855.506l-2.872.838a.5.5 0 0 1-.62-.62l.838-2.872a2 2 0 0 1 .506-.854z"/></svg>',
})),
ui.nameEditOpen ? h('div', { class: 'col', style: 'gap:8px;width:100%' },
h('p', { class: 'small muted', style: 'margin:0' }, t('namesCustomHow')),
diff --git a/src/style.css b/src/style.css
index 89662c0..caef890 100644
--- a/src/style.css
+++ b/src/style.css
@@ -210,6 +210,15 @@ textarea { resize: vertical; min-height: 84px; font-family: var(--mono); font-si
font-family: var(--mono); font-size: 15px; color: var(--ink); background: var(--surface2); border: 1px dashed var(--line-strong);
border-radius: 11px; padding: 12px 14px; word-break: break-all; text-align: center;
}
+/* a quiet edit affordance living inside the address box */
+.addr-editable { position: relative; padding-right: 34px; }
+.addr-edit {
+ position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
+ background: none; border: none; box-shadow: none; padding: 6px; line-height: 0;
+ color: var(--muted); cursor: pointer;
+}
+.addr-edit:hover { color: var(--ink); background: none; }
+.addr-edit:active { transform: translateY(-50%); }
.path { font-family: var(--mono); font-size: 12px; color: var(--faint); }
.addr-check { font-family: var(--mono); font-size: 12px; line-height: 1.5; color: var(--muted); word-break: break-all; padding: 0 2px; }
.addr-check .hl { color: var(--ink); font-weight: 700; }