Skip to content

Commit

Permalink
Merge pull request #3442 from microsoftgraph/feat/theme-popover
Browse files Browse the repository at this point in the history
feat: migrate theme popover to v9
  • Loading branch information
Mnickii authored Dec 11, 2024
2 parents c25fe22 + 08411d8 commit be5a415
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 4 deletions.
16 changes: 15 additions & 1 deletion src/app/views/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ interface IAppState {
sidebarTabSelection: string;
}

const getSystemTheme = (): string => {
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
return 'dark';
}
return 'light';
};

class App extends Component<IAppProps, IAppState> {
private mediaQueryList = window.matchMedia('(max-width: 992px)');
private currentTheme: ITheme = getTheme();
Expand Down Expand Up @@ -130,6 +137,12 @@ class App extends Component<IAppProps, IAppState> {
// Listens for messages from host document
window.addEventListener('message', this.receiveMessage, false);
this.handleSharedQueries();

// Load the theme from local storage or use the system theme as the default
const savedTheme = localStorage.getItem('appTheme') ?? getSystemTheme();
// @ts-ignore
this.props.actions.changeTheme(savedTheme);
loadGETheme(savedTheme); // Remove when cleaning up
};

public handleSharedQueries() {
Expand Down Expand Up @@ -412,7 +425,8 @@ class App extends Component<IAppProps, IAppState> {
const fluentV9Themes: Record<string, Theme> = {
'light': webLightTheme,
'dark': webDarkTheme,
'high-contrast': teamsHighContrastTheme
'high-contrast': teamsHighContrastTheme,
'system': getSystemTheme() === 'dark' ? webDarkTheme : webLightTheme
}
return (
// @ts-ignore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import { lazy } from 'react';

export const popups = new Map<string, any>([
['share-query', lazy(() => import('../../../query-runner/query-input/share-query/ShareQuery'))],
['theme-chooser', lazy(() => import('../../../main-header/settings/ThemeChooser'))],
['theme-chooser', lazy(() => import('../../../main-header/settings/ThemeChooserV9'))],
['preview-collection', lazy(() => import('../../../sidebar/resource-explorer/collection/APICollection'))],
['full-permissions', lazy(() => import('../../../query-runner/request/permissions/Permissions.Full'))],
['collection-permissions', lazy(() => import('../../../sidebar/resource-explorer/collection/CollectionPermissions'))],
['edit-collection-panel', lazy(() => import('../../../sidebar/resource-explorer/collection/EditCollectionPanel'))],
['edit-scope-panel', lazy(() => import('../../../sidebar/resource-explorer/collection/EditScopePanel'))]

]);

export type PopupItem =
Expand Down
3 changes: 2 additions & 1 deletion src/app/views/main-header/settings/SettingsV9.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ const SettingsV9 = ()=>{
const toggleThemeChooserDialogState = () => {
showThemeChooser({
settings: {
title: translateMessage('Change theme')
title: translateMessage('Change theme'),
width: 'xl'
}
});
telemetry.trackEvent(eventTypes.BUTTON_CLICK_EVENT, {
Expand Down
123 changes: 123 additions & 0 deletions src/app/views/main-header/settings/ThemeChooserV9.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import React, { useEffect } from 'react';
import { makeStyles, RadioGroup, Radio} from '@fluentui/react-components';
import { useAppDispatch, useAppSelector } from '../../../../store';
import { componentNames, eventTypes, telemetry } from '../../../../telemetry';
import { PopupsComponent } from '../../../services/context/popups-context';
import { changeTheme } from '../../../services/slices/theme.slice';
import { loadGETheme } from '../../../../themes';
import { translateMessage } from '../../../utils/translate-messages';
import { BrightnessHighRegular, WeatherMoonFilled, CircleHalfFillFilled, SettingsFilled} from '@fluentui/react-icons';

const availableThemes = [
{
key: 'light',
displayName: 'Web Light',
icon: <BrightnessHighRegular />
},
{
key: 'dark',
displayName: 'Web Dark',
icon: <WeatherMoonFilled />
},
{
key: 'high-contrast',
displayName: 'Teams High Contrast',
icon: <CircleHalfFillFilled />
},
{
key: 'system',
displayName: 'System Default',
icon: <SettingsFilled />
}
];

const useIconOptionStyles = makeStyles({
root: {
display: 'flex',
alignItems: 'center'
},
icon: {
fontSize: '30px',
display: 'block'
},
name: {
display: 'block'
},
radio: {
'&:checked ~ .fui-Radio__indicator::after': {
borderRadius: '50%'
}
}

});

const useLabelStyles = makeStyles({
root: {
display: 'block',
alignItems: 'center',
justifyContent: 'center',
textAlign: 'center'
}
});

const getSystemTheme = (): string => {
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
return 'dark';
}
return 'light';
};

const ThemeChooserV9: React.FC<PopupsComponent<null>> = () => {
const dispatch = useAppDispatch();
const appTheme = useAppSelector(state=> state.theme);
const iconOptionStyles = useIconOptionStyles();
const labelStyles = useLabelStyles();

useEffect(() => {
// Load the theme from local storage or use the system theme as the default
const savedTheme = localStorage.getItem('appTheme') ?? getSystemTheme();
dispatch(changeTheme(savedTheme));
loadGETheme(savedTheme); // Remove when cleaning up
}, [dispatch]);


const handleChangeTheme = (selectedTheme: { key: string; displayName: string; icon: JSX.Element }) => {
const newTheme: string = selectedTheme.key;
// Save the selected theme to local storage
localStorage.setItem('appTheme', newTheme);
// Applies the theme to the Fluent UI components
dispatch(changeTheme(newTheme));
loadGETheme(newTheme); //Remove when cleaning up
telemetry.trackEvent(eventTypes.BUTTON_CLICK_EVENT, {
ComponentName: componentNames.SELECT_THEME_BUTTON,
SelectedTheme: newTheme.replace('-', ' ').toSentenceCase()
});
};
return (
<RadioGroup layout="horizontal" aria-labelledby='theme-chooser'
value={availableThemes.find(theme => theme.key === appTheme)?.displayName}
>
{availableThemes.map((theme) => (
<div key={theme.key} className={iconOptionStyles.root}>
<Radio
value={theme.key}
checked={appTheme === theme.key}
className={iconOptionStyles.radio}
label={{
className: labelStyles.root,
children: (
<>
<div className={iconOptionStyles.icon}>{theme.icon}</div>
<div className={iconOptionStyles.name}>{translateMessage(theme.displayName)} </div>
</>
)
}}
onClick={() => handleChangeTheme(theme)}>
</Radio>
</div>
))}
</RadioGroup>
);
}

export default ThemeChooserV9
10 changes: 9 additions & 1 deletion src/themes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,19 @@ import { IPartialTheme, loadTheme } from '@fluentui/react';
import { dark } from './dark';
import { highContrast } from './high-contrast';
import { light } from './light';
// changes to be removed on cleanup
const getSystemTheme = (): string => {
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
return 'dark';
}
return 'light';
};

const themes: any = {
dark,
light,
'high-contrast': highContrast
'high-contrast': highContrast,
system: getSystemTheme() === 'dark' ? dark : light
};

export function loadGETheme(theme: string): void {
Expand Down

0 comments on commit be5a415

Please sign in to comment.