Doceditor: Fixed theme

This commit is contained in:
Akmal Isomadinov 2024-07-24 14:18:06 +05:00
parent 3eb4671598
commit 098a540aaa
5 changed files with 122 additions and 34 deletions

View File

@ -24,15 +24,18 @@
// 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
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 { SYSTEM_THEME_KEY } from "@docspace/shared/constants";
import Providers from "@/providers";
import Scripts from "@/components/Scripts";
import StyledComponentsRegistry from "@/utils/registry";
import { getColorTheme, getSettings, getUser } from "@/utils/actions";
import "@/styles/globals.scss";
import Providers from "@/providers";
import { getSettings, getUser } from "@/utils/actions";
export default async function RootLayout({
children,
@ -41,13 +44,23 @@ export default async function RootLayout({
}) {
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")) {
console.log("is health check");
return <></>;
}
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();
if (settings === "access-restricted") redirect(`${getBaseUrl()}/${settings}`);
@ -70,7 +83,7 @@ export default async function RootLayout({
<body>
<StyledComponentsRegistry>
<Providers
contextData={{ user, settings }}
contextData={{ user, settings, systemTheme, colorTheme }}
api_host={api_host}
timer={timer}
>

View File

@ -26,34 +26,59 @@
import React from "react";
import { i18n } from "i18next";
import { match, P } from "ts-pattern";
import { Base, Dark, TColorScheme, TTheme } from "@docspace/shared/themes";
import { getSystemTheme } from "@docspace/shared/utils";
import { setCookie } from "@docspace/shared/utils/cookie";
import { ThemeKeys } from "@docspace/shared/enums";
import { getAppearanceTheme } from "@docspace/shared/api/settings";
import { TUser } from "@docspace/shared/api/people/types";
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 {
user?: TUser;
i18n?: i18n;
systemTheme?: ThemeKeys;
colorTheme?: TGetColorTheme;
}
const useTheme = ({ user, i18n }: UseThemeProps) => {
const useTheme = ({ user, i18n, systemTheme, colorTheme }: UseThemeProps) => {
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>(() => {
if (user?.theme === ThemeKeys.DarkStr)
return {
...Dark,
currentColorScheme: currentColorTheme,
};
const interfaceDirection = i18n?.dir ? i18n.dir() : "ltr";
const newTheme = match<MatchType>([user?.theme, systemTheme])
.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 {
...Base,
...newTheme,
currentColorScheme: currentColorTheme,
interfaceDirection,
fontFamily: getFontFamilyDependingOnLanguage(i18n?.language ?? "en"),
};
});
@ -73,28 +98,26 @@ const useTheme = ({ user, i18n }: UseThemeProps) => {
}, []);
const getUserTheme = React.useCallback(() => {
if (!user?.theme) return;
let theme = user.theme;
const SYSTEM_THEME = getSystemTheme();
let theme = user?.theme ?? SYSTEM_THEME;
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) {
setTheme({
...Base,
currentColorScheme: currentColorTheme,
interfaceDirection,
fontFamily: getFontFamilyDependingOnLanguage(i18n?.language),
});
const fontFamily = getFontFamilyDependingOnLanguage(i18n?.language ?? "en");
return;
}
const isBaseTheme = theme === ThemeKeys.BaseStr;
const themeCookie = isBaseTheme ? ThemeKeys.BaseStr : ThemeKeys.DarkStr;
setTheme({
...Dark,
...(isBaseTheme ? Base : Dark),
currentColorScheme: currentColorTheme,
interfaceDirection,
fontFamily,
});
setCookie(SYSTEM_THEME_KEY, themeCookie);
}, [user?.theme, i18n, currentColorTheme]);
React.useEffect(() => {
@ -105,6 +128,16 @@ const useTheme = ({ user, i18n }: UseThemeProps) => {
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 };
};

View File

@ -30,7 +30,11 @@ import React from "react";
import { ThemeProvider as ComponentThemeProvider } from "@docspace/shared/components/theme-provider";
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 useI18N from "@/hooks/useI18N";
@ -39,12 +43,25 @@ type TThemeProvider = {
children: React.ReactNode;
settings: TSettings | 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 { theme, currentColorTheme } = useTheme({ user, i18n });
const { theme, currentColorTheme } = useTheme({
user,
i18n,
systemTheme,
colorTheme,
});
return (
<ComponentThemeProvider

View File

@ -24,9 +24,13 @@
// 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
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 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 TranslationProvider from "./TranslationProvider";
@ -35,6 +39,8 @@ import ErrorProvider from "./ErrorProvider";
export type TContextData = {
user: TUser | undefined;
settings: TSettings | undefined;
systemTheme: ThemeKeys | undefined;
colorTheme: TGetColorTheme | undefined;
};
export type TProviders = {

View File

@ -36,7 +36,10 @@ import type {
TFile,
} from "@docspace/shared/api/files/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 {
ActionType,
@ -500,3 +503,19 @@ export async function getEditorUrl(
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;
}