| index 14349c5..bfd9816 100644 |
| --- a/web/static/shell.js |
| +++ b/web/static/shell.js |
| @@ -6177,6 +6177,21 @@ async function editGroup() { |
| input.focus(); |
| } |
| |
| +// Open the DM with someone, creating it on first use — the one "Message them" |
| +// behaviour behind the profile card, the member sheet, and the mention menu. |
| +async function openOrCreateDM(uid) { |
| + const dm = existingDM(uid); |
| + if (dm) return openThread(dm.id); // already have a DM — reopen it, don't start a second |
| + try { |
| + const id = await createThread([uid], { group: false }); |
| + await loadThreads(); |
| + renderThreadList(); |
| + openThread(id); |
| + } catch (e) { |
| + console.error(e); |
| + } |
| +} |
| + |
| function showMembers() { |
| const t = threads.find((x) => x.id === activeId); |
| if (!t) return; |
| @@ -6194,7 +6209,9 @@ function showMembers() { |
| const row = document.createElement("div"); |
| row.className = "list-row" + (me ? " static" : ""); |
| |
| - // The identity area (avatar + name); tapping a member opens/reopens a DM. |
| + // The identity area (avatar + name); tapping a member opens their profile |
| + // card (the contacts-app convention) — Message lives on the card, so a |
| + // stray tap no longer starts a DM you didn't want. |
| const main = document.createElement(me ? "div" : "button"); |
| main.className = "member-main"; |
| main.appendChild(avatarEl(name, () => avatarFor(uid))); |
| @@ -6228,21 +6245,9 @@ function showMembers() { |
| } |
| main.appendChild(idcol); |
| if (!me) |
| - main.onclick = async () => { |
| + main.onclick = () => { |
| backdrop.remove(); |
| - const dm = existingDM(uid); |
| - if (dm) { |
| - openThread(dm.id); // already have a DM — reopen it, don't start a second |
| - return; |
| - } |
| - try { |
| - const id = await createThread([uid], { group: false }); |
| - await loadThreads(); |
| - renderThreadList(); |
| - openThread(id); |
| - } catch (e) { |
| - console.error(e); |
| - } |
| + viewProfile(uid); |
| }; |
| row.appendChild(main); |
| |
| @@ -6375,6 +6380,23 @@ function viewProfile(uid) { |
| p.textContent = blurb; |
| card.appendChild(p); |
| } |
| + |
| + // Message them — the card's action when it was reached from somewhere other |
| + // than their DM (the member sheet, a mention). Inside their DM it's noise. |
| + const dm = existingDM(uid); |
| + if (uid !== myUserId && !(dm && dm.id === activeId)) { |
| + const row = document.createElement("div"); |
| + row.className = "row"; |
| + row.style.cssText = "justify-content:center;margin-top:14px"; |
| + const msg = document.createElement("button"); |
| + msg.textContent = `Message ${displayNameFor(nicknames[uid], e.label) || "them"}`; |
| + msg.onclick = () => { |
| + backdrop.remove(); |
| + openOrCreateDM(uid); |
| + }; |
| + row.appendChild(msg); |
| + card.appendChild(row); |
| + } |
| } |
| |
| // A DM partner renamed themself while I hold my own name for them (#577): a |
| @@ -8268,18 +8290,9 @@ function openMentionMenu(entry, anchor) { |
| const msg = document.createElement("button"); |
| msg.className = "mention-menu-item"; |
| msg.textContent = `Message ${entry.label}`; |
| - msg.onclick = async () => { |
| + msg.onclick = () => { |
| pop.remove(); |
| - const dm = existingDM(entry.user_id); |
| - if (dm) return openThread(dm.id); |
| - try { |
| - const id = await createThread([entry.user_id], { group: false }); |
| - await loadThreads(); |
| - renderThreadList(); |
| - openThread(id); |
| - } catch (e) { |
| - console.error(e); |
| - } |
| + openOrCreateDM(entry.user_id); |
| }; |
| pop.appendChild(msg); |
| document.body.appendChild(pop); |