Add dynamic Storybook stories loading from features.json

Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-01-08 14:56:09 +00:00
parent 7111ca899c
commit a78d3743d6
7 changed files with 224 additions and 17 deletions

View File

@@ -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<typeof ConfirmDialog>;
export default meta;
type Story = StoryObj<typeof meta>;
// 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'),
},
};

View File

@@ -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<typeof ConfirmDialog>;
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'),
},
};

View File

@@ -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<typeof DataGrid>;
export default meta;
type Story = StoryObj<typeof meta>;
// 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,
};

View File

@@ -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<typeof DataGrid>;
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',
},
};

View File

@@ -1,7 +1,6 @@
'use client';
import {
IconButton as MuiIconButton,
Paper,
Table,
TableBody,

View File

@@ -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<typeof Button>;
export default meta;
type Story = StoryObj<typeof meta>;
// 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<ButtonProps>,
};
// Secondary Button
export const Secondary: Story = {
name: buttonStories.secondary.name,
args: buttonStories.secondary.args as Partial<ButtonProps>,
};
// Button with Icon
export const WithIcon: Story = {
name: buttonStories.withIcon.name,
args: buttonStories.withIcon.args as Partial<ButtonProps>,
};
// Loading State
export const Loading: Story = {
name: buttonStories.loading.name,
args: buttonStories.loading.args as Partial<ButtonProps>,
};

View File

@@ -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<string, any> = {};
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<typeof Component> = {
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<typeof Button>;
export default meta;
type Story = StoryObj<typeof meta>;
// 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,
};