From a59fdee1accc62cfa8c25278b512c71a77da6af0 Mon Sep 17 00:00:00 2001 From: myusername Date: Mon, 11 May 2026 15:49:53 +0530 Subject: [PATCH 1/4] feat: Button component created --- src/index.css | 61 +++++++++++-- src/shared/Button/Button.stories.tsx | 127 +++++++++++++++++++++++++++ src/shared/Button/Button.tsx | 125 ++++++++++++++++++++++++++ src/shared/Button/index.ts | 2 + 4 files changed, 306 insertions(+), 9 deletions(-) create mode 100644 src/shared/Button/Button.stories.tsx create mode 100644 src/shared/Button/Button.tsx create mode 100644 src/shared/Button/index.ts diff --git a/src/index.css b/src/index.css index ad25b80..f291666 100644 --- a/src/index.css +++ b/src/index.css @@ -2,18 +2,47 @@ /* 1. Fallback tokens (match SemanticTokens EXACTLY) */ :root { + /* Background */ --color-bg-primary: #ffffff; --color-bg-secondary: #f5f5f5; + --color-bg-tertiary: #eeede9; + + /* Text */ --color-text-primary: #000000; --color-text-secondary: #555555; - --color-border: #e5e5e5; - --color-danger: #ef4444; - --color-success: #22c55e; + --color-text-tertiary: #888780; + + /* Border */ + --color-border-primary: rgba(0, 0, 0, 0.32); + --color-border-secondary: rgba(0, 0, 0, 0.2); + --color-border-tertiary: rgba(0, 0, 0, 0.1); + + /* Danger */ + --color-bg-danger: #fde8e8; + --color-text-danger: #b91c1c; + --color-border-danger: #f5c2c2; + + /* Warning */ + --color-bg-warning: #fef3c7; + --color-text-warning: #92400e; + --color-border-warning: #fde68a; + /* Success */ + --color-bg-success: #e6f4ea; + --color-text-success: #166534; + --color-border-success: #bbf7d0; + + /* Info */ + --color-bg-info: #e8f1fb; + --color-text-info: #1e3a8a; + --color-border-info: #bfdbfe; + + /* Radius */ --radius-sm: 4px; --radius-md: 8px; --radius-lg: 12px; + /* Shadow */ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05); --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1); } @@ -30,16 +59,30 @@ --color-text-secondary: var(--color-text-secondary); --color-text-tertiary: var(--color-text-tertiary); - /* Borders */ + /* Border */ --color-border-primary: var(--color-border-primary); --color-border-secondary: var(--color-border-secondary); --color-border-tertiary: var(--color-border-tertiary); - /* Status */ - --color-danger: var(--color-danger); - --color-warning: var(--color-warning); - --color-success: var(--color-success); - --color-info: var(--color-info); + /* Danger */ + --color-bg-danger: var(--color-bg-danger); + --color-text-danger: var(--color-text-danger); + --color-border-danger: var(--color-border-danger); + + /* Warning */ + --color-bg-warning: var(--color-bg-warning); + --color-text-warning: var(--color-text-warning); + --color-border-warning: var(--color-border-warning); + + /* Success */ + --color-bg-success: var(--color-bg-success); + --color-text-success: var(--color-text-success); + --color-border-success: var(--color-border-success); + + /* Info */ + --color-bg-info: var(--color-bg-info); + --color-text-info: var(--color-text-info); + --color-border-info: var(--color-border-info); } /* Disable transitions on first load (prevents flash) */ diff --git a/src/shared/Button/Button.stories.tsx b/src/shared/Button/Button.stories.tsx new file mode 100644 index 0000000..2b0717b --- /dev/null +++ b/src/shared/Button/Button.stories.tsx @@ -0,0 +1,127 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { Button } from '.'; + +const meta = { + title: 'Shared/Primitives/Button', + component: Button, + tags: ['autodocs'], + + argTypes: { + variant: { + control: 'select', + options: [ + 'primary', + 'secondary', + 'danger', + 'warning', + 'ghost', + 'info', + ], + }, + + size: { + control: 'select', + options: ['sm', 'md', 'lg'], + }, + + isLoading: { + control: 'boolean', + }, + + isDisabled: { + control: 'boolean', + }, + + fullWidth: { + control: 'boolean', + }, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Primary: Story = { + args: { + children: 'Primary Button', + variant: 'primary', + }, +}; + +export const Secondary: Story = { + args: { + children: 'Secondary Button', + variant: 'secondary', + }, +}; + +export const Danger: Story = { + args: { + children: 'Danger Button', + variant: 'danger', + }, +}; + +export const Warning: Story = { + args: { + children: 'Warning Button', + variant: 'warning', + }, +}; + +export const Ghost: Story = { + args: { + children: 'Ghost Button', + variant: 'ghost', + }, +}; + +export const Info: Story = { + args: { + children: 'Info Button', + variant: 'info', + }, +}; + +export const Small: Story = { + args: { + children: 'Small Button', + size: 'sm', + }, +}; + +export const Medium: Story = { + args: { + children: 'Medium Button', + size: 'md', + }, +}; + +export const Large: Story = { + args: { + children: 'Large Button', + size: 'lg', + }, +}; + +export const Loading: Story = { + args: { + children: 'Loading...', + isLoading: true, + }, +}; + +export const Disabled: Story = { + args: { + children: 'Disabled Button', + isDisabled: true, + }, +}; + +export const FullWidth: Story = { + args: { + children: 'Full Width Button', + fullWidth: true, + }, +}; \ No newline at end of file diff --git a/src/shared/Button/Button.tsx b/src/shared/Button/Button.tsx new file mode 100644 index 0000000..5c93819 --- /dev/null +++ b/src/shared/Button/Button.tsx @@ -0,0 +1,125 @@ +import React from 'react'; +import { cva, type VariantProps } from 'class-variance-authority'; + +const button = cva( + [ + 'inline-flex items-center justify-center gap-2', + 'rounded-md font-medium', + 'transition-all', + 'active:scale-[0.98]', + 'focus:outline-none', + 'disabled:opacity-50', + 'disabled:cursor-not-allowed disabled:pointer-events-none', + ], + { + variants: { + variant: { + primary: + 'bg-text-info text-bg-primary border border-border-info', + + secondary: + 'bg-bg-secondary text-text-primary border border-border-secondary', + + danger: + 'bg-bg-danger text-text-danger border border-border-danger', + + warning: + 'bg-bg-warning text-text-warning border border-border-warning', + + info: + 'bg-bg-info text-text-info border border-border-info', + + ghost: + 'bg-transparent text-text-secondary border border-transparent', + }, + + size: { + sm: 'px-3 py-1.5 text-sm', + md: 'px-4 py-2 text-sm', + lg: 'px-5 py-3 text-base', + }, + + fullWidth: { + true: 'w-full', + }, + }, + + defaultVariants: { + variant: 'primary', + size: 'md', + fullWidth: false, + }, + } +); + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + children: React.ReactNode; + + isLoading?: boolean; + isDisabled?: boolean; + + leftIcon?: React.ReactNode; + rightIcon?: React.ReactNode; + + testId?: string; +} + +export function Button({ + children, + + variant, + size, + fullWidth, + + className, + + isLoading = false, + isDisabled = false, + + leftIcon, + rightIcon, + + testId, + + ...props +}: ButtonProps) { + const disabled = isDisabled || isLoading; + + return ( + + ); +} \ No newline at end of file diff --git a/src/shared/Button/index.ts b/src/shared/Button/index.ts new file mode 100644 index 0000000..a957269 --- /dev/null +++ b/src/shared/Button/index.ts @@ -0,0 +1,2 @@ +export { Button } from './Button' +export type { ButtonProps } from './Button' \ No newline at end of file From 86b839c5b7b1b8fe5b5942e8b8b3d274c9d4db8b Mon Sep 17 00:00:00 2001 From: myusername Date: Mon, 11 May 2026 15:54:36 +0530 Subject: [PATCH 2/4] feat: check husky --- eslint.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eslint.config.js b/eslint.config.js index 4d3f803..4965db1 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -11,7 +11,7 @@ import { defineConfig, globalIgnores } from 'eslint/config' import eslintConfigPrettier from 'eslint-config-prettier' export default defineConfig([ - globalIgnores(['dist', 'storybook-static']), + globalIgnores(['dist']), { files: ['**/*.{ts,tsx}'], From d984e493569ae6f218b8b757d031f3adb6682a1e Mon Sep 17 00:00:00 2001 From: myusername Date: Mon, 11 May 2026 15:56:52 +0530 Subject: [PATCH 3/4] feat: husky check --- eslint.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eslint.config.js b/eslint.config.js index 4965db1..4d3f803 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -11,7 +11,7 @@ import { defineConfig, globalIgnores } from 'eslint/config' import eslintConfigPrettier from 'eslint-config-prettier' export default defineConfig([ - globalIgnores(['dist']), + globalIgnores(['dist', 'storybook-static']), { files: ['**/*.{ts,tsx}'], From d8ef3f244c5bbb0e3d9b66564f130d054e638c52 Mon Sep 17 00:00:00 2001 From: myusername Date: Mon, 11 May 2026 15:59:20 +0530 Subject: [PATCH 4/4] feat: husky check --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 7b69783..e56ea6e 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "format:check": "prettier --check .", "lint": "eslint .", "preview": "vite preview", + "prepare": "husky", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build", "chromatic": "npx chromatic --project-token=chpt_bd8d0a3ce41cca0", @@ -81,4 +82,4 @@ "vite-tsconfig-paths": "^6.1.1", "vitest": "^4.1.5" } -} \ No newline at end of file +}