diff --git a/crabfit-frontend/src/App.tsx b/crabfit-frontend/src/App.tsx
index 0154143..1b20075 100644
--- a/crabfit-frontend/src/App.tsx
+++ b/crabfit-frontend/src/App.tsx
@@ -3,9 +3,9 @@ import { BrowserRouter, Switch, Route } from 'react-router-dom';
import { ThemeProvider, Global } from '@emotion/react';
import { Workbox } from 'workbox-window';
-import { Settings, Loading, Egg, UpdateDialog } from 'components';
+import { Settings, Loading, Egg, UpdateDialog, TranslateDialog } from 'components';
-import { useSettingsStore } from 'stores';
+import { useSettingsStore, useTranslateStore } from 'stores';
import theme from 'theme';
const EGG_PATTERN = ['ArrowUp', 'ArrowUp', 'ArrowDown', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowLeft', 'ArrowRight', 'b', 'a'];
@@ -29,6 +29,8 @@ const App = () => {
const [eggKey, setEggKey] = useState(0);
const [updateAvailable, setUpdateAvailable] = useState(false);
+ const languageSupported = useTranslateStore(state => state.navigatorSupported);
+ const translateDialogDismissed = useTranslateStore(state => state.translateDialogDismissed);
const eggHandler = useCallback(
event => {
@@ -93,7 +95,7 @@ const App = () => {
styles={theme => ({
html: {
scrollBehavior: 'smooth',
- '-webkit-print-color-adjust': 'exact',
+ WebkitPrintColorAdjust: 'exact',
},
body: {
backgroundColor: theme.background,
@@ -127,6 +129,8 @@ const App = () => {
})}
/>
+ {!languageSupported && !translateDialogDismissed && }
+
}>
diff --git a/crabfit-frontend/src/components/TranslateDialog/TranslateDialog.tsx b/crabfit-frontend/src/components/TranslateDialog/TranslateDialog.tsx
new file mode 100644
index 0000000..391c1af
--- /dev/null
+++ b/crabfit-frontend/src/components/TranslateDialog/TranslateDialog.tsx
@@ -0,0 +1,32 @@
+import { Button } from 'components';
+
+import { useTranslateStore } from 'stores';
+
+import {
+ Wrapper,
+ ButtonWrapper,
+} from './translateDialogStyle';
+
+const TranslateDialog = ({ onClose }) => {
+ const navigatorLang = useTranslateStore(state => state.navigatorLang);
+ const setDialogDismissed = useTranslateStore(state => state.setDialogDismissed);
+
+ return (
+
+
+
Translate Crab Fit
+
Crab Fit hasn't been translated to your language yet.
+
+
+
+
+
+
+ );
+}
+
+export default TranslateDialog;
diff --git a/crabfit-frontend/src/components/TranslateDialog/translateDialogStyle.ts b/crabfit-frontend/src/components/TranslateDialog/translateDialogStyle.ts
new file mode 100644
index 0000000..4a31995
--- /dev/null
+++ b/crabfit-frontend/src/components/TranslateDialog/translateDialogStyle.ts
@@ -0,0 +1,49 @@
+import styled from '@emotion/styled';
+
+export const Wrapper = styled.div`
+ position: fixed;
+ top: 20px;
+ left: 20px;
+ background-color: ${props => props.theme.background};
+ ${props => props.theme.mode === 'dark' && `
+ border: 1px solid ${props.theme.primaryBackground};
+ `}
+ z-index: 900;
+ padding: 20px;
+ border-radius: 3px;
+ box-sizing: border-box;
+ width: 500px;
+ max-width: calc(100% - 40px);
+ box-shadow: 0 3px 6px 0 rgba(0,0,0,.3);
+ display: flex;
+ align-items: center;
+
+ & h2 {
+ margin: 0;
+ font-size: 1.3rem;
+ }
+ & p {
+ margin: 12px 0 0;
+ font-size: 1rem;
+ }
+
+ @media (max-width: 400px) {
+ display: block;
+ }
+`;
+
+export const ButtonWrapper = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ justify-content: flex-end;
+ gap: 12px;
+ flex-wrap: wrap;
+ margin-left: 20px;
+ white-space: nowrap;
+
+ @media (max-width: 400px) {
+ margin: 20px 0 0;
+ white-space: normal;
+ }
+`;
diff --git a/crabfit-frontend/src/components/index.ts b/crabfit-frontend/src/components/index.ts
index 1b73344..9147137 100644
--- a/crabfit-frontend/src/components/index.ts
+++ b/crabfit-frontend/src/components/index.ts
@@ -19,6 +19,7 @@ export { default as Footer } from './Footer/Footer';
export { default as Recents } from './Recents/Recents';
export { default as Logo } from './Logo/Logo';
export { default as UpdateDialog } from './UpdateDialog/UpdateDialog';
+export { default as TranslateDialog } from './TranslateDialog/TranslateDialog';
export const _GoogleCalendar = () => import('./GoogleCalendar/GoogleCalendar');
export const _OutlookCalendar = () => import('./OutlookCalendar/OutlookCalendar');
diff --git a/crabfit-frontend/src/pages/Home/Home.tsx b/crabfit-frontend/src/pages/Home/Home.tsx
index 2531303..5cdcd21 100644
--- a/crabfit-frontend/src/pages/Home/Home.tsx
+++ b/crabfit-frontend/src/pages/Home/Home.tsx
@@ -224,11 +224,11 @@ const Home = ({ offline }) => {
{t('home:about.name')}
- {stats.eventCount ?? '600+'}
+ {stats.eventCount ?? '700+'}
{t('home:about.events')}
- {stats.personCount ?? '1500+'}
+ {stats.personCount ?? '1600+'}
{t('home:about.availabilities')}
diff --git a/crabfit-frontend/src/stores/index.ts b/crabfit-frontend/src/stores/index.ts
index e9ce967..162b349 100644
--- a/crabfit-frontend/src/stores/index.ts
+++ b/crabfit-frontend/src/stores/index.ts
@@ -1,5 +1,6 @@
import create from 'zustand';
import { persist } from 'zustand/middleware';
+import locales from 'res/dayjs_locales';
export const useSettingsStore = create(persist(
set => ({
@@ -44,3 +45,20 @@ export const useLocaleUpdateStore = create(set => ({
locale: 'en',
setLocale: locale => set({ locale }),
}));
+
+export const useTranslateStore = create(persist(
+ set => ({
+ navigatorLang: navigator.language,
+ navigatorSupported: Object.keys(locales).includes(navigator.language.substring(0, 2)),
+ translateDialogDismissed: false,
+
+ setDialogDismissed: value => set({ translateDialogDismissed: value }),
+ }),
+ {
+ name: 'crabfit-translate',
+ blacklist: [
+ 'navigatorLang',
+ 'navigatorSupported',
+ ],
+ },
+));