feat: theme change and adjustments

This commit is contained in:
Vukasin 2025-07-06 18:34:31 +02:00
parent 4485563b47
commit 6938164eff
32 changed files with 328 additions and 332 deletions

View File

@ -192,7 +192,7 @@ export const Examples = ({
}}
>
<Card
className="group cursor-pointer h-full shadow-none transition-all bg-sidebar hover:bg-neutral-100 dark:hover:bg-neutral-800/60 p-0 justify-center"
className="group cursor-pointer h-full shadow-none transition-all bg-card hover:bg-neutral-100 dark:hover:bg-neutral-800/60 p-0 justify-center"
onClick={() => onSelectPrompt && onSelectPrompt(prompt.query)}
>
<CardHeader className="p-2 grid-rows-1">

View File

@ -225,23 +225,23 @@
}
:root {
--background: oklch(98.46% 0.002 247.84);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--background: oklch(0.9741 0 129.63);
--foreground: oklch(0.2277 0.0034 67.65);
--card: oklch(98.46% 0.002 247.84);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover: oklch(0.9924 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(54.65% 0.246 262.87);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted: oklch(0.93 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent: oklch(0.1149 0 0 / 6%);
--accent-foreground: oklch(0.145 0 0);
--destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--border: oklch(0.1149 0 0 / 8%);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116);
@ -250,11 +250,11 @@
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--radius: 0.625rem;
--sidebar: oklch(98.46% 0.002 247.84);
--sidebar: oklch(0.9741 0 129.63);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent: oklch(0.1149 0 0 / 4%);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
@ -263,29 +263,29 @@
.dark {
--background: oklch(0.185 0.005 285.823);
--foreground: oklch(0.985 0 0);
--card: oklch(0.145 0 0);
--card: oklch(0.2 0.005 285.823);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.145 0 0);
--popover: oklch(0.2267 0.0051 264.48);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.985 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(54.65% 0.246 262.87);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted: oklch(0.31 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(27.39% 0.005 286.03);
--accent: oklch(0.274 0.006 286.033);
--accent-foreground: oklch(98.46% 0.002 247.84)
--destructive: oklch(0.396 0.141 25.723);
--destructive-foreground: oklch(0.637 0.237 25.331);
--border: oklch(0.269 0 0);
--input: oklch(0.269 0 0);
--border: oklch(0.9911 0 0 / 6%);
--input: oklch(0.28 0 0);
--ring: oklch(0.439 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(21.03% 0.006 285.89);
--sidebar: oklch(0.185 0.005 285.823);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);

View File

@ -286,7 +286,7 @@ export function HeroSection() {
<div className="relative z-10">
<Card className="shadow-none w-full max-w-8xl mx-auto bg-transparent border-none rounded-3xl overflow-hidden">
<div className="w-full text-sm flex flex-col justify-between items-start rounded-2xl">
<CardContent className="w-full p-1.5 pb-2 bg-sidebar rounded-3xl border">
<CardContent className="w-full p-1.5 pb-2 bg-card rounded-3xl border">
<div className="relative flex flex-col w-full h-full gap-2 justify-between">
<div className="flex flex-col gap-1 px-2">
<Textarea

View File

@ -188,7 +188,7 @@ export function NavUserWithTeams({
sideOffset={4}
>
<DropdownMenuLabel className="p-0 font-normal">
<div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
<div className="flex items-center gap-2 px-1.5 py-1.5 text-left text-sm">
<Avatar className="h-8 w-8 rounded-lg">
<AvatarImage src={user.avatar} alt={user.name} />
<AvatarFallback className="rounded-lg">

View File

@ -78,7 +78,7 @@ export const ChatInput = forwardRef<ChatInputHandles, ChatInputProps>(
onAgentSelect,
agentName,
messages = [],
bgColor = 'bg-sidebar',
bgColor = 'bg-card',
toolCalls = [],
toolCallIndex = 0,
showToolPreview = false,

View File

@ -106,7 +106,7 @@ export const FloatingToolPreview: React.FC<FloatingToolPreviewProps> = ({
layoutId={CONTENT_LAYOUT_ID}
whileHover={{ scale: 1.01 }}
whileTap={{ scale: 0.99 }}
className="bg-sidebar border border-border rounded-3xl p-2 w-full cursor-pointer group"
className="bg-card border border-border rounded-3xl p-2 w-full cursor-pointer group"
onClick={handleClick}
style={{ opacity: isExpanding ? 0 : 1 }}
>

View File

@ -169,7 +169,7 @@ export function renderMarkdownContent(
<div key={`tool-${match.index}-${index}`} className="my-1">
<button
onClick={() => handleToolClick(messageId, toolName)}
className="inline-flex items-center gap-1.5 py-1 px-1 text-xs text-muted-foreground bg-muted hover:bg-muted/80 rounded-lg transition-colors cursor-pointer border border-neutral-200 dark:border-neutral-700/50"
className="inline-flex items-center gap-1.5 py-1 px-1 pr-1.5 text-xs text-muted-foreground bg-muted hover:bg-muted/80 rounded-lg transition-colors cursor-pointer border border-neutral-200 dark:border-neutral-700/50"
>
<div className='border-2 bg-gradient-to-br from-neutral-200 to-neutral-300 dark:from-neutral-700 dark:to-neutral-800 flex items-center justify-center p-0.5 rounded-sm border-neutral-400/20 dark:border-neutral-600'>
<IconComponent className="h-3.5 w-3.5 text-muted-foreground flex-shrink-0" />
@ -251,7 +251,7 @@ export function renderMarkdownContent(
<div key={toolCallKey} className="my-1">
<button
onClick={() => handleToolClick(messageId, toolName)}
className="inline-flex items-center gap-1.5 py-1 px-1 text-xs text-muted-foreground bg-muted hover:bg-muted/80 rounded-lg transition-colors cursor-pointer border border-neutral-200 dark:border-neutral-700/50"
className="inline-flex items-center gap-1.5 py-1 px-1 pr-1.5 text-xs text-muted-foreground bg-muted hover:bg-muted/80 rounded-lg transition-colors cursor-pointer border border-neutral-200 dark:border-neutral-700/50"
>
<div className='border-2 bg-gradient-to-br from-neutral-200 to-neutral-300 dark:from-neutral-700 dark:to-neutral-800 flex items-center justify-center p-0.5 rounded-sm border-neutral-400/20 dark:border-neutral-600'>
<IconComponent className="h-3.5 w-3.5 text-muted-foreground flex-shrink-0" />
@ -567,7 +567,7 @@ export const ThreadContent: React.FC<ThreadContentProps> = ({
if (debugMode) {
return (
<div key={group.key} className="flex justify-end">
<div className="flex max-w-[85%] rounded-2xl bg-primary/10 px-4 py-3 break-words overflow-hidden">
<div className="flex max-w-[85%] rounded-2xl bg-card px-4 py-3 break-words overflow-hidden">
<pre className="text-xs font-mono whitespace-pre-wrap overflow-x-auto min-w-0 flex-1">
{message.content}
</pre>
@ -590,7 +590,7 @@ export const ThreadContent: React.FC<ThreadContentProps> = ({
return (
<div key={group.key} className="flex justify-end">
<div className="flex max-w-[85%] rounded-2xl bg-primary/10 px-4 py-3 break-words overflow-hidden">
<div className="flex max-w-[85%] rounded-3xl rounded-br-lg bg-card border px-4 py-3 break-words overflow-hidden">
<div className="space-y-3 min-w-0 flex-1">
{cleanContent && (
<Markdown className="text-sm prose prose-sm dark:prose-invert chat-markdown max-w-none [&>:first-child]:mt-0 prose-headings:mt-3 break-words overflow-wrap-anywhere">{cleanContent}</Markdown>
@ -640,7 +640,7 @@ export const ThreadContent: React.FC<ThreadContentProps> = ({
</div>
{/* Message content - ALL messages in the group */}
<div className="flex max-w-[90%] rounded-lg text-sm break-words overflow-hidden">
<div className="flex max-w-[90%] text-sm break-words overflow-hidden">
<div className="space-y-2 min-w-0 flex-1">
{(() => {
// In debug mode, just show raw messages content

View File

@ -387,8 +387,8 @@ export function FileAttachment({
<div
className={cn(
"group relative rounded-xl w-full",
"border border-black/10 dark:border-white/10",
"bg-black/5 dark:bg-black/20",
"border",
"bg-card",
"overflow-hidden",
"h-[300px]", // Fixed height for previews
"pt-10", // Room for header
@ -462,7 +462,7 @@ export function FileAttachment({
</div>
{/* Header with filename */}
<div className="absolute top-0 left-0 right-0 bg-black/5 dark:bg-white/5 p-2 z-10 flex items-center justify-between">
<div className="absolute top-0 left-0 right-0 bg-accent p-2 z-10 flex items-center justify-between">
<div className="text-sm font-medium truncate">{filename}</div>
{onClick && (
<button

View File

@ -1551,7 +1551,7 @@ export function FileViewerModal({
{files.map((file) => (
<button
key={file.path}
className={`flex flex-col items-center p-3 rounded-lg border hover:bg-muted/50 transition-colors ${selectedFilePath === file.path
className={`flex flex-col items-center p-3 rounded-2xl border hover:bg-muted/50 transition-colors ${selectedFilePath === file.path
? 'bg-muted border-primary/20'
: ''
}`}

View File

@ -196,7 +196,7 @@ export function ToolCallSidePanel({
displayIndex = completedIndex;
displayTotalCalls = totalCompletedCalls;
}
}
}
const currentToolName = displayToolCall?.assistantCall?.name || 'Tool Call';
const CurrentToolIcon = getToolIcon(
@ -434,8 +434,7 @@ export function ToolCallSidePanel({
<div className="pt-4 pl-4 pr-4">
<div className="flex items-center justify-between">
<div className="ml-2 flex items-center gap-2">
<Computer className="h-4 w-4" />
<h2 className="text-md font-medium text-zinc-900 dark:text-zinc-100">
<h2 className="text-lg font-medium text-zinc-900 dark:text-zinc-100">
{agentName ? `${agentName}'s Computer` : 'Suna\'s Computer'}
</h2>
</div>
@ -473,8 +472,7 @@ export function ToolCallSidePanel({
<div className="pt-4 pl-4 pr-4">
<div className="flex items-center justify-between">
<div className="ml-2 flex items-center gap-2">
<Computer className="h-4 w-4" />
<h2 className="text-md font-medium text-zinc-900 dark:text-zinc-100">
<h2 className="text-lg font-medium text-zinc-900 dark:text-zinc-100">
{agentName ? `${agentName}'s Computer` : 'Suna\'s Computer'}
</h2>
</div>
@ -520,8 +518,7 @@ export function ToolCallSidePanel({
<div className="pt-4 pl-4 pr-4">
<div className="flex items-center justify-between">
<div className="ml-2 flex items-center gap-2">
<Computer className="h-4 w-4" />
<h2 className="text-md font-medium text-zinc-900 dark:text-zinc-100">
<h2 className="text-lg font-medium text-zinc-900 dark:text-zinc-100">
{agentName ? `${agentName}'s Computer` : 'Suna\'s Computer'}
</h2>
</div>
@ -567,8 +564,7 @@ export function ToolCallSidePanel({
<div className="pt-4 pl-4 pr-4">
<div className="flex items-center justify-between">
<div className="ml-2 flex items-center gap-2">
<Computer className="h-4 w-4" />
<h2 className="text-md font-medium text-zinc-900 dark:text-zinc-100">
<h2 className="text-lg font-medium text-zinc-900 dark:text-zinc-100">
{agentName ? `${agentName}'s Computer` : 'Suna\'s Computer'}
</h2>
</div>
@ -612,14 +608,13 @@ export function ToolCallSidePanel({
return (
<div className="flex flex-col h-full">
<motion.div
<motion.div
layoutId={CONTENT_LAYOUT_ID}
className="p-3"
>
<div className="flex items-center justify-between">
<motion.div layoutId="tool-icon" className="ml-2 flex items-center gap-2">
<Computer className="h-4 w-4" />
<h2 className="text-md font-medium text-zinc-900 dark:text-zinc-100">
<h2 className="text-lg font-medium text-zinc-900 dark:text-zinc-100">
{agentName ? `${agentName}'s Computer` : 'Suna\'s Computer'}
</h2>
</motion.div>
@ -695,16 +690,16 @@ export function ToolCallSidePanel({
}
}}
className={cn(
'fixed top-2 right-2 bottom-4 border rounded-2xl flex flex-col z-30',
'fixed top-2 right-2 bottom-4 border rounded-3xl flex flex-col z-30',
isMobile
? 'left-2'
: 'w-[40vw] sm:w-[450px] md:w-[500px] lg:w-[550px] xl:w-[645px]',
)}
style={{
overflow: 'hidden',
style={{
overflow: 'hidden',
}}
>
<div className="flex-1 flex flex-col overflow-hidden bg-sidebar">
<div className="flex-1 flex flex-col overflow-hidden bg-card">
{renderContent()}
</div>
{(displayTotalCalls > 1 || (isCurrentToolStreaming && totalCompletedCalls > 0)) && (

View File

@ -74,7 +74,7 @@ export function BrowserToolView({
try {
const cleanedOutput = outputString.replace(/\\n/g, '\n').replace(/\\"/g, '"').replace(/\\u([0-9a-fA-F]{4})/g, (match, grp) => String.fromCharCode(parseInt(grp, 16)));
const outputJson = JSON.parse(cleanedOutput);
if (outputJson.image_url) {
screenshotUrl = outputJson.image_url;
}
@ -84,21 +84,21 @@ export function BrowserToolView({
} catch (parseError) {
}
}
if (!screenshotUrl) {
const imageUrlMatch = innerContentString.match(/"image_url":\s*"([^"]+)"/);
if (imageUrlMatch) {
screenshotUrl = imageUrlMatch[1];
}
}
if (!browserStateMessageId) {
const messageIdMatch = innerContentString.match(/"message_id":\s*"([^"]+)"/);
if (messageIdMatch) {
browserStateMessageId = messageIdMatch[1];
}
}
if (!browserStateMessageId && !screenshotUrl) {
const outputMatch = innerContentString.match(/\boutput='(.*?)'(?=\s*\))/);
const outputString = outputMatch ? outputMatch[1] : null;
@ -117,17 +117,17 @@ export function BrowserToolView({
}
}
} else if (innerContentString && typeof innerContentString === "object") {
screenshotUrl = (() => {
if (!innerContentString) return null;
if (!("tool_execution" in innerContentString)) return null;
if (!("result" in innerContentString.tool_execution)) return null;
if (!("output" in innerContentString.tool_execution.result)) return null;
if (!("image_url" in innerContentString.tool_execution.result.output)) return null;
if (typeof innerContentString.tool_execution.result.output.image_url !== "string") return null;
return innerContentString.tool_execution.result.output.image_url;
})()
}
screenshotUrl = (() => {
if (!innerContentString) return null;
if (!("tool_execution" in innerContentString)) return null;
if (!("result" in innerContentString.tool_execution)) return null;
if (!("output" in innerContentString.tool_execution.result)) return null;
if (!("image_url" in innerContentString.tool_execution.result.output)) return null;
if (typeof innerContentString.tool_execution.result.output.image_url !== "string") return null;
return innerContentString.tool_execution.result.output.image_url;
})()
}
} catch (error) {
}
@ -139,7 +139,7 @@ export function BrowserToolView({
);
if (browserStateMessage) {
const browserStateContent = safeJsonParse<{
const browserStateContent = safeJsonParse<{
screenshot_base64?: string;
image_url?: string;
}>(
@ -266,11 +266,11 @@ export function BrowserToolView({
};
return (
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
<div className="flex flex-row items-center justify-between">
<div className="flex items-center gap-2">
<div className="relative p-2 rounded-lg bg-gradient-to-br from-purple-500/20 to-purple-600/10 border border-purple-500/20">
<div className="relative p-2 rounded-lg bg-gradient-to-br from-purple-500/20 to-purple-600/10 border border-purple-500/20">
<MonitorPlay className="w-5 h-5 text-purple-500 dark:text-purple-400" />
</div>
<div>
@ -279,13 +279,13 @@ export function BrowserToolView({
</CardTitle>
</div>
</div>
{!isRunning && (
<Badge
variant="secondary"
<Badge
variant="secondary"
className={
isSuccess
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
isSuccess
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
: "bg-gradient-to-b from-rose-200 to-rose-100 text-rose-700 dark:from-rose-800/50 dark:to-rose-900/60 dark:text-rose-300"
}
>
@ -339,9 +339,9 @@ export function BrowserToolView({
</h3>
{url && (
<div className="mt-4">
<Button
variant="outline"
size="sm"
<Button
variant="outline"
size="sm"
className="bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-700 shadow-sm hover:shadow-md transition-shadow"
asChild
>
@ -355,52 +355,52 @@ export function BrowserToolView({
</div>
)
) :
(screenshotUrl || screenshotBase64) ? (
<div className="flex items-center justify-center w-full h-full overflow-auto relative p-4">
{imageLoading && (
<ImageLoader />
)}
<Card className={`p-0 overflow-hidden border ${imageLoading ? 'hidden' : 'block'}`}>
{screenshotUrl ? (
<img
src={screenshotUrl}
alt="Browser Screenshot"
className="max-w-full max-h-full object-contain"
onLoad={handleImageLoad}
onError={handleImageError}
/>
) : (
<img
src={`data:image/jpeg;base64,${screenshotBase64}`}
alt="Browser Screenshot"
className="max-w-full max-h-full object-contain"
onLoad={handleImageLoad}
onError={handleImageError}
/>
(screenshotUrl || screenshotBase64) ? (
<div className="flex items-center justify-center w-full h-full overflow-auto relative p-4">
{imageLoading && (
<ImageLoader />
)}
</Card>
{imageError && !imageLoading && (
<div className="absolute inset-0 flex items-center justify-center bg-zinc-50 dark:bg-zinc-900">
<div className="text-center text-zinc-500 dark:text-zinc-400">
<AlertTriangle className="h-8 w-8 mx-auto mb-2" />
<p>Failed to load screenshot</p>
<Card className={`p-0 overflow-hidden border ${imageLoading ? 'hidden' : 'block'}`}>
{screenshotUrl ? (
<img
src={screenshotUrl}
alt="Browser Screenshot"
className="max-w-full max-h-full object-contain"
onLoad={handleImageLoad}
onError={handleImageError}
/>
) : (
<img
src={`data:image/jpeg;base64,${screenshotBase64}`}
alt="Browser Screenshot"
className="max-w-full max-h-full object-contain"
onLoad={handleImageLoad}
onError={handleImageError}
/>
)}
</Card>
{imageError && !imageLoading && (
<div className="absolute inset-0 flex items-center justify-center bg-zinc-50 dark:bg-zinc-900">
<div className="text-center text-zinc-500 dark:text-zinc-400">
<AlertTriangle className="h-8 w-8 mx-auto mb-2" />
<p>Failed to load screenshot</p>
</div>
</div>
</div>
)}
</div>
) : (
<div className="p-8 h-full flex flex-col items-center justify-center w-full bg-gradient-to-b from-white to-zinc-50 dark:from-zinc-950 dark:to-zinc-900 text-zinc-700 dark:text-zinc-400">
<div className="w-20 h-20 rounded-full flex items-center justify-center mb-6 bg-gradient-to-b from-zinc-100 to-zinc-50 shadow-inner dark:from-zinc-800/40 dark:to-zinc-900/60">
<MonitorPlay className="h-10 w-10 text-zinc-400 dark:text-zinc-600" />
)}
</div>
<h3 className="text-xl font-semibold mb-2 text-zinc-900 dark:text-zinc-100">
No Browser State Available
</h3>
<p className="text-sm text-zinc-500 dark:text-zinc-400">
Browser state image not found for this action
</p>
</div>
)}
) : (
<div className="p-8 h-full flex flex-col items-center justify-center w-full bg-gradient-to-b from-white to-zinc-50 dark:from-zinc-950 dark:to-zinc-900 text-zinc-700 dark:text-zinc-400">
<div className="w-20 h-20 rounded-full flex items-center justify-center mb-6 bg-gradient-to-b from-zinc-100 to-zinc-50 shadow-inner dark:from-zinc-800/40 dark:to-zinc-900/60">
<MonitorPlay className="h-10 w-10 text-zinc-400 dark:text-zinc-600" />
</div>
<h3 className="text-xl font-semibold mb-2 text-zinc-900 dark:text-zinc-100">
No Browser State Available
</h3>
<p className="text-sm text-zinc-500 dark:text-zinc-400">
Browser state image not found for this action
</p>
</div>
)}
</div>
</CardContent>
@ -418,7 +418,7 @@ export function BrowserToolView({
</span>
)}
</div>
<div className="text-xs text-zinc-500 dark:text-zinc-400">
{toolTimestamp && !isRunning
? formatTimestamp(toolTimestamp)

View File

@ -126,7 +126,7 @@ export function CompleteToolView({
};
return (
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
<div className="flex flex-row items-center justify-between">
<div className="flex items-center gap-2">
@ -187,7 +187,7 @@ export function CompleteToolView({
{/* Summary Section */}
{completeData.summary && (
<div className="space-y-2">
<div className="bg-muted/50 rounded-lg p-4 border border-border">
<div className="bg-muted/50 rounded-2xl p-4 border border-border">
<Markdown className="text-sm prose prose-sm dark:prose-invert chat-markdown max-w-none [&>:first-child]:mt-0 prose-headings:mt-3">
{completeData.summary}
</Markdown>

View File

@ -133,7 +133,7 @@ export function DeployToolView({
}, [deployResult?.output]);
return (
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
<div className="flex flex-row items-center justify-between">
<div className="flex items-center gap-2">
@ -223,7 +223,7 @@ export function DeployToolView({
{/* Terminal Output */}
{cleanOutput.length > 0 && (
<div className="bg-zinc-100 dark:bg-neutral-900 rounded-lg overflow-hidden border border-zinc-200/20">
<div className="bg-zinc-200 dark:bg-zinc-800 px-4 py-2 flex items-center gap-2">
<div className="bg-accent px-4 py-2 flex items-center gap-2">
<TerminalIcon className="h-4 w-4 text-zinc-600 dark:text-zinc-400" />
<span className="text-sm font-medium text-zinc-700 dark:text-zinc-300">
Deployment Log
@ -259,7 +259,7 @@ export function DeployToolView({
{/* Raw Error Output */}
{rawContent && (
<div className="bg-zinc-100 dark:bg-neutral-900 rounded-lg overflow-hidden border border-zinc-200/20">
<div className="bg-zinc-200 dark:bg-zinc-800 px-4 py-2 flex items-center gap-2">
<div className="bg-accent px-4 py-2 flex items-center gap-2">
<TerminalIcon className="h-4 w-4 text-zinc-600 dark:text-zinc-400" />
<span className="text-sm font-medium text-zinc-700 dark:text-zinc-300">
Error Details

View File

@ -129,7 +129,7 @@ export function GenericToolView({
);
return (
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
<div className="flex flex-row items-center justify-between">
<div className="flex items-center gap-2">

View File

@ -115,7 +115,7 @@ export function WebCrawlToolView({
const copyContent = async () => {
if (!webpageContent?.text) return;
try {
await navigator.clipboard.writeText(webpageContent.text);
setCopiedContent(true);
@ -129,34 +129,34 @@ export function WebCrawlToolView({
const wordCount = content.trim().split(/\s+/).length;
const charCount = content.length;
const lineCount = content.split('\n').length;
return { wordCount, charCount, lineCount };
};
const contentStats = webpageContent?.text ? getContentStats(webpageContent.text) : null;
return (
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
<div className="flex flex-row items-center justify-between">
<div className="flex items-center gap-2">
<div className="relative p-2 rounded-lg bg-gradient-to-br from-primary/20 to-primary/10 border border-primary/20">
<Globe className="w-5 h-5 text-primary" />
</div>
<div>
<CardTitle className="text-base font-medium text-zinc-900 dark:text-zinc-100">
{toolTitle}
</CardTitle>
</div>
</div>
{!isStreaming && (
<Badge
<Badge
variant="secondary"
className={
isSuccess
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
isSuccess
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
: "bg-gradient-to-b from-rose-200 to-rose-100 text-rose-700 dark:from-rose-800/50 dark:to-rose-900/60 dark:text-rose-300"
}
>
@ -201,21 +201,21 @@ export function WebCrawlToolView({
<div className="group relative">
<div className="flex items-center gap-3 p-4 bg-zinc-50 dark:bg-zinc-900 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors rounded-xl border border-zinc-200 dark:border-zinc-800">
{favicon && (
<img
src={favicon}
alt=""
<img
src={favicon}
alt=""
className="w-6 h-6 rounded-md flex-shrink-0"
onError={(e) => {
(e.target as HTMLImageElement).style.display = 'none';
}}
}}
/>
)}
<div className="flex-1 min-w-0">
<p className="font-mono text-sm text-zinc-900 dark:text-zinc-100 truncate">{truncateString(url, 70)}</p>
<p className="text-xs text-zinc-500 dark:text-zinc-400 mt-1">{domain}</p>
</div>
<Button
variant="ghost"
<Button
variant="ghost"
size="sm"
className="opacity-70 group-hover:opacity-100 transition-opacity"
asChild
@ -266,7 +266,7 @@ export function WebCrawlToolView({
)}
</div>
</div>
<div className="flex items-center gap-1">
<TooltipProvider>
<Tooltip>
@ -332,7 +332,7 @@ export function WebCrawlToolView({
</div>
)}
</CardContent>
{/* Footer */}
<div className="px-4 py-2 h-10 bg-gradient-to-r from-zinc-50/90 to-zinc-100/90 dark:from-zinc-900/90 dark:to-zinc-800/90 backdrop-blur-sm border-t border-zinc-200 dark:border-zinc-800 flex justify-between items-center gap-4">
<div className="h-full flex items-center gap-2 text-sm text-zinc-500 dark:text-zinc-400">
@ -343,7 +343,7 @@ export function WebCrawlToolView({
</Badge>
)}
</div>
<div className="text-xs text-zinc-500 dark:text-zinc-400">
{toolTimestamp && !isStreaming
? formatTimestamp(toolTimestamp)

View File

@ -70,11 +70,11 @@ export function AskToolView({
};
return (
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
<div className="flex flex-row items-center justify-between">
<div className="flex items-center gap-2">
<div className="relative p-2 rounded-lg bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20">
<div className="relative p-2 rounded-xl bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20">
<MessageCircleQuestion className="w-5 h-5 text-blue-500 dark:text-blue-400" />
</div>
<div>

View File

@ -89,7 +89,7 @@ export function CommandToolView({
const linesToShow = showFullOutput ? formattedOutput : previewLines;
return (
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
<div className="flex flex-row items-center justify-between">
<div className="flex items-center gap-2">

View File

@ -51,7 +51,7 @@ export function TerminateCommandToolView({
const rawSessionName = React.useMemo(() => {
if (sessionName) return sessionName;
if (!assistantContent) return null;
const contentStr = normalizeContentToString(assistantContent);
@ -82,24 +82,24 @@ export function TerminateCommandToolView({
const finalSessionName = rawSessionName?.trim() || sessionName;
const toolTitle = getToolTitle(name) || 'Terminate Session';
const terminationSuccess = React.useMemo(() => {
if (!output) return false;
const outputLower = output.toLowerCase();
if (outputLower.includes('does not exist')) return false;
if (outputLower.includes('terminated') || outputLower.includes('killed')) return true;
if (typeof toolContent === 'string') {
const toolResultMatch = toolContent.match(/ToolResult\(success=(true|false)/i);
if (toolResultMatch) {
return toolResultMatch[1].toLowerCase() === 'true';
}
}
return actualIsSuccess;
}, [output, actualIsSuccess, toolContent]);
useEffect(() => {
if (isStreaming) {
const timer = setInterval(() => {
@ -129,16 +129,16 @@ export function TerminateCommandToolView({
}
} catch (e) {
}
processedOutput = String(processedOutput);
processedOutput = processedOutput.replace(/\\\\/g, '\\');
processedOutput = processedOutput
.replace(/\\n/g, '\n')
.replace(/\\t/g, '\t')
.replace(/\\"/g, '"')
.replace(/\\'/g, "'");
processedOutput = processedOutput.replace(/\\u([0-9a-fA-F]{4})/g, (match, group) => {
return String.fromCharCode(parseInt(group, 16));
});
@ -150,7 +150,7 @@ export function TerminateCommandToolView({
const linesToShow = showFullOutput ? formattedOutput : previewLines;
return (
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
<div className="flex flex-row items-center justify-between">
<div className="flex items-center gap-2">
@ -163,13 +163,13 @@ export function TerminateCommandToolView({
</CardTitle>
</div>
</div>
{!isStreaming && (
<Badge
variant="secondary"
<Badge
variant="secondary"
className={
terminationSuccess
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
terminationSuccess
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
: "bg-gradient-to-b from-rose-200 to-rose-100 text-rose-700 dark:from-rose-800/50 dark:to-rose-900/60 dark:text-rose-300"
}
>
@ -222,18 +222,18 @@ export function TerminateCommandToolView({
<ArrowRight className="h-4 w-4 mr-2 text-zinc-500 dark:text-zinc-400" />
Result
</h3>
<Badge
<Badge
className={cn(
"ml-2",
terminationSuccess
? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400"
terminationSuccess
? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400"
: "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400"
)}
>
{terminationSuccess ? 'Success' : 'Failed'}
</Badge>
</div>
<div className="bg-zinc-100 dark:bg-neutral-900 rounded-lg overflow-hidden border border-zinc-200/20">
<div className="bg-zinc-300 dark:bg-neutral-800 flex items-center justify-between dark:border-zinc-700/50">
<div className="bg-zinc-200 w-full dark:bg-zinc-800 px-4 py-2 flex items-center gap-2">
@ -250,8 +250,8 @@ export function TerminateCommandToolView({
<div className="p-4 max-h-96 overflow-auto scrollbar-hide">
<pre className="text-xs text-zinc-600 dark:text-zinc-300 font-mono whitespace-pre-wrap break-all overflow-visible">
{linesToShow.map((line, index) => (
<div
key={index}
<div
key={index}
className="py-0.5 bg-transparent"
>
{line || ' '}
@ -267,7 +267,7 @@ export function TerminateCommandToolView({
</div>
</div>
)}
{!output && !isStreaming && (
<div className="bg-black rounded-lg overflow-hidden border border-zinc-700/20 shadow-md p-6 flex items-center justify-center">
<div className="text-center">
@ -292,7 +292,7 @@ export function TerminateCommandToolView({
</div>
)}
</CardContent>
<div className="px-4 py-2 h-10 bg-gradient-to-r from-zinc-50/90 to-zinc-100/90 dark:from-zinc-900/90 dark:to-zinc-800/90 backdrop-blur-sm border-t border-zinc-200 dark:border-zinc-800 flex justify-between items-center gap-4">
<div className="h-full flex items-center gap-2 text-sm text-zinc-500 dark:text-zinc-400">
{!isStreaming && finalSessionName && (
@ -302,7 +302,7 @@ export function TerminateCommandToolView({
</Badge>
)}
</div>
<div className="text-xs text-zinc-500 dark:text-zinc-400 flex items-center gap-2">
<Clock className="h-3.5 w-3.5" />
{actualToolTimestamp && !isStreaming

View File

@ -74,7 +74,7 @@ export function DataProviderEndpointsToolView({
isSuccess = true,
isStreaming = false,
}: ToolViewProps) {
const {
serviceName,
endpoints,
@ -89,19 +89,19 @@ export function DataProviderEndpointsToolView({
assistantTimestamp
);
const providerConfig = serviceName && PROVIDER_CONFIG[serviceName]
? PROVIDER_CONFIG[serviceName]
const providerConfig = serviceName && PROVIDER_CONFIG[serviceName]
? PROVIDER_CONFIG[serviceName]
: PROVIDER_CONFIG['linkedin'];
const IconComponent = providerConfig.icon;
const endpointCount = endpoints && typeof endpoints === 'object' ? Object.keys(endpoints).length : 0;
return (
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
<div className="flex flex-row items-center justify-between">
<div className="flex items-center gap-2">
<div className="relative p-2 rounded-lg bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20">
<div className="relative p-2 rounded-xl bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20">
<Globe className="w-5 h-5 text-blue-500 dark:text-blue-400" />
</div>
<div>
@ -110,14 +110,14 @@ export function DataProviderEndpointsToolView({
</CardTitle>
</div>
</div>
{!isStreaming && (
<Badge
variant="secondary"
<Badge
variant="secondary"
className={cn(
"text-xs font-medium",
actualIsSuccess
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
actualIsSuccess
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
: "bg-red-50 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800"
)}
>
@ -157,7 +157,7 @@ export function DataProviderEndpointsToolView({
)}>
<IconComponent className="h-6 w-6 text-white drop-shadow-sm" />
</div>
<div className="flex-1">
<h3 className="text-lg font-semibold text-zinc-900 dark:text-zinc-100">
{providerConfig.name}
@ -166,13 +166,13 @@ export function DataProviderEndpointsToolView({
{endpointCount > 0 ? `${endpointCount} endpoints loaded and ready` : 'Endpoints loaded and ready'}
</p>
</div>
<Badge
variant="secondary"
<Badge
variant="secondary"
className={cn(
"text-xs font-medium",
actualIsSuccess
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
actualIsSuccess
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
: "bg-red-50 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800"
)}
>
@ -198,12 +198,12 @@ export function DataProviderEndpointsToolView({
Connection Status
</span>
</div>
<Badge
variant="secondary"
<Badge
variant="secondary"
className={cn(
"text-xs font-medium",
actualIsSuccess
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
actualIsSuccess
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
: "bg-red-50 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800"
)}
>
@ -215,7 +215,7 @@ export function DataProviderEndpointsToolView({
{actualIsSuccess ? 'Active' : 'Inactive'}
</Badge>
</div>
<div className="flex items-center justify-between p-3 bg-white dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800">
<div className="flex items-center gap-3">
<div className="w-2 h-2 rounded-full bg-blue-500"></div>
@ -227,7 +227,7 @@ export function DataProviderEndpointsToolView({
{endpointCount > 0 ? `${endpointCount} endpoints` : 'Ready'}
</Badge>
</div>
<div className="flex items-center justify-between p-3 bg-white dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800">
<div className="flex items-center gap-3">
<div className="w-2 h-2 rounded-full bg-purple-500"></div>
@ -257,7 +257,7 @@ export function DataProviderEndpointsToolView({
</div>
)}
</CardContent>
<div className="px-4 py-2 h-10 bg-zinc-50/50 dark:bg-zinc-900/50 backdrop-blur-sm border-t border-zinc-200 dark:border-zinc-800 flex justify-between items-center gap-4">
<div className="h-full flex items-center gap-2 text-sm text-zinc-500 dark:text-zinc-400">
{!isStreaming && (
@ -267,7 +267,7 @@ export function DataProviderEndpointsToolView({
</Badge>
)}
</div>
<div className="text-xs text-zinc-500 dark:text-zinc-400">
{actualToolTimestamp && !isStreaming
? formatTimestamp(actualToolTimestamp)

View File

@ -32,7 +32,7 @@ const PROVIDER_CONFIG = {
borderColor: 'border-blue-200 dark:border-blue-800'
},
'twitter': {
name: 'Twitter Data Provider',
name: 'Twitter Data Provider',
icon: MessageCircle,
color: 'from-sky-400 to-sky-500',
bgColor: 'bg-sky-50 dark:bg-sky-900/20',
@ -82,7 +82,7 @@ export function ExecuteDataProviderCallToolView({
isSuccess = true,
isStreaming = false,
}: ToolViewProps) {
const {
serviceName,
route,
@ -100,18 +100,18 @@ export function ExecuteDataProviderCallToolView({
);
const providerKey = serviceName?.toLowerCase() as keyof typeof PROVIDER_CONFIG;
const providerConfig = providerKey && PROVIDER_CONFIG[providerKey]
? PROVIDER_CONFIG[providerKey]
const providerConfig = providerKey && PROVIDER_CONFIG[providerKey]
? PROVIDER_CONFIG[providerKey]
: PROVIDER_CONFIG['linkedin'];
const IconComponent = providerConfig.icon;
return (
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
<div className="flex flex-row items-center justify-between">
<div className="flex items-center gap-2">
<div className="relative p-2 rounded-lg bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20">
<div className="relative p-2 rounded-xl bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20">
<Globe className="w-5 h-5 text-blue-500 dark:text-blue-400" />
</div>
<div>
@ -120,14 +120,14 @@ export function ExecuteDataProviderCallToolView({
</CardTitle>
</div>
</div>
{!isStreaming && (
<Badge
variant="secondary"
<Badge
variant="secondary"
className={cn(
"text-xs font-medium",
actualIsSuccess
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
actualIsSuccess
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
: "bg-red-50 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800"
)}
>
@ -167,7 +167,7 @@ export function ExecuteDataProviderCallToolView({
)}>
<IconComponent className="h-6 w-6 text-white drop-shadow-sm" />
</div>
<div className="flex-1">
<h3 className="text-lg font-semibold text-zinc-900 dark:text-zinc-100">
{providerConfig.name}
@ -178,7 +178,7 @@ export function ExecuteDataProviderCallToolView({
</p>
)}
</div>
{route && (
<Badge variant="outline" className="text-xs font-mono">
{route}
@ -209,7 +209,7 @@ export function ExecuteDataProviderCallToolView({
</div>
<div className="grid gap-3">
{Object.entries(payload).map(([key, value]) => (
<div
<div
key={key}
className="flex items-center justify-between p-3 bg-white dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800 hover:bg-zinc-50 dark:hover:bg-zinc-800/50 transition-colors"
>
@ -231,7 +231,7 @@ export function ExecuteDataProviderCallToolView({
<span>Raw JSON</span>
<ChevronRight className="h-3 w-3 text-zinc-400 group-open:rotate-90 transition-transform" />
</summary>
<div className="mt-3 p-4 bg-zinc-900 dark:bg-zinc-950 rounded-lg border border-zinc-200 dark:border-zinc-800">
<pre className="text-xs font-mono text-emerald-400 dark:text-emerald-300 overflow-x-auto">
{JSON.stringify(payload, null, 2)}

View File

@ -35,7 +35,7 @@ export function ExposePortToolView({
assistantTimestamp,
toolTimestamp,
}: ToolViewProps) {
const {
port,
url,
@ -52,26 +52,26 @@ export function ExposePortToolView({
);
return (
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
<div className="flex flex-row items-center justify-between">
<div className="flex items-center gap-2">
<div className="relative p-2 rounded-lg bg-gradient-to-br from-green-500/20 to-green-600/10 border border-green-500/20">
<Computer className="w-5 h-5 text-green-500 dark:text-green-400" />
</div>
<div className="relative p-2 rounded-lg bg-gradient-to-br from-green-500/20 to-green-600/10 border border-green-500/20">
<Computer className="w-5 h-5 text-green-500 dark:text-green-400" />
</div>
<div>
<CardTitle className="text-base font-medium text-zinc-900 dark:text-zinc-100">
Port Exposure
</CardTitle>
</div>
</div>
{!isStreaming && (
<Badge
variant="secondary"
<Badge
variant="secondary"
className={
actualIsSuccess
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
actualIsSuccess
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
: "bg-gradient-to-b from-rose-200 to-rose-100 text-rose-700 dark:from-rose-800/50 dark:to-rose-900/60 dark:text-rose-300"
}
>
@ -88,7 +88,7 @@ export function ExposePortToolView({
<CardContent className="p-0 h-full flex-1 overflow-hidden relative">
{isStreaming ? (
<LoadingState
<LoadingState
icon={Computer}
iconColor="text-emerald-500 dark:text-emerald-400"
bgColor="bg-gradient-to-b from-emerald-100 to-emerald-50 shadow-inner dark:from-emerald-800/40 dark:to-emerald-900/60 dark:shadow-emerald-950/20"
@ -174,7 +174,7 @@ export function ExposePortToolView({
</Badge>
)}
</div>
<div className="text-xs text-zinc-500 dark:text-zinc-400">
{actualToolTimestamp && formatTimestamp(actualToolTimestamp)}
</div>

View File

@ -107,7 +107,7 @@ export function FileOperationToolView({
const processedFilePath = processFilePath(filePath);
const fileName = getFileName(processedFilePath);
const fileExtension = getFileExtension(fileName);
const isMarkdown = isFileType.markdown(fileExtension);
const isHtml = isFileType.html(fileExtension);
const isCsv = isFileType.csv(fileExtension);
@ -269,7 +269,7 @@ export function FileOperationToolView({
};
return (
<Card className="flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
<Card className="flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<Tabs defaultValue={'preview'} className="w-full h-full">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2 mb-0">
<div className="flex flex-row items-center justify-between">

View File

@ -6,9 +6,9 @@ import { ScrollArea } from '@/components/ui/scroll-area';
import { Card } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
Search, Database, FileText, Link2, Key, AlertTriangle,
Copy, Globe, FileCode, Table, BookOpen, ExternalLink
import {
Search, Database, FileText, Link2, Key, AlertTriangle,
Copy, Globe, FileCode, Table, BookOpen, ExternalLink
} from 'lucide-react';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import { cn } from '@/lib/utils';
@ -39,12 +39,12 @@ function SearchResultsRenderer({ data, metadata }: { data: any; metadata?: any }
// Normalize search results from various formats
const normalizeResults = (data: any): SearchResult[] => {
let items: any[] = [];
if (data?.results) items = data.results;
else if (data?.data) items = data.data;
else if (Array.isArray(data)) items = data;
else return [];
return items.map((item, index) => ({
...item,
url: item.url || item.link || item.href,
@ -53,10 +53,10 @@ function SearchResultsRenderer({ data, metadata }: { data: any; metadata?: any }
title: item.title || item.name || `Result ${index + 1}`
})).filter(item => item.title || item.url);
};
const results = normalizeResults(data);
const meta = metadata || data;
return (
<div className="p-3">
<div className="flex items-center justify-between mb-4">
@ -72,18 +72,18 @@ function SearchResultsRenderer({ data, metadata }: { data: any; metadata?: any }
</div>
)}
</div>
{(meta?.autopromptString || meta?.query) && (
<div className="mb-4 p-2 bg-zinc-50 dark:bg-zinc-900 rounded text-xs text-zinc-600 dark:text-zinc-400">
<span className="font-medium">Query: </span>
<span className="italic">{meta.autopromptString || meta.query}</span>
</div>
)}
<ScrollArea className="max-h-96">
<div className="space-y-3">
{results.map((result, idx) => (
<Card key={idx} className="p-3 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 hover:border-zinc-300 dark:hover:border-zinc-600 transition-colors">
<Card key={idx} className="p-3 bg-card border border-zinc-200 dark:border-zinc-700 hover:border-zinc-300 dark:hover:border-zinc-600 transition-colors">
<div className="space-y-2">
<div className="flex items-start gap-2">
<Badge variant="outline" className="text-xs shrink-0 mt-0.5">
@ -95,8 +95,8 @@ function SearchResultsRenderer({ data, metadata }: { data: any; metadata?: any }
</h4>
</div>
{result.image && (
<img
src={result.image}
<img
src={result.image}
alt=""
className="w-16 h-12 object-cover rounded border border-zinc-200 dark:border-zinc-700"
onError={(e) => {
@ -105,7 +105,7 @@ function SearchResultsRenderer({ data, metadata }: { data: any; metadata?: any }
/>
)}
</div>
{(result.author || result.date) && (
<div className="flex items-center gap-2 text-xs text-zinc-500 dark:text-zinc-400">
{result.author && <span>By {result.author}</span>}
@ -114,12 +114,12 @@ function SearchResultsRenderer({ data, metadata }: { data: any; metadata?: any }
)}
</div>
)}
{result.url && (
<div className="flex items-center gap-1.5 text-xs">
{result.favicon && (
<img
src={result.favicon}
<img
src={result.favicon}
alt=""
className="w-4 h-4"
onError={(e) => {
@ -128,9 +128,9 @@ function SearchResultsRenderer({ data, metadata }: { data: any; metadata?: any }
/>
)}
<Globe className="h-3 w-3 text-zinc-500" />
<a
href={result.url}
target="_blank"
<a
href={result.url}
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 dark:text-blue-400 hover:underline truncate flex-1"
>
@ -155,7 +155,7 @@ function SearchResultsRenderer({ data, metadata }: { data: any; metadata?: any }
</TooltipProvider>
</div>
)}
{result.summary && (
<p className="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
{result.summary}
@ -174,9 +174,9 @@ function SearchResultsRenderer({ data, metadata }: { data: any; metadata?: any }
function TableRenderer({ data }: { data: any }) {
const renderAsTable = (items: any[]) => {
if (!items.length) return null;
const headers = Object.keys(items[0]);
return (
<div className="p-3">
<div className="flex items-center gap-2 mb-3">
@ -212,11 +212,11 @@ function TableRenderer({ data }: { data: any }) {
</div>
);
};
if (Array.isArray(data)) {
return renderAsTable(data);
}
return <JsonRenderer data={data} />;
}
@ -246,7 +246,7 @@ function KeyValueRenderer({ content }: { content: string }) {
const [key, ...valueParts] = line.split(':');
return { key: key.trim(), value: valueParts.join(':').trim() };
});
return (
<div className="p-3">
<div className="flex items-center gap-2 mb-3">
@ -274,7 +274,7 @@ function KeyValueRenderer({ content }: { content: string }) {
// Renderer for URL lists
function UrlListRenderer({ content }: { content: string }) {
const urls = content.match(/https?:\/\/\S+/g) || [];
return (
<div className="p-3">
<div className="flex items-center gap-2 mb-3">
@ -287,9 +287,9 @@ function UrlListRenderer({ content }: { content: string }) {
{urls.map((url, idx) => (
<div key={idx} className="flex items-center gap-2">
<ExternalLink className="h-3 w-3 text-zinc-500" />
<a
href={url}
target="_blank"
<a
href={url}
target="_blank"
rel="noopener noreferrer"
className="text-xs text-blue-600 dark:text-blue-400 hover:underline truncate"
>
@ -337,21 +337,21 @@ function TextRenderer({ content }: { content: string }) {
// Main renderer component
export function MCPContentRenderer({ detectionResult, rawContent }: MCPContentRendererProps) {
const { format, confidence, metadata, parsedData } = detectionResult;
// Convert content to string if needed
const contentStr = typeof rawContent === 'string' ? rawContent : JSON.stringify(rawContent, null, 2);
// Select appropriate renderer based on detected format
switch (format) {
case ContentFormat.SEARCH_RESULTS:
return <SearchResultsRenderer data={parsedData || rawContent} metadata={metadata} />;
case ContentFormat.TABLE:
return <TableRenderer data={parsedData || rawContent} />;
case ContentFormat.JSON:
return <JsonRenderer data={parsedData || rawContent} />;
case ContentFormat.MARKDOWN:
return (
<div className="p-3">
@ -364,19 +364,19 @@ export function MCPContentRenderer({ detectionResult, rawContent }: MCPContentRe
<MarkdownRenderer content={contentStr} />
</div>
);
case ContentFormat.CSV:
return <CsvRenderer content={contentStr} />;
case ContentFormat.KEY_VALUE:
return <KeyValueRenderer content={contentStr} />;
case ContentFormat.URL_LIST:
return <UrlListRenderer content={contentStr} />;
case ContentFormat.ERROR:
return <ErrorRenderer content={contentStr} />;
case ContentFormat.CODE:
return (
<div className="p-3">
@ -393,7 +393,7 @@ export function MCPContentRenderer({ detectionResult, rawContent }: MCPContentRe
</ScrollArea>
</div>
);
default:
return <TextRenderer content={contentStr} />;
}

View File

@ -20,10 +20,10 @@ import { ScrollArea } from "@/components/ui/scroll-area";
import { formatTimestamp } from '../utils';
import { detectMCPFormat } from '../mcp-format-detector';
import { MCPContentRenderer } from '../mcp-content-renderer';
import {
parseMCPResult,
parseMCPToolCall,
getMCPServerIcon,
import {
parseMCPResult,
parseMCPToolCall,
getMCPServerIcon,
getMCPServerColor,
formatMCPToolDisplayName,
MCPResult,
@ -46,16 +46,16 @@ export function McpToolView({
const parsedTool = parseMCPToolCall(assistantContent || '');
const result = toolContent ? parseMCPResult(toolContent) : null;
const serverName = result?.mcp_metadata?.server_name || parsedTool.serverName;
const toolName = result?.mcp_metadata?.tool_name || parsedTool.toolName;
const fullToolName = result?.mcp_metadata?.full_tool_name || parsedTool.fullToolName;
const argumentsCount = result?.mcp_metadata?.arguments_count ?? Object.keys(parsedTool.arguments).length;
const displayName = result?.mcp_metadata ?
const displayName = result?.mcp_metadata ?
formatMCPToolDisplayName(serverName, toolName) :
parsedTool.displayName;
const ServerIcon = getMCPServerIcon(serverName);
const serverColor = getMCPServerColor(serverName);
@ -79,7 +79,7 @@ export function McpToolView({
const hasArguments = Object.keys(parsedTool.arguments).length > 0;
return (
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
<div className="flex flex-row items-center justify-between">
<div className="flex items-center gap-3">
@ -101,13 +101,13 @@ export function McpToolView({
</p>
</div>
</div>
{!isStreaming && (
<Badge
variant="secondary"
<Badge
variant="secondary"
className={
isSuccess && result && !result.isError
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
: "bg-gradient-to-b from-rose-200 to-rose-100 text-rose-700 dark:from-rose-800/50 dark:to-rose-900/60 dark:text-rose-300"
}
>
@ -149,7 +149,7 @@ export function McpToolView({
) : (
<ScrollArea className="h-full w-full">
<div className="p-4 space-y-4">
{/* Tool Information */}
<div className="bg-zinc-50/70 dark:bg-zinc-900/30 p-4 rounded-lg border border-zinc-100 dark:border-zinc-800">
<div className="flex items-center gap-2 mb-3">
@ -187,7 +187,7 @@ export function McpToolView({
</span>
</div>
</div>
{/* Show error type if available */}
{result?.error_type && (
<div className="mt-3 pt-3 border-t border-zinc-200 dark:border-zinc-700">
@ -208,7 +208,7 @@ export function McpToolView({
? "border-emerald-200 dark:border-emerald-800 bg-emerald-50/30 dark:bg-emerald-900/10"
: "border-red-200 dark:border-red-800 bg-red-50/30 dark:bg-red-900/10"
)}>
<div
<div
className="p-3 cursor-pointer hover:bg-black/5 dark:hover:bg-white/5 transition-colors"
onClick={() => setExpandedResult(!expandedResult)}
>
@ -237,10 +237,10 @@ export function McpToolView({
)}
</div>
</div>
{expandedResult && (
<div className="border-t border-zinc-200 dark:border-zinc-800">
<MCPContentRenderer
<MCPContentRenderer
detectionResult={detectMCPFormat(result.data || '')}
rawContent={result.data || ''}
/>

View File

@ -35,11 +35,11 @@ function SafeImage({ src, alt, filePath, className }: { src: string; alt: string
'Authorization': `Bearer ${session?.access_token}`
}
});
if (!response.ok) {
throw new Error(`Failed to load image: ${response.status} ${response.statusText}`);
}
const blob = await response.blob();
const url = URL.createObjectURL(blob);
setImgSrc(url);
@ -51,11 +51,11 @@ function SafeImage({ src, alt, filePath, className }: { src: string; alt: string
setImgSrc(src);
}
};
setupAuthenticatedImage();
setError(false);
setAttempts(0);
return () => {
if (imgSrc && imgSrc.startsWith('blob:')) {
URL.revokeObjectURL(imgSrc);
@ -67,7 +67,7 @@ function SafeImage({ src, alt, filePath, className }: { src: string; alt: string
if (attempts < 3) {
setAttempts(attempts + 1);
console.log(`Image load failed (attempt ${attempts + 1}). Trying alternative:`, filePath);
if (attempts === 0) {
setImgSrc(filePath);
} else if (attempts === 1) {
@ -103,7 +103,7 @@ function SafeImage({ src, alt, filePath, className }: { src: string; alt: string
const handleDownload = (e: React.MouseEvent) => {
e.stopPropagation();
if (!imgSrc) return;
const link = document.createElement('a');
link.href = imgSrc;
link.download = filePath.split('/').pop() || 'image';
@ -146,7 +146,7 @@ function SafeImage({ src, alt, filePath, className }: { src: string; alt: string
return (
<div className="flex flex-col items-center">
<div className={cn(
"overflow-hidden transition-all duration-300 rounded-lg border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 mb-3",
"overflow-hidden transition-all duration-300 rounded-3xl border bg-card mb-3",
isZoomed ? "cursor-zoom-out" : "cursor-zoom-in"
)}>
<div className="relative flex items-center justify-center">
@ -156,8 +156,8 @@ function SafeImage({ src, alt, filePath, className }: { src: string; alt: string
onClick={handleZoomToggle}
className={cn(
"max-w-full object-contain transition-all duration-300 ease-in-out",
isZoomed
? "max-h-[80vh]"
isZoomed
? "max-h-[80vh]"
: "max-h-[500px] hover:scale-[1.01]",
className
)}
@ -169,12 +169,12 @@ function SafeImage({ src, alt, filePath, className }: { src: string; alt: string
</div>
</div>
<div className="flex items-center justify-between w-full px-2 py-2 bg-zinc-50 dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800">
<div className="flex items-center justify-between w-full px-2 py-2 bg-zinc-50 dark:bg-zinc-900 rounded-2xl border border-zinc-200 dark:border-zinc-800">
<Badge variant="secondary" className="bg-white/90 dark:bg-black/70 text-zinc-700 dark:text-zinc-300 shadow-sm">
<ImageIcon className="h-3 w-3 mr-1" />
{filePath.split('.').pop()?.toUpperCase()}
</Badge>
<div className="flex items-center gap-1">
<Button
variant="outline"
@ -197,9 +197,9 @@ function SafeImage({ src, alt, filePath, className }: { src: string; alt: string
>
<ZoomIn className="h-4 w-4" />
</Button>
<span className="w-px h-6 bg-zinc-200 dark:bg-zinc-700 mx-2"></span>
<Button
variant="outline"
size="icon"
@ -226,7 +226,7 @@ export function SeeImageToolView({
project,
}: ToolViewProps) {
const [progress, setProgress] = useState(0);
const {
filePath,
description,
@ -241,7 +241,7 @@ export function SeeImageToolView({
toolTimestamp,
assistantTimestamp
);
console.log('Final file path:', filePath);
useEffect(() => {
@ -289,11 +289,11 @@ export function SeeImageToolView({
const isAnimated = ['gif', 'webp'].includes(fileExt.toLowerCase());
return (
<Card className="flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
<Card className="flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-gradient-to-r from-zinc-50/90 to-zinc-100/90 dark:from-zinc-900/90 dark:to-zinc-800/90 backdrop-blur-sm border-b p-2 px-4 space-y-0">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<div className={cn("relative p-2 rounded-lg bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20 transition-colors", config.bgColor)}>
<div className={cn("relative p-2 rounded-xl bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20 transition-colors", config.bgColor)}>
<ImageIcon className={cn("w-5 h-5", config.color)} />
</div>
<div>
@ -309,13 +309,13 @@ export function SeeImageToolView({
</div>
</div>
</div>
{!isStreaming ? (
<Badge variant="secondary" className={cn(
"px-2.5 py-1 transition-colors flex items-center gap-1.5",
actualIsSuccess
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
: "bg-gradient-to-b from-rose-200 to-rose-100 text-rose-700 dark:from-rose-800/50 dark:to-rose-900/60 dark:text-rose-300"
"px-2.5 py-1 transition-colors flex items-center gap-1.5",
actualIsSuccess
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
: "bg-gradient-to-b from-rose-200 to-rose-100 text-rose-700 dark:from-rose-800/50 dark:to-rose-900/60 dark:text-rose-300"
)}>
{actualIsSuccess ? (
<>
@ -337,7 +337,7 @@ export function SeeImageToolView({
)}
</div>
</CardHeader>
<CardContent className="p-0 flex-1 overflow-hidden relative">
{isStreaming ? (
<div className="flex flex-col items-center justify-center h-full p-12 bg-gradient-to-b from-white to-zinc-50 dark:from-zinc-950 dark:to-zinc-900">
@ -349,7 +349,7 @@ export function SeeImageToolView({
</div>
<Skeleton className="h-48 w-full rounded-lg mb-6" />
<div className="w-full h-2 bg-zinc-200 dark:bg-zinc-700 rounded-full overflow-hidden">
<div
<div
className="h-full bg-gradient-to-r from-blue-400 to-blue-500 dark:from-blue-600 dark:to-blue-400 rounded-full transition-all duration-300 ease-out"
style={{ width: `${progress}%` }}
></div>
@ -370,7 +370,7 @@ export function SeeImageToolView({
</div>
)}
</CardContent>
<div className="h-10 px-4 py-2 bg-gradient-to-r from-zinc-50/90 to-zinc-100/90 dark:from-zinc-900/90 dark:to-zinc-800/90 backdrop-blur-sm border-t border-zinc-200 dark:border-zinc-800 flex justify-between items-center">
<div className="flex items-center gap-2 text-sm text-zinc-500 dark:text-zinc-400">
<Badge className="py-0.5 h-6 bg-gradient-to-b from-blue-50 to-blue-100 text-blue-700 border border-blue-200/50 dark:from-blue-900/30 dark:to-blue-800/20 dark:text-blue-400 dark:border-blue-800/30">
@ -383,7 +383,7 @@ export function SeeImageToolView({
</Badge>
)}
</div>
<div className="text-xs text-zinc-500 dark:text-zinc-400">
{actualToolTimestamp && !isStreaming
? formatTimestamp(actualToolTimestamp)

View File

@ -219,7 +219,7 @@ export function StrReplaceToolView({
const shouldShowError = !isStreaming && (!oldStr || !newStr) && (assistantContent || toolContent);
return (
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
<div className="flex flex-row items-center justify-between">
<div className="flex items-center gap-2">
@ -275,7 +275,7 @@ export function StrReplaceToolView({
<ScrollArea className="h-full w-full">
<div className="p-4">
<div className="bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-lg overflow-hidden mb-4">
<div className="p-3 border-b border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900 flex items-center justify-between">
<div className="p-3 border-b border-zinc-200 dark:border-zinc-800 bg-accent flex items-center justify-between">
<div className="flex items-center">
<File className="h-4 w-4 mr-2 text-zinc-500 dark:text-zinc-400" />
<code className="text-xs font-mono text-zinc-700 dark:text-zinc-300">

View File

@ -118,7 +118,7 @@ export function WebScrapeToolView({
const timestampMatch = filePath.match(/(\d{8}_\d{6})/);
const domainMatch = filePath.match(/(\w+)_com\.json$/);
const fileName = filePath.split('/').pop() || filePath;
return {
timestamp: timestampMatch ? timestampMatch[1] : '',
domain: domainMatch ? domainMatch[1] : 'unknown',
@ -128,27 +128,27 @@ export function WebScrapeToolView({
};
return (
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
<div className="flex flex-row items-center justify-between">
<div className="flex items-center gap-2">
<div className="relative p-2 rounded-lg bg-gradient-to-br from-primary/20 to-primary/10 border border-primary/20">
<Globe className="w-5 h-5 text-primary" />
</div>
<div>
<CardTitle className="text-base font-medium text-zinc-900 dark:text-zinc-100">
{toolTitle}
</CardTitle>
</div>
</div>
{!isStreaming && (
<Badge
<Badge
variant="secondary"
className={
actualIsSuccess
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
actualIsSuccess
? "bg-gradient-to-b from-emerald-200 to-emerald-100 text-emerald-700 dark:from-emerald-800/50 dark:to-emerald-900/60 dark:text-emerald-300"
: "bg-gradient-to-b from-rose-200 to-rose-100 text-rose-700 dark:from-rose-800/50 dark:to-rose-900/60 dark:text-rose-300"
}
>
@ -193,21 +193,21 @@ export function WebScrapeToolView({
<div className="group relative">
<div className="flex items-center gap-3 p-4 bg-zinc-50 dark:bg-zinc-900 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors rounded-xl border border-zinc-200 dark:border-zinc-800">
{favicon && (
<img
src={favicon}
alt=""
<img
src={favicon}
alt=""
className="w-6 h-6 rounded-md flex-shrink-0"
onError={(e) => {
(e.target as HTMLImageElement).style.display = 'none';
}}
}}
/>
)}
<div className="flex-1 min-w-0">
<p className="font-mono text-sm text-zinc-900 dark:text-zinc-100 truncate">{truncateString(url, 70)}</p>
<p className="text-xs text-zinc-500 dark:text-zinc-400 mt-1">{domain}</p>
</div>
<Button
variant="ghost"
<Button
variant="ghost"
size="sm"
className="opacity-70 group-hover:opacity-100 transition-opacity"
asChild
@ -238,17 +238,17 @@ export function WebScrapeToolView({
{files.map((filePath, idx) => {
const fileInfo = formatFileInfo(filePath);
const isCopied = copiedFile === filePath;
return (
<div
key={idx}
<div
key={idx}
className="group relative bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-4 hover:border-zinc-300 dark:hover:border-zinc-700 transition-all duration-200 hover:shadow-sm"
>
<div className="flex items-start gap-3">
<div className="w-10 h-10 rounded-lg bg-gradient-to-br from-green-500/20 to-green-600/10 flex items-center justify-center border border-green-500/20 flex-shrink-0">
<FileText className="w-5 h-5 text-green-600 dark:text-green-400" />
</div>
<div className="flex-1 min-w-0 space-y-2">
<div className="flex items-center gap-2 flex-wrap">
<Badge variant="outline" className="text-xs font-normal">
@ -261,7 +261,7 @@ export function WebScrapeToolView({
</Badge>
)}
</div>
<div className="space-y-1">
<p className="font-mono text-sm text-zinc-900 dark:text-zinc-100 font-medium">
{fileInfo.fileName}
@ -324,7 +324,7 @@ export function WebScrapeToolView({
</div>
)}
</CardContent>
{/* Footer */}
<div className="px-4 py-2 h-10 bg-gradient-to-r from-zinc-50/90 to-zinc-100/90 dark:from-zinc-900/90 dark:to-zinc-800/90 backdrop-blur-sm border-t border-zinc-200 dark:border-zinc-800 flex justify-between items-center gap-4">
<div className="h-full flex items-center gap-2 text-sm text-zinc-500 dark:text-zinc-400">
@ -335,7 +335,7 @@ export function WebScrapeToolView({
</Badge>
)}
</div>
<div className="text-xs text-zinc-500 dark:text-zinc-400">
{actualToolTimestamp && !isStreaming
? formatTimestamp(actualToolTimestamp)

View File

@ -87,11 +87,11 @@ export function WebSearchToolView({
};
return (
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-white dark:bg-zinc-950">
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
<div className="flex flex-row items-center justify-between">
<div className="flex items-center gap-2">
<div className="relative p-2 rounded-lg bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20">
<div className="relative p-2 rounded-xl bg-gradient-to-br from-blue-500/20 to-blue-600/10 border border-blue-500/20">
<Search className="w-5 h-5 text-blue-500 dark:text-blue-400" />
</div>
<div>
@ -194,7 +194,7 @@ export function WebSearchToolView({
return (
<div
key={idx}
className="bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-lg shadow-sm hover:shadow transition-shadow"
className="bg-card border rounded-lg shadow-sm hover:shadow transition-shadow"
>
<div className="p-4">
<div className="flex items-start gap-3 mb-2">

View File

@ -54,7 +54,7 @@ function AlertDialogContent({
<AlertDialogPrimitive.Content
data-slot="alert-dialog-content"
className={cn(
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-xl border p-6 shadow-lg duration-200 sm:max-w-lg',
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-2xl border p-6 shadow-lg duration-200 sm:max-w-lg',
className,
)}
{...props}

View File

@ -4,7 +4,7 @@ import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@/lib/utils';
const alertVariants = cva(
'relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current',
'relative w-full rounded-xl border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current',
{
variants: {
variant: {

View File

@ -5,7 +5,7 @@ import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@/lib/utils';
const badgeVariants = cva(
'inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden',
'inline-flex items-center justify-center rounded-lg border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden',
{
variants: {
variant: {

View File

@ -15,6 +15,7 @@ const Toaster = ({ ...props }: ToasterProps) => {
'--normal-bg': 'var(--popover)',
'--normal-text': 'var(--popover-foreground)',
'--normal-border': 'var(--border)',
'--border-radius': '1rem',
} as React.CSSProperties
}
{...props}