aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2022-02-06 15:30:57 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2022-02-08 21:43:18 +0100
commit3e73cfb2dcaec87b2ea1066cd4472c36bcb7138f (patch)
tree28cc0533b20fe24002c1dc4d20577eaaac03ff20
parentfeat: Save selected service to file (diff)
downloadsophie-3e73cfb2dcaec87b2ea1066cd4472c36bcb7138f.tar.gz
sophie-3e73cfb2dcaec87b2ea1066cd4472c36bcb7138f.tar.zst
sophie-3e73cfb2dcaec87b2ea1066cd4472c36bcb7138f.zip
feat: Unread message badges
-rw-r--r--packages/renderer/src/components/ServiceIcon.tsx80
-rw-r--r--packages/renderer/src/components/ServiceSwitcher.tsx13
-rw-r--r--packages/renderer/src/components/Sidebar.tsx2
3 files changed, 81 insertions, 14 deletions
diff --git a/packages/renderer/src/components/ServiceIcon.tsx b/packages/renderer/src/components/ServiceIcon.tsx
index e02da71..83b2a5f 100644
--- a/packages/renderer/src/components/ServiceIcon.tsx
+++ b/packages/renderer/src/components/ServiceIcon.tsx
@@ -18,15 +18,18 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import { styled } from '@mui/material/styles'; 21import Badge from '@mui/material/Badge';
22import { styled, useTheme } from '@mui/material/styles';
23import { Service } from '@sophie/shared';
24import { observer } from 'mobx-react-lite';
22import React from 'react'; 25import React from 'react';
23 26
24const ServiceIconRoot = styled('div', { 27const ServiceIconRoot = styled('div', {
25 name: 'ServiceIcon', 28 name: 'ServiceIcon',
26 slot: 'Root', 29 slot: 'Root',
27})(({ theme }) => ({ 30})(({ theme }) => ({
28 width: 34, 31 width: 36,
29 height: 34, 32 height: 36,
30 borderRadius: theme.shape.borderRadius, 33 borderRadius: theme.shape.borderRadius,
31 background: 'currentColor', 34 background: 'currentColor',
32 display: 'flex', 35 display: 'flex',
@@ -44,10 +47,73 @@ const ServiceIconText = styled('div', {
44 color: theme.palette.primary.contrastText, 47 color: theme.palette.primary.contrastText,
45})); 48}));
46 49
47export default function ServiceIcon({ name }: { name: string }): JSX.Element { 50const IndirectMessageBadge = styled(Badge)(({ theme }) => ({
51 '& .MuiBadge-dot': {
52 // The indirect message badge floats ouside the icon in the middle.
53 top: '50%',
54 ...(theme.direction === 'ltr'
55 ? {
56 left: theme.spacing(-1),
57 }
58 : {
59 right: theme.spacing(-1),
60 }),
61 background:
62 theme.palette.mode === 'dark'
63 ? theme.palette.text.primary
64 : 'currentColor',
65 },
66}));
67
68const 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 },
84}));
85
86function ServiceIcon({ service }: { service: Service }): JSX.Element {
87 const { direction } = useTheme();
88 const {
89 settings: { name },
90 directMessageCount,
91 indirectMessageCount,
92 } = service;
93
48 return ( 94 return (
49 <ServiceIconRoot> 95 <IndirectMessageBadge
50 <ServiceIconText>{name.length > 0 ? name[0] : '?'}</ServiceIconText> 96 badgeContent={indirectMessageCount}
51 </ServiceIconRoot> 97 variant="dot"
98 anchorOrigin={{
99 vertical: 'top',
100 horizontal: direction === 'ltr' ? 'left' : 'right',
101 }}
102 >
103 <DirectMessageBadge
104 badgeContent={directMessageCount}
105 color="error"
106 anchorOrigin={{
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>
52 ); 116 );
53} 117}
118
119export default observer(ServiceIcon);
diff --git a/packages/renderer/src/components/ServiceSwitcher.tsx b/packages/renderer/src/components/ServiceSwitcher.tsx
index e4d371e..2cf997e 100644
--- a/packages/renderer/src/components/ServiceSwitcher.tsx
+++ b/packages/renderer/src/components/ServiceSwitcher.tsx
@@ -32,7 +32,6 @@ const ServiceSwitcherRoot = styled(Tabs, {
32 slot: 'Root', 32 slot: 'Root',
33})(({ theme }) => ({ 33})(({ theme }) => ({
34 '.MuiTabs-indicator': { 34 '.MuiTabs-indicator': {
35 width: 3,
36 ...(theme.direction === 'ltr' 35 ...(theme.direction === 'ltr'
37 ? { 36 ? {
38 left: 0, 37 left: 0,
@@ -56,12 +55,12 @@ const ServiceSwitcherTab = styled(Tab, {
56 '&.Mui-selected': { 55 '&.Mui-selected': {
57 backgroundColor: 56 backgroundColor:
58 theme.palette.mode === 'dark' 57 theme.palette.mode === 'dark'
59 ? alpha(theme.palette.text.primary, 0.16) 58 ? alpha(theme.palette.text.primary, 0.12)
60 : alpha(theme.palette.primary.light, 0.3), 59 : alpha(theme.palette.primary.light, 0.24),
61 }, 60 },
62})); 61}));
63 62
64export default observer(() => { 63function ServiceSwitcher(): JSX.Element {
65 const store = useStore(); 64 const store = useStore();
66 const { 65 const {
67 settings: { selectedService }, 66 settings: { selectedService },
@@ -81,10 +80,12 @@ export default observer(() => {
81 <ServiceSwitcherTab 80 <ServiceSwitcherTab
82 key={service.id} 81 key={service.id}
83 value={service.id} 82 value={service.id}
84 icon={<ServiceIcon name={service.settings.name} />} 83 icon={<ServiceIcon service={service} />}
85 aria-label={service.settings.name} 84 aria-label={service.settings.name}
86 /> 85 />
87 ))} 86 ))}
88 </ServiceSwitcherRoot> 87 </ServiceSwitcherRoot>
89 ); 88 );
90}); 89}
90
91export default observer(ServiceSwitcher);
diff --git a/packages/renderer/src/components/Sidebar.tsx b/packages/renderer/src/components/Sidebar.tsx
index ed78fc6..0eb8f93 100644
--- a/packages/renderer/src/components/Sidebar.tsx
+++ b/packages/renderer/src/components/Sidebar.tsx
@@ -39,7 +39,7 @@ export default function Sidebar(): JSX.Element {
39 backgroundClip: 'padding-box', 39 backgroundClip: 'padding-box',
40 background: alpha(theme.palette.text.primary, 0.09), 40 background: alpha(theme.palette.text.primary, 0.09),
41 borderInlineEnd: `1px solid ${theme.palette.divider}`, 41 borderInlineEnd: `1px solid ${theme.palette.divider}`,
42 minWidth: 67, 42 minWidth: 69,
43 })} 43 })}
44 > 44 >
45 <ServiceSwitcher /> 45 <ServiceSwitcher />