Theming

Hello,

I have my app set up so that I can dynamically switch between the built in themes and it works well. 

I've used your theme studio to modify the material theme but I would like to save it as it's own theme so that I can pick it from the list just like any built in theme. I tried renaming the modified scss and editing the skin-name in the scss but it just results in a mess when applied.

How would I go about making a custom theme that can be included just like the built in themes so I can switch between them dynamically?

Thanks


3 Replies

SH Sheldon August 23, 2023 03:05 PM UTC

Any suggestions on this? I want to make a custom theme and then be able to treat it like one of the built in themes so I can swap between several custom themes and the built in themes dynamically.


Sheldon



SH Sheldon August 25, 2023 02:49 PM UTC

No reply at all to this? You guys are usually pretty quick..



SS Swetha Srikumar Syncfusion Team August 28, 2023 07:13 AM UTC

Hi Sheldon,


Based on the details you have provided, we have prepared a sample application incorporating the bootstrap5-dark, tailwind and tailwind-dark built-in themes. This implementation allows for dynamic theme changing with both built-in and customized themes.


Please refer to the following code snippet, video and sample for clarification:

_Host.cshtml

@page "/"

@using Microsoft.AspNetCore.Components.Web

@using Microsoft.AspNetCore.WebUtilities;

@namespace DynamicTheming.Pages

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@{

    Layout = null;

    @*Pass the URL query to select the theme name *@

    QueryHelpers.ParseQuery(Request.QueryString.Value).TryGetValue("theme", out var themeName);

    themeName = themeName.Count > 0 ? themeName.First() : "tailwind-dark";

}

<!DOCTYPE html>

<html lang="en">

<head>

    //… 

    @*Sets the selected theme name into styles*@

    @if (themeName == "bootstrap5-dark" || themeName == "tailwind" || themeName == "tailwind-dark")

    {

        <link rel='nofollow' href=@("_content/Syncfusion.Blazor.Themes/" + themeName + ".css") rel="stylesheet" />

    }

    else

    {

        <link rel='nofollow' href=@("css/custom-theme/" + themeName + ".css") rel="stylesheet" />

    }

 

    <script src="_content/Syncfusion.Blazor.Core/scripts/syncfusion-blazor.min.js" type="text/javascript"></script>

 

    //…

</head>

//…

Index.razor

@page "/"

 

<PageTitle>Index</PageTitle>

 

@inject DynamicTheming.Shared.ThemeGenerator themeHelper

@inject NavigationManager uriHelper

@using Microsoft.AspNetCore.WebUtilities;

@inject IJSRuntime JSRuntime;

 

<h1>Dynamic Theming</h1>

 

<div>

    <table>

        <tbody>

            <tr>

                <td>

                    CHOOSE THEME

                </td>

                <td>

<SfDropDownList TItem="Theme" TValue="string" @bind-value="themeHelper.currentTheme" DataSource="themeHelper.Themes" Placeholder="CHOOSE THEME">

<DropDownListEvents TItem="Theme" TValue="string" ValueChange="OnThemeChange"></DropDownListEvents>

<DropDownListFieldSettings Text="Text" Value="Value"></DropDownListFieldSettings>

</SfDropDownList>

                </td>

            </tr>

            @if(themeHelper.currentTheme == "tailwind-dark" || themeHelper.currentTheme == "tailwind" || themeHelper.currentTheme == "bootstrap5-dark"){

            <tr>

                <td>

                    Primary color

                </td>

                <td>

<SfColorPicker @bind-Value="themeVariables.PrimaryColor" Mode="ColorPickerMode.Palette"></SfColorPicker>

                </td>

            </tr>

            <tr>

                <td>

                    Primary font

                </td>

                <td>

<SfColorPicker @bind-Value="themeVariables.PrimaryFont" Mode="ColorPickerMode.Palette"></SfColorPicker>

                </td>

            </tr>

            <tr>

                <td>

                    Secondary color

                </td>

                <td>

<SfColorPicker @bind-Value="themeVariables.SecondaryColor" Mode="ColorPickerMode.Palette"></SfColorPicker>

                </td>

            </tr>

            <tr>

                <td>

                    Secondary font

                </td>

                <td>

<SfColorPicker @bind-Value="themeVariables.SecondaryFont" Mode="ColorPickerMode.Palette"></SfColorPicker>

                </td>

            </tr>

            <tr>

                <td>

<SfTextBox Placeholder="Enter custom theme name" @bind-Value="CustomThemeName"></SfTextBox>

                </td>

                <td>

                </td>

            </tr>

            <tr>

                <td>

<SfButton Content="Generate theme" OnClick="GenerateTheme"></SfButton>

                </td>

                <td>

                </td>

            </tr>

            }

        </tbody>

    </table>

