diff --git a/packages/ui/.storybook/main.ts b/packages/ui/.storybook/main.ts new file mode 100644 index 00000000..a01fb35b --- /dev/null +++ b/packages/ui/.storybook/main.ts @@ -0,0 +1,12 @@ +import type { StorybookConfig } from '@storybook/react-vite'; + +const config: StorybookConfig = { + stories: ['../src/**/*.stories.@(ts|tsx)'], + addons: ['@storybook/addon-essentials', '@storybook/addon-a11y'], + framework: { + name: '@storybook/react-vite', + options: {}, + }, +}; + +export default config; diff --git a/packages/ui/.storybook/preview.ts b/packages/ui/.storybook/preview.ts new file mode 100644 index 00000000..f7c4aa21 --- /dev/null +++ b/packages/ui/.storybook/preview.ts @@ -0,0 +1,16 @@ +import type { Preview } from '@storybook/react'; + +const preview: Preview = { + parameters: { + backgrounds: { + default: 'dark', + values: [ + { name: 'dark', value: '#06070A' }, + { name: 'elevated', value: '#0E1118' }, + { name: 'light', value: '#F8F9FC' }, + ], + }, + }, +}; + +export default preview; diff --git a/packages/ui/package.json b/packages/ui/package.json index 84b30bd2..b5a9eabb 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -2,6 +2,10 @@ "name": "@bytelyst/ui", "version": "0.1.0", "type": "module", + "scripts": { + "storybook": "storybook dev -p 6006", + "build-storybook": "storybook build" + }, "exports": { ".": "./src/index.ts", "./button": "./src/components/Button.tsx", @@ -31,6 +35,12 @@ "devDependencies": { "typescript": "^5.7.0", "@types/react": "^19.0.0", - "@types/react-dom": "^19.0.0" + "@types/react-dom": "^19.0.0", + "@storybook/react-vite": "^8.5.0", + "@storybook/react": "^8.5.0", + "@storybook/addon-essentials": "^8.5.0", + "@storybook/addon-a11y": "^8.5.0", + "storybook": "^8.5.0", + "vite": "^6.0.0" } } diff --git a/packages/ui/src/components/Badge.stories.tsx b/packages/ui/src/components/Badge.stories.tsx new file mode 100644 index 00000000..0e532fa1 --- /dev/null +++ b/packages/ui/src/components/Badge.stories.tsx @@ -0,0 +1,22 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Badge } from './Badge.js'; + +const meta: Meta = { + title: 'Components/Badge', + component: Badge, + argTypes: { + variant: { control: 'select', options: ['success', 'warning', 'error', 'info', 'neutral'] }, + size: { control: 'select', options: ['sm', 'md'] }, + dot: { control: 'boolean' }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Success: Story = { args: { children: 'Active', variant: 'success' } }; +export const Warning: Story = { args: { children: 'Pending', variant: 'warning' } }; +export const Error: Story = { args: { children: 'Failed', variant: 'error' } }; +export const Info: Story = { args: { children: 'Info', variant: 'info' } }; +export const Neutral: Story = { args: { children: 'Draft', variant: 'neutral' } }; +export const WithDot: Story = { args: { children: 'Online', variant: 'success', dot: true } }; diff --git a/packages/ui/src/components/Button.stories.tsx b/packages/ui/src/components/Button.stories.tsx new file mode 100644 index 00000000..7c116043 --- /dev/null +++ b/packages/ui/src/components/Button.stories.tsx @@ -0,0 +1,44 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Button } from './Button.js'; + +const meta: Meta = { + title: 'Components/Button', + component: Button, + argTypes: { + variant: { control: 'select', options: ['primary', 'secondary', 'ghost', 'danger'] }, + size: { control: 'select', options: ['sm', 'md', 'lg'] }, + loading: { control: 'boolean' }, + disabled: { control: 'boolean' }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: { children: 'Primary Button', variant: 'primary' }, +}; + +export const Secondary: Story = { + args: { children: 'Secondary Button', variant: 'secondary' }, +}; + +export const Ghost: Story = { + args: { children: 'Ghost Button', variant: 'ghost' }, +}; + +export const Danger: Story = { + args: { children: 'Danger Button', variant: 'danger' }, +}; + +export const Loading: Story = { + args: { children: 'Loading...', variant: 'primary', loading: true }, +}; + +export const Small: Story = { + args: { children: 'Small', variant: 'primary', size: 'sm' }, +}; + +export const Large: Story = { + args: { children: 'Large', variant: 'primary', size: 'lg' }, +}; diff --git a/packages/ui/src/components/Card.stories.tsx b/packages/ui/src/components/Card.stories.tsx new file mode 100644 index 00000000..0f8a8f04 --- /dev/null +++ b/packages/ui/src/components/Card.stories.tsx @@ -0,0 +1,38 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Card, CardHeader, CardTitle, CardDescription } from './Card.js'; + +const meta: Meta = { + title: 'Components/Card', + component: Card, + argTypes: { + padding: { control: 'select', options: ['none', 'sm', 'md', 'lg'] }, + hover: { control: 'boolean' }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { children: 'Card content goes here' }, +}; + +export const WithHeader: Story = { + render: args => ( + + + Card Title + A short description of this card. + +

Body content

+
+ ), +}; + +export const Hoverable: Story = { + args: { hover: true, children: 'Hover me to see the border effect' }, +}; + +export const LargePadding: Story = { + args: { padding: 'lg', children: 'Large padding card' }, +}; diff --git a/packages/ui/src/components/Input.stories.tsx b/packages/ui/src/components/Input.stories.tsx new file mode 100644 index 00000000..c4d1e31e --- /dev/null +++ b/packages/ui/src/components/Input.stories.tsx @@ -0,0 +1,20 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Input } from './Input.js'; + +const meta: Meta = { + title: 'Components/Input', + component: Input, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { args: { placeholder: 'Enter text...' } }; +export const WithLabel: Story = { args: { label: 'Email', placeholder: 'you@example.com' } }; +export const WithError: Story = { + args: { label: 'Email', value: 'bad', error: 'Invalid email address' }, +}; +export const WithHint: Story = { + args: { label: 'Username', placeholder: 'johndoe', hint: '3-20 characters, no spaces' }, +}; +export const Disabled: Story = { args: { label: 'Read Only', value: 'locked', disabled: true } };