aboutsummaryrefslogtreecommitdiffstats
path: root/packages/renderer
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2022-03-14 20:06:52 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2022-05-16 00:54:54 +0200
commit1743621c3c2b0474be81276390fa45399105a4af (patch)
tree8b2eadd937fa13816a8702cd2873daced241f66c /packages/renderer
parentfeat(renderer): Update window title (diff)
downloadsophie-1743621c3c2b0474be81276390fa45399105a4af.tar.gz
sophie-1743621c3c2b0474be81276390fa45399105a4af.tar.zst
sophie-1743621c3c2b0474be81276390fa45399105a4af.zip
feat(renderer): Show service error on service icon
Service icons fade out on errors and an icon is displayed. Signed-off-by: Kristóf Marussy <kristof@marussy.com>
Diffstat (limited to 'packages/renderer')
-rw-r--r--packages/renderer/src/components/sidebar/ServiceIcon.tsx71
1 files changed, 52 insertions, 19 deletions
diff --git a/packages/renderer/src/components/sidebar/ServiceIcon.tsx b/packages/renderer/src/components/sidebar/ServiceIcon.tsx
index fe047cf..b8f9b96 100644
--- a/packages/renderer/src/components/sidebar/ServiceIcon.tsx
+++ b/packages/renderer/src/components/sidebar/ServiceIcon.tsx
@@ -18,6 +18,7 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import IconWarning from '@mui/icons-material/Warning';
21import Badge from '@mui/material/Badge'; 22import Badge from '@mui/material/Badge';
22import { styled, useTheme } from '@mui/material/styles'; 23import { styled, useTheme } from '@mui/material/styles';
23import { observer } from 'mobx-react-lite'; 24import { observer } from 'mobx-react-lite';
@@ -28,7 +29,8 @@ import type Service from '../../stores/Service';
28const ServiceIconRoot = styled('div', { 29const ServiceIconRoot = styled('div', {
29 name: 'ServiceIcon', 30 name: 'ServiceIcon',
30 slot: 'Root', 31 slot: 'Root',
31})(({ theme }) => ({ 32 shouldForwardProp: (prop) => prop !== 'hasError',
33})<{ hasError: boolean }>(({ theme, hasError }) => ({
32 width: 36, 34 width: 36,
33 height: 36, 35 height: 36,
34 borderRadius: theme.shape.borderRadius, 36 borderRadius: theme.shape.borderRadius,
@@ -36,6 +38,13 @@ const ServiceIconRoot = styled('div', {
36 display: 'flex', 38 display: 'flex',
37 justifyContent: 'center', 39 justifyContent: 'center',
38 alignItems: 'center', 40 alignItems: 'center',
41 filter: hasError ? 'grayscale(100%)' : 'none',
42 opacity: hasError ? theme.palette.action.disabledOpacity : 1,
43 transition: theme.transitions.create(['filter', 'opacity'], {
44 duration: hasError
45 ? theme.transitions.duration.enteringScreen
46 : theme.transitions.duration.leavingScreen,
47 }),
39})); 48}));
40 49
41const ServiceIconText = styled('div', { 50const ServiceIconText = styled('div', {
@@ -48,15 +57,18 @@ const ServiceIconText = styled('div', {
48 color: theme.palette.primary.contrastText, 57 color: theme.palette.primary.contrastText,
49})); 58}));
50 59
51const ServiceIconBadge = styled(Badge, { 60const ServiceIconBadgeBase = styled(Badge)({
52 name: 'ServiceIcon', 61 '& > .MuiBadge-badge': {
53 slot: 'Badge',
54})(({ theme }) => ({
55 '.MuiBadge-badge': {
56 // Place badge above the sidebar inner shadow. 62 // Place badge above the sidebar inner shadow.
57 zIndex: 200, 63 zIndex: 200,
58 }, 64 },
59 '.MuiBadge-dot': { 65});
66
67const ServiceIconBadge = styled(ServiceIconBadgeBase, {
68 name: 'ServiceIcon',
69 slot: 'Badge',
70})(({ theme }) => ({
71 '& > .MuiBadge-dot': {
60 background: 72 background:
61 theme.palette.mode === 'dark' 73 theme.palette.mode === 'dark'
62 ? theme.palette.text.primary 74 ? theme.palette.text.primary
@@ -64,15 +76,28 @@ const ServiceIconBadge = styled(Badge, {
64 }, 76 },
65})); 77}));
66 78
79const ServiceIconErrorBadge = styled(ServiceIconBadgeBase, {
80 name: 'ServiceIcon',
81 slot: 'ErrorBadge',
82})(({ theme }) => ({
83 '& > .MuiBadge-standard': {
84 color:
85 theme.palette.mode === 'dark'
86 ? theme.palette.error.light
87 : theme.palette.error.main,
88 },
89}));
90
67function ServiceIcon({ service }: { service: Service }): JSX.Element { 91function ServiceIcon({ service }: { service: Service }): JSX.Element {
68 const { direction } = useTheme(); 92 const { direction } = useTheme();
69 const { 93 const {
70 settings: { name }, 94 settings: { name },
71 directMessageCount, 95 directMessageCount,
72 indirectMessageCount, 96 indirectMessageCount,
97 hasError,
73 } = service; 98 } = service;
74 99
75 // Hadge color histeresis for smooth appear / disappear animation. 100 // Badge color histeresis for smooth appear / disappear animation.
76 // If we compute hasDirectMessage = directMessageCount >= 1 directly (without any histeresis), 101 // If we compute hasDirectMessage = directMessageCount >= 1 directly (without any histeresis),
77 // the badge momentarily turns light during the disappear animation. 102 // the badge momentarily turns light during the disappear animation.
78 const [hasDirectMessage, setHasDirectMessage] = useState(false); 103 const [hasDirectMessage, setHasDirectMessage] = useState(false);
@@ -85,21 +110,29 @@ function ServiceIcon({ service }: { service: Service }): JSX.Element {
85 }, [directMessageCount, indirectMessageCount, setHasDirectMessage]); 110 }, [directMessageCount, indirectMessageCount, setHasDirectMessage]);
86 111
87 return ( 112 return (
88 <ServiceIconBadge 113 <ServiceIconErrorBadge
89 badgeContent={ 114 badgeContent={hasError ? <IconWarning fontSize="small" /> : 0}
90 hasDirectMessage ? directMessageCount : indirectMessageCount
91 }
92 variant={hasDirectMessage ? 'standard' : 'dot'}
93 color="error"
94 anchorOrigin={{ 115 anchorOrigin={{
95 vertical: 'top', 116 vertical: 'bottom',
96 horizontal: direction === 'ltr' ? 'right' : 'left', 117 horizontal: direction === 'ltr' ? 'right' : 'left',
97 }} 118 }}
98 > 119 >
99 <ServiceIconRoot> 120 <ServiceIconBadge
100 <ServiceIconText>{name.length > 0 ? name[0] : '?'}</ServiceIconText> 121 badgeContent={
101 </ServiceIconRoot> 122 hasDirectMessage ? directMessageCount : indirectMessageCount
102 </ServiceIconBadge> 123 }
124 variant={hasDirectMessage ? 'standard' : 'dot'}
125 color="error"
126 anchorOrigin={{
127 vertical: 'top',
128 horizontal: direction === 'ltr' ? 'right' : 'left',
129 }}
130 >
131 <ServiceIconRoot hasError={hasError}>
132 <ServiceIconText>{name.length > 0 ? name[0] : '?'}</ServiceIconText>
133 </ServiceIconRoot>
134 </ServiceIconBadge>
135 </ServiceIconErrorBadge>
103 ); 136 );
104} 137}
105 138