</div>

 

<br />

 

<br />

 

<br />

 

<br />

 

 

<div style="margin: 20px"><SfButton IsPrimary=true>Button</SfButton></div>

 

<br />

<br />

 

<div style="margin: 20px"><SfCalendar TValue="DateTime"></SfCalendar></div>

 

 

@code {

 

    private string CustomThemeName;

    private ThemeVariable themeVariables = new ThemeVariable();

 

    protected override void OnInitialized()

    {

        string url = uriHelper.Uri;

        int index = url.IndexOf("?theme=");

        themeHelper.currentTheme = index > -1 ? url.Substring(index + 7) : themeHelper.Themes[0].Value;

        @if (themeHelper.currentTheme == "tailwind-dark" || themeHelper.currentTheme == "tailwind" || themeHelper.currentTheme == "bootstrap5-dark")

        {

            themeVariables = themeHelper.GetThemeVariables();

        }

    }

 

    /// <summary>

    /// The switcher OnChange event handler.

    /// </summary>

    public void OnThemeChange(ChangeEventArgs<string, Theme> args)

    {

        var theme = GetThemeName();

        if (theme != args.ItemData.Value)

        {

uriHelper.NavigateTo(GetUri(args.ItemData.Value), true);

        }

        @if (themeHelper.currentTheme == "tailwind-dark" || themeHelper.currentTheme == "tailwind" || themeHelper.currentTheme == "bootstrap5-dark")

        {

            themeVariables = themeHelper.GetThemeVariables();

        }

    }

 

    /// <summary>

    /// Returns the theme name from Uri QueryString.

    /// </summary>

    private string GetThemeName()

    {

        var uri = uriHelper.ToAbsoluteUri(uriHelper.Uri);

        QueryHelpers.ParseQuery(uri.Query).TryGetValue("theme", out var theme);

        theme = theme.Count > 0 ? theme.First() : "bootstrap4";

        return theme;

    }

 

    /// <summary>

    /// Returns the new Uri to navigate with theme changes.

    /// </summary>

    private string GetUri(string themeName)

    {

        var uri = uriHelper.ToAbsoluteUri(uriHelper.Uri);

        return uri.AbsolutePath + "?theme=" + themeName;

    }

 

    public void GenerateTheme()

    {

themeHelper.RefreshTheme(themeVariables, CustomThemeName);

    }

}

 

 

<style>

 

    th, td {

        padding: 15px;

    }

 

</style>


ThemeGenerator.cs

using DartSassHost;

using DartSassHost.Helpers;

using JavaScriptEngineSwitcher.ChakraCore;

using Microsoft.AspNetCore.Components;

using System.Text.RegularExpressions;

 

namespace DynamicTheming.Shared

{

    public class Theme

    {

        public string Value { get; set; }

        public string Text { get; set; }

    }

    public class ThemeGenerator: ComponentBase

    {

        private IHostEnvironment env;

        private NavigationManager uriHelper;

 

        public string currentTheme { get; set; }

        protected ThemeVariable themeVariables = new ThemeVariable();

 

        private string PrimaryColorVariable = "$primary";

        private string PrimaryFontVariable = "$primary-text-color";

        private string SecondaryColorVariable = "$secondary";

        private string SecondaryBgColorVariable = "$secondary-bg-color";

        private string SecondaryFontVariable = "$secondary-text-color";

        private string OutputCssFile { get; set; }

        private string FolderPath { get; set; }

        private string[] FileNames { get; set; }

        public ThemeGenerator(IHostEnvironment hostingEnvironment, NavigationManager navigationManager)

        {

            env = hostingEnvironment;

            uriHelper = navigationManager;

OutputCssFile = env.ContentRootPath + @"\wwwroot\css\custom-theme\.css";

FolderPath = env.ContentRootPath + @"\wwwroot\css\custom-theme";

            FileNames = Directory.GetFiles(FolderPath).Select(Path.GetFileNameWithoutExtension).ToArray();

            foreach (var file in FileNames)

            {

Themes.Add(new Theme() { Text = file, Value = file });

            }

        }

 

