Skip to content

Commit 285422f

Browse files
lambasuclaude
andcommitted
Add tab-brief prototype (contact 34)
Second prototype: agent joins group chat and pins a context-brief.md tab instead of posting a welcome card in the thread. - New group contact 34 "Northwind launch" with contextBriefId - Messages seed: same Northwind thread, ending with two system messages (agent added + agent pinned context-brief.md) - contextBriefs.js: structured brief data (team, open items, tools, files, decisions) - ContextBriefPanel component: renders brief as a styled markdown-ish document (team table, open items with status badges, tool chips, file rows, decisions list) - ChatHeader: pinnedTab prop renders a purple pinned tab alongside Chat/Shared/Recap; activeTab + onSelectTab wired through - ChatView: activeTab state, resets on chat change; renders ContextBriefPanel when pinned tab is active - System message pin icon variant for the "pinned" event Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent b991228 commit 285422f

11 files changed

Lines changed: 666 additions & 1 deletion

src/components/ChatHeader.css

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,27 @@
6565
border-radius: 2px;
6666
}
6767

68+
.chat-view-tab.tab-pinned {
69+
display: flex;
70+
align-items: center;
71+
gap: 5px;
72+
color: #5B5FC7;
73+
}
74+
75+
.chat-view-tab.tab-pinned:hover {
76+
color: #4448B3;
77+
}
78+
79+
.chat-view-tab.tab-pinned.active {
80+
color: #4448B3;
81+
font-weight: 600;
82+
}
83+
84+
.tab-pin-icon {
85+
flex-shrink: 0;
86+
opacity: 0.75;
87+
}
88+
6889
.chat-view-tab.tab-add {
6990
color: #616161;
7091
padding: 14px 8px;

src/components/ChatHeader.jsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ export default function ChatHeader({
1414
onToggleSessions,
1515
showThreads,
1616
onToggleThreads,
17+
pinnedTab,
18+
activeTab = 'chat',
19+
onSelectTab,
1720
}) {
1821
return (
1922
<div className="chat-view-header">
@@ -28,7 +31,22 @@ export default function ChatHeader({
2831
</>
2932
) : (
3033
<>
31-
<button className="chat-view-tab active">Chat</button>
34+
<button
35+
className={`chat-view-tab${activeTab === 'chat' ? ' active' : ''}`}
36+
onClick={() => onSelectTab?.('chat')}
37+
>Chat</button>
38+
{pinnedTab && (
39+
<button
40+
className={`chat-view-tab tab-pinned${activeTab === 'pinned' ? ' active' : ''}`}
41+
onClick={() => onSelectTab?.('pinned')}
42+
>
43+
<svg width="12" height="12" viewBox="0 0 20 20" fill="currentColor" className="tab-pin-icon" aria-hidden="true">
44+
<path d="M13.5 2a.5.5 0 0 1 .354.146l4 4A.5.5 0 0 1 17.5 7c0 .97-.97 1.97-2.5 2.5L12 14H9.5a.5.5 0 0 1-.354-.854L11 11.293 8.707 9 6.854 10.854A.5.5 0 0 1 6 10.5V8L10.5 5C11.03 3.47 12.03 2.5 13 2.5l.5-.5z"/>
45+
<path d="M3.5 14.5 8 10" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" fill="none"/>
46+
</svg>
47+
{pinnedTab.label}
48+
</button>
49+
)}
3250
<button className="chat-view-tab">Shared</button>
3351
<button className="chat-view-tab">Recap</button>
3452
<button className="chat-view-tab">Storyline</button>

src/components/ChatView.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,12 @@
748748
white-space: nowrap;
749749
}
750750

751+
.system-message-icon {
752+
flex-shrink: 0;
753+
color: #5B5FC7;
754+
opacity: 0.8;
755+
}
756+
751757
/* ── Stakeholder people grid (card section type: people) ────────────── */
752758
.card-people {
753759
display: grid;

src/components/ChatView.jsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ import {
1212
designerAgent,
1313
pollyAgent,
1414
breakthuAgent,
15+
contextBriefs,
1516
} from '../data'
1617
import { TypingIndicator } from './common'
18+
import ContextBriefPanel from './ContextBriefPanel'
1719
import MessageRow from './MessageRow'
1820
import SessionsRail from './SessionsRail'
1921
import AgentsRail from './AgentsRail'
@@ -119,6 +121,7 @@ export default function ChatView({
119121
const [channelThreadPostId, setChannelThreadPostId] = useState(null)
120122
const [threadRailOpen, setThreadRailOpen] = useState(false)
121123
const [highlightMessageId, setHighlightMessageId] = useState(null)
124+
const [activeTab, setActiveTab] = useState('chat')
122125
const messagesEndRef = useRef(null)
123126

124127
// Reset per-chat ephemeral state when activeChatId changes. Using the
@@ -140,6 +143,7 @@ export default function ChatView({
140143
setChannelThreadPostId(null)
141144
setThreadRailOpen(false)
142145
setHighlightMessageId(null)
146+
setActiveTab('chat')
143147
const intentMatches = navIntent && navIntent.chatId === activeChatId
144148
const intentHasSession = intentMatches && 'sessionId' in navIntent
145149
if (intentHasSession) {
@@ -530,6 +534,9 @@ export default function ChatView({
530534
const agentSuggestions = isAgent ? promptSuggestions[activeChatId] : null
531535
const showPromptSuggestions = !!agentSuggestions && messages.length === 0 && mainTypingAgentId !== activeChatId
532536

537+
const contextBrief = activeContact.contextBriefId ? contextBriefs[activeContact.contextBriefId] : null
538+
const pinnedTab = contextBrief ? { label: contextBrief.filename } : null
539+
533540
return (
534541
<div className="chat-view">
535542
<div className="chat-view-main">
@@ -550,8 +557,14 @@ export default function ChatView({
550557
setThreadRailOpen(true)
551558
}
552559
}}
560+
pinnedTab={pinnedTab}
561+
activeTab={activeTab}
562+
onSelectTab={setActiveTab}
553563
/>
554564

565+
{activeTab === 'pinned' && contextBrief ? (
566+
<ContextBriefPanel brief={contextBrief} />
567+
) : (
555568
<div className="chat-messages">
556569
{isChannel ? (
557570
<div className="messages-container messages-container-channel">
@@ -616,6 +629,7 @@ export default function ChatView({
616629
</div>
617630
)}
618631
</div>
632+
)}
619633

620634
<div className="chat-compose-area">
621635
{mainTypingAgentId === activeChatId && (

0 commit comments

Comments
 (0)