diff --git a/README.md b/README.md index 7b00a0c..5bc424c 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,32 @@ In your `_ViewImports.cshtml` add: @addTagHelper *, HeroiconsTagHelper ``` +In your `Startup.cs` add: + +```csharp +public void ConfigureServices(IServiceCollection services) +{ + services.AddHeroicons(Configuration); +} +``` + +In your `appsettings.json` add: + +```json +{ + "Heroicons": { + "IncludeComments": true + } +} + +``` + +## Settings + +### IncludeComments + +Setting this to `true` will add an html comment before the svg tag with the style and name of the icon to help make development/debugging easier. + ## Usage There are two versions of the tag helper which are used to pick between the `outline` and `solid` icon styles. diff --git a/generator/IconSourceGenerator.cs b/generator/IconSourceGenerator.cs index 6309ab7..036cdd5 100644 --- a/generator/IconSourceGenerator.cs +++ b/generator/IconSourceGenerator.cs @@ -117,6 +117,7 @@ public static class IconList source.AppendLine(" case IconSymbol." + icon.ClassName + ":"); source.AppendLine(" return new Icon"); source.AppendLine(" {"); + source.Append(" Name = \"").Append(icon.Name).AppendLine("\","); source.Append(" Path = \"").Append(path.Replace("\"", "\\\"")).AppendLine("\","); source.Append(" ViewBox = \"").Append(viewBox).AppendLine("\","); source.AppendLine(" };"); @@ -135,6 +136,7 @@ public static class IconList public class Icon { + public string Name { get; set; } public string Path { get; set; } public string ViewBox { get; set; } } diff --git a/sample/Startup.cs b/sample/Startup.cs index d81408e..4853a97 100644 --- a/sample/Startup.cs +++ b/sample/Startup.cs @@ -19,6 +19,8 @@ public Startup(IConfiguration configuration) public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); + + services.AddHeroicons(Configuration); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/sample/appsettings.Development.json b/sample/appsettings.Development.json index 8983e0f..611245d 100644 --- a/sample/appsettings.Development.json +++ b/sample/appsettings.Development.json @@ -1,4 +1,7 @@ { + "Heroicons": { + "IncludeComments": true + }, "Logging": { "LogLevel": { "Default": "Information", diff --git a/sample/appsettings.json b/sample/appsettings.json index d9d9a9b..32c1921 100644 --- a/sample/appsettings.json +++ b/sample/appsettings.json @@ -1,10 +1,10 @@ { + "AllowedHosts": "*", "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } - }, - "AllowedHosts": "*" + } } diff --git a/src/HeroiconOptions.cs b/src/HeroiconOptions.cs new file mode 100644 index 0000000..78c4671 --- /dev/null +++ b/src/HeroiconOptions.cs @@ -0,0 +1,11 @@ +namespace Tailwind.Heroicons +{ + public class HeroiconOptions + { + /// + /// Add an html comment before the svg tag with the style and name of the icon. + /// + /// This is off by default. + public bool IncludeComments { get; set; } + } +} diff --git a/src/HeroiconsExtensions.cs b/src/HeroiconsExtensions.cs new file mode 100644 index 0000000..e167589 --- /dev/null +++ b/src/HeroiconsExtensions.cs @@ -0,0 +1,31 @@ +namespace Microsoft.Extensions.DependencyInjection +{ + using System; + + using Microsoft.Extensions.Configuration; + + using Tailwind.Heroicons; + + public static class HeroiconsExtensions + { + public static IServiceCollection AddHeroicons(this IServiceCollection services, IConfiguration configuration) + { + if (services is null) throw new ArgumentNullException(nameof(services)); + if (configuration is null) throw new ArgumentNullException(nameof(configuration)); + + services.Configure(configuration.GetSection("Heroicons")); + + return services; + } + + public static IServiceCollection AddHeroicons(this IServiceCollection services, Action configureOptions) + { + if (services is null) throw new ArgumentNullException(nameof(services)); + if (configureOptions is null) throw new ArgumentNullException(nameof(configureOptions)); + + services.Configure(configureOptions); + + return services; + } + } +} diff --git a/src/IconTagHelper.cs b/src/IconTagHelper.cs index 31c7a7f..f577475 100644 --- a/src/IconTagHelper.cs +++ b/src/IconTagHelper.cs @@ -3,18 +3,26 @@ using System; using Microsoft.AspNetCore.Razor.TagHelpers; + using Microsoft.Extensions.Options; [HtmlTargetElement("heroicon-outline", TagStructure = TagStructure.WithoutEndTag)] [HtmlTargetElement("heroicon-solid", TagStructure = TagStructure.WithoutEndTag)] public class IconTagHelper : TagHelper { + private readonly HeroiconOptions _settings; + + public IconTagHelper(IOptions settings) + { + _settings = settings?.Value ?? throw new ArgumentNullException(nameof(settings)); + } + [HtmlAttributeName("icon")] public IconSymbol Icon { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output) { - if (context == null) throw new ArgumentNullException(nameof(context)); - if (output == null) throw new ArgumentNullException(nameof(output)); + if (context is null) throw new ArgumentNullException(nameof(context)); + if (output is null) throw new ArgumentNullException(nameof(output)); var isSolid = context.TagName.Equals("heroicon-solid", StringComparison.OrdinalIgnoreCase); @@ -40,6 +48,15 @@ public override void Process(TagHelperContext context, TagHelperOutput output) output.Attributes.Add("viewbox", icon.ViewBox); output.Content.AppendHtml(icon.Path); + + if (_settings.IncludeComments) + { + output.PreElement.AppendHtml(""); + } } } } diff --git a/test/IconTagHelperTests.cs b/test/IconTagHelperTests.cs index c6bb307..3a214cd 100644 --- a/test/IconTagHelperTests.cs +++ b/test/IconTagHelperTests.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.TagHelpers; + using Microsoft.Extensions.Options; using Shouldly; @@ -19,7 +20,8 @@ public void Should_set_svg_attributes() var context = MakeTagHelperContext(tagName: "heroicon-outline"); var output = MakeTagHelperOutput(tagName: "heroicon-outline"); - var helper = new IconTagHelper(); + var options = Options.Create(new HeroiconOptions()); + var helper = new IconTagHelper(options); // When helper.Process(context, output); @@ -41,7 +43,8 @@ public void Should_output_outline_bell_icon(string tagName) var context = MakeTagHelperContext(tagName); var output = MakeTagHelperOutput(tagName); - var helper = new IconTagHelper + var options = Options.Create(new HeroiconOptions()); + var helper = new IconTagHelper(options) { Icon = IconSymbol.Bell }; @@ -66,7 +69,8 @@ public void Should_output_solid_bell_icon(string tagName) var context = MakeTagHelperContext(tagName); var output = MakeTagHelperOutput(tagName); - var helper = new IconTagHelper + var options = Options.Create(new HeroiconOptions()); + var helper = new IconTagHelper(options) { Icon = IconSymbol.Bell }; @@ -101,7 +105,8 @@ public void Should_apply_custom_attributes(string attributeName, string attribut { attributeName, attributeValue }, }); - var helper = new IconTagHelper + var options = Options.Create(new HeroiconOptions()); + var helper = new IconTagHelper(options) { Icon = IconSymbol.Bell }; @@ -113,6 +118,52 @@ public void Should_apply_custom_attributes(string attributeName, string attribut output.Attributes.ShouldContain(new TagHelperAttribute(attributeName, attributeValue)); } + [Fact] + public void Should_not_include_html_comment_when_IncludeComments_is_false() + { + // Given + var context = MakeTagHelperContext(tagName: "heroicon-outline"); + var output = MakeTagHelperOutput(tagName: "heroicon-outline"); + + var options = Options.Create(new HeroiconOptions + { + IncludeComments = false, + }); + var helper = new IconTagHelper(options) + { + Icon = IconSymbol.Bell, + }; + + // When + helper.Process(context, output); + + // Then + output.PreElement.GetContent().ShouldBeEmpty(); + } + + [Fact] + public void Should_include_html_comment_when_IncludeComments_is_true() + { + // Given + var context = MakeTagHelperContext(tagName: "heroicon-outline"); + var output = MakeTagHelperOutput(tagName: "heroicon-outline"); + + var options = Options.Create(new HeroiconOptions + { + IncludeComments = true, + }); + var helper = new IconTagHelper(options) + { + Icon = IconSymbol.Bell, + }; + + // When + helper.Process(context, output); + + // Then + output.PreElement.GetContent().ShouldBe(""); + } + private static TagHelperContext MakeTagHelperContext(string tagName, TagHelperAttributeList attributes = null) { attributes ??= new TagHelperAttributeList();