Fix/Keep themes in peace across embed and booking pages and App (#8108)
This commit is contained in:
parent
39c48e7f79
commit
2c96444058
|
@ -2,7 +2,6 @@ import { useRouter } from "next/router";
|
||||||
import { useCallback, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
|
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import useTheme from "@calcom/lib/hooks/useTheme";
|
|
||||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||||
import type { RecurringEvent } from "@calcom/types/Calendar";
|
import type { RecurringEvent } from "@calcom/types/Calendar";
|
||||||
import { Button, TextArea } from "@calcom/ui";
|
import { Button, TextArea } from "@calcom/ui";
|
||||||
|
@ -34,7 +33,6 @@ export default function CancelBooking(props: Props) {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
const [error, setError] = useState<string | null>(booking ? null : t("booking_already_cancelled"));
|
const [error, setError] = useState<string | null>(booking ? null : t("booking_already_cancelled"));
|
||||||
useTheme(props.theme);
|
|
||||||
|
|
||||||
const cancelBookingRef = useCallback((node: HTMLTextAreaElement) => {
|
const cancelBookingRef = useCallback((node: HTMLTextAreaElement) => {
|
||||||
if (node !== null) {
|
if (node !== null) {
|
||||||
|
|
|
@ -27,7 +27,8 @@ const I18nextAdapter = appWithTranslation<NextJsAppProps<SSRConfig> & { children
|
||||||
export type AppProps = Omit<NextAppProps<WithNonceProps & Record<string, unknown>>, "Component"> & {
|
export type AppProps = Omit<NextAppProps<WithNonceProps & Record<string, unknown>>, "Component"> & {
|
||||||
Component: NextAppProps["Component"] & {
|
Component: NextAppProps["Component"] & {
|
||||||
requiresLicense?: boolean;
|
requiresLicense?: boolean;
|
||||||
isThemeSupported?: boolean | ((arg: { router: NextRouter }) => boolean);
|
isThemeSupported?: boolean;
|
||||||
|
isBookingPage?: boolean | ((arg: { router: NextRouter }) => boolean);
|
||||||
getLayout?: (page: React.ReactElement, router: NextRouter) => ReactNode;
|
getLayout?: (page: React.ReactElement, router: NextRouter) => ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,45 +62,66 @@ const CustomI18nextProvider = (props: AppPropsWithChildren) => {
|
||||||
return <I18nextAdapter {...passedProps} />;
|
return <I18nextAdapter {...passedProps} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const enum ThemeSupport {
|
||||||
|
// e.g. Login Page
|
||||||
|
None = "none",
|
||||||
|
// Entire App except Booking Pages
|
||||||
|
App = "systemOnly",
|
||||||
|
// Booking Pages(including Routing Forms)
|
||||||
|
Booking = "userConfigured",
|
||||||
|
}
|
||||||
|
|
||||||
const CalcomThemeProvider = (
|
const CalcomThemeProvider = (
|
||||||
props: PropsWithChildren<
|
props: PropsWithChildren<
|
||||||
WithNonceProps & { isThemeSupported?: boolean | ((arg: { router: NextRouter }) => boolean) }
|
WithNonceProps & {
|
||||||
|
isBookingPage?: boolean | ((arg: { router: NextRouter }) => boolean);
|
||||||
|
isThemeSupported?: boolean;
|
||||||
|
}
|
||||||
>
|
>
|
||||||
) => {
|
) => {
|
||||||
// We now support the inverse of how we handled it in the past. Setting this to false will disable theme.
|
// We now support the inverse of how we handled it in the past. Setting this to false will disable theme.
|
||||||
// undefined or true means we use system theme
|
// undefined or true means we use system theme
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const isThemeSupported = (() => {
|
const isBookingPage = (() => {
|
||||||
if (typeof props.isThemeSupported === "function") {
|
if (typeof props.isBookingPage === "function") {
|
||||||
return props.isThemeSupported({ router: router });
|
return props.isBookingPage({ router: router });
|
||||||
}
|
}
|
||||||
if (typeof props.isThemeSupported === "undefined") {
|
|
||||||
return true;
|
return props.isBookingPage;
|
||||||
}
|
|
||||||
return props.isThemeSupported;
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const forcedTheme = !isThemeSupported ? "light" : undefined;
|
const themeSupport = isBookingPage
|
||||||
|
? ThemeSupport.Booking
|
||||||
|
: // if isThemeSupported is explicitly false, we don't use theme there
|
||||||
|
props.isThemeSupported === false
|
||||||
|
? ThemeSupport.None
|
||||||
|
: ThemeSupport.App;
|
||||||
|
|
||||||
|
const forcedTheme = themeSupport === ThemeSupport.None ? "light" : undefined;
|
||||||
// Use namespace of embed to ensure same namespaced embed are displayed with same theme. This allows different embeds on the same website to be themed differently
|
// Use namespace of embed to ensure same namespaced embed are displayed with same theme. This allows different embeds on the same website to be themed differently
|
||||||
// One such example is our Embeds Demo and Testing page at http://localhost:3100
|
// One such example is our Embeds Demo and Testing page at http://localhost:3100
|
||||||
// Having `getEmbedNamespace` defined on window before react initializes the app, ensures that embedNamespace is available on the first mount and can be used as part of storageKey
|
// Having `getEmbedNamespace` defined on window before react initializes the app, ensures that embedNamespace is available on the first mount and can be used as part of storageKey
|
||||||
const embedNamespace = typeof window !== "undefined" ? window.getEmbedNamespace() : null;
|
const embedNamespace = typeof window !== "undefined" ? window.getEmbedNamespace() : null;
|
||||||
const isEmbedMode = typeof embedNamespace === "string";
|
const isEmbedMode = typeof embedNamespace === "string";
|
||||||
// If embedNamespace is not defined, we use the default storageKey -> The default storage key changs based on if we force light mode or not
|
|
||||||
// This is done to ensure that the default theme is light when we force light mode and as soon as you navigate to a page that is dark we dont need a hard refresh to change
|
|
||||||
const storageKey = isEmbedMode
|
const storageKey = isEmbedMode
|
||||||
? `embed-theme-${embedNamespace}`
|
? `embed-theme-${embedNamespace}`
|
||||||
: !isThemeSupported
|
: themeSupport === ThemeSupport.App
|
||||||
? "cal-light"
|
? "app-theme"
|
||||||
: "theme";
|
: themeSupport === ThemeSupport.Booking
|
||||||
|
? "booking-theme"
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ThemeProvider
|
<ThemeProvider
|
||||||
nonce={props.nonce}
|
nonce={props.nonce}
|
||||||
enableColorScheme={false}
|
enableColorScheme={false}
|
||||||
enableSystem={isThemeSupported}
|
enableSystem={themeSupport !== ThemeSupport.None}
|
||||||
forcedTheme={forcedTheme}
|
forcedTheme={forcedTheme}
|
||||||
storageKey={storageKey}
|
storageKey={storageKey}
|
||||||
|
// next-themes doesn't listen to changes on storageKey. So we need to force a re-render when storageKey changes
|
||||||
|
// This is how login to dashboard soft navigation changes theme from light to dark
|
||||||
|
key={storageKey}
|
||||||
attribute="class">
|
attribute="class">
|
||||||
{/* Embed Mode can be detected reliably only on client side here as there can be static generated pages as well which can't determine if it's embed mode at backend */}
|
{/* Embed Mode can be detected reliably only on client side here as there can be static generated pages as well which can't determine if it's embed mode at backend */}
|
||||||
{/* color-scheme makes background:transparent not work in iframe which is required by embed. */}
|
{/* color-scheme makes background:transparent not work in iframe which is required by embed. */}
|
||||||
|
@ -134,7 +156,8 @@ const AppProviders = (props: AppPropsWithChildren) => {
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<CalcomThemeProvider
|
<CalcomThemeProvider
|
||||||
nonce={props.pageProps.nonce}
|
nonce={props.pageProps.nonce}
|
||||||
isThemeSupported={props.Component.isThemeSupported}>
|
isThemeSupported={props.Component.isThemeSupported}
|
||||||
|
isBookingPage={props.Component.isBookingPage}>
|
||||||
<FeatureFlagsProvider>
|
<FeatureFlagsProvider>
|
||||||
<MetaProvider>{props.children}</MetaProvider>
|
<MetaProvider>{props.children}</MetaProvider>
|
||||||
</FeatureFlagsProvider>
|
</FeatureFlagsProvider>
|
||||||
|
|
|
@ -195,6 +195,8 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
User.isBookingPage = true;
|
||||||
|
|
||||||
const getEventTypesWithHiddenFromDB = async (userId: number) => {
|
const getEventTypesWithHiddenFromDB = async (userId: number) => {
|
||||||
return (
|
return (
|
||||||
await prisma.eventType.findMany({
|
await prisma.eventType.findMany({
|
||||||
|
|
|
@ -54,6 +54,8 @@ export default function Type(props: AvailabilityPageProps) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type.isBookingPage = true;
|
||||||
|
|
||||||
const paramsSchema = z.object({ type: z.string(), user: z.string() });
|
const paramsSchema = z.object({ type: z.string(), user: z.string() });
|
||||||
async function getUserPageProps(context: GetStaticPropsContext) {
|
async function getUserPageProps(context: GetStaticPropsContext) {
|
||||||
// load server side dependencies
|
// load server side dependencies
|
||||||
|
|
|
@ -69,6 +69,8 @@ export default function Book(props: BookPageProps) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Book.isBookingPage = true;
|
||||||
|
|
||||||
const querySchema = z.object({
|
const querySchema = z.object({
|
||||||
bookingUid: z.string().optional(),
|
bookingUid: z.string().optional(),
|
||||||
count: z.coerce.number().optional(),
|
count: z.coerce.number().optional(),
|
||||||
|
|
|
@ -15,7 +15,7 @@ type AppPageType = {
|
||||||
getServerSideProps: AppGetServerSideProps;
|
getServerSideProps: AppGetServerSideProps;
|
||||||
// A component than can accept any properties
|
// A component than can accept any properties
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
default: ((props: any) => JSX.Element) & Pick<AppProps["Component"], "isThemeSupported" | "getLayout">;
|
default: ((props: any) => JSX.Element) & Pick<AppProps["Component"], "isBookingPage" | "getLayout">;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Found = {
|
type Found = {
|
||||||
|
@ -70,17 +70,17 @@ const AppPage: AppPageType["default"] = function AppPage(props) {
|
||||||
return <route.Component {...componentProps} />;
|
return <route.Component {...componentProps} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
AppPage.isThemeSupported = ({ router }) => {
|
AppPage.isBookingPage = ({ router }) => {
|
||||||
const route = getRoute(router.query.slug as string, router.query.pages as string[]);
|
const route = getRoute(router.query.slug as string, router.query.pages as string[]);
|
||||||
if (route.notFound) {
|
if (route.notFound) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const isThemeSupported = route.Component.isThemeSupported;
|
const isBookingPage = route.Component.isBookingPage;
|
||||||
if (typeof isThemeSupported === "function") {
|
if (typeof isBookingPage === "function") {
|
||||||
return isThemeSupported({ router });
|
return isBookingPage({ router });
|
||||||
}
|
}
|
||||||
|
|
||||||
return !!isThemeSupported;
|
return !!isBookingPage;
|
||||||
};
|
};
|
||||||
|
|
||||||
AppPage.getLayout = (page, router) => {
|
AppPage.getLayout = (page, router) => {
|
||||||
|
|
|
@ -268,7 +268,9 @@ export default function Success(props: SuccessProps) {
|
||||||
return t("emailed_you_and_attendees" + titleSuffix);
|
return t("emailed_you_and_attendees" + titleSuffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
useTheme(isSuccessBookingPage ? props.profile.theme : "light");
|
// This is a weird case where the same route can be opened in booking flow as a success page or as a booking detail page from the app
|
||||||
|
// As Booking Page it has to support configured theme, but as booking detail page it should not do any change. Let Shell.tsx handle it.
|
||||||
|
useTheme(isSuccessBookingPage ? props.profile.theme : undefined);
|
||||||
useBrandColors({
|
useBrandColors({
|
||||||
brandColor: props.profile.brandColor,
|
brandColor: props.profile.brandColor,
|
||||||
darkBrandColor: props.profile.darkBrandColor,
|
darkBrandColor: props.profile.darkBrandColor,
|
||||||
|
@ -705,6 +707,8 @@ export default function Success(props: SuccessProps) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Success.isBookingPage = true;
|
||||||
|
|
||||||
type RecurringBookingsProps = {
|
type RecurringBookingsProps = {
|
||||||
eventType: SuccessProps["eventType"];
|
eventType: SuccessProps["eventType"];
|
||||||
recurringBookings: SuccessProps["recurringBookings"];
|
recurringBookings: SuccessProps["recurringBookings"];
|
||||||
|
|
|
@ -24,6 +24,8 @@ export default function Type(props: DynamicAvailabilityPageProps) {
|
||||||
return <AvailabilityPage {...props} />;
|
return <AvailabilityPage {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type.isBookingPage = true;
|
||||||
|
|
||||||
const querySchema = z.object({
|
const querySchema = z.object({
|
||||||
link: z.string().optional().default(""),
|
link: z.string().optional().default(""),
|
||||||
slug: z.string().optional().default(""),
|
slug: z.string().optional().default(""),
|
||||||
|
|
|
@ -19,6 +19,8 @@ export default function Book(props: HashLinkPageProps) {
|
||||||
return <BookingPage {...props} />;
|
return <BookingPage {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Book.isBookingPage = true;
|
||||||
|
|
||||||
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||||
const ssr = await ssrInit(context);
|
const ssr = await ssrInit(context);
|
||||||
const link = asStringOrThrow(context.query.link as string);
|
const link = asStringOrThrow(context.query.link as string);
|
||||||
|
|
|
@ -203,4 +203,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||||
} as const;
|
} as const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TeamPage.isBookingPage = true;
|
||||||
|
|
||||||
export default TeamPage;
|
export default TeamPage;
|
||||||
|
|
|
@ -24,6 +24,8 @@ export default function TeamType(props: AvailabilityTeamPageProps) {
|
||||||
return <AvailabilityPage {...props} />;
|
return <AvailabilityPage {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TeamType.isBookingPage = true;
|
||||||
|
|
||||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||||
const slugParam = asStringOrNull(context.query.slug);
|
const slugParam = asStringOrNull(context.query.slug);
|
||||||
const typeParam = asStringOrNull(context.query.type);
|
const typeParam = asStringOrNull(context.query.type);
|
||||||
|
|
|
@ -23,6 +23,7 @@ export type TeamBookingPageProps = inferSSRProps<typeof getServerSideProps>;
|
||||||
export default function TeamBookingPage(props: TeamBookingPageProps) {
|
export default function TeamBookingPage(props: TeamBookingPageProps) {
|
||||||
return <BookingPage {...props} />;
|
return <BookingPage {...props} />;
|
||||||
}
|
}
|
||||||
|
TeamBookingPage.isBookingPage = true;
|
||||||
|
|
||||||
const querySchema = z.object({
|
const querySchema = z.object({
|
||||||
rescheduleUid: z.string().optional(),
|
rescheduleUid: z.string().optional(),
|
||||||
|
|
|
@ -332,7 +332,6 @@ export default function FormEditPage({
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
FormEditPage.isThemeSupported = true;
|
|
||||||
|
|
||||||
FormEditPage.getLayout = (page: React.ReactElement) => {
|
FormEditPage.getLayout = (page: React.ReactElement) => {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -252,8 +252,6 @@ export default function RoutingForms({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
RoutingForms.isThemeSupported = true;
|
|
||||||
|
|
||||||
RoutingForms.getLayout = (page: React.ReactElement) => {
|
RoutingForms.getLayout = (page: React.ReactElement) => {
|
||||||
return <Shell withoutMain={true}>{page}</Shell>;
|
return <Shell withoutMain={true}>{page}</Shell>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -197,8 +197,6 @@ export default function ReporterWrapper({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReporterWrapper.isThemeSupported = true;
|
|
||||||
|
|
||||||
ReporterWrapper.getLayout = (page: React.ReactElement) => {
|
ReporterWrapper.getLayout = (page: React.ReactElement) => {
|
||||||
return (
|
return (
|
||||||
<Shell backPath="/apps/routing-forms/forms" withoutMain={true}>
|
<Shell backPath="/apps/routing-forms/forms" withoutMain={true}>
|
||||||
|
|
|
@ -523,7 +523,6 @@ export default function RouteBuilder({
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
RouteBuilder.isThemeSupported = true;
|
|
||||||
|
|
||||||
RouteBuilder.getLayout = (page: React.ReactElement) => {
|
RouteBuilder.getLayout = (page: React.ReactElement) => {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -26,8 +26,6 @@ export default function Router({ form, message }: inferSSRProps<typeof getServer
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Router.isThemeSupported = true;
|
|
||||||
|
|
||||||
const querySchema = z
|
const querySchema = z
|
||||||
.object({
|
.object({
|
||||||
form: z.string(),
|
form: z.string(),
|
||||||
|
|
|
@ -165,7 +165,7 @@ export default function RoutingLink(props: inferSSRProps<typeof getServerSidePro
|
||||||
return <RoutingForm {...props} />;
|
return <RoutingForm {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
RoutingLink.isThemeSupported = true;
|
RoutingLink.isBookingPage = true;
|
||||||
|
|
||||||
export const getServerSideProps = async function getServerSideProps(
|
export const getServerSideProps = async function getServerSideProps(
|
||||||
context: AppGetServerSidePropsContext,
|
context: AppGetServerSidePropsContext,
|
||||||
|
|
|
@ -22,7 +22,6 @@ import classNames from "@calcom/lib/classNames";
|
||||||
import { APP_NAME, DESKTOP_APP_LINK, JOIN_SLACK, ROADMAP, WEBAPP_URL } from "@calcom/lib/constants";
|
import { APP_NAME, DESKTOP_APP_LINK, JOIN_SLACK, ROADMAP, WEBAPP_URL } from "@calcom/lib/constants";
|
||||||
import getBrandColours from "@calcom/lib/getBrandColours";
|
import getBrandColours from "@calcom/lib/getBrandColours";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import useTheme from "@calcom/lib/hooks/useTheme";
|
|
||||||
import { isKeyInObject } from "@calcom/lib/isKeyInObject";
|
import { isKeyInObject } from "@calcom/lib/isKeyInObject";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
|
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
|
||||||
|
@ -231,7 +230,8 @@ export default function Shell(props: LayoutProps) {
|
||||||
// if a page is unauthed and isPublic is true, the redirect does not happen.
|
// if a page is unauthed and isPublic is true, the redirect does not happen.
|
||||||
useRedirectToLoginIfUnauthenticated(props.isPublic);
|
useRedirectToLoginIfUnauthenticated(props.isPublic);
|
||||||
useRedirectToOnboardingIfNeeded();
|
useRedirectToOnboardingIfNeeded();
|
||||||
useTheme();
|
// System Theme is automatically supported using ThemeProvider. If we intend to use user theme throughout the app we need to uncomment this.
|
||||||
|
// useTheme(profile.theme);
|
||||||
useBrandColors();
|
useBrandColors();
|
||||||
|
|
||||||
return !props.isPublic ? (
|
return !props.isPublic ? (
|
||||||
|
|
|
@ -4,23 +4,28 @@ import { useEffect } from "react";
|
||||||
import { useEmbedTheme } from "@calcom/embed-core/embed-iframe";
|
import { useEmbedTheme } from "@calcom/embed-core/embed-iframe";
|
||||||
import type { Maybe } from "@calcom/trpc/server";
|
import type { Maybe } from "@calcom/trpc/server";
|
||||||
|
|
||||||
// makes sure the ui doesn't flash
|
/**
|
||||||
export default function useTheme(theme?: Maybe<string>) {
|
* It should be called once per route and only if you want to use app configured theme. System only theme works automatically by using ThemeProvider
|
||||||
|
* Calling it without a theme will just returns the current theme.
|
||||||
|
* It handles embed configured theme as well.
|
||||||
|
*/
|
||||||
|
export default function useTheme(themeToSet?: Maybe<string>) {
|
||||||
const { resolvedTheme, setTheme, forcedTheme, theme: activeTheme } = useNextTheme();
|
const { resolvedTheme, setTheme, forcedTheme, theme: activeTheme } = useNextTheme();
|
||||||
const embedTheme = useEmbedTheme();
|
const embedTheme = useEmbedTheme();
|
||||||
// Embed UI configuration takes more precedence over App Configuration
|
|
||||||
const currentTheme = embedTheme || theme || "system";
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentTheme !== activeTheme && typeof currentTheme === "string") {
|
// If themeToSet is not provided the purpose is to just return the current the current values
|
||||||
setTheme(currentTheme);
|
if (themeToSet === undefined) return;
|
||||||
}
|
|
||||||
|
// Embed theme takes precedence over theme configured in app. This allows embeds to be themed differently
|
||||||
|
const finalThemeToSet = embedTheme || themeToSet || "system";
|
||||||
|
|
||||||
|
if (!finalThemeToSet || finalThemeToSet === activeTheme) return;
|
||||||
|
|
||||||
|
console.log("Setting theme", { resolvedTheme, finalThemeToSet, activeTheme, forcedTheme });
|
||||||
|
setTheme(finalThemeToSet);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps -- we do not want activeTheme to re-render this effect
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- we do not want activeTheme to re-render this effect
|
||||||
}, [currentTheme, setTheme]);
|
}, [themeToSet, setTheme]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (forcedTheme) setTheme(forcedTheme);
|
|
||||||
}, [forcedTheme, setTheme]);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
resolvedTheme,
|
resolvedTheme,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user