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
+11
View File
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { ref, computed, watch, nextTick, onMounted, onUnmounted } from 'vue'
import { useRoute } from 'vue-router'
import { useMeshStore } from '@/stores/mesh'
import { useTransportStore } from '@/stores/transport'
import type { MeshMessage, MeshPeer, SessionStatus } from '@/stores/mesh'
@@ -12,6 +13,7 @@ import '@/views/mesh/mesh-styles.css'
const mesh = useMeshStore()
const transport = useTransportStore()
const route = useRoute()
// Responsive layout breakpoints
const isWideDesktop = ref(window.innerWidth >= 1536)
@@ -301,6 +303,15 @@ onMounted(async () => {
loadPendingFromSession()
await Promise.all([mesh.refreshAll(), transport.fetchStatus(), refreshFederationNodes(), refreshSelfOnion(), refreshSelfDid(), refreshContacts()])
refreshOutboxCount()
// Deep-link from a message toast: open the sender's conversation if we can
// match it; otherwise just land on the mesh page (graceful fallback).
const targetPeer = typeof route.query.peer === 'string' ? route.query.peer : ''
if (targetPeer) {
const match = mesh.peers.find(
(p) => p.pubkey_hex === targetPeer || p.did === targetPeer
)
if (match) openChat(match)
}
// Start background polling for Archipelago (Tor) messages so unread count works
loadArchMessages()
if (!archPollInterval) {