From 7abdbfd6f5280219fe07cdc9bc3e277cf2541d3a Mon Sep 17 00:00:00 2001 From: Mnickii Date: Tue, 26 Nov 2024 15:22:59 +0100 Subject: [PATCH 1/8] migrate theme popover to v9 --- .../lazy-loader/component-registry/popups.tsx | 2 +- .../main-header/settings/ThemeChooserV9.tsx | 68 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/app/views/main-header/settings/ThemeChooserV9.tsx diff --git a/src/app/views/common/lazy-loader/component-registry/popups.tsx b/src/app/views/common/lazy-loader/component-registry/popups.tsx index 732f62b88f..e752284a9a 100644 --- a/src/app/views/common/lazy-loader/component-registry/popups.tsx +++ b/src/app/views/common/lazy-loader/component-registry/popups.tsx @@ -2,7 +2,7 @@ import { lazy } from 'react'; export const popups = new Map([ ['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/PreviewCollection'))], ['full-permissions', lazy(() => import('../../../query-runner/request/permissions/Permissions.Full'))] ]); diff --git a/src/app/views/main-header/settings/ThemeChooserV9.tsx b/src/app/views/main-header/settings/ThemeChooserV9.tsx new file mode 100644 index 0000000000..0d783ed324 --- /dev/null +++ b/src/app/views/main-header/settings/ThemeChooserV9.tsx @@ -0,0 +1,68 @@ +import { Menu, MenuTrigger, MenuButton, MenuPopover, MenuList, MenuItem } 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 { BrightnessHighRegular, WeatherMoonFilled, CircleHalfFillFilled } from '@fluentui/react-icons'; + +const availableThemes = [ + { + key: 'light', + displayName: 'Web Light', + icon: + }, + { + key: 'dark', + displayName: 'Web Dark', + icon: + }, + { + key: 'high-contrast', + displayName: 'Teams High Contrast', + icon: + } +]; + +const ThemeChooserV9: React.FC> = () => { + const dispatch = useAppDispatch(); + const appTheme = useAppSelector(state=> state.theme); + + + const handleChangeTheme = (selectedTheme: { key: string; displayName: string; icon: JSX.Element }) => { + const newTheme: string = selectedTheme?.key ?? ''; + // Applies the theme to the Fluent UI components + switch (newTheme) { + case 'light': + return dispatch(changeTheme('light')); + case 'dark': + return dispatch(changeTheme('dark')); + case 'high-contrast': + return dispatch(changeTheme('high-contrast')); + } + telemetry.trackEvent(eventTypes.BUTTON_CLICK_EVENT, { + ComponentName: componentNames.SELECT_THEME_BUTTON, + SelectedTheme: newTheme.replace('-', ' ').toSentenceCase() + }); + }; + return ( + + + theme.key === appTheme)?.icon}> + {availableThemes.find(theme => theme.key === appTheme)?.displayName} + + + + + + {availableThemes.map(theme => ( + handleChangeTheme(theme)}> + {theme.displayName} + + ))} + + + + ); +} + +export default ThemeChooserV9 \ No newline at end of file From 4c818055bfc9c59332fb311a8e9d29db2490ec41 Mon Sep 17 00:00:00 2001 From: Mnickii Date: Thu, 28 Nov 2024 11:06:16 +0100 Subject: [PATCH 2/8] revert loadGETheme removal for v8 components --- .../views/main-header/settings/ThemeChooserV9.tsx | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/app/views/main-header/settings/ThemeChooserV9.tsx b/src/app/views/main-header/settings/ThemeChooserV9.tsx index 0d783ed324..5735d7e52d 100644 --- a/src/app/views/main-header/settings/ThemeChooserV9.tsx +++ b/src/app/views/main-header/settings/ThemeChooserV9.tsx @@ -3,6 +3,7 @@ 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 { BrightnessHighRegular, WeatherMoonFilled, CircleHalfFillFilled } from '@fluentui/react-icons'; const availableThemes = [ @@ -29,16 +30,10 @@ const ThemeChooserV9: React.FC> = () => { const handleChangeTheme = (selectedTheme: { key: string; displayName: string; icon: JSX.Element }) => { - const newTheme: string = selectedTheme?.key ?? ''; + const newTheme: string = selectedTheme.key; // Applies the theme to the Fluent UI components - switch (newTheme) { - case 'light': - return dispatch(changeTheme('light')); - case 'dark': - return dispatch(changeTheme('dark')); - case 'high-contrast': - return dispatch(changeTheme('high-contrast')); - } + dispatch(changeTheme(newTheme)); + loadGETheme(newTheme); //Remove when cleaning up telemetry.trackEvent(eventTypes.BUTTON_CLICK_EVENT, { ComponentName: componentNames.SELECT_THEME_BUTTON, SelectedTheme: newTheme.replace('-', ' ').toSentenceCase() From 7f546a9aa43ee2b1c6b2df48665b925aaa458f2f Mon Sep 17 00:00:00 2001 From: Mnickii Date: Thu, 28 Nov 2024 12:43:00 +0100 Subject: [PATCH 3/8] use customized radio Group --- .../main-header/settings/ThemeChooserV9.tsx | 58 +++++++++++++------ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/src/app/views/main-header/settings/ThemeChooserV9.tsx b/src/app/views/main-header/settings/ThemeChooserV9.tsx index 5735d7e52d..8d81829b4a 100644 --- a/src/app/views/main-header/settings/ThemeChooserV9.tsx +++ b/src/app/views/main-header/settings/ThemeChooserV9.tsx @@ -1,9 +1,10 @@ -import { Menu, MenuTrigger, MenuButton, MenuPopover, MenuList, MenuItem } from '@fluentui/react-components'; +import { makeStyles, shorthands, 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 } from '@fluentui/react-icons'; const availableThemes = [ @@ -24,9 +25,26 @@ const availableThemes = [ } ]; +const useIconOptionStyles = makeStyles({ + root: { + display: 'flex', + alignItems: 'center', + ...shorthands.gap('5px') + } +}); + +const useLabelStyles = makeStyles({ + root: { + display: 'flex', + ...shorthands.gap('5px') + } +}); + const ThemeChooserV9: React.FC> = () => { const dispatch = useAppDispatch(); const appTheme = useAppSelector(state=> state.theme); + const iconOptionStyles = useIconOptionStyles(); + const labelStyles = useLabelStyles(); const handleChangeTheme = (selectedTheme: { key: string; displayName: string; icon: JSX.Element }) => { @@ -40,23 +58,27 @@ const ThemeChooserV9: React.FC> = () => { }); }; return ( - - - theme.key === appTheme)?.icon}> - {availableThemes.find(theme => theme.key === appTheme)?.displayName} - - - - - - {availableThemes.map(theme => ( - handleChangeTheme(theme)}> - {theme.displayName} - - ))} - - - + theme.key === appTheme)?.displayName} + > + {availableThemes.map((theme) => ( +
+ + {theme.icon} {translateMessage(theme.displayName)} + + ) + }} + onClick={() => handleChangeTheme(theme)}> + +
+ ))} +
); } From 7dfd1483ef0bbd03645452b05a9be95ceb70badd Mon Sep 17 00:00:00 2001 From: Mnickii Date: Thu, 28 Nov 2024 13:00:51 +0100 Subject: [PATCH 4/8] adjusst icon size --- src/app/views/main-header/settings/ThemeChooserV9.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/app/views/main-header/settings/ThemeChooserV9.tsx b/src/app/views/main-header/settings/ThemeChooserV9.tsx index 8d81829b4a..3023660d25 100644 --- a/src/app/views/main-header/settings/ThemeChooserV9.tsx +++ b/src/app/views/main-header/settings/ThemeChooserV9.tsx @@ -1,4 +1,4 @@ -import { makeStyles, shorthands, RadioGroup, Radio} from '@fluentui/react-components'; +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'; @@ -29,14 +29,17 @@ const useIconOptionStyles = makeStyles({ root: { display: 'flex', alignItems: 'center', - ...shorthands.gap('5px') + gap: '5px' + }, + icon: { + fontSize: '30px' } }); const useLabelStyles = makeStyles({ root: { display: 'flex', - ...shorthands.gap('5px') + gap: '5px' } }); @@ -70,7 +73,7 @@ const ThemeChooserV9: React.FC> = () => { className: labelStyles.root, children: ( <> - {theme.icon} {translateMessage(theme.displayName)} + {theme.icon} {translateMessage(theme.displayName)} ) }} From f4aa8d5815092a2b35208f8a2d797f54bee6b475 Mon Sep 17 00:00:00 2001 From: Mnickii Date: Mon, 2 Dec 2024 11:11:55 +0100 Subject: [PATCH 5/8] remove checked --- src/app/views/main-header/settings/ThemeChooserV9.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/views/main-header/settings/ThemeChooserV9.tsx b/src/app/views/main-header/settings/ThemeChooserV9.tsx index 3023660d25..b52ccbdd02 100644 --- a/src/app/views/main-header/settings/ThemeChooserV9.tsx +++ b/src/app/views/main-header/settings/ThemeChooserV9.tsx @@ -68,7 +68,6 @@ const ThemeChooserV9: React.FC> = () => {
Date: Tue, 3 Dec 2024 11:31:36 +0100 Subject: [PATCH 6/8] detect system theme in theme-chooser and set as default --- .../views/main-header/settings/SettingsV9.tsx | 3 +- .../main-header/settings/ThemeChooserV9.tsx | 41 ++++++++++++++++--- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/app/views/main-header/settings/SettingsV9.tsx b/src/app/views/main-header/settings/SettingsV9.tsx index 711a6420fc..e46b91a396 100644 --- a/src/app/views/main-header/settings/SettingsV9.tsx +++ b/src/app/views/main-header/settings/SettingsV9.tsx @@ -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, { diff --git a/src/app/views/main-header/settings/ThemeChooserV9.tsx b/src/app/views/main-header/settings/ThemeChooserV9.tsx index b52ccbdd02..60af98d504 100644 --- a/src/app/views/main-header/settings/ThemeChooserV9.tsx +++ b/src/app/views/main-header/settings/ThemeChooserV9.tsx @@ -1,3 +1,4 @@ +import React, { useEffect } from 'react'; import { makeStyles, RadioGroup, Radio} from '@fluentui/react-components'; import { useAppDispatch, useAppSelector } from '../../../../store'; import { componentNames, eventTypes, telemetry } from '../../../../telemetry'; @@ -28,30 +29,56 @@ const availableThemes = [ const useIconOptionStyles = makeStyles({ root: { display: 'flex', - alignItems: 'center', - gap: '5px' + alignItems: 'center' }, icon: { fontSize: '30px' + }, + radio: { + '&:checked ~ .fui-Radio__indicator::after': { + borderRadius: '50%' + } } + }); const useLabelStyles = makeStyles({ root: { display: 'flex', - gap: '5px' + textAlign: 'center' + }, + container: { + display: 'block', + alignItems: 'center', + justifyContent: 'center' } }); +const getSystemTheme = (): string => { + if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { + return 'dark'; + } + return 'light'; +}; + const ThemeChooserV9: React.FC> = () => { 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 @@ -62,18 +89,20 @@ const ThemeChooserV9: React.FC> = () => { }; return ( theme.key === appTheme)?.displayName} + value={availableThemes.find(theme => theme.key === appTheme)?.displayName} > {availableThemes.map((theme) => (
+
{theme.icon} {translateMessage(theme.displayName)} - +
) }} onClick={() => handleChangeTheme(theme)}> From 21ba3c90bebd836c198459f9f19cb4fa76bfd92a Mon Sep 17 00:00:00 2001 From: Mnickii Date: Wed, 4 Dec 2024 13:50:42 +0100 Subject: [PATCH 7/8] include system theme appwise --- src/app/views/App.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/app/views/App.tsx b/src/app/views/App.tsx index ef6aaa4f24..9507742dbf 100644 --- a/src/app/views/App.tsx +++ b/src/app/views/App.tsx @@ -68,6 +68,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 { private mediaQueryList = window.matchMedia('(max-width: 992px)'); private currentTheme: ITheme = getTheme(); @@ -128,6 +135,12 @@ class App extends Component { // 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() { From 08411d8af01eac3f417b422c7bf1b98368fb8f47 Mon Sep 17 00:00:00 2001 From: Mnickii Date: Tue, 10 Dec 2024 11:18:49 +0100 Subject: [PATCH 8/8] add system to options --- src/app/views/App.tsx | 3 ++- .../main-header/settings/ThemeChooserV9.tsx | 27 ++++++++++++------- src/themes/index.ts | 10 ++++++- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/app/views/App.tsx b/src/app/views/App.tsx index e20d41b099..50fa9448a9 100644 --- a/src/app/views/App.tsx +++ b/src/app/views/App.tsx @@ -425,7 +425,8 @@ class App extends Component { const fluentV9Themes: Record = { 'light': webLightTheme, 'dark': webDarkTheme, - 'high-contrast': teamsHighContrastTheme + 'high-contrast': teamsHighContrastTheme, + 'system': getSystemTheme() === 'dark' ? webDarkTheme : webLightTheme } return ( // @ts-ignore diff --git a/src/app/views/main-header/settings/ThemeChooserV9.tsx b/src/app/views/main-header/settings/ThemeChooserV9.tsx index 60af98d504..0140a5ee4b 100644 --- a/src/app/views/main-header/settings/ThemeChooserV9.tsx +++ b/src/app/views/main-header/settings/ThemeChooserV9.tsx @@ -6,7 +6,7 @@ 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 } from '@fluentui/react-icons'; +import { BrightnessHighRegular, WeatherMoonFilled, CircleHalfFillFilled, SettingsFilled} from '@fluentui/react-icons'; const availableThemes = [ { @@ -23,6 +23,11 @@ const availableThemes = [ key: 'high-contrast', displayName: 'Teams High Contrast', icon: + }, + { + key: 'system', + displayName: 'System Default', + icon: } ]; @@ -32,7 +37,11 @@ const useIconOptionStyles = makeStyles({ alignItems: 'center' }, icon: { - fontSize: '30px' + fontSize: '30px', + display: 'block' + }, + name: { + display: 'block' }, radio: { '&:checked ~ .fui-Radio__indicator::after': { @@ -44,13 +53,10 @@ const useIconOptionStyles = makeStyles({ const useLabelStyles = makeStyles({ root: { - display: 'flex', - textAlign: 'center' - }, - container: { display: 'block', alignItems: 'center', - justifyContent: 'center' + justifyContent: 'center', + textAlign: 'center' } }); @@ -100,9 +106,10 @@ const ThemeChooserV9: React.FC> = () => { label={{ className: labelStyles.root, children: ( -
- {theme.icon} {translateMessage(theme.displayName)} -
+ <> +
{theme.icon}
+
{translateMessage(theme.displayName)}
+ ) }} onClick={() => handleChangeTheme(theme)}> diff --git a/src/themes/index.ts b/src/themes/index.ts index b7eacfa3eb..f3b8349a8f 100644 --- a/src/themes/index.ts +++ b/src/themes/index.ts @@ -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 {