From c8a41aba4187fade39023e63f606e559ab3c7ae1 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 12 Dec 2025 10:32:14 +0000 Subject: [PATCH] feat: add Storybook stories for UI components and update existing stories - Add 16 new story files for UI components: - Alert, Avatar, Badge, Card, Checkbox, Input, Label, Progress - Separator, Skeleton, Slider, Switch, Tabs, Textarea, Toggle, Tooltip - Update existing stories to use @storybook/nextjs-vite instead of @storybook/react - Remove title property from meta objects per playbook guidelines - All stories follow the playbook pattern with Default story first - Include argTypes with descriptions for all controllable props - Add showcase stories for variants, sizes, and states Co-Authored-By: unknown <> --- apps/web/client/src/stories/Alert.stories.tsx | 106 +++++++++++++ .../web/client/src/stories/Avatar.stories.tsx | 82 +++++++++++ apps/web/client/src/stories/Badge.stories.tsx | 95 ++++++++++++ .../web/client/src/stories/Button.stories.tsx | 3 +- apps/web/client/src/stories/Card.stories.tsx | 104 +++++++++++++ .../client/src/stories/Checkbox.stories.tsx | 86 +++++++++++ apps/web/client/src/stories/Input.stories.tsx | 97 ++++++++++++ apps/web/client/src/stories/Label.stories.tsx | 87 +++++++++++ .../client/src/stories/Progress.stories.tsx | 99 +++++++++++++ .../src/stories/ProjectCard.stories.tsx | 7 +- .../src/stories/ProjectsPage.stories.tsx | 11 +- .../src/stories/SelectProject.stories.tsx | 7 +- .../client/src/stories/Separator.stories.tsx | 84 +++++++++++ .../client/src/stories/Skeleton.stories.tsx | 95 ++++++++++++ .../web/client/src/stories/Slider.stories.tsx | 106 +++++++++++++ .../web/client/src/stories/Switch.stories.tsx | 86 +++++++++++ apps/web/client/src/stories/Tabs.stories.tsx | 119 +++++++++++++++ .../client/src/stories/Textarea.stories.tsx | 77 ++++++++++ .../web/client/src/stories/Toggle.stories.tsx | 110 ++++++++++++++ .../client/src/stories/Tooltip.stories.tsx | 139 ++++++++++++++++++ .../web/client/src/stories/TopBar.stories.tsx | 6 +- 21 files changed, 1577 insertions(+), 29 deletions(-) create mode 100644 apps/web/client/src/stories/Alert.stories.tsx create mode 100644 apps/web/client/src/stories/Avatar.stories.tsx create mode 100644 apps/web/client/src/stories/Badge.stories.tsx create mode 100644 apps/web/client/src/stories/Card.stories.tsx create mode 100644 apps/web/client/src/stories/Checkbox.stories.tsx create mode 100644 apps/web/client/src/stories/Input.stories.tsx create mode 100644 apps/web/client/src/stories/Label.stories.tsx create mode 100644 apps/web/client/src/stories/Progress.stories.tsx create mode 100644 apps/web/client/src/stories/Separator.stories.tsx create mode 100644 apps/web/client/src/stories/Skeleton.stories.tsx create mode 100644 apps/web/client/src/stories/Slider.stories.tsx create mode 100644 apps/web/client/src/stories/Switch.stories.tsx create mode 100644 apps/web/client/src/stories/Tabs.stories.tsx create mode 100644 apps/web/client/src/stories/Textarea.stories.tsx create mode 100644 apps/web/client/src/stories/Toggle.stories.tsx create mode 100644 apps/web/client/src/stories/Tooltip.stories.tsx diff --git a/apps/web/client/src/stories/Alert.stories.tsx b/apps/web/client/src/stories/Alert.stories.tsx new file mode 100644 index 0000000000..d636e27626 --- /dev/null +++ b/apps/web/client/src/stories/Alert.stories.tsx @@ -0,0 +1,106 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import { Alert, AlertTitle, AlertDescription } from '@onlook/ui/alert'; +import { AlertCircle, Info, CheckCircle2, AlertTriangle } from 'lucide-react'; + +const meta = { + component: Alert, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + variant: { + description: 'Visual style variant of the alert', + control: { type: 'select' }, + options: ['default', 'destructive'], + }, + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + Information + + This is an informational alert message. + + + ), +}; + +export const Destructive: Story = { + render: () => ( + + + Error + + Something went wrong. Please try again later. + + + ), +}; + +export const Success: Story = { + render: () => ( + + + Success + + Your changes have been saved successfully. + + + ), +}; + +export const Warning: Story = { + render: () => ( + + + Warning + + This action may have unintended consequences. + + + ), +}; + +export const TitleOnly: Story = { + render: () => ( + + + Quick notification + + ), +}; + +export const Variants: Story = { + render: () => ( +
+ + + Default Alert + + This is the default alert style. + + + + + Destructive Alert + + This is the destructive alert style. + + +
+ ), +}; diff --git a/apps/web/client/src/stories/Avatar.stories.tsx b/apps/web/client/src/stories/Avatar.stories.tsx new file mode 100644 index 0000000000..dd8dec6bb2 --- /dev/null +++ b/apps/web/client/src/stories/Avatar.stories.tsx @@ -0,0 +1,82 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import { Avatar, AvatarImage, AvatarFallback } from '@onlook/ui/avatar'; + +const meta = { + component: Avatar, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + CN + + ), +}; + +export const WithFallback: Story = { + render: () => ( + + + JD + + ), +}; + +export const FallbackOnly: Story = { + render: () => ( + + AB + + ), +}; + +export const Sizes: Story = { + render: () => ( +
+ + + SM + + + + MD + + + + LG + + + + XL + +
+ ), +}; + +export const Group: Story = { + render: () => ( +
+ + + U1 + + + U2 + + + U3 + + + +5 + +
+ ), +}; diff --git a/apps/web/client/src/stories/Badge.stories.tsx b/apps/web/client/src/stories/Badge.stories.tsx new file mode 100644 index 0000000000..daa15c8960 --- /dev/null +++ b/apps/web/client/src/stories/Badge.stories.tsx @@ -0,0 +1,95 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import { Badge } from '@onlook/ui/badge'; +import { Check, AlertCircle, Clock } from 'lucide-react'; + +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; + +export default meta; +type Story = StoryObj; + +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 WithIcon: Story = { + args: { + children: ( + <> + + Success + + ), + variant: 'default', + }, +}; + +export const Variants: Story = { + render: () => ( +
+ Default + Secondary + Destructive + Outline +
+ ), +}; + +export const WithIcons: Story = { + render: () => ( +
+ + + Success + + + + Error + + + + Pending + +
+ ), +}; diff --git a/apps/web/client/src/stories/Button.stories.tsx b/apps/web/client/src/stories/Button.stories.tsx index a8e4cd4e91..a65a2ae9cb 100644 --- a/apps/web/client/src/stories/Button.stories.tsx +++ b/apps/web/client/src/stories/Button.stories.tsx @@ -1,9 +1,8 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; import { Button } from '@onlook/ui/button'; import { Heart, Plus, Trash2 } from 'lucide-react'; const meta = { - title: 'UI/Button', component: Button, parameters: { layout: 'centered', diff --git a/apps/web/client/src/stories/Card.stories.tsx b/apps/web/client/src/stories/Card.stories.tsx new file mode 100644 index 0000000000..61e371e053 --- /dev/null +++ b/apps/web/client/src/stories/Card.stories.tsx @@ -0,0 +1,104 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import { + Card, + CardHeader, + CardTitle, + CardDescription, + CardContent, + CardFooter, + CardAction, +} from '@onlook/ui/card'; +import { Button } from '@onlook/ui/button'; + +const meta = { + component: Card, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + Card Title + Card description goes here + + +

Card content goes here. This is where you put the main content of the card.

+
+ + + +
+ ), +}; + +export const Simple: Story = { + render: () => ( + + +

A simple card with just content.

+
+
+ ), +}; + +export const WithAction: Story = { + render: () => ( + + + Project Settings + Manage your project configuration + + + + + +

Configure your project settings here.

+
+
+ ), +}; + +export const WithFooterActions: Story = { + render: () => ( + + + Delete Project + This action cannot be undone + + +

Are you sure you want to delete this project? All data will be permanently removed.

+
+ + + + +
+ ), +}; + +export const HeaderOnly: Story = { + render: () => ( + + + Notifications + You have 3 unread messages + + + ), +}; diff --git a/apps/web/client/src/stories/Checkbox.stories.tsx b/apps/web/client/src/stories/Checkbox.stories.tsx new file mode 100644 index 0000000000..c430e68513 --- /dev/null +++ b/apps/web/client/src/stories/Checkbox.stories.tsx @@ -0,0 +1,86 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import { fn } from '@storybook/test'; +import { Checkbox } from '@onlook/ui/checkbox'; +import { Label } from '@onlook/ui/label'; + +const meta = { + component: Checkbox, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + checked: { + description: 'Whether the checkbox is checked', + control: 'boolean', + }, + disabled: { + description: 'Whether the checkbox is disabled', + control: 'boolean', + }, + }, + args: { + onCheckedChange: fn(), + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + checked: false, + disabled: false, + }, +}; + +export const Checked: Story = { + args: { + checked: true, + }, +}; + +export const Disabled: Story = { + args: { + disabled: true, + }, +}; + +export const DisabledChecked: Story = { + args: { + checked: true, + disabled: true, + }, +}; + +export const WithLabel: Story = { + render: () => ( +
+ + +
+ ), +}; + +export const States: Story = { + render: () => ( +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ ), +}; diff --git a/apps/web/client/src/stories/Input.stories.tsx b/apps/web/client/src/stories/Input.stories.tsx new file mode 100644 index 0000000000..eb1e57a2e2 --- /dev/null +++ b/apps/web/client/src/stories/Input.stories.tsx @@ -0,0 +1,97 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import { Input } from '@onlook/ui/input'; + +const meta = { + component: Input, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + type: { + description: 'The type of input', + control: { type: 'select' }, + options: ['text', 'password', 'email', 'number', 'search', 'tel', 'url'], + }, + placeholder: { + description: 'Placeholder text', + control: 'text', + }, + disabled: { + description: 'Whether the input is disabled', + control: 'boolean', + }, + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + type: 'text', + placeholder: 'Enter text...', + }, +}; + +export const Email: Story = { + args: { + type: 'email', + placeholder: 'Enter email...', + }, +}; + +export const Password: Story = { + args: { + type: 'password', + placeholder: 'Enter password...', + }, +}; + +export const Disabled: Story = { + args: { + type: 'text', + placeholder: 'Disabled input', + disabled: true, + }, +}; + +export const WithValue: Story = { + args: { + type: 'text', + defaultValue: 'Hello World', + }, +}; + +export const Search: Story = { + args: { + type: 'search', + placeholder: 'Search...', + }, +}; + +export const Number: Story = { + args: { + type: 'number', + placeholder: 'Enter number...', + }, +}; + +export const Types: Story = { + render: () => ( +
+ + + + + +
+ ), +}; diff --git a/apps/web/client/src/stories/Label.stories.tsx b/apps/web/client/src/stories/Label.stories.tsx new file mode 100644 index 0000000000..64e23ac7dd --- /dev/null +++ b/apps/web/client/src/stories/Label.stories.tsx @@ -0,0 +1,87 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import { Label } from '@onlook/ui/label'; +import { Input } from '@onlook/ui/input'; +import { Checkbox } from '@onlook/ui/checkbox'; + +const meta = { + component: Label, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + htmlFor: { + description: 'ID of the form element this label is for', + control: 'text', + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + children: 'Label', + }, +}; + +export const WithInput: Story = { + render: () => ( +
+ + +
+ ), +}; + +export const WithCheckbox: Story = { + render: () => ( +
+ + +
+ ), +}; + +export const Required: Story = { + render: () => ( +
+ + +
+ ), +}; + +export const WithDescription: Story = { + render: () => ( +
+ + +

+ Must be at least 8 characters long. +

+
+ ), +}; + +export const FormFields: Story = { + render: () => ( +
+
+ + +
+
+ + +
+
+ + +
+
+ ), +}; diff --git a/apps/web/client/src/stories/Progress.stories.tsx b/apps/web/client/src/stories/Progress.stories.tsx new file mode 100644 index 0000000000..891b89a534 --- /dev/null +++ b/apps/web/client/src/stories/Progress.stories.tsx @@ -0,0 +1,99 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import { Progress } from '@onlook/ui/progress'; + +const meta = { + component: Progress, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + value: { + description: 'Progress value (0-100)', + control: { type: 'range', min: 0, max: 100, step: 1 }, + }, + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + value: 50, + }, +}; + +export const Empty: Story = { + args: { + value: 0, + }, +}; + +export const Quarter: Story = { + args: { + value: 25, + }, +}; + +export const Half: Story = { + args: { + value: 50, + }, +}; + +export const ThreeQuarters: Story = { + args: { + value: 75, + }, +}; + +export const Complete: Story = { + args: { + value: 100, + }, +}; + +export const ProgressSteps: Story = { + render: () => ( +
+
+
+ 0% +
+ +
+
+
+ 25% +
+ +
+
+
+ 50% +
+ +
+
+
+ 75% +
+ +
+
+
+ 100% +
+ +
+
+ ), +}; diff --git a/apps/web/client/src/stories/ProjectCard.stories.tsx b/apps/web/client/src/stories/ProjectCard.stories.tsx index 4fff925d67..3c592cece0 100644 --- a/apps/web/client/src/stories/ProjectCard.stories.tsx +++ b/apps/web/client/src/stories/ProjectCard.stories.tsx @@ -1,14 +1,9 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; import { ProjectCard } from '@/app/projects/_components/select/project-card'; import { HighlightText } from '@/app/projects/_components/select/highlight-text'; import type { Project } from '@onlook/models'; -/** - * ProjectCard displays individual project information with hover effects, - * preview images, and interactive elements like edit and settings buttons. - */ const meta = { - title: 'Projects/ProjectCard', component: ProjectCard, parameters: { layout: 'padded', diff --git a/apps/web/client/src/stories/ProjectsPage.stories.tsx b/apps/web/client/src/stories/ProjectsPage.stories.tsx index 016d4f95f1..8cb9304e6c 100644 --- a/apps/web/client/src/stories/ProjectsPage.stories.tsx +++ b/apps/web/client/src/stories/ProjectsPage.stories.tsx @@ -1,14 +1,9 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; import { TopBarPresentation } from '@/app/projects/_components/top-bar-presentation'; import { SelectProjectPresentation } from '@/app/projects/_components/select-presentation'; import type { Project, User } from '@onlook/models'; import { fn } from '@storybook/test'; import { useState } from 'react'; - -/** - * ProjectsPageComposed - Full projects page combining TopBar and SelectProject. - * This demonstrates the complete page layout and interactions. - */ const ProjectsPageComposed = ({ user, projects, @@ -60,11 +55,7 @@ const ProjectsPageComposed = ({ ); }; -/** - * ProjectsPage - Full page view demonstrating the complete projects interface. - */ const meta = { - title: 'Pages/ProjectsPage', component: ProjectsPageComposed, parameters: { layout: 'fullscreen', diff --git a/apps/web/client/src/stories/SelectProject.stories.tsx b/apps/web/client/src/stories/SelectProject.stories.tsx index 8423972c9f..daca379246 100644 --- a/apps/web/client/src/stories/SelectProject.stories.tsx +++ b/apps/web/client/src/stories/SelectProject.stories.tsx @@ -1,14 +1,9 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; import { SelectProjectPresentation } from '@/app/projects/_components/select-presentation'; import type { Project } from '@onlook/models'; import { fn } from '@storybook/test'; -/** - * SelectProject displays the main project selection interface with recent projects carousel, - * templates section, and a full projects grid/masonry layout. - */ const meta = { - title: 'Projects/SelectProject', component: SelectProjectPresentation, parameters: { layout: 'fullscreen', diff --git a/apps/web/client/src/stories/Separator.stories.tsx b/apps/web/client/src/stories/Separator.stories.tsx new file mode 100644 index 0000000000..530dd08518 --- /dev/null +++ b/apps/web/client/src/stories/Separator.stories.tsx @@ -0,0 +1,84 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import { Separator } from '@onlook/ui/separator'; + +const meta = { + component: Separator, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + orientation: { + description: 'Orientation of the separator', + control: { type: 'select' }, + options: ['horizontal', 'vertical'], + }, + decorative: { + description: 'Whether the separator is decorative', + control: 'boolean', + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + orientation: 'horizontal', + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], +}; + +export const Horizontal: Story = { + render: () => ( +
+
+

Radix Primitives

+

+ An open-source UI component library. +

+
+ +
+
Blog
+ +
Docs
+ +
Source
+
+
+ ), +}; + +export const Vertical: Story = { + render: () => ( +
+
Blog
+ +
Docs
+ +
Source
+
+ ), +}; + +export const InList: Story = { + render: () => ( +
+
Item 1
+ +
Item 2
+ +
Item 3
+ +
Item 4
+
+ ), +}; diff --git a/apps/web/client/src/stories/Skeleton.stories.tsx b/apps/web/client/src/stories/Skeleton.stories.tsx new file mode 100644 index 0000000000..dadab7f42d --- /dev/null +++ b/apps/web/client/src/stories/Skeleton.stories.tsx @@ -0,0 +1,95 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import { Skeleton } from '@onlook/ui/skeleton'; + +const meta = { + component: Skeleton, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + className: 'h-4 w-[250px]', + }, +}; + +export const Circle: Story = { + args: { + className: 'h-12 w-12 rounded-full', + }, +}; + +export const Card: Story = { + render: () => ( +
+ +
+ + +
+
+ ), +}; + +export const TextLines: Story = { + render: () => ( +
+ + + +
+ ), +}; + +export const ProfileCard: Story = { + render: () => ( +
+ +
+ + +
+
+ ), +}; + +export const ListItems: Story = { + render: () => ( +
+ {[1, 2, 3].map((i) => ( +
+ +
+ + +
+
+ ))} +
+ ), +}; + +export const FormSkeleton: Story = { + render: () => ( +
+
+ + +
+
+ + +
+
+ + +
+ +
+ ), +}; diff --git a/apps/web/client/src/stories/Slider.stories.tsx b/apps/web/client/src/stories/Slider.stories.tsx new file mode 100644 index 0000000000..f84e1c3394 --- /dev/null +++ b/apps/web/client/src/stories/Slider.stories.tsx @@ -0,0 +1,106 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import { fn } from '@storybook/test'; +import { Slider } from '@onlook/ui/slider'; + +const meta = { + component: Slider, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + min: { + description: 'Minimum value', + control: 'number', + }, + max: { + description: 'Maximum value', + control: 'number', + }, + step: { + description: 'Step increment', + control: 'number', + }, + disabled: { + description: 'Whether the slider is disabled', + control: 'boolean', + }, + }, + args: { + onValueChange: fn(), + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + defaultValue: [50], + min: 0, + max: 100, + }, +}; + +export const WithStep: Story = { + args: { + defaultValue: [25], + min: 0, + max: 100, + step: 25, + }, +}; + +export const Range: Story = { + args: { + defaultValue: [25, 75], + min: 0, + max: 100, + }, +}; + +export const Disabled: Story = { + args: { + defaultValue: [50], + disabled: true, + }, +}; + +export const CustomRange: Story = { + args: { + defaultValue: [5], + min: 0, + max: 10, + step: 1, + }, +}; + +export const Values: Story = { + render: () => ( +
+
+
0%
+ +
+
+
50%
+ +
+
+
100%
+ +
+
+
Range (25-75)
+ +
+
+ ), +}; diff --git a/apps/web/client/src/stories/Switch.stories.tsx b/apps/web/client/src/stories/Switch.stories.tsx new file mode 100644 index 0000000000..57bc4e093a --- /dev/null +++ b/apps/web/client/src/stories/Switch.stories.tsx @@ -0,0 +1,86 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import { fn } from '@storybook/test'; +import { Switch } from '@onlook/ui/switch'; +import { Label } from '@onlook/ui/label'; + +const meta = { + component: Switch, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + checked: { + description: 'Whether the switch is checked', + control: 'boolean', + }, + disabled: { + description: 'Whether the switch is disabled', + control: 'boolean', + }, + }, + args: { + onCheckedChange: fn(), + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + checked: false, + disabled: false, + }, +}; + +export const Checked: Story = { + args: { + checked: true, + }, +}; + +export const Disabled: Story = { + args: { + disabled: true, + }, +}; + +export const DisabledChecked: Story = { + args: { + checked: true, + disabled: true, + }, +}; + +export const WithLabel: Story = { + render: () => ( +
+ + +
+ ), +}; + +export const States: Story = { + render: () => ( +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ ), +}; diff --git a/apps/web/client/src/stories/Tabs.stories.tsx b/apps/web/client/src/stories/Tabs.stories.tsx new file mode 100644 index 0000000000..55bb4b72e9 --- /dev/null +++ b/apps/web/client/src/stories/Tabs.stories.tsx @@ -0,0 +1,119 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import { Tabs, TabsList, TabsTrigger, TabsContent } from '@onlook/ui/tabs'; +import { Settings, User, CreditCard } from 'lucide-react'; + +const meta = { + component: Tabs, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + Account + Password + + +

+ Make changes to your account here. +

+
+ +

+ Change your password here. +

+
+
+ ), +}; + +export const WithIcons: Story = { + render: () => ( + + + + + Profile + + + + Settings + + + + Billing + + + +

+ Manage your profile information. +

+
+ +

+ Configure your application settings. +

+
+ +

+ Manage your billing and subscription. +

+
+
+ ), +}; + +export const ThreeTabs: Story = { + render: () => ( + + + Tab 1 + Tab 2 + Tab 3 + + +

Content for Tab 1

+
+ +

Content for Tab 2

+
+ +

Content for Tab 3

+
+
+ ), +}; + +export const DisabledTab: Story = { + render: () => ( + + + Active + + Disabled + + Another + + +

This tab is active.

+
+ +

Another tab content.

+
+
+ ), +}; diff --git a/apps/web/client/src/stories/Textarea.stories.tsx b/apps/web/client/src/stories/Textarea.stories.tsx new file mode 100644 index 0000000000..169e78bf67 --- /dev/null +++ b/apps/web/client/src/stories/Textarea.stories.tsx @@ -0,0 +1,77 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; +import { Textarea } from '@onlook/ui/textarea'; + +const meta = { + component: Textarea, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + placeholder: { + description: 'Placeholder text', + control: 'text', + }, + disabled: { + description: 'Whether the textarea is disabled', + control: 'boolean', + }, + rows: { + description: 'Number of visible text lines', + control: 'number', + }, + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + placeholder: 'Type your message here...', + }, +}; + +export const WithValue: Story = { + args: { + defaultValue: 'This is some pre-filled content in the textarea.', + }, +}; + +export const Disabled: Story = { + args: { + placeholder: 'Disabled textarea', + disabled: true, + }, +}; + +export const WithRows: Story = { + args: { + placeholder: 'Textarea with 5 rows', + rows: 5, + }, +}; + +export const LongContent: Story = { + args: { + defaultValue: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.', + }, +}; + +export const States: Story = { + render: () => ( +
+