Inline ListChangedIndicator with titles, normalize screen gaps, and rename ResultPanel to ToolResultPanel
- Place ListChangedIndicator on same line as section titles using Group with space-between in ToolControls, ResourceControls, and PromptControls - Add ListChanged stories for ResourceControls and show indicators in ConnectedView stories - Normalize ScreenLayout gap from "xl" to "md" across all screens for consistent spacing - Rename ResultPanel to ToolResultPanel (component, interface, files, and stories) - Replace Grid layout in ToolsScreen with equal-width flex children for detail and result panels Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ed6d79c5ed
commit
5594e940c9
2 changed files with 69 additions and 56 deletions
|
|
@ -0,0 +1,70 @@
|
|||
import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||
import { fn } from "storybook/test";
|
||||
import { ToolResultPanel } from "./ToolResultPanel";
|
||||
|
||||
const meta: Meta<typeof ToolResultPanel> = {
|
||||
title: "Groups/ToolResultPanel",
|
||||
component: ToolResultPanel,
|
||||
args: {
|
||||
onClear: fn(),
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof ToolResultPanel>;
|
||||
|
||||
export const Empty: Story = {
|
||||
args: {
|
||||
content: [],
|
||||
},
|
||||
};
|
||||
|
||||
export const TextResult: Story = {
|
||||
args: {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "The current weather in San Francisco is 65°F and sunny.",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const JsonResult: Story = {
|
||||
args: {
|
||||
content: [
|
||||
{
|
||||
type: "json",
|
||||
text: '{"temperature":65,"unit":"fahrenheit","condition":"sunny","city":"San Francisco"}',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const ImageResult: Story = {
|
||||
args: {
|
||||
content: [
|
||||
{
|
||||
type: "image",
|
||||
data: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==",
|
||||
mimeType: "image/png",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const MixedContent: Story = {
|
||||
args: {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "Here is the generated image based on your description:",
|
||||
},
|
||||
{
|
||||
type: "image",
|
||||
data: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==",
|
||||
mimeType: "image/png",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
import { Button, Group, Stack, Text, Title } from "@mantine/core";
|
||||
import { ContentViewer } from "../../elements/ContentViewer/ContentViewer";
|
||||
|
||||
export interface ResultContentItem {
|
||||
type: string;
|
||||
text?: string;
|
||||
data?: string;
|
||||
mimeType?: string;
|
||||
}
|
||||
|
||||
export interface ToolResultPanelProps {
|
||||
content: ResultContentItem[];
|
||||
onClear: () => void;
|
||||
}
|
||||
|
||||
const ClearButton = Button.withProps({
|
||||
variant: "light",
|
||||
size: "sm",
|
||||
});
|
||||
|
||||
function resolveTextType(type: string): "text" | "json" {
|
||||
return type === "text" ? "text" : "json";
|
||||
}
|
||||
|
||||
function resolveMediaType(mimeType?: string): "image" | "audio" {
|
||||
return mimeType?.startsWith("image") ? "image" : "audio";
|
||||
}
|
||||
|
||||
export function ToolResultPanel({ content, onClear }: ToolResultPanelProps) {
|
||||
return (
|
||||
<Stack>
|
||||
<Title order={4}>Results</Title>
|
||||
{content.length === 0 ? (
|
||||
<Text c="dimmed">No results yet</Text>
|
||||
) : (
|
||||
<>
|
||||
{content.map((item, index) => {
|
||||
if (item.text !== undefined) {
|
||||
return (
|
||||
<ContentViewer
|
||||
key={index}
|
||||
type={resolveTextType(item.type)}
|
||||
content={item.text}
|
||||
copyable
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (item.data !== undefined) {
|
||||
return (
|
||||
<ContentViewer
|
||||
key={index}
|
||||
type={resolveMediaType(item.mimeType)}
|
||||
content={item.data}
|
||||
mimeType={item.mimeType}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
<Group>
|
||||
<ClearButton onClick={onClear}>Clear</ClearButton>
|
||||
</Group>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in a new issue