refine UI layout, theming, and component consistency across screens

- Add MCP logo (light/dark variants) to ConnectedLayout header
- Replace Tabs with SegmentedControl in header, split into 1/3 sections
- Wrap all screens in Container for consistent margins
- Use Card instead of Paper for panel backgrounds across all screens
- Add SubscribeButton atom, CopyButton for resource URI
- Move annotations from ResourceListItem to ResourcePreviewPanel
- Improve AnnotationBadge colors for dark mode visibility
- Add Tools, Resources, and Prompts headers to list panels
- Add ConnectedLayout stories for Tools, Resources, and Prompts tabs
- Remove unused onCopy prop and copy button from PromptMessagesDisplay

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
cliffhall 2026-03-23 16:56:53 -04:00
commit f674ce0c22

View file

@ -1,5 +1,8 @@
import { Button, Group, Stack, Text, Title } from "@mantine/core";
import { Group, Stack, Text, Title } from "@mantine/core";
import { AnnotationBadge } from "../../atoms/AnnotationBadge/AnnotationBadge";
import { ContentViewer } from "../../atoms/ContentViewer/ContentViewer";
import { CopyButton } from "../../atoms/CopyButton/CopyButton";
import { SubscribeButton } from "../../atoms/SubscribeButton/SubscribeButton";
export interface ResourcePreviewPanelProps {
uri: string;
@ -12,6 +15,12 @@ export interface ResourcePreviewPanelProps {
onUnsubscribe: () => void;
}
function priorityLabel(priority: number): string {
if (priority >= 0.7) return "priority: high";
if (priority >= 0.4) return "priority: medium";
return "priority: low";
}
function resolveContentType(mimeType: string): "json" | "image" | "text" {
if (mimeType === "application/json") return "json";
if (mimeType.startsWith("image/")) return "image";
@ -30,51 +39,53 @@ export function ResourcePreviewPanel({
}: ResourcePreviewPanelProps) {
return (
<Stack gap="md">
<Title order={4}>Content Preview</Title>
<Text size="sm">
URI:{" "}
<Text span c="blue">
{uri}
</Text>
</Text>
<Text size="sm" c="dimmed">
MIME: {mimeType}
</Text>
{annotations && (
<Stack gap="xs">
<Text size="sm">Annotations:</Text>
{annotations.audience && (
<Text size="sm" c="dimmed">
Audience: {annotations.audience}
</Text>
)}
{annotations.priority !== undefined && (
<Text size="sm" c="dimmed">
Priority: {annotations.priority}
</Text>
)}
</Stack>
)}
<Group justify="space-between" wrap="nowrap">
<Title order={4}>Resource</Title>
<Group gap="xs" wrap="nowrap">
<Text size="sm" c="blue" truncate="end">
{uri}
</Text>
<CopyButton value={uri} />
</Group>
</Group>
<ContentViewer
type={resolveContentType(mimeType)}
content={content}
mimeType={mimeType}
copyable
/>
<Group>
<Button
variant="light"
size="sm"
onClick={isSubscribed ? onUnsubscribe : onSubscribe}
>
{isSubscribed ? "Unsubscribe" : "Subscribe"}
</Button>
</Group>
{lastUpdated && (
<Text size="xs" c="dimmed" ta="right">
Last updated: {lastUpdated}
<Group justify="space-between" wrap="nowrap">
{lastUpdated ? (
<Text size="xs" c="dimmed">
Last updated: {lastUpdated}
</Text>
) : (
<span />
)}
<Text size="sm" c="dimmed">
{mimeType}
</Text>
)}
</Group>
<Group justify="space-between">
<Group gap="xs">
{annotations?.audience && (
<AnnotationBadge
label={annotations.audience}
variant="audience"
/>
)}
{annotations?.priority !== undefined && (
<AnnotationBadge
label={priorityLabel(annotations.priority)}
variant="priority"
/>
)}
</Group>
<SubscribeButton
subscribed={isSubscribed}
onToggle={isSubscribed ? onUnsubscribe : onSubscribe}
/>
</Group>
</Stack>
);
}