From 5075e9f4c585138cddfe7e7962170dbd2e73874a Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sun, 2 Aug 2026 19:57:22 -0700 Subject: Header: wallet + avatar only; the avatar opens an identity menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The chat button leaves the header — the avatar's popup menu carries Edit profile, Settings, Messages, and Logout (lock()). The menu is available inside the chat takeover too, which now keeps the full header. Messages provides just the avatar node via the headerAvatar seam; the app owns the menu. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi --- src/app.js | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) (limited to 'src/app.js') diff --git a/src/app.js b/src/app.js index 3a19573..4ae1912 100644 --- a/src/app.js +++ b/src/app.js @@ -1340,6 +1340,30 @@ function lock() { } // ================================================================ WALLET +// The avatar anchors the identity menu: Edit profile, Settings, Messages, +// Logout. The avatar node itself comes from the messages feature (profile +// cache + punk fallback); without that feature there's no menu. +function avatarMenu() { + const me = (featureHook('nostrLoginIdentity') || {}).pubkey || (wallet.nostrPubkey && wallet.nostrPubkey()); + const node = me && featureHook('headerAvatar', me); + if (!node) return null; + const item = (label, fn) => h('button', { + class: 'icon-select-item', + onClick: () => { ui.avatarMenu = false; fn(); render(); }, + }, label); + return h('span', { class: 'avatar-menu-wrap' }, + h('button', { class: 'header-avatar', onClick: () => { ui.avatarMenu = !ui.avatarMenu; render(); } }, node), + ui.avatarMenu + ? h('span', {}, + h('div', { class: 'menu-backdrop', onClick: () => { ui.avatarMenu = false; render(); } }), + h('div', { class: 'icon-select-menu avatar-menu' }, + item(t('profEdit'), () => featureHook('showProfile', me)), + item(t('tabSettings'), () => { ui.chatOpen = false; ui.profilePk = null; ui.screen = 'wallet'; ui.tab = 'settings'; ui.settingsPage = null; }), + item(t('msgDmsTitle'), () => { ui.profilePk = null; ui.chatOpen = true; }), + item(t('logout'), () => lock()))) + : null); +} + function brandHeader(withLock) { const acc = activeAccount(); return h( @@ -1351,11 +1375,10 @@ function brandHeader(withLock) { h('div', { class: 'logo-full', 'aria-label': 'coinos', role: 'img', html: '' }) ), withLock - ? h('div', { class: 'row gap6' }, - ...featureAll('headerButtons'), + ? h('div', { class: 'row gap6', style: 'align-items:center' }, h('button', { class: 'btn-sm', onClick: () => { ui.screen = 'accounts'; render(); } }, acc ? acc.label : t('accounts')), - featureHook('headerAvatar')) + avatarMenu()) : null ); } -- cgit v1.2.3