0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-06 20:40:08 -05:00

refactor(console): add AppBoundary in admin console

This commit is contained in:
Charles Zhao 2022-06-01 15:13:48 +08:00
parent 7781d49667
commit ba13ea06e5
No known key found for this signature in database
GPG key ID: 4858774754C92DF2
5 changed files with 100 additions and 61 deletions

View file

@ -8,6 +8,7 @@ import './scss/normalized.scss';
// eslint-disable-next-line import/no-unassigned-import // eslint-disable-next-line import/no-unassigned-import
import '@fontsource/roboto-mono'; import '@fontsource/roboto-mono';
import AppBoundary from './components/AppBoundary';
import AppContent from './components/AppContent'; import AppContent from './components/AppContent';
import ErrorBoundary from './components/ErrorBoundary'; import ErrorBoundary from './components/ErrorBoundary';
import Toast from './components/Toast'; import Toast from './components/Toast';
@ -36,19 +37,39 @@ const Main = () => {
return ( return (
<ErrorBoundary> <ErrorBoundary>
<SWRConfig value={{ fetcher }}> <SWRConfig value={{ fetcher }}>
<Toast /> <AppBoundary>
<Routes> <Toast />
<Route path="callback" element={<Callback />} /> <Routes>
<Route element={<AppContent />}> <Route path="callback" element={<Callback />} />
<Route path="*" element={<NotFound />} /> <Route element={<AppContent />}>
<Route path="get-started" element={<GetStarted />} /> <Route path="*" element={<NotFound />} />
<Route path="applications"> <Route path="get-started" element={<GetStarted />} />
<Route index element={<Applications />} /> <Route path="applications">
<Route path=":id"> <Route index element={<Applications />} />
<Route index element={<Navigate to="settings" />} /> <Route path=":id">
<Route path="settings" element={<ApplicationDetails />} /> <Route index element={<Navigate to="settings" />} />
<Route path="advanced-settings" element={<ApplicationDetails />} /> <Route path="settings" element={<ApplicationDetails />} />
<Route path="advanced-settings" element={<ApplicationDetails />} />
</Route>
</Route> </Route>
<Route path="api-resources">
<Route index element={<ApiResources />} />
<Route path=":id" element={<ApiResourceDetails />} />
</Route>
<Route path="connectors">
<Route index element={<Connectors />} />
<Route path="social" element={<Connectors />} />
<Route path=":connectorId" element={<ConnectorDetails />} />
</Route>
<Route path="users">
<Route index element={<Users />} />
<Route path=":id" element={<UserDetails />} />
</Route>
<Route path="sign-in-experience">
<Route index element={<Navigate to="experience" />} />
<Route path=":tab" element={<SignInExperience />} />
</Route>
<Route path="settings" element={<Settings />} />
</Route> </Route>
<Route path="api-resources"> <Route path="api-resources">
<Route index element={<ApiResources />} /> <Route index element={<ApiResources />} />
@ -69,8 +90,8 @@ const Main = () => {
</Route> </Route>
<Route path="settings" element={<Settings />} /> <Route path="settings" element={<Settings />} />
<Route path="dashboard" element={<Dashboard />} /> <Route path="dashboard" element={<Dashboard />} />
</Route> </Routes>
</Routes> </AppBoundary>
</SWRConfig> </SWRConfig>
</ErrorBoundary> </ErrorBoundary>
); );

View file

@ -0,0 +1,21 @@
@use '@logto/shared/scss/console-themes' as themes;
.light {
@include themes.light;
}
.dark {
@include themes.dark;
}
@media (prefers-color-scheme: light) {
body {
@include themes.light;
}
}
@media (prefers-color-scheme: dark) {
body {
@include themes.dark;
}
}

View file

@ -0,0 +1,44 @@
import { AppearanceMode } from '@logto/schemas';
import React, { ReactNode, useEffect } from 'react';
import { themeStorageKey } from '@/consts';
import useAdminConsoleConfigs from '@/hooks/use-configs';
import initI18n from '@/i18n/init';
import * as styles from './index.module.scss';
type Props = {
children?: ReactNode;
};
const AppBoundary = ({ children }: Props) => {
const defaultTheme = localStorage.getItem(themeStorageKey) ?? AppearanceMode.SyncWithSystem;
const { configs } = useAdminConsoleConfigs();
const theme = configs?.appearanceMode ?? defaultTheme;
useEffect(() => {
const isFollowSystem = theme === AppearanceMode.SyncWithSystem;
const className = styles[theme] ?? '';
if (!isFollowSystem) {
document.body.classList.add(className);
}
return () => {
if (!isFollowSystem) {
document.body.classList.remove(className);
}
};
}, [theme]);
useEffect(() => {
(async () => {
void initI18n(configs?.language);
})();
}, [configs?.language]);
// eslint-disable-next-line react/jsx-no-useless-fragment
return <>{children}</>;
};
export default AppBoundary;

View file

@ -26,23 +26,3 @@
margin: 0 auto; margin: 0 auto;
} }
} }
.light {
@include themes.light;
}
.dark {
@include themes.dark;
}
@media (prefers-color-scheme: light) {
body {
@include themes.light;
}
}
@media (prefers-color-scheme: dark) {
body {
@include themes.dark;
}
}

