Skip to content

Commit 27bd112

Browse files
authored
[dev-v5] Refactoring Theme TS classes (#3814)
* Update Theme and add body attributes * Update media
1 parent bfa2842 commit 27bd112

File tree

3 files changed

+134
-57
lines changed

3 files changed

+134
-57
lines changed
Lines changed: 1 addition & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as FluentUIComponents from '@fluentui/web-components'
2-
import { webLightTheme, webDarkTheme, BrandVariants, Theme, createDarkTheme, createLightTheme } from '@fluentui/tokens';
3-
import { setTheme } from '@fluentui/web-components';
2+
import * as Theme from './Utilities/Theme'
43

54
export namespace Microsoft.FluentUI.Blazor.FluentUIWebComponents {
65

@@ -57,58 +56,4 @@ export namespace Microsoft.FluentUI.Blazor.FluentUIWebComponents {
5756
FluentUIComponents.TreeDefinition.define(registry);
5857
FluentUIComponents.TreeItemDefinition.define(registry);
5958
}
60-
61-
/**
62-
* Initialize the FluentUI Theme
63-
*/
64-
export function initializeTheme(blazor: Blazor) {
65-
66-
const themeColorVariants: BrandVariants = {
67-
10: "#050205",
68-
20: "#231121",
69-
30: "#3C183A",
70-
40: "#511C4E",
71-
50: "#661F63",
72-
60: "#7D2279",
73-
70: "#94248F",
74-
80: "#AA28A5",
75-
90: "#B443AE",
76-
100: "#BD59B6",
77-
110: "#C66EBF",
78-
120: "#CF82C7",
79-
130: "#D795D0",
80-
140: "#DFA8D9",
81-
150: "#E7BBE1",
82-
160: "#EECEEA"
83-
};
84-
85-
const lightTheme: Theme = {
86-
...createLightTheme(themeColorVariants),
87-
};
88-
89-
const darkTheme: Theme = {
90-
...createDarkTheme(themeColorVariants),
91-
};
92-
93-
setTheme(webLightTheme);
94-
95-
blazor.theme = {
96-
isSystemDark: () => {
97-
return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
98-
},
99-
100-
isDarkMode: () => {
101-
const luminance: string = getComputedStyle(document.documentElement).getPropertyValue('--base-layer-luminance');
102-
return parseFloat(luminance) < 0.5;
103-
},
104-
105-
setLightTheme: () => {
106-
setTheme(webLightTheme);
107-
},
108-
109-
setDarkTheme: () => {
110-
setTheme(webDarkTheme);
111-
}
112-
}
113-
}
11459
}

src/Core.Scripts/src/Startup.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Microsoft as LoggerFile } from './Utilities/Logger';
2+
import { Microsoft as ThemeFile } from './Utilities/Theme';
23
import { Microsoft as FluentUIComponentsFile } from './FluentUIWebComponents';
34
import { Microsoft as FluentPageScriptFile } from './Components/PageScript/FluentPageScript';
45
import { Microsoft as FluentUIStylesFile } from './FluentUIStyles';
@@ -42,7 +43,14 @@ export namespace Microsoft.FluentUI.Blazor.Startup {
4243
FluentUIStyles.applyStyles();
4344

4445
// Initialize Fluent UI theme
45-
FluentUIComponents.initializeTheme(blazor);
46+
blazor.theme = ThemeFile.FluentUI.Blazor.Utilities.Theme;
47+
ThemeFile.FluentUI.Blazor.Utilities.Theme.addMediaQueriesListener();
48+
if (blazor.theme.isSystemDark()) {
49+
blazor.theme.setDarkTheme();
50+
}
51+
else {
52+
blazor.theme.setLightTheme();
53+
}
4654

4755
// Initialize all custom components
4856
FluentPageScript.registerComponent(blazor, mode);
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import { webLightTheme, webDarkTheme, BrandVariants, Theme, createDarkTheme, createLightTheme } from '@fluentui/tokens';
2+
import { setTheme } from '@fluentui/web-components';
3+
4+
export namespace Microsoft.FluentUI.Blazor.Utilities.Theme {
5+
6+
const themeColorVariants: BrandVariants = {
7+
10: "#050205",
8+
20: "#231121",
9+
30: "#3C183A",
10+
40: "#511C4E",
11+
50: "#661F63",
12+
60: "#7D2279",
13+
70: "#94248F",
14+
80: "#AA28A5",
15+
90: "#B443AE",
16+
100: "#BD59B6",
17+
110: "#C66EBF",
18+
120: "#CF82C7",
19+
130: "#D795D0",
20+
140: "#DFA8D9",
21+
150: "#E7BBE1",
22+
160: "#EECEEA"
23+
};
24+
25+
const lightTheme: Theme = {
26+
...createLightTheme(themeColorVariants),
27+
};
28+
29+
const darkTheme: Theme = {
30+
...createDarkTheme(themeColorVariants),
31+
};
32+
33+
/**
34+
* Returns true if the browser is in dark mode
35+
* @returns
36+
*/
37+
export function isSystemDark(): boolean {
38+
return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
39+
}
40+
41+
/**
42+
* Returns true if the current FluentUI theme is dark mode
43+
* @returns
44+
*/
45+
export function isDarkMode(): boolean {
46+
const luminance: string = getComputedStyle(document.documentElement).getPropertyValue('--base-layer-luminance');
47+
return parseFloat(luminance) < 0.5;
48+
}
49+
50+
/**
51+
* Sets the FluentUI theme to light mode
52+
*/
53+
export function setLightTheme(): void {
54+
setTheme(webLightTheme);
55+
updateBodyTag(false);
56+
}
57+
58+
/**
59+
* Sets the FluentUI theme to dark mode
60+
*/
61+
export function setDarkTheme(): void {
62+
setTheme(webDarkTheme);
63+
updateBodyTag(true);
64+
}
65+
66+
/**
67+
* Adds a listener for media queries to the window object
68+
* to update the body `data-media` attribute with the current media query
69+
*/
70+
export function addMediaQueriesListener(): void {
71+
72+
// Check if the media queries listener is already added
73+
if ((window as any).__fluentuiBlazorMediaQueriesListener) {
74+
return;
75+
}
76+
(window as any).__fluentuiBlazorMediaQueriesListener = true;
77+
78+
// List of media queries to listen to
79+
const getMediaQueries = (): { id: string, query: string }[] => {
80+
return [
81+
{ id: 'xs', query: '(max-width: 599.98px)' },
82+
{ id: 'sm', query: '(min-width: 600px) and (max-width: 959.98px)' },
83+
{ id: 'md', query: '(min-width: 960px) and (max-width: 1279.98px)' },
84+
{ id: 'lg', query: '(min-width: 1280px) and (max-width: 1919.98px)' },
85+
{ id: 'xl', query: '(min-width: 1920px) and (max-width: 2559.98px)' },
86+
{ id: 'xxl', query: '(min-width: 2560px)' },
87+
];
88+
}
89+
90+
// Set the initial data-media attribute based on the current matching media query
91+
const bodyTag: HTMLElement = document?.body;
92+
if (bodyTag) {
93+
const matched = getMediaQueries().find(mq => window.matchMedia(mq.query).matches);
94+
if (matched) {
95+
bodyTag.setAttribute('data-media', matched.id);
96+
}
97+
}
98+
99+
// Add event listeners for each media query
100+
getMediaQueries().forEach((mediaQuery) => {
101+
window.matchMedia(mediaQuery.query).addEventListener('change', media => {
102+
if (media.matches) {
103+
const bodyTag: HTMLElement = document?.body;
104+
if (bodyTag && bodyTag.getAttribute('data-media') !== mediaQuery.id) {
105+
bodyTag.setAttribute('data-media', mediaQuery.id);
106+
}
107+
}
108+
});
109+
});
110+
}
111+
112+
// Update the body tag to set the data-theme attribute
113+
function updateBodyTag(isDark: boolean): void {
114+
const bodyTag: HTMLElement = document?.body;
115+
116+
if (bodyTag) {
117+
if (isDark) {
118+
bodyTag.setAttribute('data-theme', 'dark');
119+
} else {
120+
bodyTag.removeAttribute('data-theme');
121+
}
122+
}
123+
}
124+
}

0 commit comments

Comments
 (0)