From d7971d27dfd8cb8ea238d6bc6075e37852a9b6a4 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Wed, 24 May 2023 20:56:04 +1000 Subject: [PATCH] Add translate dialog for users with other languages --- frontend/src/App.jsx | 62 ----------------- frontend/src/app/layout.tsx | 2 + frontend/src/components/Egg/Egg.module.scss | 6 +- ....styles.ts => TranslateDialog.module.scss} | 14 ++-- .../TranslateDialog/TranslateDialog.tsx | 68 ++++++++++++------- frontend/src/stores/localeUpdateStore.ts | 13 ---- frontend/src/stores/translateStore.ts | 28 -------- frontend/src/stores/twaStore.ts | 14 ---- 8 files changed, 57 insertions(+), 150 deletions(-) delete mode 100644 frontend/src/App.jsx rename frontend/src/components/TranslateDialog/{TranslateDialog.styles.ts => TranslateDialog.module.scss} (83%) delete mode 100644 frontend/src/stores/localeUpdateStore.ts delete mode 100644 frontend/src/stores/translateStore.ts delete mode 100644 frontend/src/stores/twaStore.ts diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx deleted file mode 100644 index 7491131..0000000 --- a/frontend/src/App.jsx +++ /dev/null @@ -1,62 +0,0 @@ -import { useState, useEffect, useCallback, Suspense } from 'react' -import { Route, Routes } from 'react-router-dom' - -import * as Pages from '/src/pages' -import { Settings, Loading, Egg, TranslateDialog } from '/src/components' - -import { useSettingsStore, useTranslateStore } from '/src/stores' - -const EGG_PATTERN = ['ArrowUp', 'ArrowUp', 'ArrowDown', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowLeft', 'ArrowRight', 'b', 'a'] - -const App = () => { - const [eggCount, setEggCount] = useState(0) - const [eggVisible, setEggVisible] = useState(false) - const [eggKey, setEggKey] = useState(0) - - const languageSupported = useTranslateStore(state => state.navigatorSupported) - const translateDialogDismissed = useTranslateStore(state => state.translateDialogDismissed) - - const eggHandler = useCallback(e => { - if (EGG_PATTERN.indexOf(e.key) < 0 || e.key !== EGG_PATTERN[eggCount]) return setEggCount(0) - setEggCount(eggCount+1) - if (EGG_PATTERN.length === eggCount+1) { - setEggKey(eggKey+1) - setEggCount(0) - setEggVisible(true) - } - }, [eggCount, eggKey]) - - useEffect(() => { - document.addEventListener('keyup', eggHandler, false) - return () => document.removeEventListener('keyup', eggHandler, false) - }, [eggHandler]) - - // Use user theme preference - const theme = useSettingsStore(state => state.theme) - useEffect(() => { - document.body.classList.toggle('light', theme === 'Light') - document.body.classList.toggle('dark', theme === 'Dark') - }, [theme]) - - return ( - <> - {!languageSupported && !translateDialogDismissed && } - - }> - - - - } /> - } /> - } /> - } /> - } /> - - - - {eggVisible && setEggVisible(false)} />} - - ) -} - -export default App diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index 71ed4c0..8b8d9a7 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -2,6 +2,7 @@ import { Metadata } from 'next' import Egg from '/src/components/Egg/Egg' import Settings from '/src/components/Settings/Settings' +import TranslateDialog from '/src/components/TranslateDialog/TranslateDialog' import { fallbackLng } from '/src/i18n/options' import { useTranslation } from '/src/i18n/server' @@ -33,6 +34,7 @@ const RootLayout = async ({ children }: { children: React.ReactNode }) => { {children} + } diff --git a/frontend/src/components/Egg/Egg.module.scss b/frontend/src/components/Egg/Egg.module.scss index ee1313c..73128cf 100644 --- a/frontend/src/components/Egg/Egg.module.scss +++ b/frontend/src/components/Egg/Egg.module.scss @@ -5,11 +5,15 @@ outline: none; width: 100%; height: 100%; - display: flex; + display: none; align-items: center; justify-content: center; overflow: visible; + &[open] { + display: flex; + } + &::backdrop { background: rgba(0,0,0,.6); } diff --git a/frontend/src/components/TranslateDialog/TranslateDialog.styles.ts b/frontend/src/components/TranslateDialog/TranslateDialog.module.scss similarity index 83% rename from frontend/src/components/TranslateDialog/TranslateDialog.styles.ts rename to frontend/src/components/TranslateDialog/TranslateDialog.module.scss index d4f782b..29ef7f0 100644 --- a/frontend/src/components/TranslateDialog/TranslateDialog.styles.ts +++ b/frontend/src/components/TranslateDialog/TranslateDialog.module.scss @@ -1,9 +1,7 @@ -import { styled } from 'goober' - -export const Wrapper = styled('div')` +.popup { position: fixed; - top: 20px; - left: 20px; + bottom: 20px; + right: 20px; background-color: var(--background); border: 1px solid var(--surface); z-index: 900; @@ -28,9 +26,9 @@ export const Wrapper = styled('div')` @media (max-width: 400px) { display: block; } -` +} -export const ButtonWrapper = styled('div')` +.buttons { display: flex; flex-direction: column; align-items: stretch; @@ -44,4 +42,4 @@ export const ButtonWrapper = styled('div')` margin: 20px 0 0; white-space: normal; } -` +} diff --git a/frontend/src/components/TranslateDialog/TranslateDialog.tsx b/frontend/src/components/TranslateDialog/TranslateDialog.tsx index 780d529..831073b 100644 --- a/frontend/src/components/TranslateDialog/TranslateDialog.tsx +++ b/frontend/src/components/TranslateDialog/TranslateDialog.tsx @@ -1,32 +1,52 @@ -import { Button } from '/src/components' +'use client' -import { useTranslateStore } from '/src/stores' +import { useEffect, useState } from 'react' +import { create } from 'zustand' +import { persist } from 'zustand/middleware' -import { - Wrapper, - ButtonWrapper, -} from './TranslateDialog.styles' +import Button from '/src/components/Button/Button' +import { languages } from '/src/i18n/options' +import { useStore } from '/src/stores' + +import styles from './TranslateDialog.module.scss' + +interface TranslateStore { + translateDialogDismissed: boolean + dismissDialog: () => void +} + +const useTranslateStore = create()(persist( + set => ({ + translateDialogDismissed: false, + dismissDialog: () => set({ translateDialogDismissed: true }), + }), + { name: 'crabfit-translate' }, +)) const TranslateDialog = () => { - const navigatorLang = useTranslateStore(state => state.navigatorLang) - const setDialogDismissed = useTranslateStore(state => state.setDialogDismissed) + const [isSupported, setIsSupported] = useState(true) + const store = useStore(useTranslateStore, state => state) - return ( - -
-

Translate Crab Fit

-

Crab Fit hasn't been translated to your language yet.

-
- - - - -
- ) + // Check if current language has translations + useEffect(() => { + setIsSupported((languages as readonly string[]).includes(navigator.language.substring(0, 2))) + }, []) + + return (store?.translateDialogDismissed === false && !isSupported) ?
+
+

