mirror of
https://github.com/ershisan99/flashcards-example-project.git
synced 2025-12-16 20:59:27 +00:00
lint everything
This commit is contained in:
@@ -2,11 +2,11 @@ const fs = require('fs')
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
const ruleFiles = fs
|
const ruleFiles = fs
|
||||||
.readdirSync(__dirname)
|
.readdirSync(__dirname)
|
||||||
.filter(file => file !== 'index.js' && !file.endsWith('test.js'))
|
.filter(file => file !== 'index.js' && !file.endsWith('test.js'))
|
||||||
|
|
||||||
const rules = Object.fromEntries(
|
const rules = Object.fromEntries(
|
||||||
ruleFiles.map(file => [path.basename(file, '.js'), require('./' + file)])
|
ruleFiles.map(file => [path.basename(file, '.js'), require('./' + file)])
|
||||||
)
|
)
|
||||||
|
|
||||||
module.exports = { rules }
|
module.exports = { rules }
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
// @ts-check
|
// @ts-check
|
||||||
/** @type {import('eslint').Rule.RuleModule} */
|
/** @type {import('eslint').Rule.RuleModule} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
meta: {
|
create(context) {
|
||||||
fixable: 'code',
|
return {
|
||||||
},
|
ImportDeclaration(node) {
|
||||||
create(context) {
|
if (
|
||||||
return {
|
(node.source && node.source.value === '@reduxjs/toolkit/query/') ||
|
||||||
ImportDeclaration(node) {
|
node.source.value === '@reduxjs/toolkit/query'
|
||||||
if (
|
) {
|
||||||
(node.source && node.source.value === '@reduxjs/toolkit/query/') ||
|
context.report({
|
||||||
node.source.value === '@reduxjs/toolkit/query'
|
fix(fixer) {
|
||||||
) {
|
return fixer.replaceText(node.source, "'@reduxjs/toolkit/query/react'")
|
||||||
context.report({
|
},
|
||||||
node,
|
message:
|
||||||
message:
|
"Import from '@reduxjs/toolkit/query/' is disallowed. Please import from '@reduxjs/toolkit/query/react'.",
|
||||||
"Import from '@reduxjs/toolkit/query/' is disallowed. Please import from '@reduxjs/toolkit/query/react'.",
|
node,
|
||||||
fix(fixer) {
|
})
|
||||||
return fixer.replaceText(node.source, "'@reduxjs/toolkit/query/react'")
|
}
|
||||||
},
|
},
|
||||||
})
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
meta: {
|
||||||
},
|
fixable: 'code',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"format": "prettier --write src",
|
"format": "prettier --write src",
|
||||||
"lint": "eslint --fix src/**/*.{tsx,ts,jsx,js} --no-error-on-unmatched-pattern && stylelint --fix src/{,*/}*.{scss,css} --allow-empty-input",
|
"lint": "eslint . --ext .jsx,.js,.tsx,.ts --no-error-on-unmatched-pattern --fix && stylelint --fix src/{,*/}*.{scss,css} --allow-empty-input",
|
||||||
|
"sb": "storybook dev -p 6006",
|
||||||
"storybook": "storybook dev -p 6006",
|
"storybook": "storybook dev -p 6006",
|
||||||
"build-storybook": "storybook build"
|
"build-storybook": "storybook build"
|
||||||
},
|
},
|
||||||
|
|||||||
10
src/App.tsx
10
src/App.tsx
@@ -4,9 +4,9 @@ import { Router } from '@/router'
|
|||||||
import { store } from '@/services/store'
|
import { store } from '@/services/store'
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
return (
|
return (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<Router />
|
<Router />
|
||||||
</Provider>
|
</Provider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,71 +1,71 @@
|
|||||||
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
||||||
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
||||||
<svg
|
<svg
|
||||||
fill={'none'}
|
fill={'none'}
|
||||||
height={'44'}
|
|
||||||
ref={ref}
|
|
||||||
viewBox={'0 0 44 44'}
|
|
||||||
width={'44'}
|
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
<g filter={'url(#filter0_d_5918_2450)'}>
|
|
||||||
<rect fill={'#4C4C4C'} height={'24'} rx={'4'} width={'24'} x={'10'} y={'8'} />
|
|
||||||
<g clipPath={'url(#clip0_5918_2450)'}>
|
|
||||||
<path
|
|
||||||
d={
|
|
||||||
'M26.6666 25.3334H17.3333C17.1565 25.3334 16.9869 25.4036 16.8619 25.5286C16.7369 25.6537 16.6666 25.8232 16.6666 26C16.6666 26.1769 16.7369 26.3464 16.8619 26.4714C16.9869 26.5965 17.1565 26.6667 17.3333 26.6667H26.6666C26.8434 26.6667 27.013 26.5965 27.138 26.4714C27.2631 26.3464 27.3333 26.1769 27.3333 26C27.3333 25.8232 27.2631 25.6537 27.138 25.5286C27.013 25.4036 26.8434 25.3334 26.6666 25.3334Z'
|
|
||||||
}
|
|
||||||
fill={'white'}
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d={
|
|
||||||
'M17.3333 24H17.3933L20.1733 23.7467C20.4778 23.7163 20.7626 23.5821 20.98 23.3667L26.98 17.3667C27.2128 17.1206 27.3387 16.7923 27.3299 16.4537C27.3212 16.115 27.1786 15.7937 26.9333 15.56L25.1066 13.7333C24.8682 13.5094 24.5558 13.3809 24.2288 13.3723C23.9019 13.3637 23.5831 13.4756 23.3333 13.6867L17.3333 19.6867C17.1178 19.904 16.9836 20.1888 16.9533 20.4933L16.6666 23.2733C16.6576 23.371 16.6703 23.4694 16.7037 23.5616C16.7371 23.6538 16.7905 23.7374 16.86 23.8067C16.9222 23.8684 16.9961 23.9173 17.0773 23.9505C17.1586 23.9837 17.2455 24.0005 17.3333 24ZM24.18 14.6667L26 16.4867L24.6666 17.7867L22.88 16L24.18 14.6667ZM18.2466 20.6067L22 16.88L23.8 18.68L20.0666 22.4133L18.0666 22.6L18.2466 20.6067Z'
|
|
||||||
}
|
|
||||||
fill={'white'}
|
|
||||||
/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<defs>
|
|
||||||
<filter
|
|
||||||
colorInterpolationFilters={'sRGB'}
|
|
||||||
filterUnits={'userSpaceOnUse'}
|
|
||||||
height={'44'}
|
height={'44'}
|
||||||
id={'filter0_d_5918_2450'}
|
ref={ref}
|
||||||
|
viewBox={'0 0 44 44'}
|
||||||
width={'44'}
|
width={'44'}
|
||||||
x={'0'}
|
xmlns={'http://www.w3.org/2000/svg'}
|
||||||
y={'0'}
|
{...props}
|
||||||
>
|
>
|
||||||
<feFlood floodOpacity={'0'} result={'BackgroundImageFix'} />
|
<g filter={'url(#filter0_d_5918_2450)'}>
|
||||||
<feColorMatrix
|
<rect fill={'#4C4C4C'} height={'24'} rx={'4'} width={'24'} x={'10'} y={'8'} />
|
||||||
in={'SourceAlpha'}
|
<g clipPath={'url(#clip0_5918_2450)'}>
|
||||||
result={'hardAlpha'}
|
<path
|
||||||
type={'matrix'}
|
d={
|
||||||
values={'0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0'}
|
'M26.6666 25.3334H17.3333C17.1565 25.3334 16.9869 25.4036 16.8619 25.5286C16.7369 25.6537 16.6666 25.8232 16.6666 26C16.6666 26.1769 16.7369 26.3464 16.8619 26.4714C16.9869 26.5965 17.1565 26.6667 17.3333 26.6667H26.6666C26.8434 26.6667 27.013 26.5965 27.138 26.4714C27.2631 26.3464 27.3333 26.1769 27.3333 26C27.3333 25.8232 27.2631 25.6537 27.138 25.5286C27.013 25.4036 26.8434 25.3334 26.6666 25.3334Z'
|
||||||
/>
|
}
|
||||||
<feOffset dy={'2'} />
|
fill={'white'}
|
||||||
<feGaussianBlur stdDeviation={'5'} />
|
/>
|
||||||
<feColorMatrix
|
<path
|
||||||
type={'matrix'}
|
d={
|
||||||
values={'0 0 0 0 0.429167 0 0 0 0 0.429167 0 0 0 0 0.429167 0 0 0 0.25 0'}
|
'M17.3333 24H17.3933L20.1733 23.7467C20.4778 23.7163 20.7626 23.5821 20.98 23.3667L26.98 17.3667C27.2128 17.1206 27.3387 16.7923 27.3299 16.4537C27.3212 16.115 27.1786 15.7937 26.9333 15.56L25.1066 13.7333C24.8682 13.5094 24.5558 13.3809 24.2288 13.3723C23.9019 13.3637 23.5831 13.4756 23.3333 13.6867L17.3333 19.6867C17.1178 19.904 16.9836 20.1888 16.9533 20.4933L16.6666 23.2733C16.6576 23.371 16.6703 23.4694 16.7037 23.5616C16.7371 23.6538 16.7905 23.7374 16.86 23.8067C16.9222 23.8684 16.9961 23.9173 17.0773 23.9505C17.1586 23.9837 17.2455 24.0005 17.3333 24ZM24.18 14.6667L26 16.4867L24.6666 17.7867L22.88 16L24.18 14.6667ZM18.2466 20.6067L22 16.88L23.8 18.68L20.0666 22.4133L18.0666 22.6L18.2466 20.6067Z'
|
||||||
/>
|
}
|
||||||
<feBlend
|
fill={'white'}
|
||||||
in2={'BackgroundImageFix'}
|
/>
|
||||||
mode={'normal'}
|
</g>
|
||||||
result={'effect1_dropShadow_5918_2450'}
|
</g>
|
||||||
/>
|
<defs>
|
||||||
<feBlend
|
<filter
|
||||||
in={'SourceGraphic'}
|
colorInterpolationFilters={'sRGB'}
|
||||||
in2={'effect1_dropShadow_5918_2450'}
|
filterUnits={'userSpaceOnUse'}
|
||||||
mode={'normal'}
|
height={'44'}
|
||||||
result={'shape'}
|
id={'filter0_d_5918_2450'}
|
||||||
/>
|
width={'44'}
|
||||||
</filter>
|
x={'0'}
|
||||||
<clipPath id={'clip0_5918_2450'}>
|
y={'0'}
|
||||||
<rect fill={'white'} height={'16'} transform={'translate(14 12)'} width={'16'} />
|
>
|
||||||
</clipPath>
|
<feFlood floodOpacity={'0'} result={'BackgroundImageFix'} />
|
||||||
</defs>
|
<feColorMatrix
|
||||||
</svg>
|
in={'SourceAlpha'}
|
||||||
|
result={'hardAlpha'}
|
||||||
|
type={'matrix'}
|
||||||
|
values={'0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0'}
|
||||||
|
/>
|
||||||
|
<feOffset dy={'2'} />
|
||||||
|
<feGaussianBlur stdDeviation={'5'} />
|
||||||
|
<feColorMatrix
|
||||||
|
type={'matrix'}
|
||||||
|
values={'0 0 0 0 0.429167 0 0 0 0 0.429167 0 0 0 0 0.429167 0 0 0 0.25 0'}
|
||||||
|
/>
|
||||||
|
<feBlend
|
||||||
|
in2={'BackgroundImageFix'}
|
||||||
|
mode={'normal'}
|
||||||
|
result={'effect1_dropShadow_5918_2450'}
|
||||||
|
/>
|
||||||
|
<feBlend
|
||||||
|
in={'SourceGraphic'}
|
||||||
|
in2={'effect1_dropShadow_5918_2450'}
|
||||||
|
mode={'normal'}
|
||||||
|
result={'shape'}
|
||||||
|
/>
|
||||||
|
</filter>
|
||||||
|
<clipPath id={'clip0_5918_2450'}>
|
||||||
|
<rect fill={'white'} height={'16'} transform={'translate(14 12)'} width={'16'} />
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
)
|
)
|
||||||
const ForwardRef = forwardRef(SvgComponent)
|
const ForwardRef = forwardRef(SvgComponent)
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
||||||
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
||||||
<svg
|
<svg
|
||||||
fill={'none'}
|
fill={'none'}
|
||||||
height={18}
|
height={18}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
viewBox={'0 0 18 18'}
|
viewBox={'0 0 18 18'}
|
||||||
width={18}
|
width={18}
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
xmlns={'http://www.w3.org/2000/svg'}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M16 0H2a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2V2a2 2 0 00-2-2zM7 14L2 9l1.41-1.41L7 11.17l7.59-7.59L16 5l-9 9z'
|
'M16 0H2a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2V2a2 2 0 00-2-2zM7 14L2 9l1.41-1.41L7 11.17l7.59-7.59L16 5l-9 9z'
|
||||||
}
|
}
|
||||||
fill={'currentColor'}
|
fill={'currentColor'}
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
const ForwardRef = forwardRef(SvgComponent)
|
const ForwardRef = forwardRef(SvgComponent)
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
||||||
const ChevronUp = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
const ChevronUp = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
||||||
<svg
|
<svg
|
||||||
fill={'none'}
|
fill={'none'}
|
||||||
height={12}
|
height={12}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
viewBox={'0 0 12 12'}
|
viewBox={'0 0 12 12'}
|
||||||
width={12}
|
width={12}
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
xmlns={'http://www.w3.org/2000/svg'}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<g clipPath={'url(#clip0_9209_3250)'}>
|
<g clipPath={'url(#clip0_9209_3250)'}>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M9.77084 7.25705C9.77107 7.37388 9.73039 7.4871 9.65584 7.57705C9.61387 7.62768 9.56232 7.66953 9.50415 7.70021C9.44597 7.73089 9.38232 7.74978 9.31683 7.75582C9.25134 7.76186 9.18531 7.75492 9.1225 7.7354C9.0597 7.71588 9.00137 7.68416 8.95084 7.64205L6.27084 5.40205L3.58584 7.56205C3.5347 7.60359 3.47585 7.6346 3.41268 7.65332C3.34951 7.67203 3.28327 7.67808 3.21775 7.67111C3.15224 7.66414 3.08875 7.64429 3.03093 7.61271C2.97311 7.58112 2.92211 7.53842 2.88084 7.48705C2.83533 7.43532 2.80099 7.37474 2.78 7.30911C2.759 7.24348 2.7518 7.17421 2.75884 7.10567C2.76589 7.03712 2.78702 6.97077 2.82092 6.91078C2.85482 6.85079 2.90076 6.79845 2.95584 6.75705L5.95584 4.34205C6.04531 4.26851 6.15753 4.22831 6.27334 4.22831C6.38916 4.22831 6.50138 4.26851 6.59084 4.34205L9.59084 6.84205C9.65135 6.89221 9.69918 6.95593 9.73046 7.02803C9.76173 7.10014 9.77557 7.1786 9.77084 7.25705Z'
|
'M9.77084 7.25705C9.77107 7.37388 9.73039 7.4871 9.65584 7.57705C9.61387 7.62768 9.56232 7.66953 9.50415 7.70021C9.44597 7.73089 9.38232 7.74978 9.31683 7.75582C9.25134 7.76186 9.18531 7.75492 9.1225 7.7354C9.0597 7.71588 9.00137 7.68416 8.95084 7.64205L6.27084 5.40205L3.58584 7.56205C3.5347 7.60359 3.47585 7.6346 3.41268 7.65332C3.34951 7.67203 3.28327 7.67808 3.21775 7.67111C3.15224 7.66414 3.08875 7.64429 3.03093 7.61271C2.97311 7.58112 2.92211 7.53842 2.88084 7.48705C2.83533 7.43532 2.80099 7.37474 2.78 7.30911C2.759 7.24348 2.7518 7.17421 2.75884 7.10567C2.76589 7.03712 2.78702 6.97077 2.82092 6.91078C2.85482 6.85079 2.90076 6.79845 2.95584 6.75705L5.95584 4.34205C6.04531 4.26851 6.15753 4.22831 6.27334 4.22831C6.38916 4.22831 6.50138 4.26851 6.59084 4.34205L9.59084 6.84205C9.65135 6.89221 9.69918 6.95593 9.73046 7.02803C9.76173 7.10014 9.77557 7.1786 9.77084 7.25705Z'
|
||||||
}
|
}
|
||||||
fill={'white'}
|
fill={'white'}
|
||||||
/>
|
/>
|
||||||
</g>
|
</g>
|
||||||
<defs>
|
<defs>
|
||||||
<clipPath id={'clip0_9209_3250'}>
|
<clipPath id={'clip0_9209_3250'}>
|
||||||
<rect fill={'white'} height={12} width={12} />
|
<rect fill={'white'} height={12} width={12} />
|
||||||
</clipPath>
|
</clipPath>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
const ForwardRef = forwardRef(ChevronUp)
|
const ForwardRef = forwardRef(ChevronUp)
|
||||||
const Memo = memo(ForwardRef)
|
const Memo = memo(ForwardRef)
|
||||||
|
|||||||
@@ -1,37 +1,37 @@
|
|||||||
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
||||||
|
|
||||||
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
||||||
<svg
|
|
||||||
fill={'none'}
|
|
||||||
height={'24'}
|
|
||||||
ref={ref}
|
|
||||||
viewBox={'0 0 24 24'}
|
|
||||||
width={'24'}
|
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
<svg
|
<svg
|
||||||
fill={'none'}
|
fill={'none'}
|
||||||
height={'24'}
|
height={'24'}
|
||||||
viewBox={'0 0 24 24'}
|
ref={ref}
|
||||||
width={'24'}
|
viewBox={'0 0 24 24'}
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
width={'24'}
|
||||||
|
xmlns={'http://www.w3.org/2000/svg'}
|
||||||
|
{...props}
|
||||||
>
|
>
|
||||||
<g clipPath={'url(#clip0_9883_2381)'}>
|
<svg
|
||||||
<path
|
fill={'none'}
|
||||||
d={
|
height={'24'}
|
||||||
'M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41Z'
|
viewBox={'0 0 24 24'}
|
||||||
}
|
width={'24'}
|
||||||
fill={'white'}
|
xmlns={'http://www.w3.org/2000/svg'}
|
||||||
/>
|
>
|
||||||
</g>
|
<g clipPath={'url(#clip0_9883_2381)'}>
|
||||||
<defs>
|
<path
|
||||||
<clipPath id={'clip0_9883_2381'}>
|
d={
|
||||||
<rect fill={'white'} height={'24'} width={'24'} />
|
'M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41Z'
|
||||||
</clipPath>
|
}
|
||||||
</defs>
|
fill={'white'}
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id={'clip0_9883_2381'}>
|
||||||
|
<rect fill={'white'} height={'24'} width={'24'} />
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
</svg>
|
</svg>
|
||||||
</svg>
|
|
||||||
)
|
)
|
||||||
const ForwardRef = forwardRef(SvgComponent)
|
const ForwardRef = forwardRef(SvgComponent)
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
import { SVGProps } from 'react'
|
import { SVGProps } from 'react'
|
||||||
const SvgComponent = (props: SVGProps<SVGSVGElement>) => (
|
const SvgComponent = (props: SVGProps<SVGSVGElement>) => (
|
||||||
<svg
|
<svg
|
||||||
fill={'none'}
|
fill={'none'}
|
||||||
height={'16'}
|
height={'16'}
|
||||||
viewBox={'0 0 16 16'}
|
viewBox={'0 0 16 16'}
|
||||||
width={'16'}
|
width={'16'}
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
xmlns={'http://www.w3.org/2000/svg'}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<g clipPath={'url(#clip0_28366_3239)'}>
|
<g clipPath={'url(#clip0_28366_3239)'}>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M12.6666 13.3334H3.33329C3.15648 13.3334 2.98691 13.4036 2.86189 13.5286C2.73686 13.6537 2.66663 13.8232 2.66663 14C2.66663 14.1769 2.73686 14.3464 2.86189 14.4714C2.98691 14.5965 3.15648 14.6667 3.33329 14.6667H12.6666C12.8434 14.6667 13.013 14.5965 13.138 14.4714C13.2631 14.3464 13.3333 14.1769 13.3333 14C13.3333 13.8232 13.2631 13.6537 13.138 13.5286C13.013 13.4036 12.8434 13.3334 12.6666 13.3334Z'
|
'M12.6666 13.3334H3.33329C3.15648 13.3334 2.98691 13.4036 2.86189 13.5286C2.73686 13.6537 2.66663 13.8232 2.66663 14C2.66663 14.1769 2.73686 14.3464 2.86189 14.4714C2.98691 14.5965 3.15648 14.6667 3.33329 14.6667H12.6666C12.8434 14.6667 13.013 14.5965 13.138 14.4714C13.2631 14.3464 13.3333 14.1769 13.3333 14C13.3333 13.8232 13.2631 13.6537 13.138 13.5286C13.013 13.4036 12.8434 13.3334 12.6666 13.3334Z'
|
||||||
}
|
}
|
||||||
fill={'white'}
|
fill={'white'}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M3.33329 12H3.39329L6.17329 11.7467C6.47782 11.7163 6.76264 11.5821 6.97995 11.3667L12.98 5.36665C13.2128 5.12063 13.3387 4.79233 13.3299 4.45368C13.3212 4.11503 13.1786 3.79366 12.9333 3.55999L11.1066 1.73332C10.8682 1.50938 10.5558 1.38089 10.2288 1.37229C9.90187 1.36368 9.58314 1.47557 9.33329 1.68665L3.33329 7.68665C3.1178 7.90396 2.98362 8.18879 2.95329 8.49332L2.66662 11.2733C2.65764 11.371 2.67031 11.4694 2.70373 11.5616C2.73715 11.6538 2.79049 11.7374 2.85995 11.8067C2.92225 11.8684 2.99612 11.9173 3.07735 11.9505C3.15857 11.9837 3.24555 12.0005 3.33329 12ZM10.18 2.66665L12 4.48665L10.6666 5.78665L8.87995 3.99999L10.18 2.66665ZM4.24662 8.60665L7.99995 4.87999L9.79995 6.67999L6.06662 10.4133L4.06662 10.6L4.24662 8.60665Z'
|
'M3.33329 12H3.39329L6.17329 11.7467C6.47782 11.7163 6.76264 11.5821 6.97995 11.3667L12.98 5.36665C13.2128 5.12063 13.3387 4.79233 13.3299 4.45368C13.3212 4.11503 13.1786 3.79366 12.9333 3.55999L11.1066 1.73332C10.8682 1.50938 10.5558 1.38089 10.2288 1.37229C9.90187 1.36368 9.58314 1.47557 9.33329 1.68665L3.33329 7.68665C3.1178 7.90396 2.98362 8.18879 2.95329 8.49332L2.66662 11.2733C2.65764 11.371 2.67031 11.4694 2.70373 11.5616C2.73715 11.6538 2.79049 11.7374 2.85995 11.8067C2.92225 11.8684 2.99612 11.9173 3.07735 11.9505C3.15857 11.9837 3.24555 12.0005 3.33329 12ZM10.18 2.66665L12 4.48665L10.6666 5.78665L8.87995 3.99999L10.18 2.66665ZM4.24662 8.60665L7.99995 4.87999L9.79995 6.67999L6.06662 10.4133L4.06662 10.6L4.24662 8.60665Z'
|
||||||
}
|
}
|
||||||
fill={'white'}
|
fill={'white'}
|
||||||
/>
|
/>
|
||||||
</g>
|
</g>
|
||||||
<defs>
|
<defs>
|
||||||
<clipPath id={'clip0_28366_3239'}>
|
<clipPath id={'clip0_28366_3239'}>
|
||||||
<rect fill={'white'} height={'16'} width={'16'} />
|
<rect fill={'white'} height={'16'} width={'16'} />
|
||||||
</clipPath>
|
</clipPath>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
export default SvgComponent
|
export default SvgComponent
|
||||||
|
|||||||
@@ -1,34 +1,34 @@
|
|||||||
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
||||||
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
||||||
<svg
|
<svg
|
||||||
fill={'none'}
|
fill={'none'}
|
||||||
height={'16'}
|
height={'16'}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
viewBox={'0 0 16 16'}
|
viewBox={'0 0 16 16'}
|
||||||
width={'16'}
|
width={'16'}
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
xmlns={'http://www.w3.org/2000/svg'}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<g clipPath={'url(#clip0_5918_2436)'}>
|
<g clipPath={'url(#clip0_5918_2436)'}>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M12.6666 13.3334H3.33329C3.15648 13.3334 2.98691 13.4036 2.86189 13.5286C2.73686 13.6537 2.66663 13.8232 2.66663 14C2.66663 14.1769 2.73686 14.3464 2.86189 14.4714C2.98691 14.5965 3.15648 14.6667 3.33329 14.6667H12.6666C12.8434 14.6667 13.013 14.5965 13.138 14.4714C13.2631 14.3464 13.3333 14.1769 13.3333 14C13.3333 13.8232 13.2631 13.6537 13.138 13.5286C13.013 13.4036 12.8434 13.3334 12.6666 13.3334Z'
|
'M12.6666 13.3334H3.33329C3.15648 13.3334 2.98691 13.4036 2.86189 13.5286C2.73686 13.6537 2.66663 13.8232 2.66663 14C2.66663 14.1769 2.73686 14.3464 2.86189 14.4714C2.98691 14.5965 3.15648 14.6667 3.33329 14.6667H12.6666C12.8434 14.6667 13.013 14.5965 13.138 14.4714C13.2631 14.3464 13.3333 14.1769 13.3333 14C13.3333 13.8232 13.2631 13.6537 13.138 13.5286C13.013 13.4036 12.8434 13.3334 12.6666 13.3334Z'
|
||||||
}
|
}
|
||||||
fill={'white'}
|
fill={'white'}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M3.33329 12H3.39329L6.17329 11.7467C6.47782 11.7163 6.76264 11.5821 6.97995 11.3667L12.98 5.36665C13.2128 5.12063 13.3387 4.79233 13.3299 4.45368C13.3212 4.11503 13.1786 3.79366 12.9333 3.55999L11.1066 1.73332C10.8682 1.50938 10.5558 1.38089 10.2288 1.37229C9.90187 1.36368 9.58314 1.47557 9.33329 1.68665L3.33329 7.68665C3.1178 7.90396 2.98362 8.18879 2.95329 8.49332L2.66662 11.2733C2.65764 11.371 2.67031 11.4694 2.70373 11.5616C2.73715 11.6538 2.79049 11.7374 2.85995 11.8067C2.92225 11.8684 2.99612 11.9173 3.07735 11.9505C3.15857 11.9837 3.24555 12.0005 3.33329 12ZM10.18 2.66665L12 4.48665L10.6666 5.78665L8.87995 3.99999L10.18 2.66665ZM4.24662 8.60665L7.99995 4.87999L9.79995 6.67999L6.06662 10.4133L4.06662 10.6L4.24662 8.60665Z'
|
'M3.33329 12H3.39329L6.17329 11.7467C6.47782 11.7163 6.76264 11.5821 6.97995 11.3667L12.98 5.36665C13.2128 5.12063 13.3387 4.79233 13.3299 4.45368C13.3212 4.11503 13.1786 3.79366 12.9333 3.55999L11.1066 1.73332C10.8682 1.50938 10.5558 1.38089 10.2288 1.37229C9.90187 1.36368 9.58314 1.47557 9.33329 1.68665L3.33329 7.68665C3.1178 7.90396 2.98362 8.18879 2.95329 8.49332L2.66662 11.2733C2.65764 11.371 2.67031 11.4694 2.70373 11.5616C2.73715 11.6538 2.79049 11.7374 2.85995 11.8067C2.92225 11.8684 2.99612 11.9173 3.07735 11.9505C3.15857 11.9837 3.24555 12.0005 3.33329 12ZM10.18 2.66665L12 4.48665L10.6666 5.78665L8.87995 3.99999L10.18 2.66665ZM4.24662 8.60665L7.99995 4.87999L9.79995 6.67999L6.06662 10.4133L4.06662 10.6L4.24662 8.60665Z'
|
||||||
}
|
}
|
||||||
fill={'white'}
|
fill={'white'}
|
||||||
/>
|
/>
|
||||||
</g>
|
</g>
|
||||||
<defs>
|
<defs>
|
||||||
<clipPath id={'clip0_5918_2436'}>
|
<clipPath id={'clip0_5918_2436'}>
|
||||||
<rect fill={'white'} height={'16'} width={'16'} />
|
<rect fill={'white'} height={'16'} width={'16'} />
|
||||||
</clipPath>
|
</clipPath>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
const ForwardRef = forwardRef(SvgComponent)
|
const ForwardRef = forwardRef(SvgComponent)
|
||||||
const Memo = memo(ForwardRef)
|
const Memo = memo(ForwardRef)
|
||||||
|
|||||||
@@ -1,100 +1,100 @@
|
|||||||
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
||||||
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
||||||
<svg
|
<svg
|
||||||
fill={'none'}
|
fill={'none'}
|
||||||
height={96}
|
height={96}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
viewBox={'0 0 96 96'}
|
viewBox={'0 0 96 96'}
|
||||||
width={96}
|
width={96}
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
xmlns={'http://www.w3.org/2000/svg'}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M95.5 48c0 26.234-21.266 47.5-47.5 47.5C21.767 95.5.5 74.234.5 48 .5 21.767 21.767.5 48 .5 74.234.5 95.5 21.767 95.5 48z'
|
'M95.5 48c0 26.234-21.266 47.5-47.5 47.5C21.767 95.5.5 74.234.5 48 .5 21.767 21.767.5 48 .5 74.234.5 95.5 21.767 95.5 48z'
|
||||||
}
|
}
|
||||||
fill={'#8C61FF'}
|
fill={'#8C61FF'}
|
||||||
fillOpacity={0.05}
|
fillOpacity={0.05}
|
||||||
stroke={'#BEA6FF'}
|
stroke={'#BEA6FF'}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M77.889 54.454a.651.651 0 0 1-.643-.643v-9.24a.643.643 0 0 1 1.285 0v9.25a.643.643 0 0 1-.641.633zM77.889 41.777a.643.643 0 0 1-.643-.643V39.24a.643.643 0 0 1 1.285 0v1.903a.634.634 0 0 1-.641.634zM25.786 32.503h-3.559a.668.668 0 0 1 0-1.335h3.56a.667.667 0 0 1 0 1.335z'
|
'M77.889 54.454a.651.651 0 0 1-.643-.643v-9.24a.643.643 0 0 1 1.285 0v9.25a.643.643 0 0 1-.641.633zM77.889 41.777a.643.643 0 0 1-.643-.643V39.24a.643.643 0 0 1 1.285 0v1.903a.634.634 0 0 1-.641.634zM25.786 32.503h-3.559a.668.668 0 0 1 0-1.335h3.56a.667.667 0 0 1 0 1.335z'
|
||||||
}
|
}
|
||||||
fill={'#BEA6FF'}
|
fill={'#BEA6FF'}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M24.007 34.282a.668.668 0 0 1-.667-.667v-3.559a.668.668 0 0 1 1.335 0v3.56c0 .367-.3.666-.668.666zM36.857 73.714a.857.857 0 1 1 0 1.715.857.857 0 0 1 0-1.715zM31.714 73.714a.857.857 0 1 1 0 1.715.857.857 0 0 1 0-1.715zM26.571 73.714a.857.857 0 1 1 0 1.715.857.857 0 0 1 0-1.715z'
|
'M24.007 34.282a.668.668 0 0 1-.667-.667v-3.559a.668.668 0 0 1 1.335 0v3.56c0 .367-.3.666-.668.666zM36.857 73.714a.857.857 0 1 1 0 1.715.857.857 0 0 1 0-1.715zM31.714 73.714a.857.857 0 1 1 0 1.715.857.857 0 0 1 0-1.715zM26.571 73.714a.857.857 0 1 1 0 1.715.857.857 0 0 1 0-1.715z'
|
||||||
}
|
}
|
||||||
fill={'#BEA6FF'}
|
fill={'#BEA6FF'}
|
||||||
/>
|
/>
|
||||||
<path d={'M47.864 23.242l-24.1 19.799 24.1 19.808 24.1-19.808-24.1-19.8z'} fill={'#333'} />
|
<path d={'M47.864 23.242l-24.1 19.799 24.1 19.808 24.1-19.808-24.1-19.8z'} fill={'#333'} />
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M47.865 63.544a.667.667 0 0 1-.417-.195l-24.1-19.808a.698.698 0 0 1-.183-.833.725.725 0 0 1 .183-.242l24.1-19.799a.695.695 0 0 1 .926 0l24.1 19.799a.725.725 0 0 1 .25.537.695.695 0 0 1-.25.538l-24.1 19.808a.668.668 0 0 1-.51.195zM24.859 43.04l23.006 18.91L70.87 43.04l-23.006-18.9-23.006 18.9z'
|
'M47.865 63.544a.667.667 0 0 1-.417-.195l-24.1-19.808a.698.698 0 0 1-.183-.833.725.725 0 0 1 .183-.242l24.1-19.799a.695.695 0 0 1 .926 0l24.1 19.799a.725.725 0 0 1 .25.537.695.695 0 0 1-.25.538l-24.1 19.808a.668.668 0 0 1-.51.195zM24.859 43.04l23.006 18.91L70.87 43.04l-23.006-18.9-23.006 18.9z'
|
||||||
}
|
}
|
||||||
fill={'#BEA6FF'}
|
fill={'#BEA6FF'}
|
||||||
/>
|
/>
|
||||||
<path d={'M65.013 28.803H30.717v40.784h34.296V28.803z'} fill={'#333'} />
|
<path d={'M65.013 28.803H30.717v40.784h34.296V28.803z'} fill={'#333'} />
|
||||||
<path d={'M55.41 40.853l-11.716 9.63v19.104h21.319V40.853H55.41z'} fill={'#333'} />
|
<path d={'M55.41 40.853l-11.716 9.63v19.104h21.319V40.853H55.41z'} fill={'#333'} />
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M65.059 70.282H30.763a.704.704 0 0 1-.695-.695V28.803a.695.695 0 0 1 .695-.677H65.06a.695.695 0 0 1 .695.696v40.784a.705.705 0 0 1-.695.676zM31.412 68.91h32.905V29.517H31.412V68.91z'
|
'M65.059 70.282H30.763a.704.704 0 0 1-.695-.695V28.803a.695.695 0 0 1 .695-.677H65.06a.695.695 0 0 1 .695.696v40.784a.705.705 0 0 1-.695.676zM31.412 68.91h32.905V29.517H31.412V68.91z'
|
||||||
}
|
}
|
||||||
fill={'#BEA6FF'}
|
fill={'#BEA6FF'}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M58.987 35.06H48.17a.695.695 0 0 1 0-1.39h10.817a.696.696 0 0 1 0 1.39zM44.463 35.06h-7.721a.696.696 0 0 1 0-1.39h7.72a.696.696 0 0 1 0 1.39zM58.987 39.694h-7.11a.695.695 0 0 1 0-1.39h7.11a.695.695 0 1 1 0 1.39zM48.17 39.694H36.742a.695.695 0 0 1 0-1.39H48.17a.695.695 0 1 1 0 1.39zM58.988 44.329H46.317a.696.696 0 0 1 0-1.39h12.67a.696.696 0 0 1 0 1.39zM42.609 44.329h-5.867a.696.696 0 0 1 0-1.39h5.867a.696.696 0 0 1 0 1.39zM58.987 48.964h-6.182a.695.695 0 0 1 0-1.39h6.182a.695.695 0 1 1 0 1.39zM49.097 48.964H36.742a.695.695 0 0 1 0-1.39h12.355a.695.695 0 1 1 0 1.39zM54.047 53.598H41.682a.695.695 0 1 1 0-1.39h12.365a.695.695 0 1 1 0 1.39z'
|
'M58.987 35.06H48.17a.695.695 0 0 1 0-1.39h10.817a.696.696 0 0 1 0 1.39zM44.463 35.06h-7.721a.696.696 0 0 1 0-1.39h7.72a.696.696 0 0 1 0 1.39zM58.987 39.694h-7.11a.695.695 0 0 1 0-1.39h7.11a.695.695 0 1 1 0 1.39zM48.17 39.694H36.742a.695.695 0 0 1 0-1.39H48.17a.695.695 0 1 1 0 1.39zM58.988 44.329H46.317a.696.696 0 0 1 0-1.39h12.67a.696.696 0 0 1 0 1.39zM42.609 44.329h-5.867a.696.696 0 0 1 0-1.39h5.867a.696.696 0 0 1 0 1.39zM58.987 48.964h-6.182a.695.695 0 0 1 0-1.39h6.182a.695.695 0 1 1 0 1.39zM49.097 48.964H36.742a.695.695 0 0 1 0-1.39h12.355a.695.695 0 1 1 0 1.39zM54.047 53.598H41.682a.695.695 0 1 1 0-1.39h12.365a.695.695 0 1 1 0 1.39z'
|
||||||
}
|
}
|
||||||
fill={'#BEA6FF'}
|
fill={'#BEA6FF'}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M23.765 43.04v26.547l16.147-13.273L23.765 43.04zM55.818 56.314l16.146 13.273V43.04L55.818 56.315z'
|
'M23.765 43.04v26.547l16.147-13.273L23.765 43.04zM55.818 56.314l16.146 13.273V43.04L55.818 56.315z'
|
||||||
}
|
}
|
||||||
fill={'#333'}
|
fill={'#333'}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d={'M47.864 62.849l-7.952-6.535-16.147 13.273h48.2L55.816 56.314l-7.953 6.535z'}
|
d={'M47.864 62.849l-7.952-6.535-16.147 13.273h48.2L55.816 56.314l-7.953 6.535z'}
|
||||||
fill={'#333'}
|
fill={'#333'}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M28.4 50.493v15.284l9.297-7.637-9.297-7.647zM63.196 57.88l8.768 7.212V50.678l-8.768 7.202z'
|
'M28.4 50.493v15.284l9.297-7.637-9.297-7.647zM63.196 57.88l8.768 7.212V50.678l-8.768 7.202z'
|
||||||
}
|
}
|
||||||
fill={'#333'}
|
fill={'#333'}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M23.765 70.282a.67.67 0 0 1-.296-.074.686.686 0 0 1-.399-.62V43.04a.685.685 0 0 1 .399-.62.695.695 0 0 1 .741.083l16.147 13.273a.704.704 0 0 1 0 1.075L24.21 70.115a.686.686 0 0 1-.445.167zm.695-25.768v23.6l14.358-11.8-14.358-11.8z'
|
'M23.765 70.282a.67.67 0 0 1-.296-.074.686.686 0 0 1-.399-.62V43.04a.685.685 0 0 1 .399-.62.695.695 0 0 1 .741.083l16.147 13.273a.704.704 0 0 1 0 1.075L24.21 70.115a.686.686 0 0 1-.445.167zm.695-25.768v23.6l14.358-11.8-14.358-11.8z'
|
||||||
}
|
}
|
||||||
fill={'#BEA6FF'}
|
fill={'#BEA6FF'}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d={'M60.424 60.095l-10.15 8.343-7.08-5.821-8.473 6.97h37.243l-11.54-9.492z'}
|
d={'M60.424 60.095l-10.15 8.343-7.08-5.821-8.473 6.97h37.243l-11.54-9.492z'}
|
||||||
fill={'#333'}
|
fill={'#333'}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M71.964 70.282a.686.686 0 0 1-.445-.167L55.373 56.861a.703.703 0 0 1 0-1.076l16.174-13.282a.696.696 0 0 1 .742-.084.687.687 0 0 1 .398.621v26.547a.686.686 0 0 1-.398.621.668.668 0 0 1-.325.074zM56.911 56.314l14.358 11.8v-23.6l-14.358 11.8z'
|
'M71.964 70.282a.686.686 0 0 1-.445-.167L55.373 56.861a.703.703 0 0 1 0-1.076l16.174-13.282a.696.696 0 0 1 .742-.084.687.687 0 0 1 .398.621v26.547a.686.686 0 0 1-.398.621.668.668 0 0 1-.325.074zM56.911 56.314l14.358 11.8v-23.6l-14.358 11.8z'
|
||||||
}
|
}
|
||||||
fill={'#BEA6FF'}
|
fill={'#BEA6FF'}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M71.964 70.282h-48.2a.704.704 0 0 1-.657-.463.705.705 0 0 1 .213-.77l16.147-13.273a.695.695 0 0 1 .927 0l7.508 6.173 7.508-6.174a.695.695 0 0 1 .927 0L72.483 69.05a.705.705 0 0 1 .213.77.704.704 0 0 1-.732.463zm-46.262-1.371h44.325L55.79 57.212l-7.508 6.173a.695.695 0 0 1-.927 0l-7.508-6.173L25.702 68.91zM46.358 75.36h-3.56a.668.668 0 0 1 0-1.335h3.56a.668.668 0 0 1 0 1.335z'
|
'M71.964 70.282h-48.2a.704.704 0 0 1-.657-.463.705.705 0 0 1 .213-.77l16.147-13.273a.695.695 0 0 1 .927 0l7.508 6.173 7.508-6.174a.695.695 0 0 1 .927 0L72.483 69.05a.705.705 0 0 1 .213.77.704.704 0 0 1-.732.463zm-46.262-1.371h44.325L55.79 57.212l-7.508 6.173a.695.695 0 0 1-.927 0l-7.508-6.173L25.702 68.91zM46.358 75.36h-3.56a.668.668 0 0 1 0-1.335h3.56a.668.668 0 0 1 0 1.335z'
|
||||||
}
|
}
|
||||||
fill={'#BEA6FF'}
|
fill={'#BEA6FF'}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M44.579 77.14a.668.668 0 0 1-.668-.668v-3.559a.668.668 0 0 1 1.335 0v3.56a.667.667 0 0 1-.667.666z'
|
'M44.579 77.14a.668.668 0 0 1-.668-.668v-3.559a.668.668 0 0 1 1.335 0v3.56a.667.667 0 0 1-.667.666z'
|
||||||
}
|
}
|
||||||
fill={'#BEA6FF'}
|
fill={'#BEA6FF'}
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
const ForwardRef = forwardRef(SvgComponent)
|
const ForwardRef = forwardRef(SvgComponent)
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
||||||
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
||||||
<svg
|
<svg
|
||||||
fill={'none'}
|
fill={'none'}
|
||||||
height={20}
|
height={20}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
viewBox={'0 0 24 24'}
|
viewBox={'0 0 24 24'}
|
||||||
width={20}
|
width={20}
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
xmlns={'http://www.w3.org/2000/svg'}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
clipRule={'evenodd'}
|
clipRule={'evenodd'}
|
||||||
d={
|
d={
|
||||||
'M12 4.5C7 4.5 2.73 7.6 1 12a11.83 11.83 0 0 0 22 0c-1.73-4.39-6-7.5-11-7.5zM12 17a5 5 0 1 1 0-10 5 5 0 0 1 0 10zm0-8a3 3 0 1 0 0 6 3 3 0 0 0 0-6z'
|
'M12 4.5C7 4.5 2.73 7.6 1 12a11.83 11.83 0 0 0 22 0c-1.73-4.39-6-7.5-11-7.5zM12 17a5 5 0 1 1 0-10 5 5 0 0 1 0 10zm0-8a3 3 0 1 0 0 6 3 3 0 0 0 0-6z'
|
||||||
}
|
}
|
||||||
fill={'#fff'}
|
fill={'#fff'}
|
||||||
fillRule={'evenodd'}
|
fillRule={'evenodd'}
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
const ForwardRef = forwardRef(SvgComponent)
|
const ForwardRef = forwardRef(SvgComponent)
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
export { default as Eye } from './eye'
|
|
||||||
export { default as VisibilityOff } from './visibility-off'
|
|
||||||
export { default as Check } from './check'
|
|
||||||
export { default as Email } from './email'
|
|
||||||
export { default as Camera } from './camera'
|
export { default as Camera } from './camera'
|
||||||
export { default as Logout } from './logout'
|
export { default as Check } from './check'
|
||||||
export { default as Edit } from './edit'
|
|
||||||
export { default as Logo } from './logo'
|
|
||||||
export { default as PersonOutline } from './person-outline'
|
|
||||||
export { default as ChevronUp } from './chevron-up'
|
export { default as ChevronUp } from './chevron-up'
|
||||||
export { default as Close } from './close'
|
export { default as Close } from './close'
|
||||||
export { default as Search } from './search'
|
export { default as Edit } from './edit'
|
||||||
|
export { default as Edit2Outline } from './edit-2-outline'
|
||||||
|
export { default as Email } from './email'
|
||||||
|
export { default as Eye } from './eye'
|
||||||
export { default as KeyboardArrowLeft } from './keyboard-arrow-left'
|
export { default as KeyboardArrowLeft } from './keyboard-arrow-left'
|
||||||
export { default as KeyboardArrowRight } from './keyboard-arrow-right'
|
export { default as KeyboardArrowRight } from './keyboard-arrow-right'
|
||||||
|
export { default as Logo } from './logo'
|
||||||
|
export { default as Logout } from './logout'
|
||||||
|
export { default as PersonOutline } from './person-outline'
|
||||||
export { default as PlayCircleOutline } from './play-circle-outline'
|
export { default as PlayCircleOutline } from './play-circle-outline'
|
||||||
export { default as Edit2Outline } from './edit-2-outline'
|
export { default as Search } from './search'
|
||||||
export { default as TrashOutline } from './trash-outline'
|
export { default as TrashOutline } from './trash-outline'
|
||||||
|
export { default as VisibilityOff } from './visibility-off'
|
||||||
|
|||||||
@@ -1,26 +1,28 @@
|
|||||||
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
||||||
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
||||||
<svg
|
<svg
|
||||||
fill={'none'}
|
fill={'none'}
|
||||||
height={'16'}
|
height={'16'}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
viewBox={'0 0 16 16'}
|
viewBox={'0 0 16 16'}
|
||||||
width={'16'}
|
width={'16'}
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
xmlns={'http://www.w3.org/2000/svg'}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<g clipPath={'url(#clip0_5928_3055)'}>
|
<g clipPath={'url(#clip0_5928_3055)'}>
|
||||||
<path
|
<path
|
||||||
d={'M10.2733 11.06L7.21998 8L10.2733 4.94L9.33331 4L5.33331 8L9.33331 12L10.2733 11.06Z'}
|
d={
|
||||||
fill={'white'}
|
'M10.2733 11.06L7.21998 8L10.2733 4.94L9.33331 4L5.33331 8L9.33331 12L10.2733 11.06Z'
|
||||||
/>
|
}
|
||||||
</g>
|
fill={'white'}
|
||||||
<defs>
|
/>
|
||||||
<clipPath id={'clip0_5928_3055'}>
|
</g>
|
||||||
<rect fill={'white'} height={'16'} width={'16'} />
|
<defs>
|
||||||
</clipPath>
|
<clipPath id={'clip0_5928_3055'}>
|
||||||
</defs>
|
<rect fill={'white'} height={'16'} width={'16'} />
|
||||||
</svg>
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
)
|
)
|
||||||
const ForwardRef = forwardRef(SvgComponent)
|
const ForwardRef = forwardRef(SvgComponent)
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,28 @@
|
|||||||
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
||||||
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
||||||
<svg
|
<svg
|
||||||
fill={'none'}
|
fill={'none'}
|
||||||
height={'16'}
|
height={'16'}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
viewBox={'0 0 16 16'}
|
viewBox={'0 0 16 16'}
|
||||||
width={'16'}
|
width={'16'}
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
xmlns={'http://www.w3.org/2000/svg'}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<g clipPath={'url(#clip0_5928_3027)'}>
|
<g clipPath={'url(#clip0_5928_3027)'}>
|
||||||
<path
|
<path
|
||||||
d={'M5.72665 11.06L8.77999 8L5.72665 4.94L6.66665 4L10.6667 8L6.66665 12L5.72665 11.06Z'}
|
d={
|
||||||
fill={'white'}
|
'M5.72665 11.06L8.77999 8L5.72665 4.94L6.66665 4L10.6667 8L6.66665 12L5.72665 11.06Z'
|
||||||
/>
|
}
|
||||||
</g>
|
fill={'white'}
|
||||||
<defs>
|
/>
|
||||||
<clipPath id={'clip0_5928_3027'}>
|
</g>
|
||||||
<rect fill={'white'} height={'16'} width={'16'} />
|
<defs>
|
||||||
</clipPath>
|
<clipPath id={'clip0_5928_3027'}>
|
||||||
</defs>
|
<rect fill={'white'} height={'16'} width={'16'} />
|
||||||
</svg>
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
)
|
)
|
||||||
const ForwardRef = forwardRef(SvgComponent)
|
const ForwardRef = forwardRef(SvgComponent)
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +1,34 @@
|
|||||||
import { SVGProps } from 'react'
|
import { SVGProps } from 'react'
|
||||||
const SvgComponent = (props: SVGProps<SVGSVGElement>) => (
|
const SvgComponent = (props: SVGProps<SVGSVGElement>) => (
|
||||||
<svg
|
<svg
|
||||||
fill={'none'}
|
fill={'none'}
|
||||||
height={36}
|
height={36}
|
||||||
viewBox={'0 0 157 36'}
|
viewBox={'0 0 157 36'}
|
||||||
width={157}
|
width={157}
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
xmlns={'http://www.w3.org/2000/svg'}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M70.99 24.72a7.34 7.34 0 0 1-3.5-.83 6.43 6.43 0 0 1-2.44-2.33c-.6-1-.89-2.13-.89-3.38s.3-2.37.89-3.36c.6-1 1.41-1.77 2.45-2.32a7.25 7.25 0 0 1 3.5-.85c1.1 0 2.08.19 2.96.57.89.39 1.63.94 2.23 1.66l-1.87 1.74a4.02 4.02 0 0 0-3.17-1.48c-.78 0-1.48.17-2.09.52-.6.34-1.09.81-1.44 1.43-.33.61-.5 1.3-.5 2.1 0 .77.17 1.47.5 2.09.35.6.83 1.1 1.44 1.44.61.34 1.31.5 2.1.5a4 4 0 0 0 3.16-1.5l1.87 1.74c-.6.73-1.34 1.3-2.23 1.68a7.4 7.4 0 0 1-2.97.58zM83.66 24.72c-1.8 0-3.2-.5-4.22-1.5-1-1-1.5-2.43-1.5-4.28v-7.08h2.93v6.97c0 2.26.93 3.4 2.8 3.4.92 0 1.61-.28 2.1-.82.47-.55.71-1.41.71-2.58v-6.97h2.89v7.08c0 1.85-.5 3.28-1.52 4.28-1 1-2.4 1.5-4.2 1.5zM101.5 17.93a3.13 3.13 0 0 1 2.3 3.12c0 1.1-.42 1.96-1.29 2.56-.84.6-2.09.9-3.73.9h-6.52V11.86h6.16c1.53 0 2.7.3 3.53.89a2.8 2.8 0 0 1 1.24 2.4 3.04 3.04 0 0 1-1.68 2.78zm-6.35-3.86v2.97h2.9c.72 0 1.26-.12 1.63-.38.38-.25.56-.62.56-1.11 0-.5-.18-.86-.56-1.1a2.92 2.92 0 0 0-1.63-.38h-2.9zm3.4 8.23c.77 0 1.34-.13 1.73-.38.4-.25.6-.65.6-1.18 0-1.04-.78-1.57-2.33-1.57h-3.4v3.13h3.4zM114.32 21.8h-5.85l-1.12 2.7h-2.99l5.62-12.64h2.88l5.64 12.64h-3.07l-1.11-2.7zm-.92-2.23l-2-4.84-2 4.84h4zM121.78 14.25h-4.03v-2.39h10.98v2.39h-4.03V24.5h-2.92V14.25zM136.23 24.72a7.4 7.4 0 0 1-3.55-.85 6.39 6.39 0 0 1-2.47-2.33 6.5 6.5 0 0 1-.88-3.36 6.34 6.34 0 0 1 3.35-5.69 7.4 7.4 0 0 1 3.55-.84c1.3 0 2.48.28 3.53.85a6.35 6.35 0 0 1 3.37 5.68 6.4 6.4 0 0 1-.9 3.36 6.4 6.4 0 0 1-2.47 2.33 7.29 7.29 0 0 1-3.53.85zm0-2.5a3.69 3.69 0 0 0 3.42-1.95c.35-.6.52-1.3.52-2.09 0-.78-.17-1.48-.52-2.1a3.56 3.56 0 0 0-1.4-1.42 3.94 3.94 0 0 0-2.02-.52 3.94 3.94 0 0 0-3.44 1.95c-.34.61-.5 1.3-.5 2.1 0 .77.16 1.47.5 2.09a3.82 3.82 0 0 0 3.44 1.94zM153.35 24.5l-2.43-3.52H148.24v3.52h-2.92V11.86h5.45c1.12 0 2.09.19 2.9.56.83.38 1.47.9 1.91 1.6.44.68.67 1.49.67 2.43a4.3 4.3 0 0 1-.69 2.44 4.25 4.25 0 0 1-1.9 1.55l2.82 4.06h-3.13zm-.06-8.05c0-.71-.22-1.25-.68-1.63-.45-.38-1.11-.57-1.99-.57h-2.36v4.4h2.37c.88 0 1.54-.2 2-.58a2 2 0 0 0 .68-1.62zM0 11.88h2.91v12.6H0v-12.6zM8.5 14.25H4.49v-2.37h10.97v2.37h-4.03v10.22H8.5V14.25zM33.74 11.88h2.92v12.6h-2.92v-12.6zM51.2 11.88v12.6h-2.39l-6.28-7.65v7.64h-2.88v-12.6h2.41l6.27 7.65v-7.64h2.88z'
|
'M70.99 24.72a7.34 7.34 0 0 1-3.5-.83 6.43 6.43 0 0 1-2.44-2.33c-.6-1-.89-2.13-.89-3.38s.3-2.37.89-3.36c.6-1 1.41-1.77 2.45-2.32a7.25 7.25 0 0 1 3.5-.85c1.1 0 2.08.19 2.96.57.89.39 1.63.94 2.23 1.66l-1.87 1.74a4.02 4.02 0 0 0-3.17-1.48c-.78 0-1.48.17-2.09.52-.6.34-1.09.81-1.44 1.43-.33.61-.5 1.3-.5 2.1 0 .77.17 1.47.5 2.09.35.6.83 1.1 1.44 1.44.61.34 1.31.5 2.1.5a4 4 0 0 0 3.16-1.5l1.87 1.74c-.6.73-1.34 1.3-2.23 1.68a7.4 7.4 0 0 1-2.97.58zM83.66 24.72c-1.8 0-3.2-.5-4.22-1.5-1-1-1.5-2.43-1.5-4.28v-7.08h2.93v6.97c0 2.26.93 3.4 2.8 3.4.92 0 1.61-.28 2.1-.82.47-.55.71-1.41.71-2.58v-6.97h2.89v7.08c0 1.85-.5 3.28-1.52 4.28-1 1-2.4 1.5-4.2 1.5zM101.5 17.93a3.13 3.13 0 0 1 2.3 3.12c0 1.1-.42 1.96-1.29 2.56-.84.6-2.09.9-3.73.9h-6.52V11.86h6.16c1.53 0 2.7.3 3.53.89a2.8 2.8 0 0 1 1.24 2.4 3.04 3.04 0 0 1-1.68 2.78zm-6.35-3.86v2.97h2.9c.72 0 1.26-.12 1.63-.38.38-.25.56-.62.56-1.11 0-.5-.18-.86-.56-1.1a2.92 2.92 0 0 0-1.63-.38h-2.9zm3.4 8.23c.77 0 1.34-.13 1.73-.38.4-.25.6-.65.6-1.18 0-1.04-.78-1.57-2.33-1.57h-3.4v3.13h3.4zM114.32 21.8h-5.85l-1.12 2.7h-2.99l5.62-12.64h2.88l5.64 12.64h-3.07l-1.11-2.7zm-.92-2.23l-2-4.84-2 4.84h4zM121.78 14.25h-4.03v-2.39h10.98v2.39h-4.03V24.5h-2.92V14.25zM136.23 24.72a7.4 7.4 0 0 1-3.55-.85 6.39 6.39 0 0 1-2.47-2.33 6.5 6.5 0 0 1-.88-3.36 6.34 6.34 0 0 1 3.35-5.69 7.4 7.4 0 0 1 3.55-.84c1.3 0 2.48.28 3.53.85a6.35 6.35 0 0 1 3.37 5.68 6.4 6.4 0 0 1-.9 3.36 6.4 6.4 0 0 1-2.47 2.33 7.29 7.29 0 0 1-3.53.85zm0-2.5a3.69 3.69 0 0 0 3.42-1.95c.35-.6.52-1.3.52-2.09 0-.78-.17-1.48-.52-2.1a3.56 3.56 0 0 0-1.4-1.42 3.94 3.94 0 0 0-2.02-.52 3.94 3.94 0 0 0-3.44 1.95c-.34.61-.5 1.3-.5 2.1 0 .77.16 1.47.5 2.09a3.82 3.82 0 0 0 3.44 1.94zM153.35 24.5l-2.43-3.52H148.24v3.52h-2.92V11.86h5.45c1.12 0 2.09.19 2.9.56.83.38 1.47.9 1.91 1.6.44.68.67 1.49.67 2.43a4.3 4.3 0 0 1-.69 2.44 4.25 4.25 0 0 1-1.9 1.55l2.82 4.06h-3.13zm-.06-8.05c0-.71-.22-1.25-.68-1.63-.45-.38-1.11-.57-1.99-.57h-2.36v4.4h2.37c.88 0 1.54-.2 2-.58a2 2 0 0 0 .68-1.62zM0 11.88h2.91v12.6H0v-12.6zM8.5 14.25H4.49v-2.37h10.97v2.37h-4.03v10.22H8.5V14.25zM33.74 11.88h2.92v12.6h-2.92v-12.6zM51.2 11.88v12.6h-2.39l-6.28-7.65v7.64h-2.88v-12.6h2.41l6.27 7.65v-7.64h2.88z'
|
||||||
}
|
}
|
||||||
fill={'#fff'}
|
fill={'#fff'}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
clipRule={'evenodd'}
|
clipRule={'evenodd'}
|
||||||
d={'M34.99 6.53a1.96 1.96 0 1 1 0 3.93 1.96 1.96 0 0 1 0-3.93z'}
|
d={'M34.99 6.53a1.96 1.96 0 1 1 0 3.93 1.96 1.96 0 0 1 0-3.93z'}
|
||||||
fill={'#FF0808'}
|
fill={'#FF0808'}
|
||||||
fillRule={'evenodd'}
|
fillRule={'evenodd'}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
clipRule={'evenodd'}
|
clipRule={'evenodd'}
|
||||||
d={
|
d={
|
||||||
'M19.5 16.04A2 2 0 0 1 21.5 18a2 2 0 0 1-2 1.96A2 2 0 0 1 17.46 18a2 2 0 0 1 2.02-1.96zM42.48 34.5a16.5 16.5 0 1 0 0-33 16.5 16.5 0 0 0 0 33zm0 1.5a18 18 0 1 0 0-36 18 18 0 0 0 0 36z'
|
'M19.5 16.04A2 2 0 0 1 21.5 18a2 2 0 0 1-2 1.96A2 2 0 0 1 17.46 18a2 2 0 0 1 2.02-1.96zM42.48 34.5a16.5 16.5 0 1 0 0-33 16.5 16.5 0 0 0 0 33zm0 1.5a18 18 0 1 0 0-36 18 18 0 0 0 0 36z'
|
||||||
}
|
}
|
||||||
fill={'#fff'}
|
fill={'#fff'}
|
||||||
fillRule={'evenodd'}
|
fillRule={'evenodd'}
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
export default SvgComponent
|
export default SvgComponent
|
||||||
|
|||||||
@@ -1,35 +1,21 @@
|
|||||||
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
import { SVGProps, Ref, forwardRef, memo } from "react"
|
||||||
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
const SvgComponent = (
|
||||||
<svg
|
props: SVGProps<SVGSVGElement>,
|
||||||
fill={'none'}
|
ref: Ref<SVGSVGElement>
|
||||||
height={'16'}
|
) => (
|
||||||
ref={ref}
|
<svg
|
||||||
viewBox={'0 0 16 16'}
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width={'16'}
|
width={24}
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
height={24}
|
||||||
{...props}
|
fill="none"
|
||||||
>
|
ref={ref}
|
||||||
<g clipPath={'url(#clip0_6627_107)'}>
|
{...props}
|
||||||
<path
|
>
|
||||||
d={
|
<g fill="#000" clipPath="url(#a)">
|
||||||
'M4.66663 3.99996C4.84344 3.99996 5.01301 3.92972 5.13803 3.8047C5.26305 3.67967 5.33329 3.5101 5.33329 3.33329C5.33329 3.15648 5.26305 2.98691 5.13803 2.86189C5.01301 2.73686 4.84344 2.66663 4.66663 2.66663H3.33329C3.15648 2.66663 2.98691 2.73686 2.86189 2.86189C2.73686 2.98691 2.66663 3.15648 2.66663 3.33329V12.6666C2.66663 12.8434 2.73686 13.013 2.86189 13.138C2.98691 13.2631 3.15648 13.3333 3.33329 13.3333H4.66663C4.84344 13.3333 5.01301 13.2631 5.13803 13.138C5.26305 13.013 5.33329 12.8434 5.33329 12.6666C5.33329 12.4898 5.26305 12.3202 5.13803 12.1952C5.01301 12.0702 4.84344 12 4.66663 12H3.99996V3.99996H4.66663Z'
|
<path d="M7 6a1 1 0 0 0 0-2H5a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1h2a1 1 0 0 0 0-2H6V6h1Zm13.82 5.42-2.82-4a1 1 0 1 0-1.63 1.16L18.09 11H10a1 1 0 0 0 0 2h8l-1.8 2.4a1 1 0 0 0 1.6 1.2l3-4a1 1 0 0 0 .02-1.18Z" />
|
||||||
}
|
</g>
|
||||||
fill={'white'}
|
</svg>
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d={
|
|
||||||
'M13.88 7.61338L12 4.94672C11.898 4.80299 11.7433 4.70548 11.5697 4.67549C11.396 4.64551 11.2176 4.6855 11.0733 4.78672C11.0012 4.83724 10.9399 4.90154 10.8927 4.97592C10.8456 5.05029 10.8137 5.13326 10.7988 5.22004C10.784 5.30681 10.7864 5.39568 10.8061 5.4815C10.8257 5.56732 10.8622 5.64839 10.9133 5.72005L12.06 7.33338H6.66667C6.48986 7.33338 6.32029 7.40362 6.19526 7.52864C6.07024 7.65367 6 7.82324 6 8.00005C6 8.17686 6.07024 8.34643 6.19526 8.47145C6.32029 8.59648 6.48986 8.66672 6.66667 8.66672H12L10.8 10.2667C10.7475 10.3368 10.7093 10.4165 10.6875 10.5013C10.6658 10.5861 10.661 10.6743 10.6734 10.761C10.6857 10.8477 10.7151 10.931 10.7597 11.0064C10.8043 11.0817 10.8633 11.1475 10.9333 11.2C11.0487 11.2866 11.1891 11.3334 11.3333 11.3334C11.4368 11.3334 11.5389 11.3093 11.6315 11.263C11.724 11.2167 11.8046 11.1495 11.8667 11.0667L13.8667 8.40005C13.952 8.28729 13.9994 8.15031 14.0018 8.00889C14.0041 7.86748 13.9615 7.72897 13.88 7.61338Z'
|
|
||||||
}
|
|
||||||
fill={'white'}
|
|
||||||
/>
|
|
||||||
</g>
|
|
||||||
<defs>
|
|
||||||
<clipPath id={'clip0_6627_107'}>
|
|
||||||
<rect fill={'white'} height={'16'} width={'16'} />
|
|
||||||
</clipPath>
|
|
||||||
</defs>
|
|
||||||
</svg>
|
|
||||||
)
|
)
|
||||||
const ForwardRef = forwardRef(SvgComponent)
|
const ForwardRef = forwardRef(SvgComponent)
|
||||||
|
const Memo = memo(ForwardRef)
|
||||||
export default memo(ForwardRef)
|
export default Memo
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
import { SVGProps } from 'react'
|
import { SVGProps } from 'react'
|
||||||
const SvgComponent = (props: SVGProps<SVGSVGElement>) => (
|
const SvgComponent = (props: SVGProps<SVGSVGElement>) => (
|
||||||
<svg
|
<svg
|
||||||
fill={'none'}
|
fill={'none'}
|
||||||
height={16}
|
height={16}
|
||||||
viewBox={'0 0 16 16'}
|
viewBox={'0 0 16 16'}
|
||||||
width={16}
|
width={16}
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
xmlns={'http://www.w3.org/2000/svg'}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<g clipPath={'url(#clip0_6693_1154)'} fill={'#fff'}>
|
<g clipPath={'url(#clip0_6693_1154)'} fill={'#fff'}>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M8 7.334a2.667 2.667 0 1 0 0-5.333 2.667 2.667 0 0 0 0 5.334zm0-4a1.333 1.333 0 1 1 0 2.667 1.333 1.333 0 0 1 0-2.666zM8 8.668a4.667 4.667 0 0 0-4.667 4.666.667.667 0 1 0 1.334 0 3.333 3.333 0 0 1 6.666 0 .667.667 0 1 0 1.334 0A4.667 4.667 0 0 0 8 8.668z'
|
'M8 7.334a2.667 2.667 0 1 0 0-5.333 2.667 2.667 0 0 0 0 5.334zm0-4a1.333 1.333 0 1 1 0 2.667 1.333 1.333 0 0 1 0-2.666zM8 8.668a4.667 4.667 0 0 0-4.667 4.666.667.667 0 1 0 1.334 0 3.333 3.333 0 0 1 6.666 0 .667.667 0 1 0 1.334 0A4.667 4.667 0 0 0 8 8.668z'
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</g>
|
</g>
|
||||||
<defs>
|
<defs>
|
||||||
<clipPath id={'clip0_6693_1154'}>
|
<clipPath id={'clip0_6693_1154'}>
|
||||||
<path d={'M0 0h16v16H0z'} fill={'#fff'} />
|
<path d={'M0 0h16v16H0z'} fill={'#fff'} />
|
||||||
</clipPath>
|
</clipPath>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
export default SvgComponent
|
export default SvgComponent
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
import { SVGProps } from 'react'
|
import { SVGProps } from 'react'
|
||||||
const SvgComponent = (props: SVGProps<SVGSVGElement>) => (
|
const SvgComponent = (props: SVGProps<SVGSVGElement>) => (
|
||||||
<svg
|
<svg
|
||||||
fill={'none'}
|
fill={'none'}
|
||||||
height={'16'}
|
height={'16'}
|
||||||
viewBox={'0 0 16 16'}
|
viewBox={'0 0 16 16'}
|
||||||
width={'16'}
|
width={'16'}
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
xmlns={'http://www.w3.org/2000/svg'}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<g clipPath={'url(#clip0_28366_3435)'}>
|
<g clipPath={'url(#clip0_28366_3435)'}>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M8.00004 1.33337C6.6815 1.33337 5.39257 1.72437 4.29624 2.45691C3.19991 3.18945 2.34543 4.23064 1.84085 5.44882C1.33626 6.66699 1.20424 8.00744 1.46148 9.30064C1.71871 10.5938 2.35365 11.7817 3.286 12.7141C4.21835 13.6464 5.40624 14.2814 6.69944 14.5386C7.99265 14.7958 9.33309 14.6638 10.5513 14.1592C11.7694 13.6547 12.8106 12.8002 13.5432 11.7038C14.2757 10.6075 14.6667 9.31858 14.6667 8.00004C14.6667 7.12456 14.4943 6.25766 14.1592 5.44882C13.8242 4.63998 13.3331 3.90505 12.7141 3.286C12.095 2.66694 11.3601 2.17588 10.5513 1.84084C9.74243 1.50581 8.87552 1.33337 8.00004 1.33337ZM8.00004 13.3334C6.94521 13.3334 5.91406 13.0206 5.037 12.4345C4.15994 11.8485 3.47635 11.0156 3.07269 10.041C2.66902 9.06648 2.5634 7.99412 2.76919 6.95956C2.97498 5.92499 3.48293 4.97468 4.22881 4.2288C4.97469 3.48292 5.925 2.97497 6.95956 2.76919C7.99413 2.5634 9.06648 2.66902 10.041 3.07268C11.0156 3.47635 11.8485 4.15994 12.4345 5.037C13.0206 5.91406 13.3334 6.94521 13.3334 8.00004C13.3334 9.41453 12.7715 10.7711 11.7713 11.7713C10.7711 12.7715 9.41453 13.3334 8.00004 13.3334Z'
|
'M8.00004 1.33337C6.6815 1.33337 5.39257 1.72437 4.29624 2.45691C3.19991 3.18945 2.34543 4.23064 1.84085 5.44882C1.33626 6.66699 1.20424 8.00744 1.46148 9.30064C1.71871 10.5938 2.35365 11.7817 3.286 12.7141C4.21835 13.6464 5.40624 14.2814 6.69944 14.5386C7.99265 14.7958 9.33309 14.6638 10.5513 14.1592C11.7694 13.6547 12.8106 12.8002 13.5432 11.7038C14.2757 10.6075 14.6667 9.31858 14.6667 8.00004C14.6667 7.12456 14.4943 6.25766 14.1592 5.44882C13.8242 4.63998 13.3331 3.90505 12.7141 3.286C12.095 2.66694 11.3601 2.17588 10.5513 1.84084C9.74243 1.50581 8.87552 1.33337 8.00004 1.33337ZM8.00004 13.3334C6.94521 13.3334 5.91406 13.0206 5.037 12.4345C4.15994 11.8485 3.47635 11.0156 3.07269 10.041C2.66902 9.06648 2.5634 7.99412 2.76919 6.95956C2.97498 5.92499 3.48293 4.97468 4.22881 4.2288C4.97469 3.48292 5.925 2.97497 6.95956 2.76919C7.99413 2.5634 9.06648 2.66902 10.041 3.07268C11.0156 3.47635 11.8485 4.15994 12.4345 5.037C13.0206 5.91406 13.3334 6.94521 13.3334 8.00004C13.3334 9.41453 12.7715 10.7711 11.7713 11.7713C10.7711 12.7715 9.41453 13.3334 8.00004 13.3334Z'
|
||||||
}
|
}
|
||||||
fill={'white'}
|
fill={'white'}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M8.22666 4.96667C8.06331 4.81613 7.85932 4.71692 7.64004 4.68136C7.42077 4.6458 7.19588 4.67547 6.99333 4.76667C6.7967 4.84621 6.62825 4.98257 6.5095 5.15832C6.39075 5.33407 6.32709 5.54123 6.32666 5.75334V10.2467C6.32709 10.4588 6.39075 10.6659 6.5095 10.8417C6.62825 11.0174 6.7967 11.1538 6.99333 11.2333C7.13784 11.2989 7.29464 11.333 7.45333 11.3333C7.73927 11.3321 8.01467 11.2252 8.22666 11.0333L10.6667 8.78667C10.7758 8.68674 10.8629 8.56519 10.9226 8.42976C10.9822 8.29433 11.013 8.14798 11.013 8C11.013 7.85203 10.9822 7.70568 10.9226 7.57025C10.8629 7.43482 10.7758 7.31327 10.6667 7.21334L8.22666 4.96667ZM7.66666 9.73334V6.26667L9.53999 8L7.66666 9.73334Z'
|
'M8.22666 4.96667C8.06331 4.81613 7.85932 4.71692 7.64004 4.68136C7.42077 4.6458 7.19588 4.67547 6.99333 4.76667C6.7967 4.84621 6.62825 4.98257 6.5095 5.15832C6.39075 5.33407 6.32709 5.54123 6.32666 5.75334V10.2467C6.32709 10.4588 6.39075 10.6659 6.5095 10.8417C6.62825 11.0174 6.7967 11.1538 6.99333 11.2333C7.13784 11.2989 7.29464 11.333 7.45333 11.3333C7.73927 11.3321 8.01467 11.2252 8.22666 11.0333L10.6667 8.78667C10.7758 8.68674 10.8629 8.56519 10.9226 8.42976C10.9822 8.29433 11.013 8.14798 11.013 8C11.013 7.85203 10.9822 7.70568 10.9226 7.57025C10.8629 7.43482 10.7758 7.31327 10.6667 7.21334L8.22666 4.96667ZM7.66666 9.73334V6.26667L9.53999 8L7.66666 9.73334Z'
|
||||||
}
|
}
|
||||||
fill={'white'}
|
fill={'white'}
|
||||||
/>
|
/>
|
||||||
</g>
|
</g>
|
||||||
<defs>
|
<defs>
|
||||||
<clipPath id={'clip0_28366_3435'}>
|
<clipPath id={'clip0_28366_3435'}>
|
||||||
<rect fill={'white'} height={'16'} width={'16'} />
|
<rect fill={'white'} height={'16'} width={'16'} />
|
||||||
</clipPath>
|
</clipPath>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
export default SvgComponent
|
export default SvgComponent
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
||||||
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
||||||
<svg
|
<svg
|
||||||
fill={'none'}
|
fill={'none'}
|
||||||
height={20}
|
height={20}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
viewBox={'0 0 20 20'}
|
viewBox={'0 0 20 20'}
|
||||||
width={20}
|
width={20}
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
xmlns={'http://www.w3.org/2000/svg'}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<g clipPath={'url(#clip0_21547_180)'}>
|
<g clipPath={'url(#clip0_21547_180)'}>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M17.2583 16.075L14.425 13.25C15.3392 12.0854 15.8352 10.6472 15.8333 9.16667C15.8333 7.84813 15.4423 6.5592 14.7098 5.46287C13.9773 4.36654 12.9361 3.51206 11.7179 3.00747C10.4997 2.50289 9.15927 2.37087 7.86607 2.6281C6.57286 2.88534 5.38497 3.52027 4.45262 4.45262C3.52027 5.38497 2.88534 6.57286 2.6281 7.86607C2.37087 9.15927 2.50289 10.4997 3.00747 11.7179C3.51206 12.9361 4.36654 13.9773 5.46287 14.7098C6.5592 15.4423 7.84813 15.8333 9.16667 15.8333C10.6472 15.8352 12.0854 15.3392 13.25 14.425L16.075 17.2583C16.1525 17.3364 16.2446 17.3984 16.3462 17.4407C16.4477 17.4831 16.5567 17.5048 16.6667 17.5048C16.7767 17.5048 16.8856 17.4831 16.9871 17.4407C17.0887 17.3984 17.1809 17.3364 17.2583 17.2583C17.3364 17.1809 17.3984 17.0887 17.4407 16.9871C17.4831 16.8856 17.5048 16.7767 17.5048 16.6667C17.5048 16.5567 17.4831 16.4477 17.4407 16.3462C17.3984 16.2446 17.3364 16.1525 17.2583 16.075ZM4.16667 9.16667C4.16667 8.17776 4.45991 7.21106 5.00932 6.38882C5.55873 5.56657 6.33962 4.92571 7.25325 4.54727C8.16688 4.16883 9.17222 4.06982 10.1421 4.26274C11.112 4.45567 12.0029 4.93187 12.7022 5.63114C13.4015 6.3304 13.8777 7.22131 14.0706 8.19122C14.2635 9.16112 14.1645 10.1665 13.7861 11.0801C13.4076 11.9937 12.7668 12.7746 11.9445 13.324C11.1223 13.8734 10.1556 14.1667 9.16667 14.1667C7.84059 14.1667 6.56882 13.6399 5.63114 12.7022C4.69345 11.7645 4.16667 10.4928 4.16667 9.16667Z'
|
'M17.2583 16.075L14.425 13.25C15.3392 12.0854 15.8352 10.6472 15.8333 9.16667C15.8333 7.84813 15.4423 6.5592 14.7098 5.46287C13.9773 4.36654 12.9361 3.51206 11.7179 3.00747C10.4997 2.50289 9.15927 2.37087 7.86607 2.6281C6.57286 2.88534 5.38497 3.52027 4.45262 4.45262C3.52027 5.38497 2.88534 6.57286 2.6281 7.86607C2.37087 9.15927 2.50289 10.4997 3.00747 11.7179C3.51206 12.9361 4.36654 13.9773 5.46287 14.7098C6.5592 15.4423 7.84813 15.8333 9.16667 15.8333C10.6472 15.8352 12.0854 15.3392 13.25 14.425L16.075 17.2583C16.1525 17.3364 16.2446 17.3984 16.3462 17.4407C16.4477 17.4831 16.5567 17.5048 16.6667 17.5048C16.7767 17.5048 16.8856 17.4831 16.9871 17.4407C17.0887 17.3984 17.1809 17.3364 17.2583 17.2583C17.3364 17.1809 17.3984 17.0887 17.4407 16.9871C17.4831 16.8856 17.5048 16.7767 17.5048 16.6667C17.5048 16.5567 17.4831 16.4477 17.4407 16.3462C17.3984 16.2446 17.3364 16.1525 17.2583 16.075ZM4.16667 9.16667C4.16667 8.17776 4.45991 7.21106 5.00932 6.38882C5.55873 5.56657 6.33962 4.92571 7.25325 4.54727C8.16688 4.16883 9.17222 4.06982 10.1421 4.26274C11.112 4.45567 12.0029 4.93187 12.7022 5.63114C13.4015 6.3304 13.8777 7.22131 14.0706 8.19122C14.2635 9.16112 14.1645 10.1665 13.7861 11.0801C13.4076 11.9937 12.7668 12.7746 11.9445 13.324C11.1223 13.8734 10.1556 14.1667 9.16667 14.1667C7.84059 14.1667 6.56882 13.6399 5.63114 12.7022C4.69345 11.7645 4.16667 10.4928 4.16667 9.16667Z'
|
||||||
}
|
}
|
||||||
fill={'#808080'}
|
fill={'#808080'}
|
||||||
/>
|
/>
|
||||||
</g>
|
</g>
|
||||||
<defs>
|
<defs>
|
||||||
<clipPath id={'clip0_21547_180'}>
|
<clipPath id={'clip0_21547_180'}>
|
||||||
<rect fill={'white'} height={20} width={20} />
|
<rect fill={'white'} height={20} width={20} />
|
||||||
</clipPath>
|
</clipPath>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
export default memo(forwardRef(SvgComponent))
|
export default memo(forwardRef(SvgComponent))
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
import { SVGProps } from 'react'
|
import { SVGProps } from 'react'
|
||||||
const SvgComponent = (props: SVGProps<SVGSVGElement>) => (
|
const SvgComponent = (props: SVGProps<SVGSVGElement>) => (
|
||||||
<svg
|
<svg
|
||||||
fill={'none'}
|
fill={'none'}
|
||||||
height={'16'}
|
height={'16'}
|
||||||
viewBox={'0 0 16 16'}
|
viewBox={'0 0 16 16'}
|
||||||
width={'16'}
|
width={'16'}
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
xmlns={'http://www.w3.org/2000/svg'}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<g clipPath={'url(#clip0_28366_3245)'}>
|
<g clipPath={'url(#clip0_28366_3245)'}>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M14 3.99998H10.6667V2.88665C10.6511 2.45986 10.4668 2.05669 10.1544 1.76551C9.842 1.47433 9.42687 1.31891 9.00004 1.33332H7.00004C6.57321 1.31891 6.15808 1.47433 5.84566 1.76551C5.53324 2.05669 5.34901 2.45986 5.33337 2.88665V3.99998H2.00004C1.82323 3.99998 1.65366 4.07022 1.52864 4.19525C1.40361 4.32027 1.33337 4.48984 1.33337 4.66665C1.33337 4.84346 1.40361 5.01303 1.52864 5.13805C1.65366 5.26308 1.82323 5.33332 2.00004 5.33332H2.66671V12.6666C2.66671 13.1971 2.87742 13.7058 3.25249 14.0809C3.62757 14.4559 4.13627 14.6666 4.66671 14.6666H11.3334C11.8638 14.6666 12.3725 14.4559 12.7476 14.0809C13.1227 13.7058 13.3334 13.1971 13.3334 12.6666V5.33332H14C14.1769 5.33332 14.3464 5.26308 14.4714 5.13805C14.5965 5.01303 14.6667 4.84346 14.6667 4.66665C14.6667 4.48984 14.5965 4.32027 14.4714 4.19525C14.3464 4.07022 14.1769 3.99998 14 3.99998ZM6.66671 2.88665C6.66671 2.77998 6.80671 2.66665 7.00004 2.66665H9.00004C9.19337 2.66665 9.33337 2.77998 9.33337 2.88665V3.99998H6.66671V2.88665ZM12 12.6666C12 12.8435 11.9298 13.013 11.8048 13.1381C11.6798 13.2631 11.5102 13.3333 11.3334 13.3333H4.66671C4.4899 13.3333 4.32033 13.2631 4.1953 13.1381C4.07028 13.013 4.00004 12.8435 4.00004 12.6666V5.33332H12V12.6666Z'
|
'M14 3.99998H10.6667V2.88665C10.6511 2.45986 10.4668 2.05669 10.1544 1.76551C9.842 1.47433 9.42687 1.31891 9.00004 1.33332H7.00004C6.57321 1.31891 6.15808 1.47433 5.84566 1.76551C5.53324 2.05669 5.34901 2.45986 5.33337 2.88665V3.99998H2.00004C1.82323 3.99998 1.65366 4.07022 1.52864 4.19525C1.40361 4.32027 1.33337 4.48984 1.33337 4.66665C1.33337 4.84346 1.40361 5.01303 1.52864 5.13805C1.65366 5.26308 1.82323 5.33332 2.00004 5.33332H2.66671V12.6666C2.66671 13.1971 2.87742 13.7058 3.25249 14.0809C3.62757 14.4559 4.13627 14.6666 4.66671 14.6666H11.3334C11.8638 14.6666 12.3725 14.4559 12.7476 14.0809C13.1227 13.7058 13.3334 13.1971 13.3334 12.6666V5.33332H14C14.1769 5.33332 14.3464 5.26308 14.4714 5.13805C14.5965 5.01303 14.6667 4.84346 14.6667 4.66665C14.6667 4.48984 14.5965 4.32027 14.4714 4.19525C14.3464 4.07022 14.1769 3.99998 14 3.99998ZM6.66671 2.88665C6.66671 2.77998 6.80671 2.66665 7.00004 2.66665H9.00004C9.19337 2.66665 9.33337 2.77998 9.33337 2.88665V3.99998H6.66671V2.88665ZM12 12.6666C12 12.8435 11.9298 13.013 11.8048 13.1381C11.6798 13.2631 11.5102 13.3333 11.3334 13.3333H4.66671C4.4899 13.3333 4.32033 13.2631 4.1953 13.1381C4.07028 13.013 4.00004 12.8435 4.00004 12.6666V5.33332H12V12.6666Z'
|
||||||
}
|
}
|
||||||
fill={'white'}
|
fill={'white'}
|
||||||
/>
|
/>
|
||||||
</g>
|
</g>
|
||||||
<defs>
|
<defs>
|
||||||
<clipPath id={'clip0_28366_3245'}>
|
<clipPath id={'clip0_28366_3245'}>
|
||||||
<rect fill={'white'} height={'16'} width={'16'} />
|
<rect fill={'white'} height={'16'} width={'16'} />
|
||||||
</clipPath>
|
</clipPath>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
export default SvgComponent
|
export default SvgComponent
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
import { Ref, SVGProps, forwardRef, memo } from 'react'
|
||||||
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
||||||
<svg
|
<svg
|
||||||
fill={'none'}
|
fill={'none'}
|
||||||
height={20}
|
height={20}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
viewBox={'0 0 24 24'}
|
viewBox={'0 0 24 24'}
|
||||||
width={20}
|
width={20}
|
||||||
xmlns={'http://www.w3.org/2000/svg'}
|
xmlns={'http://www.w3.org/2000/svg'}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d={
|
d={
|
||||||
'M12 5.975a9.77 9.77 0 0 1 8.82 5.5 9.647 9.647 0 0 1-2.41 3.12l1.41 1.41c1.39-1.23 2.49-2.77 3.18-4.53-1.73-4.39-6-7.5-11-7.5-1.27 0-2.49.2-3.64.57l1.65 1.65c.65-.13 1.31-.22 1.99-.22zm-1.07 1.14L13 9.185c.57.25 1.03.71 1.28 1.28l2.07 2.07c.08-.34.14-.7.14-1.07.01-2.48-2.01-4.49-4.49-4.49-.37 0-.72.05-1.07.14zm-8.92-3.27l2.68 2.68A11.738 11.738 0 0 0 1 11.475c1.73 4.39 6 7.5 11 7.5 1.52 0 2.98-.29 4.32-.82l3.42 3.42 1.41-1.41L3.42 2.425l-1.41 1.42zm7.5 7.5l2.61 2.61c-.04.01-.08.02-.12.02a2.5 2.5 0 0 1-2.5-2.5c0-.05.01-.08.01-.13zm-3.4-3.4l1.75 1.75a4.6 4.6 0 0 0-.36 1.78 4.507 4.507 0 0 0 6.27 4.14l.98.98c-.88.24-1.8.38-2.75.38a9.77 9.77 0 0 1-8.82-5.5c.7-1.43 1.72-2.61 2.93-3.53z'
|
'M12 5.975a9.77 9.77 0 0 1 8.82 5.5 9.647 9.647 0 0 1-2.41 3.12l1.41 1.41c1.39-1.23 2.49-2.77 3.18-4.53-1.73-4.39-6-7.5-11-7.5-1.27 0-2.49.2-3.64.57l1.65 1.65c.65-.13 1.31-.22 1.99-.22zm-1.07 1.14L13 9.185c.57.25 1.03.71 1.28 1.28l2.07 2.07c.08-.34.14-.7.14-1.07.01-2.48-2.01-4.49-4.49-4.49-.37 0-.72.05-1.07.14zm-8.92-3.27l2.68 2.68A11.738 11.738 0 0 0 1 11.475c1.73 4.39 6 7.5 11 7.5 1.52 0 2.98-.29 4.32-.82l3.42 3.42 1.41-1.41L3.42 2.425l-1.41 1.42zm7.5 7.5l2.61 2.61c-.04.01-.08.02-.12.02a2.5 2.5 0 0 1-2.5-2.5c0-.05.01-.08.01-.13zm-3.4-3.4l1.75 1.75a4.6 4.6 0 0 0-.36 1.78 4.507 4.507 0 0 0 6.27 4.14l.98.98c-.88.24-1.8.38-2.75.38a9.77 9.77 0 0 1-8.82-5.5c.7-1.43 1.72-2.61 2.93-3.53z'
|
||||||
}
|
}
|
||||||
fill={'#fff'}
|
fill={'#fff'}
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
const ForwardRef = forwardRef(SvgComponent)
|
const ForwardRef = forwardRef(SvgComponent)
|
||||||
|
|
||||||
|
|||||||
@@ -3,16 +3,16 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||||||
import { CheckEmail } from './'
|
import { CheckEmail } from './'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
component: CheckEmail,
|
component: CheckEmail,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
title: 'Auth/Check email',
|
title: 'Auth/Check email',
|
||||||
} satisfies Meta<typeof CheckEmail>
|
} satisfies Meta<typeof CheckEmail>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
type Story = StoryObj<typeof meta>
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
email: 'your_email@domain.com',
|
email: 'your_email@domain.com',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,26 +6,26 @@ import { Button, Card, Typography } from '../../ui'
|
|||||||
import s from './check-email.module.scss'
|
import s from './check-email.module.scss'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
email: string
|
email: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CheckEmail = ({ email }: Props) => {
|
export const CheckEmail = ({ email }: Props) => {
|
||||||
const message = `We've sent an e-mail with instructions to ${email}`
|
const message = `We've sent an e-mail with instructions to ${email}`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className={s.card}>
|
<Card className={s.card}>
|
||||||
<Typography className={s.title} variant={'large'}>
|
<Typography className={s.title} variant={'large'}>
|
||||||
Check your email
|
Check your email
|
||||||
</Typography>
|
</Typography>
|
||||||
<div className={s.iconContainer}>
|
<div className={s.iconContainer}>
|
||||||
<Email />
|
<Email />
|
||||||
</div>
|
</div>
|
||||||
<Typography className={s.instructions} variant={'body2'}>
|
<Typography className={s.instructions} variant={'body2'}>
|
||||||
{message}
|
{message}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Button as={Link} fullWidth to={'/sing-in'}>
|
<Button as={Link} fullWidth to={'/sing-in'}>
|
||||||
Back to Sign in
|
Back to Sign in
|
||||||
</Button>
|
</Button>
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,16 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||||||
import { NewPassword } from './'
|
import { NewPassword } from './'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
component: NewPassword,
|
component: NewPassword,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
title: 'Auth/New password',
|
title: 'Auth/New password',
|
||||||
} satisfies Meta<typeof NewPassword>
|
} satisfies Meta<typeof NewPassword>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
type Story = StoryObj<typeof meta>
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
onSubmit: data => console.info(data),
|
onSubmit: data => console.info(data),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,48 +8,48 @@ import { z } from 'zod'
|
|||||||
import s from './new-password.module.scss'
|
import s from './new-password.module.scss'
|
||||||
|
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
password: z.string().nonempty('Enter password'),
|
password: z.string().nonempty('Enter password'),
|
||||||
})
|
})
|
||||||
|
|
||||||
type FormType = z.infer<typeof schema>
|
type FormType = z.infer<typeof schema>
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onSubmit: (data: FormType) => void
|
onSubmit: (data: FormType) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NewPassword = (props: Props) => {
|
export const NewPassword = (props: Props) => {
|
||||||
const { control, handleSubmit } = useForm<FormType>({
|
const { control, handleSubmit } = useForm<FormType>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
password: '',
|
password: '',
|
||||||
},
|
},
|
||||||
resolver: zodResolver(schema),
|
resolver: zodResolver(schema),
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleFormSubmitted = handleSubmit(props.onSubmit)
|
const handleFormSubmitted = handleSubmit(props.onSubmit)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DevTool control={control} />
|
<DevTool control={control} />
|
||||||
<Card className={s.card}>
|
<Card className={s.card}>
|
||||||
<Typography className={s.title} variant={'large'}>
|
<Typography className={s.title} variant={'large'}>
|
||||||
Create new password
|
Create new password
|
||||||
</Typography>
|
</Typography>
|
||||||
<form onSubmit={handleFormSubmitted}>
|
<form onSubmit={handleFormSubmitted}>
|
||||||
<ControlledTextField
|
<ControlledTextField
|
||||||
containerProps={{ className: s.input }}
|
containerProps={{ className: s.input }}
|
||||||
control={control}
|
control={control}
|
||||||
name={'password'}
|
name={'password'}
|
||||||
placeholder={'Password'}
|
placeholder={'Password'}
|
||||||
type={'password'}
|
type={'password'}
|
||||||
/>
|
/>
|
||||||
<Typography className={s.instructions} variant={'caption'}>
|
<Typography className={s.instructions} variant={'caption'}>
|
||||||
Create new password and we will send you further instructions to email
|
Create new password and we will send you further instructions to email
|
||||||
</Typography>
|
</Typography>
|
||||||
<Button fullWidth type={'submit'}>
|
<Button fullWidth type={'submit'}>
|
||||||
Create new password
|
Create new password
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
</Card>
|
</Card>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,16 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||||||
import { RecoverPassword } from './'
|
import { RecoverPassword } from './'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
component: RecoverPassword,
|
component: RecoverPassword,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
title: 'Auth/Recover password',
|
title: 'Auth/Recover password',
|
||||||
} satisfies Meta<typeof RecoverPassword>
|
} satisfies Meta<typeof RecoverPassword>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
type Story = StoryObj<typeof meta>
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
onSubmit: data => console.info(data),
|
onSubmit: data => console.info(data),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,51 +9,55 @@ import { z } from 'zod'
|
|||||||
import s from './recover-password.module.scss'
|
import s from './recover-password.module.scss'
|
||||||
|
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
email: z.string().email('Invalid email address').nonempty('Enter email'),
|
email: z.string().email('Invalid email address').nonempty('Enter email'),
|
||||||
})
|
})
|
||||||
|
|
||||||
type FormType = z.infer<typeof schema>
|
type FormType = z.infer<typeof schema>
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onSubmit: (data: FormType) => void
|
onSubmit: (data: FormType) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RecoverPassword = (props: Props) => {
|
export const RecoverPassword = (props: Props) => {
|
||||||
const { control, handleSubmit } = useForm<FormType>({
|
const { control, handleSubmit } = useForm<FormType>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
email: '',
|
email: '',
|
||||||
},
|
},
|
||||||
mode: 'onSubmit',
|
mode: 'onSubmit',
|
||||||
resolver: zodResolver(schema),
|
resolver: zodResolver(schema),
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleFormSubmitted = handleSubmit(props.onSubmit)
|
const handleFormSubmitted = handleSubmit(props.onSubmit)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DevTool control={control} />
|
<DevTool control={control} />
|
||||||
<Card className={s.card}>
|
<Card className={s.card}>
|
||||||
<Typography className={s.title} variant={'large'}>
|
<Typography className={s.title} variant={'large'}>
|
||||||
Forgot your password?
|
Forgot your password?
|
||||||
</Typography>
|
</Typography>
|
||||||
<form onSubmit={handleFormSubmitted}>
|
<form onSubmit={handleFormSubmitted}>
|
||||||
<div className={s.form}>
|
<div className={s.form}>
|
||||||
<ControlledTextField control={control} name={'email'} placeholder={'Email'} />
|
<ControlledTextField
|
||||||
</div>
|
control={control}
|
||||||
<Typography className={s.instructions} variant={'body2'}>
|
name={'email'}
|
||||||
Enter your email address and we will send you further instructions
|
placeholder={'Email'}
|
||||||
</Typography>
|
/>
|
||||||
<Button className={s.button} fullWidth type={'submit'}>
|
</div>
|
||||||
Send Instructions
|
<Typography className={s.instructions} variant={'body2'}>
|
||||||
</Button>
|
Enter your email address and we will send you further instructions
|
||||||
</form>
|
</Typography>
|
||||||
<Typography className={s.caption} variant={'body2'}>
|
<Button className={s.button} fullWidth type={'submit'}>
|
||||||
Did you remember your password?
|
Send Instructions
|
||||||
</Typography>
|
</Button>
|
||||||
<Typography as={Link} className={s.loginLink} to={'/sign-in'} variant={'link1'}>
|
</form>
|
||||||
Try logging in
|
<Typography className={s.caption} variant={'body2'}>
|
||||||
</Typography>
|
Did you remember your password?
|
||||||
</Card>
|
</Typography>
|
||||||
</>
|
<Typography as={Link} className={s.loginLink} to={'/sign-in'} variant={'link1'}>
|
||||||
)
|
Try logging in
|
||||||
|
</Typography>
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,16 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||||||
import { SignIn } from './'
|
import { SignIn } from './'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
component: SignIn,
|
component: SignIn,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
title: 'Auth/Sign in',
|
title: 'Auth/Sign in',
|
||||||
} satisfies Meta<typeof SignIn>
|
} satisfies Meta<typeof SignIn>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
type Story = StoryObj<typeof meta>
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
onSubmit: data => console.info(data),
|
onSubmit: data => console.info(data),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,79 +9,79 @@ import { z } from 'zod'
|
|||||||
import s from './sign-in.module.scss'
|
import s from './sign-in.module.scss'
|
||||||
|
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
email: z.string().email('Invalid email address').nonempty('Enter email'),
|
email: z.string().email('Invalid email address').nonempty('Enter email'),
|
||||||
password: z.string().nonempty('Enter password'),
|
password: z.string().nonempty('Enter password'),
|
||||||
rememberMe: z.boolean().optional(),
|
rememberMe: z.boolean().optional(),
|
||||||
})
|
})
|
||||||
|
|
||||||
type FormType = z.infer<typeof schema>
|
type FormType = z.infer<typeof schema>
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onSubmit: (data: FormType) => void
|
onSubmit: (data: FormType) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SignIn = (props: Props) => {
|
export const SignIn = (props: Props) => {
|
||||||
const { control, handleSubmit } = useForm<FormType>({
|
const { control, handleSubmit } = useForm<FormType>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
email: '',
|
email: '',
|
||||||
password: '',
|
password: '',
|
||||||
rememberMe: false,
|
rememberMe: false,
|
||||||
},
|
},
|
||||||
mode: 'onSubmit',
|
mode: 'onSubmit',
|
||||||
resolver: zodResolver(schema),
|
resolver: zodResolver(schema),
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleFormSubmitted = handleSubmit(props.onSubmit)
|
const handleFormSubmitted = handleSubmit(props.onSubmit)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DevTool control={control} />
|
<DevTool control={control} />
|
||||||
<Card className={s.card}>
|
<Card className={s.card}>
|
||||||
<Typography className={s.title} variant={'large'}>
|
<Typography className={s.title} variant={'large'}>
|
||||||
Sign In
|
Sign In
|
||||||
</Typography>
|
</Typography>
|
||||||
<form onSubmit={handleFormSubmitted}>
|
<form onSubmit={handleFormSubmitted}>
|
||||||
<div className={s.form}>
|
<div className={s.form}>
|
||||||
<ControlledTextField
|
<ControlledTextField
|
||||||
control={control}
|
control={control}
|
||||||
label={'Email'}
|
label={'Email'}
|
||||||
name={'email'}
|
name={'email'}
|
||||||
placeholder={'Email'}
|
placeholder={'Email'}
|
||||||
/>
|
/>
|
||||||
<ControlledTextField
|
<ControlledTextField
|
||||||
control={control}
|
control={control}
|
||||||
label={'Password'}
|
label={'Password'}
|
||||||
name={'password'}
|
name={'password'}
|
||||||
placeholder={'Password'}
|
placeholder={'Password'}
|
||||||
type={'password'}
|
type={'password'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ControlledCheckbox
|
<ControlledCheckbox
|
||||||
className={s.checkbox}
|
className={s.checkbox}
|
||||||
control={control}
|
control={control}
|
||||||
label={'Remember me'}
|
label={'Remember me'}
|
||||||
name={'rememberMe'}
|
name={'rememberMe'}
|
||||||
position={'left'}
|
position={'left'}
|
||||||
/>
|
/>
|
||||||
<Typography
|
<Typography
|
||||||
as={Link}
|
as={Link}
|
||||||
className={s.recoverPasswordLink}
|
className={s.recoverPasswordLink}
|
||||||
to={'/recover-password'}
|
to={'/recover-password'}
|
||||||
variant={'body2'}
|
variant={'body2'}
|
||||||
>
|
>
|
||||||
Forgot Password?
|
Forgot Password?
|
||||||
</Typography>
|
</Typography>
|
||||||
<Button className={s.button} fullWidth type={'submit'}>
|
<Button className={s.button} fullWidth type={'submit'}>
|
||||||
Sign In
|
Sign In
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
<Typography className={s.caption} variant={'body2'}>
|
<Typography className={s.caption} variant={'body2'}>
|
||||||
{`Don't have an account?`}
|
{`Don't have an account?`}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography as={Link} className={s.signUpLink} to={'/sign-up'} variant={'link1'}>
|
<Typography as={Link} className={s.signUpLink} to={'/sign-up'} variant={'link1'}>
|
||||||
Sign Up
|
Sign Up
|
||||||
</Typography>
|
</Typography>
|
||||||
</Card>
|
</Card>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,16 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||||||
import { SignUp } from './'
|
import { SignUp } from './'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
component: SignUp,
|
component: SignUp,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
title: 'Auth/Sign up',
|
title: 'Auth/Sign up',
|
||||||
} satisfies Meta<typeof SignUp>
|
} satisfies Meta<typeof SignUp>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
type Story = StoryObj<typeof meta>
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
onSubmit: data => console.info(data),
|
onSubmit: data => console.info(data),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,86 +10,86 @@ import { z } from 'zod'
|
|||||||
import s from './sign-up.module.scss'
|
import s from './sign-up.module.scss'
|
||||||
|
|
||||||
const schema = z
|
const schema = z
|
||||||
.object({
|
.object({
|
||||||
email: z.string().email('Invalid email address').nonempty('Enter email'),
|
email: z.string().email('Invalid email address').nonempty('Enter email'),
|
||||||
password: z.string().nonempty('Enter password'),
|
password: z.string().nonempty('Enter password'),
|
||||||
passwordConfirmation: z.string().nonempty('Confirm your password'),
|
passwordConfirmation: z.string().nonempty('Confirm your password'),
|
||||||
})
|
})
|
||||||
.superRefine((data, ctx) => {
|
.superRefine((data, ctx) => {
|
||||||
if (data.password !== data.passwordConfirmation) {
|
if (data.password !== data.passwordConfirmation) {
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: z.ZodIssueCode.custom,
|
code: z.ZodIssueCode.custom,
|
||||||
message: 'Passwords do not match',
|
message: 'Passwords do not match',
|
||||||
path: ['passwordConfirmation'],
|
path: ['passwordConfirmation'],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return data
|
return data
|
||||||
})
|
})
|
||||||
|
|
||||||
type FormType = z.infer<typeof schema>
|
type FormType = z.infer<typeof schema>
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onSubmit: (data: Omit<FormType, 'passwordConfirmation'>) => void
|
onSubmit: (data: Omit<FormType, 'passwordConfirmation'>) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SignUp = (props: Props) => {
|
export const SignUp = (props: Props) => {
|
||||||
const { control, handleSubmit } = useForm<FormType>({
|
const { control, handleSubmit } = useForm<FormType>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
email: '',
|
email: '',
|
||||||
password: '',
|
password: '',
|
||||||
passwordConfirmation: '',
|
passwordConfirmation: '',
|
||||||
},
|
},
|
||||||
mode: 'onSubmit',
|
mode: 'onSubmit',
|
||||||
resolver: zodResolver(schema),
|
resolver: zodResolver(schema),
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleFormSubmitted = handleSubmit(data =>
|
const handleFormSubmitted = handleSubmit(data =>
|
||||||
props.onSubmit(omit(data, ['passwordConfirmation']))
|
props.onSubmit(omit(data, ['passwordConfirmation']))
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DevTool control={control} />
|
<DevTool control={control} />
|
||||||
<Card className={s.card}>
|
<Card className={s.card}>
|
||||||
<Typography className={s.title} variant={'large'}>
|
<Typography className={s.title} variant={'large'}>
|
||||||
Sign Up
|
Sign Up
|
||||||
</Typography>
|
</Typography>
|
||||||
<form onSubmit={handleFormSubmitted}>
|
<form onSubmit={handleFormSubmitted}>
|
||||||
<div className={s.form}>
|
<div className={s.form}>
|
||||||
<ControlledTextField
|
<ControlledTextField
|
||||||
control={control}
|
control={control}
|
||||||
label={'Email'}
|
label={'Email'}
|
||||||
name={'email'}
|
name={'email'}
|
||||||
placeholder={'Email'}
|
placeholder={'Email'}
|
||||||
/>
|
/>
|
||||||
<ControlledTextField
|
<ControlledTextField
|
||||||
control={control}
|
control={control}
|
||||||
label={'Password'}
|
label={'Password'}
|
||||||
name={'password'}
|
name={'password'}
|
||||||
placeholder={'Password'}
|
placeholder={'Password'}
|
||||||
type={'password'}
|
type={'password'}
|
||||||
/>
|
/>
|
||||||
<ControlledTextField
|
<ControlledTextField
|
||||||
control={control}
|
control={control}
|
||||||
label={'Confirm password'}
|
label={'Confirm password'}
|
||||||
name={'passwordConfirmation'}
|
name={'passwordConfirmation'}
|
||||||
placeholder={'Confirm password'}
|
placeholder={'Confirm password'}
|
||||||
type={'password'}
|
type={'password'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button className={s.button} fullWidth type={'submit'}>
|
<Button className={s.button} fullWidth type={'submit'}>
|
||||||
Sign Up
|
Sign Up
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
{/* eslint-disable-next-line react/no-unescaped-entities */}
|
{/* eslint-disable-next-line react/no-unescaped-entities */}
|
||||||
<Typography className={s.caption} variant={'body2'}>
|
<Typography className={s.caption} variant={'body2'}>
|
||||||
Already have an account?
|
Already have an account?
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography as={Link} className={s.signInLink} to={'/sign-in'} variant={'link1'}>
|
<Typography as={Link} className={s.signInLink} to={'/sign-in'} variant={'link1'}>
|
||||||
Sign In
|
Sign In
|
||||||
</Typography>
|
</Typography>
|
||||||
</Card>
|
</Card>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,45 +3,45 @@ import { Card } from '@/services/decks'
|
|||||||
import { formatDate } from '@/utils'
|
import { formatDate } from '@/utils'
|
||||||
|
|
||||||
const columns: Column[] = [
|
const columns: Column[] = [
|
||||||
{
|
{
|
||||||
key: 'question',
|
key: 'question',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
title: 'Question',
|
title: 'Question',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'answer',
|
key: 'answer',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
title: 'Answer',
|
title: 'Answer',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'updated',
|
key: 'updated',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
title: 'Last Updated',
|
title: 'Last Updated',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'grade',
|
key: 'grade',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
title: 'Grade',
|
title: 'Grade',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
cards: Card[] | undefined
|
cards: Card[] | undefined
|
||||||
}
|
}
|
||||||
export const CardsTable = ({ cards }: Props) => {
|
export const CardsTable = ({ cards }: Props) => {
|
||||||
return (
|
return (
|
||||||
<Table>
|
<Table>
|
||||||
<TableHeader columns={columns} />
|
<TableHeader columns={columns} />
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{cards?.map(card => (
|
{cards?.map(card => (
|
||||||
<TableRow key={card.id}>
|
<TableRow key={card.id}>
|
||||||
<TableCell>{card.question}</TableCell>
|
<TableCell>{card.question}</TableCell>
|
||||||
<TableCell>{card.answer}</TableCell>
|
<TableCell>{card.answer}</TableCell>
|
||||||
<TableCell>{formatDate(card.updated)}</TableCell>
|
<TableCell>{formatDate(card.updated)}</TableCell>
|
||||||
<TableCell>{card.grade}</TableCell>
|
<TableCell>{card.grade}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,68 +5,68 @@ import { Button } from '@/components'
|
|||||||
import { Meta, StoryObj } from '@storybook/react'
|
import { Meta, StoryObj } from '@storybook/react'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
component: DeckDialog,
|
component: DeckDialog,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
title: 'Decks/Deck Dialog',
|
title: 'Decks/Deck Dialog',
|
||||||
} satisfies Meta<typeof DeckDialog>
|
} satisfies Meta<typeof DeckDialog>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
type Story = StoryObj<typeof meta>
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
onOpenChange: () => {},
|
onOpenChange: () => {},
|
||||||
open: true,
|
open: true,
|
||||||
},
|
},
|
||||||
render: args => {
|
render: args => {
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const closeModal = () => setOpen(false)
|
const closeModal = () => setOpen(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button onClick={() => setOpen(true)}>Open Modal</Button>
|
<Button onClick={() => setOpen(true)}>Open Modal</Button>
|
||||||
<DeckDialog
|
<DeckDialog
|
||||||
{...args}
|
{...args}
|
||||||
onCancel={closeModal}
|
onCancel={closeModal}
|
||||||
onConfirm={data => {
|
onConfirm={data => {
|
||||||
console.log(data)
|
console.log(data)
|
||||||
closeModal()
|
closeModal()
|
||||||
}}
|
}}
|
||||||
onOpenChange={setOpen}
|
onOpenChange={setOpen}
|
||||||
open={open}
|
open={open}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WithDefaultValues: Story = {
|
export const WithDefaultValues: Story = {
|
||||||
args: {
|
args: {
|
||||||
onOpenChange: () => {},
|
onOpenChange: () => {},
|
||||||
open: true,
|
open: true,
|
||||||
},
|
},
|
||||||
render: args => {
|
render: args => {
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const closeModal = () => setOpen(false)
|
const closeModal = () => setOpen(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button onClick={() => setOpen(true)}>Open Modal</Button>
|
<Button onClick={() => setOpen(true)}>Open Modal</Button>
|
||||||
<DeckDialog
|
<DeckDialog
|
||||||
{...args}
|
{...args}
|
||||||
defaultValues={{
|
defaultValues={{
|
||||||
isPrivate: true,
|
isPrivate: true,
|
||||||
name: 'some name',
|
name: 'some name',
|
||||||
}}
|
}}
|
||||||
onCancel={closeModal}
|
onCancel={closeModal}
|
||||||
onConfirm={data => {
|
onConfirm={data => {
|
||||||
console.log(data)
|
console.log(data)
|
||||||
closeModal()
|
closeModal()
|
||||||
}}
|
}}
|
||||||
onOpenChange={setOpen}
|
onOpenChange={setOpen}
|
||||||
open={open}
|
open={open}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,47 +7,52 @@ import { z } from 'zod'
|
|||||||
import s from './deck-dialog.module.scss'
|
import s from './deck-dialog.module.scss'
|
||||||
|
|
||||||
const newDeckSchema = z.object({
|
const newDeckSchema = z.object({
|
||||||
isPrivate: z.boolean(),
|
isPrivate: z.boolean(),
|
||||||
name: z.string().min(3).max(50),
|
name: z.string().min(3).max(50),
|
||||||
})
|
})
|
||||||
|
|
||||||
type FormValues = z.infer<typeof newDeckSchema>
|
type FormValues = z.infer<typeof newDeckSchema>
|
||||||
|
|
||||||
type Props = Pick<DialogProps, 'onCancel' | 'onOpenChange' | 'open'> & {
|
type Props = Pick<DialogProps, 'onCancel' | 'onOpenChange' | 'open'> & {
|
||||||
defaultValues?: FormValues
|
defaultValues?: FormValues
|
||||||
onConfirm: (data: FormValues) => void
|
onConfirm: (data: FormValues) => void
|
||||||
}
|
}
|
||||||
export const DeckDialog = ({
|
export const DeckDialog = ({
|
||||||
defaultValues = { isPrivate: false, name: '' },
|
defaultValues = { isPrivate: false, name: '' },
|
||||||
onCancel,
|
onCancel,
|
||||||
onConfirm,
|
onConfirm,
|
||||||
...dialogProps
|
...dialogProps
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const { control, handleSubmit, reset } = useForm<FormValues>({
|
const { control, handleSubmit, reset } = useForm<FormValues>({
|
||||||
defaultValues,
|
defaultValues,
|
||||||
resolver: zodResolver(newDeckSchema),
|
resolver: zodResolver(newDeckSchema),
|
||||||
})
|
})
|
||||||
const onSubmit = handleSubmit(data => {
|
const onSubmit = handleSubmit(data => {
|
||||||
onConfirm(data)
|
onConfirm(data)
|
||||||
dialogProps.onOpenChange?.(false)
|
dialogProps.onOpenChange?.(false)
|
||||||
reset()
|
reset()
|
||||||
})
|
})
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
reset()
|
reset()
|
||||||
onCancel?.()
|
onCancel?.()
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog {...dialogProps} onCancel={handleCancel} onConfirm={onSubmit} title={'Create new deck'}>
|
<Dialog
|
||||||
<form className={s.content} onSubmit={onSubmit}>
|
{...dialogProps}
|
||||||
<ControlledTextField control={control} label={'Deck name'} name={'name'} />
|
onCancel={handleCancel}
|
||||||
<ControlledCheckbox
|
onConfirm={onSubmit}
|
||||||
control={control}
|
title={'Create new deck'}
|
||||||
label={'Private'}
|
>
|
||||||
name={'isPrivate'}
|
<form className={s.content} onSubmit={onSubmit}>
|
||||||
position={'left'}
|
<ControlledTextField control={control} label={'Deck name'} name={'name'} />
|
||||||
/>
|
<ControlledCheckbox
|
||||||
</form>
|
control={control}
|
||||||
</Dialog>
|
label={'Private'}
|
||||||
)
|
name={'isPrivate'}
|
||||||
|
position={'left'}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</Dialog>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,86 +2,89 @@ import { Link } from 'react-router-dom'
|
|||||||
|
|
||||||
import { Edit2Outline, PlayCircleOutline, TrashOutline } from '@/assets'
|
import { Edit2Outline, PlayCircleOutline, TrashOutline } from '@/assets'
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Column,
|
Column,
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
TableCell,
|
TableCell,
|
||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@/components'
|
} from '@/components'
|
||||||
import { Deck } from '@/services/decks'
|
import { Deck } from '@/services/decks'
|
||||||
import { formatDate } from '@/utils'
|
import { formatDate } from '@/utils'
|
||||||
|
|
||||||
import s from './decks-table.module.scss'
|
import s from './decks-table.module.scss'
|
||||||
const columns: Column[] = [
|
const columns: Column[] = [
|
||||||
{
|
{
|
||||||
key: 'name',
|
key: 'name',
|
||||||
title: 'Name',
|
title: 'Name',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'cardsCount',
|
key: 'cardsCount',
|
||||||
title: 'Cards',
|
title: 'Cards',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'updated',
|
key: 'updated',
|
||||||
title: 'Last Updated',
|
title: 'Last Updated',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'author',
|
key: 'author',
|
||||||
title: 'Created By',
|
title: 'Created By',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'actions',
|
key: 'actions',
|
||||||
title: '',
|
title: '',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
currentUserId: string
|
currentUserId: string
|
||||||
decks: Deck[] | undefined
|
decks: Deck[] | undefined
|
||||||
onDeleteClick: (id: string) => void
|
onDeleteClick: (id: string) => void
|
||||||
onEditClick: (id: string) => void
|
onEditClick: (id: string) => void
|
||||||
}
|
}
|
||||||
export const DecksTable = ({ currentUserId, decks, onDeleteClick, onEditClick }: Props) => {
|
export const DecksTable = ({ currentUserId, decks, onDeleteClick, onEditClick }: Props) => {
|
||||||
const handleEditClick = (id: string) => () => onEditClick(id)
|
const handleEditClick = (id: string) => () => onEditClick(id)
|
||||||
const handleDeleteClick = (id: string) => () => onDeleteClick(id)
|
const handleDeleteClick = (id: string) => () => onDeleteClick(id)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Table>
|
<Table>
|
||||||
<TableHeader columns={columns} />
|
<TableHeader columns={columns} />
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{decks?.map(deck => (
|
{decks?.map(deck => (
|
||||||
<TableRow key={deck.id}>
|
<TableRow key={deck.id}>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Typography as={Link} to={`/decks/${deck.id}`} variant={'body2'}>
|
<Typography as={Link} to={`/decks/${deck.id}`} variant={'body2'}>
|
||||||
{deck.name}
|
{deck.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>{deck.cardsCount}</TableCell>
|
<TableCell>{deck.cardsCount}</TableCell>
|
||||||
<TableCell>{formatDate(deck.updated)}</TableCell>
|
<TableCell>{formatDate(deck.updated)}</TableCell>
|
||||||
<TableCell>{deck.author.name}</TableCell>
|
<TableCell>{deck.author.name}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<div className={s.iconsContainer}>
|
<div className={s.iconsContainer}>
|
||||||
<Button as={Link} to={`/decks/${deck.id}/learn`} variant={'icon'}>
|
<Button as={Link} to={`/decks/${deck.id}/learn`} variant={'icon'}>
|
||||||
<PlayCircleOutline />
|
<PlayCircleOutline />
|
||||||
</Button>
|
</Button>
|
||||||
{deck.author.id === currentUserId && (
|
{deck.author.id === currentUserId && (
|
||||||
<>
|
<>
|
||||||
<Button onClick={handleEditClick(deck.id)} variant={'icon'}>
|
<Button onClick={handleEditClick(deck.id)} variant={'icon'}>
|
||||||
<Edit2Outline />
|
<Edit2Outline />
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={handleDeleteClick(deck.id)} variant={'icon'}>
|
<Button
|
||||||
<TrashOutline />
|
onClick={handleDeleteClick(deck.id)}
|
||||||
</Button>
|
variant={'icon'}
|
||||||
</>
|
>
|
||||||
)}
|
<TrashOutline />
|
||||||
</div>
|
</Button>
|
||||||
</TableCell>
|
</>
|
||||||
</TableRow>
|
)}
|
||||||
))}
|
</div>
|
||||||
</TableBody>
|
</TableCell>
|
||||||
</Table>
|
</TableRow>
|
||||||
)
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,35 +5,35 @@ import { Button } from '@/components'
|
|||||||
import { Meta, StoryObj } from '@storybook/react'
|
import { Meta, StoryObj } from '@storybook/react'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
component: DeleteDeckDialog,
|
component: DeleteDeckDialog,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
title: 'Decks/Delete Deck Dialog',
|
title: 'Decks/Delete Deck Dialog',
|
||||||
} satisfies Meta<typeof DeleteDeckDialog>
|
} satisfies Meta<typeof DeleteDeckDialog>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
type Story = StoryObj<typeof meta>
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
deckName: 'Deck Name',
|
deckName: 'Deck Name',
|
||||||
onOpenChange: () => {},
|
onOpenChange: () => {},
|
||||||
open: true,
|
open: true,
|
||||||
},
|
},
|
||||||
render: args => {
|
render: args => {
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const closeModal = () => setOpen(false)
|
const closeModal = () => setOpen(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button onClick={() => setOpen(true)}>Open Modal</Button>
|
<Button onClick={() => setOpen(true)}>Open Modal</Button>
|
||||||
<DeleteDeckDialog
|
<DeleteDeckDialog
|
||||||
{...args}
|
{...args}
|
||||||
onCancel={closeModal}
|
onCancel={closeModal}
|
||||||
onConfirm={closeModal}
|
onConfirm={closeModal}
|
||||||
onOpenChange={setOpen}
|
onOpenChange={setOpen}
|
||||||
open={open}
|
open={open}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,17 @@ import { Dialog, DialogProps } from '@/components'
|
|||||||
import s from './delete-deck-dialog.module.scss'
|
import s from './delete-deck-dialog.module.scss'
|
||||||
export default {}
|
export default {}
|
||||||
type Props = Pick<DialogProps, 'onCancel' | 'onConfirm' | 'onOpenChange' | 'open'> & {
|
type Props = Pick<DialogProps, 'onCancel' | 'onConfirm' | 'onOpenChange' | 'open'> & {
|
||||||
deckName: string
|
deckName: string
|
||||||
}
|
}
|
||||||
export const DeleteDeckDialog = ({ deckName, ...dialogProps }: Props) => {
|
export const DeleteDeckDialog = ({ deckName, ...dialogProps }: Props) => {
|
||||||
return (
|
return (
|
||||||
<Dialog {...dialogProps} title={'Delete deck'}>
|
<Dialog {...dialogProps} title={'Delete deck'}>
|
||||||
<div className={s.content}>
|
<div className={s.content}>
|
||||||
<p>
|
<p>
|
||||||
Do you really want to remove <strong>{deckName}</strong>?
|
Do you really want to remove <strong>{deckName}</strong>?
|
||||||
</p>
|
</p>
|
||||||
<p>All cards will be deleted.</p>
|
<p>All cards will be deleted.</p>
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,27 +3,27 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||||||
import { PersonalInformation } from './'
|
import { PersonalInformation } from './'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
component: PersonalInformation,
|
component: PersonalInformation,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
title: 'Profile/Personal information',
|
title: 'Profile/Personal information',
|
||||||
} satisfies Meta<typeof PersonalInformation>
|
} satisfies Meta<typeof PersonalInformation>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
type Story = StoryObj<typeof meta>
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
avatar: 'https://picsum.photos/200',
|
avatar: 'https://picsum.photos/200',
|
||||||
email: 'your_email@domain.com',
|
email: 'your_email@domain.com',
|
||||||
name: 'John Doe',
|
name: 'John Doe',
|
||||||
onAvatarChange: () => {
|
onAvatarChange: () => {
|
||||||
console.info('avatar changed')
|
console.info('avatar changed')
|
||||||
|
},
|
||||||
|
onLogout: () => {
|
||||||
|
console.info('logout')
|
||||||
|
},
|
||||||
|
onNameChange: () => {
|
||||||
|
console.info('name changed')
|
||||||
|
},
|
||||||
},
|
},
|
||||||
onLogout: () => {
|
|
||||||
console.info('logout')
|
|
||||||
},
|
|
||||||
onNameChange: () => {
|
|
||||||
console.info('name changed')
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,62 +4,62 @@ import { Button, Card, Typography } from '../../ui'
|
|||||||
import s from './personal-information.module.scss'
|
import s from './personal-information.module.scss'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
avatar: string
|
avatar: string
|
||||||
email: string
|
email: string
|
||||||
name: string
|
name: string
|
||||||
onAvatarChange: (newAvatar: string) => void
|
onAvatarChange: (newAvatar: string) => void
|
||||||
onLogout: () => void
|
onLogout: () => void
|
||||||
onNameChange: (newName: string) => void
|
onNameChange: (newName: string) => void
|
||||||
}
|
}
|
||||||
export const PersonalInformation = ({
|
export const PersonalInformation = ({
|
||||||
avatar,
|
avatar,
|
||||||
email,
|
email,
|
||||||
name,
|
name,
|
||||||
onAvatarChange,
|
onAvatarChange,
|
||||||
onLogout,
|
onLogout,
|
||||||
onNameChange,
|
onNameChange,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const handleAvatarChanged = () => {
|
const handleAvatarChanged = () => {
|
||||||
onAvatarChange('new Avatar')
|
onAvatarChange('new Avatar')
|
||||||
}
|
}
|
||||||
const handleNameChanged = () => {
|
const handleNameChanged = () => {
|
||||||
onNameChange('New name')
|
onNameChange('New name')
|
||||||
}
|
}
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
onLogout()
|
onLogout()
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className={s.card}>
|
<Card className={s.card}>
|
||||||
<Typography className={s.title} variant={'large'}>
|
<Typography className={s.title} variant={'large'}>
|
||||||
Personal Information
|
Personal Information
|
||||||
</Typography>
|
</Typography>
|
||||||
<div className={s.photoContainer}>
|
<div className={s.photoContainer}>
|
||||||
<div>
|
<div>
|
||||||
<img alt={'avatar'} src={avatar} />
|
<img alt={'avatar'} src={avatar} />
|
||||||
<button className={s.editAvatarButton} onClick={handleAvatarChanged}>
|
<button className={s.editAvatarButton} onClick={handleAvatarChanged}>
|
||||||
<Camera />
|
<Camera />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={s.nameWithEditButton}>
|
<div className={s.nameWithEditButton}>
|
||||||
<Typography className={s.name} variant={'h1'}>
|
<Typography className={s.name} variant={'h1'}>
|
||||||
{name}
|
{name}
|
||||||
</Typography>
|
</Typography>
|
||||||
<button className={s.editNameButton} onClick={handleNameChanged}>
|
<button className={s.editNameButton} onClick={handleNameChanged}>
|
||||||
<Edit />
|
<Edit />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<Typography className={s.email} variant={'body2'}>
|
<Typography className={s.email} variant={'body2'}>
|
||||||
{/* eslint-disable-next-line react/no-unescaped-entities */}
|
{/* eslint-disable-next-line react/no-unescaped-entities */}
|
||||||
{email}
|
{email}
|
||||||
</Typography>
|
</Typography>
|
||||||
<div className={s.buttonContainer}>
|
<div className={s.buttonContainer}>
|
||||||
<Button onClick={handleLogout} variant={'secondary'}>
|
<Button onClick={handleLogout} variant={'secondary'}>
|
||||||
<Logout />
|
<Logout />
|
||||||
Sign Out
|
Sign Out
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,65 +1,67 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react'
|
import type { Meta, StoryObj } from '@storybook/react'
|
||||||
|
|
||||||
import { Button } from './'
|
import { Button } from './'
|
||||||
|
import {Camera} from "@/assets";
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
argTypes: {
|
argTypes: {
|
||||||
variant: {
|
variant: {
|
||||||
control: { type: 'radio' },
|
control: { type: 'radio' },
|
||||||
options: ['primary', 'secondary', 'tertiary', 'link'],
|
options: ['primary', 'secondary', 'tertiary', 'link'],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
component: Button,
|
||||||
component: Button,
|
tags: ['autodocs'],
|
||||||
tags: ['autodocs'],
|
title: 'Components/Button',
|
||||||
title: 'Components/Button',
|
|
||||||
} satisfies Meta<typeof Button>
|
} satisfies Meta<typeof Button>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
type Story = StoryObj<typeof meta>
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
export const Primary: Story = {
|
export const Primary: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Primary Button',
|
children: <>Turn Camera On <Camera/></>,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
variant: 'primary',
|
variant: 'primary',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Secondary: Story = {
|
export const Secondary: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Secondary Button',
|
children: 'Secondary Button',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
variant: 'secondary',
|
variant: 'secondary',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
export const Tertiary: Story = {
|
export const Tertiary: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Tertiary Button',
|
children: 'Tertiary Button',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
variant: 'tertiary',
|
variant: 'tertiary',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
export const Link: Story = {
|
export const Link: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Tertiary Button',
|
children: 'Tertiary Button',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
variant: 'link',
|
variant: 'link',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FullWidth: Story = {
|
export const FullWidth: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Full Width Button',
|
children: 'Full Width Button',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
fullWidth: true,
|
fullWidth: true,
|
||||||
variant: 'primary',
|
variant: 'primary',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AsLink: Story = {
|
export const AsLink: Story = {
|
||||||
args: {
|
args: {
|
||||||
as: 'a',
|
as: 'button',
|
||||||
children: 'Link that looks like a button',
|
children: 'Link that looks like a button',
|
||||||
variant: 'primary',
|
variant: 'primary',
|
||||||
},
|
href: 'https://google.com',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,20 @@ import { ComponentPropsWithoutRef, ElementType, ReactNode } from 'react'
|
|||||||
import s from './button.module.scss'
|
import s from './button.module.scss'
|
||||||
|
|
||||||
export type ButtonProps<T extends ElementType = 'button'> = {
|
export type ButtonProps<T extends ElementType = 'button'> = {
|
||||||
as?: T
|
as?: T
|
||||||
children: ReactNode
|
children: ReactNode
|
||||||
className?: string
|
className?: string
|
||||||
fullWidth?: boolean
|
fullWidth?: boolean
|
||||||
variant?: 'icon' | 'link' | 'primary' | 'secondary' | 'tertiary'
|
variant?: 'icon' | 'link' | 'primary' | 'secondary' | 'tertiary'
|
||||||
} & ComponentPropsWithoutRef<T>
|
} & ComponentPropsWithoutRef<T>
|
||||||
|
|
||||||
export const Button = <T extends ElementType = 'button'>(props: ButtonProps<T>) => {
|
export const Button = <T extends ElementType = 'button'>(props: ButtonProps<T>) => {
|
||||||
const { as: Component = 'button', className, fullWidth, variant = 'primary', ...rest } = props
|
const { as: Component = 'button', className, fullWidth, variant = 'primary', ...rest } = props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Component className={`${s[variant]} ${fullWidth ? s.fullWidth : ''} ${className}`} {...rest} />
|
<Component
|
||||||
)
|
className={`${s[variant]} ${fullWidth ? s.fullWidth : ''} ${className}`}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,21 +4,21 @@ import { Card } from './'
|
|||||||
import { Typography } from '@/components'
|
import { Typography } from '@/components'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
component: Card,
|
component: Card,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
title: 'Components/Card',
|
title: 'Components/Card',
|
||||||
} satisfies Meta<typeof Card>
|
} satisfies Meta<typeof Card>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
type Story = StoryObj<typeof meta>
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: <Typography variant={'large'}>Card</Typography>,
|
children: <Typography variant={'large'}>Card</Typography>,
|
||||||
style: {
|
style: {
|
||||||
height: '300px',
|
height: '300px',
|
||||||
padding: '24px',
|
padding: '24px',
|
||||||
width: '300px',
|
width: '300px',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import s from './card.module.scss'
|
|||||||
export type CardProps = {} & ComponentPropsWithoutRef<'div'>
|
export type CardProps = {} & ComponentPropsWithoutRef<'div'>
|
||||||
|
|
||||||
export const Card = forwardRef<HTMLDivElement, CardProps>(({ className, ...restProps }, ref) => {
|
export const Card = forwardRef<HTMLDivElement, CardProps>(({ className, ...restProps }, ref) => {
|
||||||
const classNames = {
|
const classNames = {
|
||||||
root: clsx(s.root, className),
|
root: clsx(s.root, className),
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className={classNames.root} ref={ref} {...restProps}></div>
|
return <div className={classNames.root} ref={ref} {...restProps}></div>
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,32 +3,32 @@ import { useState } from 'react'
|
|||||||
import { Checkbox } from './checkbox'
|
import { Checkbox } from './checkbox'
|
||||||
import { Meta, StoryObj } from '@storybook/react'
|
import { Meta, StoryObj } from '@storybook/react'
|
||||||
const meta = {
|
const meta = {
|
||||||
component: Checkbox,
|
component: Checkbox,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
title: 'Components/Checkbox',
|
title: 'Components/Checkbox',
|
||||||
} satisfies Meta<typeof Checkbox>
|
} satisfies Meta<typeof Checkbox>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
|
|
||||||
type Story = StoryObj<typeof meta>
|
type Story = StoryObj<typeof meta>
|
||||||
export const Uncontrolled: Story = {
|
export const Uncontrolled: Story = {
|
||||||
args: {
|
args: {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
label: 'Click here',
|
label: 'Click here',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Controlled: Story = {
|
export const Controlled: Story = {
|
||||||
render: args => {
|
render: args => {
|
||||||
const [checked, setChecked] = useState(false)
|
const [checked, setChecked] = useState(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
{...args}
|
{...args}
|
||||||
checked={checked}
|
checked={checked}
|
||||||
label={'Click here'}
|
label={'Click here'}
|
||||||
onChange={() => setChecked(!checked)}
|
onChange={() => setChecked(!checked)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,57 +9,60 @@ import { clsx } from 'clsx'
|
|||||||
import s from './checkbox.module.scss'
|
import s from './checkbox.module.scss'
|
||||||
|
|
||||||
export type CheckboxProps = {
|
export type CheckboxProps = {
|
||||||
checked?: boolean
|
checked?: boolean
|
||||||
className?: string
|
className?: string
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
id?: string
|
id?: string
|
||||||
label?: string
|
label?: string
|
||||||
onChange?: (checked: boolean) => void
|
onChange?: (checked: boolean) => void
|
||||||
position?: 'left'
|
position?: 'left'
|
||||||
required?: boolean
|
required?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Checkbox: FC<CheckboxProps> = ({
|
export const Checkbox: FC<CheckboxProps> = ({
|
||||||
checked,
|
checked,
|
||||||
className,
|
className,
|
||||||
disabled,
|
disabled,
|
||||||
id,
|
id,
|
||||||
label,
|
label,
|
||||||
onChange,
|
onChange,
|
||||||
position,
|
position,
|
||||||
required,
|
required,
|
||||||
}) => {
|
}) => {
|
||||||
const classNames = {
|
const classNames = {
|
||||||
buttonWrapper: clsx(s.buttonWrapper, disabled && s.disabled, position === 'left' && s.left),
|
buttonWrapper: clsx(s.buttonWrapper, disabled && s.disabled, position === 'left' && s.left),
|
||||||
container: clsx(s.container, className),
|
container: clsx(s.container, className),
|
||||||
indicator: s.indicator,
|
indicator: s.indicator,
|
||||||
label: clsx(s.label, disabled && s.disabled),
|
label: clsx(s.label, disabled && s.disabled),
|
||||||
root: s.root,
|
root: s.root,
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames.container}>
|
<div className={classNames.container}>
|
||||||
<LabelRadix.Root asChild>
|
<LabelRadix.Root asChild>
|
||||||
<Typography as={'label'} className={classNames.label} variant={'body2'}>
|
<Typography as={'label'} className={classNames.label} variant={'body2'}>
|
||||||
<div className={classNames.buttonWrapper}>
|
<div className={classNames.buttonWrapper}>
|
||||||
<CheckboxRadix.Root
|
<CheckboxRadix.Root
|
||||||
checked={checked}
|
checked={checked}
|
||||||
className={classNames.root}
|
className={classNames.root}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
id={id}
|
id={id}
|
||||||
onCheckedChange={onChange}
|
onCheckedChange={onChange}
|
||||||
required={required}
|
required={required}
|
||||||
>
|
>
|
||||||
{checked && (
|
{checked && (
|
||||||
<CheckboxRadix.Indicator className={classNames.indicator} forceMount>
|
<CheckboxRadix.Indicator
|
||||||
<Check />
|
className={classNames.indicator}
|
||||||
</CheckboxRadix.Indicator>
|
forceMount
|
||||||
)}
|
>
|
||||||
</CheckboxRadix.Root>
|
<Check />
|
||||||
</div>
|
</CheckboxRadix.Indicator>
|
||||||
{label}
|
)}
|
||||||
</Typography>
|
</CheckboxRadix.Root>
|
||||||
</LabelRadix.Root>
|
</div>
|
||||||
</div>
|
{label}
|
||||||
)
|
</Typography>
|
||||||
|
</LabelRadix.Root>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,34 +3,34 @@ import { FieldValues, UseControllerProps, useController } from 'react-hook-form'
|
|||||||
import { Checkbox, CheckboxProps } from '../../'
|
import { Checkbox, CheckboxProps } from '../../'
|
||||||
|
|
||||||
export type ControlledCheckboxProps<TFieldValues extends FieldValues> =
|
export type ControlledCheckboxProps<TFieldValues extends FieldValues> =
|
||||||
UseControllerProps<TFieldValues> & Omit<CheckboxProps, 'id' | 'onChange' | 'value'>
|
UseControllerProps<TFieldValues> & Omit<CheckboxProps, 'id' | 'onChange' | 'value'>
|
||||||
|
|
||||||
export const ControlledCheckbox = <TFieldValues extends FieldValues>({
|
export const ControlledCheckbox = <TFieldValues extends FieldValues>({
|
||||||
control,
|
|
||||||
defaultValue,
|
|
||||||
name,
|
|
||||||
rules,
|
|
||||||
shouldUnregister,
|
|
||||||
...checkboxProps
|
|
||||||
}: ControlledCheckboxProps<TFieldValues>) => {
|
|
||||||
const {
|
|
||||||
field: { onChange, value },
|
|
||||||
} = useController({
|
|
||||||
control,
|
control,
|
||||||
defaultValue,
|
defaultValue,
|
||||||
name,
|
name,
|
||||||
rules,
|
rules,
|
||||||
shouldUnregister,
|
shouldUnregister,
|
||||||
})
|
...checkboxProps
|
||||||
|
}: ControlledCheckboxProps<TFieldValues>) => {
|
||||||
|
const {
|
||||||
|
field: { onChange, value },
|
||||||
|
} = useController({
|
||||||
|
control,
|
||||||
|
defaultValue,
|
||||||
|
name,
|
||||||
|
rules,
|
||||||
|
shouldUnregister,
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
{...{
|
{...{
|
||||||
checked: value,
|
checked: value,
|
||||||
id: name,
|
id: name,
|
||||||
onChange,
|
onChange,
|
||||||
...checkboxProps,
|
...checkboxProps,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,28 +3,28 @@ import { Control, FieldPath, FieldValues, useController } from 'react-hook-form'
|
|||||||
import { RadioGroup, RadioGroupProps } from '@/components/ui'
|
import { RadioGroup, RadioGroupProps } from '@/components/ui'
|
||||||
|
|
||||||
export type ControlledRadioGroupProps<TFieldValues extends FieldValues> = {
|
export type ControlledRadioGroupProps<TFieldValues extends FieldValues> = {
|
||||||
control: Control<TFieldValues>
|
control: Control<TFieldValues>
|
||||||
name: FieldPath<TFieldValues>
|
name: FieldPath<TFieldValues>
|
||||||
} & Omit<RadioGroupProps, 'id' | 'onChange' | 'value'>
|
} & Omit<RadioGroupProps, 'id' | 'onChange' | 'value'>
|
||||||
|
|
||||||
export const ControlledRadioGroup = <TFieldValues extends FieldValues>(
|
export const ControlledRadioGroup = <TFieldValues extends FieldValues>(
|
||||||
props: ControlledRadioGroupProps<TFieldValues>
|
props: ControlledRadioGroupProps<TFieldValues>
|
||||||
) => {
|
) => {
|
||||||
const {
|
const {
|
||||||
field: { onChange, ...field },
|
field: { onChange, ...field },
|
||||||
fieldState: { error },
|
fieldState: { error },
|
||||||
} = useController({
|
} = useController({
|
||||||
control: props.control,
|
control: props.control,
|
||||||
name: props.name,
|
name: props.name,
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
{...props}
|
{...props}
|
||||||
{...field}
|
{...field}
|
||||||
errorMessage={error?.message}
|
errorMessage={error?.message}
|
||||||
id={props.name}
|
id={props.name}
|
||||||
onValueChange={onChange}
|
onValueChange={onChange}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,20 +3,20 @@ import { Control, FieldPath, FieldValues, useController } from 'react-hook-form'
|
|||||||
import { TextField, TextFieldProps } from '@/components'
|
import { TextField, TextFieldProps } from '@/components'
|
||||||
|
|
||||||
export type ControlledTextFieldProps<TFieldValues extends FieldValues> = {
|
export type ControlledTextFieldProps<TFieldValues extends FieldValues> = {
|
||||||
control: Control<TFieldValues>
|
control: Control<TFieldValues>
|
||||||
name: FieldPath<TFieldValues>
|
name: FieldPath<TFieldValues>
|
||||||
} & Omit<TextFieldProps, 'id' | 'onChange' | 'value'>
|
} & Omit<TextFieldProps, 'id' | 'onChange' | 'value'>
|
||||||
|
|
||||||
export const ControlledTextField = <TFieldValues extends FieldValues>(
|
export const ControlledTextField = <TFieldValues extends FieldValues>(
|
||||||
props: ControlledTextFieldProps<TFieldValues>
|
props: ControlledTextFieldProps<TFieldValues>
|
||||||
) => {
|
) => {
|
||||||
const {
|
const {
|
||||||
field,
|
field,
|
||||||
fieldState: { error },
|
fieldState: { error },
|
||||||
} = useController({
|
} = useController({
|
||||||
control: props.control,
|
control: props.control,
|
||||||
name: props.name,
|
name: props.name,
|
||||||
})
|
})
|
||||||
|
|
||||||
return <TextField {...props} {...field} errorMessage={error?.message} id={props.name} />
|
return <TextField {...props} {...field} errorMessage={error?.message} id={props.name} />
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,31 +4,31 @@ import { Dialog } from './'
|
|||||||
import { Meta, StoryObj } from '@storybook/react'
|
import { Meta, StoryObj } from '@storybook/react'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
component: Dialog,
|
component: Dialog,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
title: 'Components/Dialog',
|
title: 'Components/Dialog',
|
||||||
} satisfies Meta<typeof Dialog>
|
} satisfies Meta<typeof Dialog>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
type Story = StoryObj<typeof meta>
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Modal',
|
children: 'Modal',
|
||||||
onOpenChange: () => {},
|
onOpenChange: () => {},
|
||||||
open: true,
|
open: true,
|
||||||
title: 'Modal',
|
title: 'Modal',
|
||||||
},
|
},
|
||||||
render: args => {
|
render: args => {
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<button onClick={() => setOpen(true)}>Open Modal</button>
|
<button onClick={() => setOpen(true)}>Open Modal</button>
|
||||||
<Dialog {...args} onOpenChange={setOpen} open={open}>
|
<Dialog {...args} onOpenChange={setOpen} open={open}>
|
||||||
Dialog content here
|
Dialog content here
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,28 +3,28 @@ import { Button, Modal, ModalProps } from '@/components'
|
|||||||
import s from './dialog.module.scss'
|
import s from './dialog.module.scss'
|
||||||
|
|
||||||
export type DialogProps = ModalProps & {
|
export type DialogProps = ModalProps & {
|
||||||
cancelText?: string
|
cancelText?: string
|
||||||
confirmText?: string
|
confirmText?: string
|
||||||
onCancel?: () => void
|
onCancel?: () => void
|
||||||
onConfirm?: () => void
|
onConfirm?: () => void
|
||||||
}
|
}
|
||||||
export const Dialog = ({
|
export const Dialog = ({
|
||||||
cancelText = 'Cancel',
|
cancelText = 'Cancel',
|
||||||
children,
|
children,
|
||||||
confirmText = 'OK',
|
confirmText = 'OK',
|
||||||
onCancel,
|
onCancel,
|
||||||
onConfirm,
|
onConfirm,
|
||||||
...modalProps
|
...modalProps
|
||||||
}: DialogProps) => {
|
}: DialogProps) => {
|
||||||
return (
|
return (
|
||||||
<Modal {...modalProps}>
|
<Modal {...modalProps}>
|
||||||
{children}
|
{children}
|
||||||
<div className={s.buttons}>
|
<div className={s.buttons}>
|
||||||
<Button onClick={onCancel} variant={'secondary'}>
|
<Button onClick={onCancel} variant={'secondary'}>
|
||||||
{cancelText}
|
{cancelText}
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={onConfirm}>{confirmText}</Button>
|
<Button onClick={onConfirm}>{confirmText}</Button>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,18 +6,18 @@ import { clsx } from 'clsx'
|
|||||||
import s from './label.module.scss'
|
import s from './label.module.scss'
|
||||||
|
|
||||||
export type LabelProps = {
|
export type LabelProps = {
|
||||||
label?: ReactNode
|
label?: ReactNode
|
||||||
} & ComponentPropsWithoutRef<'label'>
|
} & ComponentPropsWithoutRef<'label'>
|
||||||
|
|
||||||
export const Label: FC<LabelProps> = ({ children, className, label, ...rest }) => {
|
export const Label: FC<LabelProps> = ({ children, className, label, ...rest }) => {
|
||||||
const classNames = {
|
const classNames = {
|
||||||
label: clsx(s.label, className),
|
label: clsx(s.label, className),
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LabelRadixUI.Root {...rest}>
|
<LabelRadixUI.Root {...rest}>
|
||||||
{label && <div className={classNames.label}>{label}</div>}
|
{label && <div className={classNames.label}>{label}</div>}
|
||||||
{children}
|
{children}
|
||||||
</LabelRadixUI.Root>
|
</LabelRadixUI.Root>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,31 +4,31 @@ import { Modal } from '@/components'
|
|||||||
import { Meta, StoryObj } from '@storybook/react'
|
import { Meta, StoryObj } from '@storybook/react'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
component: Modal,
|
component: Modal,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
title: 'Components/Modal',
|
title: 'Components/Modal',
|
||||||
} satisfies Meta<typeof Modal>
|
} satisfies Meta<typeof Modal>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
type Story = StoryObj<typeof meta>
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Modal',
|
children: 'Modal',
|
||||||
onOpenChange: () => {},
|
onOpenChange: () => {},
|
||||||
open: true,
|
open: true,
|
||||||
title: 'Modal',
|
title: 'Modal',
|
||||||
},
|
},
|
||||||
render: args => {
|
render: args => {
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<button onClick={() => setOpen(true)}>Open Modal</button>
|
<button onClick={() => setOpen(true)}>Open Modal</button>
|
||||||
<Modal {...args} onOpenChange={setOpen} open={open}>
|
<Modal {...args} onOpenChange={setOpen} open={open}>
|
||||||
Modal content here
|
Modal content here
|
||||||
</Modal>
|
</Modal>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,30 +7,30 @@ import * as DialogPrimitive from '@radix-ui/react-dialog'
|
|||||||
import s from './modal.module.scss'
|
import s from './modal.module.scss'
|
||||||
|
|
||||||
export type ModalProps = {
|
export type ModalProps = {
|
||||||
children: ReactNode
|
children: ReactNode
|
||||||
onOpenChange: (open: boolean) => void
|
onOpenChange: (open: boolean) => void
|
||||||
open: boolean
|
open: boolean
|
||||||
title?: string
|
title?: string
|
||||||
} & Omit<ComponentPropsWithoutRef<typeof DialogPrimitive.Dialog>, 'onOpenChange' | 'open'>
|
} & Omit<ComponentPropsWithoutRef<typeof DialogPrimitive.Dialog>, 'onOpenChange' | 'open'>
|
||||||
export const Modal = ({ children, title, ...props }: ModalProps) => {
|
export const Modal = ({ children, title, ...props }: ModalProps) => {
|
||||||
return (
|
return (
|
||||||
<DialogPrimitive.Root {...props}>
|
<DialogPrimitive.Root {...props}>
|
||||||
<DialogPrimitive.Portal>
|
<DialogPrimitive.Portal>
|
||||||
<DialogPrimitive.Overlay className={s.overlay} />
|
<DialogPrimitive.Overlay className={s.overlay} />
|
||||||
<DialogPrimitive.Content className={s.content}>
|
<DialogPrimitive.Content className={s.content}>
|
||||||
<div className={s.header}>
|
<div className={s.header}>
|
||||||
<DialogPrimitive.Title asChild>
|
<DialogPrimitive.Title asChild>
|
||||||
<Typography as={'h2'} variant={'h2'}>
|
<Typography as={'h2'} variant={'h2'}>
|
||||||
{title}
|
{title}
|
||||||
</Typography>
|
</Typography>
|
||||||
</DialogPrimitive.Title>
|
</DialogPrimitive.Title>
|
||||||
<DialogPrimitive.Close className={s.closeButton}>
|
<DialogPrimitive.Close className={s.closeButton}>
|
||||||
<Close />
|
<Close />
|
||||||
</DialogPrimitive.Close>
|
</DialogPrimitive.Close>
|
||||||
</div>
|
</div>
|
||||||
{children}
|
{children}
|
||||||
</DialogPrimitive.Content>
|
</DialogPrimitive.Content>
|
||||||
</DialogPrimitive.Portal>
|
</DialogPrimitive.Portal>
|
||||||
</DialogPrimitive.Root>
|
</DialogPrimitive.Root>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import s from './page.module.scss'
|
|||||||
export type PageProps = ComponentPropsWithoutRef<'div'>
|
export type PageProps = ComponentPropsWithoutRef<'div'>
|
||||||
|
|
||||||
export const Page = forwardRef<HTMLDivElement, PageProps>(({ className, ...props }, ref) => {
|
export const Page = forwardRef<HTMLDivElement, PageProps>(({ className, ...props }, ref) => {
|
||||||
const classNames = {
|
const classNames = {
|
||||||
root: clsx(s.root, className),
|
root: clsx(s.root, className),
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div {...props} className={classNames.root} ref={ref} />
|
return <div {...props} className={classNames.root} ref={ref} />
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -7,187 +7,194 @@ import { clsx } from 'clsx'
|
|||||||
import s from './pagination.module.scss'
|
import s from './pagination.module.scss'
|
||||||
|
|
||||||
type PaginationConditionals =
|
type PaginationConditionals =
|
||||||
| {
|
| {
|
||||||
onPerPageChange: (itemPerPage: number) => void
|
onPerPageChange: (itemPerPage: number) => void
|
||||||
perPage: number
|
perPage: number
|
||||||
perPageOptions: number[]
|
perPageOptions: number[]
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
onPerPageChange?: never
|
onPerPageChange?: never
|
||||||
perPage?: null
|
perPage?: null
|
||||||
perPageOptions?: never
|
perPageOptions?: never
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PaginationProps = {
|
export type PaginationProps = {
|
||||||
count: number
|
count: number
|
||||||
onChange: (page: number) => void
|
onChange: (page: number) => void
|
||||||
onPerPageChange?: (itemPerPage: number) => void
|
onPerPageChange?: (itemPerPage: number) => void
|
||||||
page: number
|
page: number
|
||||||
perPage?: number
|
perPage?: number
|
||||||
perPageOptions?: number[]
|
perPageOptions?: number[]
|
||||||
siblings?: number
|
siblings?: number
|
||||||
} & PaginationConditionals
|
} & PaginationConditionals
|
||||||
|
|
||||||
const classNames = {
|
const classNames = {
|
||||||
container: s.container,
|
container: s.container,
|
||||||
dots: s.dots,
|
dots: s.dots,
|
||||||
icon: s.icon,
|
icon: s.icon,
|
||||||
item: s.item,
|
item: s.item,
|
||||||
pageButton(selected?: boolean) {
|
pageButton(selected?: boolean) {
|
||||||
return clsx(this.item, selected && s.selected)
|
return clsx(this.item, selected && s.selected)
|
||||||
},
|
},
|
||||||
root: s.root,
|
root: s.root,
|
||||||
select: s.select,
|
select: s.select,
|
||||||
selectBox: s.selectBox,
|
selectBox: s.selectBox,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Pagination: FC<PaginationProps> = ({
|
export const Pagination: FC<PaginationProps> = ({
|
||||||
count,
|
|
||||||
onChange,
|
|
||||||
onPerPageChange,
|
|
||||||
page,
|
|
||||||
perPage = null,
|
|
||||||
perPageOptions,
|
|
||||||
siblings,
|
|
||||||
}) => {
|
|
||||||
const {
|
|
||||||
handleMainPageClicked,
|
|
||||||
handleNextPageClicked,
|
|
||||||
handlePreviousPageClicked,
|
|
||||||
isFirstPage,
|
|
||||||
isLastPage,
|
|
||||||
paginationRange,
|
|
||||||
} = usePagination({
|
|
||||||
count,
|
count,
|
||||||
onChange,
|
onChange,
|
||||||
|
onPerPageChange,
|
||||||
page,
|
page,
|
||||||
|
perPage = null,
|
||||||
|
perPageOptions,
|
||||||
siblings,
|
siblings,
|
||||||
})
|
}) => {
|
||||||
|
const {
|
||||||
|
handleMainPageClicked,
|
||||||
|
handleNextPageClicked,
|
||||||
|
handlePreviousPageClicked,
|
||||||
|
isFirstPage,
|
||||||
|
isLastPage,
|
||||||
|
paginationRange,
|
||||||
|
} = usePagination({
|
||||||
|
count,
|
||||||
|
onChange,
|
||||||
|
page,
|
||||||
|
siblings,
|
||||||
|
})
|
||||||
|
|
||||||
const showPerPageSelect = !!perPage && !!perPageOptions && !!onPerPageChange
|
const showPerPageSelect = !!perPage && !!perPageOptions && !!onPerPageChange
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames.root}>
|
<div className={classNames.root}>
|
||||||
<div className={classNames.container}>
|
<div className={classNames.container}>
|
||||||
<PrevButton disabled={isFirstPage} onClick={handlePreviousPageClicked} />
|
<PrevButton disabled={isFirstPage} onClick={handlePreviousPageClicked} />
|
||||||
|
|
||||||
<MainPaginationButtons
|
<MainPaginationButtons
|
||||||
currentPage={page}
|
currentPage={page}
|
||||||
onClick={handleMainPageClicked}
|
onClick={handleMainPageClicked}
|
||||||
paginationRange={paginationRange}
|
paginationRange={paginationRange}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<NextButton disabled={isLastPage} onClick={handleNextPageClicked} />
|
<NextButton disabled={isLastPage} onClick={handleNextPageClicked} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{showPerPageSelect && (
|
{showPerPageSelect && (
|
||||||
<PerPageSelect
|
<PerPageSelect
|
||||||
{...{
|
{...{
|
||||||
onPerPageChange,
|
onPerPageChange,
|
||||||
perPage,
|
perPage,
|
||||||
perPageOptions,
|
perPageOptions,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
type NavigationButtonProps = {
|
type NavigationButtonProps = {
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
onClick: () => void
|
onClick: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
type PageButtonProps = NavigationButtonProps & {
|
type PageButtonProps = NavigationButtonProps & {
|
||||||
page: number
|
page: number
|
||||||
selected: boolean
|
selected: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const Dots: FC = () => {
|
const Dots: FC = () => {
|
||||||
return <span className={classNames.dots}>…</span>
|
return <span className={classNames.dots}>…</span>
|
||||||
}
|
}
|
||||||
const PageButton: FC<PageButtonProps> = ({ disabled, onClick, page, selected }) => {
|
const PageButton: FC<PageButtonProps> = ({ disabled, onClick, page, selected }) => {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
className={classNames.pageButton(selected)}
|
className={classNames.pageButton(selected)}
|
||||||
disabled={selected || disabled}
|
disabled={selected || disabled}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
{page}
|
{page}
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const PrevButton: FC<NavigationButtonProps> = ({ disabled, onClick }) => {
|
const PrevButton: FC<NavigationButtonProps> = ({ disabled, onClick }) => {
|
||||||
return (
|
return (
|
||||||
<button className={classNames.item} disabled={disabled} onClick={onClick}>
|
<button className={classNames.item} disabled={disabled} onClick={onClick}>
|
||||||
<KeyboardArrowLeft className={classNames.icon} />
|
<KeyboardArrowLeft className={classNames.icon} />
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const NextButton: FC<NavigationButtonProps> = ({ disabled, onClick }) => {
|
const NextButton: FC<NavigationButtonProps> = ({ disabled, onClick }) => {
|
||||||
return (
|
return (
|
||||||
<button className={classNames.item} disabled={disabled} onClick={onClick}>
|
<button className={classNames.item} disabled={disabled} onClick={onClick}>
|
||||||
<KeyboardArrowRight className={classNames.icon} />
|
<KeyboardArrowRight className={classNames.icon} />
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
type MainPaginationButtonsProps = {
|
type MainPaginationButtonsProps = {
|
||||||
currentPage: number
|
currentPage: number
|
||||||
onClick: (pageNumber: number) => () => void
|
onClick: (pageNumber: number) => () => void
|
||||||
paginationRange: (number | string)[]
|
paginationRange: (number | string)[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const MainPaginationButtons: FC<MainPaginationButtonsProps> = ({
|
const MainPaginationButtons: FC<MainPaginationButtonsProps> = ({
|
||||||
currentPage,
|
currentPage,
|
||||||
onClick,
|
onClick,
|
||||||
paginationRange,
|
paginationRange,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{paginationRange.map((page: number | string, index) => {
|
{paginationRange.map((page: number | string, index) => {
|
||||||
const isSelected = page === currentPage
|
const isSelected = page === currentPage
|
||||||
|
|
||||||
if (typeof page !== 'number') {
|
if (typeof page !== 'number') {
|
||||||
return <Dots key={index} />
|
return <Dots key={index} />
|
||||||
}
|
}
|
||||||
|
|
||||||
return <PageButton key={index} onClick={onClick(page)} page={page} selected={isSelected} />
|
return (
|
||||||
})}
|
<PageButton
|
||||||
</>
|
key={index}
|
||||||
)
|
onClick={onClick(page)}
|
||||||
|
page={page}
|
||||||
|
selected={isSelected}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PerPageSelectProps = {
|
export type PerPageSelectProps = {
|
||||||
onPerPageChange: (itemPerPage: number) => void
|
onPerPageChange: (itemPerPage: number) => void
|
||||||
perPage: number
|
perPage: number
|
||||||
perPageOptions: number[]
|
perPageOptions: number[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PerPageSelect: FC<PerPageSelectProps> = (
|
export const PerPageSelect: FC<PerPageSelectProps> = (
|
||||||
{
|
{
|
||||||
// perPage,
|
// perPage,
|
||||||
// perPageOptions,
|
// perPageOptions,
|
||||||
// onPerPageChange,
|
// onPerPageChange,
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
// const selectOptions = perPageOptions.map(value => ({
|
// const selectOptions = perPageOptions.map(value => ({
|
||||||
// label: value,
|
// label: value,
|
||||||
// value,
|
// value,
|
||||||
// }))
|
// }))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames.selectBox}>
|
<div className={classNames.selectBox}>
|
||||||
Показать
|
Показать
|
||||||
{/*<Select*/}
|
{/*<Select*/}
|
||||||
{/* className={classNames.select}*/}
|
{/* className={classNames.select}*/}
|
||||||
{/* value={perPage}*/}
|
{/* value={perPage}*/}
|
||||||
{/* options={selectOptions}*/}
|
{/* options={selectOptions}*/}
|
||||||
{/* onChange={onPerPageChange}*/}
|
{/* onChange={onPerPageChange}*/}
|
||||||
{/* variant="pagination"*/}
|
{/* variant="pagination"*/}
|
||||||
{/*/>*/}
|
{/*/>*/}
|
||||||
на странице
|
на странице
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,110 +3,110 @@ import { useCallback, useMemo } from 'react'
|
|||||||
// original code: https://www.freecodecamp.org/news/build-a-custom-pagination-component-in-react/
|
// original code: https://www.freecodecamp.org/news/build-a-custom-pagination-component-in-react/
|
||||||
|
|
||||||
const range = (start: number, end: number) => {
|
const range = (start: number, end: number) => {
|
||||||
let length = end - start + 1
|
const length = end - start + 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Create an array of certain length and set the elements within it from
|
Create an array of certain length and set the elements within it from
|
||||||
start value to end value.
|
start value to end value.
|
||||||
*/
|
*/
|
||||||
return Array.from({ length }, (_, idx) => idx + start)
|
return Array.from({ length }, (_, idx) => idx + start)
|
||||||
}
|
}
|
||||||
|
|
||||||
const DOTS = '...'
|
const DOTS = '...'
|
||||||
|
|
||||||
type UsePaginationParamType = {
|
type UsePaginationParamType = {
|
||||||
count: number
|
count: number
|
||||||
siblings?: number
|
onChange: (pageNumber: number) => void
|
||||||
page: number
|
page: number
|
||||||
onChange: (pageNumber: number) => void
|
siblings?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
type PaginationRange = (number | '...')[]
|
type PaginationRange = ('...' | number)[]
|
||||||
|
|
||||||
export const usePagination = ({ count, siblings = 1, page, onChange }: UsePaginationParamType) => {
|
export const usePagination = ({ count, onChange, page, siblings = 1 }: UsePaginationParamType) => {
|
||||||
const paginationRange = useMemo(() => {
|
const paginationRange = useMemo(() => {
|
||||||
// Pages count is determined as siblingCount + firstPage + lastPage + page + 2*DOTS
|
// Pages count is determined as siblingCount + firstPage + lastPage + page + 2*DOTS
|
||||||
const totalPageNumbers = siblings + 5
|
const totalPageNumbers = siblings + 5
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Case 1:
|
Case 1:
|
||||||
If the number of pages is less than the page numbers we want to show in our
|
If the number of pages is less than the page numbers we want to show in our
|
||||||
paginationComponent, we return the range [1..totalPageCount]
|
paginationComponent, we return the range [1..totalPageCount]
|
||||||
*/
|
*/
|
||||||
if (totalPageNumbers >= count) {
|
if (totalPageNumbers >= count) {
|
||||||
return range(1, count)
|
return range(1, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Calculate left and right sibling index and make sure they are within range 1 and totalPageCount
|
Calculate left and right sibling index and make sure they are within range 1 and totalPageCount
|
||||||
*/
|
*/
|
||||||
const leftSiblingIndex = Math.max(page - siblings, 1)
|
const leftSiblingIndex = Math.max(page - siblings, 1)
|
||||||
const rightSiblingIndex = Math.min(page + siblings, count)
|
const rightSiblingIndex = Math.min(page + siblings, count)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We do not show dots when there is only one page number to be inserted
|
We do not show dots when there is only one page number to be inserted
|
||||||
between the extremes of siblings and the page limits i.e 1 and totalPageCount.
|
between the extremes of siblings and the page limits i.e 1 and totalPageCount.
|
||||||
Hence, we are using leftSiblingIndex > 2 and rightSiblingIndex < totalPageCount - 2
|
Hence, we are using leftSiblingIndex > 2 and rightSiblingIndex < totalPageCount - 2
|
||||||
*/
|
*/
|
||||||
const shouldShowLeftDots = leftSiblingIndex > 2
|
const shouldShowLeftDots = leftSiblingIndex > 2
|
||||||
const shouldShowRightDots = rightSiblingIndex < count - 2
|
const shouldShowRightDots = rightSiblingIndex < count - 2
|
||||||
|
|
||||||
const firstPageIndex = 1
|
const firstPageIndex = 1
|
||||||
const lastPageIndex = count
|
const lastPageIndex = count
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Case 2: No left dots to show, but rights dots to be shown
|
Case 2: No left dots to show, but rights dots to be shown
|
||||||
*/
|
*/
|
||||||
if (!shouldShowLeftDots && shouldShowRightDots) {
|
if (!shouldShowLeftDots && shouldShowRightDots) {
|
||||||
let leftItemCount = 3 + 2 * siblings
|
const leftItemCount = 3 + 2 * siblings
|
||||||
let leftRange = range(1, leftItemCount)
|
const leftRange = range(1, leftItemCount)
|
||||||
|
|
||||||
return [...leftRange, DOTS, count]
|
return [...leftRange, DOTS, count]
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Case 3: No right dots to show, but left dots to be shown
|
Case 3: No right dots to show, but left dots to be shown
|
||||||
*/
|
*/
|
||||||
if (shouldShowLeftDots && !shouldShowRightDots) {
|
if (shouldShowLeftDots && !shouldShowRightDots) {
|
||||||
let rightItemCount = 3 + 2 * siblings
|
const rightItemCount = 3 + 2 * siblings
|
||||||
let rightRange = range(count - rightItemCount + 1, count)
|
const rightRange = range(count - rightItemCount + 1, count)
|
||||||
|
|
||||||
return [firstPageIndex, DOTS, ...rightRange]
|
return [firstPageIndex, DOTS, ...rightRange]
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Case 4: Both left and right dots to be shown
|
Case 4: Both left and right dots to be shown
|
||||||
*/
|
*/
|
||||||
if (shouldShowLeftDots && shouldShowRightDots) {
|
if (shouldShowLeftDots && shouldShowRightDots) {
|
||||||
let middleRange = range(leftSiblingIndex, rightSiblingIndex)
|
const middleRange = range(leftSiblingIndex, rightSiblingIndex)
|
||||||
|
|
||||||
return [firstPageIndex, DOTS, ...middleRange, DOTS, lastPageIndex]
|
return [firstPageIndex, DOTS, ...middleRange, DOTS, lastPageIndex]
|
||||||
|
}
|
||||||
|
}, [siblings, page, count]) as PaginationRange
|
||||||
|
|
||||||
|
const lastPage = paginationRange.at(-1)
|
||||||
|
|
||||||
|
const isFirstPage = page === 1
|
||||||
|
const isLastPage = page === lastPage
|
||||||
|
|
||||||
|
const handleNextPageClicked = useCallback(() => {
|
||||||
|
onChange(page + 1)
|
||||||
|
}, [page, onChange])
|
||||||
|
|
||||||
|
const handlePreviousPageClicked = useCallback(() => {
|
||||||
|
onChange(page - 1)
|
||||||
|
}, [page, onChange])
|
||||||
|
|
||||||
|
function handleMainPageClicked(pageNumber: number) {
|
||||||
|
return () => onChange(pageNumber)
|
||||||
}
|
}
|
||||||
}, [siblings, page, count]) as PaginationRange
|
|
||||||
|
|
||||||
const lastPage = paginationRange.at(-1)
|
return {
|
||||||
|
handleMainPageClicked,
|
||||||
const isFirstPage = page === 1
|
handleNextPageClicked,
|
||||||
const isLastPage = page === lastPage
|
handlePreviousPageClicked,
|
||||||
|
isFirstPage,
|
||||||
const handleNextPageClicked = useCallback(() => {
|
isLastPage,
|
||||||
onChange(page + 1)
|
paginationRange,
|
||||||
}, [page, onChange])
|
}
|
||||||
|
|
||||||
const handlePreviousPageClicked = useCallback(() => {
|
|
||||||
onChange(page - 1)
|
|
||||||
}, [page, onChange])
|
|
||||||
|
|
||||||
function handleMainPageClicked(pageNumber: number) {
|
|
||||||
return () => onChange(pageNumber)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
paginationRange,
|
|
||||||
isFirstPage,
|
|
||||||
isLastPage,
|
|
||||||
handleMainPageClicked,
|
|
||||||
handleNextPageClicked,
|
|
||||||
handlePreviousPageClicked,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,29 +3,29 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||||||
import { RadioGroup } from './'
|
import { RadioGroup } from './'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
component: RadioGroup,
|
component: RadioGroup,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
title: 'Components/Radio Group',
|
title: 'Components/Radio Group',
|
||||||
} satisfies Meta<typeof RadioGroup>
|
} satisfies Meta<typeof RadioGroup>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
type Story = StoryObj<typeof meta>
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
options: [
|
options: [
|
||||||
{ label: 'Option One', value: 'option-one' },
|
{ label: 'Option One', value: 'option-one' },
|
||||||
{ label: 'Option Two', value: 'option-two' },
|
{ label: 'Option Two', value: 'option-two' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Disabled: Story = {
|
export const Disabled: Story = {
|
||||||
args: {
|
args: {
|
||||||
disabled: true,
|
disabled: true,
|
||||||
options: [
|
options: [
|
||||||
{ label: 'Option One', value: 'option-one' },
|
{ label: 'Option One', value: 'option-one' },
|
||||||
{ label: 'Option Two', value: 'option-two' },
|
{ label: 'Option Two', value: 'option-two' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,56 +7,56 @@ import { clsx } from 'clsx'
|
|||||||
import s from './radio-group.module.scss'
|
import s from './radio-group.module.scss'
|
||||||
|
|
||||||
const RadioGroupRoot = React.forwardRef<
|
const RadioGroupRoot = React.forwardRef<
|
||||||
React.ElementRef<typeof RadioGroupPrimitive.Root>,
|
React.ElementRef<typeof RadioGroupPrimitive.Root>,
|
||||||
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
|
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
|
||||||
>(({ className, ...props }, ref) => {
|
>(({ className, ...props }, ref) => {
|
||||||
return <RadioGroupPrimitive.Root className={clsx(s.root, className)} {...props} ref={ref} />
|
return <RadioGroupPrimitive.Root className={clsx(s.root, className)} {...props} ref={ref} />
|
||||||
})
|
})
|
||||||
|
|
||||||
RadioGroupRoot.displayName = RadioGroupPrimitive.Root.displayName
|
RadioGroupRoot.displayName = RadioGroupPrimitive.Root.displayName
|
||||||
|
|
||||||
const RadioGroupItem = React.forwardRef<
|
const RadioGroupItem = React.forwardRef<
|
||||||
React.ElementRef<typeof RadioGroupPrimitive.Item>,
|
React.ElementRef<typeof RadioGroupPrimitive.Item>,
|
||||||
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
|
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
|
||||||
>(({ children, className, ...props }, ref) => {
|
>(({ children, className, ...props }, ref) => {
|
||||||
return (
|
return (
|
||||||
<RadioGroupPrimitive.Item className={clsx(s.option, className)} ref={ref} {...props}>
|
<RadioGroupPrimitive.Item className={clsx(s.option, className)} ref={ref} {...props}>
|
||||||
<div className={s.icon}></div>
|
<div className={s.icon}></div>
|
||||||
</RadioGroupPrimitive.Item>
|
</RadioGroupPrimitive.Item>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName
|
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName
|
||||||
|
|
||||||
type Option = {
|
type Option = {
|
||||||
label: string
|
label: string
|
||||||
value: string
|
value: string
|
||||||
}
|
}
|
||||||
export type RadioGroupProps = Omit<
|
export type RadioGroupProps = Omit<
|
||||||
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>,
|
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>,
|
||||||
'children'
|
'children'
|
||||||
> & {
|
> & {
|
||||||
errorMessage?: string
|
errorMessage?: string
|
||||||
options: Option[]
|
options: Option[]
|
||||||
}
|
}
|
||||||
const RadioGroup = React.forwardRef<
|
const RadioGroup = React.forwardRef<
|
||||||
React.ElementRef<typeof RadioGroupPrimitive.Root>,
|
React.ElementRef<typeof RadioGroupPrimitive.Root>,
|
||||||
RadioGroupProps
|
RadioGroupProps
|
||||||
>((props, ref) => {
|
>((props, ref) => {
|
||||||
const { errorMessage, options, ...restProps } = props
|
const { errorMessage, options, ...restProps } = props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RadioGroupRoot {...restProps} ref={ref}>
|
<RadioGroupRoot {...restProps} ref={ref}>
|
||||||
{options.map(option => (
|
{options.map(option => (
|
||||||
<div className={s.label} key={option.value}>
|
<div className={s.label} key={option.value}>
|
||||||
<RadioGroupItem id={option.value} value={option.value} />
|
<RadioGroupItem id={option.value} value={option.value} />
|
||||||
<Typography as={'label'} htmlFor={option.value} variant={'body2'}>
|
<Typography as={'label'} htmlFor={option.value} variant={'body2'}>
|
||||||
{option.label}
|
{option.label}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</RadioGroupRoot>
|
</RadioGroupRoot>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
export { RadioGroup, RadioGroupItem, RadioGroupRoot }
|
export { RadioGroup, RadioGroupItem, RadioGroupRoot }
|
||||||
|
|||||||
@@ -5,37 +5,37 @@ import { clsx } from 'clsx'
|
|||||||
|
|
||||||
import s from './slider.module.scss'
|
import s from './slider.module.scss'
|
||||||
const Slider = forwardRef<
|
const Slider = forwardRef<
|
||||||
ElementRef<typeof SliderPrimitive.Root>,
|
ElementRef<typeof SliderPrimitive.Root>,
|
||||||
Omit<ComponentPropsWithoutRef<typeof SliderPrimitive.Root>, 'value'> & {
|
Omit<ComponentPropsWithoutRef<typeof SliderPrimitive.Root>, 'value'> & {
|
||||||
value?: (number | undefined)[]
|
value?: (number | undefined)[]
|
||||||
}
|
|
||||||
>(({ className, max, onValueChange, value, ...props }, ref) => {
|
|
||||||
useEffect(() => {
|
|
||||||
if (value?.[1] === undefined || value?.[1] === null) {
|
|
||||||
onValueChange?.([value?.[0] ?? 0, max ?? 0])
|
|
||||||
}
|
}
|
||||||
}, [max, value, onValueChange])
|
>(({ className, max, onValueChange, value, ...props }, ref) => {
|
||||||
|
useEffect(() => {
|
||||||
|
if (value?.[1] === undefined || value?.[1] === null) {
|
||||||
|
onValueChange?.([value?.[0] ?? 0, max ?? 0])
|
||||||
|
}
|
||||||
|
}, [max, value, onValueChange])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={s.container}>
|
<div className={s.container}>
|
||||||
<span>{value?.[0]}</span>
|
<span>{value?.[0]}</span>
|
||||||
<SliderPrimitive.Root
|
<SliderPrimitive.Root
|
||||||
className={clsx(s.root, className)}
|
className={clsx(s.root, className)}
|
||||||
max={max}
|
max={max}
|
||||||
onValueChange={onValueChange}
|
onValueChange={onValueChange}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
{...props}
|
{...props}
|
||||||
value={[value?.[0] ?? 0, value?.[1] ?? max ?? 0]}
|
value={[value?.[0] ?? 0, value?.[1] ?? max ?? 0]}
|
||||||
>
|
>
|
||||||
<SliderPrimitive.Track className={s.track}>
|
<SliderPrimitive.Track className={s.track}>
|
||||||
<SliderPrimitive.Range className={'absolute h-full bg-primary'} />
|
<SliderPrimitive.Range className={'absolute h-full bg-primary'} />
|
||||||
</SliderPrimitive.Track>
|
</SliderPrimitive.Track>
|
||||||
<SliderPrimitive.Thumb className={s.thumb} />
|
<SliderPrimitive.Thumb className={s.thumb} />
|
||||||
<SliderPrimitive.Thumb className={s.thumb} />
|
<SliderPrimitive.Thumb className={s.thumb} />
|
||||||
</SliderPrimitive.Root>
|
</SliderPrimitive.Root>
|
||||||
<span>{value?.[1]}</span>
|
<span>{value?.[1]}</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
Slider.displayName = SliderPrimitive.Root.displayName
|
Slider.displayName = SliderPrimitive.Root.displayName
|
||||||
|
|||||||
@@ -3,124 +3,127 @@ import { Typography } from '@/components'
|
|||||||
import { Meta } from '@storybook/react'
|
import { Meta } from '@storybook/react'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
component: Table,
|
component: Table,
|
||||||
title: 'Components/Table',
|
title: 'Components/Table',
|
||||||
} as Meta<typeof Table>
|
} as Meta<typeof Table>
|
||||||
|
|
||||||
export const Default = {
|
export const Default = {
|
||||||
args: {
|
args: {
|
||||||
children: (
|
children: (
|
||||||
<>
|
<>
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHeadCell>Название</TableHeadCell>
|
<TableHeadCell>Название</TableHeadCell>
|
||||||
<TableHeadCell align={'center'}>Описание</TableHeadCell>
|
<TableHeadCell align={'center'}>Описание</TableHeadCell>
|
||||||
<TableHeadCell>Ссылка</TableHeadCell>
|
<TableHeadCell>Ссылка</TableHeadCell>
|
||||||
<TableHeadCell>Тип</TableHeadCell>
|
<TableHeadCell>Тип</TableHeadCell>
|
||||||
<TableHeadCell>Вид</TableHeadCell>
|
<TableHeadCell>Вид</TableHeadCell>
|
||||||
<TableHeadCell />
|
<TableHeadCell />
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell>Web Basic</TableCell>
|
<TableCell>Web Basic</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||||
incididunt ut sed do eiusmod tempoei usmodr sit amet, consectetur adipiscing elit, sed
|
tempor incididunt ut sed do eiusmod tempoei usmodr sit amet, consectetur
|
||||||
do...
|
adipiscing elit, sed do...
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Typography
|
<Typography
|
||||||
as={'a'}
|
as={'a'}
|
||||||
href={'https://it-incubator.io/'}
|
href={'https://it-incubator.io/'}
|
||||||
target={'_blank'}
|
target={'_blank'}
|
||||||
variant={'link1'}
|
variant={'link1'}
|
||||||
>
|
>
|
||||||
Какая-то ссылка кудато на какой-то источник с информациейо ссылка кудато на какой-то
|
Какая-то ссылка кудато на какой-то источник с информациейо ссылка
|
||||||
источник
|
кудато на какой-то источник
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>Основной</TableCell>
|
<TableCell>Основной</TableCell>
|
||||||
<TableCell>Читать</TableCell>
|
<TableCell>Читать</TableCell>
|
||||||
<TableCell>🦎</TableCell>
|
<TableCell>🦎</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell>Web Basic</TableCell>
|
<TableCell>Web Basic</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||||
incididunt ut sed do eiusmod tempoei usmodr sit amet, consectetur adipiscing elit, sed
|
tempor incididunt ut sed do eiusmod tempoei usmodr sit amet, consectetur
|
||||||
do...
|
adipiscing elit, sed do...
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
Какая-то ссылка кудато на какой-то источник с информациейо ссылка кудато на какой-то
|
Какая-то ссылка кудато на какой-то источник с информациейо ссылка кудато
|
||||||
источник
|
на какой-то источник
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>Основной</TableCell>
|
<TableCell>Основной</TableCell>
|
||||||
<TableCell>Читать</TableCell>
|
<TableCell>Читать</TableCell>
|
||||||
<TableCell>✨</TableCell>
|
<TableCell>✨</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = [
|
const data = [
|
||||||
{
|
{
|
||||||
category: 'Основной',
|
category: 'Основной',
|
||||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor',
|
description:
|
||||||
id: '01',
|
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor',
|
||||||
link: 'Какая-то ссылка кудато на какой-то источник с информациейо ссылка кудато на какой-то',
|
id: '01',
|
||||||
title: 'Web Basic',
|
link: 'Какая-то ссылка кудато на какой-то источник с информациейо ссылка кудато на какой-то',
|
||||||
type: 'Читать',
|
title: 'Web Basic',
|
||||||
},
|
type: 'Читать',
|
||||||
{
|
},
|
||||||
category: 'Основной',
|
{
|
||||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor',
|
category: 'Основной',
|
||||||
id: '02',
|
description:
|
||||||
link: 'Какая-то ссылка куда-то',
|
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor',
|
||||||
title: 'Web Basic',
|
id: '02',
|
||||||
type: 'Читать',
|
link: 'Какая-то ссылка куда-то',
|
||||||
},
|
title: 'Web Basic',
|
||||||
{
|
type: 'Читать',
|
||||||
category: 'Основной',
|
},
|
||||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor',
|
{
|
||||||
id: '03',
|
category: 'Основной',
|
||||||
link: 'Какая-то ссылка кудато на какой-то источник с информациейо ссылка кудато на какой-то. Какая-то ссылка кудато на какой-то источник с информациейо ссылка куда-то на какой-то',
|
description:
|
||||||
title: 'Web Basic',
|
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor',
|
||||||
type: 'Читать',
|
id: '03',
|
||||||
},
|
link: 'Какая-то ссылка кудато на какой-то источник с информациейо ссылка кудато на какой-то. Какая-то ссылка кудато на какой-то источник с информациейо ссылка куда-то на какой-то',
|
||||||
|
title: 'Web Basic',
|
||||||
|
type: 'Читать',
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const WithMapMethod = {
|
export const WithMapMethod = {
|
||||||
args: {
|
args: {
|
||||||
children: (
|
children: (
|
||||||
<>
|
<>
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHeadCell>Название</TableHeadCell>
|
<TableHeadCell>Название</TableHeadCell>
|
||||||
<TableHeadCell align={'center'}>Описание</TableHeadCell>
|
<TableHeadCell align={'center'}>Описание</TableHeadCell>
|
||||||
<TableHeadCell>Ссылка</TableHeadCell>
|
<TableHeadCell>Ссылка</TableHeadCell>
|
||||||
<TableHeadCell>Тип</TableHeadCell>
|
<TableHeadCell>Тип</TableHeadCell>
|
||||||
<TableHeadCell>Вид</TableHeadCell>
|
<TableHeadCell>Вид</TableHeadCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{data.map(item => (
|
{data.map(item => (
|
||||||
<TableRow key={item.id}>
|
<TableRow key={item.id}>
|
||||||
<TableCell>{item.title}</TableCell>
|
<TableCell>{item.title}</TableCell>
|
||||||
<TableCell>{item.description}</TableCell>
|
<TableCell>{item.description}</TableCell>
|
||||||
<TableCell>{item.link}</TableCell>
|
<TableCell>{item.link}</TableCell>
|
||||||
<TableCell>{item.category}</TableCell>
|
<TableCell>{item.category}</TableCell>
|
||||||
<TableCell>{item.type}</TableCell>
|
<TableCell>{item.type}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Empty = {
|
export const Empty = {
|
||||||
render: () => <TableEmpty />,
|
render: () => <TableEmpty />,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,123 +6,125 @@ import { clsx } from 'clsx'
|
|||||||
import s from './table.module.scss'
|
import s from './table.module.scss'
|
||||||
|
|
||||||
export const Table = forwardRef<HTMLTableElement, ComponentPropsWithoutRef<'table'>>(
|
export const Table = forwardRef<HTMLTableElement, ComponentPropsWithoutRef<'table'>>(
|
||||||
({ className, ...rest }, ref) => {
|
({ className, ...rest }, ref) => {
|
||||||
const classNames = {
|
const classNames = {
|
||||||
table: clsx(className, s.table),
|
table: clsx(className, s.table),
|
||||||
}
|
}
|
||||||
|
|
||||||
return <table className={classNames.table} {...rest} ref={ref} />
|
return <table className={classNames.table} {...rest} ref={ref} />
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
export const TableHead = forwardRef<ElementRef<'thead'>, ComponentPropsWithoutRef<'thead'>>(
|
export const TableHead = forwardRef<ElementRef<'thead'>, ComponentPropsWithoutRef<'thead'>>(
|
||||||
({ ...rest }, ref) => {
|
({ ...rest }, ref) => {
|
||||||
return <thead {...rest} ref={ref} />
|
return <thead {...rest} ref={ref} />
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
export const TableBody = forwardRef<ElementRef<'tbody'>, ComponentPropsWithoutRef<'tbody'>>(
|
export const TableBody = forwardRef<ElementRef<'tbody'>, ComponentPropsWithoutRef<'tbody'>>(
|
||||||
({ ...rest }, ref) => {
|
({ ...rest }, ref) => {
|
||||||
return <tbody {...rest} ref={ref} />
|
return <tbody {...rest} ref={ref} />
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
export const TableRow = forwardRef<ElementRef<'tr'>, ComponentPropsWithoutRef<'tr'>>(
|
export const TableRow = forwardRef<ElementRef<'tr'>, ComponentPropsWithoutRef<'tr'>>(
|
||||||
({ ...rest }, ref) => {
|
({ ...rest }, ref) => {
|
||||||
return <tr {...rest} ref={ref} />
|
return <tr {...rest} ref={ref} />
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
export const TableHeadCell = forwardRef<ElementRef<'th'>, ComponentPropsWithoutRef<'th'>>(
|
export const TableHeadCell = forwardRef<ElementRef<'th'>, ComponentPropsWithoutRef<'th'>>(
|
||||||
({ children, className, ...rest }, ref) => {
|
({ children, className, ...rest }, ref) => {
|
||||||
const classNames = {
|
const classNames = {
|
||||||
headCell: clsx(className, s.headCell),
|
headCell: clsx(className, s.headCell),
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<th className={classNames.headCell} {...rest} ref={ref}>
|
<th className={classNames.headCell} {...rest} ref={ref}>
|
||||||
<span>{children}</span>
|
<span>{children}</span>
|
||||||
</th>
|
</th>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
export const TableCell = forwardRef<ElementRef<'td'>, ComponentPropsWithoutRef<'td'>>(
|
export const TableCell = forwardRef<ElementRef<'td'>, ComponentPropsWithoutRef<'td'>>(
|
||||||
({ className, ...rest }, ref) => {
|
({ className, ...rest }, ref) => {
|
||||||
const classNames = {
|
const classNames = {
|
||||||
cell: clsx(className, s.tableCell),
|
cell: clsx(className, s.tableCell),
|
||||||
}
|
}
|
||||||
|
|
||||||
return <td className={classNames.cell} {...rest} ref={ref} />
|
return <td className={classNames.cell} {...rest} ref={ref} />
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
export const TableEmpty: FC<ComponentProps<'div'> & { mb?: string; mt?: string }> = ({
|
export const TableEmpty: FC<ComponentProps<'div'> & { mb?: string; mt?: string }> = ({
|
||||||
className,
|
className,
|
||||||
mb,
|
mb,
|
||||||
mt = '89px',
|
mt = '89px',
|
||||||
}) => {
|
}) => {
|
||||||
const classNames = {
|
const classNames = {
|
||||||
empty: clsx(className, s.empty),
|
empty: clsx(className, s.empty),
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Typography
|
<Typography
|
||||||
className={classNames.empty}
|
className={classNames.empty}
|
||||||
style={{ marginBottom: mb, marginTop: mt }}
|
style={{ marginBottom: mb, marginTop: mt }}
|
||||||
variant={'h2'}
|
variant={'h2'}
|
||||||
>
|
>
|
||||||
Пока тут еще нет данных! :(
|
Пока тут еще нет данных! :(
|
||||||
</Typography>
|
</Typography>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
export type Column = {
|
export type Column = {
|
||||||
key: string
|
key: string
|
||||||
sortable?: boolean
|
sortable?: boolean
|
||||||
title: string
|
title: string
|
||||||
}
|
}
|
||||||
export type Sort = {
|
export type Sort = {
|
||||||
direction: 'asc' | 'desc'
|
direction: 'asc' | 'desc'
|
||||||
key: string
|
key: string
|
||||||
} | null
|
} | null
|
||||||
|
|
||||||
export const TableHeader: FC<
|
export const TableHeader: FC<
|
||||||
Omit<
|
Omit<
|
||||||
ComponentPropsWithoutRef<'thead'> & {
|
ComponentPropsWithoutRef<'thead'> & {
|
||||||
columns: Column[]
|
columns: Column[]
|
||||||
onSort?: (sort: Sort) => void
|
onSort?: (sort: Sort) => void
|
||||||
sort?: Sort
|
sort?: Sort
|
||||||
},
|
},
|
||||||
'children'
|
'children'
|
||||||
>
|
>
|
||||||
> = ({ columns, onSort, sort, ...restProps }) => {
|
> = ({ columns, onSort, sort, ...restProps }) => {
|
||||||
const handleSort = (key: string, sortable?: boolean) => () => {
|
const handleSort = (key: string, sortable?: boolean) => () => {
|
||||||
if (!onSort || !sortable) {
|
if (!onSort || !sortable) {
|
||||||
return
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sort?.key !== key) {
|
||||||
|
return onSort({ direction: 'asc', key })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sort.direction === 'desc') {
|
||||||
|
return onSort(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
return onSort({
|
||||||
|
direction: sort?.direction === 'asc' ? 'desc' : 'asc',
|
||||||
|
key,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sort?.key !== key) {
|
return (
|
||||||
return onSort({ direction: 'asc', key })
|
<TableHead {...restProps}>
|
||||||
}
|
<TableRow>
|
||||||
|
{columns.map(({ key, sortable = true, title }) => (
|
||||||
if (sort.direction === 'desc') {
|
<TableHeadCell key={key} onClick={handleSort(key, sortable)}>
|
||||||
return onSort(null)
|
{title}
|
||||||
}
|
{sort && sort.key === key && (
|
||||||
|
<span>{sort.direction === 'asc' ? '▲' : '▼'}</span>
|
||||||
return onSort({
|
)}
|
||||||
direction: sort?.direction === 'asc' ? 'desc' : 'asc',
|
</TableHeadCell>
|
||||||
key,
|
))}
|
||||||
})
|
</TableRow>
|
||||||
}
|
</TableHead>
|
||||||
|
)
|
||||||
return (
|
|
||||||
<TableHead {...restProps}>
|
|
||||||
<TableRow>
|
|
||||||
{columns.map(({ key, sortable = true, title }) => (
|
|
||||||
<TableHeadCell key={key} onClick={handleSort(key, sortable)}>
|
|
||||||
{title}
|
|
||||||
{sort && sort.key === key && <span>{sort.direction === 'asc' ? '▲' : '▼'}</span>}
|
|
||||||
</TableHeadCell>
|
|
||||||
))}
|
|
||||||
</TableRow>
|
|
||||||
</TableHead>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,28 +8,28 @@ import s from './tabs.module.scss'
|
|||||||
const Tabs = TabsPrimitive.Root
|
const Tabs = TabsPrimitive.Root
|
||||||
|
|
||||||
const TabsList = forwardRef<
|
const TabsList = forwardRef<
|
||||||
ElementRef<typeof TabsPrimitive.List>,
|
ElementRef<typeof TabsPrimitive.List>,
|
||||||
ComponentPropsWithoutRef<typeof TabsPrimitive.List>
|
ComponentPropsWithoutRef<typeof TabsPrimitive.List>
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<TabsPrimitive.List className={clsx(s.list, className)} ref={ref} {...props} />
|
<TabsPrimitive.List className={clsx(s.list, className)} ref={ref} {...props} />
|
||||||
))
|
))
|
||||||
|
|
||||||
TabsList.displayName = TabsPrimitive.List.displayName
|
TabsList.displayName = TabsPrimitive.List.displayName
|
||||||
|
|
||||||
const TabsTrigger = forwardRef<
|
const TabsTrigger = forwardRef<
|
||||||
ElementRef<typeof TabsPrimitive.Trigger>,
|
ElementRef<typeof TabsPrimitive.Trigger>,
|
||||||
ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<TabsPrimitive.Trigger className={clsx(s.trigger, className)} ref={ref} {...props} />
|
<TabsPrimitive.Trigger className={clsx(s.trigger, className)} ref={ref} {...props} />
|
||||||
))
|
))
|
||||||
|
|
||||||
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
|
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
|
||||||
|
|
||||||
const TabsContent = forwardRef<
|
const TabsContent = forwardRef<
|
||||||
ElementRef<typeof TabsPrimitive.Content>,
|
ElementRef<typeof TabsPrimitive.Content>,
|
||||||
ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<TabsPrimitive.Content className={clsx(s.content, className)} ref={ref} {...props} />
|
<TabsPrimitive.Content className={clsx(s.content, className)} ref={ref} {...props} />
|
||||||
))
|
))
|
||||||
|
|
||||||
TabsContent.displayName = TabsPrimitive.Content.displayName
|
TabsContent.displayName = TabsPrimitive.Content.displayName
|
||||||
|
|||||||
@@ -3,33 +3,33 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||||||
import { TextField } from './'
|
import { TextField } from './'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
title: 'Components/TextField',
|
component: TextField,
|
||||||
component: TextField,
|
tags: ['autodocs'],
|
||||||
tags: ['autodocs'],
|
title: 'Components/TextField',
|
||||||
} satisfies Meta<typeof TextField>
|
} satisfies Meta<typeof TextField>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
type Story = StoryObj<typeof meta>
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
label: 'Label',
|
label: 'Label',
|
||||||
placeholder: 'Placeholder',
|
placeholder: 'Placeholder',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Password: Story = {
|
export const Password: Story = {
|
||||||
args: {
|
args: {
|
||||||
label: 'Label',
|
label: 'Label',
|
||||||
placeholder: 'Password',
|
placeholder: 'Password',
|
||||||
type: 'password',
|
type: 'password',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Error: Story = {
|
export const Error: Story = {
|
||||||
args: {
|
args: {
|
||||||
label: 'Input with error',
|
errorMessage: 'Error message',
|
||||||
value: 'Wrong value',
|
label: 'Input with error',
|
||||||
errorMessage: 'Error message',
|
value: 'Wrong value',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,91 +7,91 @@ import { clsx } from 'clsx'
|
|||||||
import s from './text-field.module.scss'
|
import s from './text-field.module.scss'
|
||||||
|
|
||||||
export type TextFieldProps = {
|
export type TextFieldProps = {
|
||||||
containerProps?: ComponentProps<'div'>
|
containerProps?: ComponentProps<'div'>
|
||||||
errorMessage?: string
|
errorMessage?: string
|
||||||
label?: string
|
label?: string
|
||||||
labelProps?: ComponentProps<'label'>
|
labelProps?: ComponentProps<'label'>
|
||||||
onValueChange?: (value: string) => void
|
onValueChange?: (value: string) => void
|
||||||
search?: boolean
|
search?: boolean
|
||||||
} & ComponentPropsWithoutRef<'input'>
|
} & ComponentPropsWithoutRef<'input'>
|
||||||
|
|
||||||
export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
|
export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
className,
|
className,
|
||||||
containerProps,
|
containerProps,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
label,
|
label,
|
||||||
labelProps,
|
labelProps,
|
||||||
onChange,
|
onChange,
|
||||||
onValueChange,
|
onValueChange,
|
||||||
placeholder,
|
placeholder,
|
||||||
search,
|
search,
|
||||||
type,
|
type,
|
||||||
...restProps
|
...restProps
|
||||||
},
|
},
|
||||||
ref
|
ref
|
||||||
) => {
|
) => {
|
||||||
const [showPassword, setShowPassword] = useState(false)
|
const [showPassword, setShowPassword] = useState(false)
|
||||||
|
|
||||||
const isShowPasswordButtonShown = type === 'password'
|
const isShowPasswordButtonShown = type === 'password'
|
||||||
|
|
||||||
const finalType = getFinalType(type, showPassword)
|
const finalType = getFinalType(type, showPassword)
|
||||||
|
|
||||||
function handleChange(e: ChangeEvent<HTMLInputElement>) {
|
function handleChange(e: ChangeEvent<HTMLInputElement>) {
|
||||||
onChange?.(e)
|
onChange?.(e)
|
||||||
onValueChange?.(e.target.value)
|
onValueChange?.(e.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const classNames = {
|
||||||
|
error: clsx(s.error),
|
||||||
|
field: clsx(s.field, !!errorMessage && s.error, search && s.hasLeadingIcon, className),
|
||||||
|
fieldContainer: clsx(s.fieldContainer),
|
||||||
|
label: clsx(s.label, labelProps?.className),
|
||||||
|
leadingIcon: s.leadingIcon,
|
||||||
|
root: clsx(s.root, containerProps?.className),
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classNames.root}>
|
||||||
|
{label && (
|
||||||
|
<Typography as={'label'} className={classNames.label} variant={'body2'}>
|
||||||
|
{label}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
<div className={classNames.fieldContainer}>
|
||||||
|
{search && <Search className={classNames.leadingIcon} />}
|
||||||
|
<input
|
||||||
|
className={classNames.field}
|
||||||
|
onChange={handleChange}
|
||||||
|
placeholder={placeholder}
|
||||||
|
ref={ref}
|
||||||
|
type={finalType}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
|
{isShowPasswordButtonShown && (
|
||||||
|
<button
|
||||||
|
className={s.showPassword}
|
||||||
|
onClick={() => setShowPassword(prev => !prev)}
|
||||||
|
type={'button'}
|
||||||
|
>
|
||||||
|
{showPassword ? <VisibilityOff /> : <Eye />}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Typography className={classNames.error} variant={'error'}>
|
||||||
|
{errorMessage}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const classNames = {
|
|
||||||
error: clsx(s.error),
|
|
||||||
field: clsx(s.field, !!errorMessage && s.error, search && s.hasLeadingIcon, className),
|
|
||||||
fieldContainer: clsx(s.fieldContainer),
|
|
||||||
label: clsx(s.label, labelProps?.className),
|
|
||||||
leadingIcon: s.leadingIcon,
|
|
||||||
root: clsx(s.root, containerProps?.className),
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classNames.root}>
|
|
||||||
{label && (
|
|
||||||
<Typography as={'label'} className={classNames.label} variant={'body2'}>
|
|
||||||
{label}
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
<div className={classNames.fieldContainer}>
|
|
||||||
{search && <Search className={classNames.leadingIcon} />}
|
|
||||||
<input
|
|
||||||
className={classNames.field}
|
|
||||||
onChange={handleChange}
|
|
||||||
placeholder={placeholder}
|
|
||||||
ref={ref}
|
|
||||||
type={finalType}
|
|
||||||
{...restProps}
|
|
||||||
/>
|
|
||||||
{isShowPasswordButtonShown && (
|
|
||||||
<button
|
|
||||||
className={s.showPassword}
|
|
||||||
onClick={() => setShowPassword(prev => !prev)}
|
|
||||||
type={'button'}
|
|
||||||
>
|
|
||||||
{showPassword ? <VisibilityOff /> : <Eye />}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Typography className={classNames.error} variant={'error'}>
|
|
||||||
{errorMessage}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
function getFinalType(type: ComponentProps<'input'>['type'], showPassword: boolean) {
|
function getFinalType(type: ComponentProps<'input'>['type'], showPassword: boolean) {
|
||||||
if (type === 'password' && showPassword) {
|
if (type === 'password' && showPassword) {
|
||||||
return 'text'
|
return 'text'
|
||||||
}
|
}
|
||||||
|
|
||||||
return type
|
return type
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,121 +3,121 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||||||
import { Typography } from './'
|
import { Typography } from './'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
argTypes: {
|
argTypes: {
|
||||||
variant: {
|
variant: {
|
||||||
control: { type: 'radio' },
|
control: { type: 'radio' },
|
||||||
options: [
|
options: [
|
||||||
'large',
|
'large',
|
||||||
'h1',
|
'h1',
|
||||||
'h2',
|
'h2',
|
||||||
'h3',
|
'h3',
|
||||||
'body1',
|
'body1',
|
||||||
'body2',
|
'body2',
|
||||||
'subtitle1',
|
'subtitle1',
|
||||||
'subtitle2',
|
'subtitle2',
|
||||||
'caption',
|
'caption',
|
||||||
'overline',
|
'overline',
|
||||||
'link1',
|
'link1',
|
||||||
'link2',
|
'link2',
|
||||||
'error',
|
'error',
|
||||||
],
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
component: Typography,
|
||||||
component: Typography,
|
tags: ['autodocs'],
|
||||||
tags: ['autodocs'],
|
title: 'Components/Typography',
|
||||||
title: 'Components/Typography',
|
|
||||||
} satisfies Meta<typeof Typography>
|
} satisfies Meta<typeof Typography>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
type Story = StoryObj<typeof meta>
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
export const Large: Story = {
|
export const Large: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Card content',
|
children: 'Card content',
|
||||||
variant: 'large',
|
variant: 'large',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const H1: Story = {
|
export const H1: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Card content',
|
children: 'Card content',
|
||||||
variant: 'h1',
|
variant: 'h1',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const H2: Story = {
|
export const H2: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Card content',
|
children: 'Card content',
|
||||||
variant: 'h2',
|
variant: 'h2',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const H3: Story = {
|
export const H3: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Card content',
|
children: 'Card content',
|
||||||
variant: 'h3',
|
variant: 'h3',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Body1: Story = {
|
export const Body1: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Card content',
|
children: 'Card content',
|
||||||
variant: 'body1',
|
variant: 'body1',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Body2: Story = {
|
export const Body2: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Card content',
|
children: 'Card content',
|
||||||
variant: 'body2',
|
variant: 'body2',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Subtitle1: Story = {
|
export const Subtitle1: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Card content',
|
children: 'Card content',
|
||||||
variant: 'subtitle1',
|
variant: 'subtitle1',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Subtitle2: Story = {
|
export const Subtitle2: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Card content',
|
children: 'Card content',
|
||||||
variant: 'subtitle2',
|
variant: 'subtitle2',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Caption: Story = {
|
export const Caption: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Card content',
|
children: 'Card content',
|
||||||
variant: 'caption',
|
variant: 'caption',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Overline: Story = {
|
export const Overline: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Card content',
|
children: 'Card content',
|
||||||
variant: 'overline',
|
variant: 'overline',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Link1: Story = {
|
export const Link1: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Card content',
|
children: 'Card content',
|
||||||
variant: 'link1',
|
variant: 'link1',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Link2: Story = {
|
export const Link2: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Card content',
|
children: 'Card content',
|
||||||
variant: 'link2',
|
variant: 'link2',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Error: Story = {
|
export const Error: Story = {
|
||||||
args: {
|
args: {
|
||||||
children: 'Card content',
|
children: 'Card content',
|
||||||
variant: 'error',
|
variant: 'error',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,33 +5,33 @@ import { clsx } from 'clsx'
|
|||||||
import s from './typography.module.scss'
|
import s from './typography.module.scss'
|
||||||
|
|
||||||
export interface TextProps<T extends ElementType> {
|
export interface TextProps<T extends ElementType> {
|
||||||
as?: T
|
as?: T
|
||||||
children?: ReactNode
|
children?: ReactNode
|
||||||
className?: string
|
className?: string
|
||||||
variant?:
|
variant?:
|
||||||
| 'body1'
|
| 'body1'
|
||||||
| 'body2'
|
| 'body2'
|
||||||
| 'caption'
|
| 'caption'
|
||||||
| 'error'
|
| 'error'
|
||||||
| 'h1'
|
| 'h1'
|
||||||
| 'h2'
|
| 'h2'
|
||||||
| 'h3'
|
| 'h3'
|
||||||
| 'large'
|
| 'large'
|
||||||
| 'link1'
|
| 'link1'
|
||||||
| 'link2'
|
| 'link2'
|
||||||
| 'overline'
|
| 'overline'
|
||||||
| 'subtitle1'
|
| 'subtitle1'
|
||||||
| 'subtitle2'
|
| 'subtitle2'
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Typography<T extends ElementType = 'p'>({
|
export function Typography<T extends ElementType = 'p'>({
|
||||||
as,
|
as,
|
||||||
className,
|
className,
|
||||||
variant = 'body1',
|
variant = 'body1',
|
||||||
...restProps
|
...restProps
|
||||||
}: TextProps<T> & Omit<ComponentPropsWithoutRef<T>, keyof TextProps<T>>) {
|
}: TextProps<T> & Omit<ComponentPropsWithoutRef<T>, keyof TextProps<T>>) {
|
||||||
const classNames = clsx(s.text, s[variant], className)
|
const classNames = clsx(s.text, s[variant], className)
|
||||||
const Component = as || 'p'
|
const Component = as || 'p'
|
||||||
|
|
||||||
return <Component className={classNames} {...restProps} />
|
return <Component className={classNames} {...restProps} />
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import '@fontsource/roboto/700.css'
|
|||||||
import './styles/index.scss'
|
import './styles/index.scss'
|
||||||
|
|
||||||
createRoot(document.getElementById('root')!).render(
|
createRoot(document.getElementById('root')!).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<App />
|
<App />
|
||||||
</StrictMode>
|
</StrictMode>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
|
||||||
import { Button, Page, Slider, TextField, Typography } from '@/components'
|
import { Button, Page, Slider, TextField, Typography } from '@/components'
|
||||||
|
import { DecksTable } from '@/components'
|
||||||
import { DeckDialog } from '@/components/decks/deck-dialog'
|
import { DeckDialog } from '@/components/decks/deck-dialog'
|
||||||
import { DecksTable } from '@/components/decks/decks-table'
|
|
||||||
import { DeleteDeckDialog } from '@/components/decks/delete-deck-dialog'
|
import { DeleteDeckDialog } from '@/components/decks/delete-deck-dialog'
|
||||||
import { Pagination } from '@/components/ui/pagination'
|
import { Pagination } from '@/components/ui/pagination'
|
||||||
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { Page, SignIn } from '@/components'
|
import { Page, SignIn } from '@/components'
|
||||||
|
|
||||||
export const SignInPage = () => {
|
export const SignInPage = () => {
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
<SignIn onSubmit={() => {}} />
|
<SignIn onSubmit={() => {}} />
|
||||||
</Page>
|
</Page>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,51 +1,51 @@
|
|||||||
import {
|
import {
|
||||||
Navigate,
|
Navigate,
|
||||||
Outlet,
|
Outlet,
|
||||||
RouteObject,
|
RouteObject,
|
||||||
RouterProvider,
|
RouterProvider,
|
||||||
createBrowserRouter,
|
createBrowserRouter,
|
||||||
} from 'react-router-dom'
|
} from 'react-router-dom'
|
||||||
|
|
||||||
import { DecksPage, SignInPage } from './pages'
|
import { DecksPage, SignInPage } from './pages'
|
||||||
import { DeckPage } from '@/pages/deck-page/deck-page'
|
import { DeckPage } from '@/pages/deck-page/deck-page'
|
||||||
|
|
||||||
const publicRoutes: RouteObject[] = [
|
const publicRoutes: RouteObject[] = [
|
||||||
{
|
{
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
element: <SignInPage />,
|
element: <SignInPage />,
|
||||||
path: '/login',
|
path: '/login',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
element: <Outlet />,
|
element: <Outlet />,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const privateRoutes: RouteObject[] = [
|
const privateRoutes: RouteObject[] = [
|
||||||
{
|
{
|
||||||
element: <DecksPage />,
|
element: <DecksPage />,
|
||||||
path: '/',
|
path: '/',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
element: <DeckPage />,
|
element: <DeckPage />,
|
||||||
path: '/decks/:deckId',
|
path: '/decks/:deckId',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
{
|
{
|
||||||
children: privateRoutes,
|
children: privateRoutes,
|
||||||
element: <PrivateRoutes />,
|
element: <PrivateRoutes />,
|
||||||
},
|
},
|
||||||
...publicRoutes,
|
...publicRoutes,
|
||||||
])
|
])
|
||||||
|
|
||||||
export const Router = () => {
|
export const Router = () => {
|
||||||
return <RouterProvider router={router} />
|
return <RouterProvider router={router} />
|
||||||
}
|
}
|
||||||
|
|
||||||
function PrivateRoutes() {
|
function PrivateRoutes() {
|
||||||
const isAuthenticated = true
|
const isAuthenticated = true
|
||||||
|
|
||||||
return isAuthenticated ? <Outlet /> : <Navigate to={'/login'} />
|
return isAuthenticated ? <Outlet /> : <Navigate to={'/login'} />
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
|
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
|
||||||
|
|
||||||
export const baseApi = createApi({
|
export const baseApi = createApi({
|
||||||
baseQuery: fetchBaseQuery({
|
baseQuery: fetchBaseQuery({
|
||||||
baseUrl: 'https://api.flashcards.andrii.es',
|
baseUrl: 'https://api.flashcards.andrii.es',
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
prepareHeaders: headers => {
|
prepareHeaders: headers => {
|
||||||
headers.append('x-auth-skip', 'true')
|
headers.append('x-auth-skip', 'true')
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
endpoints: () => ({}),
|
endpoints: () => ({}),
|
||||||
reducerPath: 'baseApi',
|
reducerPath: 'baseApi',
|
||||||
tagTypes: ['Decks'],
|
tagTypes: ['Decks'],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,68 +1,68 @@
|
|||||||
import {
|
import {
|
||||||
CardsResponse,
|
CardsResponse,
|
||||||
CreateDeckArgs,
|
CreateDeckArgs,
|
||||||
DeckResponse,
|
DeckResponse,
|
||||||
DecksResponse,
|
DecksResponse,
|
||||||
GetDecksArgs,
|
GetDecksArgs,
|
||||||
UpdateDeckArgs,
|
UpdateDeckArgs,
|
||||||
} from './decks.types'
|
} from './decks.types'
|
||||||
import { baseApi } from '@/services'
|
import { baseApi } from '@/services'
|
||||||
|
|
||||||
const decksService = baseApi.injectEndpoints({
|
const decksService = baseApi.injectEndpoints({
|
||||||
endpoints: builder => ({
|
endpoints: builder => ({
|
||||||
createDeck: builder.mutation<DeckResponse, CreateDeckArgs>({
|
createDeck: builder.mutation<DeckResponse, CreateDeckArgs>({
|
||||||
invalidatesTags: ['Decks'],
|
invalidatesTags: ['Decks'],
|
||||||
onQueryStarted: async (_, { dispatch, getCacheEntry, getState, queryFulfilled }) => {
|
onQueryStarted: async (_, { dispatch, getCacheEntry, getState, queryFulfilled }) => {
|
||||||
const data = getCacheEntry()
|
const data = getCacheEntry()
|
||||||
const state = getState()
|
const state = getState()
|
||||||
|
|
||||||
decksService.util.re
|
decksService.util.re
|
||||||
await queryFulfilled
|
await queryFulfilled
|
||||||
},
|
},
|
||||||
query: body => ({
|
query: body => ({
|
||||||
body,
|
body,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: `v1/decks`,
|
url: `v1/decks`,
|
||||||
}),
|
}),
|
||||||
|
}),
|
||||||
|
deleteDeck: builder.mutation<void, { id: string }>({
|
||||||
|
invalidatesTags: ['Decks'],
|
||||||
|
query: ({ id }) => ({
|
||||||
|
method: 'DELETE',
|
||||||
|
url: `v1/decks/${id}`,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
getDeckById: builder.query<DeckResponse, { id: string }>({
|
||||||
|
query: ({ id }) => `v1/decks/${id}`,
|
||||||
|
}),
|
||||||
|
getDeckCards: builder.query<CardsResponse, { id: string }>({
|
||||||
|
query: ({ id }) => `v1/decks/${id}/cards`,
|
||||||
|
}),
|
||||||
|
getDecks: builder.query<DecksResponse, GetDecksArgs | void>({
|
||||||
|
providesTags: ['Decks'],
|
||||||
|
query: args => {
|
||||||
|
return {
|
||||||
|
params: args ?? undefined,
|
||||||
|
url: `v1/decks`,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
updateDeck: builder.mutation<DeckResponse, UpdateDeckArgs>({
|
||||||
|
invalidatesTags: ['Decks'],
|
||||||
|
query: ({ id, ...body }) => ({
|
||||||
|
body,
|
||||||
|
method: 'PATCH',
|
||||||
|
url: `v1/decks/${id}`,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
deleteDeck: builder.mutation<void, { id: string }>({
|
|
||||||
invalidatesTags: ['Decks'],
|
|
||||||
query: ({ id }) => ({
|
|
||||||
method: 'DELETE',
|
|
||||||
url: `v1/decks/${id}`,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
getDeckById: builder.query<DeckResponse, { id: string }>({
|
|
||||||
query: ({ id }) => `v1/decks/${id}`,
|
|
||||||
}),
|
|
||||||
getDeckCards: builder.query<CardsResponse, { id: string }>({
|
|
||||||
query: ({ id }) => `v1/decks/${id}/cards`,
|
|
||||||
}),
|
|
||||||
getDecks: builder.query<DecksResponse, GetDecksArgs | void>({
|
|
||||||
providesTags: ['Decks'],
|
|
||||||
query: args => {
|
|
||||||
return {
|
|
||||||
params: args ?? undefined,
|
|
||||||
url: `v1/decks`,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
updateDeck: builder.mutation<DeckResponse, UpdateDeckArgs>({
|
|
||||||
invalidatesTags: ['Decks'],
|
|
||||||
query: ({ id, ...body }) => ({
|
|
||||||
body,
|
|
||||||
method: 'PATCH',
|
|
||||||
url: `v1/decks/${id}`,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
useCreateDeckMutation,
|
useCreateDeckMutation,
|
||||||
useDeleteDeckMutation,
|
useDeleteDeckMutation,
|
||||||
useGetDeckByIdQuery,
|
useGetDeckByIdQuery,
|
||||||
useGetDeckCardsQuery,
|
useGetDeckCardsQuery,
|
||||||
useGetDecksQuery,
|
useGetDecksQuery,
|
||||||
useUpdateDeckMutation,
|
useUpdateDeckMutation,
|
||||||
} = decksService
|
} = decksService
|
||||||
|
|||||||
@@ -1,44 +1,43 @@
|
|||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
|
||||||
|
|
||||||
import { Tab } from '@/services'
|
import { Tab } from '@/services'
|
||||||
|
import { PayloadAction, createSlice } from '@reduxjs/toolkit'
|
||||||
|
|
||||||
export const decksSlice = createSlice({
|
export const decksSlice = createSlice({
|
||||||
name: 'decks',
|
initialState: {
|
||||||
initialState: {
|
currentPage: 1,
|
||||||
currentPage: 1,
|
currentTab: 'all' as Tab,
|
||||||
perPage: 10,
|
maxCards: undefined as number | undefined,
|
||||||
search: '',
|
minCards: 0,
|
||||||
minCards: 0,
|
perPage: 10,
|
||||||
maxCards: undefined as number | undefined,
|
search: '',
|
||||||
currentTab: 'all' as Tab,
|
|
||||||
},
|
|
||||||
reducers: {
|
|
||||||
setCurrentPage: (state, action: PayloadAction<number>) => {
|
|
||||||
state.currentPage = action.payload
|
|
||||||
},
|
},
|
||||||
setPerPage: (state, action: PayloadAction<number>) => {
|
name: 'decks',
|
||||||
state.perPage = action.payload
|
reducers: {
|
||||||
|
resetCurrentPage: state => {
|
||||||
|
state.currentPage = 1
|
||||||
|
},
|
||||||
|
resetFilters: state => {
|
||||||
|
state.search = ''
|
||||||
|
state.currentTab = 'all'
|
||||||
|
state.minCards = 0
|
||||||
|
state.maxCards = undefined
|
||||||
|
},
|
||||||
|
setCurrentPage: (state, action: PayloadAction<number>) => {
|
||||||
|
state.currentPage = action.payload
|
||||||
|
},
|
||||||
|
setCurrentTab: (state, action: PayloadAction<Tab>) => {
|
||||||
|
state.currentTab = action.payload
|
||||||
|
},
|
||||||
|
setMaxCards: (state, action: PayloadAction<number>) => {
|
||||||
|
state.maxCards = action.payload
|
||||||
|
},
|
||||||
|
setMinCards: (state, action: PayloadAction<number>) => {
|
||||||
|
state.minCards = action.payload
|
||||||
|
},
|
||||||
|
setPerPage: (state, action: PayloadAction<number>) => {
|
||||||
|
state.perPage = action.payload
|
||||||
|
},
|
||||||
|
setSearch: (state, action: PayloadAction<string>) => {
|
||||||
|
state.search = action.payload
|
||||||
|
},
|
||||||
},
|
},
|
||||||
setSearch: (state, action: PayloadAction<string>) => {
|
|
||||||
state.search = action.payload
|
|
||||||
},
|
|
||||||
setCurrentTab: (state, action: PayloadAction<Tab>) => {
|
|
||||||
state.currentTab = action.payload
|
|
||||||
},
|
|
||||||
setMinCards: (state, action: PayloadAction<number>) => {
|
|
||||||
state.minCards = action.payload
|
|
||||||
},
|
|
||||||
setMaxCards: (state, action: PayloadAction<number>) => {
|
|
||||||
state.maxCards = action.payload
|
|
||||||
},
|
|
||||||
resetFilters: state => {
|
|
||||||
state.search = ''
|
|
||||||
state.currentTab = 'all'
|
|
||||||
state.minCards = 0
|
|
||||||
state.maxCards = undefined
|
|
||||||
},
|
|
||||||
resetCurrentPage: state => {
|
|
||||||
state.currentPage = 1
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,72 +1,72 @@
|
|||||||
export type Pagination = {
|
export type Pagination = {
|
||||||
totalPages: number
|
currentPage: number
|
||||||
currentPage: number
|
itemsPerPage: number
|
||||||
itemsPerPage: number
|
totalItems: number
|
||||||
totalItems: number
|
totalPages: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Author = {
|
export type Author = {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Deck = {
|
export type Deck = {
|
||||||
id: string
|
author: Author
|
||||||
userId: string
|
cardsCount: number
|
||||||
name: string
|
cover?: null | string
|
||||||
isPrivate: boolean
|
created: string
|
||||||
shots: number
|
id: string
|
||||||
cover?: string | null
|
isBlocked?: boolean | null
|
||||||
rating: number
|
isDeleted: boolean | null
|
||||||
isDeleted: boolean | null
|
isPrivate: boolean
|
||||||
isBlocked?: boolean | null
|
name: string
|
||||||
created: string
|
rating: number
|
||||||
updated: string
|
shots: number
|
||||||
cardsCount: number
|
updated: string
|
||||||
author: Author
|
userId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DecksResponse = {
|
export type DecksResponse = {
|
||||||
maxCardsCount: number
|
items: Deck[]
|
||||||
pagination: Pagination
|
maxCardsCount: number
|
||||||
items: Deck[]
|
pagination: Pagination
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DeckResponse = Deck
|
export type DeckResponse = Deck
|
||||||
|
|
||||||
export type CardsResponse = {
|
export type CardsResponse = {
|
||||||
pagination: Pagination
|
items: Card[]
|
||||||
items: Card[]
|
pagination: Pagination
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Card = {
|
export type Card = {
|
||||||
id: string
|
answer: string
|
||||||
question: string
|
answerImg?: null | string
|
||||||
answer: string
|
created: string
|
||||||
deckId: string
|
deckId: string
|
||||||
questionImg?: string | null
|
grade: number
|
||||||
answerImg?: string | null
|
id: string
|
||||||
created: string
|
question: string
|
||||||
updated: string
|
questionImg?: null | string
|
||||||
shots: number
|
shots: number
|
||||||
grade: number
|
updated: string
|
||||||
userId: string
|
userId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GetDecksArgs = {
|
export type GetDecksArgs = {
|
||||||
minCardsCount?: number
|
authorId?: string
|
||||||
maxCardsCount?: number
|
currentPage?: number
|
||||||
name?: string
|
itemsPerPage?: number
|
||||||
authorId?: string
|
maxCardsCount?: number
|
||||||
orderBy?: string
|
minCardsCount?: number
|
||||||
currentPage?: number
|
name?: string
|
||||||
itemsPerPage?: number
|
orderBy?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CreateDeckArgs = {
|
export type CreateDeckArgs = {
|
||||||
name: string
|
cover?: string
|
||||||
isPrivate?: boolean
|
isPrivate?: boolean
|
||||||
cover?: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UpdateDeckArgs = Partial<CreateDeckArgs> & { id: Deck['id'] }
|
export type UpdateDeckArgs = Partial<CreateDeckArgs> & { id: Deck['id'] }
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import { configureStore } from '@reduxjs/toolkit'
|
|||||||
import { setupListeners } from '@reduxjs/toolkit/query/react'
|
import { setupListeners } from '@reduxjs/toolkit/query/react'
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
middleware: getDefaultMiddleware => getDefaultMiddleware().concat(baseApi.middleware),
|
middleware: getDefaultMiddleware => getDefaultMiddleware().concat(baseApi.middleware),
|
||||||
reducer: {
|
reducer: {
|
||||||
[baseApi.reducerPath]: baseApi.reducer,
|
[baseApi.reducerPath]: baseApi.reducer,
|
||||||
[decksSlice.name]: decksSlice.reducer,
|
[decksSlice.name]: decksSlice.reducer,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export type AppDispatch = typeof store.dispatch
|
export type AppDispatch = typeof store.dispatch
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
export function formatDate(date: string | undefined) {
|
export function formatDate(date: string | undefined) {
|
||||||
if (!date) return ''
|
if (!date) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
return new Date(date).toLocaleDateString('ru-RU')
|
return new Date(date).toLocaleDateString('ru-RU')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { defineConfig } from 'vite'
|
|||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: [{ find: '@', replacement: path.resolve(__dirname, 'src') }],
|
alias: [{ find: '@', replacement: path.resolve(__dirname, 'src') }],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user