mirror of
https://github.com/logto-io/logto.git
synced 2025-03-10 22:22:45 -05:00
fix(ui): theme adaption (#3350)
This commit is contained in:
parent
16b3c580e6
commit
e89b82d27a
4 changed files with 26 additions and 22 deletions
|
@ -29,9 +29,10 @@ import './scss/normalized.scss';
|
|||
|
||||
const App = () => {
|
||||
const { context, Provider } = usePageContext();
|
||||
const { experienceSettings, setLoading, setExperienceSettings } = context;
|
||||
const { isPreview, experienceSettings, setLoading, setExperienceSettings } = context;
|
||||
const customCssRef = useRef(document.createElement('style'));
|
||||
const [isPreview] = usePreview(context);
|
||||
|
||||
usePreview(context);
|
||||
|
||||
useEffect(() => {
|
||||
document.head.append(customCssRef.current);
|
||||
|
|
|
@ -3,6 +3,7 @@ import { useState, useMemo, createContext } from 'react';
|
|||
import { isMobile } from 'react-device-detect';
|
||||
|
||||
import type { SignInExperienceResponse, Platform, Theme } from '@/types';
|
||||
import { parseQueryParameters } from '@/utils';
|
||||
|
||||
export type Context = {
|
||||
theme: Theme;
|
||||
|
@ -11,6 +12,7 @@ export type Context = {
|
|||
platform: Platform;
|
||||
termsAgreement: boolean;
|
||||
experienceSettings: SignInExperienceResponse | undefined;
|
||||
isPreview: boolean;
|
||||
setTheme: React.Dispatch<React.SetStateAction<Theme>>;
|
||||
setToast: React.Dispatch<React.SetStateAction<string>>;
|
||||
setLoading: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
|
@ -26,6 +28,7 @@ export const PageContext = createContext<Context>({
|
|||
platform: isMobile ? 'mobile' : 'web',
|
||||
termsAgreement: false,
|
||||
experienceSettings: undefined,
|
||||
isPreview: false,
|
||||
setTheme: noop,
|
||||
setToast: noop,
|
||||
setLoading: noop,
|
||||
|
@ -42,6 +45,9 @@ const usePageContext = () => {
|
|||
const [experienceSettings, setExperienceSettings] = useState<SignInExperienceResponse>();
|
||||
const [termsAgreement, setTermsAgreement] = useState(false);
|
||||
|
||||
const { preview } = parseQueryParameters(window.location.search);
|
||||
const isPreview = preview === 'true';
|
||||
|
||||
const context = useMemo(
|
||||
() => ({
|
||||
theme,
|
||||
|
@ -50,6 +56,7 @@ const usePageContext = () => {
|
|||
platform,
|
||||
termsAgreement,
|
||||
experienceSettings,
|
||||
isPreview,
|
||||
setTheme,
|
||||
setLoading,
|
||||
setToast,
|
||||
|
@ -57,7 +64,7 @@ const usePageContext = () => {
|
|||
setTermsAgreement,
|
||||
setExperienceSettings,
|
||||
}),
|
||||
[experienceSettings, loading, platform, termsAgreement, theme, toast]
|
||||
[experienceSettings, isPreview, loading, platform, termsAgreement, theme, toast]
|
||||
);
|
||||
|
||||
return {
|
||||
|
|
|
@ -3,28 +3,15 @@ import { conditionalString } from '@silverhand/essentials';
|
|||
import { useEffect, useState } from 'react';
|
||||
|
||||
import * as styles from '@/Layout/AppLayout/index.module.scss';
|
||||
import * as appStyles from '@/Providers/AppBoundary/index.module.scss';
|
||||
import type { Context } from '@/hooks/use-page-context';
|
||||
import initI18n from '@/i18n/init';
|
||||
import { changeLanguage } from '@/i18n/utils';
|
||||
import type { SignInExperienceResponse, PreviewConfig, Theme } from '@/types';
|
||||
import { parseQueryParameters } from '@/utils';
|
||||
import type { SignInExperienceResponse, PreviewConfig } from '@/types';
|
||||
import { filterPreviewSocialConnectors } from '@/utils/social-connectors';
|
||||
|
||||
const applyTheme = (theme: Theme) => {
|
||||
document.body.classList.remove(
|
||||
conditionalString(appStyles.light),
|
||||
conditionalString(appStyles.dark)
|
||||
);
|
||||
document.body.classList.add(conditionalString(appStyles[theme]));
|
||||
};
|
||||
|
||||
const usePreview = (context: Context): [boolean, PreviewConfig?] => {
|
||||
const [previewConfig, setPreviewConfig] = useState<PreviewConfig>();
|
||||
const { setExperienceSettings, setPlatform } = context;
|
||||
|
||||
const { preview } = parseQueryParameters(window.location.search);
|
||||
const isPreview = preview === 'true';
|
||||
const { isPreview, setExperienceSettings, setPlatform, setTheme } = context;
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPreview) {
|
||||
|
@ -80,13 +67,13 @@ const usePreview = (context: Context): [boolean, PreviewConfig?] => {
|
|||
};
|
||||
|
||||
(async () => {
|
||||
applyTheme(mode);
|
||||
setTheme(mode);
|
||||
|
||||
setPlatform(platform);
|
||||
|
||||
setExperienceSettings(experienceSettings);
|
||||
})();
|
||||
}, [isPreview, previewConfig, setExperienceSettings, setPlatform]);
|
||||
}, [isPreview, previewConfig, setExperienceSettings, setPlatform, setTheme]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPreview || !previewConfig?.language) {
|
||||
|
|
|
@ -8,9 +8,18 @@ const darkThemeWatchMedia = window.matchMedia('(prefers-color-scheme: dark)');
|
|||
const getThemeBySystemConfiguration = (): Theme => (darkThemeWatchMedia.matches ? 'dark' : 'light');
|
||||
|
||||
export default function useTheme(): Theme {
|
||||
const { experienceSettings, theme, setTheme } = useContext(PageContext);
|
||||
const { isPreview, experienceSettings, theme, setTheme } = useContext(PageContext);
|
||||
|
||||
useEffect(() => {
|
||||
/**
|
||||
* Note:
|
||||
* In preview mode, the theme of the page is controlled by the preview options and does not follow system changes.
|
||||
* The `usePreview` hook changes the theme of the page by calling the `setTheme` API of the `PageContext`.
|
||||
*/
|
||||
if (isPreview) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!experienceSettings?.color.isDarkModeEnabled) {
|
||||
return;
|
||||
}
|
||||
|
@ -26,7 +35,7 @@ export default function useTheme(): Theme {
|
|||
return () => {
|
||||
darkThemeWatchMedia.removeEventListener('change', changeTheme);
|
||||
};
|
||||
}, [experienceSettings, setTheme]);
|
||||
}, [experienceSettings, isPreview, setTheme]);
|
||||
|
||||
return theme;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue