feat: coming soon
This commit is contained in:
@ -1,17 +0,0 @@
|
||||
import Image, { ImageProps } from 'next/image'
|
||||
|
||||
export const Avatar: React.FC<ImageProps> = (props) => {
|
||||
return (
|
||||
<>
|
||||
<Image {...props} className='avatar-image' />
|
||||
|
||||
<style jsx>
|
||||
{`
|
||||
:global(.avatar-image) {
|
||||
border-radius: 50%;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
import { forwardRef } from 'react'
|
||||
|
||||
interface ButtonProps extends React.ComponentPropsWithRef<'button'> {}
|
||||
|
||||
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
(props, ref) => {
|
||||
const { children, ...rest } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
<button ref={ref} {...rest} className='button'>
|
||||
{children}
|
||||
</button>
|
||||
|
||||
<style jsx>{`
|
||||
.button {
|
||||
cursor: pointer;
|
||||
font-size: var(--default-font-size);
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.8px;
|
||||
padding: 1rem 2rem;
|
||||
transform: translateY(-3px);
|
||||
background-color: transparent;
|
||||
border: 1px solid var(--color-primary);
|
||||
border-radius: 10px;
|
||||
transition: all 0.3s ease-in;
|
||||
color: var(--color-primary);
|
||||
outline: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.button:hover {
|
||||
background-color: var(--color-primary);
|
||||
color: #fff;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
||||
)
|
15
components/design/Button/Button.stories.tsx
Normal file
15
components/design/Button/Button.stories.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import { Meta, Story } from '@storybook/react'
|
||||
|
||||
import { Button as Component, ButtonProps } from './Button'
|
||||
|
||||
const Stories: Meta = {
|
||||
title: 'Button',
|
||||
component: Component
|
||||
}
|
||||
|
||||
export default Stories
|
||||
|
||||
export const Button: Story<ButtonProps> = (arguments_) => (
|
||||
<Component {...arguments_} />
|
||||
)
|
||||
Button.args = { children: 'Get started' }
|
@ -1,6 +1,6 @@
|
||||
import { render } from '@testing-library/react'
|
||||
|
||||
import { Button } from '../Button'
|
||||
import { Button } from './'
|
||||
|
||||
describe('<Button />', () => {
|
||||
it('should render', async () => {
|
19
components/design/Button/Button.tsx
Normal file
19
components/design/Button/Button.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import classNames from 'classnames'
|
||||
|
||||
export interface ButtonProps extends React.ComponentPropsWithoutRef<'button'> {}
|
||||
|
||||
export const Button: React.FC<ButtonProps> = (props) => {
|
||||
const { children, className, ...rest } = props
|
||||
|
||||
return (
|
||||
<button
|
||||
className={classNames(
|
||||
'py-2 px-6 font-paragraph rounded-lg bg-transparent border border-green-800 dark:border-green-400 text-green-800 dark:text-green-400 hover:bg-green-800 hover:text-white dark:hover:bg-green-400 dark:hover:text-black fill-current stroke-current transform transition-colors duration-300 ease-in-out focus:outline-none focus:bg-green-800 focus:text-white dark:focus:bg-green-400 dark:focus:text-black',
|
||||
className
|
||||
)}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
)
|
||||
}
|
1
components/design/Button/index.ts
Normal file
1
components/design/Button/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './Button'
|
@ -1,24 +0,0 @@
|
||||
interface ContainerProps extends React.ComponentPropsWithRef<'div'> {}
|
||||
|
||||
export const Container: React.FC<ContainerProps> = (props) => {
|
||||
const { children, className } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={`container ${className ?? ''}`}>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
<style jsx>
|
||||
{`
|
||||
.container {
|
||||
height: calc(100vh - 110px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
interface DividerProps {
|
||||
content: string
|
||||
}
|
||||
|
||||
export const Divider: React.FC<DividerProps> = (props) => {
|
||||
const { content } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='text-divider'>{content}</div>
|
||||
|
||||
<style jsx>
|
||||
{`
|
||||
.text-divider {
|
||||
--text-divider-gap: 1rem;
|
||||
--color-divider: #414141;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
letter-spacing: 0.1em;
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
height: 1px;
|
||||
background-color: var(--color-divider);
|
||||
flex-grow: 1;
|
||||
}
|
||||
&::before {
|
||||
margin-right: var(--text-divider-gap);
|
||||
}
|
||||
&::after {
|
||||
margin-left: var(--text-divider-gap);
|
||||
}
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
import { forwardRef, useMemo } from 'react'
|
||||
|
||||
export const icons = [
|
||||
'add',
|
||||
'delete',
|
||||
'edit',
|
||||
'emoji',
|
||||
'send',
|
||||
'settings',
|
||||
'more',
|
||||
'download'
|
||||
] as const
|
||||
|
||||
export type Icon = typeof icons[number]
|
||||
|
||||
interface IconButtonProps extends React.ComponentPropsWithRef<'button'> {
|
||||
icon: Icon
|
||||
hasBackground?: boolean
|
||||
size?: number
|
||||
}
|
||||
|
||||
export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
||||
(props, ref) => {
|
||||
const { icon, hasBackground = false, size = 60, ...rest } = props
|
||||
|
||||
const imageSize = useMemo(() => {
|
||||
return size / 2.6
|
||||
}, [size])
|
||||
|
||||
return (
|
||||
<>
|
||||
<button ref={ref} className='button' {...rest}>
|
||||
<img src={`/images/svg/icons/${icon}.svg`} alt={icon} />
|
||||
</button>
|
||||
|
||||
<style jsx>
|
||||
{`
|
||||
.button {
|
||||
background: ${hasBackground
|
||||
? 'var(--color-background-secondary)'
|
||||
: 'none'};
|
||||
border-radius: ${hasBackground ? '50%' : '0'};
|
||||
width: ${hasBackground ? `${size}px` : '100%'};
|
||||
height: ${hasBackground ? `${size}px` : '100%'};
|
||||
border: none;
|
||||
outline: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
.button:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
.button > img {
|
||||
width: ${imageSize}px;
|
||||
height: ${imageSize}px;
|
||||
display: block;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
||||
)
|
@ -1,128 +0,0 @@
|
||||
import { forwardRef, useState } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { ErrorMessage } from '../Authentication/ErrorMessage'
|
||||
import useTranslation from 'next-translate/useTranslation'
|
||||
|
||||
interface InputProps extends React.ComponentPropsWithRef<'input'> {
|
||||
label: string
|
||||
errors?: string[]
|
||||
showForgotPassword?: boolean
|
||||
}
|
||||
|
||||
export const Input = forwardRef<HTMLInputElement, InputProps>((props, ref) => {
|
||||
const {
|
||||
label,
|
||||
name,
|
||||
type = 'text',
|
||||
errors = [],
|
||||
showForgotPassword = false,
|
||||
...rest
|
||||
} = props
|
||||
const { t } = useTranslation()
|
||||
const [inputType, setInputType] = useState(type)
|
||||
|
||||
const handlePassword = (): void => {
|
||||
const oppositeType = inputType === 'password' ? 'text' : 'password'
|
||||
setInputType(oppositeType)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='container'>
|
||||
<div className='input-with-label'>
|
||||
<div className='label-container'>
|
||||
<label className='label' htmlFor={name}>
|
||||
{label}
|
||||
</label>
|
||||
{type === 'password' && showForgotPassword ? (
|
||||
<Link href='/authentication/forgot-password'>
|
||||
<a className='label-forgot-password'>
|
||||
{t('authentication:forgot-password')}
|
||||
</a>
|
||||
</Link>
|
||||
) : null}
|
||||
</div>
|
||||
<div className='input-container'>
|
||||
<input
|
||||
data-testid='input'
|
||||
className='input'
|
||||
{...rest}
|
||||
ref={ref}
|
||||
id={name}
|
||||
name={name}
|
||||
type={inputType}
|
||||
/>
|
||||
{type === 'password' && (
|
||||
<div
|
||||
data-testid='password-eye'
|
||||
onClick={handlePassword}
|
||||
className='password-eye'
|
||||
/>
|
||||
)}
|
||||
<ErrorMessage errors={errors} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style jsx>
|
||||
{`
|
||||
.container {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.input-container {
|
||||
margin-top: 0;
|
||||
position: relative;
|
||||
}
|
||||
.input-with-label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.label-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 5px 0;
|
||||
}
|
||||
.label-forgot-password {
|
||||
font-size: 12px;
|
||||
}
|
||||
.label {
|
||||
color: var(--color-secondary);
|
||||
font-size: 16px;
|
||||
font-family: 'Poppins', 'Arial', 'sans-serif';
|
||||
padding-left: 3px;
|
||||
}
|
||||
.input {
|
||||
background-color: #f1f1f1;
|
||||
font-family: 'Roboto', 'Arial', 'sans-serif';
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
padding: 0 20px;
|
||||
color: #2a2a2a;
|
||||
border: 0;
|
||||
box-shadow: ${errors.length >= 1
|
||||
? '0 0 0 2px var(--color-error)'
|
||||
: 'none'};
|
||||
border-radius: 10px;
|
||||
}
|
||||
.input:focus {
|
||||
outline: 0;
|
||||
border-color: var(--color-primary);
|
||||
box-shadow: 0 0 0 2px var(--color-primary);
|
||||
}
|
||||
.password-eye {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 16px;
|
||||
z-index: 1;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-image: url(/images/svg/icons/input/${inputType}.svg);
|
||||
background-size: cover;
|
||||
cursor: pointer;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
})
|
@ -1,80 +0,0 @@
|
||||
export interface LoaderProps {
|
||||
width?: number
|
||||
height?: number
|
||||
}
|
||||
|
||||
export const Loader: React.FC<LoaderProps> = (props) => {
|
||||
const { width = 50, height = 50 } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
<div data-testid='progress-spinner' className='progress-spinner'>
|
||||
<svg className='progress-spinner-svg' viewBox='25 25 50 50'>
|
||||
<circle
|
||||
className='progress-spinner-circle'
|
||||
cx='50'
|
||||
cy='50'
|
||||
r='20'
|
||||
fill='none'
|
||||
strokeWidth='2'
|
||||
strokeMiterlimit='10'
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<style jsx>{`
|
||||
.progress-spinner {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
width: ${width}px;
|
||||
height: ${height}px;
|
||||
display: inline-block;
|
||||
}
|
||||
.progress-spinner::before {
|
||||
content: '';
|
||||
display: block;
|
||||
padding-top: 100%;
|
||||
}
|
||||
.progress-spinner-svg {
|
||||
animation: progress-spinner-rotate 2s linear infinite;
|
||||
height: 100%;
|
||||
transform-origin: center center;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
}
|
||||
.progress-spinner-circle {
|
||||
stroke-dasharray: 89, 200;
|
||||
stroke-dashoffset: 0;
|
||||
stroke: var(--color-primary);
|
||||
animation: progress-spinner-dash 1.5s ease-in-out infinite;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
@keyframes progress-spinner-rotate {
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@keyframes progress-spinner-dash {
|
||||
0% {
|
||||
stroke-dasharray: 1, 200;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
50% {
|
||||
stroke-dasharray: 89, 200;
|
||||
stroke-dashoffset: -35px;
|
||||
}
|
||||
100% {
|
||||
stroke-dasharray: 89, 200;
|
||||
stroke-dashoffset: -124px;
|
||||
}
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
10
components/design/Main/Main.test.tsx
Normal file
10
components/design/Main/Main.test.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import { render } from '@testing-library/react'
|
||||
|
||||
import { Main } from './'
|
||||
|
||||
describe('<Main />', () => {
|
||||
it('should render successfully', () => {
|
||||
const { baseElement } = render(<Main />)
|
||||
expect(baseElement).toBeTruthy()
|
||||
})
|
||||
})
|
20
components/design/Main/Main.tsx
Normal file
20
components/design/Main/Main.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import classNames from 'classnames'
|
||||
|
||||
export interface MainProps {
|
||||
className?: string
|
||||
}
|
||||
|
||||
export const Main: React.FC<MainProps> = (props) => {
|
||||
const { children, className } = props
|
||||
|
||||
return (
|
||||
<main
|
||||
className={classNames(
|
||||
'flex flex-1 flex-col justify-center items-center py-8',
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</main>
|
||||
)
|
||||
}
|
1
components/design/Main/index.ts
Normal file
1
components/design/Main/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './Main'
|
@ -1,80 +0,0 @@
|
||||
import { forwardRef, useMemo } from 'react'
|
||||
import Image from 'next/image'
|
||||
|
||||
export type SocialMedia = 'Discord' | 'GitHub' | 'Google'
|
||||
|
||||
type SocialMediaColors = {
|
||||
[key in SocialMedia]: string
|
||||
}
|
||||
|
||||
interface SocialMediaButtonProps extends React.ComponentPropsWithRef<'button'> {
|
||||
socialMedia: SocialMedia
|
||||
}
|
||||
|
||||
const socialMediaColors: SocialMediaColors = {
|
||||
Discord: '#7289DA',
|
||||
GitHub: '#24292E',
|
||||
Google: '#FCFCFC'
|
||||
}
|
||||
|
||||
export const SocialMediaButton = forwardRef<
|
||||
HTMLButtonElement,
|
||||
SocialMediaButtonProps
|
||||
>((props, ref) => {
|
||||
const { socialMedia, className, ...rest } = props
|
||||
|
||||
const socialMediaColor = useMemo(() => {
|
||||
return socialMediaColors[socialMedia]
|
||||
}, [socialMedia])
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
data-testid='button'
|
||||
ref={ref}
|
||||
{...rest}
|
||||
className={`button ${className ?? ''}`}
|
||||
>
|
||||
<Image
|
||||
width={20}
|
||||
height={20}
|
||||
src={`/images/svg/web/${socialMedia}.svg`}
|
||||
alt={socialMedia}
|
||||
/>
|
||||
<span className='social-media'>{socialMedia}</span>
|
||||
</button>
|
||||
|
||||
<style jsx>
|
||||
{`
|
||||
.button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
outline: none;
|
||||
font-size: var(--default-font-size);
|
||||
font-family: 'Roboto', 'Arial', 'sans-serif';
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
letter-spacing: 0.8px;
|
||||
padding: 0.9rem 2.4rem;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.2);
|
||||
background: ${socialMediaColor};
|
||||
color: ${socialMedia === 'Google' ? '#000' : '#fff'};
|
||||
transition: all 0.3s ease-out;
|
||||
}
|
||||
.button:hover {
|
||||
opacity: 0.85;
|
||||
transition: all 0.3s ease-in;
|
||||
}
|
||||
.button:before {
|
||||
display: none;
|
||||
}
|
||||
.social-media {
|
||||
margin-left: 0.7rem;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
})
|
@ -0,0 +1,23 @@
|
||||
import { Meta, Story } from '@storybook/react'
|
||||
|
||||
import { SocialMediaButton, SocialMediaButtonProps } from './SocialMediaButton'
|
||||
|
||||
const Stories: Meta = {
|
||||
title: 'SocialMediaButton',
|
||||
component: SocialMediaButton
|
||||
}
|
||||
|
||||
export default Stories
|
||||
|
||||
const Template: Story<SocialMediaButtonProps> = (arguments_) => (
|
||||
<SocialMediaButton {...arguments_} />
|
||||
)
|
||||
|
||||
export const Github = Template.bind({})
|
||||
Github.args = { socialMedia: 'GitHub' }
|
||||
|
||||
export const Discord = Template.bind({})
|
||||
Discord.args = { socialMedia: 'Discord' }
|
||||
|
||||
export const Google = Template.bind({})
|
||||
Google.args = { socialMedia: 'Google' }
|
@ -1,6 +1,6 @@
|
||||
import { render } from '@testing-library/react'
|
||||
|
||||
import { SocialMedia, SocialMediaButton } from '../SocialMediaButton'
|
||||
import { SocialMedia, SocialMediaButton } from './'
|
||||
|
||||
describe('<SocialMediaButton />', () => {
|
||||
it('should render the social media', async () => {
|
62
components/design/SocialMediaButton/SocialMediaButton.tsx
Normal file
62
components/design/SocialMediaButton/SocialMediaButton.tsx
Normal file
@ -0,0 +1,62 @@
|
||||
import { useMemo } from 'react'
|
||||
import Image from 'next/image'
|
||||
import classNames from 'classnames'
|
||||
|
||||
export type SocialMedia = 'Discord' | 'GitHub' | 'Google'
|
||||
|
||||
type SocialMediaColors = {
|
||||
[key in SocialMedia]: string
|
||||
}
|
||||
|
||||
export interface SocialMediaButtonProps
|
||||
extends React.ComponentPropsWithRef<'button'> {
|
||||
socialMedia: SocialMedia
|
||||
}
|
||||
|
||||
const socialMediaColors: SocialMediaColors = {
|
||||
Discord: '#404EED',
|
||||
GitHub: '#24292E',
|
||||
Google: '#FCFCFC'
|
||||
}
|
||||
|
||||
export const SocialMediaButton: React.FC<SocialMediaButtonProps> = (props) => {
|
||||
const { socialMedia, className, ...rest } = props
|
||||
|
||||
const socialMediaColor = useMemo(() => {
|
||||
return socialMediaColors[socialMedia]
|
||||
}, [socialMedia])
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
data-testid='button'
|
||||
{...rest}
|
||||
className={classNames(
|
||||
`button py-2 px-6 inline-flex outline-none items-center font-paragraph rounded-lg cursor-pointer transition duration-300 ease-in-out hover:opacity-80 focus:outline-none`,
|
||||
className
|
||||
)}
|
||||
>
|
||||
<Image
|
||||
width={20}
|
||||
height={20}
|
||||
src={`/images/svg/web/${socialMedia}.svg`}
|
||||
alt={socialMedia}
|
||||
/>
|
||||
<span className='ml-2'>{socialMedia}</span>
|
||||
</button>
|
||||
|
||||
<style jsx>
|
||||
{`
|
||||
.button {
|
||||
background: ${socialMediaColor};
|
||||
color: ${socialMedia === 'Google' ? '#000' : '#fff'};
|
||||
border: ${socialMedia === 'Google' ? '1px solid #000' : 'none'};
|
||||
}
|
||||
.button:focus {
|
||||
box-shadow: 0 0 0 2px #27b05e;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
1
components/design/SocialMediaButton/index.ts
Normal file
1
components/design/SocialMediaButton/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './SocialMediaButton'
|
@ -1,106 +0,0 @@
|
||||
import { forwardRef } from 'react'
|
||||
|
||||
interface TooltipProps extends React.ComponentPropsWithRef<'div'> {
|
||||
content: string
|
||||
direction?: 'top' | 'bottom' | 'right' | 'left'
|
||||
}
|
||||
|
||||
export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
|
||||
(props, ref) => {
|
||||
const { direction = 'bottom', children, content, ...rest } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
<div ref={ref} {...rest} className='tooltip-wrapper'>
|
||||
{children}
|
||||
<div className={`tooltip ${direction}`}>{content}</div>
|
||||
</div>
|
||||
|
||||
<style jsx>
|
||||
{`
|
||||
.tooltip-wrapper {
|
||||
--tooltip-text-color: white;
|
||||
--tooltip-background-color: black;
|
||||
--tooltip-margin: 50px;
|
||||
--tooltip-arrow-size: 6px;
|
||||
}
|
||||
.tooltip-wrapper {
|
||||
display: inline-block;
|
||||
|
||||
}
|
||||
.tooltip {
|
||||
position: absolute;
|
||||
border-radius: 6px;
|
||||
left: 100%;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
padding: 10px;
|
||||
color: var(--tooltip-text-color);
|
||||
background: var(--tooltip-background-color);
|
||||
font-size: 15px;
|
||||
font-family: sans-serif;
|
||||
line-height: 1;
|
||||
z-index: 100;
|
||||
white-space: nowrap;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all 0.15s ease-in;
|
||||
}
|
||||
.tooltip-wrapper ~ .tooltip-wrapper:hover .tooltip,
|
||||
.tooltip-wrapper:first-child:hover .tooltip {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transition: all 0.35s ease-out;
|
||||
margin: 0;
|
||||
}
|
||||
.tooltip::before {
|
||||
content: ' ';
|
||||
left: 50%;
|
||||
border: solid transparent;
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
border-width: var(--tooltip-arrow-size);
|
||||
margin-left: calc(var(--tooltip-arrow-size) * -1);
|
||||
}
|
||||
.tooltip.top {
|
||||
top: calc(var(--tooltip-margin) * -1);
|
||||
}
|
||||
.tooltip.top::before {
|
||||
top: 100%;
|
||||
border-top-color: var(--tooltip-background-color);
|
||||
}
|
||||
.tooltip.right {
|
||||
left: calc(100% + var(--tooltip-margin));
|
||||
}
|
||||
.tooltip.right::before {
|
||||
left: calc(var(--tooltip-arrow-size) * -1);
|
||||
border-right-color: var(--tooltip-background-color);
|
||||
}
|
||||
.tooltip.bottom {
|
||||
bottom: calc(var(--tooltip-margin) * -1);
|
||||
}
|
||||
.tooltip.bottom::before {
|
||||
bottom: 100%;
|
||||
border-bottom-color: var(--tooltip-background-color);
|
||||
}
|
||||
.tooltip.left {
|
||||
left: auto;
|
||||
right: calc(100% + var(--tooltip-margin));
|
||||
top: 50%;
|
||||
transform: translateX(0) translateY(-50%);
|
||||
}
|
||||
.tooltip.left::before {
|
||||
left: auto;
|
||||
right: calc(var(--tooltip-arrow-size) * -2);
|
||||
top: 50%;
|
||||
transform: translateX(0) translateY(-50%);
|
||||
border-left-color: var(--tooltip-background-color);
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
||||
)
|
@ -1,13 +0,0 @@
|
||||
import { render } from '@testing-library/react'
|
||||
|
||||
import { Avatar } from '../Avatar'
|
||||
|
||||
describe('<Avatar />', () => {
|
||||
it('should render', async () => {
|
||||
const altAttribute = 'avatar'
|
||||
const { getByAltText } = render(
|
||||
<Avatar width={50} height={50} src='/avatar.png' alt={altAttribute} />
|
||||
)
|
||||
expect(getByAltText(altAttribute)).toBeInTheDocument()
|
||||
})
|
||||
})
|
@ -1,10 +0,0 @@
|
||||
import { render } from '@testing-library/react'
|
||||
|
||||
import { Container } from '../Container'
|
||||
|
||||
describe('<Container />', () => {
|
||||
it('should render', async () => {
|
||||
const { getByText } = render(<Container>Content</Container>)
|
||||
expect(getByText('Content')).toBeInTheDocument()
|
||||
})
|
||||
})
|
@ -1,11 +0,0 @@
|
||||
import { render } from '@testing-library/react'
|
||||
|
||||
import { Divider } from '../Divider'
|
||||
|
||||
describe('<Divider />', () => {
|
||||
it('should render with the content', async () => {
|
||||
const content = 'divider'
|
||||
const { getByText } = render(<Divider content={content} />)
|
||||
expect(getByText(content)).toBeInTheDocument()
|
||||
})
|
||||
})
|
@ -1,13 +0,0 @@
|
||||
import { render } from '@testing-library/react'
|
||||
|
||||
import { Icon, IconButton } from '../IconButton'
|
||||
|
||||
describe('<IconButton />', () => {
|
||||
it('should render with the icon', async () => {
|
||||
const icon: Icon = 'add'
|
||||
const { getByAltText } = render(<IconButton icon={icon} />)
|
||||
const iconImage = getByAltText(icon)
|
||||
expect(iconImage).toBeInTheDocument()
|
||||
expect(iconImage).toHaveAttribute('src', `/images/svg/icons/${icon}.svg`)
|
||||
})
|
||||
})
|
@ -1,26 +0,0 @@
|
||||
import { render, fireEvent } from '@testing-library/react'
|
||||
|
||||
import { Input } from '../Input'
|
||||
|
||||
describe('<Input />', () => {
|
||||
it('should render the label', async () => {
|
||||
const labelContent = 'label content'
|
||||
const { getByText } = render(<Input label={labelContent} />)
|
||||
expect(getByText(labelContent)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should not render the eye icon if the input is not of type "password"', async () => {
|
||||
const { queryByTestId } = render(<Input type='text' label='content' />)
|
||||
const passwordEye = queryByTestId('password-eye')
|
||||
expect(passwordEye).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should handlePassword with eye icon', async () => {
|
||||
const { findByTestId } = render(<Input type='password' label='content' />)
|
||||
const passwordEye = await findByTestId('password-eye')
|
||||
const input = await findByTestId('input')
|
||||
expect(input).toHaveAttribute('type', 'password')
|
||||
fireEvent.click(passwordEye)
|
||||
expect(input).toHaveAttribute('type', 'text')
|
||||
})
|
||||
})
|
@ -1,20 +0,0 @@
|
||||
import { render } from '@testing-library/react'
|
||||
|
||||
import { Loader } from '../Loader'
|
||||
|
||||
describe('<Loader />', () => {
|
||||
it('should render with correct width and height', async () => {
|
||||
const size = 20
|
||||
const { findByTestId } = render(<Loader width={size} height={size} />)
|
||||
const progressSpinner = await findByTestId('progress-spinner')
|
||||
expect(progressSpinner).toHaveStyle(`width: ${size}px`)
|
||||
expect(progressSpinner).toHaveStyle(`height: ${size}px`)
|
||||
})
|
||||
|
||||
it('should render with default width and height', async () => {
|
||||
const { findByTestId } = render(<Loader />)
|
||||
const progressSpinner = await findByTestId('progress-spinner')
|
||||
expect(progressSpinner).toHaveStyle('width: 50px')
|
||||
expect(progressSpinner).toHaveStyle('height: 50px')
|
||||
})
|
||||
})
|
@ -1,11 +0,0 @@
|
||||
import { render } from '@testing-library/react'
|
||||
|
||||
import { Tooltip } from '../Tooltip'
|
||||
|
||||
describe('<Tooltip />', () => {
|
||||
it('should render with content', async () => {
|
||||
const content = 'tooltip content'
|
||||
const { getByText } = render(<Tooltip content={content} />)
|
||||
expect(getByText(content)).toBeInTheDocument()
|
||||
})
|
||||
})
|
Reference in New Issue
Block a user