diff --git a/packages/ui/src/App.tsx b/packages/ui/src/App.tsx index bea4d67bf..5a5215e04 100644 --- a/packages/ui/src/App.tsx +++ b/packages/ui/src/App.tsx @@ -2,6 +2,7 @@ import { SignInMode } from '@logto/schemas'; import { useEffect } from 'react'; import { Route, Routes, BrowserRouter, Navigate } from 'react-router-dom'; +import AppBoundary from './containers/AppBoundary'; import AppContent from './containers/AppContent'; import LoadingLayerProvider from './containers/LoadingLayerProvider'; import usePageContext from './hooks/use-page-context'; @@ -15,6 +16,7 @@ import ErrorPage from './pages/ErrorPage'; import ForgotPassword from './pages/ForgotPassword'; import Passcode from './pages/Passcode'; import PasswordRegisterWithUsername from './pages/PasswordRegisterWithUsername'; +import Profile from './pages/Profile'; import Register from './pages/Register'; import ResetPassword from './pages/ResetPassword'; import SecondaryRegister from './pages/SecondaryRegister'; @@ -57,60 +59,66 @@ const App = () => { const isSignInOnly = experienceSettings.signInMode === SignInMode.SignIn; return ( - - - + + + - } /> - } /> - } - /> - - }> - {/* Sign-in */} + } /> + }> + } /> + } /> : } + path="/unknown-session" + element={} /> - } /> - } /> - } /> - {/* Register */} - : } - /> - } - /> - } /> + }> + {/* Sign-in */} + : } + /> + } /> + } /> + } /> - {/* Forgot password */} - } /> - } /> + {/* Register */} + : } + /> + } + /> + } /> - {/* Continue set up missing profile */} - } /> - } /> + {/* Forgot password */} + } /> + } /> - {/* Social sign-in pages */} - } /> - } /> - } /> + {/* Continue set up missing profile */} + } + /> + } /> - {/* Always keep route path with param as the last one */} - } /> + {/* Social sign-in pages */} + } /> + } /> + } /> + + {/* Always keep route path with param as the last one */} + } /> + + + } /> - - } /> - - - + + + ); }; diff --git a/packages/ui/src/containers/AppBoundary/index.module.scss b/packages/ui/src/containers/AppBoundary/index.module.scss new file mode 100644 index 000000000..62b82ec69 --- /dev/null +++ b/packages/ui/src/containers/AppBoundary/index.module.scss @@ -0,0 +1,22 @@ +@use '@/scss/colors' as colors; +@use '@/scss/underscore' as _; + +body { + &.light { + @include colors.light; + } + + &.dark { + @include colors.dark; + } +} + +:global(body.mobile) { + --max-width: 360px; + background: var(--color-bg-body); +} + +:global(body.desktop) { + --max-width: 400px; + background: var(--color-bg-float-base); +} diff --git a/packages/ui/src/containers/AppBoundary/index.tsx b/packages/ui/src/containers/AppBoundary/index.tsx new file mode 100644 index 000000000..36ef98761 --- /dev/null +++ b/packages/ui/src/containers/AppBoundary/index.tsx @@ -0,0 +1,48 @@ +import { conditionalString } from '@silverhand/essentials'; +import type { ReactNode } from 'react'; +import { useCallback, useContext, useEffect } from 'react'; + +import Toast from '@/components/Toast'; +import useColorTheme from '@/hooks/use-color-theme'; +import { PageContext } from '@/hooks/use-page-context'; +import useTheme from '@/hooks/use-theme'; + +import ConfirmModalProvider from '../ConfirmModalProvider'; +import * as styles from './index.module.scss'; + +type Props = { + children: ReactNode; +}; + +const AppBoundary = ({ children }: Props) => { + // Set Primary Color + useColorTheme(); + const theme = useTheme(); + const { platform, toast, setToast } = useContext(PageContext); + + // Set Theme Mode + useEffect(() => { + document.body.classList.remove(conditionalString(styles.light), conditionalString(styles.dark)); + document.body.classList.add(conditionalString(styles[theme])); + }, [theme]); + + // Apply Platform Style + useEffect(() => { + document.body.classList.remove('desktop', 'mobile'); + document.body.classList.add(platform === 'mobile' ? 'mobile' : 'desktop'); + }, [platform]); + + // Prevent internal eventListener rebind + const hideToast = useCallback(() => { + setToast(''); + }, [setToast]); + + return ( + + + {children} + + ); +}; + +export default AppBoundary; diff --git a/packages/ui/src/containers/AppContent/index.module.scss b/packages/ui/src/containers/AppContent/index.module.scss index a530f8f1d..084d4ad84 100644 --- a/packages/ui/src/containers/AppContent/index.module.scss +++ b/packages/ui/src/containers/AppContent/index.module.scss @@ -1,6 +1,4 @@ @use '@/scss/underscore' as _; -@use '@/scss/colors' as colors; -@use '@/scss/fonts' as fonts; /* Preview Settings */ .preview { @@ -13,30 +11,10 @@ } } -/* Foundation */ -body { - --radius: 8px; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: auto; - word-break: break-word; - @include colors.static; - - &.light { - @include colors.light; - } - - &.dark { - @include colors.dark; - } - - @include fonts.fonts; -} - /* Main Layout */ .container { position: absolute; inset: 0; - color: var(--color-type-primary); overflow: auto; @include _.flex_column(center, normal); } @@ -51,14 +29,6 @@ body { } :global(body.mobile) { - --max-width: 360px; - background: var(--color-bg-body); - - .container { - background: var(--color-bg-body); - font: var(--font-body-2); - } - .main { flex: 1; align-self: stretch; @@ -69,14 +39,6 @@ body { } :global(body.desktop) { - --max-width: 400px; - background: var(--color-bg-float-base); - - .container { - background: var(--color-bg-float-base); - font: var(--font-body-2); - } - .main { width: 640px; min-height: 640px; diff --git a/packages/ui/src/containers/AppContent/index.tsx b/packages/ui/src/containers/AppContent/index.tsx index 2683d2733..04104a9ac 100644 --- a/packages/ui/src/containers/AppContent/index.tsx +++ b/packages/ui/src/containers/AppContent/index.tsx @@ -1,52 +1,21 @@ -import { conditionalString } from '@silverhand/essentials'; -import type { ReactNode } from 'react'; -import { useEffect, useCallback, useContext } from 'react'; +import { useContext } from 'react'; +import { Outlet } from 'react-router-dom'; -import Toast from '@/components/Toast'; -import ConfirmModalProvider from '@/containers/ConfirmModalProvider'; -import useColorTheme from '@/hooks/use-color-theme'; import { PageContext } from '@/hooks/use-page-context'; -import useTheme from '@/hooks/use-theme'; import * as styles from './index.module.scss'; -export type Props = { - children: ReactNode; -}; - -const AppContent = ({ children }: Props) => { - const theme = useTheme(); - const { toast, platform, setToast } = useContext(PageContext); - - // Prevent internal eventListener rebind - const hideToast = useCallback(() => { - setToast(''); - }, [setToast]); - - // Set Primary Color - useColorTheme(); - - // Set Theme Mode - useEffect(() => { - document.body.classList.remove(conditionalString(styles.light), conditionalString(styles.dark)); - document.body.classList.add(conditionalString(styles[theme])); - }, [theme]); - - // Apply Platform Style - useEffect(() => { - document.body.classList.remove('desktop', 'mobile'); - document.body.classList.add(platform === 'mobile' ? 'mobile' : 'desktop'); - }, [platform]); +const AppContent = () => { + const { platform } = useContext(PageContext); return ( - -
- {platform === 'web' &&
} -
{children}
- {platform === 'web' &&
} - -
- +
+ {platform === 'web' &&
} +
+ +
+ {platform === 'web' &&
} +
); }; diff --git a/packages/ui/src/pages/Profile/index.tsx b/packages/ui/src/pages/Profile/index.tsx new file mode 100644 index 000000000..b023e60ab --- /dev/null +++ b/packages/ui/src/pages/Profile/index.tsx @@ -0,0 +1,5 @@ +const Profile = () => { + return <>Profile works!; +}; + +export default Profile; diff --git a/packages/ui/src/scss/normalized.scss b/packages/ui/src/scss/normalized.scss index a71811085..c9ff891bf 100644 --- a/packages/ui/src/scss/normalized.scss +++ b/packages/ui/src/scss/normalized.scss @@ -1,7 +1,18 @@ +@use '@/scss/colors' as colors; +@use '@/scss/fonts' as fonts; + body { + @include colors.static; + @include fonts.fonts; + + --radius: 8px; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: auto; margin: 0; padding: 0; - font-family: sans-serif; + word-break: break-word; + color: var(--color-type-primary); + font: var(--font-body-2); } * {