feat: Add Mantine theme, 12 atom components, and 25 molecule components with Storybook stories

- Mantine theme with component extensions (Badge, Card, Paper, Button, etc.)
- CSS custom properties for design tokens (--inspector-* vars)
- Dark/light mode support with auto detection
- 12 atoms: StatusIndicator, AnnotationBadge, CapabilityItem, LogEntry,
  ProgressDisplay, ContentViewer, ListChangedIndicator, CopyButton,
  ConnectionToggle, TransportBadge, InlineError, MessageBubble
- 25 molecules: ServerCard, AddServerMenu, SchemaForm, ToolListItem,
  ToolDetailPanel, ResultPanel, ResourceListItem, ResourcePreviewPanel,
  ResourceTemplateInput, PromptArgumentsForm, PromptMessagesDisplay,
  LogControls, TaskCard, HistoryEntry, ServerInfoContent, ServerSettingsForm,
  RootsTable, SamplingRequestPanel, ElicitationFormPanel, ElicitationUrlPanel,
  InlineSamplingRequest, InlineElicitationRequest, PendingClientRequests,
  ImportServerJsonPanel, ExperimentalFeaturesPanel
- Exclude storybook-static from version control
- Exclude .stories.tsx from app tsconfig (Storybook-only modules)

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

View file

@ -0,0 +1,59 @@
import { Button, Group, Stack, Text, Title } from '@mantine/core'
import { ContentViewer } from '../../atoms/ContentViewer/ContentViewer'
export interface ResultContentItem {
type: string
text?: string
data?: string
mimeType?: string
}
export interface ResultPanelProps {
content: ResultContentItem[]
onCopy: () => void
onClear: () => void
}
export function ResultPanel({ content, onCopy, onClear }: ResultPanelProps) {
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={item.type === 'text' ? 'text' : 'json'}
content={item.text}
/>
)
}
if (item.data !== undefined) {
return (
<ContentViewer
key={index}
type={item.mimeType?.startsWith('image') ? 'image' : 'audio'}
content={item.data}
mimeType={item.mimeType}
/>
)
}
return null
})}
</>
)}
<Group>
<Button variant="light" size="sm" onClick={onCopy}>
Copy
</Button>
<Button variant="light" size="sm" onClick={onClear}>
Clear
</Button>
</Group>
</Stack>
)
}