Theme loading without flickering (#2233)
This commit is contained in:
@@ -62,7 +62,7 @@
|
|||||||
"i18next-http-backend": "^2.0.0",
|
"i18next-http-backend": "^2.0.0",
|
||||||
"livekit-client": "^2.0.2",
|
"livekit-client": "^2.0.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#8123e9a3f1142a7619758c0a238172b007e3a06a",
|
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#d55c6a36df539f6adacc335efe5b9be27c9cee4a",
|
||||||
"matrix-widget-api": "^1.3.1",
|
"matrix-widget-api": "^1.3.1",
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
"pako": "^2.0.4",
|
"pako": "^2.0.4",
|
||||||
|
|||||||
@@ -13,7 +13,8 @@
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="cpd-theme-dark">
|
<!-- The default class is: .no-theme {display: none}. It will be overwritten once the app is loaded. -->
|
||||||
|
<body class="no-theme">
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -72,7 +72,9 @@ export const App: FC<AppProps> = ({ history }) => {
|
|||||||
const [loaded, setLoaded] = useState(false);
|
const [loaded, setLoaded] = useState(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Initializer.init()?.then(() => {
|
Initializer.init()?.then(() => {
|
||||||
|
if (loaded) return;
|
||||||
setLoaded(true);
|
setLoaded(true);
|
||||||
|
widget?.api.sendContentLoaded();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import styles from "./FullScreenView.module.css";
|
|||||||
import { TranslatedError } from "./TranslatedError";
|
import { TranslatedError } from "./TranslatedError";
|
||||||
import { Config } from "./config/Config";
|
import { Config } from "./config/Config";
|
||||||
import { RageshakeButton } from "./settings/RageshakeButton";
|
import { RageshakeButton } from "./settings/RageshakeButton";
|
||||||
|
import { useUrlParams } from "./UrlParams";
|
||||||
|
|
||||||
interface FullScreenViewProps {
|
interface FullScreenViewProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
@@ -37,12 +38,11 @@ export const FullScreenView: FC<FullScreenViewProps> = ({
|
|||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
|
const { hideHeader } = useUrlParams();
|
||||||
return (
|
return (
|
||||||
<div className={classNames(styles.page, className)}>
|
<div className={classNames(styles.page, className)}>
|
||||||
<Header>
|
<Header>
|
||||||
<LeftNav>
|
<LeftNav>{!hideHeader && <HeaderLogo />}</LeftNav>
|
||||||
<HeaderLogo />
|
|
||||||
</LeftNav>
|
|
||||||
<RightNav />
|
<RightNav />
|
||||||
</Header>
|
</Header>
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ export const useInteractiveRegistration = (): {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (widget) return;
|
if (widget) return;
|
||||||
|
// An empty registerRequest is used to get the privacy policy and recaptcha key.
|
||||||
authClient.current!.registerRequest({}).catch((error) => {
|
authClient.current!.registerRequest({}).catch((error) => {
|
||||||
setPrivacyPolicyUrl(
|
setPrivacyPolicyUrl(
|
||||||
error.data?.params["m.login.terms"]?.policies?.privacy_policy?.en?.url,
|
error.data?.params["m.login.terms"]?.policies?.privacy_policy?.en?.url,
|
||||||
|
|||||||
@@ -157,6 +157,10 @@ body {
|
|||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
/* We use this to not render the page at all until we know the theme.*/
|
||||||
|
.no-theme {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body,
|
body,
|
||||||
|
|||||||
@@ -22,10 +22,9 @@ export const useTheme = (): void => {
|
|||||||
const { theme: themeName } = useUrlParams();
|
const { theme: themeName } = useUrlParams();
|
||||||
const previousTheme = useRef<string | null>(document.body.classList.item(0));
|
const previousTheme = useRef<string | null>(document.body.classList.item(0));
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
// Don't update the current theme if the url does not contain a theme prop.
|
// If the url does not contain a theme props we default to "dark".
|
||||||
if (!themeName) return;
|
const theme = themeName?.includes("light") ? "light" : "dark";
|
||||||
const theme = themeName.includes("light") ? "light" : "dark";
|
const themeHighContrast = themeName?.includes("high-contrast") ? "-hc" : "";
|
||||||
const themeHighContrast = themeName.includes("high-contrast") ? "-hc" : "";
|
|
||||||
const themeString = "cpd-theme-" + theme + themeHighContrast;
|
const themeString = "cpd-theme-" + theme + themeHighContrast;
|
||||||
if (themeString !== previousTheme.current) {
|
if (themeString !== previousTheme.current) {
|
||||||
document.body.classList.remove(
|
document.body.classList.remove(
|
||||||
@@ -37,5 +36,6 @@ export const useTheme = (): void => {
|
|||||||
document.body.classList.add(themeString);
|
document.body.classList.add(themeString);
|
||||||
previousTheme.current = themeString;
|
previousTheme.current = themeString;
|
||||||
}
|
}
|
||||||
|
document.body.classList.remove("no-theme");
|
||||||
}, [previousTheme, themeName]);
|
}, [previousTheme, themeName]);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -158,6 +158,8 @@ export const widget = ((): WidgetHelpers | null => {
|
|||||||
useE2eForGroupCall: e2eEnabled,
|
useE2eForGroupCall: e2eEnabled,
|
||||||
fallbackICEServerAllowed: allowIceFallback,
|
fallbackICEServerAllowed: allowIceFallback,
|
||||||
},
|
},
|
||||||
|
// ContentLoaded event will be sent as soon as the theme is set (see useTheme.ts)
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
const clientPromise = new Promise<MatrixClient>((resolve) => {
|
const clientPromise = new Promise<MatrixClient>((resolve) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user