From 1d5af6f3bcfe5652ec6ed3c0d040a45e1a88bcec Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 9 Jan 2025 18:59:27 +0530 Subject: [PATCH 1/7] T --- web/apps/auth/src/pages/share.tsx | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/web/apps/auth/src/pages/share.tsx b/web/apps/auth/src/pages/share.tsx index 00e16a1d93..ce01bb0c9d 100644 --- a/web/apps/auth/src/pages/share.tsx +++ b/web/apps/auth/src/pages/share.tsx @@ -8,13 +8,7 @@ interface SharedCode { codes: string; } -interface CodeDisplay { - currentCode: string; - nextCode: string; - progress: number; -} - -const Share: React.FC = () => { +const Page: React.FC = () => { const [sharedCode, setSharedCode] = useState(null); const [error, setError] = useState(null); const [timeStatus, setTimeStatus] = useState(-10); @@ -51,10 +45,10 @@ const Share: React.FC = () => { try { const decryptedCode = (await decryptMetadataJSON_New( { - encryptedData: base64UrlToByteArray(data), - decryptionHeader: base64UrlToByteArray(header), + encryptedData: base64UrlToBytes(data), + decryptionHeader: base64UrlToBytes(header), }, - base64UrlToByteArray(key), + base64UrlToBytes(key), )) as SharedCode; setSharedCode(decryptedCode); } catch (error) { @@ -83,7 +77,7 @@ const Share: React.FC = () => { if (status === 0) { setCodeDisplay( - getCodeDisplay( + parseCodeDisplay( codes, sharedCode.startTime, sharedCode.step, @@ -215,17 +209,20 @@ const Share: React.FC = () => { ); }; -export default Share; +export default Page; -const base64UrlToByteArray = (base64Url: string): Uint8Array => { +const base64UrlToBytes = (base64Url: string): Uint8Array => { const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/"); return Uint8Array.from(atob(base64), (c) => c.charCodeAt(0)); }; -const formatCode = (code: string): string => - code.replace(/(.{3})/g, "$1 ").trim(); +interface CodeDisplay { + currentCode: string; + nextCode: string; + progress: number; +} -const getCodeDisplay = ( +const parseCodeDisplay = ( codes: string[], startTime: number, stepDuration: number, @@ -241,3 +238,5 @@ const getCodeDisplay = ( progress, }; }; + +const formatCode = (code: string) => code.replace(/(.{3})/g, "$1 ").trim(); From f46a0befdf014c7720bed48e6ced553cf3e75ac9 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 9 Jan 2025 19:06:19 +0530 Subject: [PATCH 2/7] T --- web/apps/auth/src/pages/share.tsx | 34 ++++++++++++++++--------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/web/apps/auth/src/pages/share.tsx b/web/apps/auth/src/pages/share.tsx index ce01bb0c9d..50d34e196c 100644 --- a/web/apps/auth/src/pages/share.tsx +++ b/web/apps/auth/src/pages/share.tsx @@ -1,5 +1,6 @@ import { EnteLogo } from "@/base/components/EnteLogo"; import { decryptMetadataJSON_New } from "@/base/crypto"; +import { Box, Stack, Typography } from "@mui/material"; import React, { useEffect, useMemo, useState } from "react"; interface SharedCode { @@ -95,34 +96,29 @@ const Page: React.FC = () => { [codeDisplay.progress], ); - const Message: React.FC<{ text: string }> = ({ text }) => ( -

{text}

- ); - return ( -
-
+ {error &&

{error}

} {timeStatus === -10 && !error && ( - + {"Decrypting..."} )} {timeStatus === -1 && ( - + + Your or the person who shared the code has out of sync + time. + )} - {timeStatus === 1 && } + {timeStatus === 1 && The code has expired.} {timeStatus === 0 && (
{
)} -
+ { Try Ente Auth - + ); }; @@ -240,3 +236,9 @@ const parseCodeDisplay = ( }; const formatCode = (code: string) => code.replace(/(.{3})/g, "$1 ").trim(); + +const Message: React.FC = ({ children }) => ( + + {children} + +); From efb15e3866c83a7920f4624f1cc2b96db5294b6e Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 9 Jan 2025 19:16:16 +0530 Subject: [PATCH 3/7] T --- web/apps/auth/src/pages/auth.tsx | 6 ++--- web/apps/auth/src/pages/share.tsx | 42 ++++++++++++++----------------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/web/apps/auth/src/pages/auth.tsx b/web/apps/auth/src/pages/auth.tsx index c11da2a6f9..1049f3cc92 100644 --- a/web/apps/auth/src/pages/auth.tsx +++ b/web/apps/auth/src/pages/auth.tsx @@ -345,12 +345,12 @@ const UnparseableCode: React.FC = ({ {code.issuer} ({ - color: theme.palette.critical.main, + sx={{ + color: "critical.main", flex: 1, minHeight: "16px", mb: 2, - })} + }} > {errorMessage} diff --git a/web/apps/auth/src/pages/share.tsx b/web/apps/auth/src/pages/share.tsx index 50d34e196c..c87c475e68 100644 --- a/web/apps/auth/src/pages/share.tsx +++ b/web/apps/auth/src/pages/share.tsx @@ -1,6 +1,6 @@ import { EnteLogo } from "@/base/components/EnteLogo"; import { decryptMetadataJSON_New } from "@/base/crypto"; -import { Box, Stack, Typography } from "@mui/material"; +import { Box, Button, Stack, Typography } from "@mui/material"; import React, { useEffect, useMemo, useState } from "react"; interface SharedCode { @@ -107,8 +107,14 @@ const Page: React.FC = () => { > - - {error &&

{error}

} + + {error && ( + + {error} + + )} {timeStatus === -10 && !error && ( {"Decrypting..."} )} @@ -178,29 +184,19 @@ const Page: React.FC = () => { )} - - - + Try Ente Auth + ); }; From 623bb66fa7e353a2bc24df78247438b0c2803b1d Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 9 Jan 2025 19:29:43 +0530 Subject: [PATCH 4/7] T --- web/apps/auth/src/pages/share.tsx | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/web/apps/auth/src/pages/share.tsx b/web/apps/auth/src/pages/share.tsx index c87c475e68..3de9acef8a 100644 --- a/web/apps/auth/src/pages/share.tsx +++ b/web/apps/auth/src/pages/share.tsx @@ -126,8 +126,8 @@ const Page: React.FC = () => { )} {timeStatus === 1 && The code has expired.} {timeStatus === 0 && ( -
{ position: "absolute", right: "20px", bottom: "20px", - fontSize: "12px", - opacity: 0.6, }} > -

+ {codeDisplay.nextCode === "" ? "Last code" : "next"} -

+ {codeDisplay.nextCode !== "" && ( -

+ {codeDisplay.nextCode} -

+ )}
- +
)} From fe9cccd3ab674f853705414af3b2896066397faa Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 9 Jan 2025 19:46:03 +0530 Subject: [PATCH 5/7] LO --- web/apps/accounts/src/pages/_app.tsx | 17 ++------------ web/apps/auth/src/pages/_app.tsx | 21 +++-------------- ...gOverlay.tsx => GalleryLoadingOverlay.tsx} | 2 +- web/apps/photos/src/pages/_app.tsx | 23 ++++--------------- web/apps/photos/src/pages/gallery.tsx | 6 ++--- web/apps/photos/src/pages/shared-albums.tsx | 6 ++--- .../base/components/LoadingOverlay.tsx | 23 +++++++++++++++++++ 7 files changed, 39 insertions(+), 59 deletions(-) rename web/apps/photos/src/components/{LoadingOverlay.tsx => GalleryLoadingOverlay.tsx} (85%) create mode 100644 web/packages/base/components/LoadingOverlay.tsx diff --git a/web/apps/accounts/src/pages/_app.tsx b/web/apps/accounts/src/pages/_app.tsx index 400d3616c3..65ead78130 100644 --- a/web/apps/accounts/src/pages/_app.tsx +++ b/web/apps/accounts/src/pages/_app.tsx @@ -1,8 +1,7 @@ import { staticAppTitle } from "@/base/app"; import { CustomHead } from "@/base/components/Head"; +import { LoadingOverlay } from "@/base/components/LoadingOverlay"; import { AttributedMiniDialog } from "@/base/components/MiniDialog"; -import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator"; -import { Overlay } from "@/base/components/mui/Container"; import { AppNavbar } from "@/base/components/Navbar"; import { useAttributedMiniDialog } from "@/base/components/utils/dialog"; import { getTheme, THEME_COLOR } from "@/base/components/utils/theme"; @@ -50,19 +49,7 @@ const App: React.FC = ({ Component, pageProps }) => { - {!isI18nReady && ( - ({ - display: "flex", - justifyContent: "center", - alignItems: "center", - zIndex: 2000, - backgroundColor: theme.colors.background.base, - })} - > - - - )} + {!isI18nReady && } {showNavbar && } {isI18nReady && } diff --git a/web/apps/auth/src/pages/_app.tsx b/web/apps/auth/src/pages/_app.tsx index f719ad301d..70cc79bfcf 100644 --- a/web/apps/auth/src/pages/_app.tsx +++ b/web/apps/auth/src/pages/_app.tsx @@ -1,9 +1,8 @@ import { accountLogout } from "@/accounts/services/logout"; import { clientPackageName, staticAppTitle } from "@/base/app"; import { CustomHead } from "@/base/components/Head"; +import { LoadingOverlay } from "@/base/components/LoadingOverlay"; import { AttributedMiniDialog } from "@/base/components/MiniDialog"; -import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator"; -import { Overlay } from "@/base/components/mui/Container"; import { AppNavbar } from "@/base/components/Navbar"; import { useAttributedMiniDialog } from "@/base/components/utils/dialog"; import { THEME_COLOR, getTheme } from "@/base/components/utils/theme"; @@ -94,22 +93,8 @@ const App: React.FC = ({ Component, pageProps }) => { - {(loading || !isI18nReady) && ( - ({ - display: "flex", - justifyContent: "center", - alignItems: "center", - zIndex: 2000, - backgroundColor: theme.colors.background.base, - })} - > - - - )} - {isI18nReady && ( - - )} + {(loading || !isI18nReady) && } + {isI18nReady && } diff --git a/web/apps/photos/src/components/LoadingOverlay.tsx b/web/apps/photos/src/components/GalleryLoadingOverlay.tsx similarity index 85% rename from web/apps/photos/src/components/LoadingOverlay.tsx rename to web/apps/photos/src/components/GalleryLoadingOverlay.tsx index 90869c91ae..5a6b3a3427 100644 --- a/web/apps/photos/src/components/LoadingOverlay.tsx +++ b/web/apps/photos/src/components/GalleryLoadingOverlay.tsx @@ -1,5 +1,5 @@ import { styled } from "@mui/material"; -export const LoadingOverlay = styled("div")` +export const GalleryLoadingOverlay = styled("div")` left: 0; top: 0; outline: none; diff --git a/web/apps/photos/src/pages/_app.tsx b/web/apps/photos/src/pages/_app.tsx index 4df9e18abd..c08fd8b0dc 100644 --- a/web/apps/photos/src/pages/_app.tsx +++ b/web/apps/photos/src/pages/_app.tsx @@ -1,8 +1,7 @@ import { clientPackageName, isDesktop, staticAppTitle } from "@/base/app"; import { CustomHead } from "@/base/components/Head"; +import { LoadingOverlay } from "@/base/components/LoadingOverlay"; import { AttributedMiniDialog } from "@/base/components/MiniDialog"; -import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator"; -import { Overlay } from "@/base/components/mui/Container"; import { AppNavbar } from "@/base/components/Navbar"; import { genericErrorDialogAttributes, @@ -152,7 +151,7 @@ export default function App({ Component, pageProps }: AppProps) { }); router.events.on("routeChangeComplete", () => { - log.debug(() => `Route change took ${Date.now() - t}} ms`); + log.debug(() => `Route change took ${Date.now() - t} ms`); setLoading(false); }); }, []); @@ -229,22 +228,8 @@ export default function App({ Component, pageProps }: AppProps) { /> - {(loading || !isI18nReady) && ( - ({ - display: "flex", - justifyContent: "center", - alignItems: "center", - zIndex: 2000, - backgroundColor: theme.colors.background.base, - })} - > - - - )} - {isI18nReady && ( - - )} + {(loading || !isI18nReady) && } + {isI18nReady && } diff --git a/web/apps/photos/src/pages/gallery.tsx b/web/apps/photos/src/pages/gallery.tsx index cd274d7d81..854898c6da 100644 --- a/web/apps/photos/src/pages/gallery.tsx +++ b/web/apps/photos/src/pages/gallery.tsx @@ -97,7 +97,7 @@ import { import { FixCreationTime } from "components/FixCreationTime"; import FullScreenDropZone from "components/FullScreenDropZone"; import GalleryEmptyState from "components/GalleryEmptyState"; -import { LoadingOverlay } from "components/LoadingOverlay"; +import { GalleryLoadingOverlay } from "components/GalleryLoadingOverlay"; import PhotoFrame from "components/PhotoFrame"; import { ITEM_TYPE, TimeStampListItem } from "components/PhotoList"; import Sidebar from "components/Sidebar"; @@ -892,9 +892,9 @@ export default function Gallery() { }} /> {blockingLoad && ( - + - + )} {isFirstLoad && ( diff --git a/web/apps/photos/src/pages/shared-albums.tsx b/web/apps/photos/src/pages/shared-albums.tsx index 42db4149e6..c7c081550b 100644 --- a/web/apps/photos/src/pages/shared-albums.tsx +++ b/web/apps/photos/src/pages/shared-albums.tsx @@ -52,7 +52,7 @@ import { FilesDownloadProgressAttributes, } from "components/FilesDownloadProgress"; import FullScreenDropZone from "components/FullScreenDropZone"; -import { LoadingOverlay } from "components/LoadingOverlay"; +import { GalleryLoadingOverlay } from "components/GalleryLoadingOverlay"; import PhotoFrame from "components/PhotoFrame"; import { ITEM_TYPE, TimeStampListItem } from "components/PhotoList"; import Uploader from "components/Upload/Uploader"; @@ -520,9 +520,9 @@ export default function PublicCollectionGallery() { selectable={downloadEnabled} /> {blockingLoad && ( - + - + )} ( + ({ + display: "flex", + justifyContent: "center", + alignItems: "center", + zIndex: 2000, + backgroundColor: theme.colors.background.base, + })} + > + + +); From 5f33fe9215665aefbe4bfea5838780af61fda227 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 9 Jan 2025 19:48:14 +0530 Subject: [PATCH 6/7] F --- web/docs/dependencies.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/web/docs/dependencies.md b/web/docs/dependencies.md index a52875d9cc..f4d2ac3e54 100644 --- a/web/docs/dependencies.md +++ b/web/docs/dependencies.md @@ -142,6 +142,11 @@ with Next.js. For more details, see [translations.md](translations.md). +### Font + +The app uses Inter as its primary font, via +[@fontsource-variable/inter](https://fontsource.org/fonts/inter/install). + ### UI components - [react-window](https://github.com/bvaughn/react-window) is used for lazy-ily From ea417bd46a92b09ce7fa5aa4a2e0b97d8fcf24c7 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 9 Jan 2025 19:57:11 +0530 Subject: [PATCH 7/7] H --- web/apps/accounts/src/pages/_app.tsx | 6 +++--- web/apps/auth/src/pages/_app.tsx | 5 ++--- web/apps/photos/src/pages/_app.tsx | 5 ++--- .../base/components/utils/hooks-i18n.ts | 21 +++++++++++++++++++ 4 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 web/packages/base/components/utils/hooks-i18n.ts diff --git a/web/apps/accounts/src/pages/_app.tsx b/web/apps/accounts/src/pages/_app.tsx index 65ead78130..f828ecab03 100644 --- a/web/apps/accounts/src/pages/_app.tsx +++ b/web/apps/accounts/src/pages/_app.tsx @@ -4,8 +4,8 @@ import { LoadingOverlay } from "@/base/components/LoadingOverlay"; import { AttributedMiniDialog } from "@/base/components/MiniDialog"; import { AppNavbar } from "@/base/components/Navbar"; import { useAttributedMiniDialog } from "@/base/components/utils/dialog"; +import { useSetupI18n } from "@/base/components/utils/hooks-i18n"; import { getTheme, THEME_COLOR } from "@/base/components/utils/theme"; -import { setupI18n } from "@/base/i18n"; import { disableDiskLogs } from "@/base/log"; import { logUnhandledErrorsAndRejections } from "@/base/log-web"; import { CssBaseline } from "@mui/material"; @@ -19,13 +19,13 @@ import "@fontsource-variable/inter"; import "styles/global.css"; const App: React.FC = ({ Component, pageProps }) => { - const [isI18nReady, setIsI18nReady] = useState(false); const [showNavbar, setShowNavbar] = useState(false); + + const isI18nReady = useSetupI18n(); const { showMiniDialog, miniDialogProps } = useAttributedMiniDialog(); useEffect(() => { disableDiskLogs(); - void setupI18n().finally(() => setIsI18nReady(true)); logUnhandledErrorsAndRejections(true); return () => logUnhandledErrorsAndRejections(false); }, []); diff --git a/web/apps/auth/src/pages/_app.tsx b/web/apps/auth/src/pages/_app.tsx index 70cc79bfcf..67b72c3b82 100644 --- a/web/apps/auth/src/pages/_app.tsx +++ b/web/apps/auth/src/pages/_app.tsx @@ -5,8 +5,8 @@ import { LoadingOverlay } from "@/base/components/LoadingOverlay"; import { AttributedMiniDialog } from "@/base/components/MiniDialog"; import { AppNavbar } from "@/base/components/Navbar"; import { useAttributedMiniDialog } from "@/base/components/utils/dialog"; +import { useSetupI18n } from "@/base/components/utils/hooks-i18n"; import { THEME_COLOR, getTheme } from "@/base/components/utils/theme"; -import { setupI18n } from "@/base/i18n"; import { logStartupBanner, logUnhandledErrorsAndRejections, @@ -32,10 +32,10 @@ import "styles/global.css"; const App: React.FC = ({ Component, pageProps }) => { const router = useRouter(); - const [isI18nReady, setIsI18nReady] = useState(false); const [loading, setLoading] = useState(false); const [showNavbar, setShowNavBar] = useState(false); + const isI18nReady = useSetupI18n(); const { showMiniDialog, miniDialogProps } = useAttributedMiniDialog(); const [themeColor, setThemeColor] = useLocalState( LS_KEYS.THEME, @@ -43,7 +43,6 @@ const App: React.FC = ({ Component, pageProps }) => { ); useEffect(() => { - void setupI18n().finally(() => setIsI18nReady(true)); const user = getData(LS_KEYS.USER) as User | undefined | null; void migrateKVToken(user); logStartupBanner(user?.id); diff --git a/web/apps/photos/src/pages/_app.tsx b/web/apps/photos/src/pages/_app.tsx index c08fd8b0dc..d1908fe8db 100644 --- a/web/apps/photos/src/pages/_app.tsx +++ b/web/apps/photos/src/pages/_app.tsx @@ -7,8 +7,8 @@ import { genericErrorDialogAttributes, useAttributedMiniDialog, } from "@/base/components/utils/dialog"; +import { useSetupI18n } from "@/base/components/utils/hooks-i18n"; import { THEME_COLOR, getTheme } from "@/base/components/utils/theme"; -import { setupI18n } from "@/base/i18n"; import log from "@/base/log"; import { logStartupBanner, @@ -53,7 +53,6 @@ import "styles/global.css"; export default function App({ Component, pageProps }: AppProps) { const router = useRouter(); - const [isI18nReady, setIsI18nReady] = useState(false); const [loading, setLoading] = useState(false); const [showNavbar, setShowNavBar] = useState(false); const [watchFolderView, setWatchFolderView] = useState(false); @@ -64,6 +63,7 @@ export default function App({ Component, pageProps }: AppProps) { useState(null); const isOffline = useIsOffline(); + const isI18nReady = useSetupI18n(); const { showMiniDialog, miniDialogProps } = useAttributedMiniDialog(); const { loadingBarRef, showLoadingBar, hideLoadingBar } = useLoadingBar(); const [themeColor, setThemeColor] = useLocalState( @@ -72,7 +72,6 @@ export default function App({ Component, pageProps }: AppProps) { ); useEffect(() => { - void setupI18n().finally(() => setIsI18nReady(true)); const user = getData(LS_KEYS.USER) as User | undefined | null; void migrateKVToken(user); logStartupBanner(user?.id); diff --git a/web/packages/base/components/utils/hooks-i18n.ts b/web/packages/base/components/utils/hooks-i18n.ts new file mode 100644 index 0000000000..1f7accce96 --- /dev/null +++ b/web/packages/base/components/utils/hooks-i18n.ts @@ -0,0 +1,21 @@ +import { setupI18n } from "@/base/i18n"; +import { useEffect, useState } from "react"; + +/** + * A hook that initializes the localization library that we use. + * + * This is only meant to be called from the top level `_app.tsx`, as this + * initialization is expected to only happen once for the lifetime of the page. + * + * @returns a boolean which will be set to true when the localized strings have + * been loaded. + */ +export const useSetupI18n = () => { + const [isI18nReady, setIsI18nReady] = useState(false); + + useEffect(() => { + void setupI18n().finally(() => setIsI18nReady(true)); + }, []); + + return isI18nReady; +};