Skip to content

Commit 235757a

Browse files
committed
Add Vote Proposal card layout
1 parent 7937cac commit 235757a

File tree

10 files changed

+460
-2
lines changed

10 files changed

+460
-2
lines changed

src/components/v2/Icon/icons/check.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@ import * as React from 'react';
22
import { SVGProps } from 'react';
33

44
const SvgCheck = (props: SVGProps<SVGSVGElement>) => (
5-
<svg viewBox="0 0 65 64" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
5+
<svg
6+
viewBox="0 0 65 64"
7+
fill="none"
8+
xmlns="http://www.w3.org/2000/svg"
9+
strokeWidth={4}
10+
{...props}
11+
>
612
<circle cx={32.5} cy={32} r={24} fill="currentColor" />
713
<path
814
d="m41.5 26-12 12-6-6"
915
stroke="#fff"
10-
strokeWidth={4}
16+
strokeWidth="inherit"
1117
strokeLinecap="round"
1218
strokeLinejoin="round"
1319
/>

src/components/v2/Icon/icons/dots.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import * as React from 'react';
2+
import { SVGProps } from 'react';
3+
4+
const SvgDots = (props: SVGProps<SVGSVGElement>) => (
5+
<svg
6+
width="21"
7+
height="4"
8+
viewBox="0 0 21 4"
9+
fill="none"
10+
xmlns="http://www.w3.org/2000/svg"
11+
{...props}
12+
>
13+
<circle cx="10.5" cy="2" r="2" fill="currentColor" />
14+
<circle cx="18.5" cy="2" r="2" fill="currentColor" />
15+
<circle cx="2.5" cy="2" r="2" fill="currentColor" />
16+
</svg>
17+
);
18+
19+
export default SvgDots;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as React from 'react';
2+
import { SVGProps } from 'react';
3+
4+
const SvgExclamation = (props: SVGProps<SVGSVGElement>) => (
5+
<svg viewBox="0 0 3 18" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
6+
<circle cx="1.5" cy="16.5" r="1.5" fill="currentColor" />
7+
<rect x="0.5" width="2" height="12" rx="1" fill="currentColor" />
8+
</svg>
9+
);
10+
11+
export default SvgExclamation;

src/components/v2/Icon/icons/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ export { default as checkInline } from './checkInline';
3535
export { default as mark } from './mark';
3636
export { default as arrowShaft } from './arrowShaft';
3737
export { default as notice } from './notice';
38+
export { default as dots } from './dots';
39+
export { default as exclamation } from './exclamation';
3840

3941
// Coin icons
4042
export { default as aave } from './coins/aave';
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import React from 'react';
2+
import { withThemeProvider, withCenterStory } from 'stories/decorators';
3+
import { VoteProposalUi } from '.';
4+
5+
export default {
6+
title: 'Components/VoteProposalUi',
7+
decorators: [withThemeProvider, withCenterStory({ width: 750 })],
8+
parameters: {
9+
backgrounds: {
10+
default: 'Default',
11+
},
12+
},
13+
};
14+
15+
export const Active = () => (
16+
<VoteProposalUi
17+
proposalNumber={58}
18+
proposalText="Buy back and burn and Tokenomic contribution finised soon"
19+
proposalStatus="active"
20+
votedFor="2130.02 XVS"
21+
votedAgainst="2130.02 XVS"
22+
abstain="100 XVS"
23+
voteStatus="votedFor"
24+
/>
25+
);
26+
export const Queued = () => (
27+
<VoteProposalUi
28+
proposalNumber={58}
29+
proposalText="Buy back and burn and Tokenomic contribution finised soon"
30+
proposalStatus="queued"
31+
/>
32+
);
33+
export const ReadyToExecute = () => (
34+
<VoteProposalUi
35+
proposalNumber={58}
36+
proposalText="Buy back and burn and Tokenomic contribution finised soon"
37+
proposalStatus="readyToExecute"
38+
/>
39+
);
40+
export const Executed = () => (
41+
<VoteProposalUi
42+
proposalNumber={58}
43+
proposalText="Buy back and burn and Tokenomic contribution finised soon"
44+
proposalStatus="executed"
45+
/>
46+
);
47+
export const Cancelled = () => (
48+
<VoteProposalUi
49+
proposalNumber={58}
50+
proposalText="Buy back and burn and Tokenomic contribution finised soon"
51+
proposalStatus="cancelled"
52+
/>
53+
);
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/** @jsxImportSource @emotion/react */
2+
import React, { useMemo } from 'react';
3+
import Paper from '@mui/material/Paper';
4+
import Grid from '@mui/material/Grid';
5+
import Typography from '@mui/material/Typography';
6+
7+
import { useTranslation } from 'translation';
8+
import { Icon } from '../Icon';
9+
import { ProgressBar } from '../ProgressBar';
10+
import { useStyles } from './styles';
11+
12+
type ProposalStatus = 'active' | 'queued' | 'readyToExecute' | 'executed' | 'cancelled';
13+
14+
interface IStatusCard {
15+
status: ProposalStatus;
16+
votedFor?: string;
17+
votedAgainst?: string;
18+
abstain?: string;
19+
}
20+
21+
const StatusCard: React.FC<IStatusCard> = ({ status, votedFor, votedAgainst, abstain }) => {
22+
const styles = useStyles();
23+
const { t } = useTranslation();
24+
25+
switch (status) {
26+
case 'active':
27+
return (
28+
<>
29+
<div css={styles.voteRow}>
30+
<Typography variant="small2" color="textPrimary">
31+
{t('voteProposalUi.statusCard.for')}
32+
</Typography>
33+
34+
<Typography variant="small2" color="textPrimary">
35+
{votedFor}
36+
</Typography>
37+
</div>
38+
<ProgressBar value={20} step={1} ariaLabel="progress" min={1} max={100} />
39+
40+
<div css={styles.voteRow}>
41+
<Typography variant="small2" color="textPrimary">
42+
{t('voteProposalUi.statusCard.against')}
43+
</Typography>
44+
45+
<Typography variant="small2" color="textPrimary">
46+
{votedAgainst}
47+
</Typography>
48+
</div>
49+
<ProgressBar value={20} step={1} ariaLabel="progress" min={1} max={100} />
50+
51+
<div css={styles.voteRow}>
52+
<Typography variant="small2" color="textPrimary">
53+
{t('voteProposalUi.statusCard.abstain')}
54+
</Typography>
55+
56+
<Typography variant="small2" color="textPrimary">
57+
{abstain}
58+
</Typography>
59+
</div>
60+
<ProgressBar value={5} step={1} ariaLabel="progress" min={1} max={100} />
61+
</>
62+
);
63+
case 'queued':
64+
return (
65+
<>
66+
<div css={[styles.iconWrapper, styles.iconDotsWrapper]}>
67+
<Icon css={styles.icon} name="dots" />
68+
</div>
69+
<Typography css={styles.statusText} variant="body2">
70+
{t('voteProposalUi.statusCard.queued')}
71+
</Typography>
72+
</>
73+
);
74+
case 'readyToExecute':
75+
return (
76+
<>
77+
<div css={[styles.iconWrapper, styles.iconInfoWrapper]}>
78+
<Icon css={styles.icon} name="exclamation" />
79+
</div>
80+
<Typography css={styles.statusText} variant="body2">
81+
{t('voteProposalUi.statusCard.readyToExecute')}
82+
</Typography>
83+
</>
84+
);
85+
case 'executed':
86+
return (
87+
<>
88+
<div css={[styles.iconWrapper, styles.iconMarkWrapper]}>
89+
<Icon css={[styles.icon, styles.iconCheck]} name="mark" />
90+
</div>
91+
<Typography css={styles.statusText} variant="body2">
92+
{t('voteProposalUi.statusCard.executed')}
93+
</Typography>
94+
</>
95+
);
96+
default:
97+
case 'cancelled':
98+
return (
99+
<>
100+
<div css={[styles.iconWrapper, styles.iconCloseWrapper]}>
101+
<Icon css={styles.icon} name="close" />
102+
</div>
103+
<Typography css={styles.statusText} variant="body2">
104+
{t('voteProposalUi.statusCard.cancelled')}
105+
</Typography>
106+
</>
107+
);
108+
}
109+
};
110+
111+
type VoteStatus = 'votedFor' | 'votedAgainst' | 'abstained';
112+
113+
interface IVoteProposalUiProps {
114+
className?: string;
115+
proposalNumber: number;
116+
proposalText: string;
117+
proposalStatus: ProposalStatus;
118+
voteStatus?: VoteStatus;
119+
votedFor?: string;
120+
votedAgainst?: string;
121+
abstain?: string;
122+
}
123+
124+
export const VoteProposalUi: React.FC<IVoteProposalUiProps> = ({
125+
className,
126+
proposalNumber,
127+
proposalText,
128+
proposalStatus,
129+
voteStatus,
130+
votedFor,
131+
votedAgainst,
132+
abstain,
133+
}) => {
134+
const styles = useStyles();
135+
const { t } = useTranslation();
136+
137+
const voteStatusText = useMemo(() => {
138+
switch (voteStatus) {
139+
case 'votedFor':
140+
return t('voteProposalUi.voteStatus.votedFor');
141+
case 'votedAgainst':
142+
return t('voteProposalUi.voteStatus.votedAgainst');
143+
case 'abstained':
144+
return t('voteProposalUi.voteStatus.abstained');
145+
default:
146+
return t('voteProposalUi.voteStatus.notVoted');
147+
}
148+
}, [voteStatus]);
149+
150+
return (
151+
<Paper className={className} css={styles.root}>
152+
<Grid container>
153+
<Grid css={[styles.gridItem, styles.gridItemLeft]} item xs={12} sm={8}>
154+
<div css={styles.cardHeader}>
155+
<div css={styles.cardBadges}>
156+
<Typography
157+
variant="small2"
158+
color="textPrimary"
159+
css={[styles.cardBadgeItem, styles.cardBadgeNumber]}
160+
>
161+
#{proposalNumber}
162+
</Typography>
163+
{proposalStatus === 'active' && (
164+
<Typography
165+
variant="small2"
166+
color="textPrimary"
167+
css={[styles.cardBadgeItem, styles.cardBadgeActive]}
168+
>
169+
{t('voteProposalUi.proposalStatus.active')}
170+
</Typography>
171+
)}
172+
</div>
173+
174+
<Typography variant="small2">{voteStatusText}</Typography>
175+
</div>
176+
177+
<Typography variant="h4" css={styles.cardTitle}>
178+
{proposalText}
179+
</Typography>
180+
181+
<div css={styles.cardFooter}>
182+
<Typography variant="small2">
183+
{t('voteProposalUi.activeUntil')}
184+
<Typography variant="small2" color="textPrimary">
185+
27 Jun 13:54
186+
</Typography>
187+
</Typography>
188+
189+
<Typography color="textPrimary" variant="small2">
190+
27h : 13m : 54s
191+
</Typography>
192+
</div>
193+
</Grid>
194+
<Grid css={[styles.gridItem, styles.gridItemRight]} item xs={12} sm={4}>
195+
<StatusCard
196+
status={proposalStatus}
197+
votedFor={votedFor}
198+
votedAgainst={votedAgainst}
199+
abstain={abstain}
200+
/>
201+
</Grid>
202+
</Grid>
203+
</Paper>
204+
);
205+
};

0 commit comments

Comments
 (0)