From 53bc5d1d72cf3ef51202087799bb656321f8b6e5 Mon Sep 17 00:00:00 2001 From: Matt Toohey Date: Tue, 17 Mar 2026 16:46:28 +1100 Subject: [PATCH 1/7] feat(ui): add cross-navigation buttons between note and session dialogs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When viewing a note that has an associated chat session, show a MessageSquare button in the dialog header that dismisses the note and opens the corresponding session dialog. When viewing a chat session that has an associated note, show a FileText button in the dialog header that dismisses the session and opens the corresponding note dialog. Both buttons only appear when the association exists. Wired up in BranchCard (timeline notes ↔ branch sessions) and ProjectSection (project notes ↔ project sessions). --- .../lib/features/branches/BranchCard.svelte | 32 ++++++++++++++--- .../src/lib/features/notes/NoteModal.svelte | 24 +++++++++---- .../features/projects/ProjectSection.svelte | 30 ++++++++++++++-- .../lib/features/sessions/SessionModal.svelte | 36 ++++++++++++++++++- .../features/timeline/BranchTimeline.svelte | 4 +-- 5 files changed, 110 insertions(+), 16 deletions(-) diff --git a/apps/staged/src/lib/features/branches/BranchCard.svelte b/apps/staged/src/lib/features/branches/BranchCard.svelte index 246be108..15c5aa40 100644 --- a/apps/staged/src/lib/features/branches/BranchCard.svelte +++ b/apps/staged/src/lib/features/branches/BranchCard.svelte @@ -160,7 +160,7 @@ let commitDiffSha = $state(null); // Note modal (opened by clicking a note in the timeline) - let openNote = $state<{ title: string; content: string } | null>(null); + let openNote = $state<{ title: string; content: string; sessionId?: string } | null>(null); // Image viewer modal (opened by clicking an image in the timeline) let viewImageId = $state(null); @@ -351,12 +351,21 @@ // Timeline item interactions // ========================================================================= + /** Look up note info from timeline data by session ID (for cross-modal navigation). */ + function findNoteForSession( + sessionId: string + ): { id: string; title: string; content: string } | null { + const note = timeline?.notes.find((n) => n.sessionId === sessionId && n.content?.trim()); + if (!note) return null; + return { id: note.id, title: note.title, content: note.content }; + } + function handleCommitClick(sha: string) { commitDiffSha = sha; } - function handleNoteClick(_noteId: string, title: string, content: string) { - openNote = { title, content }; + function handleNoteClick(_noteId: string, title: string, content: string, sessionId?: string) { + openNote = { title, content, sessionId }; } async function handleReviewClick(reviewId: string) { @@ -803,7 +812,16 @@ {/if} {#if openNote} - (openNote = null)} /> + (openNote = null)} + onOpenSession={(sid) => { + openNote = null; + sessionMgr.openSessionId = sid; + }} + /> {/if} {#if viewImageId} @@ -847,6 +865,12 @@ repoDir={branch.worktreePath} branchId={branch.id} projectId={branch.projectId} + noteInfo={findNoteForSession(sessionMgr.openSessionId)} + onOpenNote={(noteId, title, content) => { + const sid = sessionMgr.openSessionId; + sessionMgr.openSessionId = null; + openNote = { title, content, sessionId: sid ?? undefined }; + }} onClose={async () => { const closedSessionId = sessionMgr.openSessionId; sessionMgr.openSessionId = null; diff --git a/apps/staged/src/lib/features/notes/NoteModal.svelte b/apps/staged/src/lib/features/notes/NoteModal.svelte index 9a1dffdf..7cddb2c2 100644 --- a/apps/staged/src/lib/features/notes/NoteModal.svelte +++ b/apps/staged/src/lib/features/notes/NoteModal.svelte @@ -6,7 +6,7 @@ -->