Part 2: Contentment, Tag Helpers and Icon Pickers in Umbraco 11

This is a follow up blog to how I used Umbraco 11 and Contentment Icon Picker

This blog is how I have managed to get the colour picker to work but also move my logic in to a Tag Helper instead of in the Razor view. 

I'm not a fan of putting logic in to the Razor View and when I asked my question on Our forum, Bjarne suggested I use Tag Helpers and that got me thinking. 

I watched the great YouTube video from Warren on how to make a custom Tag Helper, specifically when using Umbraco. It's well worth a watch.

In my previous blog I had the icon working but I couldn't get the colour picker to work. This code is still a work in progress and if you see anything that could be improved, please, let me know. 

The code

So, my Razor View went from

@foreach (var menu in Model)
{
    if (menu.Content is NavItem navItem && navItem.Link != null)
    {
        var iconCleaned = string.Empty;
        var myIcon = new Umbraco.Cms.Core.Models.IconModel();

        if(navItem.Icon != null)
        {
            iconCleaned = navItem.Icon.Split(' ').First();
            myIcon = _iconService.GetIcon(iconCleaned);   
        }
       
        <li class="nav-item active">
            <a class="nav-link" href="#">
              @if(myIcon != null)
              {
                   <i class="my-icon">@Html.Raw(myIcon.SvgString)</i>
              }
               
                Blog Home 2 <span class="sr-only">(current)</span></a>
        </li>
    }
}

 

and then using a Tag Helper it now looks like this 

@foreach (var menu in Model)
{
    if (menu.Content is NavItem navItem && navItem.Link != null)
    {
        <li class="nav-item active">
            <a class="nav-link" href="@navItem.Link.Url">
                @if(navItem.Icon != null)
                {
                <i class="my-icon">
                        <svgIcon icon-name="@navItem.Icon.Split(' ').First()" icon-color="@navItem.Icon.Split(' ').Last()"></svgIcon> @navItem.Link.Name
                    </i>
                }
                else
                {
                    @navItem.Link.Name
                }
            </a>
        </li>
    }
}

 

My Tag Helper is called svgIcon and I pass the icon-name and icon-color to my helper class. 

My helper, which is called SvgIconTagHelper.cs and it looks like this

using ExCSS;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Umbraco.Cms.Core.Services;
using Umbraco.Extensions;

namespace OwainCodes23
{
    [HtmlTargetElement("svgIcon")]
    public class SvgIconTagHelper : TagHelper
    {
        private readonly IIconService _iconService;

        public SvgIconTagHelper(IIconService iconService)
        {
            _iconService = iconService;
        }

        [HtmlAttributeName("icon-name")]
        public string? Icon { get; set; }

        [HtmlAttributeName("icon-color")]
        public string? CssColor { get; set; }


        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            var parser = new StylesheetParser();

            // Colours and class names taken from Umbraco CSS
            var stylesheet = parser.Parse(".color-black{color: #000}" +
                ".color-blue-grey{color:#607d8b}" +
                ".color-grey{color:#9e9e9e}" +
                ".color-brown{color:#795548}" +
                ".color-blue{color:#2196f3}" +
                ".color-light-blue{color:#03a9f4}" +
                ".color-indigo{color:#3f51b5}" +
                ".color-purple{color:#9c27b0}" +
                ".color-deep-purple{color:#673ab7}" +
                ".color-cyan{color:#00bcd4}" +
                ".color-green{color:#4caf50}" +
                ".color-light-green{color:#8bc34a}" +
                ".color-lime{color:#cddc39}" +
                ".color-yellow{color:#ffeb3b}" +
                ".color-amber{color:#ffc107}" +
                ".color-orange{color:#ff9800}" +
                ".color-deep-orange{color:#ff5722}" +
                ".color-red{color:#f44336}" +
                ".color-pink{color:#e91e63}");

            var styles = stylesheet.StyleRules.ToList();

            var color = "#000";
            if (!CssColor.IsNullOrWhiteSpace() && styles.Any())
            {
                foreach (var style in styles)
                {
                    if (style.SelectorText.Replace(".", "") == CssColor)
                    {
                        color = style.Style.Color;
                    }
                }
            }


            if (!Icon.IsNullOrWhiteSpace())
            {
                Umbraco.Cms.Core.Models.IconModel svgIcon = _iconService.GetIcon(Icon);
                if (svgIcon != null)
                {
                    var colouredSvg = svgIcon.SvgString.Replace("path", "path fill='" + color + "'");

                    output.TagName = "";
                    output.SuppressOutput();
                    output.Content.SetHtmlContent(colouredSvg);
                }

            }

        }
    }
}

 

Explaining my code

The first thing you might notice is the very first link, using ExCSS which is a CSS parser for .Net 

I use in further down in my Tag. 

I use the Umbraco Icon Service, which I had injected in to my Razor View but now it's within the Tag and I setup to HTML Attributes which match the values that are on the View within the Tag.

Now you'll notice a long string of CSS classes with colours. These classes match the name that the icon picker sets for each colour and the colour values are copied straight from the Umbraco CSS. Obviously, if Umbraco add / remove / change these colour names then I would need to update this but that's fine. 

I parse this string in to a list and then I can iterate over the list to check to see if the icon-name matches any of the values in the css list.

Next, I get the Icon using the Icon Service which is returned as an SVG. I used the extension SvgString which allows me to search for all instances of "Path" and then append a fill value to the path which is the css colour value. 

This now means the SVG is coloured. 

The end result, I have an icon picker with working colour picker which renders everything via a Tag Helper to a Razor view. 

 

Published on: 08 March 2023