diff --git a/app/root.tsx b/app/root.tsx index b560c11d8..ca41d8405 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -4,11 +4,13 @@ import type { LinksFunction } from "react-router" import { useChangeLanguage } from "remix-i18next/react" import type { Route } from "./+types/root" import { LanguageSwitcher } from "./library/language-switcher" +import { ClientHintCheck, getHints } from "./services/client-hints" import tailwindcss from "./tailwind.css?url" -export async function loader({ context }: Route.LoaderArgs) { +export async function loader({ context, request }: Route.LoaderArgs) { const { lang, clientEnv } = context - return { lang, clientEnv } + const hints = getHints(request) + return { lang, clientEnv, hints } } export const links: LinksFunction = () => [{ rel: "stylesheet", href: tailwindcss }] @@ -20,7 +22,6 @@ export const handle = { export default function App({ loaderData }: Route.ComponentProps) { const { lang, clientEnv } = loaderData useChangeLanguage(lang) - return ( <> @@ -35,6 +36,7 @@ export const Layout = ({ children }: { children: React.ReactNode }) => { return ( + diff --git a/app/services/client-hints.tsx b/app/services/client-hints.tsx new file mode 100644 index 000000000..328134767 --- /dev/null +++ b/app/services/client-hints.tsx @@ -0,0 +1,47 @@ +import { getHintUtils } from "@epic-web/client-hints" +import { clientHint as colorSchemeHint, subscribeToSchemeChange } from "@epic-web/client-hints/color-scheme" +import { clientHint as reducedMotionHint, subscribeToMotionChange } from "@epic-web/client-hints/reduced-motion" +import { clientHint as timeZoneHint } from "@epic-web/client-hints/time-zone" +import { useEffect } from "react" +import { useRevalidator, useRouteLoaderData } from "react-router" +import type { Route } from "../+types/root" + +export const { getHints, getClientHintCheckScript } = getHintUtils({ + theme: colorSchemeHint, + timeZone: timeZoneHint, + reducedMotion: reducedMotionHint, + // add other hints here +}) + +/** + * @public + * Utility function used to get the time zone for the current users browser on either the client or the server. + * */ +export const getTimeZone = (request?: Request) => getHints(request).timeZone + +/** + * @public + * Utility used to get the client hints for the current users browser. + * */ +export function useHints() { + const requestInfo = useRouteLoaderData("root") + return requestInfo?.hints +} +/** + * Utility component used to check the client hints on the client and send them to the server. + */ +export function ClientHintCheck({ nonce }: { nonce?: string }) { + const { revalidate } = useRevalidator() + useEffect(() => subscribeToSchemeChange(() => revalidate()), [revalidate]) + useEffect(() => subscribeToMotionChange(() => revalidate()), [revalidate]) + + return ( +