From 73d9e5f6f24494bb3fa4901062572d142b826910 Mon Sep 17 00:00:00 2001 From: Nicolas Varrot Date: Thu, 12 Feb 2026 02:45:33 +0000 Subject: [PATCH] feat: add channel/type icons to session list in sidebar Show Discord, Telegram, WhatsApp, Signal, Slack brand icons, clock icon for cron sessions, bot icon for sub-agents, and globe icon for webchat sessions. Falls back to message bubble for unknown channels. Closes feedback #23 --- src/components/SessionIcon.tsx | 89 ++++++++++++++++++++++++++++++++++ src/components/Sidebar.tsx | 5 +- src/hooks/useGateway.ts | 2 + src/types/index.ts | 2 + 4 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 src/components/SessionIcon.tsx diff --git a/src/components/SessionIcon.tsx b/src/components/SessionIcon.tsx new file mode 100644 index 0000000..9bc2230 --- /dev/null +++ b/src/components/SessionIcon.tsx @@ -0,0 +1,89 @@ +import { MessageSquare, Clock, Globe, Bot } from 'lucide-react'; +import type { Session } from '../types'; + +// SVG brand icons (not available in lucide) +function DiscordIcon({ size = 15, className = '' }: { size?: number; className?: string }) { + return ( + + + + ); +} + +function TelegramIcon({ size = 15, className = '' }: { size?: number; className?: string }) { + return ( + + + + ); +} + +function SignalIcon({ size = 15, className = '' }: { size?: number; className?: string }) { + return ( + + + + ); +} + +function WhatsAppIcon({ size = 15, className = '' }: { size?: number; className?: string }) { + return ( + + + + ); +} + +function SlackIcon({ size = 15, className = '' }: { size?: number; className?: string }) { + return ( + + + + ); +} + +/** + * Returns the appropriate icon for a session based on its channel or kind. + * Detects cron sessions from the session key pattern. + */ +export function SessionIcon({ session, isActive, isCurrentSession }: { + session: Session; + isActive?: boolean; + isCurrentSession?: boolean; +}) { + const size = 15; + const baseClass = isCurrentSession ? 'text-cyan-300/70' : isActive ? 'text-violet-400/70' : ''; + + // Detect cron sessions from key pattern + const isCron = session.key.includes(':cron:'); + if (isCron) { + return ; + } + + // Detect sub-agent / spawned sessions + const isSubAgent = session.key.includes(':spawn:') || session.key.includes(':sub:'); + if (isSubAgent) { + return ; + } + + const channel = session.channel?.toLowerCase(); + + switch (channel) { + case 'discord': + return ; + case 'telegram': + return ; + case 'signal': + return ; + case 'whatsapp': + return ; + case 'slack': + return ; + case 'webchat': + return ; + case 'teamspeak': + return ; + default: + return ; + } +} diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 8cd34a0..29b9481 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -1,7 +1,8 @@ import { useState, useMemo, useRef, useEffect } from 'react'; -import { MessageSquare, X, Sparkles, Search } from 'lucide-react'; +import { X, Sparkles, Search } from 'lucide-react'; import type { Session } from '../types'; import { useT } from '../hooks/useLocale'; +import { SessionIcon } from './SessionIcon'; interface Props { sessions: Session[]; @@ -103,7 +104,7 @@ export function Sidebar({ sessions, activeSession, onSwitch, open, onClose }: Pr }`} >
- + {s.isActive && ( )} diff --git a/src/hooks/useGateway.ts b/src/hooks/useGateway.ts index 28ca729..ecdd3ff 100644 --- a/src/hooks/useGateway.ts +++ b/src/hooks/useGateway.ts @@ -90,6 +90,8 @@ export function useGateway() { contextTokens: s.contextTokens as number | undefined, inputTokens: s.inputTokens as number | undefined, outputTokens: s.outputTokens as number | undefined, + channel: (s.lastChannel || s.channel) as string | undefined, + kind: s.kind as string | undefined, }))); } } catch { diff --git a/src/types/index.ts b/src/types/index.ts index dcf4400..516bc8d 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -24,6 +24,8 @@ export interface Session { contextTokens?: number; inputTokens?: number; outputTokens?: number; + channel?: string; + kind?: string; } export type ConnectionStatus = 'disconnected' | 'connecting' | 'connected';