feature/storybook #2
@ -7,10 +7,15 @@
|
||||
"rules": {
|
||||
"react-hooks/rules-of-hooks": "off"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"src/app/**/*.stories.tsx"
|
||||
],
|
||||
"plugins": [
|
||||
"prettier"
|
||||
"rules": {
|
||||
"react/jsx-props-no-spreading": "off"
|
||||
}
|
||||
},
|
||||
],
|
||||
"settings": {
|
||||
"react": {
|
||||
@ -35,6 +40,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"plugins": [
|
||||
"prettier"
|
||||
],
|
||||
"extends": [
|
||||
"airbnb",
|
||||
"next/core-web-vitals",
|
||||
"next/typescript",
|
||||
"prettier",
|
||||
"plugin:storybook/recommended"
|
||||
],
|
||||
"rules": {
|
||||
"no-use-before-define": "off",
|
||||
"class-methods-use-this": "off",
|
||||
@ -49,7 +64,7 @@
|
||||
{
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"endOfLine":"auto",
|
||||
"endOfLine": "auto",
|
||||
"useTabs": false,
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
@ -85,11 +100,5 @@
|
||||
"devDependencies": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"extends": [
|
||||
"airbnb",
|
||||
"next/core-web-vitals",
|
||||
"next/typescript",
|
||||
"prettier"
|
||||
]
|
||||
}
|
||||
}
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -38,3 +38,5 @@ yarn-error.log*
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
*storybook.log
|
||||
|
17
.storybook/main.ts
Normal file
17
.storybook/main.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import type { StorybookConfig } from "@storybook/nextjs";
|
||||
|
||||
const config: StorybookConfig = {
|
||||
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
|
||||
addons: [
|
||||
"@storybook/addon-onboarding",
|
||||
"@storybook/addon-essentials",
|
||||
"@chromatic-com/storybook",
|
||||
"@storybook/addon-interactions",
|
||||
],
|
||||
framework: {
|
||||
name: "@storybook/nextjs",
|
||||
options: {},
|
||||
},
|
||||
staticDirs: ["../public"],
|
||||
};
|
||||
export default config;
|
72
.storybook/preview.tsx
Normal file
72
.storybook/preview.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import type { Preview } from "@storybook/react";
|
||||
import React from "react";
|
||||
import "../src/app/globals.css"
|
||||
/**
|
||||
*
|
||||
* This function will expand the object with nested properties
|
||||
* @param obj refrence Object to that
|
||||
* @param leftKeys keys to be nested object keys
|
||||
* @param value value to be nested
|
||||
*
|
||||
*/
|
||||
export const recursiveNestedProps = (
|
||||
obj: Record<string, unknown>,
|
||||
leftKeys: string[],
|
||||
value: unknown,
|
||||
): Record<string, unknown> => {
|
||||
if (leftKeys.length <= 0) return obj;
|
||||
if (leftKeys.length === 1) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
obj[leftKeys[0]] = value;
|
||||
return obj;
|
||||
}
|
||||
const key = leftKeys.shift();
|
||||
if (!key) return obj;
|
||||
|
||||
if (!obj[key]) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
obj[key] = {};
|
||||
}
|
||||
|
||||
return recursiveNestedProps(
|
||||
obj[key] as Record<string, unknown>,
|
||||
leftKeys,
|
||||
value,
|
||||
);
|
||||
};
|
||||
|
||||
const preview: Preview = {
|
||||
decorators: [
|
||||
(Story, data) => {
|
||||
const parsedProps = {} as Record<string, unknown>;
|
||||
const props = data.allArgs;
|
||||
Object.entries(props).forEach((prop) => {
|
||||
const [key, value] = prop;
|
||||
if (!key.includes("vm")) {
|
||||
parsedProps[key] = value;
|
||||
return;
|
||||
}
|
||||
const splitedKey = key.split(".");
|
||||
|
||||
recursiveNestedProps(parsedProps, splitedKey, value);
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Story parsedProps={parsedProps} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
],
|
||||
parameters: {
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/i,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default preview;
|
@ -11,7 +11,6 @@ services:
|
||||
POSTGRES_USER: admin
|
||||
POSTGRES_DB: nextbp
|
||||
|
||||
|
||||
app:
|
||||
build: .
|
||||
ports:
|
||||
|
15
package.json
15
package.json
@ -8,7 +8,9 @@
|
||||
"start": "next start --port 4000",
|
||||
"lint": "next lint --fix",
|
||||
"test": "vitest",
|
||||
"seed": "node -r dotenv/config ./src/bootstrap/boundaries/db/seed.js"
|
||||
"seed": "node -r dotenv/config ./src/bootstrap/boundaries/db/seed.js",
|
||||
"storybook": "storybook dev -p 6006 --no-open",
|
||||
"build-storybook": "storybook build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@heroicons/react": "^2.1.5",
|
||||
@ -24,6 +26,7 @@
|
||||
"lucide-react": "^0.454.0",
|
||||
"next": "15.0.2",
|
||||
"next-i18n-router": "^5.5.1",
|
||||
"next-themes": "^0.4.3",
|
||||
"postgres": "^3.4.5",
|
||||
"react": "19.0.0-rc-69d4b800-20241021",
|
||||
"react-cookie": "^7.2.2",
|
||||
@ -37,7 +40,15 @@
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@chromatic-com/storybook": "^3.2.2",
|
||||
"@faker-js/faker": "^9.1.0",
|
||||
"@storybook/addon-essentials": "^8.4.5",
|
||||
"@storybook/addon-interactions": "^8.4.5",
|
||||
"@storybook/addon-onboarding": "^8.4.5",
|
||||
"@storybook/blocks": "^8.4.5",
|
||||
"@storybook/nextjs": "^8.4.5",
|
||||
"@storybook/react": "^8.4.5",
|
||||
"@storybook/test": "^8.4.5",
|
||||
"@testing-library/dom": "^10.4.0",
|
||||
"@testing-library/react": "^16.0.1",
|
||||
"@types/node": "^20",
|
||||
@ -53,10 +64,12 @@
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
"eslint-import-resolver-typescript": "^3.6.3",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"eslint-plugin-storybook": "^0.11.1",
|
||||
"jsdom": "^25.0.1",
|
||||
"moq.ts": "^10.0.8",
|
||||
"postcss": "^8",
|
||||
"prettier": "^3.3.3",
|
||||
"storybook": "^8.4.5",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5",
|
||||
"vitest": "^2.1.4"
|
||||
|
@ -0,0 +1,11 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { ThemeProvider as NextThemesProvider } from "next-themes"
|
||||
|
||||
export function ThemeProvider({
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NextThemesProvider>) {
|
||||
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
import { ThemeProvider } from "@/app/[lang]/dashboard/components/client/theme-provider/theme-provider";
|
||||
import { initI18next } from "@/bootstrap/i18n/i18n";
|
||||
import TranslationsProvider from "@/bootstrap/i18n/i18n-provider";
|
||||
import localFont from "next/font/local";
|
||||
@ -21,13 +22,20 @@ export default async function layout(
|
||||
const { lang } = await params;
|
||||
const { resources } = await initI18next({ lng: lang });
|
||||
return (
|
||||
<html lang={lang}>
|
||||
<html lang={lang} suppressHydrationWarning>
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="light"
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
<TranslationsProvider lng={lang} resources={resources}>
|
||||
{children}
|
||||
</TranslationsProvider>
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
@ -59,6 +59,7 @@ export interface ButtonProps
|
||||
const ButtonUi = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "button";
|
||||
console.log('is disabled', props);
|
||||
return (
|
||||
<Comp
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
|
31
src/app/components/button/stories/Button.stories.tsx
Normal file
31
src/app/components/button/stories/Button.stories.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import Button from "@/app/components/button/button";
|
||||
import Story from "@/bootstrap/helpers/view/storybook-base-template-type";
|
||||
import getArgVM from "@/bootstrap/helpers/view/storybook-with-arg-vm";
|
||||
import type { Meta } from "@storybook/react";
|
||||
|
||||
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
|
||||
const meta: Meta = {
|
||||
title: "general/Button",
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
|
||||
export const Primary: Story = {
|
||||
argTypes: {
|
||||
"vm.props.isDisable": {
|
||||
control: "boolean",
|
||||
},
|
||||
"vm.props.title": {
|
||||
control: "text",
|
||||
},
|
||||
},
|
||||
args: {
|
||||
"vm.props.title": "Button",
|
||||
"vm.props.isDisable": false,
|
||||
},
|
||||
render: (_props, globalData) => {
|
||||
const vm = getArgVM(globalData.parsedProps.vm)// You can use parsed props to access your vm properties.
|
||||
return <Button vm={vm} memoizedByVM={false} />
|
||||
}
|
||||
};
|
@ -0,0 +1,5 @@
|
||||
import { Meta, StoryObj } from "@storybook/react";
|
||||
|
||||
type Story = StoryObj<Meta>;
|
||||
|
||||
export default Story;
|
14
src/bootstrap/helpers/view/storybook-with-arg-vm.ts
Normal file
14
src/bootstrap/helpers/view/storybook-with-arg-vm.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import IBaseVM from "@/bootstrap/helpers/vm/i-base-vm";
|
||||
|
||||
const getArgVM = <IVM>(vmObj: IVM) => {
|
||||
class VM implements IBaseVM<IVM> {
|
||||
useVM(): IVM {
|
||||
return {
|
||||
...vmObj,
|
||||
};
|
||||
}
|
||||
}
|
||||
return new VM();
|
||||
};
|
||||
|
||||
export default getArgVM;
|
Loading…
x
Reference in New Issue
Block a user