Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions apps/web/client/src/stories/Alert.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite';
import { Alert, AlertDescription, AlertTitle } from '@onlook/ui/alert';
import { AlertCircle, CheckCircle2, Info, AlertTriangle } from 'lucide-react';

const meta = {
component: Alert,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
decorators: [
(Story) => (
<div className="w-[400px]">
<Story />
</div>
),
],
argTypes: {
variant: {
description: 'Visual style variant of the alert',
control: { type: 'select' },
options: ['default', 'destructive'],
},
},
} satisfies Meta<typeof Alert>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
render: () => (
<Alert>
<Info className="h-4 w-4" />
<AlertTitle>Information</AlertTitle>
<AlertDescription>
This is an informational alert message.
</AlertDescription>
</Alert>
),
};

export const Destructive: Story = {
render: () => (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertTitle>Error</AlertTitle>
<AlertDescription>
Something went wrong. Please try again later.
</AlertDescription>
</Alert>
),
};

export const Success: Story = {
render: () => (
<Alert>
<CheckCircle2 className="h-4 w-4 text-green-500" />
<AlertTitle>Success</AlertTitle>
<AlertDescription>
Your changes have been saved successfully.
</AlertDescription>
</Alert>
),
};

export const Warning: Story = {
render: () => (
<Alert>
<AlertTriangle className="h-4 w-4 text-yellow-500" />
<AlertTitle>Warning</AlertTitle>
<AlertDescription>
This action may have unintended consequences.
</AlertDescription>
</Alert>
),
};

export const TitleOnly: Story = {
render: () => (
<Alert>
<Info className="h-4 w-4" />
<AlertTitle>Alert with title only</AlertTitle>
</Alert>
),
};

export const DescriptionOnly: Story = {
render: () => (
<Alert>
<Info className="h-4 w-4" />
<AlertDescription>
Alert with description only, no title.
</AlertDescription>
</Alert>
),
};

export const AllVariants: Story = {
render: () => (
<div className="flex flex-col gap-4">
<Alert>
<Info className="h-4 w-4" />
<AlertTitle>Default Alert</AlertTitle>
<AlertDescription>This is the default alert style.</AlertDescription>
</Alert>
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertTitle>Destructive Alert</AlertTitle>
<AlertDescription>This is the destructive alert style.</AlertDescription>
</Alert>
</div>
),
};
93 changes: 93 additions & 0 deletions apps/web/client/src/stories/Avatar.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite';
import { Avatar, AvatarFallback, AvatarImage } from '@onlook/ui/avatar';

const meta = {
component: Avatar,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
} satisfies Meta<typeof Avatar>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
render: () => (
<Avatar>
<AvatarImage src="https://api.dicebear.com/7.x/avataaars/svg?seed=Jane" alt="User avatar" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>
),
};

export const WithFallback: Story = {
render: () => (
<Avatar>
<AvatarImage src="https://invalid-url.com/image.jpg" alt="User avatar" />
<AvatarFallback>AB</AvatarFallback>
</Avatar>
),
};

export const FallbackOnly: Story = {
render: () => (
<Avatar>
<AvatarFallback>CD</AvatarFallback>
</Avatar>
),
};

export const Sizes: Story = {
render: () => (
<div className="flex items-center gap-4">
<Avatar className="size-6">
<AvatarImage src="https://api.dicebear.com/7.x/avataaars/svg?seed=Small" alt="Small avatar" />
<AvatarFallback>SM</AvatarFallback>
</Avatar>
<Avatar className="size-8">
<AvatarImage src="https://api.dicebear.com/7.x/avataaars/svg?seed=Default" alt="Default avatar" />
<AvatarFallback>DF</AvatarFallback>
</Avatar>
<Avatar className="size-12">
<AvatarImage src="https://api.dicebear.com/7.x/avataaars/svg?seed=Large" alt="Large avatar" />
<AvatarFallback>LG</AvatarFallback>
</Avatar>
<Avatar className="size-16">
<AvatarImage src="https://api.dicebear.com/7.x/avataaars/svg?seed=XLarge" alt="Extra large avatar" />
<AvatarFallback>XL</AvatarFallback>
</Avatar>
</div>
),
};

