add storybook
This commit is contained in:
2
react-advanced-tag1/.gitignore
vendored
2
react-advanced-tag1/.gitignore
vendored
@@ -22,3 +22,5 @@ dist-ssr
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
*storybook.log
|
||||
|
||||
19
react-advanced-tag1/.storybook/main.ts
Normal file
19
react-advanced-tag1/.storybook/main.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import type { StorybookConfig } from '@storybook/react-vite';
|
||||
|
||||
const config: StorybookConfig = {
|
||||
"stories": [
|
||||
"../src/**/*.mdx",
|
||||
"../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"
|
||||
],
|
||||
"addons": [
|
||||
"@storybook/addon-essentials",
|
||||
"@storybook/addon-onboarding",
|
||||
"@chromatic-com/storybook",
|
||||
"@storybook/experimental-addon-test"
|
||||
],
|
||||
"framework": {
|
||||
"name": "@storybook/react-vite",
|
||||
"options": {}
|
||||
}
|
||||
};
|
||||
export default config;
|
||||
15
react-advanced-tag1/.storybook/preview.ts
Normal file
15
react-advanced-tag1/.storybook/preview.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import type { Preview } from '@storybook/react'
|
||||
|
||||
const preview: Preview = {
|
||||
parameters: {
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/i,
|
||||
},
|
||||
},
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
}
|
||||
|
||||
export default preview
|
||||
9
react-advanced-tag1/.storybook/vitest.setup.ts
Normal file
9
react-advanced-tag1/.storybook/vitest.setup.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { beforeAll } from 'vitest';
|
||||
import { setProjectAnnotations } from '@storybook/react';
|
||||
import * as projectAnnotations from './preview';
|
||||
|
||||
// This is an important step to apply the right configuration when testing your stories.
|
||||
// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations
|
||||
const project = setProjectAnnotations([projectAnnotations]);
|
||||
|
||||
beforeAll(project.beforeAll);
|
||||
1824
react-advanced-tag1/package-lock.json
generated
1824
react-advanced-tag1/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,9 @@
|
||||
"test:coverage": "vitest --coverage",
|
||||
"test:coverage:report": "vitest --coverage --reporter=html",
|
||||
"test:coverage:report:open": "vitest --coverage --reporter=html && open coverage/index.html",
|
||||
"prettier": "prettier ./src --write"
|
||||
"prettier": "prettier ./src --write",
|
||||
"storybook": "storybook dev -p 6006",
|
||||
"build-storybook": "storybook build"
|
||||
},
|
||||
"dependencies": {
|
||||
"immer": "^10.1.1",
|
||||
@@ -27,22 +29,39 @@
|
||||
"zustand": "^5.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@chromatic-com/storybook": "^3.2.6",
|
||||
"@eslint/js": "^9.21.0",
|
||||
"@storybook/addon-essentials": "^8.6.12",
|
||||
"@storybook/addon-onboarding": "^8.6.12",
|
||||
"@storybook/blocks": "^8.6.12",
|
||||
"@storybook/experimental-addon-test": "^8.6.12",
|
||||
"@storybook/react": "^8.6.12",
|
||||
"@storybook/react-vite": "^8.6.12",
|
||||
"@storybook/test": "^8.6.12",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@types/react": "^19.0.10",
|
||||
"@types/react-dom": "^19.0.4",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"@vitest/browser": "^3.1.1",
|
||||
"@vitest/coverage-v8": "^3.1.1",
|
||||
"@vitest/ui": "^3.1.1",
|
||||
"eslint": "^9.21.0",
|
||||
"eslint-plugin-react-hooks": "^5.1.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.19",
|
||||
"eslint-plugin-storybook": "^0.12.0",
|
||||
"globals": "^15.15.0",
|
||||
"jsdom": "^26.0.0",
|
||||
"playwright": "^1.51.1",
|
||||
"prettier": "3.5.3",
|
||||
"storybook": "^8.6.12",
|
||||
"typescript": "~5.7.2",
|
||||
"typescript-eslint": "^8.24.1",
|
||||
"vite": "^6.2.0",
|
||||
"vitest": "^3.1.1"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"plugin:storybook/recommended"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
import './ComponentWrapper.css'
|
||||
|
||||
interface ComponentWrapperProps {
|
||||
/** Title to show */
|
||||
title?: string
|
||||
/** Description to show */
|
||||
description?: string
|
||||
/** Content to show */
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper component that displays a title, description, and content.
|
||||
*/
|
||||
export default function ComponentWrapper({
|
||||
children,
|
||||
title,
|
||||
|
||||
41
react-advanced-tag1/src/common/components/globals/Button.tsx
Normal file
41
react-advanced-tag1/src/common/components/globals/Button.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import { ComponentPropsWithoutRef, CSSProperties } from 'react'
|
||||
|
||||
interface ButtonProps extends ComponentPropsWithoutRef<'button'> {
|
||||
variant: 'primary' | 'secondary'
|
||||
size: 'sm' | 'md' | 'lg'
|
||||
}
|
||||
|
||||
export const Button = ({
|
||||
children,
|
||||
variant,
|
||||
size,
|
||||
...restProps
|
||||
}: ButtonProps) => {
|
||||
const sizeStyles: Record<ButtonProps['size'], CSSProperties> = {
|
||||
sm: {
|
||||
padding: '0.5rem',
|
||||
},
|
||||
md: {
|
||||
padding: '0.75rem',
|
||||
},
|
||||
lg: {
|
||||
padding: '1rem',
|
||||
},
|
||||
}
|
||||
const variantStyles: Record<ButtonProps['variant'], CSSProperties> = {
|
||||
primary: {
|
||||
backgroundColor: 'blue',
|
||||
},
|
||||
secondary: {
|
||||
backgroundColor: 'gray',
|
||||
},
|
||||
}
|
||||
return (
|
||||
<button
|
||||
{...restProps}
|
||||
style={{ ...variantStyles[variant], ...sizeStyles[size] }}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { useState } from 'react'
|
||||
import './MainLayout.css'
|
||||
import Footer from '../common/components/Footer'
|
||||
import Header from '../common/components/Header'
|
||||
import { Button } from '../common/components/globals/Button'
|
||||
|
||||
export default function MainLayout({
|
||||
children,
|
||||
@@ -24,7 +25,9 @@ export default function MainLayout({
|
||||
<div className="content">
|
||||
{children}
|
||||
|
||||
<button onClick={handleClick}>Click</button>
|
||||
<Button onClick={handleClick} variant="secondary" size="sm">
|
||||
Click
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
|
||||
51
react-advanced-tag1/src/stories/Button.stories.tsx
Normal file
51
react-advanced-tag1/src/stories/Button.stories.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import { Button } from '../common/components/globals/Button'
|
||||
import { fn } from '@storybook/test'
|
||||
import { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
const meta: Meta<typeof Button> = {
|
||||
title: 'Elements/Button',
|
||||
component: Button,
|
||||
argTypes: {
|
||||
variant: { control: 'radio', options: ['primary', 'secondary'] },
|
||||
size: { control: 'radio', options: ['sm', 'md', 'lg'] },
|
||||
},
|
||||
args: {
|
||||
onClick: fn(),
|
||||
},
|
||||
}
|
||||
|
||||
export default meta
|
||||
|
||||
type Story = StoryObj<typeof Button>
|
||||
|
||||
export const Primary: Story = {
|
||||
args: {
|
||||
children: 'Primary Button',
|
||||
variant: 'primary',
|
||||
size: 'md',
|
||||
},
|
||||
}
|
||||
|
||||
export const Secondary: Story = {
|
||||
args: {
|
||||
children: 'Secondary Button',
|
||||
variant: 'secondary',
|
||||
size: 'md',
|
||||
},
|
||||
}
|
||||
|
||||
export const Small: Story = {
|
||||
args: {
|
||||
children: 'Small Button',
|
||||
variant: 'primary',
|
||||
size: 'sm',
|
||||
},
|
||||
}
|
||||
|
||||
export const Large: Story = {
|
||||
args: {
|
||||
children: 'Large Button',
|
||||
variant: 'primary',
|
||||
size: 'lg',
|
||||
},
|
||||
}
|
||||
43
react-advanced-tag1/src/stories/ComponentWrapper.stories.tsx
Normal file
43
react-advanced-tag1/src/stories/ComponentWrapper.stories.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import ComponentWrapper from '../common/components/ComponentWrapper/ComponentWrapper'
|
||||
import { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
const meta: Meta<typeof ComponentWrapper> = {
|
||||
title: 'Wrapper/ComponentWrapper',
|
||||
component: ComponentWrapper,
|
||||
argTypes: {
|
||||
title: { control: 'text' },
|
||||
description: { control: 'text' },
|
||||
},
|
||||
}
|
||||
|
||||
export default meta
|
||||
|
||||
type Story = StoryObj<typeof ComponentWrapper>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
title: 'Default Title',
|
||||
description: 'This is a default description.',
|
||||
children: <p>Default content goes here.</p>,
|
||||
},
|
||||
}
|
||||
|
||||
export const WithoutTitle: Story = {
|
||||
args: {
|
||||
description: 'This wrapper has no title.',
|
||||
children: <p>Content without a title.</p>,
|
||||
},
|
||||
}
|
||||
|
||||
export const WithoutDescription: Story = {
|
||||
args: {
|
||||
title: 'Title Only',
|
||||
children: <p>Content without a description.</p>,
|
||||
},
|
||||
}
|
||||
|
||||
export const Empty: Story = {
|
||||
args: {
|
||||
children: <p>Empty wrapper with only content.</p>,
|
||||
},
|
||||
}
|
||||
15
react-advanced-tag1/src/stories/Footer.stories.tsx
Normal file
15
react-advanced-tag1/src/stories/Footer.stories.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Meta, StoryObj } from '@storybook/react'
|
||||
import Footer from '../common/components/Footer'
|
||||
|
||||
const meta: Meta<typeof Footer> = {
|
||||
title: 'Common/Footer',
|
||||
component: Footer,
|
||||
}
|
||||
|
||||
export default meta
|
||||
|
||||
type Story = StoryObj<typeof Footer>
|
||||
|
||||
export const Default: Story = {
|
||||
render: () => <Footer />,
|
||||
}
|
||||
15
react-advanced-tag1/src/stories/Header.stories.tsx
Normal file
15
react-advanced-tag1/src/stories/Header.stories.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import Header from '../common/components/Header/index'
|
||||
import { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
const meta: Meta<typeof Header> = {
|
||||
title: 'Common/Header',
|
||||
component: Header,
|
||||
}
|
||||
|
||||
export default meta
|
||||
|
||||
type Story = StoryObj<typeof Header>
|
||||
|
||||
export const Default: Story = {
|
||||
render: () => <Header />,
|
||||
}
|
||||
1
react-advanced-tag1/vitest.shims.d.ts
vendored
Normal file
1
react-advanced-tag1/vitest.shims.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="@vitest/browser/providers/playwright" />
|
||||
34
react-advanced-tag1/vitest.workspace.ts
Normal file
34
react-advanced-tag1/vitest.workspace.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { defineWorkspace } from 'vitest/config';
|
||||
|
||||
import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin';
|
||||
|
||||
const dirname =
|
||||
typeof __dirname !== 'undefined'
|
||||
? __dirname
|
||||
: path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
// More info at: https://storybook.js.org/docs/writing-tests/test-addon
|
||||
export default defineWorkspace([
|
||||
'vite.config.ts',
|
||||
{
|
||||
extends: 'vite.config.ts',
|
||||
plugins: [
|
||||
// The plugin will run tests for the stories defined in your Storybook config
|
||||
// See options at: https://storybook.js.org/docs/writing-tests/test-addon#storybooktest
|
||||
storybookTest({ configDir: path.join(dirname, '.storybook') }),
|
||||
],
|
||||
test: {
|
||||
name: 'storybook',
|
||||
browser: {
|
||||
enabled: true,
|
||||
headless: true,
|
||||
provider: 'playwright',
|
||||
instances: [{ browser: 'chromium' }],
|
||||
},
|
||||
setupFiles: ['.storybook/vitest.setup.ts'],
|
||||
},
|
||||
},
|
||||
]);
|
||||
Reference in New Issue
Block a user