diff options
| author | Adam Soltys <[email protected]> | 2026-10-04 23:40:47 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-10-04 23:40:47 -0700 |
| commit | 1a2a31365a09a9a5cbd4a43fac6481f3c2f57d72 (patch) | |
| tree | 01b86f5c3909c1ae524caec659b0c01094d3cdca /src/features | |
| parent | f1b0aeb9b3ee2b82808ad5a50e53fcc53f4e820b (diff) | |
| download | coinosv3-1a2a31365a09a9a5cbd4a43fac6481f3c2f57d72.tar.gz coinosv3-1a2a31365a09a9a5cbd4a43fac6481f3c2f57d72.zip | |
Show popular Concord communities on the Messages screen
Diffstat (limited to 'src/features')
| -rw-r--r-- | src/features/messages.js | 42 |
1 files changed, 28 insertions, 14 deletions
diff --git a/src/features/messages.js b/src/features/messages.js index 0a0a536..a9b21b0 100644 --- a/src/features/messages.js +++ b/src/features/messages.js @@ -1858,13 +1858,13 @@ export function messagesFeature(ctx) { } // ---- community discovery: the Vector Hub's public listing as suggestions - // under Join. Fetched on demand (it's a megabyte, mostly icons) and kept + // on Messages and under Browse. Fetched when Messages opens and kept // for the session; every listing is a CORD-05 link, which is exactly what // the paste box takes, so a tap previews it like a pasted invite. const HUB_URL = 'https://vectorapp.io/api/hub'; const hub = { state: 'idle', list: [] }; async function loadHub() { - if (hub.state === 'loading' || hub.state === 'ready') return; + if (hub.state !== 'idle') return; hub.state = 'loading'; scheduleRepaint(); try { const res = await fetch(HUB_URL, { signal: AbortSignal.timeout(20_000) }); @@ -1882,12 +1882,16 @@ export function messagesFeature(ctx) { } catch { hub.state = 'error'; } scheduleRepaint(); } - function hubRows() { - const q = (ui.msgJoinText || '').trim().toLowerCase(); + function hubRows({ preview = false } = {}) { + const q = preview ? '' : (ui.msgJoinText || '').trim().toLowerCase(); const have = new Set(communities().map((jm) => (rooms.get(jm.community_id)?.folded?.metadata?.name || jm.name || '').toLowerCase())); - const rows = hub.list.filter((c) => !q || [c.name, c.description, c.category].some((x) => x.toLowerCase().includes(q))); + let rows = hub.list.filter((c) => !q || [c.name, c.description, c.category].some((x) => x.toLowerCase().includes(q))); + if (preview) rows = rows.filter((c) => !have.has(c.name.toLowerCase())).slice(0, 6); + if (!rows.length) return [h('div', { class: 'small muted' }, t(preview ? 'msgHubNoSuggestions' : 'msgNoMatches'))]; return rows.map((c) => h('div', { - class: 'item chat-thread-row clickable', onClick: () => joinFromText(c.invite), + class: 'item chat-thread-row clickable', role: 'button', tabindex: '0', + onClick: (e) => { e.stopPropagation(); joinFromText(c.invite); }, + onKeydown: (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); joinFromText(c.invite); } }, }, c.icon ? h('img', { class: 'chat-avatar hub-icon', src: c.icon, alt: '' }) : h('div', { class: 'chat-avatar fallback' }, c.name.slice(0, 2)), h('div', { class: 'col grow', style: 'min-width:0;gap:1px' }, @@ -1898,6 +1902,21 @@ export function messagesFeature(ctx) { (c.members ? t('msgMembers', { n: c.members }) + ' · ' : '') + c.category + (c.description ? ' · ' + c.description : ''))))); } + function hubPanel({ preview = false } = {}) { + loadHub().catch(() => {}); + return h('div', { class: 'col community-discovery', style: 'gap:8px' }, + h('div', { class: 'row between', style: 'align-items:baseline' }, + h('h3', { style: 'margin:0' }, t(preview ? 'msgPopularCommunities' : 'msgDiscoverTitle')), + preview ? h('button', { class: 'btn-sm', onClick: (e) => { e.stopPropagation(); ui.msgJoinText = ''; ui.msgHomePanel = 'join'; render(); } }, t('msgBrowseCommunities')) : null), + h('a', { class: 'small muted', href: 'https://vectorapp.io/hub/', target: '_blank', rel: 'noopener noreferrer' }, t('msgHubCredit')), + hub.state === 'error' ? h('div', { class: 'row gap6', style: 'align-items:center' }, + h('span', { class: 'small muted grow' }, t('msgHubFailed')), + h('button', { class: 'btn-sm', onClick: (e) => { e.stopPropagation(); hub.state = 'idle'; loadHub().catch(() => {}); } }, t('retry'))) + : hub.state !== 'ready' ? h('div', { class: 'row gap6', style: 'align-items:center;padding:6px 0' }, h('span', { class: 'spinner sm' }), h('span', { class: 'small muted' }, t('msgHubLoading'))) + : h('div', { class: 'list' + (preview ? '' : ' hub-list') }, hubRows({ preview })), + h('div', { class: 'small muted' }, t('msgWhiteNoiseDiscovery'))); + } + function joinFromText(text) { const parsed = parseInviteLink(text); if (!parsed) { toast(t('msgBadInvite')); return; } @@ -11091,7 +11110,6 @@ export function messagesFeature(ctx) { h('button', { class: 'btn-sm', onClick: () => { ui.msgHomePanel = ui.msgHomePanel === 'create' ? null : 'create'; render(); } }, t('msgCreate'))))); if (pendingLink && pendingLink.where === 'communities') kids.push(linkInviteCard()); if (ui.msgHomePanel === 'join') { - loadHub().catch(() => {}); const isLink = !!parseInviteLink(ui.msgJoinText || ''); kids.push(h('div', { class: 'col', style: 'gap:8px' }, h('div', { class: 'row gap6' }, @@ -11101,13 +11119,7 @@ export function messagesFeature(ctx) { onKeydown: (e) => { if (e.key === 'Enter' && isLink) joinFromText(ui.msgJoinText); }, }), isLink ? h('button', { class: 'btn-sm btn-primary', onClick: () => joinFromText(ui.msgJoinText) }, t('msgJoin')) : null), - isLink ? null : h('div', { class: 'row between', style: 'align-items:baseline' }, - h('span', { class: 'small muted' }, t('msgDiscoverTitle')), - h('a', { class: 'small muted', href: 'https://vectorapp.io/hub/', target: '_blank', rel: 'noopener noreferrer' }, t('msgHubCredit'))), - isLink ? null - : hub.state === 'error' ? h('div', { class: 'small muted' }, t('msgHubFailed')) - : hub.state !== 'ready' ? h('div', { class: 'row gap6', style: 'align-items:center;padding:6px 0' }, h('span', { class: 'spinner sm' }), h('span', { class: 'small muted' }, t('msgHubLoading'))) - : h('div', { class: 'list hub-list' }, hubRows()))); + isLink ? null : hubPanel())); } if (ui.msgHomePanel === 'create') kids.push(h('div', { class: 'row gap6' }, @@ -11154,6 +11166,8 @@ export function messagesFeature(ctx) { kids.push(h('button', { class: 'linklike small', onClick: () => { ui.msgAllRooms = false; render(); } }, t('msgShowFewerDms'))); + if (ui.msgHomePanel !== 'join') kids.push(hubPanel({ preview: true })); + return h('div', { class: 'card col chat-page', style: 'gap:10px' }, ...kids); } |
