Skip to content

Commit

Permalink
Dark mode fixes: editable note and persistence (#10754)
Browse files Browse the repository at this point in the history
Signed-off-by: Hubert Zub <hubert.zub@databricks.com>
  • Loading branch information
hubertzub-db committed Jan 8, 2024
1 parent e5df626 commit 4be7f5f
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 3 deletions.
7 changes: 4 additions & 3 deletions mlflow/server/js/src/app.tsx
Expand Up @@ -14,13 +14,13 @@ import { ConfigProvider } from 'antd';
import { LegacySkeleton } from '@databricks/design-system';
import { shouldUsePathRouting } from './common/utils/FeatureUtils';
import { MlflowRouter } from './MlflowRouter';
import { useMLflowDarkTheme } from './common/hooks/useMLflowDarkTheme';

export function MLFlowRoot() {
// eslint-disable-next-line react-hooks/rules-of-hooks
const i18n = useI18nInit();
const [isDarkTheme, setIsDarkTheme] = React.useState(
window.matchMedia('(prefers-color-scheme: dark)').matches || false,
);

const [isDarkTheme, setIsDarkTheme, MlflowThemeGlobalStyles] = useMLflowDarkTheme();

if (!i18n) {
return (
Expand All @@ -37,6 +37,7 @@ export function MLFlowRoot() {
<Provider store={store}>
<DesignSystemContainer isDarkTheme={isDarkTheme}>
<ApplyGlobalStyles />
<MlflowThemeGlobalStyles />
<ConfigProvider prefixCls='ant'>
{shouldUsePathRouting() ? (
<MlflowRouter isDarkTheme={isDarkTheme} setIsDarkTheme={setIsDarkTheme} />
Expand Down
3 changes: 3 additions & 0 deletions mlflow/server/js/src/common/components/EditableNote.css
Expand Up @@ -6,3 +6,6 @@
margin-left: 16px;
}

.mde-header {
background: var(--secondary-background-color);
}
39 changes: 39 additions & 0 deletions mlflow/server/js/src/common/hooks/useMLflowDarkTheme.tsx
@@ -0,0 +1,39 @@
import { Global } from '@emotion/react';
import { useEffect, useState } from 'react';

const darkModePrefLocalStorageKey = '_mlflow_dark_mode_toggle_enabled';
const darkModeBodyClassName = 'dark-mode';

// CSS attributes to be applied when dark mode is enabled. Affects inputs and other form elements.
const darkModeCSSStyles = { body: { [`&.${darkModeBodyClassName}`]: { colorScheme: 'dark' } } };
// This component is used to set the global CSS.
const DarkModeStylesComponent = () => <Global styles={darkModeCSSStyles} />;

/**
* This hook is used to toggle the dark mode for the entire app.
* Used in open source MLflow.
* Returns a boolean value with the current state, setter function, and a component to be rendered in the root of the app.
*/
export const useMLflowDarkTheme = (): [
boolean,
React.Dispatch<React.SetStateAction<boolean>>,
React.ComponentType,
] => {
const [isDarkTheme, setIsDarkTheme] = useState(() => {
// If the user has explicitly set a preference, use that.
if (localStorage.getItem(darkModePrefLocalStorageKey) === 'true') {
return true;
}
// Otherwise, use the system preference as a default.
return window.matchMedia('(prefers-color-scheme: dark)').matches || false;
});

useEffect(() => {
// Update the theme when the user changes their system preference.
document.body.classList.toggle(darkModeBodyClassName, isDarkTheme);
// Persist the user's preference in local storage.
localStorage.setItem(darkModePrefLocalStorageKey, isDarkTheme ? 'true' : 'false');
}, [isDarkTheme]);

return [isDarkTheme, setIsDarkTheme, DarkModeStylesComponent];
};

0 comments on commit 4be7f5f

Please sign in to comment.