MudBlazor.ThemeManager.Saver
1.0.1
dotnet add package MudBlazor.ThemeManager.Saver --version 1.0.1
NuGet\Install-Package MudBlazor.ThemeManager.Saver -Version 1.0.1
<PackageReference Include="MudBlazor.ThemeManager.Saver" Version="1.0.1" />
<PackageVersion Include="MudBlazor.ThemeManager.Saver" Version="1.0.1" />
<PackageReference Include="MudBlazor.ThemeManager.Saver" />
paket add MudBlazor.ThemeManager.Saver --version 1.0.1
#r "nuget: MudBlazor.ThemeManager.Saver, 1.0.1"
#addin nuget:?package=MudBlazor.ThemeManager.Saver&version=1.0.1
#tool nuget:?package=MudBlazor.ThemeManager.Saver&version=1.0.1
MudBlazor ThemeManager Saver - Theme Saving Guide
<p align="center"> <img src="MudBlazor.ThemeManager.Saver.webp" alt="MudBlazor Theme Manager Saver" style="max-width: 100%; height: auto;"> </p>
<p align="center"> <a href="https://github.com/YOUR-USERNAME/MudBlazor.ThemeManager.Saver/actions"> <img src="https://github.com/YOUR-USERNAME/MudBlazor.ThemeManager.Saver/workflows/CI/badge.svg" alt="GitHub Workflow Status"> </a> <a href="https://codecov.io/gh/YOUR-USERNAME/MudBlazor.ThemeManager.Saver"> <img src="https://codecov.io/gh/YOUR-USERNAME/MudBlazor.ThemeManager.Saver/branch/main/graph/badge.svg" alt="Codecov"> </a> <a href="https://sonarcloud.io/dashboard?id=YOUR-USERNAME_MudBlazor.ThemeManager.Saver"> <img src="https://sonarcloud.io/api/project_badges/measure?project=YOUR-USERNAME_MudBlazor.ThemeManager.Saver&metric=alert_status" alt="Quality Gate Status"> </a> <a href="https://github.com/YOUR-USERNAME/MudBlazor.ThemeManager.Saver/blob/main/LICENSE"> <img src="https://img.shields.io/github/license/YOUR-USERNAME/MudBlazor.ThemeManager.Saver" alt="GitHub License"> </a> <a href="https://github.com/YOUR-USERNAME/MudBlazor.ThemeManager.Saver/stargazers"> <img src="https://img.shields.io/github/stars/YOUR-USERNAME/MudBlazor.ThemeManager.Saver" alt="GitHub Repo stars"> </a> <a href="https://github.com/YOUR-USERNAME/MudBlazor.ThemeManager.Saver/commits/main"> <img src="https://img.shields.io/github/last-commit/YOUR-USERNAME/MudBlazor.ThemeManager.Saver" alt="GitHub last commit"> </a> <a href="https://github.com/YOUR-USERNAME/MudBlazor.ThemeManager.Saver/graphs/contributors"> <img src="https://img.shields.io/github/contributors/YOUR-USERNAME/MudBlazor.ThemeManager.Saver" alt="Contributors"> </a> <a href="https://github.com/YOUR-USERNAME/MudBlazor.ThemeManager.Saver/discussions"> <img src="https://img.shields.io/github/discussions/YOUR-USERNAME/MudBlazor.ThemeManager.Saver" alt="Discussions"> </a> <a href="https://discord.gg/mudblazor"> <img src="https://img.shields.io/discord/786656789310865418?color=%237289da&label=Discord&logo=discord&logoColor=%23fff" alt="Discord"> </a> <a href="https://twitter.com/MudBlazor"> <img src="https://img.shields.io/twitter/follow/MudBlazor?style=social" alt="Twitter"> </a> <a href="https://www.nuget.org/packages/MudBlazor.ThemeManager.Saver/"> <img src="https://img.shields.io/nuget/v/MudBlazor.ThemeManager.Saver.svg" alt="NuGet version"> </a> <a href="https://www.nuget.org/packages/MudBlazor.ThemeManager.Saver/"> <img src="https://img.shields.io/nuget/dt/MudBlazor.ThemeManager.Saver.svg" alt="NuGet downloads"> </a> </p>
Enhanced Fork: This project is an enhanced fork of the original MudBlazor ThemeManager with additional theme saving and persistence capabilities.
Overview
MudBlazor ThemeManager Saver is a powerful component that allows you to design, customize, save, and manage themes for MudBlazor applications. This enhanced version focuses on theme saving and persistence functionality.
Current Theme Management Features
The MudThemeManager
component provides comprehensive theme customization through the ThemeManagerTheme
model, which includes:
Theme Properties
- Theme Colors: Primary, Secondary, Tertiary, Info, Success, Warning, Error, Dark, Surface
- Component Colors: AppBar, Drawer, Background, Text colors
- Typography: Font family selection (Roboto, Montserrat, Ubuntu, Segoe UI)
- Layout Settings: Border radius, elevations, drawer clip modes
- Dark/Light Mode: Full palette support for both modes
Current Implementation
The theme state is managed through the UpdatePalette
method which:
public Task UpdatePalette(ThemeUpdatedValue value)
{
// Updates both theme palette and local palette objects
// Supports both light and dark mode palettes
// Triggers theme change events
}
Theme Saving Implementation Guide
1. JSON Serialization
To save themes, you can serialize the ThemeManagerTheme
object:
// Save theme to JSON
public string SaveThemeToJson(ThemeManagerTheme theme)
{
var options = new JsonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
return JsonSerializer.Serialize(theme, options);
}
// Load theme from JSON
public ThemeManagerTheme LoadThemeFromJson(string json)
{
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
return JsonSerializer.Deserialize<ThemeManagerTheme>(json, options) ?? new ThemeManagerTheme();
}
2. Local Storage Integration
For browser-based persistence:
@inject IJSRuntime JSRuntime
// Save to localStorage
public async Task SaveThemeToLocalStorage(ThemeManagerTheme theme)
{
var json = SaveThemeToJson(theme);
await JSRuntime.InvokeVoidAsync("localStorage.setItem", "mudblazor-theme", json);
}
// Load from localStorage
public async Task<ThemeManagerTheme> LoadThemeFromLocalStorage()
{
var json = await JSRuntime.InvokeAsync<string>("localStorage.getItem", "mudblazor-theme");
return string.IsNullOrEmpty(json) ? new ThemeManagerTheme() : LoadThemeFromJson(json);
}
3. File System Persistence
For server-side or desktop applications:
// Save theme to file
public async Task SaveThemeToFile(ThemeManagerTheme theme, string filePath)
{
var json = SaveThemeToJson(theme);
await File.WriteAllTextAsync(filePath, json);
}
// Load theme from file
public async Task<ThemeManagerTheme> LoadThemeFromFile(string filePath)
{
if (!File.Exists(filePath))
return new ThemeManagerTheme();
var json = await File.ReadAllTextAsync(filePath);
return LoadThemeFromJson(json);
}
4. JSON File Persistence Service
For applications that need to persist themes as JSON files in the wwwroot folder:
using Microsoft.AspNetCore.Hosting;
using MudBlazor.ThemeManager.Saver;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
public class ThemePersistenceService
{
private readonly IWebHostEnvironment _webHostEnvironment;
private const string ThemeFileName = "theme.json";
public ThemePersistenceService(IWebHostEnvironment webHostEnvironment)
{
_webHostEnvironment = webHostEnvironment;
}
private string GetThemeFilePath()
{
return Path.Combine(_webHostEnvironment.WebRootPath, ThemeFileName);
}
public async Task SaveThemeAsync(ThemeManagerTheme themeManagerTheme, bool isDarkMode)
{
var themeData = new PersistedThemeData
{
ThemeManagerTheme = themeManagerTheme,
IsDarkMode = isDarkMode
};
var jsonTheme = JsonSerializer.Serialize(themeData, new JsonSerializerOptions { WriteIndented = true });
var filePath = GetThemeFilePath();
await File.WriteAllTextAsync(filePath, jsonTheme);
}
public async Task<PersistedThemeData?> LoadThemeAsync()
{
var filePath = GetThemeFilePath();
if (File.Exists(filePath))
{
var jsonTheme = await File.ReadAllTextAsync(filePath);
if (!string.IsNullOrEmpty(jsonTheme))
{
try
{
var themeData = JsonSerializer.Deserialize<PersistedThemeData>(jsonTheme);
return themeData;
}
catch (JsonException)
{
// Handle deserialization error, e.g., corrupted data
// Optionally, log this error
return null;
}
}
}
return null;
}
}
public class PersistedThemeData
{
public ThemeManagerTheme ThemeManagerTheme { get; set; } = new();
public bool IsDarkMode { get; set; }
}
Register the service in your Program.cs
:
builder.Services.AddScoped<ThemePersistenceService>();
5. Integration with MainLayout
Update your MainLayout:
@inject IJSRuntime JSRuntime
<MudThemeProvider @ref="_mudThemeProvider" Theme="_themeManager.Theme" @bind-IsDarkMode="@_isDarkMode" />
<MudThemeManager
Open="_themeManagerOpen"
OpenChanged="OpenThemeManager"
Theme="_themeManager"
ThemeChanged="UpdateAndSaveTheme"
IsDarkMode="@_isDarkMode" />
@code {
private ThemeManagerTheme _themeManager = new();
private bool _themeManagerOpen;
private bool _isDarkMode;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await LoadSavedTheme();
_isDarkMode = await _mudThemeProvider.GetSystemPreference();
StateHasChanged();
}
}
private async Task UpdateAndSaveTheme(ThemeManagerTheme theme)
{
_themeManager = theme;
await SaveThemeToLocalStorage(theme);
StateHasChanged();
}
private async Task LoadSavedTheme()
{
try
{
var savedTheme = await LoadThemeFromLocalStorage();
if (savedTheme != null)
{
_themeManager = savedTheme;
}
}
catch (Exception ex)
{
// Handle loading errors
Console.WriteLine($"Error loading saved theme: {ex.Message}");
}
}
}
6. MainLayout with JSON File Persistence Service
For applications using the JSON file persistence service:
@using YourApplication.Services
@inherits LayoutComponentBase
@inject IJSRuntime JSRuntime
@inject ThemePersistenceService ThemePersistenceService
<MudThemeProvider @ref="@_mudThemeProvider" Theme="_themeManager.Theme" @bind-IsDarkMode="@_isDarkMode" />
<MudPopoverProvider />
<MudDialogProvider />
<MudSnackbarProvider />
<MudLayout>
<MudAppBar Elevation="_themeManager.AppBarElevation">
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@((e) => DrawerToggle())" />
<MudSpacer />
<MudIconButton Icon="@Icons.Material.Filled.DarkMode" Color="Color.Inherit" OnClick="@((e) => DarkModeToggleAsync())" Edge="Edge.End" />
</MudAppBar>
<MudDrawer @bind-Open="_drawerOpen" ClipMode="_themeManager.DrawerClipMode" Elevation="_themeManager.DrawerElevation">
<NavMenu />
</MudDrawer>
<MudMainContent>
<MudContainer MaxWidth="MaxWidth.False" Class="mt-16 px-16">
@Body
</MudContainer>
</MudMainContent>
<MudThemeManagerButton OnClick="@((e) => OpenThemeManager(true))" />
<MudThemeManager @key="_themeManager" Open="_themeManagerOpen" OpenChanged="OpenThemeManager" Theme="_themeManager" ThemeChanged="UpdateThemeAsync" IsDarkMode="@_isDarkMode" />
</MudLayout>
@code {
private ThemeManagerTheme _themeManager = new();
private MudThemeProvider _mudThemeProvider;
private bool _isDarkMode;
private bool _drawerOpen = true;
private bool _themeManagerOpen;
private void DrawerToggle()
{
_drawerOpen = !_drawerOpen;
}
private void OpenThemeManager(bool value)
{
_themeManagerOpen = value;
}
private async Task DarkModeToggleAsync()
{
_isDarkMode = !_isDarkMode;
await ThemePersistenceService.SaveThemeAsync(_themeManager, _isDarkMode);
StateHasChanged();
}
private async Task UpdateThemeAsync(ThemeManagerTheme value)
{
_themeManager = value;
await ThemePersistenceService.SaveThemeAsync(_themeManager, _isDarkMode);
StateHasChanged();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var persistedTheme = await ThemePersistenceService.LoadThemeAsync();
if (persistedTheme != null)
{
_themeManager = persistedTheme.ThemeManagerTheme;
_isDarkMode = persistedTheme.IsDarkMode;
}
else
{
_isDarkMode = await _mudThemeProvider.GetSystemPreference();
}
StateHasChanged();
}
await base.OnAfterRenderAsync(firstRender);
}
}
Theme Preset System
You can create a preset system for commonly used themes:
public static class ThemePresets
{
public static ThemeManagerTheme DefaultLight => new()
{
Theme = new MudTheme(),
FontFamily = "Roboto",
DefaultBorderRadius = 4,
DefaultElevation = 1,
AppBarElevation = 25,
DrawerElevation = 2,
DrawerClipMode = DrawerClipMode.Never
};
public static ThemeManagerTheme MaterialDark => new()
{
// Configure dark theme preset
};
public static Dictionary<string, ThemeManagerTheme> GetAllPresets()
{
return new Dictionary<string, ThemeManagerTheme>
{
{ "Default Light", DefaultLight },
{ "Material Dark", MaterialDark }
};
}
}
Advanced Features
Theme Validation
public bool ValidateTheme(ThemeManagerTheme theme)
{
return theme != null &&
theme.Theme != null &&
!string.IsNullOrEmpty(theme.FontFamily) &&
theme.DefaultBorderRadius >= 0 &&
theme.DefaultElevation >= 0;
}
Theme Comparison
public bool AreThemesEqual(ThemeManagerTheme theme1, ThemeManagerTheme theme2)
{
var json1 = SaveThemeToJson(theme1);
var json2 = SaveThemeToJson(theme2);
return json1 == json2;
}
Best Practices
- Error Handling: Always wrap save/load operations in try-catch blocks
- Validation: Validate theme data before saving
- Versioning: Consider adding version information to saved themes
- Backup: Implement backup mechanisms for important themes
- Performance: Debounce save operations to avoid excessive writes
- Service Registration: Remember to register your persistence service in
Program.cs
- File Permissions: Ensure your application has write permissions to the wwwroot folder
- Automatic Persistence: Use the
ThemeChanged
event to automatically save themes when modified
Example Theme JSON Structure
Here's an example of how the persisted theme data looks when saved as JSON:
{
"themeManagerTheme": {
"theme": {
"paletteLight": {
"primary": "#1976d2",
"secondary": "#dc004e",
"background": "#ffffff",
"surface": "#ffffff",
"appbarBackground": "#1976d2",
"drawerBackground": "#ffffff"
// ... other palette colors
},
"paletteDark": {
"primary": "#2196f3",
"secondary": "#f48fb1",
"background": "#121212",
"surface": "#1e1e1e",
"appbarBackground": "#1976d2",
"drawerBackground": "#1e1e1e"
// ... other palette colors
}
},
"fontFamily": "Roboto",
"defaultBorderRadius": 4,
"defaultElevation": 1,
"appBarElevation": 25,
"drawerElevation": 2,
"drawerClipMode": "Never",
"rtl": false
},
"isDarkMode": false
}
Component Structure
Core Components
- MudThemeManager: Main theme management component
- MudThemeManagerButton: Button component for theme manager
- MudThemeManagerColorItem: Individual color picker component
Models
- ThemeManagerTheme: Main theme model containing all theme properties
- ThemePaletteColor: Individual color representation
- ThemeUpdatedValue: Value object for theme updates
Extensions
- Extension: Utility methods for theme operations
- PaletteSerializerContext: JSON serialization context for palettes
- ThemeSerializerContext: JSON serialization context for themes
Getting Started
Quick Setup
- Add the Package: Add the MudBlazor ThemeManager Saver package to your project
- Choose Persistence Method:
- For browser storage: Use the localStorage approach
- For server-side persistence: Use the JSON file persistence service
- Register Services: Add your chosen persistence service to
Program.cs
- Update MainLayout: Implement the theme loading/saving logic in your layout
- Customize Appearance: Use the provided CSS classes to customize the theme manager
For JSON File Persistence
Register the service:
builder.Services.AddScoped<ThemePersistenceService>();
Include the component in your MainLayout as shown in the examples above
The theme will automatically:
- Load on application startup
- Save when theme changes are made
- Save when dark/light mode is toggled
Contributing
For more information on contributing to this project, see CONTRIBUTING.md.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.AspNetCore.Components (>= 8.0.12)
- MudBlazor (>= 8.0.0)
-
net9.0
- Microsoft.AspNetCore.Components (>= 9.0.1)
- MudBlazor (>= 8.0.0)
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.0.1 | 0 | 5/26/2025 |