feat(toast): message toast opens the related chat + has a close icon (#33)

- Add a close (X) button to the message toast (closeToast, @click.stop) like the
  system notifications.
- Carry the sender pubkey on the toast; clicking now deep-links to that
  conversation (/dashboard/mesh?peer=<pubkey>) instead of the generic mesh page.
- Mesh.vue reads ?peer= on mount and opens the matching peer (by pubkey_hex/did),
  gracefully falling back to the mesh list when no match (B1/B2 identity).

type-check clean; useMessageToast tests 11/11.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-06-16 07:39:52 -04:00
co-authored by Claude Opus 4.8
parent 4576964be4
commit b602a9cea5
3 changed files with 34 additions and 3 deletions
+14 -3
View File
@@ -14,7 +14,7 @@ const MESSAGE_POLL_INTERVAL = 30000 // 30s
const receivedMessages = ref<ReceivedMessage[]>([])
const lastMessageCount = ref(0)
const loadingMessages = ref(false)
const toastMessage = ref<{ show: boolean; text: string }>({ show: false, text: '' })
const toastMessage = ref<{ show: boolean; text: string; fromPubkey: string }>({ show: false, text: '', fromPubkey: '' })
let pollTimer: ReturnType<typeof setInterval> | null = null
export function useMessageToast() {
@@ -37,6 +37,9 @@ export function useMessageToast() {
toastMessage.value = {
show: true,
text: (newCount === 1 ? latest?.message : null) ?? `${newCount} new messages`,
// Only deep-link to a specific chat when it's a single new message
// from one sender; otherwise open the mesh list.
fromPubkey: newCount === 1 ? (latest?.from_pubkey ?? '') : '',
}
lastMessageCount.value = msgs.length
} else {
@@ -83,9 +86,16 @@ export function useMessageToast() {
}
function dismissToastAndOpenMessages() {
toastMessage.value = { show: false, text: '' }
const peer = toastMessage.value.fromPubkey
toastMessage.value = { show: false, text: '', fromPubkey: '' }
markAsRead()
router.push('/dashboard/mesh')
// Open the specific conversation when we know the sender; else the mesh list.
router.push(peer ? { path: '/dashboard/mesh', query: { peer } } : '/dashboard/mesh')
}
// Dismiss the toast without navigating (the close icon).
function closeToast() {
toastMessage.value = { show: false, text: '', fromPubkey: '' }
}
return {
@@ -99,5 +109,6 @@ export function useMessageToast() {
stopPolling,
markAsRead,
dismissToastAndOpenMessages,
closeToast,
}
}