aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/messages.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-10-08 22:47:06 -0700
committerAdam Soltys <[email protected]>2026-10-08 22:47:06 -0700
commitc8158d13fcd0278a7525e762fccea2a1329f7768 (patch)
treef1e9f0a9399932ea138798342b44094a34a8b6d5 /src/features/messages.js
parent7cea4ccb253d9802d92ee93881ed545e38391870 (diff)
downloadcoinosv3-c8158d13fcd0278a7525e762fccea2a1329f7768.tar.gz
coinosv3-c8158d13fcd0278a7525e762fccea2a1329f7768.zip
Desktop layout: from 900px the bottom nav is a left rail (your profile first with a bigger face and name, Settings last) beside a 600px page column, and from 1220px the wallet (balance, Receive/Send, latest payments) rides in a right column; search is a full field in the header there. Floaters re-centred on the page column, open chats still fill the window, phones unchanged
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/features/messages.js')
-rw-r--r--src/features/messages.js35
1 files changed, 28 insertions, 7 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index 759b155..b80c87b 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -10130,8 +10130,9 @@ export function messagesFeature(ctx) {
}
function appBottomNav() {
const visitor = isVisitor();
- const active = ui.noteThread || ui.profilePk ? 'feed' : ui.chatOpen
- ? ui.msgView === 'feed' ? 'feed' : ui.msgView === 'notifs' ? 'notifs' : 'messages' : 'wallet';
+ const me = !visitor && ctx.shownPubkey ? ctx.shownPubkey() : null;
+ const active = ui.userSearch ? 'search' : me && ui.profilePk === me && !ui.noteThread ? 'profile' : ui.noteThread || ui.profilePk ? 'feed' : ui.chatOpen
+ ? ui.msgView === 'feed' ? 'feed' : ui.msgView === 'notifs' ? 'notifs' : 'messages' : ui.tab === 'settings' ? 'settings' : 'wallet';
const leavePage = () => {
stopFeedWatch(); stopNotifWatch();
// Top-level destinations must leave any feature page covering the shell.
@@ -10149,8 +10150,8 @@ export function messagesFeature(ctx) {
return notifUnread();
};
const icon = (paths) => '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' + paths + '</svg>';
- const button = (id, label, paths, onClick) => h('button', {
- type: 'button', class: 'app-nav-button' + (!visitor && (id === 'messages' ? hook('unreadMessages') : id === 'notifs' && notifsWaiting()) ? ' unread' : ''),
+ const button = (id, label, paths, onClick, cls = '') => h('button', {
+ type: 'button', class: 'app-nav-button' + cls + (!visitor && (id === 'messages' ? hook('unreadMessages') : id === 'notifs' && notifsWaiting()) ? ' unread' : ''),
'aria-label': label, 'aria-current': active === id ? 'page' : undefined,
onClick: (e) => {
// An open composer doesn't follow you around: back on the feed it sat
@@ -10160,9 +10161,17 @@ export function messagesFeature(ctx) {
onClick(e);
},
}, h('span', { html: icon(paths) }), h('span', {}, label));
+ // Your profile heads the desktop rail: a bigger face and your name, where
+ // the header's avatar sits on a phone.
+ const profileItem = me ? h('button', {
+ type: 'button', class: 'app-nav-button app-nav-wide app-nav-profile',
+ 'aria-label': t('profYourProfile'), 'aria-current': active === 'profile' ? 'page' : undefined,
+ onClick: () => { ui.profCompose = null; leavePage(); openProfile(me); render(); window.scrollTo({ top: 0 }); },
+ }, avatar(me, 'chat-avatar app-nav-ava', false), h('span', { class: 'app-nav-name' }, displayName(me))) : null;
return h('nav', {
class: 'app-bottom-nav', 'data-key': 'app-bottom-nav',
},
+ profileItem,
button('feed', t('feedTitle'), '<path d="M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-2 2m0 0a2 2 0 0 1-2-2v-9c0-1.1.9-2 2-2h2"/><path d="M18 14h-8M15 18h-5M10 6h8v4h-8z"/>', () => {
// A destination tab is a destination: tapping Feed while already
// there always returns to its top. Only the explicit "x new posts"
@@ -10191,7 +10200,13 @@ export function messagesFeature(ctx) {
ui.txDetail = null; ui.arkMoveDetail = null; ui.arkReconDetail = null; ui.arkExitDetail = null; ui.giftDetail = null;
ui.chatOpen = false; ui.msgView = null; ui.tab = 'receive';
render(); window.scrollTo({ top: 0 });
- }));
+ }),
+ // Settings joins the nav where it's the desktop rail (the header's own
+ // gear steps aside there); a phone's bar keeps four.
+ ctx.openSettingsPage ? button('settings', t('tabSettings'), '<circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33h.09a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82v.09a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>', () => {
+ if (visitor) { toFrontDoor(); return; }
+ leavePage(); ctx.openSettingsPage(null);
+ }, ' app-nav-wide') : null);
}
// ---- media views: a feed's pictures as a grid, its videos to flip through --
// All / Images / Videos sits under the feed chips. Images lays the feed's
@@ -11322,9 +11337,9 @@ export function messagesFeature(ctx) {
return h('div', { class: 'col', style: 'gap:16px' },
ctx.brandHeader(!ui.pubProf && wallet.loaded),
h('div', { class: 'card col', style: 'gap:10px' },
- h('h3', { style: 'margin:0' }, t('searchUsers')),
+ h('h3', { class: 'user-search-main', style: 'margin:0' }, t('searchUsers')),
h('input', {
- type: 'text', class: 'user-search-input', placeholder: t('searchUsersHint'), value: s.q,
+ type: 'text', class: 'user-search-input user-search-main', placeholder: t('searchUsersHint'), value: s.q,
autocapitalize: 'none', autocomplete: 'off', spellcheck: 'false',
onInput: (e) => { s.q = e.target.value; userSearcher.update(s.q); },
}),
@@ -13049,6 +13064,12 @@ export function messagesFeature(ctx) {
},
// The header magnifier: search anyone on nostr, results open profiles.
userSearchAvailable() { return true; },
+ // the desktop header's search field: typing there IS the search page's query
+ userSearchQuery(q) {
+ if (!ui.userSearch) { if (!isVisitor()) ui.chatOpen = false; ui.profilePk = null; ui.noteThread = null; ui.userSearch = { q: '', rows: null }; warmSearch(); }
+ ui.userSearch.q = q; userSearcher.update(q); render();
+ return true;
+ },
openUserSearch() {
if (!isVisitor()) ui.chatOpen = false; // a visitor's feed stays underneath, for Back
ui.profilePk = null;