chore: improve storybook (#27111)
This commit is contained in:
@@ -1,19 +1,29 @@
|
|||||||
import type { StorybookConfig } from '@storybook/nextjs'
|
import type { StorybookConfig } from '@storybook/nextjs'
|
||||||
|
|
||||||
const config: StorybookConfig = {
|
const config: StorybookConfig = {
|
||||||
// stories: ['../stories/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
|
|
||||||
stories: ['../app/components/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
|
stories: ['../app/components/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
|
||||||
addons: [
|
addons: [
|
||||||
'@storybook/addon-onboarding',
|
'@storybook/addon-onboarding',
|
||||||
'@storybook/addon-links',
|
'@storybook/addon-links',
|
||||||
'@storybook/addon-essentials',
|
'@storybook/addon-docs',
|
||||||
'@chromatic-com/storybook',
|
'@chromatic-com/storybook',
|
||||||
'@storybook/addon-interactions',
|
|
||||||
],
|
],
|
||||||
framework: {
|
framework: {
|
||||||
name: '@storybook/nextjs',
|
name: '@storybook/nextjs',
|
||||||
options: {},
|
options: {
|
||||||
|
builder: {
|
||||||
|
useSWC: true,
|
||||||
|
lazyCompilation: false,
|
||||||
|
},
|
||||||
|
nextConfigPath: undefined,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
staticDirs: ['../public'],
|
staticDirs: ['../public'],
|
||||||
|
core: {
|
||||||
|
disableWhatsNewNotifications: true,
|
||||||
|
},
|
||||||
|
docs: {
|
||||||
|
defaultName: 'Documentation',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
export default config
|
export default config
|
||||||
|
|||||||
@@ -1,12 +1,21 @@
|
|||||||
import React from 'react'
|
|
||||||
import type { Preview } from '@storybook/react'
|
import type { Preview } from '@storybook/react'
|
||||||
import { withThemeByDataAttribute } from '@storybook/addon-themes'
|
import { withThemeByDataAttribute } from '@storybook/addon-themes'
|
||||||
import I18nServer from '../app/components/i18n-server'
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||||
|
import I18N from '../app/components/i18n'
|
||||||
|
import { ToastProvider } from '../app/components/base/toast'
|
||||||
|
|
||||||
import '../app/styles/globals.css'
|
import '../app/styles/globals.css'
|
||||||
import '../app/styles/markdown.scss'
|
import '../app/styles/markdown.scss'
|
||||||
import './storybook.css'
|
import './storybook.css'
|
||||||
|
|
||||||
|
const queryClient = new QueryClient({
|
||||||
|
defaultOptions: {
|
||||||
|
queries: {
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
export const decorators = [
|
export const decorators = [
|
||||||
withThemeByDataAttribute({
|
withThemeByDataAttribute({
|
||||||
themes: {
|
themes: {
|
||||||
@@ -17,9 +26,15 @@ export const decorators = [
|
|||||||
attributeName: 'data-theme',
|
attributeName: 'data-theme',
|
||||||
}),
|
}),
|
||||||
(Story) => {
|
(Story) => {
|
||||||
return <I18nServer>
|
return (
|
||||||
|
<QueryClientProvider client={queryClient}>
|
||||||
|
<I18N locale="en-US">
|
||||||
|
<ToastProvider>
|
||||||
<Story />
|
<Story />
|
||||||
</I18nServer>
|
</ToastProvider>
|
||||||
|
</I18N>
|
||||||
|
</QueryClientProvider>
|
||||||
|
)
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -31,7 +46,11 @@ const preview: Preview = {
|
|||||||
date: /Date$/i,
|
date: /Date$/i,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
docs: {
|
||||||
|
toc: true,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
tags: ['autodocs'],
|
||||||
}
|
}
|
||||||
|
|
||||||
export default preview
|
export default preview
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react'
|
import type { Meta, StoryObj } from '@storybook/nextjs'
|
||||||
import { fn } from '@storybook/test'
|
|
||||||
|
|
||||||
import { RocketLaunchIcon } from '@heroicons/react/20/solid'
|
import { RocketLaunchIcon } from '@heroicons/react/20/solid'
|
||||||
import { Button } from '.'
|
import { Button } from '.'
|
||||||
@@ -20,8 +19,7 @@ const meta = {
|
|||||||
},
|
},
|
||||||
args: {
|
args: {
|
||||||
variant: 'ghost',
|
variant: 'ghost',
|
||||||
onClick: fn(),
|
children: 'Button',
|
||||||
children: 'adsf',
|
|
||||||
},
|
},
|
||||||
} satisfies Meta<typeof Button>
|
} satisfies Meta<typeof Button>
|
||||||
|
|
||||||
@@ -33,6 +31,9 @@ export const Default: Story = {
|
|||||||
variant: 'primary',
|
variant: 'primary',
|
||||||
loading: false,
|
loading: false,
|
||||||
children: 'Primary Button',
|
children: 'Primary Button',
|
||||||
|
styleCss: {},
|
||||||
|
spinnerClassName: '',
|
||||||
|
destructive: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react'
|
import type { Meta, StoryObj } from '@storybook/nextjs'
|
||||||
|
|
||||||
import type { ChatItem } from '../../types'
|
import type { ChatItem } from '../../types'
|
||||||
import { mockedWorkflowProcess } from './__mocks__/workflowProcess'
|
import { mockedWorkflowProcess } from './__mocks__/workflowProcess'
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react'
|
import type { Meta, StoryObj } from '@storybook/nextjs'
|
||||||
|
|
||||||
import type { ChatItem } from '../types'
|
import type { ChatItem } from '../types'
|
||||||
import Question from './question'
|
import Question from './question'
|
||||||
|
|||||||
199
web/app/components/base/confirm/index.stories.tsx
Normal file
199
web/app/components/base/confirm/index.stories.tsx
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/nextjs'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import Confirm from '.'
|
||||||
|
import Button from '../button'
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
title: 'Base/Confirm',
|
||||||
|
component: Confirm,
|
||||||
|
parameters: {
|
||||||
|
layout: 'centered',
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
component: 'Confirmation dialog component that supports warning and info types, with customizable button text and behavior.',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tags: ['autodocs'],
|
||||||
|
argTypes: {
|
||||||
|
type: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['info', 'warning'],
|
||||||
|
description: 'Dialog type',
|
||||||
|
},
|
||||||
|
isShow: {
|
||||||
|
control: 'boolean',
|
||||||
|
description: 'Whether to show the dialog',
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
control: 'text',
|
||||||
|
description: 'Dialog title',
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
control: 'text',
|
||||||
|
description: 'Dialog content',
|
||||||
|
},
|
||||||
|
confirmText: {
|
||||||
|
control: 'text',
|
||||||
|
description: 'Confirm button text',
|
||||||
|
},
|
||||||
|
cancelText: {
|
||||||
|
control: 'text',
|
||||||
|
description: 'Cancel button text',
|
||||||
|
},
|
||||||
|
isLoading: {
|
||||||
|
control: 'boolean',
|
||||||
|
description: 'Confirm button loading state',
|
||||||
|
},
|
||||||
|
isDisabled: {
|
||||||
|
control: 'boolean',
|
||||||
|
description: 'Confirm button disabled state',
|
||||||
|
},
|
||||||
|
showConfirm: {
|
||||||
|
control: 'boolean',
|
||||||
|
description: 'Whether to show confirm button',
|
||||||
|
},
|
||||||
|
showCancel: {
|
||||||
|
control: 'boolean',
|
||||||
|
description: 'Whether to show cancel button',
|
||||||
|
},
|
||||||
|
maskClosable: {
|
||||||
|
control: 'boolean',
|
||||||
|
description: 'Whether clicking mask closes dialog',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} satisfies Meta<typeof Confirm>
|
||||||
|
|
||||||
|
export default meta
|
||||||
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
|
// Interactive demo wrapper
|
||||||
|
const ConfirmDemo = (args: any) => {
|
||||||
|
const [isShow, setIsShow] = useState(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Button variant="primary" onClick={() => setIsShow(true)}>
|
||||||
|
Open Dialog
|
||||||
|
</Button>
|
||||||
|
<Confirm
|
||||||
|
{...args}
|
||||||
|
isShow={isShow}
|
||||||
|
onConfirm={() => {
|
||||||
|
console.log('✅ User clicked confirm')
|
||||||
|
setIsShow(false)
|
||||||
|
}}
|
||||||
|
onCancel={() => {
|
||||||
|
console.log('❌ User clicked cancel')
|
||||||
|
setIsShow(false)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic warning dialog - Delete action
|
||||||
|
export const WarningDialog: Story = {
|
||||||
|
render: args => <ConfirmDemo {...args} />,
|
||||||
|
args: {
|
||||||
|
type: 'warning',
|
||||||
|
title: 'Delete Confirmation',
|
||||||
|
content: 'Are you sure you want to delete this project? This action cannot be undone.',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info dialog
|
||||||
|
export const InfoDialog: Story = {
|
||||||
|
render: args => <ConfirmDemo {...args} />,
|
||||||
|
args: {
|
||||||
|
type: 'info',
|
||||||
|
title: 'Notice',
|
||||||
|
content: 'Your changes have been saved. Do you want to proceed to the next step?',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom button text
|
||||||
|
export const CustomButtonText: Story = {
|
||||||
|
render: args => <ConfirmDemo {...args} />,
|
||||||
|
args: {
|
||||||
|
type: 'warning',
|
||||||
|
title: 'Exit Editor',
|
||||||
|
content: 'You have unsaved changes. Are you sure you want to exit?',
|
||||||
|
confirmText: 'Discard Changes',
|
||||||
|
cancelText: 'Continue Editing',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loading state
|
||||||
|
export const LoadingState: Story = {
|
||||||
|
render: args => <ConfirmDemo {...args} />,
|
||||||
|
args: {
|
||||||
|
type: 'warning',
|
||||||
|
title: 'Deleting...',
|
||||||
|
content: 'Please wait while we delete the file...',
|
||||||
|
isLoading: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disabled state
|
||||||
|
export const DisabledState: Story = {
|
||||||
|
render: args => <ConfirmDemo {...args} />,
|
||||||
|
args: {
|
||||||
|
type: 'info',
|
||||||
|
title: 'Verification Required',
|
||||||
|
content: 'Please complete email verification before proceeding.',
|
||||||
|
isDisabled: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alert style - Confirm button only
|
||||||
|
export const AlertStyle: Story = {
|
||||||
|
render: args => <ConfirmDemo {...args} />,
|
||||||
|
args: {
|
||||||
|
type: 'info',
|
||||||
|
title: 'Success',
|
||||||
|
content: 'Your settings have been updated!',
|
||||||
|
showCancel: false,
|
||||||
|
confirmText: 'Got it',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dangerous action - Long content
|
||||||
|
export const DangerousAction: Story = {
|
||||||
|
render: args => <ConfirmDemo {...args} />,
|
||||||
|
args: {
|
||||||
|
type: 'warning',
|
||||||
|
title: 'Permanently Delete Account',
|
||||||
|
content: 'This action will permanently delete your account and all associated data, including: all projects and files, collaboration history, and personal settings. This action cannot be reversed!',
|
||||||
|
confirmText: 'Delete My Account',
|
||||||
|
cancelText: 'Keep My Account',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-closable mask
|
||||||
|
export const NotMaskClosable: Story = {
|
||||||
|
render: args => <ConfirmDemo {...args} />,
|
||||||
|
args: {
|
||||||
|
type: 'warning',
|
||||||
|
title: 'Important Action',
|
||||||
|
content: 'This action requires your explicit choice. Clicking outside will not close this dialog.',
|
||||||
|
maskClosable: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full feature demo - Playground
|
||||||
|
export const Playground: Story = {
|
||||||
|
render: args => <ConfirmDemo {...args} />,
|
||||||
|
args: {
|
||||||
|
type: 'warning',
|
||||||
|
title: 'This is a title',
|
||||||
|
content: 'This is the dialog content text...',
|
||||||
|
confirmText: undefined,
|
||||||
|
cancelText: undefined,
|
||||||
|
isLoading: false,
|
||||||
|
isDisabled: false,
|
||||||
|
showConfirm: true,
|
||||||
|
showCancel: true,
|
||||||
|
maskClosable: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -142,7 +142,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@antfu/eslint-config": "^5.0.0",
|
"@antfu/eslint-config": "^5.0.0",
|
||||||
"@babel/core": "^7.28.3",
|
"@babel/core": "^7.28.3",
|
||||||
"@chromatic-com/storybook": "^3.1.0",
|
"@chromatic-com/storybook": "^4.1.1",
|
||||||
"@eslint-react/eslint-plugin": "^1.15.0",
|
"@eslint-react/eslint-plugin": "^1.15.0",
|
||||||
"@happy-dom/jest-environment": "^20.0.2",
|
"@happy-dom/jest-environment": "^20.0.2",
|
||||||
"@mdx-js/loader": "^3.1.0",
|
"@mdx-js/loader": "^3.1.0",
|
||||||
@@ -151,14 +151,12 @@
|
|||||||
"@next/eslint-plugin-next": "15.5.4",
|
"@next/eslint-plugin-next": "15.5.4",
|
||||||
"@next/mdx": "15.5.4",
|
"@next/mdx": "15.5.4",
|
||||||
"@rgrove/parse-xml": "^4.1.0",
|
"@rgrove/parse-xml": "^4.1.0",
|
||||||
"@storybook/addon-essentials": "8.5.0",
|
"@storybook/addon-docs": "9.1.13",
|
||||||
"@storybook/addon-interactions": "8.5.0",
|
"@storybook/addon-links": "9.1.13",
|
||||||
"@storybook/addon-links": "8.5.0",
|
"@storybook/addon-onboarding": "9.1.13",
|
||||||
"@storybook/addon-onboarding": "8.5.0",
|
"@storybook/addon-themes": "9.1.13",
|
||||||
"@storybook/addon-themes": "8.5.0",
|
"@storybook/nextjs": "9.1.13",
|
||||||
"@storybook/nextjs": "8.5.0",
|
"@storybook/react": "9.1.13",
|
||||||
"@storybook/react": "8.5.0",
|
|
||||||
"@storybook/test": "8.5.0",
|
|
||||||
"@testing-library/dom": "^10.4.0",
|
"@testing-library/dom": "^10.4.0",
|
||||||
"@testing-library/jest-dom": "^6.8.0",
|
"@testing-library/jest-dom": "^6.8.0",
|
||||||
"@testing-library/react": "^16.0.1",
|
"@testing-library/react": "^16.0.1",
|
||||||
@@ -186,7 +184,7 @@
|
|||||||
"eslint-plugin-react-hooks": "^5.1.0",
|
"eslint-plugin-react-hooks": "^5.1.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.19",
|
"eslint-plugin-react-refresh": "^0.4.19",
|
||||||
"eslint-plugin-sonarjs": "^3.0.2",
|
"eslint-plugin-sonarjs": "^3.0.2",
|
||||||
"eslint-plugin-storybook": "^9.0.7",
|
"eslint-plugin-storybook": "^9.1.13",
|
||||||
"eslint-plugin-tailwindcss": "^3.18.0",
|
"eslint-plugin-tailwindcss": "^3.18.0",
|
||||||
"globals": "^15.11.0",
|
"globals": "^15.11.0",
|
||||||
"husky": "^9.1.6",
|
"husky": "^9.1.6",
|
||||||
@@ -197,7 +195,7 @@
|
|||||||
"magicast": "^0.3.4",
|
"magicast": "^0.3.4",
|
||||||
"postcss": "^8.4.47",
|
"postcss": "^8.4.47",
|
||||||
"sass": "^1.92.1",
|
"sass": "^1.92.1",
|
||||||
"storybook": "8.5.0",
|
"storybook": "9.1.13",
|
||||||
"tailwindcss": "^3.4.14",
|
"tailwindcss": "^3.4.14",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"uglify-js": "^3.19.3"
|
"uglify-js": "^3.19.3"
|
||||||
@@ -243,7 +241,8 @@
|
|||||||
"object.fromentries": "npm:@nolyfill/object.fromentries@^1",
|
"object.fromentries": "npm:@nolyfill/object.fromentries@^1",
|
||||||
"object.groupby": "npm:@nolyfill/object.groupby@^1",
|
"object.groupby": "npm:@nolyfill/object.groupby@^1",
|
||||||
"object.values": "npm:@nolyfill/object.values@^1",
|
"object.values": "npm:@nolyfill/object.values@^1",
|
||||||
"safe-buffer": "npm:@nolyfill/safe-buffer@^1",
|
"safe-buffer": "^5.2.1",
|
||||||
|
"@nolyfill/safe-buffer": "npm:safe-buffer@^5.2.1",
|
||||||
"safe-regex-test": "npm:@nolyfill/safe-regex-test@^1",
|
"safe-regex-test": "npm:@nolyfill/safe-regex-test@^1",
|
||||||
"safer-buffer": "npm:@nolyfill/safer-buffer@^1",
|
"safer-buffer": "npm:@nolyfill/safer-buffer@^1",
|
||||||
"side-channel": "npm:@nolyfill/side-channel@^1",
|
"side-channel": "npm:@nolyfill/side-channel@^1",
|
||||||
|
|||||||
1454
web/pnpm-lock.yaml
generated
1454
web/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user