Simplify chat by removing V avatar icon
This commit is contained in:
@@ -9,7 +9,7 @@ import React, {
|
||||
type CSSProperties,
|
||||
} from "react";
|
||||
import Link from "next/link";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { ArrowDown, useSession } from "next-auth/react";
|
||||
import { useParams, usePathname } from "next/navigation";
|
||||
import {
|
||||
MessageSquare,
|
||||
@@ -520,28 +520,21 @@ const MessageBubble = React.memo(function MessageBubble({
|
||||
style={{
|
||||
width: 24,
|
||||
height: 24,
|
||||
borderRadius: "50%",
|
||||
background: "#f4f4f5", // Zinc-100 instead of black
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
marginRight: 8,
|
||||
flexShrink: 0,
|
||||
marginTop: 2,
|
||||
border: "1px solid #e4e4e7",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: "#18181b", // Dark gray instead of white
|
||||
fontSize: "0.6rem",
|
||||
fontWeight: 700,
|
||||
fontFamily: "var(--font-lora),serif",
|
||||
fontStyle: "italic",
|
||||
}}
|
||||
>
|
||||
V.
|
||||
</span>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ color: "#a1a1aa" }}>
|
||||
<path d="m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z"/>
|
||||
<path d="M5 3v4"/>
|
||||
<path d="M19 17v4"/>
|
||||
<path d="M3 5h4"/>
|
||||
<path d="M17 19h4"/>
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
@@ -643,7 +636,7 @@ function Timeline({ entries, isActiveStream }: { entries: TimelineEntry[], isAct
|
||||
{items.map((item, i) => {
|
||||
const isLast = i === items.length - 1;
|
||||
if (item.kind === "thought") {
|
||||
return <TimelineText key={i} text={item.text} isStreaming={isActiveStream && isLast} />;
|
||||
return <TimelineThought key={i} text={item.text} isStreaming={isActiveStream && isLast} />;
|
||||
}
|
||||
if (item.kind === "text") {
|
||||
return <TimelineText key={i} text={item.text} isStreaming={isActiveStream && isLast} />;
|
||||
@@ -668,6 +661,89 @@ function Timeline({ entries, isActiveStream }: { entries: TimelineEntry[], isAct
|
||||
* bubble so each round of multi-tool-loop output reads as a discrete
|
||||
* step instead of concatenating into a wall of text.
|
||||
*/
|
||||
|
||||
function TimelineThought({ text, isStreaming }: { text: string; isStreaming?: boolean }) {
|
||||
const [expanded, setExpanded] = React.useState(true);
|
||||
|
||||
// Auto-collapse when streaming stops
|
||||
const textLenRef = React.useRef(text.length);
|
||||
React.useEffect(() => {
|
||||
let t = setTimeout(() => {
|
||||
if (text.length === textLenRef.current && !isStreaming) {
|
||||
setExpanded(false);
|
||||
}
|
||||
}, 1500);
|
||||
return () => clearTimeout(t);
|
||||
}, [text, isStreaming]);
|
||||
|
||||
React.useEffect(() => {
|
||||
textLenRef.current = text.length;
|
||||
}, [text]);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
margin: "8px 0",
|
||||
fontFamily: "var(--font-inter),ui-sans-serif,sans-serif",
|
||||
}}
|
||||
>
|
||||
<button
|
||||
onClick={() => setExpanded((v) => !v)}
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 8,
|
||||
background: "transparent",
|
||||
border: "none",
|
||||
padding: 0,
|
||||
cursor: "pointer",
|
||||
fontSize: "0.75rem",
|
||||
color: "#71717a",
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
transform: expanded ? "rotate(90deg)" : "rotate(0deg)",
|
||||
transition: "transform 0.15s ease",
|
||||
display: "inline-block",
|
||||
fontSize: "0.65rem",
|
||||
color: "#a1a1aa"
|
||||
}}
|
||||
>
|
||||
▶
|
||||
</span>
|
||||
<span className={isStreaming ? "animate-pulse" : ""} style={{ transition: "opacity 0.2s ease" }}>
|
||||
Analyzed task
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{expanded && (
|
||||
<div
|
||||
style={{
|
||||
marginTop: 8,
|
||||
marginLeft: 6,
|
||||
paddingLeft: 12,
|
||||
borderLeft: "2px solid #e5e7eb",
|
||||
fontSize: "0.84rem",
|
||||
color: "#52525b",
|
||||
lineHeight: 1.6,
|
||||
whiteSpace: "pre-wrap",
|
||||
overflowWrap: "anywhere",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: renderMarkdown(stripRawToolLogs(text)) + (isStreaming ? `<span class="animate-pulse" style="display:inline-block; width:6px; height:13px; background-color:#9ca3af; vertical-align:-1px; margin-left:2px; border-radius:1px;"></span>` : ""),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TimelineText({ text, isStreaming }: { text: string; isStreaming?: boolean }) {
|
||||
const proseWrap: React.CSSProperties = {
|
||||
overflowWrap: "anywhere",
|
||||
@@ -1068,6 +1144,8 @@ export function ChatPanel({
|
||||
);
|
||||
const [showThreads, setShowThreads] = useState(false);
|
||||
const [mcpToken, setMcpToken] = useState<string | null>(null);
|
||||
const [showScrollButton, setShowScrollButton] = useState(false);
|
||||
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||
const [isChatMinimized, setIsChatMinimized] = useState<boolean>(false);
|
||||
|
||||
// Auto-minimize when navigating to dashboard, auto-open when navigating to preview
|
||||
@@ -2920,3 +2998,36 @@ export function ChatPanel({
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function ScrollToBottomButton({ onClick, visible }: { onClick: () => void, visible: boolean }) {
|
||||
if (!visible) return null;
|
||||
return (
|
||||
<button
|
||||
onClick={onClick}
|
||||
style={{
|
||||
position: "absolute",
|
||||
bottom: "80px",
|
||||
left: "50%",
|
||||
transform: "translateX(-50%)",
|
||||
background: "#ffffff",
|
||||
border: "1px solid #e5e7eb",
|
||||
borderRadius: "999px",
|
||||
padding: "6px",
|
||||
boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)",
|
||||
cursor: "pointer",
|
||||
color: "#4b5563",
|
||||
zIndex: 50,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
transition: "all 0.2s ease"
|
||||
}}
|
||||
aria-label="Scroll to bottom"
|
||||
>
|
||||
<ArrowDown size={16} />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user