Skip to content

Commit 230814b

Browse files
committed
unread indicator
1 parent d01e715 commit 230814b

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

renderer.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ interface Session {
2727
config: SessionConfig;
2828
worktreePath: string;
2929
hasActivePty: boolean;
30+
hasUnreadActivity: boolean;
3031
}
3132

3233
interface McpServer {
@@ -73,6 +74,15 @@ function createTerminalUI(sessionId: string) {
7374
ipcRenderer.send("session-input", sessionId, data);
7475
});
7576

77+
// Listen for bell character to mark unread activity
78+
term.onBell(() => {
79+
console.log(`Bell received for session ${sessionId}, activeSessionId: ${activeSessionId}`);
80+
if (activeSessionId !== sessionId) {
81+
console.log(`Marking session ${sessionId} as unread`);
82+
markSessionAsUnread(sessionId);
83+
}
84+
});
85+
7686
// Handle resize
7787
const resizeHandler = () => {
7888
if (activeSessionId === sessionId) {
@@ -95,6 +105,7 @@ function addSession(persistedSession: PersistedSession, hasActivePty: boolean) {
95105
config: persistedSession.config,
96106
worktreePath: persistedSession.worktreePath,
97107
hasActivePty,
108+
hasUnreadActivity: false,
98109
};
99110

100111
sessions.set(persistedSession.id, session);
@@ -299,6 +310,32 @@ function addTab(sessionId: string, name: string) {
299310
tabsContainer.appendChild(tab);
300311
}
301312

313+
function markSessionAsUnread(sessionId: string) {
314+
const session = sessions.get(sessionId);
315+
if (!session) return;
316+
317+
session.hasUnreadActivity = true;
318+
319+
// Add unread indicator to tab
320+
const tab = document.getElementById(`tab-${sessionId}`);
321+
if (tab && !tab.classList.contains("unread")) {
322+
tab.classList.add("unread");
323+
}
324+
}
325+
326+
function clearUnreadStatus(sessionId: string) {
327+
const session = sessions.get(sessionId);
328+
if (!session) return;
329+
330+
session.hasUnreadActivity = false;
331+
332+
// Remove unread indicator from tab
333+
const tab = document.getElementById(`tab-${sessionId}`);
334+
if (tab) {
335+
tab.classList.remove("unread");
336+
}
337+
}
338+
302339
function switchToSession(sessionId: string) {
303340
// Hide all sessions
304341
sessions.forEach((session, id) => {
@@ -317,6 +354,9 @@ function switchToSession(sessionId: string) {
317354
document.getElementById(`sidebar-${sessionId}`)?.classList.add("active");
318355
activeSessionId = sessionId;
319356

357+
// Clear unread status when switching to this session
358+
clearUnreadStatus(sessionId);
359+
320360
// Focus and resize
321361
session.terminal.focus();
322362
setTimeout(() => {
@@ -407,6 +447,11 @@ ipcRenderer.on("session-output", (_event, sessionId: string, data: string) => {
407447
const session = sessions.get(sessionId);
408448
if (session && session.terminal) {
409449
session.terminal.write(data);
450+
451+
// Mark as unread if this is not the active session and there's output
452+
if (activeSessionId !== sessionId && session.hasActivePty) {
453+
markSessionAsUnread(sessionId);
454+
}
410455
}
411456
});
412457

styles.css

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,17 @@
105105
@apply bg-gray-800 border-b-2 border-blue-500;
106106
}
107107

108+
.tab.unread .tab-name::after {
109+
content: '';
110+
display: inline-block;
111+
width: 6px;
112+
height: 6px;
113+
background-color: #3b82f6;
114+
border-radius: 50%;
115+
margin-left: 6px;
116+
vertical-align: middle;
117+
}
118+
108119
.tab-name {
109120
@apply text-sm text-gray-300;
110121
}

0 commit comments

Comments
 (0)