Doceditor: Fixed theme
This commit is contained in:
parent
3eb4671598
commit
098a540aaa
@ -24,15 +24,18 @@
|
|||||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { headers } from "next/headers";
|
import { headers, cookies } from "next/headers";
|
||||||
|
|
||||||
|
import { ThemeKeys } from "@docspace/shared/enums";
|
||||||
import { getBaseUrl } from "@docspace/shared/utils/next-ssr-helper";
|
import { getBaseUrl } from "@docspace/shared/utils/next-ssr-helper";
|
||||||
|
import { SYSTEM_THEME_KEY } from "@docspace/shared/constants";
|
||||||
|
|
||||||
|
import Providers from "@/providers";
|
||||||
import Scripts from "@/components/Scripts";
|
import Scripts from "@/components/Scripts";
|
||||||
import StyledComponentsRegistry from "@/utils/registry";
|
import StyledComponentsRegistry from "@/utils/registry";
|
||||||
|
import { getColorTheme, getSettings, getUser } from "@/utils/actions";
|
||||||
|
|
||||||
import "@/styles/globals.scss";
|
import "@/styles/globals.scss";
|
||||||
import Providers from "@/providers";
|
|
||||||
import { getSettings, getUser } from "@/utils/actions";
|
|
||||||
|
|
||||||
export default async function RootLayout({
|
export default async function RootLayout({
|
||||||
children,
|
children,
|
||||||
@ -41,13 +44,23 @@ export default async function RootLayout({
|
|||||||
}) {
|
}) {
|
||||||
const hdrs = headers();
|
const hdrs = headers();
|
||||||
|
|
||||||
|
const cookieStore = cookies();
|
||||||
|
|
||||||
|
const systemTheme = cookieStore.get(SYSTEM_THEME_KEY)?.value as
|
||||||
|
| ThemeKeys
|
||||||
|
| undefined;
|
||||||
|
|
||||||
if (hdrs.get("x-health-check") || hdrs.get("referer")?.includes("/health")) {
|
if (hdrs.get("x-health-check") || hdrs.get("referer")?.includes("/health")) {
|
||||||
console.log("is health check");
|
console.log("is health check");
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const startDate = new Date();
|
const startDate = new Date();
|
||||||
const [user, settings] = await Promise.all([getUser(), getSettings()]);
|
const [user, settings, colorTheme] = await Promise.all([
|
||||||
|
getUser(),
|
||||||
|
getSettings(),
|
||||||
|
getColorTheme(),
|
||||||
|
]);
|
||||||
const timer = new Date().getTime() - startDate.getTime();
|
const timer = new Date().getTime() - startDate.getTime();
|
||||||
|
|
||||||
if (settings === "access-restricted") redirect(`${getBaseUrl()}/${settings}`);
|
if (settings === "access-restricted") redirect(`${getBaseUrl()}/${settings}`);
|
||||||
@ -70,7 +83,7 @@ export default async function RootLayout({
|
|||||||
<body>
|
<body>
|
||||||
<StyledComponentsRegistry>
|
<StyledComponentsRegistry>
|
||||||
<Providers
|
<Providers
|
||||||
contextData={{ user, settings }}
|
contextData={{ user, settings, systemTheme, colorTheme }}
|
||||||
api_host={api_host}
|
api_host={api_host}
|
||||||
timer={timer}
|
timer={timer}
|
||||||
>
|
>
|
||||||
|
@ -26,34 +26,59 @@
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { i18n } from "i18next";
|
import { i18n } from "i18next";
|
||||||
|
import { match, P } from "ts-pattern";
|
||||||
|
|
||||||
import { Base, Dark, TColorScheme, TTheme } from "@docspace/shared/themes";
|
import { Base, Dark, TColorScheme, TTheme } from "@docspace/shared/themes";
|
||||||
import { getSystemTheme } from "@docspace/shared/utils";
|
import { getSystemTheme } from "@docspace/shared/utils";
|
||||||
|
import { setCookie } from "@docspace/shared/utils/cookie";
|
||||||
import { ThemeKeys } from "@docspace/shared/enums";
|
import { ThemeKeys } from "@docspace/shared/enums";
|
||||||
import { getAppearanceTheme } from "@docspace/shared/api/settings";
|
import { getAppearanceTheme } from "@docspace/shared/api/settings";
|
||||||
import { TUser } from "@docspace/shared/api/people/types";
|
|
||||||
import { getFontFamilyDependingOnLanguage } from "@docspace/shared/utils/rtlUtils";
|
import { getFontFamilyDependingOnLanguage } from "@docspace/shared/utils/rtlUtils";
|
||||||
|
import { SYSTEM_THEME_KEY } from "@docspace/shared/constants";
|
||||||
|
|
||||||
const SYSTEM_THEME = getSystemTheme();
|
import type { TUser } from "@docspace/shared/api/people/types";
|
||||||
|
import type { TGetColorTheme } from "@docspace/shared/api/settings/types";
|
||||||
|
|
||||||
|
type MatchType = [ThemeKeys | undefined, ThemeKeys | undefined];
|
||||||
|
|
||||||
export interface UseThemeProps {
|
export interface UseThemeProps {
|
||||||
user?: TUser;
|
user?: TUser;
|
||||||
i18n?: i18n;
|
i18n?: i18n;
|
||||||
|
systemTheme?: ThemeKeys;
|
||||||
|
colorTheme?: TGetColorTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useTheme = ({ user, i18n }: UseThemeProps) => {
|
const useTheme = ({ user, i18n, systemTheme, colorTheme }: UseThemeProps) => {
|
||||||
const [currentColorTheme, setCurrentColorTheme] =
|
const [currentColorTheme, setCurrentColorTheme] =
|
||||||
React.useState<TColorScheme>({} as TColorScheme);
|
React.useState<TColorScheme>(() => {
|
||||||
|
console.log("currentColorTheme");
|
||||||
|
|
||||||
|
if (!colorTheme) return {} as TColorScheme;
|
||||||
|
|
||||||
|
return (
|
||||||
|
colorTheme.themes.find((theme) => theme.id === colorTheme.selected) ??
|
||||||
|
({} as TColorScheme)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const [theme, setTheme] = React.useState<TTheme>(() => {
|
const [theme, setTheme] = React.useState<TTheme>(() => {
|
||||||
if (user?.theme === ThemeKeys.DarkStr)
|
const interfaceDirection = i18n?.dir ? i18n.dir() : "ltr";
|
||||||
return {
|
|
||||||
...Dark,
|
const newTheme = match<MatchType>([user?.theme, systemTheme])
|
||||||
currentColorScheme: currentColorTheme,
|
.returnType<TTheme>()
|
||||||
};
|
.with([ThemeKeys.DarkStr, P._], () => Dark)
|
||||||
|
.with([ThemeKeys.BaseStr, P._], () => Base)
|
||||||
|
.with([ThemeKeys.SystemStr, ThemeKeys.BaseStr], () => Base)
|
||||||
|
.with([ThemeKeys.SystemStr, ThemeKeys.DarkStr], () => Dark)
|
||||||
|
.with([undefined, ThemeKeys.DarkStr], () => Dark)
|
||||||
|
.with([undefined, ThemeKeys.BaseStr], () => Base)
|
||||||
|
.otherwise(() => Base);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...Base,
|
...newTheme,
|
||||||
currentColorScheme: currentColorTheme,
|
currentColorScheme: currentColorTheme,
|
||||||
|
interfaceDirection,
|
||||||
|
fontFamily: getFontFamilyDependingOnLanguage(i18n?.language ?? "en"),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -73,28 +98,26 @@ const useTheme = ({ user, i18n }: UseThemeProps) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getUserTheme = React.useCallback(() => {
|
const getUserTheme = React.useCallback(() => {
|
||||||
if (!user?.theme) return;
|
const SYSTEM_THEME = getSystemTheme();
|
||||||
let theme = user.theme;
|
|
||||||
|
let theme = user?.theme ?? SYSTEM_THEME;
|
||||||
const interfaceDirection = i18n?.dir ? i18n.dir() : "ltr";
|
const interfaceDirection = i18n?.dir ? i18n.dir() : "ltr";
|
||||||
|
|
||||||
if (user.theme === ThemeKeys.SystemStr) theme = SYSTEM_THEME;
|
if (user?.theme === ThemeKeys.SystemStr) theme = SYSTEM_THEME;
|
||||||
|
|
||||||
if (theme === ThemeKeys.BaseStr) {
|
const fontFamily = getFontFamilyDependingOnLanguage(i18n?.language ?? "en");
|
||||||
setTheme({
|
|
||||||
...Base,
|
|
||||||
currentColorScheme: currentColorTheme,
|
|
||||||
interfaceDirection,
|
|
||||||
fontFamily: getFontFamilyDependingOnLanguage(i18n?.language),
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
const isBaseTheme = theme === ThemeKeys.BaseStr;
|
||||||
}
|
const themeCookie = isBaseTheme ? ThemeKeys.BaseStr : ThemeKeys.DarkStr;
|
||||||
|
|
||||||
setTheme({
|
setTheme({
|
||||||
...Dark,
|
...(isBaseTheme ? Base : Dark),
|
||||||
currentColorScheme: currentColorTheme,
|
currentColorScheme: currentColorTheme,
|
||||||
interfaceDirection,
|
interfaceDirection,
|
||||||
|
fontFamily,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setCookie(SYSTEM_THEME_KEY, themeCookie);
|
||||||
}, [user?.theme, i18n, currentColorTheme]);
|
}, [user?.theme, i18n, currentColorTheme]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@ -105,6 +128,16 @@ const useTheme = ({ user, i18n }: UseThemeProps) => {
|
|||||||
getUserTheme();
|
getUserTheme();
|
||||||
}, [currentColorTheme, getUserTheme]);
|
}, [currentColorTheme, getUserTheme]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
||||||
|
|
||||||
|
mediaQuery.addEventListener("change", getUserTheme);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
mediaQuery.removeEventListener("change", getUserTheme);
|
||||||
|
};
|
||||||
|
}, [getUserTheme]);
|
||||||
|
|
||||||
return { theme, currentColorTheme };
|
return { theme, currentColorTheme };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,7 +30,11 @@ import React from "react";
|
|||||||
|
|
||||||
import { ThemeProvider as ComponentThemeProvider } from "@docspace/shared/components/theme-provider";
|
import { ThemeProvider as ComponentThemeProvider } from "@docspace/shared/components/theme-provider";
|
||||||
import { TUser } from "@docspace/shared/api/people/types";
|
import { TUser } from "@docspace/shared/api/people/types";
|
||||||
import { TSettings } from "@docspace/shared/api/settings/types";
|
import type {
|
||||||
|
TGetColorTheme,
|
||||||
|
TSettings,
|
||||||
|
} from "@docspace/shared/api/settings/types";
|
||||||
|
import type { ThemeKeys } from "@docspace/shared/enums";
|
||||||
|
|
||||||
import useTheme from "@/hooks/useTheme";
|
import useTheme from "@/hooks/useTheme";
|
||||||
import useI18N from "@/hooks/useI18N";
|
import useI18N from "@/hooks/useI18N";
|
||||||
@ -39,12 +43,25 @@ type TThemeProvider = {
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
settings: TSettings | undefined;
|
settings: TSettings | undefined;
|
||||||
user: TUser | undefined;
|
user: TUser | undefined;
|
||||||
|
systemTheme: ThemeKeys | undefined;
|
||||||
|
colorTheme: TGetColorTheme | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ThemeProvider = ({ children, user, settings }: TThemeProvider) => {
|
const ThemeProvider = ({
|
||||||
|
children,
|
||||||
|
user,
|
||||||
|
settings,
|
||||||
|
systemTheme,
|
||||||
|
colorTheme,
|
||||||
|
}: TThemeProvider) => {
|
||||||
const { i18n } = useI18N({ settings, user });
|
const { i18n } = useI18N({ settings, user });
|
||||||
|
|
||||||
const { theme, currentColorTheme } = useTheme({ user, i18n });
|
const { theme, currentColorTheme } = useTheme({
|
||||||
|
user,
|
||||||
|
i18n,
|
||||||
|
systemTheme,
|
||||||
|
colorTheme,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ComponentThemeProvider
|
<ComponentThemeProvider
|
||||||
|
@ -24,9 +24,13 @@
|
|||||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||||
|
|
||||||
import { TUser } from "@docspace/shared/api/people/types";
|
|
||||||
import { TSettings } from "@docspace/shared/api/settings/types";
|
|
||||||
import { Toast } from "@docspace/shared/components/toast/Toast";
|
import { Toast } from "@docspace/shared/components/toast/Toast";
|
||||||
|
import type { TUser } from "@docspace/shared/api/people/types";
|
||||||
|
import type {
|
||||||
|
TGetColorTheme,
|
||||||
|
TSettings,
|
||||||
|
} from "@docspace/shared/api/settings/types";
|
||||||
|
import type { ThemeKeys } from "@docspace/shared/enums";
|
||||||
|
|
||||||
import ThemeProvider from "./ThemeProvider";
|
import ThemeProvider from "./ThemeProvider";
|
||||||
import TranslationProvider from "./TranslationProvider";
|
import TranslationProvider from "./TranslationProvider";
|
||||||
@ -35,6 +39,8 @@ import ErrorProvider from "./ErrorProvider";
|
|||||||
export type TContextData = {
|
export type TContextData = {
|
||||||
user: TUser | undefined;
|
user: TUser | undefined;
|
||||||
settings: TSettings | undefined;
|
settings: TSettings | undefined;
|
||||||
|
systemTheme: ThemeKeys | undefined;
|
||||||
|
colorTheme: TGetColorTheme | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TProviders = {
|
export type TProviders = {
|
||||||
|
@ -36,7 +36,10 @@ import type {
|
|||||||
TFile,
|
TFile,
|
||||||
} from "@docspace/shared/api/files/types";
|
} from "@docspace/shared/api/files/types";
|
||||||
import { TUser } from "@docspace/shared/api/people/types";
|
import { TUser } from "@docspace/shared/api/people/types";
|
||||||
import { TSettings } from "@docspace/shared/api/settings/types";
|
import type {
|
||||||
|
TGetColorTheme,
|
||||||
|
TSettings,
|
||||||
|
} from "@docspace/shared/api/settings/types";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ActionType,
|
ActionType,
|
||||||
@ -500,3 +503,19 @@ export async function getEditorUrl(
|
|||||||
|
|
||||||
return editorUrl.response as TDocServiceLocation;
|
return editorUrl.response as TDocServiceLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getColorTheme() {
|
||||||
|
const [getSettings] = createRequest(
|
||||||
|
[`/settings/colortheme`],
|
||||||
|
[["", ""]],
|
||||||
|
"GET",
|
||||||
|
);
|
||||||
|
|
||||||
|
const res = await fetch(getSettings);
|
||||||
|
|
||||||
|
if (!res.ok) return;
|
||||||
|
|
||||||
|
const colorTheme = await res.json();
|
||||||
|
|
||||||
|
return colorTheme.response as TGetColorTheme;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user