From cfdea428b6dae1726babd3b55651be38761ddb3b Mon Sep 17 00:00:00 2001 From: Angus Hollands Date: Mon, 5 Aug 2024 22:07:49 +0100 Subject: [PATCH 01/16] fix: respect system preference for theme --- packages/providers/src/theme.tsx | 85 +++++++++++++++++------ packages/site/src/loaders/theme.server.ts | 2 +- packages/site/src/pages/Root.tsx | 52 ++++++++++++-- 3 files changed, 110 insertions(+), 29 deletions(-) diff --git a/packages/providers/src/theme.tsx b/packages/providers/src/theme.tsx index e5196cf60..649edbe7d 100644 --- a/packages/providers/src/theme.tsx +++ b/packages/providers/src/theme.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect, useRef } from 'react'; import { validateRenderers, type NodeRenderers, type NodeRenderersValidated } from './renderers.js'; import { Theme } from '@myst-theme/common'; @@ -58,9 +58,34 @@ ThemeContext.displayName = 'ThemeContext'; const prefersLightMQ = '(prefers-color-scheme: light)'; +/** + * Return the theme preference indicated by the system + */ +function getPreferredTheme() { + return window.matchMedia(prefersLightMQ).matches ? Theme.light : Theme.dark; +} + +const clientThemeSource = ` + const theme = window.matchMedia(${JSON.stringify(prefersLightMQ)}).matches ? 'light' : 'dark'; + const classes = document.documentElement.classList; + const hasAnyTheme = classes.contains('light') || classes.contains('dark'); + if (hasAnyTheme) { + console.warn("Document already has theme at load. Set by cookie perhaps?"); + } else { + classes.add(theme); + } +`; + +/** + * A blocking element that runs before hydration to update the preferred class + */ +export function BlockingThemeLoader() { + return