Translate Crab Fit

+

Crab Fit hasn't been translated to your language yet.

+
+ +
+ + +
+
: null } export default TranslateDialog diff --git a/frontend/src/stores/localeUpdateStore.ts b/frontend/src/stores/localeUpdateStore.ts deleted file mode 100644 index 8a6bd26..0000000 --- a/frontend/src/stores/localeUpdateStore.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { create } from 'zustand' - -interface LocaleUpdateStore { - locale: string - setLocale: (locale: string) => void -} - -const useLocaleUpdateStore = create()(set => ({ - locale: 'en', - setLocale: locale => set({ locale }), -})) - -export default useLocaleUpdateStore diff --git a/frontend/src/stores/translateStore.ts b/frontend/src/stores/translateStore.ts deleted file mode 100644 index 8a73632..0000000 --- a/frontend/src/stores/translateStore.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { create } from 'zustand' -import { persist } from 'zustand/middleware' - -import locales from '/src/i18n/locales' - -interface TranslateStore { - navigatorLang: string - navigatorSupported: boolean - translateDialogDismissed: boolean - - setDialogDismissed: (isDismissed: boolean) => void -} - -const useTranslateStore = create()(persist( - set => ({ - navigatorLang: navigator.language, - navigatorSupported: Object.keys(locales).includes(navigator.language.substring(0, 2)), - translateDialogDismissed: false, - - setDialogDismissed: isDismissed => set({ translateDialogDismissed: isDismissed }), - }), - { - name: 'crabfit-translate', - partialize: state => ({ translateDialogDismissed: state.translateDialogDismissed }), - }, -)) - -export default useTranslateStore diff --git a/frontend/src/stores/twaStore.ts b/frontend/src/stores/twaStore.ts deleted file mode 100644 index a31495e..0000000 --- a/frontend/src/stores/twaStore.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { create } from 'zustand' - -interface TWAStore { - /** Is the site running in a trusted web activity? */ - isTWA: boolean | undefined - setIsTWA: (isTWA: boolean | undefined) => void -} - -const useTWAStore = create()(set => ({ - isTWA: undefined, - setIsTWA: isTWA => set({ isTWA }), -})) - -export default useTWAStore