diff --git a/Readme.md b/Readme.md index 3b6722b..80e9878 100644 --- a/Readme.md +++ b/Readme.md @@ -1,46 +1,100 @@ - -![](https://img.shields.io/endpoint?url=https://codecentral.devexpress.com/api/v1/VersionRange/227836631/25.2.2%2B) -[![](https://img.shields.io/badge/Open_in_DevExpress_Support_Center-FF7200?style=flat-square&logo=DevExpress&logoColor=white)](https://supportcenter.devexpress.com/ticket/details/T845557) -[![](https://img.shields.io/badge/📖_How_to_use_DevExpress_Examples-e9f6fc?style=flat-square)](https://docs.devexpress.com/GeneralInformation/403183) -[![](https://img.shields.io/badge/💬_Leave_Feedback-feecdd?style=flat-square)](#does-this-example-address-your-development-requirementsobjectives) - -# Implement a Theme Switcher in Blazor Applications +# Switch Themes and Size Modes in Blazor Applications at Runtime -This example demonstrates how to add a Theme Switcher to your application. Users can switch between DevExpress Fluent and Classic themes and external Bootstrap themes. This example uses the [DxResourceManager.RegisterTheme(ITheme)](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxResourceManager.RegisterTheme(DevExpress.Blazor.ITheme)) method to apply a theme at application startup and the [IThemeChangeService.SetTheme()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.IThemeChangeService.SetTheme(DevExpress.Blazor.ITheme)) method to change the theme at runtime. +This example adds a theme switcher to your Blazor application. Users can switch between DevExpress Fluent and Classic themes, and external Bootstrap themes. This example uses the [DxResourceManager.RegisterTheme(ITheme)](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxResourceManager.RegisterTheme(DevExpress.Blazor.ITheme)) method to apply a theme at application startup and the [IThemeChangeService.SetTheme()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.IThemeChangeService.SetTheme(DevExpress.Blazor.ITheme)) method to change the theme at runtime. -![Blazor - Theme Switcher](images/blazor-theme-switcher.png) + +This example also implements a size mode combobox that allows users to switch between small, medium, and large [size modes](https://docs.devexpress.com/Blazor/401784/styling-and-themes/size-modes). + +![Blazor - Theme and Size Mode Switchers](images/blazor-theme-and-size-mode-switcher.png) + +## Add Resources and Services + +To switch themes and size modes at runtime, configure your Blazor application as follows: + + +1. Copy the example [switcher-resources](./CS/switcher/switcher/wwwroot/switcher-resources) folder to your application *wwwroot* folder. The *switcher-resources* folder has the following structure: + + * **js/cookies-manager.js** + Contains a function that stores the theme in a cookie variable. + * **js/size-manager.js** + Contains a function that assigns selected size mode to the `--global-size` CSS variable. + * **theme-switcher.css** + Contains CSS rules that define theme switcher appearance and behavior. + +2. Add the following services to your application (copy the corresponding files from the [Services](./CS/switcher/switcher/Services) folder): + + * [ThemesService.cs](./CS/switcher/switcher/Services/ThemesService.cs) + Implements the [IThemeChangeService](https://docs.devexpress.com/Blazor/DevExpress.Blazor.IThemeChangeService) interface to switch themes at runtime and uses the [SetTheme()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.IThemeChangeService.SetTheme(DevExpress.Blazor.ITheme)) method to apply the selected theme. Supports custom accent colors for Fluent themes. + * [Themes.cs](./CS/switcher/switcher/Services/Themes.cs) + Creates a list of themes for the theme switcher via the built-in DevExpress Blazor [Themes](https://docs.devexpress.com/Blazor/DevExpress.Blazor.Themes) collection and the [Clone()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxThemeBase-1.Clone(System.Action--0-)) method. + * [CookiesService.cs](./CS/switcher/switcher/Services/CookiesService.cs) + Manages cookies. + * [SizeManager.cs](./CS/switcher/switcher/Services/SizeManager.cs) *(Optional)* + Manages application [size mode](https://docs.devexpress.com/Blazor/401784/styling-and-themes/size-modes) (small, medium, or large). + +3. In the [_Imports.razor](./CS/switcher/switcher/Components/_Imports.razor) file, register `{ProjectName}.Components.ThemeSwitcher` and `{ProjectName}.Services` namespaces: + + ```razor + @using {ProjectName}.Components.ThemeSwitcher + @using {ProjectName}.Services + ``` + +4. Register services in the [Program.cs](./CS/switcher/switcher/Program.cs) file: + + ```cs + builder.Services.AddDevExpressBlazor(); + builder.Services.AddMvc(); + builder.Services.AddHttpContextAccessor(); + builder.Services.AddScoped(); + builder.Services.AddTransient(); + builder.Services.AddScoped(); + ``` ## Configure Available Themes The theme switcher includes the following themes: -* DevExpress Fluent (Light Blue and Dark Blue) +* DevExpress Fluent (Light/Dark with custom accent color support) * DevExpress Classic (Blazing Berry, Blazing Dark, Purple, and Office White) * [Bootstrap External](https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css) +Create a [Themes.cs](./CS/switcher/switcher/Services/Themes.cs) file and configure themes: -Create a `Themes.cs` file and configure themes: - - -1. For Classic themes, choose a theme from the built-in DevExpress Blazor [Themes](https://docs.devexpress.com/Blazor/DevExpress.Blazor.Themes) collection: +1. For Classic themes, choose a theme from the built-in DevExpress Blazor [Themes](https://docs.devexpress.com/Blazor/DevExpress.Blazor.Themes) collection and add custom stylesheets (using the [Clone()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxThemeBase-1.Clone(System.Action--0-)) method): ```cs - public static readonly ITheme BlazingBerry = Themes.BlazingBerry; - public static readonly ITheme BlazingDark = Themes.BlazingDark; - public static readonly ITheme Purple = Themes.Purple; - public static readonly ITheme OfficeWhite = Themes.OfficeWhite; + public static readonly ITheme BlazingBerry = Themes.BlazingBerry.Clone(props => { + props.AddFilePaths("css/theme-bs.css"); + }); + public static readonly ITheme BlazingDark = Themes.BlazingDark.Clone(props => { + props.AddFilePaths("css/theme-bs.css"); + }); + public static readonly ITheme Purple = Themes.Purple.Clone(props => { + props.AddFilePaths("css/theme-bs.css"); + }); + public static readonly ITheme OfficeWhite = Themes.OfficeWhite.Clone(props => { + props.AddFilePaths("css/theme-bs.css"); + }); ``` 1. For Fluent themes, call the [Clone()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxThemeBase-1.Clone(System.Action--0-)) method to add theme stylesheets and change theme mode: ```cs - public static readonly ITheme FluentLight = Themes.Fluent.Clone(props => { - props.AddFilePaths("css/theme-fluent.css"); - }); - public static readonly ITheme FluentDark = Themes.Fluent.Clone(props => { - props.Mode = ThemeMode.Dark; - props.AddFilePaths("css/theme-fluent.css"); - }); + public static ITheme FluentLight(string? accent = null) { + return Themes.Fluent.Clone(props => { + props.Name = "FluentLight" + accent?.PadLeft(8); + props.SetCustomAccentColor(accent); + props.AddFilePaths("css/theme-fluent.css"); + }); + } + public static ITheme FluentDark(string? accent = null) { + return Themes.Fluent.Clone(props => { + props.Name = "FluentDark" + accent?.PadLeft(8); + props.SetCustomAccentColor(accent); + props.Mode = ThemeMode.Dark; + props.AddFilePaths("css/theme-fluent.css"); + }); + } ``` 1. For Bootstrap themes, call the [Clone()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxThemeBase-1.Clone(System.Action--0-)) method to add a Bootstrap theme stylesheet. Use the same approach if you want to apply your own stylesheets. @@ -56,62 +110,72 @@ Create a `Themes.cs` file and configure themes: ```cs public enum MyTheme { - Fluent_Light, - Fluent_Dark, + FluentLight, + FluentDark, - Blazing_Berry, - Blazing_Dark, + BlazingBerry, + BlazingDark, Purple, - Office_White, + OfficeWhite, Bootstrap } ``` -## Add a Theme Switcher to an Application +### Use Custom Accent Colors in Fluent Themes -Follow the steps below to add a Theme Switcher to your application: +The theme switcher allows you to apply a Fluent theme with a custom accent color as follows: -1. Copy this example's [ThemeSwitcher](./CS/switcher/switcher/Components/ThemeSwitcher) folder to your project. +* A masked input field used to enter hex color values +* A color picker for visual color selection -2. Copy the example's [switcher-resources](./CS/switcher/switcher/wwwroot/switcher-resources) folder to your application's *wwwroot* folder. The *switcher-resources* folder has the following structure: +The theme is applied automatically when a user selects the color. - * **js/cookies-manager.js** - Contains a function that stores the theme in a cookie variable. - * **theme-switcher.css** - Contains CSS rules that define the Theme Switcher's appearance and behavior. +Review implementation details in the [ThemeSwitcherContainer.razor](./CS/switcher/switcher/Components/ThemeSwitcher/ThemeSwitcherContainer.razor) file. -3. Add the following services to your application (copy the corresponding files): +### Add Custom Stylesheets to the Application (Apply Styles to Non-DevExpress UI Elements) - * [ThemeService.cs](./CS/switcher/switcher/Services/ThemesService.cs) - Implements [IThemeChangeService](https://docs.devexpress.com/Blazor/DevExpress.Blazor.IThemeChangeService) to switch themes at runtime and uses the [SetTheme()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.IThemeChangeService.SetTheme(DevExpress.Blazor.ITheme)) method to apply the selected theme. - * [Themes.cs](./CS/switcher/switcher/Services/Themes.cs) - Creates a list of themes for the theme switcher using the built-in DevExpres Blazor [Themes](https://docs.devexpress.com/Blazor/DevExpress.Blazor.Themes) collection (for Classic themes) and the [Clone()](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxThemeBase-1.Clone(System.Action--0-)) method for Fluent and Bootstrap themes. - * [CookiesService.cs](./CS/switcher/switcher/Services/CookiesService.cs) - Manages cookies. +Our DevExpress Blazor themes affect DevExpress components only. To apply theme-specific styles to non-DevExpress elements or the entire application, add external stylesheets to the theme using its `AddFilePaths()` method: -2. In the [_Imports.razor](./CS/switcher/switcher/Components/_Imports.razor) file, import `{ProjectName}.Components.ThemeSwitcher` and `{ProjectName}.Services` namespaces: +> Bootstrap themes require external theme-specific stylesheets. Once you register a Bootstrap theme, call the `Clone()` method and add the stylesheet using theme properties. - ```cs - @using {ProjectName}.Components.ThemeSwitcher - @using {ProjectName}.Services - ``` +```cs +public static readonly ITheme BootstrapDefault = Themes.BootstrapExternal.Clone(props => { + props.Name = "Bootstrap"; + // Links a Bootstrap theme stylesheet + props.AddFilePaths("https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"); + // Links a custom stylesheet + props.AddFilePaths("css/theme-bs.css"); +}); +``` -5. Register `ThemesService` and `CookiesService` in the [Program.cs](./CS/switcher/switcher/Program.cs#L13-L16) file. Ensure that this file also contains `Mvc` and `HttpContextAccessor` services: +### Change Bootstrap Theme Color Modes - ```cs - builder.Services.AddMvc(); - builder.Services.AddHttpContextAccessor(); - builder.Services.AddScoped(); - builder.Services.AddTransient(); - ``` +If you want to use dark Bootstrap themes, apply a `data-bs-theme` attribute to the root `` element: + +* `data-bs-theme="light"` for light themes +* `data-bs-theme="dark"` for dark themes + +Refer to the following article for more information: [Color Modes](https://getbootstrap.com/docs/5.3/customize/color-modes/). + +## Add a Theme Switcher to Your Application -6. Add the following code to the [App.razor](./CS/switcher/switcher/Components/App.razor) file: +Follow the steps below to add a theme switcher to your application: + +1. Copy the [ThemeSwitcher](./CS/switcher/switcher/Components/ThemeSwitcher) folder to your project. The folder contains: + * [ThemeSwitcher.razor](./CS/switcher/switcher/Components/ThemeSwitcher/ThemeSwitcher.razor) - The theme switcher button. + * [ThemeSwitcherContainer.razor](./CS/switcher/switcher/Components/ThemeSwitcher/ThemeSwitcherContainer.razor) - The theme selection panel with all available themes. + * [ThemeSwitcherItem.razor](./CS/switcher/switcher/Components/ThemeSwitcher/ThemeSwitcherItem.razor) - An individual theme item. + +2. Add the following code to the [Components/App.razor](./CS/switcher/switcher/Components/App.razor) file: * Inject services with the [[Inject] attribute](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.injectattribute): - ```html + ```razor + @using Microsoft.AspNetCore.Mvc.ViewFeatures + @using DevExpress.Blazor @inject IHttpContextAccessor HttpContextAccessor + @inject IFileVersionProvider FileVersionProvider @inject ThemesService ThemesService ``` @@ -123,8 +187,10 @@ Follow the steps below to add a Theme Switcher to your application: - @DxResourceManager.RegisterTheme(InitialTheme) - @* ... *@ + @DxResourceManager.RegisterTheme(Theme) + + + ``` @@ -132,50 +198,62 @@ Follow the steps below to add a Theme Switcher to your application: ```razor @code { - private ITheme InitialTheme; + private ITheme Theme; + private string AppendVersion(string path) => FileVersionProvider.AddFileVersionToPath("/", path); + protected override void OnInitialized() { - InitialTheme = ThemesService.GetThemeFromCookies(HttpContextAccessor); + Theme = ThemesService.GetThemeFromCookies(HttpContextAccessor); } } ``` -7. Declare the Theme Switcher component in the [MainLayout.razor](./CS/switcher/switcher/Components/Layout/MainLayout.razor#L22) file: +3. Declare the theme switcher component in the [MainLayout.razor](./CS/switcher/switcher/Components/Layout/MainLayout.razor) file: ```razor - - @* ... *@ - - @* ... *@ - - ``` + + ``` -## Add Stylesheets to a Theme (Apply Styles to Non-DevExpress UI Elements) +## Add a Size Mode Switcher +To change size modes at runtime, you must: -Our DevExpress Blazor themes affect DevExpress components only. To apply theme-specific styles to non-DevExpress elements or the entire application, add external stylesheets to the theme using its `AddFilePaths()` method: +1. Copy the [SizeChanger.razor](/CS/switcher/switcher/Components/Layout/SizeChanger.razor) file to the [Components/Layout](/CS/switcher/switcher/Components/Layout/) folder. This file creates a size mode menu and injects the [SizeManager](./CS/switcher/switcher/Services/SizeManager.cs) service. +2. Reference the [size-manager.js](./CS/switcher/switcher/wwwroot/switcher-resources/js/size-manager.js) script in the `` section of the [App.razor](./CS/switcher/switcher/Components/App.razor) file: -> Bootstrap themes require external theme-specific stylesheets. Once you register a Bootstrap theme, call the `Clone()` method and add the stylesheet using theme properties. - - -```cs -public static readonly ITheme BootstrapDefault = Themes.BootstrapExternal.Clone(props => { - props.Name = "Bootstrap"; - // Links a Bootstrap theme stylesheet - props.AddFilePaths("https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"); - // Links a custom stylesheet - props.AddFilePaths("css/theme-bs.css"); -}); -``` + ```html + + @* ... *@ + + @* ... *@ + + ``` -## Change Bootstrap Theme Color Modes +4. Use the `--global-size` CSS variable to define the font size application-wide: -If you want to use dark Bootstrap themes, implement custom logic that applies a `data-bs-theme` attribute to the root element: + ```css + html, body { + /* ... */ + font-size: var(--global-size); + } + ``` -* `data-bs-theme="light"` for light themes -* `data-bs-theme="dark"` for dark themes +5. Declare the size mode switcher component in the [MainLayout.razor](./CS/switcher/switcher/Components/Layout/MainLayout.razor) file: -Refer to the following article for more information: [Color Modes](https://getbootstrap.com/docs/5.3/customize/color-modes/). + ```razor + + ``` ## Files to Review @@ -189,10 +267,14 @@ Refer to the following article for more information: [Color Modes](https://getbo ## Documentation * [Themes](https://docs.devexpress.com/Blazor/401523/common-concepts/themes) +* [Fluent Theme Customization (Accent Colors)](https://docs.devexpress.com/Blazor/405530/styling-and-themes/fluent-theme-customization) +* [Size Modes](https://docs.devexpress.com/Blazor/401784/styling-and-themes/size-modes) + -## Does this example address your development requirements/objectives? - -[](https://www.devexpress.com/support/examples/survey.xml?utm_source=github&utm_campaign=blazor-theme-switcher&~~~was_helpful=yes) [](https://www.devexpress.com/support/examples/survey.xml?utm_source=github&utm_campaign=blazor-theme-switcher&~~~was_helpful=no) - +## Does this example address your development requirements/objectives? + +[](https://www.devexpress.com/support/examples/survey.xml?utm_source=github&utm_campaign=blazor-theme-switcher&~~~was_helpful=yes) [](https://www.devexpress.com/support/examples/survey.xml?utm_source=github&utm_campaign=blazor-theme-switcher&~~~was_helpful=no) + (you will be redirected to DevExpress.com to submit your response) + diff --git a/images/blazor-theme-and-size-mode-switcher.png b/images/blazor-theme-and-size-mode-switcher.png new file mode 100644 index 0000000..ef66d85 Binary files /dev/null and b/images/blazor-theme-and-size-mode-switcher.png differ diff --git a/images/blazor-theme-switcher.png b/images/blazor-theme-switcher.png deleted file mode 100644 index ab931f9..0000000 Binary files a/images/blazor-theme-switcher.png and /dev/null differ