From a78d3743d6b9d360f93f65766d68b7a9ddf99089 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 8 Jan 2026 14:56:09 +0000 Subject: [PATCH] Add dynamic Storybook stories loading from features.json Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com> --- .../admin/ConfirmDialog.dynamic.stories.tsx | 43 ++++++++++ .../admin/ConfirmDialog.stories.tsx | 13 +-- .../admin/DataGrid.dynamic.stories.tsx | 45 ++++++++++ src/components/admin/DataGrid.stories.tsx | 9 +- src/components/admin/DataGrid.tsx | 1 - .../atoms/Button.dynamic.stories.tsx | 47 +++++++++++ src/components/atoms/DynamicStories.tsx | 83 +++++++++++++++++++ 7 files changed, 224 insertions(+), 17 deletions(-) create mode 100644 src/components/admin/ConfirmDialog.dynamic.stories.tsx create mode 100644 src/components/admin/DataGrid.dynamic.stories.tsx create mode 100644 src/components/atoms/Button.dynamic.stories.tsx create mode 100644 src/components/atoms/DynamicStories.tsx diff --git a/src/components/admin/ConfirmDialog.dynamic.stories.tsx b/src/components/admin/ConfirmDialog.dynamic.stories.tsx new file mode 100644 index 0000000..9a710ac --- /dev/null +++ b/src/components/admin/ConfirmDialog.dynamic.stories.tsx @@ -0,0 +1,43 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import featuresConfig from '@/config/features.json'; +import ConfirmDialog from './ConfirmDialog'; + +const meta = { + title: 'Admin/ConfirmDialog (From JSON)', + component: ConfirmDialog, + parameters: { + layout: 'centered', + docs: { + description: { + component: 'ConfirmDialog component with stories dynamically loaded from features.json', + }, + }, + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Dynamically generate stories from features.json +const confirmDialogStories = featuresConfig.storybookStories.ConfirmDialog; + +// Default Story +export const Default: Story = { + name: confirmDialogStories.default.name, + args: { + ...confirmDialogStories.default.args, + onConfirm: () => console.log('Confirmed'), + onCancel: () => console.log('Cancelled'), + }, +}; + +// Delete Warning Story +export const DeleteWarning: Story = { + name: confirmDialogStories.deleteWarning.name, + args: { + ...confirmDialogStories.deleteWarning.args, + onConfirm: () => console.log('Confirmed delete'), + onCancel: () => console.log('Cancelled delete'), + }, +}; diff --git a/src/components/admin/ConfirmDialog.stories.tsx b/src/components/admin/ConfirmDialog.stories.tsx index 96749e0..19267b0 100644 --- a/src/components/admin/ConfirmDialog.stories.tsx +++ b/src/components/admin/ConfirmDialog.stories.tsx @@ -1,5 +1,4 @@ import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; import ConfirmDialog from './ConfirmDialog'; const meta = { @@ -9,10 +8,6 @@ const meta = { layout: 'centered', }, tags: ['autodocs'], - argTypes: { - onConfirm: { action: 'confirm' }, - onCancel: { action: 'cancel' }, - }, } satisfies Meta; export default meta; @@ -27,8 +22,8 @@ export const Default: Story = { message: 'Are you sure you want to proceed?', confirmLabel: 'Confirm', cancelLabel: 'Cancel', - onConfirm: fn(), - onCancel: fn(), + onConfirm: () => console.log('Confirmed'), + onCancel: () => console.log('Cancelled'), }, }; @@ -40,7 +35,7 @@ export const DeleteWarning: Story = { message: 'This action cannot be undone. Are you sure you want to delete this item?', confirmLabel: 'Delete', cancelLabel: 'Cancel', - onConfirm: fn(), - onCancel: fn(), + onConfirm: () => console.log('Confirmed delete'), + onCancel: () => console.log('Cancelled delete'), }, }; diff --git a/src/components/admin/DataGrid.dynamic.stories.tsx b/src/components/admin/DataGrid.dynamic.stories.tsx new file mode 100644 index 0000000..f24e4c8 --- /dev/null +++ b/src/components/admin/DataGrid.dynamic.stories.tsx @@ -0,0 +1,45 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import featuresConfig from '@/config/features.json'; +import DataGrid from './DataGrid'; + +const meta = { + title: 'Admin/DataGrid (From JSON)', + component: DataGrid, + parameters: { + layout: 'padded', + docs: { + description: { + component: 'DataGrid component with stories dynamically loaded from features.json', + }, + }, + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Dynamically generate stories from features.json +const dataGridStories = featuresConfig.storybookStories.DataGrid; + +// Default Story +export const Default: Story = { + name: dataGridStories.default.name, + args: dataGridStories.default.args, +}; + +// With Actions Story +export const WithActions: Story = { + name: dataGridStories.withActions.name, + args: { + ...dataGridStories.withActions.args, + onEdit: () => console.log('Edit clicked'), + onDelete: () => console.log('Delete clicked'), + }, +}; + +// Empty State +export const Empty: Story = { + name: dataGridStories.empty.name, + args: dataGridStories.empty.args, +}; diff --git a/src/components/admin/DataGrid.stories.tsx b/src/components/admin/DataGrid.stories.tsx index 9da2fa4..d6f845e 100644 --- a/src/components/admin/DataGrid.stories.tsx +++ b/src/components/admin/DataGrid.stories.tsx @@ -1,5 +1,4 @@ import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; import DataGrid from './DataGrid'; const meta = { @@ -9,10 +8,6 @@ const meta = { layout: 'padded', }, tags: ['autodocs'], - argTypes: { - onEdit: { action: 'edit' }, - onDelete: { action: 'delete' }, - }, } satisfies Meta; export default meta; @@ -48,8 +43,8 @@ export const WithActions: Story = { { id: 1, name: 'Active User', status: 'active' }, { id: 2, name: 'Pending User', status: 'pending' }, ], - onEdit: fn(), - onDelete: fn(), + onEdit: () => console.log('Edit clicked'), + onDelete: () => console.log('Delete clicked'), primaryKey: 'id', }, }; diff --git a/src/components/admin/DataGrid.tsx b/src/components/admin/DataGrid.tsx index 768e37d..edb7f03 100644 --- a/src/components/admin/DataGrid.tsx +++ b/src/components/admin/DataGrid.tsx @@ -1,7 +1,6 @@ 'use client'; import { - IconButton as MuiIconButton, Paper, Table, TableBody, diff --git a/src/components/atoms/Button.dynamic.stories.tsx b/src/components/atoms/Button.dynamic.stories.tsx new file mode 100644 index 0000000..f57b4b5 --- /dev/null +++ b/src/components/atoms/Button.dynamic.stories.tsx @@ -0,0 +1,47 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import featuresConfig from '@/config/features.json'; +import Button, { type ButtonProps } from './Button'; + +const meta = { + title: 'Atoms/Button (From JSON)', + component: Button, + parameters: { + layout: 'centered', + docs: { + description: { + component: 'Button component with stories dynamically loaded from features.json', + }, + }, + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Dynamically generate stories from features.json +const buttonStories = featuresConfig.storybookStories.Button; + +// Primary Button +export const Primary: Story = { + name: buttonStories.primary.name, + args: buttonStories.primary.args as Partial, +}; + +// Secondary Button +export const Secondary: Story = { + name: buttonStories.secondary.name, + args: buttonStories.secondary.args as Partial, +}; + +// Button with Icon +export const WithIcon: Story = { + name: buttonStories.withIcon.name, + args: buttonStories.withIcon.args as Partial, +}; + +// Loading State +export const Loading: Story = { + name: buttonStories.loading.name, + args: buttonStories.loading.args as Partial, +}; diff --git a/src/components/atoms/DynamicStories.tsx b/src/components/atoms/DynamicStories.tsx new file mode 100644 index 0000000..b4324ad --- /dev/null +++ b/src/components/atoms/DynamicStories.tsx @@ -0,0 +1,83 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import featuresConfig from '@/config/features.json'; +import Button from './Button'; +import TextField from './TextField'; +import Typography from './Typography'; +import IconButton from './IconButton'; +import Icon from './Icon'; + +// Component mapping +const componentMap = { + Button, + TextField, + Typography, + IconButton, + Icon, +}; + +// Dynamically generate stories from features.json +export function generateStoriesFromConfig() { + const stories: Record = {}; + const storybookStories = featuresConfig.storybookStories; + + Object.entries(storybookStories).forEach(([componentName, componentStories]) => { + if (componentMap[componentName as keyof typeof componentMap]) { + const Component = componentMap[componentName as keyof typeof componentMap]; + + const meta: Meta = { + title: `Atoms/${componentName}`, + component: Component, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + }; + + stories[componentName] = { + meta, + stories: Object.entries(componentStories).map(([storyName, storyConfig]: [string, any]) => ({ + name: storyConfig.name || storyName, + args: storyConfig.args, + })), + }; + } + }); + + return stories; +} + +// Generate stories for Button component from features.json +const buttonStories = featuresConfig.storybookStories.Button; + +const meta = { + title: 'Atoms/Button (Dynamic)', + component: Button, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Generate stories dynamically from features.json +export const Primary: Story = { + name: buttonStories.primary.name, + args: buttonStories.primary.args, +}; + +export const Secondary: Story = { + name: buttonStories.secondary.name, + args: buttonStories.secondary.args, +}; + +export const WithIcon: Story = { + name: buttonStories.withIcon.name, + args: buttonStories.withIcon.args, +}; + +export const Loading: Story = { + name: buttonStories.loading.name, + args: buttonStories.loading.args, +};