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:
parent
7781d49667
commit
ba13ea06e5
5 changed files with 100 additions and 61 deletions
|
@ -8,6 +8,7 @@ import './scss/normalized.scss';
|
|||
// eslint-disable-next-line import/no-unassigned-import
|
||||
import '@fontsource/roboto-mono';
|
||||
|
||||
import AppBoundary from './components/AppBoundary';
|
||||
import AppContent from './components/AppContent';
|
||||
import ErrorBoundary from './components/ErrorBoundary';
|
||||
import Toast from './components/Toast';
|
||||
|
@ -36,19 +37,39 @@ const Main = () => {
|
|||
return (
|
||||
<ErrorBoundary>
|
||||
<SWRConfig value={{ fetcher }}>
|
||||
<Toast />
|
||||
<Routes>
|
||||
<Route path="callback" element={<Callback />} />
|
||||
<Route element={<AppContent />}>
|
||||
<Route path="*" element={<NotFound />} />
|
||||
<Route path="get-started" element={<GetStarted />} />
|
||||
<Route path="applications">
|
||||
<Route index element={<Applications />} />
|
||||
<Route path=":id">
|
||||
<Route index element={<Navigate to="settings" />} />
|
||||
<Route path="settings" element={<ApplicationDetails />} />
|
||||
<Route path="advanced-settings" element={<ApplicationDetails />} />
|
||||
<AppBoundary>
|
||||
<Toast />
|
||||
<Routes>
|
||||
<Route path="callback" element={<Callback />} />
|
||||
<Route element={<AppContent />}>
|
||||
<Route path="*" element={<NotFound />} />
|
||||
<Route path="get-started" element={<GetStarted />} />
|
||||
<Route path="applications">
|
||||
<Route index element={<Applications />} />
|
||||
<Route path=":id">
|
||||
<Route index element={<Navigate to="settings" />} />
|
||||
<Route path="settings" element={<ApplicationDetails />} />
|
||||
<Route path="advanced-settings" element={<ApplicationDetails />} />
|
||||
</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 path="api-resources">
|
||||
<Route index element={<ApiResources />} />
|
||||
|
@ -69,8 +90,8 @@ const Main = () => {
|
|||
</Route>
|
||||
<Route path="settings" element={<Settings />} />
|
||||
<Route path="dashboard" element={<Dashboard />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
</Routes>
|
||||
</AppBoundary>
|
||||
</SWRConfig>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
44
packages/console/src/components/AppBoundary/index.tsx
Normal file
44
packages/console/src/components/AppBoundary/index.tsx
Normal 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;
|
|
@ -26,23 +26,3 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,17 @@
|
|||
import { LogtoClientError, useLogto } from '@logto/react';
|
||||
import { AppearanceMode } from '@logto/schemas';
|
||||
import React, { useEffect } from 'react';
|
||||
import { Outlet, useHref, useLocation, useNavigate } from 'react-router-dom';
|
||||
|
||||
import AppError from '@/components/AppError';
|
||||
import LogtoLoading from '@/components/LogtoLoading';
|
||||
import SessionExpired from '@/components/SessionExpired';
|
||||
import { themeStorageKey } from '@/consts';
|
||||
import useAdminConsoleConfigs from '@/hooks/use-configs';
|
||||
import initI18n from '@/i18n/init';
|
||||
|
||||
import Sidebar, { getPath } from './components/Sidebar';
|
||||
import { useSidebarMenuItems } from './components/Sidebar/hook';
|
||||
import Topbar from './components/Topbar';
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
const defaultTheme = localStorage.getItem(themeStorageKey) ?? AppearanceMode.SyncWithSystem;
|
||||
|
||||
const AppContent = () => {
|
||||
const { isAuthenticated, error, signIn } = useLogto();
|
||||
const href = useHref('/callback');
|
||||
|
@ -33,28 +28,6 @@ const AppContent = () => {
|
|||
}
|
||||
}, [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(() => {
|
||||
// Navigate to the first menu item after configs are loaded.
|
||||
if (configs && location.pathname === '/') {
|
||||
|
|
Loading…
Reference in a new issue