feat: Добавлен переиспользуемый компонент кнопки с задаваемыми размерами, вариантами и цветовыми схемами. Добавлен декоратор стилей для сторибука, установлена библиотека для работы с классами
This commit is contained in:
8
config/storybook/StyleDecorator.tsx
Normal file
8
config/storybook/StyleDecorator.tsx
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import type { Decorator } from '@storybook/react'
|
||||||
|
import '@/app/styles/index.scss'
|
||||||
|
|
||||||
|
export const StyleDecorator: Decorator = (Story) => (
|
||||||
|
<>
|
||||||
|
<Story />
|
||||||
|
</>
|
||||||
|
)
|
||||||
@@ -49,7 +49,13 @@ const config: StorybookConfig = {
|
|||||||
if (typeof rule === 'object' && rule !== null && 'test' in rule) {
|
if (typeof rule === 'object' && rule !== null && 'test' in rule) {
|
||||||
const test = rule.test
|
const test = rule.test
|
||||||
if (test instanceof RegExp) {
|
if (test instanceof RegExp) {
|
||||||
return !(test.test('.css') || test.test('.scss') || test.test('.sass'))
|
// Удаляем правила для CSS/SCSS и SVG
|
||||||
|
return !(
|
||||||
|
test.test('.css') ||
|
||||||
|
test.test('.scss') ||
|
||||||
|
test.test('.sass') ||
|
||||||
|
test.test('.svg')
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@@ -58,6 +64,12 @@ const config: StorybookConfig = {
|
|||||||
// Использование конфигурации CSS loader из проекта
|
// Использование конфигурации CSS loader из проекта
|
||||||
config.module.rules.push(buildCssLoader(true))
|
config.module.rules.push(buildCssLoader(true))
|
||||||
|
|
||||||
|
// Добавление поддержки SVGR для SVG иконок
|
||||||
|
config.module.rules.push({
|
||||||
|
test: /\.svg$/,
|
||||||
|
use: ['@svgr/webpack'],
|
||||||
|
})
|
||||||
|
|
||||||
return config
|
return config
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import type { Preview } from '@storybook/react'
|
import type { Preview } from '@storybook/react'
|
||||||
|
import { StyleDecorator } from './StyleDecorator.tsx'
|
||||||
|
|
||||||
const preview: Preview = {
|
const preview: Preview = {
|
||||||
|
decorators: [StyleDecorator],
|
||||||
parameters: {
|
parameters: {
|
||||||
controls: {
|
controls: {
|
||||||
matchers: {
|
matchers: {
|
||||||
@@ -13,7 +15,7 @@ const preview: Preview = {
|
|||||||
values: [
|
values: [
|
||||||
{
|
{
|
||||||
name: 'light',
|
name: 'light',
|
||||||
value: '#ffffff',
|
value: '#F4F5F9',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'dark',
|
name: 'dark',
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"classnames": "^2.5.1",
|
||||||
"gsap": "^3.13.0",
|
"gsap": "^3.13.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
|
|||||||
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
@@ -8,6 +8,9 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
classnames:
|
||||||
|
specifier: ^2.5.1
|
||||||
|
version: 2.5.1
|
||||||
gsap:
|
gsap:
|
||||||
specifier: ^3.13.0
|
specifier: ^3.13.0
|
||||||
version: 3.13.0
|
version: 3.13.0
|
||||||
@@ -2211,6 +2214,9 @@ packages:
|
|||||||
cjs-module-lexer@1.4.3:
|
cjs-module-lexer@1.4.3:
|
||||||
resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==}
|
resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==}
|
||||||
|
|
||||||
|
classnames@2.5.1:
|
||||||
|
resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==}
|
||||||
|
|
||||||
clean-css@5.3.3:
|
clean-css@5.3.3:
|
||||||
resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==}
|
resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==}
|
||||||
engines: {node: '>= 10.0'}
|
engines: {node: '>= 10.0'}
|
||||||
@@ -7278,6 +7284,8 @@ snapshots:
|
|||||||
|
|
||||||
cjs-module-lexer@1.4.3: {}
|
cjs-module-lexer@1.4.3: {}
|
||||||
|
|
||||||
|
classnames@2.5.1: {}
|
||||||
|
|
||||||
clean-css@5.3.3:
|
clean-css@5.3.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
source-map: 0.6.1
|
source-map: 0.6.1
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
--color-bg: #F4F5F9;
|
--color-bg: #F4F5F9;
|
||||||
--color-border: rgb(66 86 122 / 10%);
|
--color-border: rgb(66 86 122 / 10%);
|
||||||
--color-blue: #3877EE;
|
--color-blue: #3877EE;
|
||||||
|
--color-white: #FFFFFF;
|
||||||
|
|
||||||
// Градиенты
|
// Градиенты
|
||||||
--gradient-primary: linear-gradient(to right, #3877EE, #EF5DA8);
|
--gradient-primary: linear-gradient(to right, #3877EE, #EF5DA8);
|
||||||
|
|||||||
3
src/shared/assets/chevron--left.svg
Normal file
3
src/shared/assets/chevron--left.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="9" height="14" viewBox="0 0 9 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M7.66418 0.707108L1.41419 6.95711L7.66418 13.2071" stroke="#42567A" stroke-width="2"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 197 B |
78
src/shared/ui/Button/Button.module.scss
Normal file
78
src/shared/ui/Button/Button.module.scss
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
.button {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
padding: 0;
|
||||||
|
outline: none;
|
||||||
|
font-family: var(--font-family-main);
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variants
|
||||||
|
&.round {
|
||||||
|
border-radius: 50%;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.regular {
|
||||||
|
border-radius: 1em;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sizes
|
||||||
|
&.small {
|
||||||
|
height: 40px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.medium {
|
||||||
|
height: 50px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.large {
|
||||||
|
height: 60px;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Color Schemes
|
||||||
|
&.primary {
|
||||||
|
$color-primary: var(--color-primary);
|
||||||
|
background-color: transparent;
|
||||||
|
color: $color-primary;
|
||||||
|
border: 1px solid $color-primary;
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
background-color: var(--color-white);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.secondary {
|
||||||
|
$color-blue: var(--color-blue);
|
||||||
|
background-color: var(--color-white);
|
||||||
|
color: $color-blue;
|
||||||
|
box-shadow: 0px 0px 15px rgb($color-blue / 10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Icon handling
|
||||||
|
.icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 40%;
|
||||||
|
height: 40%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
102
src/shared/ui/Button/Button.stories.tsx
Normal file
102
src/shared/ui/Button/Button.stories.tsx
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/react'
|
||||||
|
import { Button } from './Button'
|
||||||
|
import ChevronLeftIcon from '@/shared/assets/chevron--left.svg'
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
title: 'Shared/Button',
|
||||||
|
component: Button,
|
||||||
|
parameters: {
|
||||||
|
layout: 'centered',
|
||||||
|
},
|
||||||
|
tags: ['autodocs'],
|
||||||
|
argTypes: {
|
||||||
|
variant: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['round', 'regular'],
|
||||||
|
description: 'Вариант внешнего вида',
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['small', 'medium', 'large'],
|
||||||
|
description: 'Размер кнопки',
|
||||||
|
},
|
||||||
|
colorScheme: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['primary', 'secondary'],
|
||||||
|
description: 'Цветовая схема',
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
control: 'boolean',
|
||||||
|
description: 'Активность кнопки',
|
||||||
|
},
|
||||||
|
onClick: { action: 'clicked' },
|
||||||
|
},
|
||||||
|
} satisfies Meta<typeof Button>
|
||||||
|
|
||||||
|
export default meta
|
||||||
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Базовая кнопка
|
||||||
|
*/
|
||||||
|
export const Default: Story = {
|
||||||
|
args: {
|
||||||
|
children: 'Submit',
|
||||||
|
variant: 'regular',
|
||||||
|
size: 'medium',
|
||||||
|
colorScheme: 'primary',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Альтернативная цветовая схема
|
||||||
|
*/
|
||||||
|
export const SecondaryColorScheme: Story = {
|
||||||
|
args: {
|
||||||
|
children: 'Submit',
|
||||||
|
variant: 'regular',
|
||||||
|
size: 'medium',
|
||||||
|
colorScheme: 'secondary',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Маленькая кнопка
|
||||||
|
*/
|
||||||
|
export const Small: Story = {
|
||||||
|
args: {
|
||||||
|
children: 'Submit',
|
||||||
|
size: 'small',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Большая кнопка
|
||||||
|
*/
|
||||||
|
export const Large: Story = {
|
||||||
|
args: {
|
||||||
|
children: 'Submit',
|
||||||
|
size: 'large',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Кнопка с SVG иконкой (шеврон)
|
||||||
|
*/
|
||||||
|
export const WithIcon: Story = {
|
||||||
|
args: {
|
||||||
|
children: <ChevronLeftIcon />,
|
||||||
|
variant: 'round',
|
||||||
|
size: 'medium',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Отключенная кнопка
|
||||||
|
*/
|
||||||
|
export const Disabled: Story = {
|
||||||
|
args: {
|
||||||
|
children: 'Submit',
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
60
src/shared/ui/Button/Button.tsx
Normal file
60
src/shared/ui/Button/Button.tsx
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { ButtonHTMLAttributes, memo, PropsWithChildren } from 'react'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
import styles from './Button.module.scss'
|
||||||
|
|
||||||
|
export type ButtonVariant = 'round' | 'regular'
|
||||||
|
export type ButtonSize = 'small' | 'medium' | 'large'
|
||||||
|
export type ButtonColorScheme = 'primary' | 'secondary'
|
||||||
|
|
||||||
|
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, PropsWithChildren {
|
||||||
|
/**
|
||||||
|
* Вариант внешнего вида кнопки
|
||||||
|
* @default 'round'
|
||||||
|
*/
|
||||||
|
variant?: ButtonVariant
|
||||||
|
/**
|
||||||
|
* Размер кнопки
|
||||||
|
* @default 'medium'
|
||||||
|
*/
|
||||||
|
size?: ButtonSize
|
||||||
|
/**
|
||||||
|
* Цветовая схема
|
||||||
|
* @default 'timeframe'
|
||||||
|
*/
|
||||||
|
colorScheme?: ButtonColorScheme
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Универсальный компонент кнопки для использования в слайдерах и других элементах интерфейса.
|
||||||
|
* Поддерживает различные варианты отображения, размеры и цветовые схемы.
|
||||||
|
*/
|
||||||
|
export const Button = memo((props: ButtonProps) => {
|
||||||
|
const {
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
variant = 'round',
|
||||||
|
size = 'medium',
|
||||||
|
colorScheme = 'primary',
|
||||||
|
disabled,
|
||||||
|
...otherProps
|
||||||
|
} = props
|
||||||
|
|
||||||
|
const mods: Record<string, boolean | undefined> = {
|
||||||
|
[styles[variant]]: true,
|
||||||
|
[styles[size]]: true,
|
||||||
|
[styles[colorScheme]]: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={classNames(styles.button, mods, className)}
|
||||||
|
disabled={disabled}
|
||||||
|
{...otherProps}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
Button.displayName = 'Button'
|
||||||
2
src/shared/ui/Button/index.ts
Normal file
2
src/shared/ui/Button/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export { Button } from './Button'
|
||||||
|
export type { ButtonProps, ButtonVariant, ButtonSize, ButtonColorScheme } from './Button'
|
||||||
2
src/shared/ui/index.ts
Normal file
2
src/shared/ui/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export { Button } from './Button'
|
||||||
|
export type { ButtonProps } from './Button'
|
||||||
Reference in New Issue
Block a user