Merge pull request #5 from instat/OTT-36-login-register-components
Ott 36 login register componentskeep-around/af30b88d367751c9e05a735e4a0467a96238ef47
commit
556669f303
|
After Width: | Height: | Size: 695 B |
|
After Width: | Height: | Size: 696 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 860 B |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 853 B |
@ -1,7 +1,9 @@ |
|||||||
import React from 'react' |
import React from 'react' |
||||||
|
|
||||||
|
import { Theme } from 'features/Theme' |
||||||
|
|
||||||
export const App = () => ( |
export const App = () => ( |
||||||
<div> |
<Theme> |
||||||
Instat TV |
Instat TV |
||||||
</div> |
</Theme> |
||||||
) |
) |
||||||
|
|||||||
@ -1,19 +0,0 @@ |
|||||||
import React, { ReactNode } from 'react' |
|
||||||
|
|
||||||
type ButtonProps = { |
|
||||||
children: ReactNode, |
|
||||||
|
|
||||||
/** |
|
||||||
* Simple click handler |
|
||||||
*/ |
|
||||||
onClick?: () => void, |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* The world's most _basic_ button |
|
||||||
*/ |
|
||||||
export const Button = ({ children, onClick }: ButtonProps) => ( |
|
||||||
<button onClick={onClick} type='button'> |
|
||||||
{children} |
|
||||||
</button> |
|
||||||
) |
|
||||||
@ -1,20 +0,0 @@ |
|||||||
import React from 'react' |
|
||||||
|
|
||||||
import { action } from '@storybook/addon-actions' |
|
||||||
|
|
||||||
import { Button } from 'features/Button' |
|
||||||
|
|
||||||
export default { |
|
||||||
component: Button, |
|
||||||
title: 'Button', |
|
||||||
} |
|
||||||
|
|
||||||
export const Text = () => <Button onClick={action('clicked')}>Hello Button</Button> |
|
||||||
|
|
||||||
export const Emoji = () => ( |
|
||||||
<Button onClick={action('clicked')}> |
|
||||||
<span role='img' aria-label='so cool'> |
|
||||||
😀 😎 👍 💯 |
|
||||||
</span> |
|
||||||
</Button> |
|
||||||
) |
|
||||||
@ -0,0 +1,28 @@ |
|||||||
|
import styled from 'styled-components/macro' |
||||||
|
|
||||||
|
const ArrowStyled = styled.button` |
||||||
|
width: 40px; |
||||||
|
height: 40px; |
||||||
|
padding: 0; |
||||||
|
border: 1px solid transparent; |
||||||
|
border-radius: 50%; |
||||||
|
background-color: transparent; |
||||||
|
background-position: center; |
||||||
|
outline: none; |
||||||
|
|
||||||
|
:active { |
||||||
|
background-color: rgba(117, 117, 117, 1); |
||||||
|
} |
||||||
|
|
||||||
|
:hover, :focus { |
||||||
|
background-color: rgba(117, 117, 117, 0.5); |
||||||
|
} |
||||||
|
` |
||||||
|
|
||||||
|
export const ArrowLeft = styled(ArrowStyled)` |
||||||
|
background-image: url(/images/arrowLeft.svg); |
||||||
|
` |
||||||
|
|
||||||
|
export const ArrowRight = styled(ArrowStyled)` |
||||||
|
background-image: url(/images/arrowRight.svg); |
||||||
|
` |
||||||
@ -0,0 +1,21 @@ |
|||||||
|
import React from 'react' |
||||||
|
|
||||||
|
import { ArrowLeft, ArrowRight } from 'features/Common' |
||||||
|
|
||||||
|
export default { |
||||||
|
component: ArrowLeft, |
||||||
|
title: 'Arrows', |
||||||
|
} |
||||||
|
|
||||||
|
const backgroundStyles = { |
||||||
|
backgroundColor: '#333', |
||||||
|
height: '200px', |
||||||
|
padding: '20px', |
||||||
|
} |
||||||
|
|
||||||
|
export const Group = () => ( |
||||||
|
<div style={backgroundStyles}> |
||||||
|
<ArrowLeft /> |
||||||
|
<ArrowRight /> |
||||||
|
</div> |
||||||
|
) |
||||||
@ -0,0 +1 @@ |
|||||||
|
export * from './styled' |
||||||
@ -0,0 +1,21 @@ |
|||||||
|
import React from 'react' |
||||||
|
|
||||||
|
import { action } from '@storybook/addon-actions' |
||||||
|
|
||||||
|
import { ButtonOutline, ButtonSolid } from 'features/Common' |
||||||
|
|
||||||
|
export default { |
||||||
|
title: 'Button', |
||||||
|
} |
||||||
|
|
||||||
|
export const Solid = () => ( |
||||||
|
<ButtonSolid onClick={action('clicked')}> |
||||||
|
Solid |
||||||
|
</ButtonSolid> |
||||||
|
) |
||||||
|
|
||||||
|
export const Outline = () => ( |
||||||
|
<ButtonOutline onClick={action('clicked')}> |
||||||
|
Outline |
||||||
|
</ButtonOutline> |
||||||
|
) |
||||||
@ -0,0 +1,44 @@ |
|||||||
|
import styled, { css } from 'styled-components/macro' |
||||||
|
|
||||||
|
const baseButtonStyles = css` |
||||||
|
width: 272px; |
||||||
|
height: 48px; |
||||||
|
border-width: 0.7px; |
||||||
|
border-style: solid; |
||||||
|
border-radius: 2px; |
||||||
|
padding: 0 12px; |
||||||
|
|
||||||
|
font-style: normal; |
||||||
|
font-size: 20px; |
||||||
|
outline-color: white; |
||||||
|
` |
||||||
|
|
||||||
|
export const outlineButtonStyles = css` |
||||||
|
${baseButtonStyles} |
||||||
|
|
||||||
|
padding-top: 8.6px; |
||||||
|
padding-bottom: 10.6px; |
||||||
|
color: ${({ theme: { colors } }) => colors.secondary}; |
||||||
|
font-weight: normal; |
||||||
|
border-color: ${({ theme: { colors } }) => colors.secondary}; |
||||||
|
background: transparent; |
||||||
|
` |
||||||
|
|
||||||
|
export const solidButtonStyles = css` |
||||||
|
${baseButtonStyles} |
||||||
|
|
||||||
|
padding-top: 18.5px; |
||||||
|
padding-bottom: 13px; |
||||||
|
color: #FFFFFF; |
||||||
|
font-weight: bold; |
||||||
|
border-color: transparent; |
||||||
|
background: ${({ theme: { colors } }) => colors.primary}; |
||||||
|
` |
||||||
|
|
||||||
|
export const ButtonSolid = styled.button` |
||||||
|
${solidButtonStyles} |
||||||
|
` |
||||||
|
|
||||||
|
export const ButtonOutline = styled.button` |
||||||
|
${outlineButtonStyles} |
||||||
|
` |
||||||
@ -0,0 +1,38 @@ |
|||||||
|
import React, { InputHTMLAttributes } from 'react' |
||||||
|
|
||||||
|
import { |
||||||
|
Wrapper, |
||||||
|
Input, |
||||||
|
Label, |
||||||
|
} from './styled' |
||||||
|
|
||||||
|
type TCheckbox = Pick<InputHTMLAttributes<HTMLInputElement>, ( |
||||||
|
| 'checked' |
||||||
|
| 'id' |
||||||
|
| 'name' |
||||||
|
| 'value' |
||||||
|
| 'onChange' |
||||||
|
)> & { |
||||||
|
label?: string, |
||||||
|
} |
||||||
|
|
||||||
|
export const Checkbox = ({ |
||||||
|
checked, |
||||||
|
id, |
||||||
|
label, |
||||||
|
name, |
||||||
|
onChange, |
||||||
|
value, |
||||||
|
}: TCheckbox) => ( |
||||||
|
<Wrapper> |
||||||
|
<Input |
||||||
|
id={id} |
||||||
|
type='checkbox' |
||||||
|
name={name} |
||||||
|
value={value} |
||||||
|
checked={checked} |
||||||
|
onChange={onChange} |
||||||
|
/> |
||||||
|
<Label htmlFor={id}>{label}</Label> |
||||||
|
</Wrapper> |
||||||
|
) |
||||||
@ -0,0 +1,28 @@ |
|||||||
|
import React from 'react' |
||||||
|
|
||||||
|
import { Checkbox } from 'features/Common' |
||||||
|
|
||||||
|
export default { |
||||||
|
component: Checkbox, |
||||||
|
title: 'Checkbox', |
||||||
|
} |
||||||
|
|
||||||
|
const backgroundStyles = { |
||||||
|
backgroundColor: '#333', |
||||||
|
height: '200px', |
||||||
|
padding: '20px', |
||||||
|
} |
||||||
|
|
||||||
|
export const Group = () => ( |
||||||
|
<div style={backgroundStyles}> |
||||||
|
<Checkbox |
||||||
|
id='primeraDivisión' |
||||||
|
label='Primera División' |
||||||
|
checked |
||||||
|
/> |
||||||
|
<Checkbox |
||||||
|
id='manchesterUnited' |
||||||
|
label='Manchester United' |
||||||
|
/> |
||||||
|
</div> |
||||||
|
) |
||||||
@ -0,0 +1,40 @@ |
|||||||
|
import styled from 'styled-components/macro' |
||||||
|
|
||||||
|
export const Wrapper = styled.div` |
||||||
|
|
||||||
|
` |
||||||
|
|
||||||
|
export const Label = styled.label` |
||||||
|
color: ${({ theme: { colors } }) => colors.text}; |
||||||
|
font-style: normal; |
||||||
|
font-weight: bold; |
||||||
|
font-size: 18px; |
||||||
|
line-height: 21px; |
||||||
|
` |
||||||
|
|
||||||
|
export const Input = styled.input` |
||||||
|
position: absolute; |
||||||
|
z-index: -1; |
||||||
|
opacity: 0; |
||||||
|
|
||||||
|
&+${Label} { |
||||||
|
display: inline-flex; |
||||||
|
align-items: center; |
||||||
|
user-select: none; |
||||||
|
} |
||||||
|
|
||||||
|
&+${Label}::before { |
||||||
|
content: ''; |
||||||
|
display: inline-block; |
||||||
|
width: 24px; |
||||||
|
height: 24px; |
||||||
|
margin-right: 22px; |
||||||
|
background-repeat: no-repeat; |
||||||
|
background-position: center center; |
||||||
|
background-image: url(/images/checkboxUnchecked.svg); |
||||||
|
} |
||||||
|
|
||||||
|
&:checked+${Label}::before { |
||||||
|
background-image: url(/images/checkboxChecked.svg); |
||||||
|
} |
||||||
|
` |
||||||
@ -0,0 +1,58 @@ |
|||||||
|
import React from 'react' |
||||||
|
|
||||||
|
import { |
||||||
|
TInputWrapper, |
||||||
|
InputWrapper, |
||||||
|
InputStyled, |
||||||
|
Label, |
||||||
|
} from './styled' |
||||||
|
|
||||||
|
type TInput = { |
||||||
|
defaultValue?: string, |
||||||
|
id: string, |
||||||
|
inputWidth?: number, |
||||||
|
label: string, |
||||||
|
labelWidth?: number, |
||||||
|
maxLength?: number, |
||||||
|
onChange?: () => void, |
||||||
|
required?: boolean, |
||||||
|
type?: string, |
||||||
|
value?: string, |
||||||
|
} & TInputWrapper |
||||||
|
|
||||||
|
export const Input = ({ |
||||||
|
defaultValue, |
||||||
|
id, |
||||||
|
inputWidth, |
||||||
|
label, |
||||||
|
labelWidth, |
||||||
|
maxLength, |
||||||
|
onChange, |
||||||
|
paddingX, |
||||||
|
required, |
||||||
|
type, |
||||||
|
value, |
||||||
|
wrapperWidth, |
||||||
|
}: TInput) => ( |
||||||
|
<InputWrapper |
||||||
|
wrapperWidth={wrapperWidth} |
||||||
|
paddingX={paddingX} |
||||||
|
> |
||||||
|
<Label |
||||||
|
htmlFor={id} |
||||||
|
labelWidth={labelWidth} |
||||||
|
> |
||||||
|
{label} |
||||||
|
</Label> |
||||||
|
<InputStyled |
||||||
|
id={id} |
||||||
|
type={type} |
||||||
|
required={required} |
||||||
|
value={value} |
||||||
|
defaultValue={defaultValue} |
||||||
|
onChange={onChange} |
||||||
|
maxLength={maxLength} |
||||||
|
inputWidth={inputWidth} |
||||||
|
/> |
||||||
|
</InputWrapper> |
||||||
|
) |
||||||
@ -0,0 +1,35 @@ |
|||||||
|
import React, { Fragment } from 'react' |
||||||
|
|
||||||
|
import { Input } from 'features/Common' |
||||||
|
|
||||||
|
export default { |
||||||
|
component: Input, |
||||||
|
title: 'Input', |
||||||
|
} |
||||||
|
|
||||||
|
export const Empty = () => ( |
||||||
|
<Input |
||||||
|
id='email' |
||||||
|
type='email' |
||||||
|
label='Email' |
||||||
|
/> |
||||||
|
) |
||||||
|
|
||||||
|
export const EmailPassword = () => ( |
||||||
|
<Fragment> |
||||||
|
<Input |
||||||
|
id='email' |
||||||
|
type='email' |
||||||
|
label='Email' |
||||||
|
labelWidth={72} |
||||||
|
defaultValue='someveeeeeeeeerylooooooooong@email.com' |
||||||
|
/> |
||||||
|
<Input |
||||||
|
id='password' |
||||||
|
type='password' |
||||||
|
label='Password' |
||||||
|
labelWidth={72} |
||||||
|
defaultValue='abcdefgh' |
||||||
|
/> |
||||||
|
</Fragment> |
||||||
|
) |
||||||
@ -0,0 +1,70 @@ |
|||||||
|
import styled from 'styled-components/macro' |
||||||
|
|
||||||
|
export type TInputWrapper = { |
||||||
|
paddingX?: number, |
||||||
|
wrapperWidth?: number, |
||||||
|
} |
||||||
|
|
||||||
|
export const InputWrapper = styled.div<TInputWrapper>` |
||||||
|
width: ${({ wrapperWidth }) => (wrapperWidth ? `${wrapperWidth}px` : '100%')}; |
||||||
|
height: 48px; |
||||||
|
margin: 20px 0; |
||||||
|
padding-left: ${({ paddingX = 24 }) => (paddingX ? `${paddingX}px` : '')}; |
||||||
|
padding-right: ${({ paddingX = 24 }) => (paddingX ? `${paddingX}px` : '')}; |
||||||
|
padding-top: 13px; |
||||||
|
padding-bottom: 11px; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
background-color: #3F3F3F; |
||||||
|
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.3); |
||||||
|
border-radius: 2px; |
||||||
|
` |
||||||
|
|
||||||
|
type TLabel = { |
||||||
|
labelWidth?: number, |
||||||
|
} |
||||||
|
|
||||||
|
export const Label = styled.label<TLabel>` |
||||||
|
font-style: normal; |
||||||
|
font-weight: normal; |
||||||
|
font-size: 16px; |
||||||
|
line-height: 24px; |
||||||
|
letter-spacing: -0.01em; |
||||||
|
padding-top: 2px; |
||||||
|
color: ${({ theme: { colors } }) => colors.secondary}; |
||||||
|
width: ${({ labelWidth }) => (labelWidth ? `${labelWidth}px` : '')}; |
||||||
|
` |
||||||
|
|
||||||
|
type TInputStyled = { |
||||||
|
inputWidth?: number, |
||||||
|
} |
||||||
|
|
||||||
|
export const InputStyled = styled.input<TInputStyled>` |
||||||
|
flex-grow: 1; |
||||||
|
font-weight: bold; |
||||||
|
font-size: 20px; |
||||||
|
line-height: 24px; |
||||||
|
width: ${({ inputWidth }) => (inputWidth ? `${inputWidth}px` : '')}; |
||||||
|
background-color: transparent; |
||||||
|
border: transparent; |
||||||
|
margin-left: 24px; |
||||||
|
color: ${({ theme: { colors } }) => colors.text}; |
||||||
|
|
||||||
|
&[type='password'] { |
||||||
|
letter-spacing: 6px; |
||||||
|
} |
||||||
|
|
||||||
|
:focus { |
||||||
|
border-color: transparent; |
||||||
|
outline: none; |
||||||
|
} |
||||||
|
|
||||||
|
:-webkit-autofill, |
||||||
|
:-webkit-autofill:hover, |
||||||
|
:-webkit-autofill:focus, |
||||||
|
:-webkit-autofill:active { |
||||||
|
box-shadow: 0 0 0 30px #3F3F3F inset; |
||||||
|
caret-color: ${({ theme: { colors } }) => colors.text}; |
||||||
|
-webkit-text-fill-color: ${({ theme: { colors } }) => colors.text}; |
||||||
|
} |
||||||
|
` |
||||||
@ -0,0 +1,38 @@ |
|||||||
|
import React, { InputHTMLAttributes } from 'react' |
||||||
|
|
||||||
|
import { |
||||||
|
Wrapper, |
||||||
|
Input, |
||||||
|
Label, |
||||||
|
} from './styled' |
||||||
|
|
||||||
|
type TCheckbox = Pick<InputHTMLAttributes<HTMLInputElement>, ( |
||||||
|
| 'checked' |
||||||
|
| 'id' |
||||||
|
| 'name' |
||||||
|
| 'value' |
||||||
|
| 'onChange' |
||||||
|
)> & { |
||||||
|
label?: string, |
||||||
|
} |
||||||
|
|
||||||
|
export const Radio = ({ |
||||||
|
checked, |
||||||
|
id, |
||||||
|
label, |
||||||
|
name, |
||||||
|
onChange, |
||||||
|
value, |
||||||
|
}: TCheckbox) => ( |
||||||
|
<Wrapper> |
||||||
|
<Input |
||||||
|
id={id} |
||||||
|
type='radio' |
||||||
|
name={name} |
||||||
|
value={value} |
||||||
|
checked={checked} |
||||||
|
onChange={onChange} |
||||||
|
/> |
||||||
|
<Label htmlFor={id}>{label}</Label> |
||||||
|
</Wrapper> |
||||||
|
) |
||||||
@ -0,0 +1,30 @@ |
|||||||
|
import React from 'react' |
||||||
|
|
||||||
|
import { Radio } from 'features/Common' |
||||||
|
|
||||||
|
export default { |
||||||
|
component: Radio, |
||||||
|
title: 'Radio', |
||||||
|
} |
||||||
|
|
||||||
|
const backgroundStyles = { |
||||||
|
backgroundColor: '#333', |
||||||
|
height: '200px', |
||||||
|
padding: '20px', |
||||||
|
} |
||||||
|
|
||||||
|
export const Group = () => ( |
||||||
|
<div style={backgroundStyles}> |
||||||
|
<Radio |
||||||
|
id='primeraDivisión' |
||||||
|
label='Primera División' |
||||||
|
name='team' |
||||||
|
checked |
||||||
|
/> |
||||||
|
<Radio |
||||||
|
id='manchesterUnited' |
||||||
|
label='Manchester United' |
||||||
|
name='team' |
||||||
|
/> |
||||||
|
</div> |
||||||
|
) |
||||||
@ -0,0 +1,40 @@ |
|||||||
|
import styled from 'styled-components/macro' |
||||||
|
|
||||||
|
export const Wrapper = styled.div` |
||||||
|
|
||||||
|
` |
||||||
|
|
||||||
|
export const Label = styled.label` |
||||||
|
color: ${({ theme: { colors } }) => colors.text}; |
||||||
|
font-style: normal; |
||||||
|
font-weight: bold; |
||||||
|
font-size: 18px; |
||||||
|
line-height: 21px; |
||||||
|
` |
||||||
|
|
||||||
|
export const Input = styled.input` |
||||||
|
position: absolute; |
||||||
|
z-index: -1; |
||||||
|
opacity: 0; |
||||||
|
|
||||||
|
&+${Label} { |
||||||
|
display: inline-flex; |
||||||
|
align-items: center; |
||||||
|
user-select: none; |
||||||
|
} |
||||||
|
|
||||||
|
&+${Label}::before { |
||||||
|
content: ''; |
||||||
|
display: inline-block; |
||||||
|
width: 26px; |
||||||
|
height: 26px; |
||||||
|
margin-right: 22px; |
||||||
|
background-repeat: no-repeat; |
||||||
|
background-position: center center; |
||||||
|
background-image: url(/images/radioUnchecked.svg); |
||||||
|
} |
||||||
|
|
||||||
|
&:checked+${Label}::before { |
||||||
|
background-image: url(/images/radioChecked.svg); |
||||||
|
} |
||||||
|
` |
||||||
@ -0,0 +1,5 @@ |
|||||||
|
export * from './Input' |
||||||
|
export * from './Button' |
||||||
|
export * from './Radio' |
||||||
|
export * from './Checkbox' |
||||||
|
export * from './Arrows' |
||||||
@ -0,0 +1,46 @@ |
|||||||
|
import { createGlobalStyle } from 'styled-components/macro' |
||||||
|
|
||||||
|
export const GlobalStyles = createGlobalStyle` |
||||||
|
*, *:before, *:after { |
||||||
|
box-sizing: border-box; |
||||||
|
} |
||||||
|
|
||||||
|
body { |
||||||
|
min-height: 100vh; |
||||||
|
margin: 0; |
||||||
|
padding: 0; |
||||||
|
font-family: Montserrat, Tahoma, sans-serif; |
||||||
|
font-size: 12px; |
||||||
|
line-height: 12px; |
||||||
|
color: #000; |
||||||
|
} |
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6, p, ul, li { |
||||||
|
margin: 0; |
||||||
|
padding: 0; |
||||||
|
font-size: 12px; |
||||||
|
line-height: 12px; |
||||||
|
} |
||||||
|
|
||||||
|
ul, li { |
||||||
|
list-style: none; |
||||||
|
} |
||||||
|
|
||||||
|
a { |
||||||
|
text-decoration: none; |
||||||
|
color: #000; |
||||||
|
} |
||||||
|
|
||||||
|
fieldset { |
||||||
|
margin: 0; |
||||||
|
min-width: 0; |
||||||
|
padding: 0; |
||||||
|
border: 0; |
||||||
|
} |
||||||
|
|
||||||
|
button, input, select, textarea { |
||||||
|
font-family: inherit; |
||||||
|
font-size: inherit; |
||||||
|
line-height: inherit; |
||||||
|
} |
||||||
|
` |
||||||
@ -0,0 +1,40 @@ |
|||||||
|
export const lightTheme = { |
||||||
|
colors: { |
||||||
|
background: '', |
||||||
|
primary: '', |
||||||
|
secondary: '', |
||||||
|
text: '', |
||||||
|
}, |
||||||
|
name: 'light' as TName, |
||||||
|
switchTheme: () => {}, |
||||||
|
} |
||||||
|
|
||||||
|
export const darkTheme = { |
||||||
|
colors: { |
||||||
|
background: ` |
||||||
|
radial-gradient( |
||||||
|
49.07% 49.07% at 50% 29.54%, |
||||||
|
rgba(255, 255, 255, 0.14) 0%, |
||||||
|
rgba(255, 255, 255, 0) 100% |
||||||
|
), |
||||||
|
rgba(0, 0, 0, 0.95) |
||||||
|
`,
|
||||||
|
primary: ` |
||||||
|
linear-gradient( |
||||||
|
180deg, |
||||||
|
rgba(255, 255, 255, 0) 0%, |
||||||
|
rgba(255, 255, 255, 0.1) 0.01%, |
||||||
|
rgba(0, 0, 0, 0.1) 99.99% |
||||||
|
), |
||||||
|
#0033CC |
||||||
|
`,
|
||||||
|
secondary: '#999999', |
||||||
|
text: '#fff', |
||||||
|
}, |
||||||
|
name: 'dark' as TName, |
||||||
|
switchTheme: () => {}, |
||||||
|
} |
||||||
|
|
||||||
|
type TName = 'light' | 'dark' |
||||||
|
|
||||||
|
export type TCustomTheme = typeof lightTheme |
||||||
@ -0,0 +1,39 @@ |
|||||||
|
import React, { |
||||||
|
useState, |
||||||
|
ReactNode, |
||||||
|
useCallback, |
||||||
|
useMemo, |
||||||
|
} from 'react' |
||||||
|
import { ThemeProvider } from 'styled-components' |
||||||
|
|
||||||
|
import { |
||||||
|
TCustomTheme, |
||||||
|
lightTheme, |
||||||
|
darkTheme, |
||||||
|
} from './config' |
||||||
|
|
||||||
|
type TThemeProps = { |
||||||
|
children: ReactNode, |
||||||
|
} |
||||||
|
|
||||||
|
export const Theme = ({ children }: TThemeProps) => { |
||||||
|
const [theme, setTheme] = useState<TCustomTheme>(darkTheme) |
||||||
|
|
||||||
|
const switchTheme = useCallback( |
||||||
|
() => { |
||||||
|
setTheme(theme.name === 'light' ? darkTheme : lightTheme) |
||||||
|
}, |
||||||
|
[theme], |
||||||
|
) |
||||||
|
|
||||||
|
const memoTheme = useMemo(() => ({ |
||||||
|
...theme, |
||||||
|
switchTheme, |
||||||
|
}), [theme, switchTheme]) |
||||||
|
|
||||||
|
return ( |
||||||
|
<ThemeProvider theme={memoTheme}> |
||||||
|
{children} |
||||||
|
</ThemeProvider> |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,5 @@ |
|||||||
|
import { TCustomTheme } from '../features/Theme/config' |
||||||
|
|
||||||
|
declare module 'styled-components' { |
||||||
|
export interface DefaultTheme extends TCustomTheme {} |
||||||
|
} |
||||||
Loading…
Reference in new issue