Skip to content

Commit bf79694

Browse files
SV UI Look&Feel: Tabs (#3304)
Signed-off-by: Paweł Perek <pawel.perek@digitalasset.com>
1 parent d23617b commit bf79694

File tree

7 files changed

+136
-122
lines changed

7 files changed

+136
-122
lines changed

apps/common/frontend/src/theme/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ declare module '@mui/material/styles' {
2727
neutral: Record<string, string>;
2828
primary: Record<string, string>;
2929
secondary: string;
30+
tertiary: string;
3031
mainnet: string;
3132
testnet: string;
3233
devnet: string;
@@ -39,6 +40,7 @@ declare module '@mui/material/styles' {
3940
neutral?: Record<string, string>;
4041
primary?: Record<string, string>;
4142
secondary?: string;
43+
tertiary?: string;
4244
mainnet: string;
4345
testnet: string;
4446
devnet: string;
@@ -78,6 +80,7 @@ let theme = createTheme({
7880
neutral: generateHslPalette(0, 0, [0, 10, 15, 25, 30, 40, 50, 60, 70, 80]),
7981
primary: generateHslPalette(195, 96, [79, 89]),
8082
secondary: '#F3FF97',
83+
tertiary: '#875CFF',
8184
mainnet: '#F8FDCD',
8285
testnet: '#C8F1FE',
8386
devnet: '#C6B2FF',
@@ -101,6 +104,9 @@ theme = createTheme(theme, {
101104
secondary: {
102105
main: '#F3FF97',
103106
},
107+
tertiary: {
108+
main: '#875CFF',
109+
},
104110
warning: {
105111
main: '#FD8575',
106112
},

apps/sv/frontend/src/__tests__/governance/proposal-details-content.test.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ describe('Proposal Details > Votes & Voting', () => {
612612
</Wrapper>
613613
);
614614

615-
const yourVoteBadge = screen.getByTestId('proposal-details-your-vote-chip');
615+
const yourVoteBadge = screen.getByTestId('proposal-details-voter-party-id-badge');
616616
expect(yourVoteBadge).toBeInTheDocument();
617617
});
618618

@@ -629,9 +629,7 @@ describe('Proposal Details > Votes & Voting', () => {
629629
</Wrapper>
630630
);
631631

632-
expect(() => screen.getByTestId('proposal-details-your-vote-chip')).toThrowError(
633-
/Unable to find an element/
634-
);
632+
expect(screen.queryByTestId('proposal-details-voter-party-id-badge')).not.toBeInTheDocument();
635633
});
636634

637635
test('should render status badge in votes list', async () => {

apps/sv/frontend/src/beta-theme/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ let betaTheme = createTheme({
2020
neutral: generateHslPalette(0, 0, [0, 10, 15, 25, 30, 40, 50, 60, 70, 80]),
2121
primary: generateHslPalette(195, 96, [79, 89]),
2222
secondary: '#F3FF97',
23+
tertiary: '#875CFF',
2324
mainnet: '#F8FDCD',
2425
testnet: '#C8F1FE',
2526
devnet: '#C6B2FF',
@@ -43,6 +44,9 @@ betaTheme = createTheme(betaTheme, {
4344
secondary: {
4445
main: '#F3FF97',
4546
},
47+
tertiary: {
48+
main: '#875CFF',
49+
},
4650
warning: {
4751
main: '#FD8575',
4852
},
@@ -217,7 +221,7 @@ betaTheme = createTheme(betaTheme, {
217221
MuiChip: {
218222
styleOverrides: {
219223
root: {
220-
backgroundColor: betaTheme.palette.primary.main,
224+
backgroundColor: betaTheme.palette.grey,
221225
},
222226
},
223227
},
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
import { Stack, Typography, TypographyProps } from '@mui/material';
4+
import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';
5+
import CancelOutlinedIcon from '@mui/icons-material/CancelOutlined';
6+
import { YourVoteStatus } from '../../utils/types';
7+
8+
interface VoteStatsProps {
9+
vote: YourVoteStatus;
10+
noVoteMessage?: string;
11+
count?: number;
12+
typography?: TypographyProps;
13+
'data-testid': string;
14+
}
15+
16+
const VoteStats: React.FC<VoteStatsProps> = ({
17+
vote,
18+
noVoteMessage = 'No Vote',
19+
count,
20+
typography,
21+
'data-testid': testId,
22+
}) => {
23+
if (vote === 'accepted') {
24+
return (
25+
<Stack direction="row" gap="4px" alignItems="center" data-testid={testId}>
26+
<CheckCircleOutlineIcon
27+
fontSize="small"
28+
color="success"
29+
data-testid={`${testId}-accepted-icon`}
30+
/>
31+
<Typography {...typography} data-testid={`${testId}-value`}>
32+
{count !== undefined && `${count} `}Accepted
33+
</Typography>
34+
</Stack>
35+
);
36+
}
37+
38+
if (vote === 'rejected') {
39+
return (
40+
<Stack direction="row" gap="4px" alignItems="center" data-testid={testId}>
41+
<CancelOutlinedIcon
42+
fontSize="small"
43+
color="error"
44+
data-testid={`${testId}-rejected-icon`}
45+
/>
46+
<Typography {...typography} data-testid={`${testId}-value`}>
47+
{count !== undefined && `${count} `}Rejected
48+
</Typography>
49+
</Stack>
50+
);
51+
}
52+
53+
return (
54+
<Typography {...typography} data-testid={`${testId}-value`}>
55+
{noVoteMessage}
56+
</Typography>
57+
);
58+
};
59+
60+
export default VoteStats;

apps/sv/frontend/src/components/beta/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ import CopyableIdentifier from './CopyableIdentifier';
55
import MemberIdentifier from './MemberIdentifier';
66
import PageHeader from './PageHeader';
77
import PageSectionHeader from './PageSectionHeader';
8+
import VoteStats from './VoteStats';
89

9-
export { CopyableIdentifier, MemberIdentifier, PageHeader, PageSectionHeader };
10+
export { CopyableIdentifier, MemberIdentifier, PageHeader, PageSectionHeader, VoteStats };

apps/sv/frontend/src/components/governance/ProposalDetailsContent.tsx

Lines changed: 36 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,14 @@ import {
88
} from '@daml.js/splice-dso-governance/lib/Splice/DsoRules';
99
import { ContractId } from '@daml/types';
1010
import { ChevronLeft } from '@mui/icons-material';
11-
import { Box, Button, Chip, Link, Stack, Tab, Tabs, Typography } from '@mui/material';
11+
import { Box, Button, Divider, Link, Stack, Tab, Tabs, Typography } from '@mui/material';
1212
import React, { PropsWithChildren, useMemo, useState } from 'react';
1313
import dayjs from 'dayjs';
1414
import relativeTime from 'dayjs/plugin/relativeTime';
1515
import {
1616
getAmuletConfigToCompareWith,
1717
getDsoConfigToCompareWith,
18-
PartyId,
1918
PrettyJsonDiff,
20-
theme,
2119
useVotesHooks,
2220
} from '@lfdecentralizedtrust/splice-common-frontend';
2321
import { sanitizeUrl } from '@lfdecentralizedtrust/splice-common-frontend-utils';
@@ -34,7 +32,7 @@ import { JsonDiffAccordion } from './JsonDiffAccordion';
3432
import { useDsoInfos } from '../../contexts/SvContext';
3533
import { DetailItem } from './proposal-details/DetailItem';
3634
import { CreateUnallocatedUnclaimedActivityRecordSection } from './proposal-details/CreateUnallocatedUnclaimedActivityRecordSection';
37-
import { CopyableIdentifier, MemberIdentifier } from '../beta';
35+
import { CopyableIdentifier, MemberIdentifier, VoteStats } from '../beta';
3836

3937
dayjs.extend(relativeTime);
4038

@@ -348,6 +346,15 @@ export const ProposalDetailsContent: React.FC<ProposalDetailsContentProps> = pro
348346
onChange={handleVoteTabChange}
349347
aria-label="vote tabs"
350348
data-testid="votes-tabs"
349+
sx={{
350+
// after experimenting with it a little, this is probably the best way to put something akin to borderBottom
351+
// inside of the <Tab> components so it doesn't interfere with <Tabs> overflow: hidden property
352+
boxShadow: 'inset 0 -2px 0 0 rgba(255, 255, 255, 0.12)',
353+
'& .MuiTabs-indicator': {
354+
backgroundColor: 'colors.tertiary',
355+
height: '2px',
356+
},
357+
}}
351358
>
352359
<Tab label={`All (${votes.length})`} value="all" data-testid="all-votes-tab" />
353360
<Tab
@@ -373,7 +380,7 @@ export const ProposalDetailsContent: React.FC<ProposalDetailsContentProps> = pro
373380
</Tabs>
374381

375382
<Box
376-
sx={{ display: 'flex', flexDirection: 'column', gap: 2, mb: 4 }}
383+
sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}
377384
data-testid="proposal-details-votes-list"
378385
>
379386
{getFilteredVotes().map((vote, index) => (
@@ -435,64 +442,34 @@ interface VoteItemProps {
435442
isYou?: boolean;
436443
}
437444

438-
const VoteItem = ({ voter, url, comment, status, isClosed, isYou = false }: VoteItemProps) => {
439-
const getStatusColor = () => {
440-
switch (status) {
441-
case 'accepted':
442-
return theme.palette.success.main;
443-
case 'rejected':
444-
return theme.palette.error.main;
445-
case 'no-vote':
446-
return isClosed ? theme.palette.error.main : '#ff9800';
447-
default:
448-
return '#757575';
449-
}
450-
};
451-
452-
const getStatusText = () => {
453-
switch (status) {
454-
case 'accepted':
455-
return 'Accepted';
456-
case 'rejected':
457-
return 'Rejected';
458-
case 'no-vote':
459-
return isClosed ? 'No Vote' : 'Awaiting Response';
460-
}
461-
};
462-
463-
return (
445+
const VoteItem: React.FC<VoteItemProps> = ({
446+
voter,
447+
url,
448+
comment,
449+
status,
450+
isClosed,
451+
isYou = false,
452+
}) => (
453+
<>
464454
<Box
465455
sx={{
466-
p: 2,
467-
border: '1px solid rgba(81, 81, 81, 1)',
468-
borderRadius: 2,
469456
display: 'flex',
470457
justifyContent: 'space-between',
471-
alignItems: 'flex-start',
458+
alignItems: 'center',
472459
}}
473460
data-testid="proposal-details-vote"
474461
>
475462
<Box sx={{ flexGrow: 1 }}>
476-
<Box sx={{ display: 'flex', alignItems: 'center', mb: 1 }}>
477-
<PartyId
463+
<Box sx={{ display: 'flex', alignItems: 'center' }}>
464+
<MemberIdentifier
478465
partyId={voter}
479-
className="proposal-details-voter-party-id"
480-
id="proposal-details-voter-party-id"
466+
size="large"
467+
isYou={isYou}
468+
data-testid="proposal-details-voter-party-id"
481469
/>
482-
{isYou && (
483-
<Chip
484-
label="You"
485-
size="small"
486-
sx={{
487-
ml: 1,
488-
bgcolor: 'rgba(255, 255, 255, 0.1)',
489-
}}
490-
data-testid="proposal-details-your-vote-chip"
491-
/>
492-
)}
493470
</Box>
494471
{comment && (
495-
<Typography variant="body2" color="text.secondary">
472+
<Typography fontSize={16} color="text.secondary">
496473
{comment}
497474
</Typography>
498475
)}
@@ -504,29 +481,15 @@ const VoteItem = ({ voter, url, comment, status, isClosed, isYou = false }: Vote
504481
</Typography>
505482
)}
506483
</Box>
507-
<Box sx={{ display: 'flex', alignItems: 'center' }}>
508-
<Box
509-
component="span"
510-
sx={{
511-
display: 'inline-block',
512-
width: 16,
513-
height: 16,
514-
borderRadius: '50%',
515-
bgcolor: getStatusColor(),
516-
mr: 1,
517-
}}
518-
/>
519-
<Typography
520-
variant="body2"
521-
color={getStatusColor()}
522-
data-testid="proposal-details-vote-status-value"
523-
>
524-
{getStatusText()}
525-
</Typography>
526-
</Box>
484+
<VoteStats
485+
vote={status}
486+
noVoteMessage={isClosed ? 'No Vote' : 'Awaiting Response'}
487+
data-testid="proposal-details-vote-status"
488+
/>
527489
</Box>
528-
);
529-
};
490+
<Divider sx={{ borderBottomWidth: 2 }} />
491+
</>
492+
);
530493

531494
interface OffboardMemberSectionProps {
532495
memberPartyId: string;

0 commit comments

Comments
 (0)