diff --git a/frontend/src/components/Alert/index.module.css b/frontend/src/components/Alert/index.module.css new file mode 100644 index 0000000..e259113 --- /dev/null +++ b/frontend/src/components/Alert/index.module.css @@ -0,0 +1,93 @@ +.alert { + min-height: 688px; + text-align: center; + + h2 { + color: var(--palatinate-blue); + margin-top: 6rem; + margin-bottom: 1rem; + } + + p { + max-width: 335px; + font-size: 14px; + font-weight: 400; + line-height: 120%; + letter-spacing: 0; + margin: 0 auto; + margin-bottom: 2.375rem; + } + + .icon { + margin: 0 auto; + margin-bottom: 1.125rem; + } + + .actions { + &:empty { + display: none; + } + + span { + font-size: 22px; + font-weight: 500; + line-height: 150%; + letter-spacing: -0.03em; + color: var(--palatinate-blue); + } + } +} + +.alertError { + svg { + color: var(--mystic); + } +} + +.alertSuccess { + svg { + color: var(--green-sheen); + } +} + +@keyframes rotating { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +.alertLoading { + .icon { + display: flex; + justify-content: center; + align-items: center; + width: 106px; + height: 106px; + border-radius: 50%; + background: linear-gradient(302.43deg, var(--medium-blue) -18.46%, var(--azure) 93.84%); + } + + svg { + color: var(--white); + animation: rotating 3s linear infinite; + } +} + +.alertInsufficientBalance { + .icon { + display: flex; + justify-content: center; + align-items: center; + width: 106px; + height: 106px; + border-radius: 50%; + background: linear-gradient(282.09deg, var(--mystic) 6.24%, var(--rose-red) 102.94%); + } + + svg { + color: var(--white); + } +} diff --git a/frontend/src/components/Alert/index.tsx b/frontend/src/components/Alert/index.tsx new file mode 100644 index 0000000..97c1be6 --- /dev/null +++ b/frontend/src/components/Alert/index.tsx @@ -0,0 +1,60 @@ +import { FC, PropsWithChildren, ReactElement } from 'react' +import classes from './index.module.css' +import { Card } from '../Card' +import { WarningCircleIcon } from '../icons/WarningCircleIcon.tsx' +import { CheckCircleIcon } from '../icons/CheckCircleIcon.tsx' +import { SpinnerIcon } from '../icons/SpinnerIcon.tsx' +import { PiggyBankSvgIcon } from '../icons/PiggyBankIcon.tsx' + +type AlertType = 'error' | 'success' | 'loading' | 'insufficient-balance' + +interface AlertTypeValues { + header: string + icon: ReactElement +} + +const alertTypeValuesMap: Record = { + error: { + header: 'Something went wrong', + icon: , + }, + success: { + header: 'Vote cast', + icon: , + }, + loading: { + header: 'Casting your vote', + icon: , + }, + 'insufficient-balance': { + header: 'Insufficient balance', + icon: , + }, +} + +const alertTypeClassMap: Record = { + error: classes.alertError, + success: classes.alertSuccess, + loading: classes.alertLoading, + 'insufficient-balance': classes.alertInsufficientBalance, +} + +interface Props extends PropsWithChildren { + type: AlertType + actions?: ReactElement +} + +export const Alert: FC = ({ children, type, actions }) => { + const { header, icon } = alertTypeValuesMap[type] + + return ( + +
+

{header}

+

{children}

+
{icon}
+
{actions}
+
+
+ ) +} diff --git a/frontend/src/components/Button/index.tsx b/frontend/src/components/Button/index.tsx index dce3b50..b5d3f88 100644 --- a/frontend/src/components/Button/index.tsx +++ b/frontend/src/components/Button/index.tsx @@ -1,5 +1,6 @@ import classes from './index.module.css' import { FC, MouseEventHandler, PropsWithChildren } from 'react' +import { StringUtils } from '../../utils/string.utils.ts' type ButtonSize = 'small' | 'medium' type ButtonColor = 'primary' | 'secondary' @@ -43,15 +44,15 @@ export const Button: FC = ({ type, }) => (