feat: add colorscheme to user in db (#987)
This commit is contained in:
89
apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx
Normal file
89
apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import type { PropsWithChildren } from "react";
|
||||
import type { MantineColorScheme, MantineColorSchemeManager } from "@mantine/core";
|
||||
import { createTheme, isMantineColorScheme, MantineProvider } from "@mantine/core";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { useSession } from "@homarr/auth/client";
|
||||
|
||||
export const CustomMantineProvider = ({ children }: PropsWithChildren) => {
|
||||
const manager = useColorSchemeManager();
|
||||
|
||||
return (
|
||||
<MantineProvider
|
||||
defaultColorScheme="auto"
|
||||
colorSchemeManager={manager}
|
||||
theme={createTheme({
|
||||
primaryColor: "red",
|
||||
autoContrast: true,
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</MantineProvider>
|
||||
);
|
||||
};
|
||||
|
||||
function useColorSchemeManager(): MantineColorSchemeManager {
|
||||
const key = "homarr-color-scheme";
|
||||
const { data: session } = useSession();
|
||||
const [sessionColorScheme, setSessionColorScheme] = useState<MantineColorScheme | undefined>(
|
||||
session?.user.colorScheme,
|
||||
);
|
||||
const { mutate: mutateColorScheme } = clientApi.user.changeColorScheme.useMutation({
|
||||
onSuccess: (_, variables) => {
|
||||
setSessionColorScheme(variables.colorScheme);
|
||||
},
|
||||
});
|
||||
|
||||
let handleStorageEvent: (event: StorageEvent) => void;
|
||||
|
||||
return {
|
||||
get: (defaultValue) => {
|
||||
if (typeof window === "undefined") {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (sessionColorScheme) {
|
||||
return sessionColorScheme;
|
||||
}
|
||||
|
||||
try {
|
||||
return (window.localStorage.getItem(key) as MantineColorScheme | undefined) ?? defaultValue;
|
||||
} catch {
|
||||
return defaultValue;
|
||||
}
|
||||
},
|
||||
|
||||
set: (value) => {
|
||||
try {
|
||||
if (session) {
|
||||
mutateColorScheme({ colorScheme: value });
|
||||
}
|
||||
window.localStorage.setItem(key, value);
|
||||
} catch (error) {
|
||||
console.warn("[@mantine/core] Local storage color scheme manager was unable to save color scheme.", error);
|
||||
}
|
||||
},
|
||||
|
||||
subscribe: (onUpdate) => {
|
||||
handleStorageEvent = (event) => {
|
||||
if (session) return; // Ignore updates when session is available as we are using session color scheme
|
||||
if (event.storageArea === window.localStorage && event.key === key && isMantineColorScheme(event.newValue)) {
|
||||
onUpdate(event.newValue);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("storage", handleStorageEvent);
|
||||
},
|
||||
|
||||
unsubscribe: () => {
|
||||
window.removeEventListener("storage", handleStorageEvent);
|
||||
},
|
||||
|
||||
clear: () => {
|
||||
window.localStorage.removeItem(key);
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,13 +1,11 @@
|
||||
import type { Metadata, Viewport } from "next";
|
||||
import { Inter } from "next/font/google";
|
||||
|
||||
import "@homarr/ui/styles.css";
|
||||
import "@homarr/notifications/styles.css";
|
||||
import "@homarr/spotlight/styles.css";
|
||||
import "@homarr/ui/styles.css";
|
||||
import "~/styles/scroll-area.scss";
|
||||
|
||||
import { ColorSchemeScript, createTheme, MantineProvider } from "@mantine/core";
|
||||
|
||||
import { env } from "@homarr/auth/env.mjs";
|
||||
import { auth } from "@homarr/auth/next";
|
||||
import { ModalProvider } from "@homarr/modals";
|
||||
@@ -15,6 +13,7 @@ import { Notifications } from "@homarr/notifications";
|
||||
|
||||
import { Analytics } from "~/components/layout/analytics";
|
||||
import { JotaiProvider } from "./_client-providers/jotai";
|
||||
import { CustomMantineProvider } from "./_client-providers/mantine";
|
||||
import { NextInternationalProvider } from "./_client-providers/next-international";
|
||||
import { AuthProvider } from "./_client-providers/session";
|
||||
import { TRPCReactProvider } from "./_client-providers/trpc";
|
||||
@@ -51,34 +50,25 @@ export const viewport: Viewport = {
|
||||
],
|
||||
};
|
||||
|
||||
export default function Layout(props: { children: React.ReactNode; params: { locale: string } }) {
|
||||
const colorScheme = "dark";
|
||||
export default async function Layout(props: { children: React.ReactNode; params: { locale: string } }) {
|
||||
const session = await auth();
|
||||
const colorScheme = session?.user.colorScheme;
|
||||
|
||||
const StackedProvider = composeWrappers([
|
||||
async (innerProps) => {
|
||||
const session = await auth();
|
||||
(innerProps) => {
|
||||
return <AuthProvider session={session} logoutUrl={env.AUTH_LOGOUT_REDIRECT_URL} {...innerProps} />;
|
||||
},
|
||||
(innerProps) => <JotaiProvider {...innerProps} />,
|
||||
(innerProps) => <TRPCReactProvider {...innerProps} />,
|
||||
(innerProps) => <NextInternationalProvider {...innerProps} locale={props.params.locale} />,
|
||||
(innerProps) => (
|
||||
<MantineProvider
|
||||
{...innerProps}
|
||||
defaultColorScheme="dark"
|
||||
theme={createTheme({
|
||||
primaryColor: "red",
|
||||
autoContrast: true,
|
||||
})}
|
||||
/>
|
||||
),
|
||||
(innerProps) => <CustomMantineProvider {...innerProps} />,
|
||||
(innerProps) => <ModalProvider {...innerProps} />,
|
||||
]);
|
||||
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
// Instead of ColorSchemScript we use data-mantine-color-scheme to prevent flickering
|
||||
<html lang="en" data-mantine-color-scheme={colorScheme} suppressHydrationWarning>
|
||||
<head>
|
||||
<ColorSchemeScript defaultColorScheme={colorScheme} />
|
||||
<Analytics />
|
||||
</head>
|
||||
<body className={["font-sans", fontSans.variable].join(" ")}>
|
||||
|
||||
Reference in New Issue
Block a user