Skip to content

Commit 643674d

Browse files
committed
🤖 Hover AIView preview in sidebar: show recent messages on workspace hover without altering active view\n\n- Add AIViewPreview (read-only, last N messages, ChatProvider for parity)\n- Integrate preview as Tooltip content around WorkspaceItem\n- Keep non-interactive/pointer-events:none to avoid stealing focus\n- Uses existing MessageRenderer for full parity\n\nGenerated with
1 parent 4bf71e9 commit 643674d

File tree

2 files changed

+303
-89
lines changed

2 files changed

+303
-89
lines changed
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import React, { useMemo } from "react";
2+
import styled from "@emotion/styled";
3+
import type { WorkspaceState } from "@/hooks/useWorkspaceAggregators";
4+
import { MessageRenderer } from "./Messages/MessageRenderer";
5+
import { ChatProvider } from "@/contexts/ChatContext";
6+
import { mergeConsecutiveStreamErrors } from "@/utils/messages/messageUtils";
7+
8+
interface AIViewPreviewProps {
9+
workspaceId: string;
10+
projectName: string;
11+
branch: string;
12+
workspacePath: string;
13+
workspaceState: WorkspaceState;
14+
maxMessages?: number;
15+
className?: string;
16+
}
17+
18+
const PreviewContainer = styled.div`
19+
width: 300px; /* match Tooltip width=\"wide\" max-width */
20+
max-width: min(300px, 80vw);
21+
max-height: 340px;
22+
display: flex;
23+
flex-direction: column;
24+
background: #1f1f1f;
25+
border: 1px solid #3a3a3a;
26+
border-radius: 8px;
27+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
28+
color: #d4d4d4;
29+
overflow: hidden;
30+
pointer-events: none; /* Keep non-interactive to avoid stealing hover */
31+
`;
32+
33+
const PreviewHeader = styled.div`
34+
padding: 6px 10px;
35+
background: #252526;
36+
border-bottom: 1px solid #3e3e42;
37+
font-size: 12px;
38+
font-weight: 600;
39+
color: #cccccc;
40+
display: flex;
41+
justify-content: space-between;
42+
align-items: center;
43+
`;
44+
45+
const HeaderPath = styled.span`
46+
font-family: var(--font-monospace);
47+
color: #888;
48+
font-weight: 400;
49+
font-size: 11px;
50+
`;
51+
52+
const PreviewContent = styled.div`
53+
padding: 10px;
54+
overflow: hidden;
55+
`;
56+
57+
const MessagesScroll = styled.div`
58+
overflow: hidden; /* non-interactive */
59+
`;
60+
61+
const FadeBottom = styled.div`
62+
position: absolute;
63+
bottom: 0;
64+
left: 0;
65+
right: 0;
66+
height: 36px;
67+
background: linear-gradient(to bottom, rgba(31, 31, 31, 0), rgba(31, 31, 31, 1));
68+
pointer-events: none;
69+
`;
70+
71+
const ContentWrapper = styled.div`
72+
position: relative;
73+
`;
74+
75+
/**
76+
* Lightweight read-only view of recent messages for hover previews.
77+
* Uses the same MessageRenderer components to ensure visual parity with AIView.
78+
*/
79+
export const AIViewPreview: React.FC<AIViewPreviewProps> = ({
80+
workspaceId,
81+
projectName,
82+
branch,
83+
workspacePath,
84+
workspaceState,
85+
maxMessages = 6,
86+
className,
87+
}) => {
88+
const merged = useMemo(() => mergeConsecutiveStreamErrors(workspaceState.messages), [
89+
workspaceState.messages,
90+
]);
91+
92+
// Select only the last N messages for brevity
93+
const messages = useMemo(() => merged.slice(Math.max(0, merged.length - maxMessages)), [
94+
merged,
95+
maxMessages,
96+
]);
97+
98+
return (
99+
<ChatProvider
100+
messages={messages}
101+
cmuxMessages={workspaceState.cmuxMessages}
102+
model={workspaceState.currentModel}
103+
>
104+
<PreviewContainer className={className} role="dialog" aria-label="Workspace preview">
105+
<PreviewHeader>
106+
<span>
107+
{projectName} / {branch}
108+
</span>
109+
<HeaderPath>{workspacePath}</HeaderPath>
110+
</PreviewHeader>
111+
<PreviewContent>
112+
<ContentWrapper>
113+
<MessagesScroll>
114+
{messages.length === 0 ? (
115+
<div style={{ color: "#6b6b6b", textAlign: "center", padding: "12px 0" }}>
116+
No messages yet
117+
</div>
118+
) : (
119+
messages.map((msg) => (
120+
<div key={msg.id} style={{ marginBottom: 8 }}>
121+
<MessageRenderer
122+
message={msg}
123+
workspaceId={workspaceId}
124+
model={workspaceState.currentModel}
125+
/>
126+
</div>
127+
))
128+
)}
129+
</MessagesScroll>
130+
<FadeBottom />
131+
</ContentWrapper>
132+
</PreviewContent>
133+
</PreviewContainer>
134+
</ChatProvider>
135+
);
136+
};
137+

0 commit comments

Comments
 (0)