Skip to content

Commit

Permalink
Merge pull request #13 from oasisprotocol/ml/alerts
Browse files Browse the repository at this point in the history
Add Alert component
  • Loading branch information
lubej authored Mar 7, 2024
2 parents e69d661 + 073b000 commit 684eea9
Show file tree
Hide file tree
Showing 13 changed files with 267 additions and 9 deletions.
93 changes: 93 additions & 0 deletions frontend/src/components/Alert/index.module.css
Original file line number Diff line number Diff line change
@@ -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);
}
}
60 changes: 60 additions & 0 deletions frontend/src/components/Alert/index.tsx
Original file line number Diff line number Diff line change
@@ -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<AlertType, AlertTypeValues> = {
error: {
header: 'Something went wrong',
icon: <WarningCircleIcon />,
},
success: {
header: 'Vote cast',
icon: <CheckCircleIcon />,
},
loading: {
header: 'Casting your vote',
icon: <SpinnerIcon />,
},
'insufficient-balance': {
header: 'Insufficient balance',
icon: <PiggyBankSvgIcon />,
},
}

const alertTypeClassMap: Record<AlertType, string> = {
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<Props> = ({ children, type, actions }) => {
const { header, icon } = alertTypeValuesMap[type]

return (
<Card className={alertTypeClassMap[type]}>
<div className={classes.alert}>
<h2>{header}</h2>
<p>{children}</p>
<div className={classes.icon}>{icon}</div>
<div className={classes.actions}>{actions}</div>
</div>
</Card>
)
}
11 changes: 6 additions & 5 deletions frontend/src/components/Button/index.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -43,15 +44,15 @@ export const Button: FC<Props> = ({
type,
}) => (
<button
className={[
className={StringUtils.clsx(
className,
classes.button,
...(disabled ? [classes.buttonDisabled] : []),
...(fullWidth ? [classes.fullWidth] : []),
disabled ? classes.buttonDisabled : undefined,
fullWidth ? classes.fullWidth : undefined,
colorMap[color],
sizeMap[size],
variantMap[variant],
].join(' ')}
variantMap[variant]
)}
onClick={onClick}
disabled={disabled}
type={type}
Expand Down
9 changes: 7 additions & 2 deletions frontend/src/components/Card/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { FC, PropsWithChildren } from 'react'
import classes from './index.module.css'
import { StringUtils } from '../../utils/string.utils.ts'

export const Card: FC<PropsWithChildren> = ({ children }) => {
return <div className={classes.card}>{children}</div>
interface Props extends PropsWithChildren {
className?: string
}

export const Card: FC<Props> = ({ children, className }) => {
return <div className={StringUtils.clsx(classes.card, className)}>{children}</div>
}
10 changes: 9 additions & 1 deletion frontend/src/components/Icon/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { cloneElement, FC, ReactElement, SVGProps } from 'react'

type IconSize = 'medium'
type IconSize = 'medium' | 'large' | 'xlarge'

interface Props {
children: ReactElement
Expand All @@ -12,6 +12,14 @@ const sizeMap: Record<IconSize, Partial<SVGProps<SVGSVGElement>>> = {
width: 30,
height: 30,
},
large: {
width: 64,
height: 64,
},
xlarge: {
width: 100,
height: 100,
},
}

export const Icon: FC<Props> = ({ children, size = 'medium' }) => {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/MascotCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const MascotCard: FC<Props> = ({ image, title, description, actions }) =>
return (
<div className={classes.mascotCard}>
{image}
<h2 className={classes.mascotCardTitle}>{title}</h2>
<h3 className={classes.mascotCardTitle}>{title}</h3>
<p className={classes.mascotCardDescription}>{description}</p>
{actions}
</div>
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/components/icons/CheckCircleIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/// <reference types="vite-plugin-svgr/client" />

import { FC } from 'react'
import CheckCircleSvg from '@phosphor-icons/core/assets/fill/check-circle-fill.svg?react'
import { Icon } from '../Icon'

export const CheckCircleIcon: FC = () => (
<Icon size="xlarge">
<CheckCircleSvg />
</Icon>
)
11 changes: 11 additions & 0 deletions frontend/src/components/icons/PiggyBankIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/// <reference types="vite-plugin-svgr/client" />

import { FC } from 'react'
import PiggyBankSvg from '@phosphor-icons/core/assets/regular/piggy-bank.svg?react'
import { Icon } from '../Icon'

export const PiggyBankSvgIcon: FC = () => (
<Icon size="large">
<PiggyBankSvg />
</Icon>
)
11 changes: 11 additions & 0 deletions frontend/src/components/icons/SpinnerIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/// <reference types="vite-plugin-svgr/client" />

import { FC } from 'react'
import SpinnerSvg from '@phosphor-icons/core/assets/regular/spinner.svg?react'
import { Icon } from '../Icon'

export const SpinnerIcon: FC = () => (
<Icon size="large">
<SpinnerSvg />
</Icon>
)
11 changes: 11 additions & 0 deletions frontend/src/components/icons/WarningCircleIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/// <reference types="vite-plugin-svgr/client" />

import { FC } from 'react'
import WarningCircleSvg from '@phosphor-icons/core/assets/fill/warning-circle-fill.svg?react'
import { Icon } from '../Icon'

export const WarningCircleIcon: FC = () => (
<Icon size="xlarge">
<WarningCircleSvg />
</Icon>
)
12 changes: 12 additions & 0 deletions frontend/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
--bright-gray: #eae6f0;
--dark-gunmetal: #242629;
--navy-blue: #000062;
--mystic: #d44c7d;
--green-sheen: #66bfa0;
--azure: #008cff;
--rose-red: #cc1e5c;
--medium-blue: #0d00d2;
}

*,
Expand Down Expand Up @@ -47,6 +52,13 @@ h1 {
}

h2 {
font-size: 30px;
font-weight: 500;
line-height: 140%;
letter-spacing: -0.03em;
}

h3 {
font-size: 26px;
font-weight: 500;
line-height: 130%;
Expand Down
28 changes: 28 additions & 0 deletions frontend/src/pages/HomePage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,38 @@ import { Button } from '../../components/Button'
import { Card } from '../../components/Card'
import classes from './index.module.css'
import { MascotCard } from '../../components/MascotCard'
import { Alert } from '../../components/Alert'

export const HomePage: FC = () => {
return (
<div>
<Alert type="insufficient-balance">
Please note there is a 100 ROSE threshold in order to cast your vote.
</Alert>
<br />
<br />
<Alert type="loading" actions={<span>Submitting vote...</span>}>
Once you confirm this vote you will not be able to cancel it.
</Alert>
<br />
<br />
<Alert
type="success"
actions={
<span>
Your vote has successfully submitted.
<br />
Thank you for your participation.
</span>
}
/>
<br />
<br />
<Alert type="error">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod Ipsum
</Alert>
<br />
<br />
<Card>
<p className={classes.cardHeaderText}>
Select your preferred mascot option. Once you confirm this vote you will not be able to cancel it.
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/utils/string.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,11 @@ export abstract class StringUtils {
static getTransactionUrl = (baseUrl: string, txHash: string) => `${baseUrl}/tx/${txHash}`

static getAccountUrl = (baseUrl: string, address: string) => `${baseUrl}/address/${address}`

static clsx = (...classNames: (string | undefined)[]) => {
return classNames
.map(className => (className ? [className] : []))
.flat()
.join(' ')
}
}

0 comments on commit 684eea9

Please sign in to comment.