diff options
author | Kristóf Marussy <kristof@marussy.com> | 2022-04-14 17:15:19 +0200 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2022-05-16 00:55:01 +0200 |
commit | 95ff89bf41bcf23e7785b37b2515a5fbc966da15 (patch) | |
tree | a194b3f87af747db2e7486cc1055ab6bbb80229c /packages/renderer/src | |
parent | chore(deps): Bump electron to 19 for setBackgroundColor fix (diff) | |
download | sophie-95ff89bf41bcf23e7785b37b2515a5fbc966da15.tar.gz sophie-95ff89bf41bcf23e7785b37b2515a5fbc966da15.tar.zst sophie-95ff89bf41bcf23e7785b37b2515a5fbc966da15.zip |
fix(renderer): Flip all RTL styles
We need a sylis plugin for this according to
https://mui.com/material-ui/guides/right-to-left/#3-install-the-rtl-plugin
Signed-off-by: Kristóf Marussy <kristof@marussy.com>
Diffstat (limited to 'packages/renderer/src')
9 files changed, 84 insertions, 30 deletions
diff --git a/packages/renderer/src/components/NotificationBanner.tsx b/packages/renderer/src/components/NotificationBanner.tsx index 36c192a..c759d46 100644 --- a/packages/renderer/src/components/NotificationBanner.tsx +++ b/packages/renderer/src/components/NotificationBanner.tsx | |||
@@ -41,21 +41,21 @@ const NotificationBannerRoot = styled(Alert)(({ theme }) => ({ | |||
41 | justifyContent: 'center', | 41 | justifyContent: 'center', |
42 | }, | 42 | }, |
43 | '.MuiAlert-action': { | 43 | '.MuiAlert-action': { |
44 | paddingInlineStart: 0, | 44 | paddingLeft: 0, |
45 | }, | 45 | }, |
46 | })); | 46 | })); |
47 | 47 | ||
48 | const NotificationBannerText = styled(Typography)(({ theme }) => ({ | 48 | const NotificationBannerText = styled(Typography)(({ theme }) => ({ |
49 | fontSize: 'inherit', | 49 | fontSize: 'inherit', |
50 | paddingTop: theme.spacing(1), | 50 | paddingTop: theme.spacing(1), |
51 | paddingInlineEnd: theme.spacing(2), | 51 | paddingRight: theme.spacing(2), |
52 | flexGrow: 9999, | 52 | flexGrow: 9999, |
53 | })); | 53 | })); |
54 | 54 | ||
55 | const NotificationBannerButtons = styled(Box)(({ theme }) => ({ | 55 | const NotificationBannerButtons = styled(Box)(({ theme }) => ({ |
56 | fontSize: 'inherit', | 56 | fontSize: 'inherit', |
57 | paddingTop: theme.spacing(0.5), | 57 | paddingTop: theme.spacing(0.5), |
58 | paddingInlineEnd: theme.spacing(0.5), | 58 | paddingRight: theme.spacing(0.5), |
59 | display: 'flex', | 59 | display: 'flex', |
60 | flexWrap: 'wrap', | 60 | flexWrap: 'wrap', |
61 | flexGrow: 1, | 61 | flexGrow: 1, |
diff --git a/packages/renderer/src/components/locationBar/LocationInputAdornment.tsx b/packages/renderer/src/components/locationBar/LocationInputAdornment.tsx index 640cbb4..82f662d 100644 --- a/packages/renderer/src/components/locationBar/LocationInputAdornment.tsx +++ b/packages/renderer/src/components/locationBar/LocationInputAdornment.tsx | |||
@@ -23,11 +23,10 @@ import { styled } from '@mui/material/styles'; | |||
23 | 23 | ||
24 | const LocationInputAdornment = styled(InputAdornment, { | 24 | const LocationInputAdornment = styled(InputAdornment, { |
25 | name: 'LocationInputAdornment', | 25 | name: 'LocationInputAdornment', |
26 | })(({ theme: { direction }, position }) => { | 26 | })(({ position }) => { |
27 | const left = direction === 'ltr' ? 'start' : 'end'; | ||
28 | const marginStart = -10; | 27 | const marginStart = -10; |
29 | const marginEnd = 2; | 28 | const marginEnd = 2; |
30 | return position === left | 29 | return position === 'start' |
31 | ? { | 30 | ? { |
32 | marginLeft: marginStart, | 31 | marginLeft: marginStart, |
33 | marginRight: marginEnd, | 32 | marginRight: marginEnd, |
diff --git a/packages/renderer/src/components/locationBar/LocationOverlayInput.tsx b/packages/renderer/src/components/locationBar/LocationOverlayInput.tsx index a09cc57..cbb5b06 100644 --- a/packages/renderer/src/components/locationBar/LocationOverlayInput.tsx +++ b/packages/renderer/src/components/locationBar/LocationOverlayInput.tsx | |||
@@ -34,6 +34,8 @@ const LocationOverlayInputRoot = styled('div', { | |||
34 | })<{ overlayVisible: boolean }>(({ theme, overlayVisible }) => { | 34 | })<{ overlayVisible: boolean }>(({ theme, overlayVisible }) => { |
35 | const itemStyle = { | 35 | const itemStyle = { |
36 | padding: '6px 0 7px 0', | 36 | padding: '6px 0 7px 0', |
37 | // Set text alignment explicitly so it can be flipped by `stylis-plugin-rtl`. | ||
38 | textAlign: 'left', | ||
37 | }; | 39 | }; |
38 | return { | 40 | return { |
39 | display: 'flex', | 41 | display: 'flex', |
@@ -86,12 +88,15 @@ const LocationOverlayInput = forwardRef( | |||
86 | <input | 88 | <input |
87 | ref={ref} | 89 | ref={ref} |
88 | className={`${className ?? ''} ${inputClassName}`} | 90 | className={`${className ?? ''} ${inputClassName}`} |
91 | dir="ltr" | ||
89 | {...props} | 92 | {...props} |
90 | /> | 93 | /> |
91 | {/* eslint-enable react/jsx-props-no-spreading */} | 94 | {/* eslint-enable react/jsx-props-no-spreading */} |
92 | {overlayVisible && ( | 95 | {overlayVisible && ( |
93 | <div aria-hidden className={`${className ?? ''} ${overlayClassName}`}> | 96 | <div aria-hidden className={`${className ?? ''} ${overlayClassName}`}> |
94 | <div className={clipClassName}>{overlay}</div> | 97 | <div className={clipClassName} dir="ltr"> |
98 | {overlay} | ||
99 | </div> | ||
95 | </div> | 100 | </div> |
96 | )} | 101 | )} |
97 | </LocationOverlayInputRoot> | 102 | </LocationOverlayInputRoot> |
diff --git a/packages/renderer/src/components/locationBar/SecurityLabel.tsx b/packages/renderer/src/components/locationBar/SecurityLabel.tsx index d9dff86..0017f89 100644 --- a/packages/renderer/src/components/locationBar/SecurityLabel.tsx +++ b/packages/renderer/src/components/locationBar/SecurityLabel.tsx | |||
@@ -45,7 +45,7 @@ const SecurityLabelText = styled('span', { | |||
45 | name: 'SecurityLabel', | 45 | name: 'SecurityLabel', |
46 | slot: 'Text', | 46 | slot: 'Text', |
47 | })(({ theme }) => ({ | 47 | })(({ theme }) => ({ |
48 | marginInlineStart: theme.spacing(1), | 48 | marginLeft: theme.spacing(1), |
49 | // Keep the same baseline as the input box text. | 49 | // Keep the same baseline as the input box text. |
50 | paddingBottom: 1, | 50 | paddingBottom: 1, |
51 | fontWeight: theme.typography.fontWeightMedium, | 51 | fontWeight: theme.typography.fontWeightMedium, |
diff --git a/packages/renderer/src/components/sidebar/ServiceIcon.tsx b/packages/renderer/src/components/sidebar/ServiceIcon.tsx index 1017be9..7a6d58a 100644 --- a/packages/renderer/src/components/sidebar/ServiceIcon.tsx +++ b/packages/renderer/src/components/sidebar/ServiceIcon.tsx | |||
@@ -20,7 +20,7 @@ | |||
20 | 20 | ||
21 | import IconWarning from '@mui/icons-material/Warning'; | 21 | import IconWarning from '@mui/icons-material/Warning'; |
22 | import Badge from '@mui/material/Badge'; | 22 | import Badge from '@mui/material/Badge'; |
23 | import { styled, useTheme } from '@mui/material/styles'; | 23 | import { styled } from '@mui/material/styles'; |
24 | import { observer } from 'mobx-react-lite'; | 24 | import { observer } from 'mobx-react-lite'; |
25 | import React, { useEffect, useState } from 'react'; | 25 | import React, { useEffect, useState } from 'react'; |
26 | 26 | ||
@@ -89,7 +89,6 @@ const ServiceIconErrorBadge = styled(ServiceIconBadgeBase, { | |||
89 | })); | 89 | })); |
90 | 90 | ||
91 | function ServiceIcon({ service }: { service: Service }): JSX.Element { | 91 | function ServiceIcon({ service }: { service: Service }): JSX.Element { |
92 | const { direction } = useTheme(); | ||
93 | const { | 92 | const { |
94 | settings: { name }, | 93 | settings: { name }, |
95 | directMessageCount, | 94 | directMessageCount, |
@@ -114,7 +113,7 @@ function ServiceIcon({ service }: { service: Service }): JSX.Element { | |||
114 | badgeContent={hasError ? <IconWarning fontSize="small" /> : 0} | 113 | badgeContent={hasError ? <IconWarning fontSize="small" /> : 0} |
115 | anchorOrigin={{ | 114 | anchorOrigin={{ |
116 | vertical: 'bottom', | 115 | vertical: 'bottom', |
117 | horizontal: direction === 'ltr' ? 'right' : 'left', | 116 | horizontal: 'right', |
118 | }} | 117 | }} |
119 | > | 118 | > |
120 | <ServiceIconBadge | 119 | <ServiceIconBadge |
@@ -125,7 +124,7 @@ function ServiceIcon({ service }: { service: Service }): JSX.Element { | |||
125 | color="error" | 124 | color="error" |
126 | anchorOrigin={{ | 125 | anchorOrigin={{ |
127 | vertical: 'top', | 126 | vertical: 'top', |
128 | horizontal: direction === 'ltr' ? 'right' : 'left', | 127 | horizontal: 'right', |
129 | }} | 128 | }} |
130 | > | 129 | > |
131 | <ServiceIconRoot hasError={hasError}> | 130 | <ServiceIconRoot hasError={hasError}> |
diff --git a/packages/renderer/src/components/sidebar/ServiceSwitcher.tsx b/packages/renderer/src/components/sidebar/ServiceSwitcher.tsx index 60b8b98..0ebd359 100644 --- a/packages/renderer/src/components/sidebar/ServiceSwitcher.tsx +++ b/packages/renderer/src/components/sidebar/ServiceSwitcher.tsx | |||
@@ -34,20 +34,13 @@ import ServiceIcon from './ServiceIcon'; | |||
34 | const ServiceSwitcherRoot = styled(Tabs, { | 34 | const ServiceSwitcherRoot = styled(Tabs, { |
35 | name: 'ServiceSwitcher', | 35 | name: 'ServiceSwitcher', |
36 | slot: 'Root', | 36 | slot: 'Root', |
37 | })(({ theme }) => ({ | 37 | })({ |
38 | // Move the indicator to the outer side of the window. | 38 | // Move the indicator to the outer side of the window. |
39 | '.MuiTabs-indicator': { | 39 | '.MuiTabs-indicator': { |
40 | ...(theme.direction === 'ltr' | 40 | left: 0, |
41 | ? { | 41 | right: 'auto', |
42 | left: 0, | ||
43 | right: 'auto', | ||
44 | } | ||
45 | : { | ||
46 | left: 'auto', | ||
47 | right: 0, | ||
48 | }), | ||
49 | }, | 42 | }, |
50 | })); | 43 | }); |
51 | 44 | ||
52 | const ServiceSwitcherTab = styled(Tab, { | 45 | const ServiceSwitcherTab = styled(Tab, { |
53 | name: 'ServiceSwitcher', | 46 | name: 'ServiceSwitcher', |
diff --git a/packages/renderer/src/components/sidebar/Sidebar.tsx b/packages/renderer/src/components/sidebar/Sidebar.tsx index 6c2f219..fc57302 100644 --- a/packages/renderer/src/components/sidebar/Sidebar.tsx +++ b/packages/renderer/src/components/sidebar/Sidebar.tsx | |||
@@ -48,7 +48,7 @@ export default function Sidebar(): JSX.Element { | |||
48 | position: 'absolute', | 48 | position: 'absolute', |
49 | top: '-20px', | 49 | top: '-20px', |
50 | bottom: '-20px', | 50 | bottom: '-20px', |
51 | [theme.direction === 'ltr' ? 'right' : 'left']: '-20px', | 51 | right: '-20px', |
52 | zIndex: 100, | 52 | zIndex: 100, |
53 | width: '20px', | 53 | width: '20px', |
54 | boxShadow: theme.shadows[4], | 54 | boxShadow: theme.shadows[4], |
diff --git a/packages/renderer/src/i18n/RtlCacheProvider.tsx b/packages/renderer/src/i18n/RtlCacheProvider.tsx new file mode 100644 index 0000000..d54308b --- /dev/null +++ b/packages/renderer/src/i18n/RtlCacheProvider.tsx | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2022 Kristóf Marussy <kristof@marussy.com> | ||
3 | * | ||
4 | * This file is part of Sophie. | ||
5 | * | ||
6 | * Sophie is free software: you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU Affero General Public License as | ||
8 | * published by the Free Software Foundation, version 3. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Affero General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Affero General Public License | ||
16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | * SPDX-License-Identifier: AGPL-3.0-only | ||
19 | */ | ||
20 | |||
21 | import createCache from '@emotion/cache'; | ||
22 | import { CacheProvider } from '@emotion/react'; | ||
23 | import { observer } from 'mobx-react-lite'; | ||
24 | import React, { ReactNode } from 'react'; | ||
25 | import { prefixer } from 'stylis'; | ||
26 | import rtlPlugin from 'stylis-plugin-rtl'; | ||
27 | |||
28 | import { useStore } from '../components/StoreProvider'; | ||
29 | |||
30 | const rtlCache = createCache({ | ||
31 | key: 'muirtl', | ||
32 | stylisPlugins: [prefixer, rtlPlugin], | ||
33 | }); | ||
34 | |||
35 | function RtlCacheProvider({ children }: { children?: ReactNode }): JSX.Element { | ||
36 | const { | ||
37 | shared: { writingDirection }, | ||
38 | } = useStore(); | ||
39 | |||
40 | return writingDirection === 'rtl' ? ( | ||
41 | <CacheProvider value={rtlCache}>{children}</CacheProvider> | ||
42 | ) : ( | ||
43 | /* | ||
44 | eslint-disable-next-line react/jsx-no-useless-fragment -- | ||
45 | Wrap expression in a fragment to satisfy typescript. | ||
46 | */ | ||
47 | <>{children}</> | ||
48 | ); | ||
49 | } | ||
50 | |||
51 | RtlCacheProvider.defaultProps = { | ||
52 | children: undefined, | ||
53 | }; | ||
54 | |||
55 | export default observer(RtlCacheProvider); | ||
diff --git a/packages/renderer/src/index.tsx b/packages/renderer/src/index.tsx index ff1ffc4..2722d3b 100644 --- a/packages/renderer/src/index.tsx +++ b/packages/renderer/src/index.tsx | |||
@@ -32,6 +32,7 @@ import Loading from './components/Loading'; | |||
32 | import StoreProvider from './components/StoreProvider'; | 32 | import StoreProvider from './components/StoreProvider'; |
33 | import ThemeProvider from './components/ThemeProvider'; | 33 | import ThemeProvider from './components/ThemeProvider'; |
34 | import { exposeToReduxDevtools, hotReload } from './devTools'; | 34 | import { exposeToReduxDevtools, hotReload } from './devTools'; |
35 | import RtlCacheProvider from './i18n/RtlCacheProvider'; | ||
35 | import loadRendererLocalization from './i18n/loadRendererLoalization'; | 36 | import loadRendererLocalization from './i18n/loadRendererLoalization'; |
36 | import { createAndConnectRendererStore } from './stores/RendererStore'; | 37 | import { createAndConnectRendererStore } from './stores/RendererStore'; |
37 | import { getLogger } from './utils/log'; | 38 | import { getLogger } from './utils/log'; |
@@ -71,12 +72,14 @@ function Root(): JSX.Element { | |||
71 | return ( | 72 | return ( |
72 | <React.StrictMode> | 73 | <React.StrictMode> |
73 | <StoreProvider store={store}> | 74 | <StoreProvider store={store}> |
74 | <ThemeProvider> | 75 | <RtlCacheProvider> |
75 | <CssBaseline enableColorScheme /> | 76 | <ThemeProvider> |
76 | <Suspense fallback={<Loading />}> | 77 | <CssBaseline enableColorScheme /> |
77 | <App devMode={isDevelopment} /> | 78 | <Suspense fallback={<Loading />}> |
78 | </Suspense> | 79 | <App devMode={isDevelopment} /> |
79 | </ThemeProvider> | 80 | </Suspense> |
81 | </ThemeProvider> | ||
82 | </RtlCacheProvider> | ||
80 | </StoreProvider> | 83 | </StoreProvider> |
81 | </React.StrictMode> | 84 | </React.StrictMode> |
82 | ); | 85 | ); |