test(ui): add primitive story coverage
This commit is contained in:
parent
5b720fda33
commit
5af6154e80
@ -5,7 +5,10 @@ const meta: Meta<typeof Badge> = {
|
|||||||
title: 'Components/Badge',
|
title: 'Components/Badge',
|
||||||
component: Badge,
|
component: Badge,
|
||||||
argTypes: {
|
argTypes: {
|
||||||
variant: { control: 'select', options: ['success', 'warning', 'error', 'info', 'neutral'] },
|
variant: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['success', 'warning', 'error', 'danger', 'info', 'neutral', 'accent'],
|
||||||
|
},
|
||||||
size: { control: 'select', options: ['sm', 'md'] },
|
size: { control: 'select', options: ['sm', 'md'] },
|
||||||
dot: { control: 'boolean' },
|
dot: { control: 'boolean' },
|
||||||
},
|
},
|
||||||
|
|||||||
@ -5,7 +5,10 @@ const meta: Meta<typeof Button> = {
|
|||||||
title: 'Components/Button',
|
title: 'Components/Button',
|
||||||
component: Button,
|
component: Button,
|
||||||
argTypes: {
|
argTypes: {
|
||||||
variant: { control: 'select', options: ['primary', 'secondary', 'ghost', 'danger'] },
|
variant: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['primary', 'secondary', 'ghost', 'destructive', 'outline', 'subtle', 'link'],
|
||||||
|
},
|
||||||
size: { control: 'select', options: ['sm', 'md', 'lg'] },
|
size: { control: 'select', options: ['sm', 'md', 'lg'] },
|
||||||
loading: { control: 'boolean' },
|
loading: { control: 'boolean' },
|
||||||
disabled: { control: 'boolean' },
|
disabled: { control: 'boolean' },
|
||||||
@ -28,7 +31,7 @@ export const Ghost: Story = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const Danger: Story = {
|
export const Danger: Story = {
|
||||||
args: { children: 'Danger Button', variant: 'danger' },
|
args: { children: 'Danger Button', variant: 'destructive' },
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Loading: Story = {
|
export const Loading: Story = {
|
||||||
|
|||||||
@ -24,7 +24,7 @@ export const WithHeader: Story = {
|
|||||||
<CardTitle>Card Title</CardTitle>
|
<CardTitle>Card Title</CardTitle>
|
||||||
<CardDescription>A short description of this card.</CardDescription>
|
<CardDescription>A short description of this card.</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<p style={{ color: 'var(--bl-text-secondary, #a0a0b0)', fontSize: 14 }}>Body content</p>
|
<p className="text-sm text-[var(--bl-text-secondary)]">Body content</p>
|
||||||
</Card>
|
</Card>
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|||||||
92
packages/ui/src/components/Controls.stories.tsx
Normal file
92
packages/ui/src/components/Controls.stories.tsx
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
import { MoreHorizontal } from 'lucide-react';
|
||||||
|
import { Checkbox } from './Checkbox.js';
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuLabel,
|
||||||
|
DropdownMenuSeparator,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from './DropdownMenu.js';
|
||||||
|
import { IconButton } from './IconButton.js';
|
||||||
|
import { RadioGroup, RadioGroupItem } from './RadioGroup.js';
|
||||||
|
import { SegmentedControl } from './SegmentedControl.js';
|
||||||
|
import { Switch } from './Switch.js';
|
||||||
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from './Tabs.js';
|
||||||
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './Tooltip.js';
|
||||||
|
|
||||||
|
const meta: Meta = {
|
||||||
|
title: 'Components/Controls',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj;
|
||||||
|
|
||||||
|
export const ChoiceControls: Story = {
|
||||||
|
render: () => {
|
||||||
|
const [mode, setMode] = React.useState('review');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="grid max-w-xl gap-4">
|
||||||
|
<SegmentedControl
|
||||||
|
aria-label="Queue mode"
|
||||||
|
value={mode}
|
||||||
|
onValueChange={setMode}
|
||||||
|
options={[
|
||||||
|
{ value: 'review', label: 'Review' },
|
||||||
|
{ value: 'approved', label: 'Approved' },
|
||||||
|
{ value: 'rejected', label: 'Rejected' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<Checkbox label="Include archived notes" />
|
||||||
|
<Switch label="Auto-refresh queue" />
|
||||||
|
<RadioGroup defaultValue="compact" aria-label="Density">
|
||||||
|
<RadioGroupItem value="compact" label="Compact" />
|
||||||
|
<RadioGroupItem value="comfortable" label="Comfortable" />
|
||||||
|
</RadioGroup>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const OverlaysAndTabs: Story = {
|
||||||
|
render: () => (
|
||||||
|
<TooltipProvider>
|
||||||
|
<div className="grid max-w-xl gap-4">
|
||||||
|
<Tabs defaultValue="queue">
|
||||||
|
<TabsList aria-label="Review sections">
|
||||||
|
<TabsTrigger value="queue">Queue</TabsTrigger>
|
||||||
|
<TabsTrigger value="timeline">Timeline</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
<TabsContent value="queue" className="pt-3">
|
||||||
|
Queue content
|
||||||
|
</TabsContent>
|
||||||
|
<TabsContent value="timeline" className="pt-3">
|
||||||
|
Timeline content
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<IconButton icon={<MoreHorizontal className="h-4 w-4" />} label="More actions" />
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>More actions</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<IconButton icon={<MoreHorizontal className="h-4 w-4" />} label="Open menu" />
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent>
|
||||||
|
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<DropdownMenuItem>Approve</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem>Reject</DropdownMenuItem>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TooltipProvider>
|
||||||
|
),
|
||||||
|
};
|
||||||
120
packages/ui/src/components/OperationalPrimitives.stories.tsx
Normal file
120
packages/ui/src/components/OperationalPrimitives.stories.tsx
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
import { Check, Clock } from 'lucide-react';
|
||||||
|
import { Button } from './Button.js';
|
||||||
|
import { DataList, DataListItem, DataListMeta } from './DataList.js';
|
||||||
|
import {
|
||||||
|
DataTable,
|
||||||
|
DataTableBody,
|
||||||
|
DataTableCell,
|
||||||
|
DataTableHead,
|
||||||
|
DataTableHeader,
|
||||||
|
DataTableRow,
|
||||||
|
} from './DataTable.js';
|
||||||
|
import { DiffCard } from './DiffCard.js';
|
||||||
|
import { IconButton } from './IconButton.js';
|
||||||
|
import { ListItemButton } from './ListItemButton.js';
|
||||||
|
import { Panel, PanelBody, PanelDescription, PanelHeader, PanelTitle } from './Panel.js';
|
||||||
|
import { StatusBadge } from './StatusBadge.js';
|
||||||
|
import { Surface, SurfaceList, SurfaceListItem } from './Surface.js';
|
||||||
|
import { Timeline } from './Timeline.js';
|
||||||
|
|
||||||
|
const meta: Meta = {
|
||||||
|
title: 'Components/Operational Primitives',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj;
|
||||||
|
|
||||||
|
export const SurfacesAndLists: Story = {
|
||||||
|
render: () => (
|
||||||
|
<div className="grid max-w-2xl gap-4">
|
||||||
|
<Panel>
|
||||||
|
<PanelHeader>
|
||||||
|
<div>
|
||||||
|
<PanelTitle>Review queue</PanelTitle>
|
||||||
|
<PanelDescription>Dense operator work surface</PanelDescription>
|
||||||
|
</div>
|
||||||
|
<IconButton icon={<Check className="h-4 w-4" />} label="Approve selected" />
|
||||||
|
</PanelHeader>
|
||||||
|
<PanelBody>
|
||||||
|
<ListItemButton selected>
|
||||||
|
<div className="font-medium">Merge duplicate research notes</div>
|
||||||
|
<div className="text-sm text-[var(--bl-text-secondary)]">2 linked notes affected</div>
|
||||||
|
</ListItemButton>
|
||||||
|
<SurfaceList>
|
||||||
|
<SurfaceListItem selected>Selected surface row</SurfaceListItem>
|
||||||
|
<SurfaceListItem>Normal surface row</SurfaceListItem>
|
||||||
|
</SurfaceList>
|
||||||
|
</PanelBody>
|
||||||
|
</Panel>
|
||||||
|
<Surface variant="muted">Reusable muted surface</Surface>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const StatusTimelineAndDiff: Story = {
|
||||||
|
render: () => (
|
||||||
|
<div className="grid max-w-2xl gap-4">
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<StatusBadge tone="success" dot>
|
||||||
|
Approved
|
||||||
|
</StatusBadge>
|
||||||
|
<StatusBadge tone="warning" dot>
|
||||||
|
Needs review
|
||||||
|
</StatusBadge>
|
||||||
|
</div>
|
||||||
|
<Timeline
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
title: 'Draft created',
|
||||||
|
description: 'Agent proposed a note update',
|
||||||
|
status: 'Draft',
|
||||||
|
tone: 'info',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
title: 'Human review',
|
||||||
|
description: 'Awaiting decision',
|
||||||
|
status: 'Pending',
|
||||||
|
tone: 'warning',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<DiffCard before="Original note body" after="Improved note body with extracted actions" />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DataDisplay: Story = {
|
||||||
|
render: () => (
|
||||||
|
<div className="grid max-w-3xl gap-4">
|
||||||
|
<DataList>
|
||||||
|
<DataListItem selected>
|
||||||
|
<div className="font-medium">Workspace intelligence</div>
|
||||||
|
<DataListMeta>
|
||||||
|
<Clock className="h-3.5 w-3.5" /> Updated 4 minutes ago
|
||||||
|
</DataListMeta>
|
||||||
|
</DataListItem>
|
||||||
|
<DataListItem>Inbox processing</DataListItem>
|
||||||
|
</DataList>
|
||||||
|
<DataTable>
|
||||||
|
<DataTableHeader>
|
||||||
|
<DataTableRow>
|
||||||
|
<DataTableHead>Name</DataTableHead>
|
||||||
|
<DataTableHead>Status</DataTableHead>
|
||||||
|
</DataTableRow>
|
||||||
|
</DataTableHeader>
|
||||||
|
<DataTableBody>
|
||||||
|
<DataTableRow>
|
||||||
|
<DataTableCell>Research notes</DataTableCell>
|
||||||
|
<DataTableCell>
|
||||||
|
<StatusBadge tone="success">Healthy</StatusBadge>
|
||||||
|
</DataTableCell>
|
||||||
|
</DataTableRow>
|
||||||
|
</DataTableBody>
|
||||||
|
</DataTable>
|
||||||
|
<Button variant="subtle">Open details</Button>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user