diff options
Diffstat (limited to 'packages/renderer/src')
-rw-r--r-- | packages/renderer/src/components/sidebar/ServiceIcon.tsx | 78 |
1 files changed, 30 insertions, 48 deletions
diff --git a/packages/renderer/src/components/sidebar/ServiceIcon.tsx b/packages/renderer/src/components/sidebar/ServiceIcon.tsx index 83b2a5f..144f860 100644 --- a/packages/renderer/src/components/sidebar/ServiceIcon.tsx +++ b/packages/renderer/src/components/sidebar/ServiceIcon.tsx | |||
@@ -22,7 +22,7 @@ import Badge from '@mui/material/Badge'; | |||
22 | import { styled, useTheme } from '@mui/material/styles'; | 22 | import { styled, useTheme } from '@mui/material/styles'; |
23 | import { Service } from '@sophie/shared'; | 23 | import { Service } from '@sophie/shared'; |
24 | import { observer } from 'mobx-react-lite'; | 24 | import { observer } from 'mobx-react-lite'; |
25 | import React from 'react'; | 25 | import React, { useEffect, useState } from 'react'; |
26 | 26 | ||
27 | const ServiceIconRoot = styled('div', { | 27 | const ServiceIconRoot = styled('div', { |
28 | name: 'ServiceIcon', | 28 | name: 'ServiceIcon', |
@@ -47,39 +47,15 @@ const ServiceIconText = styled('div', { | |||
47 | color: theme.palette.primary.contrastText, | 47 | color: theme.palette.primary.contrastText, |
48 | })); | 48 | })); |
49 | 49 | ||
50 | const IndirectMessageBadge = styled(Badge)(({ theme }) => ({ | 50 | const ServiceIconBadge = styled(Badge, { |
51 | '& .MuiBadge-dot': { | 51 | name: 'ServiceIcon', |
52 | // The indirect message badge floats ouside the icon in the middle. | 52 | slot: 'Badge', |
53 | top: '50%', | 53 | })(({ theme }) => ({ |
54 | ...(theme.direction === 'ltr' | 54 | '.MuiBadge-dot': { |
55 | ? { | ||
56 | left: theme.spacing(-1), | ||
57 | } | ||
58 | : { | ||
59 | right: theme.spacing(-1), | ||
60 | }), | ||
61 | background: | 55 | background: |
62 | theme.palette.mode === 'dark' | 56 | theme.palette.mode === 'dark' |
63 | ? theme.palette.text.primary | 57 | ? theme.palette.text.primary |
64 | : 'currentColor', | 58 | : theme.palette.primary.light, |
65 | }, | ||
66 | })); | ||
67 | |||
68 | const DirectMessageBadge = styled(Badge)(({ theme }) => ({ | ||
69 | '& .MuiBadge-badge': { | ||
70 | // Move the badge closer to the icon so that even "99+" messages can fit in the sidebar. | ||
71 | ...(theme.direction === 'ltr' | ||
72 | ? { | ||
73 | right: theme.spacing(0.25), | ||
74 | } | ||
75 | : { | ||
76 | left: theme.spacing(0.25), | ||
77 | }), | ||
78 | top: theme.spacing(0.25), | ||
79 | // Set the badge apart from the icon with a shadow (a border would be too heavy). | ||
80 | boxShadow: theme.shadows[1], | ||
81 | // Add a bit more emphasis to the badge. | ||
82 | fontWeight: 700, | ||
83 | }, | 59 | }, |
84 | })); | 60 | })); |
85 | 61 | ||
@@ -91,28 +67,34 @@ function ServiceIcon({ service }: { service: Service }): JSX.Element { | |||
91 | indirectMessageCount, | 67 | indirectMessageCount, |
92 | } = service; | 68 | } = service; |
93 | 69 | ||
70 | // Hadge color histeresis for smooth appear / disappear animation. | ||
71 | // If we compute hasDirectMessage = directMessageCount >= 1 directly (without any histeresis), | ||
72 | // the badge momentarily turns light during the disappear animation. | ||
73 | const [hasDirectMessage, setHasDirectMessage] = useState(false); | ||
74 | useEffect(() => { | ||
75 | if (directMessageCount >= 1) { | ||
76 | setHasDirectMessage(true); | ||
77 | } else if (indirectMessageCount >= 1) { | ||
78 | setHasDirectMessage(false); | ||
79 | } | ||
80 | }, [directMessageCount, indirectMessageCount, setHasDirectMessage]); | ||
81 | |||
94 | return ( | 82 | return ( |
95 | <IndirectMessageBadge | 83 | <ServiceIconBadge |
96 | badgeContent={indirectMessageCount} | 84 | badgeContent={ |
97 | variant="dot" | 85 | hasDirectMessage ? directMessageCount : indirectMessageCount |
86 | } | ||
87 | variant={hasDirectMessage ? 'standard' : 'dot'} | ||
88 | color="error" | ||
98 | anchorOrigin={{ | 89 | anchorOrigin={{ |
99 | vertical: 'top', | 90 | vertical: 'top', |
100 | horizontal: direction === 'ltr' ? 'left' : 'right', | 91 | horizontal: direction === 'ltr' ? 'right' : 'left', |
101 | }} | 92 | }} |
102 | > | 93 | > |
103 | <DirectMessageBadge | 94 | <ServiceIconRoot> |
104 | badgeContent={directMessageCount} | 95 | <ServiceIconText>{name.length > 0 ? name[0] : '?'}</ServiceIconText> |
105 | color="error" | 96 | </ServiceIconRoot> |
106 | anchorOrigin={{ | 97 | </ServiceIconBadge> |
107 | vertical: 'top', | ||
108 | horizontal: direction === 'ltr' ? 'right' : 'left', | ||
109 | }} | ||
110 | > | ||
111 | <ServiceIconRoot> | ||
112 | <ServiceIconText>{name.length > 0 ? name[0] : '?'}</ServiceIconText> | ||
113 | </ServiceIconRoot> | ||
114 | </DirectMessageBadge> | ||
115 | </IndirectMessageBadge> | ||
116 | ); | 98 | ); |
117 | } | 99 | } |
118 | 100 | ||