View file

@ -1,22 +1,17 @@
import { LogtoClientError, useLogto } from '@logto/react'; import { LogtoClientError, useLogto } from '@logto/react';
import { AppearanceMode } from '@logto/schemas';
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { Outlet, useHref, useLocation, useNavigate } from 'react-router-dom'; import { Outlet, useHref, useLocation, useNavigate } from 'react-router-dom';
import AppError from '@/components/AppError'; import AppError from '@/components/AppError';
import LogtoLoading from '@/components/LogtoLoading'; import LogtoLoading from '@/components/LogtoLoading';
import SessionExpired from '@/components/SessionExpired'; import SessionExpired from '@/components/SessionExpired';
import { themeStorageKey } from '@/consts';
import useAdminConsoleConfigs from '@/hooks/use-configs'; import useAdminConsoleConfigs from '@/hooks/use-configs';
import initI18n from '@/i18n/init';
import Sidebar, { getPath } from './components/Sidebar'; import Sidebar, { getPath } from './components/Sidebar';
import { useSidebarMenuItems } from './components/Sidebar/hook'; import { useSidebarMenuItems } from './components/Sidebar/hook';
import Topbar from './components/Topbar'; import Topbar from './components/Topbar';
import * as styles from './index.module.scss'; import * as styles from './index.module.scss';
const defaultTheme = localStorage.getItem(themeStorageKey) ?? AppearanceMode.SyncWithSystem;
const AppContent = () => { const AppContent = () => {
const { isAuthenticated, error, signIn } = useLogto(); const { isAuthenticated, error, signIn } = useLogto();
const href = useHref('/callback'); const href = useHref('/callback');
@ -33,28 +28,6 @@ const AppContent = () => {
} }
}, [href, isAuthenticated, signIn]); }, [href, isAuthenticated, signIn]);
useEffect(() => {
const theme = configs?.appearanceMode ?? defaultTheme;
const isFollowSystem = theme === AppearanceMode.SyncWithSystem;
const className = styles[theme] ?? '';
if (!isFollowSystem) {
document.body.classList.add(className);
}
return () => {
if (!isFollowSystem) {
document.body.classList.remove(className);
}
};
}, [configs?.appearanceMode]);
useEffect(() => {
(async () => {
void initI18n(configs?.language);
})();
}, [configs?.language]);
useEffect(() => { useEffect(() => {
// Navigate to the first menu item after configs are loaded. // Navigate to the first menu item after configs are loaded.
if (configs && location.pathname === '/') { if (configs && location.pathname === '/') {