export const Group: Story = {
render: () => (
<div className="flex -space-x-2">
<Avatar className="border-2 border-background">
<AvatarImage src="https://api.dicebear.com/7.x/avataaars/svg?seed=User1" alt="User 1" />
<AvatarFallback>U1</AvatarFallback>
</Avatar>
<Avatar className="border-2 border-background">
<AvatarImage src="https://api.dicebear.com/7.x/avataaars/svg?seed=User2" alt="User 2" />
<AvatarFallback>U2</AvatarFallback>
</Avatar>
<Avatar className="border-2 border-background">
<AvatarImage src="https://api.dicebear.com/7.x/avataaars/svg?seed=User3" alt="User 3" />
<AvatarFallback>U3</AvatarFallback>
</Avatar>
<Avatar className="border-2 border-background">
<AvatarFallback>+5</AvatarFallback>
</Avatar>
</div>
),
};

export const WithRealImage: Story = {
render: () => (
<Avatar>
<AvatarImage src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=100&h=100&fit=crop" alt="User photo" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>
),
};
78 changes: 78 additions & 0 deletions apps/web/client/src/stories/Badge.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite';
import { Badge } from '@onlook/ui/badge';

const meta = {
component: Badge,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
variant: {
description: 'Visual style variant of the badge',
control: { type: 'select' },
options: ['default', 'secondary', 'destructive', 'outline'],
},
asChild: {
description: 'Whether to render as a child component',
control: 'boolean',
},
},
} satisfies Meta<typeof Badge>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
children: 'Badge',
variant: 'default',
},
};

export const Secondary: Story = {
args: {
children: 'Secondary',
variant: 'secondary',
},
};

export const Destructive: Story = {
args: {
children: 'Destructive',
variant: 'destructive',
},
};

export const Outline: Story = {
args: {
children: 'Outline',
variant: 'outline',
},
};

export const AllVariants: Story = {
render: () => (
<div className="flex flex-wrap gap-2">
<Badge variant="default">Default</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="destructive">Destructive</Badge>
<Badge variant="outline">Outline</Badge>
</div>
),
};

export const WithIcon: Story = {
render: () => (
<div className="flex flex-wrap gap-2">
<Badge variant="default">
<span className="mr-1">*</span>
New
</Badge>
<Badge variant="secondary">
<span className="mr-1">!</span>
Warning
</Badge>
</div>
),
};
104 changes: 104 additions & 0 deletions apps/web/client/src/stories/Card.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite';
import { Button } from '@onlook/ui/button';
import {
Card,
CardAction,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from '@onlook/ui/card';

const meta = {
component: Card,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
decorators: [
(Story) => (
<div className="w-[400px]">
<Story />
</div>
),
],
} satisfies Meta<typeof Card>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
render: () => (
<Card>
<CardHeader>
<CardTitle>Card Title</CardTitle>
<CardDescription>Card description goes here</CardDescription>
</CardHeader>
<CardContent>
<p>Card content with some text explaining the purpose of this card.</p>
</CardContent>
<CardFooter>
<Button>Action</Button>
</CardFooter>
</Card>
),
};

export const WithAction: Story = {
render: () => (
<Card>
<CardHeader>
<CardTitle>Card with Action</CardTitle>
<CardDescription>This card has an action button in the header</CardDescription>
<CardAction>
<Button variant="outline" size="sm">Edit</Button>
</CardAction>
</CardHeader>
<CardContent>
<p>The action button appears in the top right corner of the header.</p>
</CardContent>
</Card>
),
};

export const Simple: Story = {
render: () => (
<Card>
<CardHeader>
<CardTitle>Simple Card</CardTitle>
</CardHeader>
<CardContent>
<p>A simple card with just a title and content.</p>
</CardContent>
</Card>
),
};

export const WithFooterActions: Story = {
render: () => (
<Card>
<CardHeader>
<CardTitle>Confirm Action</CardTitle>
<CardDescription>Are you sure you want to proceed?</CardDescription>
</CardHeader>
<CardContent>
<p>This action cannot be undone. Please review before confirming.</p>
</CardContent>
<CardFooter className="flex justify-end gap-2">
<Button variant="outline">Cancel</Button>
<Button>Confirm</Button>
</CardFooter>
</Card>
),
};

export const ContentOnly: Story = {
render: () => (
<Card>
<CardContent>
<p>A card with only content, no header or footer.</p>
</CardContent>
</Card>
),
};
Loading
Loading