diff options
| author | Adam Soltys <[email protected]> | 2026-09-15 00:18:45 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-09-15 00:18:45 -0700 |
| commit | e408672de5b6aa450995271a36b7483ca94db049 (patch) | |
| tree | 9aeea511fff6fbf0d4bd6ef66011db826cc80456 /src | |
| parent | b14725268da32010ed5b75735f268e014adb1cf5 (diff) | |
| download | coinosv3-e408672de5b6aa450995271a36b7483ca94db049.tar.gz coinosv3-e408672de5b6aa450995271a36b7483ca94db049.zip | |
An @handle in a bio or post opens the people search for that name.
A bare @name carries no key, so nothing can resolve it for certain —
but it can be a tap that opens the search with the name filled in. The
@ inside an email or nip05 is left alone, as is anything inside a URL.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Diffstat (limited to 'src')
| -rw-r--r-- | src/features/messages.js | 22 | ||||
| -rw-r--r-- | src/i18n.js | 1 |
2 files changed, 22 insertions, 1 deletions
diff --git a/src/features/messages.js b/src/features/messages.js index efddcc9..fd95b62 100644 --- a/src/features/messages.js +++ b/src/features/messages.js @@ -3359,7 +3359,13 @@ export function messagesFeature(ctx) { // hashtag and * turns up in ordinary prose, so honouring those would // mangle normal posts to pretty up the rare bridged one. const MD_LINK = '!?\\[[^\\]\\n]{0,300}\\]\\(\\s*<?https?:\\/\\/[^\\s>)]+>?[^)\\n]{0,300}\\)'; - const NOTE_SPLIT = new RegExp('(' + MD_LINK + '|https?:\\/\\/[^\\s]+|nostr:(?:npub|nprofile|note|nevent|naddr)1[a-z0-9]+)', 'gi'); + // A bare @handle ("Founder of @MusiKnow") names a person without a key. + // Nothing can resolve it for certain, so it becomes a tap that opens the + // people search with that name filled in. Not the @ inside an email or a + // nip05 (a word character sits before those), and never inside a URL + // (the URL token starts earlier and swallows it). + const MENTION = '(?<![\\w.@/])@[A-Za-z0-9_]{2,32}(?![\\w@])'; + const NOTE_SPLIT = new RegExp('(' + MD_LINK + '|https?:\\/\\/[^\\s]+|nostr:(?:npub|nprofile|note|nevent|naddr)1[a-z0-9]+|' + MENTION + ')', 'gi'); const MD_PARTS = new RegExp('^(!?)\\[([^\\]\\n]{0,300})\\]\\(\\s*<?(https?:\\/\\/[^\\s>)]+)>?[^)\\n]{0,300}\\)$', 'i'); // A YouTube link is a video, so show the video. All three shapes it comes @@ -3738,11 +3744,25 @@ export function messagesFeature(ctx) { } else out.push(h('span', { class: 'faint' }, part.slice(6, 18) + '…')); } else if (/^nostr:/i.test(part)) { out.push(h('span', { class: 'faint' }, part.slice(6, 18) + '…')); + } else if (/^@[A-Za-z0-9_]{2,32}$/.test(part)) { + out.push(h('a', { + href: '#', title: t('searchPeopleFor', { q: part.slice(1) }), + onClick: (e) => { e.preventDefault(); e.stopPropagation(); openPeopleSearch(part.slice(1)); }, + }, part)); } else out.push(part); } return out; } + // The header magnifier's search, opened with a name already typed. + function openPeopleSearch(q) { + ui.chatOpen = false; ui.profilePk = null; ui.noteThread = null; + ui.userSearch = { q, rows: null }; + warmSearch(); + userSearcher.update(q); + render(); + } + // Zap a specific note. With a default amount configured this is ONE TAP: // the zap fires instantly (ark first, Lightning fallback) and reports by // toast, no form, no leaving the page. Without one, a small setup screen diff --git a/src/i18n.js b/src/i18n.js index 6cb847b..6a51fef 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -198,6 +198,7 @@ const STR = { msgAttachTooBig: 'That file is too big (20 MB max)', msgUploadFailed: 'Upload failed — try again', msgPhoto: 'Photo', + searchPeopleFor: 'Search people for {q}', msgEmojiSearch: 'Search emoji…', msgEmojiMore: 'More reactions', msgEmojiNone: 'No match', |