        public List<Theme> Themes = new List<Theme>() {

            new Theme(){ Text = "TailWind Dark", Value = "tailwind-dark" },

            new Theme(){ Text = "TailWind", Value = "tailwind" },

            new Theme(){ Text = "Bootstrap5 Dark", Value = "bootstrap5-dark" },

        };

 

        public ThemeVariable GetThemeVariables()

        {

            themeVariables.PrimaryColor = GetValue(PrimaryColorVariable);

            themeVariables.PrimaryFont = GetValue(PrimaryFontVariable);

            themeVariables.SecondaryFont = GetValue(SecondaryFontVariable);

themeVariables.SecondaryColor = GetValue((currentTheme == "tailwind-dark") || (currentTheme == "tailwind") ? SecondaryBgColorVariable : SecondaryColorVariable);

 

            return themeVariables;

        }

 

        public string GetInputScssFile()

        {

            return env.ContentRootPath + @"\wwwroot\scss\custom-" + currentTheme + ".scss";

        }

 

        public string GetValue(string prop)

        {

            string value = null;

            string themeContent = File.ReadAllText(GetInputScssFile());

            Match matchedValue = Regex.Match(themeContent, $\\{prop}: (.*) !default;);

           

            if (matchedValue.Groups[1] != null)

            {

                value = matchedValue.Groups[1].Value.Trim();

            }

            return value;

        }

 

        public void RefreshTheme(ThemeVariable themeVariables, string CustomThemeName)

        {

            string InputScssFile = GetInputScssFile();

            string output = File.ReadAllText(InputScssFile);

 

            output = Regex.Replace(output, $\\{PrimaryColorVariable}:(.*);, $"{PrimaryColorVariable}: {themeVariables.PrimaryColor} !default;");

            output = Regex.Replace(output, $\\{PrimaryFontVariable}:(.*);, $"{PrimaryFontVariable}: {themeVariables.PrimaryFont} !default;");

            output = Regex.Replace(output, $\\{SecondaryFontVariable}:(.*);, $"{SecondaryFontVariable}: {themeVariables.SecondaryFont} !default;");

 

            string secondaryColor = (currentTheme == "tailwind-dark") || (currentTheme == "tailwind") ? SecondaryBgColorVariable : SecondaryColorVariable;

            output = Regex.Replace(output, $\\{secondaryColor}:(.*);, $"{secondaryColor}: {themeVariables.SecondaryColor} !default;");

 

            //to create new custom theme

            string modifiedOutputCssFile = OutputCssFile.Replace(".css", CustomThemeName.ToLower() + ".css");

            try

            {

                using (var sassCompiler = new SassCompiler(new ChakraCoreJsEngineFactory()))

                {

CompilationResult result = sassCompiler.Compile(output,false);

 

if (result.CompiledContent != null)

                    {

//Write compiled content to output css file.

File.WriteAllText(modifiedOutputCssFile, result.CompiledContent);

 

//Write updated content to input scss file.

File.WriteAllText(InputScssFile, output);

                    }

                }

            }

            catch (SassCompilerLoadException e)

            {

Console.WriteLine("During loading of Sass compiler an error occurred. See details:");

                Console.WriteLine();

Console.WriteLine(SassErrorHelpers.GenerateErrorDetails(e));

            }

            catch (SassCompilationException e)

            {

Console.WriteLine("During compilation of SCSS code an error occurred. See details:");

                Console.WriteLine();

Console.WriteLine(SassErrorHelpers.GenerateErrorDetails(e));

            }

            catch (SassException e)

            {

Console.WriteLine("During working of Sass compiler an unknown error occurred. See details:");

                Console.WriteLine();

Console.WriteLine(SassErrorHelpers.GenerateErrorDetails(e));

            }

 

uriHelper.NavigateTo(uriHelper.BaseUri + "?theme=" + currentTheme, forceLoad: true);

        }

    }

 

    public class ThemeVariable

    {

        public string PrimaryColor { get; set; }

        public string PrimaryFont { get; set; }

        public string SecondaryColor { get; set; }

        public string SecondaryFont { get; set; }

    }

}

 


Video: https://www.syncfusion.com/downloads/support/directtrac/general/ze/DynamicThemeSwitching-849626594

Sample: https://www.syncfusion.com/downloads/support/directtrac/general/ze/DynamicTheming1940471352


Please let us know if you have any concerns.


Regards,

Bharat Ram H


Loader.
Up arrow icon