aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Tananaev <anton@traccar.org>2024-04-07 09:56:18 -0700
committerAnton Tananaev <anton@traccar.org>2024-04-07 09:56:18 -0700
commit79c6ac5e2cf5a7778da5b4ac1229897234531f25 (patch)
treeb30641cc70a87e5c75fb120b2090f3f83b5f7d36
parent393651524bd66ed72d82b93f556ed4cc747a73c3 (diff)
downloadtrackermap-web-79c6ac5e2cf5a7778da5b4ac1229897234531f25.tar.gz
trackermap-web-79c6ac5e2cf5a7778da5b4ac1229897234531f25.tar.bz2
trackermap-web-79c6ac5e2cf5a7778da5b4ac1229897234531f25.zip
Theme and styles RTL support
-rw-r--r--package-lock.json43
-rw-r--r--package.json2
-rw-r--r--src/AppThemeProvider.jsx27
-rw-r--r--src/common/components/LocalizationProvider.jsx7
-rw-r--r--src/common/theme/index.js5
5 files changed, 69 insertions, 15 deletions
diff --git a/package-lock.json b/package-lock.json
index 96e8daae..5c8126d8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -37,6 +37,8 @@
"react-window": "^1.8.10",
"recharts": "^2.12.4",
"redux": "^5.0.1",
+ "stylis": "^4.3.1",
+ "stylis-plugin-rtl": "^2.1.1",
"vite": "^5.2.8",
"vite-plugin-pwa": "^0.19.8",
"vite-plugin-svgr": "^4.2.0",
@@ -1687,6 +1689,11 @@
"stylis": "4.2.0"
}
},
+ "node_modules/@emotion/babel-plugin/node_modules/stylis": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
+ "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="
+ },
"node_modules/@emotion/cache": {
"version": "11.11.0",
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz",
@@ -1699,6 +1706,11 @@
"stylis": "4.2.0"
}
},
+ "node_modules/@emotion/cache/node_modules/stylis": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
+ "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="
+ },
"node_modules/@emotion/hash": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz",
@@ -5198,9 +5210,9 @@
"integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg=="
},
"node_modules/@types/parse-json": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
- "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA=="
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
+ "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw=="
},
"node_modules/@types/pbf": {
"version": "3.0.5",
@@ -6129,6 +6141,14 @@
"resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz",
"integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w=="
},
+ "node_modules/cssjanus": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cssjanus/-/cssjanus-2.1.0.tgz",
+ "integrity": "sha512-kAijbny3GmdOi9k+QT6DGIXqFvL96aksNlGr4Rhk9qXDZYWUojU4bRc3IHWxdaLNOqgEZHuXoe5Wl2l7dxLW5g==",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@@ -10820,9 +10840,20 @@
}
},
"node_modules/stylis": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
- "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz",
+ "integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ=="
+ },
+ "node_modules/stylis-plugin-rtl": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/stylis-plugin-rtl/-/stylis-plugin-rtl-2.1.1.tgz",
+ "integrity": "sha512-q6xIkri6fBufIO/sV55md2CbgS5c6gg9EhSVATtHHCdOnbN/jcI0u3lYhNVeuI65c4lQPo67g8xmq5jrREvzlg==",
+ "dependencies": {
+ "cssjanus": "^2.0.1"
+ },
+ "peerDependencies": {
+ "stylis": "4.x"
+ }
},
"node_modules/subtag": {
"version": "0.5.0",
diff --git a/package.json b/package.json
index 82d35be0..7d898781 100644
--- a/package.json
+++ b/package.json
@@ -33,6 +33,8 @@
"react-window": "^1.8.10",
"recharts": "^2.12.4",
"redux": "^5.0.1",
+ "stylis": "^4.3.1",
+ "stylis-plugin-rtl": "^2.1.1",
"vite": "^5.2.8",
"vite-plugin-pwa": "^0.19.8",
"vite-plugin-svgr": "^4.2.0",
diff --git a/src/AppThemeProvider.jsx b/src/AppThemeProvider.jsx
index 109d25c4..8f64b931 100644
--- a/src/AppThemeProvider.jsx
+++ b/src/AppThemeProvider.jsx
@@ -1,21 +1,40 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { ThemeProvider, useMediaQuery } from '@mui/material';
+import { CacheProvider } from '@emotion/react';
+import createCache from '@emotion/cache';
+import { prefixer } from 'stylis';
+import rtlPlugin from 'stylis-plugin-rtl';
import theme from './common/theme';
+import { useLocalization } from './common/components/LocalizationProvider';
+
+const cache = {
+ ltr: createCache({
+ key: 'muiltr',
+ stylisPlugins: [prefixer],
+ }),
+ rtl: createCache({
+ key: 'muirtl',
+ stylisPlugins: [prefixer, rtlPlugin],
+ }),
+};
const AppThemeProvider = ({ children }) => {
const server = useSelector((state) => state.session.server);
+ const { direction } = useLocalization();
const serverDarkMode = server?.attributes?.darkMode;
const preferDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
const darkMode = serverDarkMode !== undefined ? serverDarkMode : preferDarkMode;
- const themeInstance = theme(server, darkMode);
+ const themeInstance = theme(server, darkMode, direction);
return (
- <ThemeProvider theme={themeInstance}>
- {children}
- </ThemeProvider>
+ <CacheProvider value={cache[direction]}>
+ <ThemeProvider theme={themeInstance}>
+ {children}
+ </ThemeProvider>
+ </CacheProvider>
);
};
diff --git a/src/common/components/LocalizationProvider.jsx b/src/common/components/LocalizationProvider.jsx
index f69feabf..3af97cf0 100644
--- a/src/common/components/LocalizationProvider.jsx
+++ b/src/common/components/LocalizationProvider.jsx
@@ -152,8 +152,9 @@ const LocalizationContext = createContext({
export const LocalizationProvider = ({ children }) => {
const [language, setLanguage] = usePersistedState('language', getDefaultLanguage());
+ const direction = /^(ar|he|fa)$/.test(language) ? 'rtl' : 'ltr';
- const value = useMemo(() => ({ languages, language, setLanguage }), [languages, language, setLanguage]);
+ const value = useMemo(() => ({ languages, language, setLanguage, direction }), [languages, language, setLanguage, direction]);
useEffect(() => {
let selected;
@@ -163,8 +164,8 @@ export const LocalizationProvider = ({ children }) => {
selected = language;
}
dayjs.locale(selected);
- document.dir = /^(ar|he|fa)$/.test(language) ? 'rtl' : 'ltr';
- }, [language]);
+ document.dir = direction;
+ }, [language, direction]);
return (
<LocalizationContext.Provider value={value}>
diff --git a/src/common/theme/index.js b/src/common/theme/index.js
index e8ce698b..00958497 100644
--- a/src/common/theme/index.js
+++ b/src/common/theme/index.js
@@ -4,8 +4,9 @@ import palette from './palette';
import dimensions from './dimensions';
import components from './components';
-export default (server, darkMode) => useMemo(() => createTheme({
+export default (server, darkMode, direction) => useMemo(() => createTheme({
palette: palette(server, darkMode),
+ direction,
dimensions,
components,
-}), [server, darkMode]);
+}), [server, darkMode, direction]);