From 3d644d779a014ff0ad3f240dffe21d89533c6a53 Mon Sep 17 00:00:00 2001 From: Taylor Date: Wed, 8 Oct 2025 20:43:32 -0400 Subject: [PATCH] Upgrade library to .NET 9 and support auto render mode --- README.md | 10 ++- .../WASM-PWA-Sample/WASM-PWA-Sample.csproj | 41 +++++----- .../TailBlazor.HeroIcons.csproj | 12 +-- .../TailBlazorHeroIcon.razor.cs | 77 ++++++++++--------- 4 files changed, 72 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index a361b5b..b7d19d9 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,10 @@ The full icon pack can be previewed here: [HeroIcons.com](https://heroicons.com) This pack allows you to modify: size, stroke(colour), stroke width, width and height, and style (outlined or solid) for all the icons in an easy package with easy searching of available icons. +> **New in .NET 9** +> +> The component library now targets .NET 9 and embeds the SVG assets directly in the assembly. This allows `TailBlazorHeroIcon` to render during Blazor's new `InteractiveAuto` mode without making HTTP requests so it works seamlessly in both server-side and client-side rendering scenarios. + ![Nuget](https://img.shields.io/nuget/v/TailBlazor.HeroIcons.svg) @@ -48,10 +52,10 @@ By default you don't need to include anything but the `Icon` parameter. However Parameter | Default Value --- | --- -`Width` | `64` -`Height` | `64` +`Width` | `24` +`Height` | `24` `StrokeWidth` | `2` -`Class` | `text-black` +`Class` | inherits the current text colour (e.g. `text-slate-500`) `IconStyle` | `IconStyle.Outline` `EnableComments` | `false` diff --git a/src/Samples/WASM-PWA-Sample/WASM-PWA-Sample/WASM-PWA-Sample.csproj b/src/Samples/WASM-PWA-Sample/WASM-PWA-Sample/WASM-PWA-Sample.csproj index a6083f5..e81f681 100644 --- a/src/Samples/WASM-PWA-Sample/WASM-PWA-Sample/WASM-PWA-Sample.csproj +++ b/src/Samples/WASM-PWA-Sample/WASM-PWA-Sample/WASM-PWA-Sample.csproj @@ -1,22 +1,19 @@ - - - - net5.0 - $(RestoreSources);/Users/{REPLACEWITHUSER}/Developer/TailBlazor/HeroIcons/src/TailBlazor.HeroIcons/bin/release;https://api.nuget.org/v3/index.json - - service-worker-assets.js - - - - - - - - - - - - - - - + + + net9.0 + enable + enable + service-worker-assets.js + + + + + + + + + + + + + diff --git a/src/TailBlazor.HeroIcons/TailBlazor.HeroIcons.csproj b/src/TailBlazor.HeroIcons/TailBlazor.HeroIcons.csproj index 7fc2241..0db61cf 100644 --- a/src/TailBlazor.HeroIcons/TailBlazor.HeroIcons.csproj +++ b/src/TailBlazor.HeroIcons/TailBlazor.HeroIcons.csproj @@ -1,6 +1,8 @@ - net5.0 + net9.0 + enable + enable TailBlazor.HeroIcons TailBlazor.HeroIcons 1.1.6 @@ -24,9 +26,9 @@ - - - + + TailBlazor.HeroIcons.icons.%(RecursiveDir)%(Filename)%(Extension) + @@ -36,4 +38,4 @@ assets - \ No newline at end of file + diff --git a/src/TailBlazor.HeroIcons/TailBlazorHeroIcon.razor.cs b/src/TailBlazor.HeroIcons/TailBlazorHeroIcon.razor.cs index 74cd8fc..8aa15b0 100644 --- a/src/TailBlazor.HeroIcons/TailBlazorHeroIcon.razor.cs +++ b/src/TailBlazor.HeroIcons/TailBlazorHeroIcon.razor.cs @@ -1,74 +1,75 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System; +using System.Reflection; +using System.Threading; using System.Xml.Linq; using Microsoft.AspNetCore.Components; -using System.Threading.Tasks; -using System.Threading; -using System.IO; namespace TailBlazor.HeroIcons { public class TailBlazorHeroIconBase : ComponentBase { - - [Inject] protected NavigationManager NavigationManager { get; set; } + private const string ResourcePrefix = "TailBlazor.HeroIcons.icons."; + private static readonly Assembly IconAssembly = typeof(TailBlazorHeroIconBase).Assembly; [Parameter] public HeroIcon Icon { get; set; } [Parameter] public int Width { get; set; } = 24; [Parameter] public int Height { get; set; } = 24; [Parameter] public int StrokeWidth { get; set; } = 2; - [Parameter] public string Class { get; set; } + [Parameter] public string? Class { get; set; } [Parameter] public IconStyle IconStyle { get; set; } = IconStyle.Outline; - [Parameter] public bool EnableComments { get; set; } = false; + [Parameter] public bool EnableComments { get; set; } + + protected string _svgIcon = string.Empty; + protected string _svgIconComment = string.Empty; - protected string _classStroke = "stroke-current "; - protected string _svgIcon = ""; - protected string _svgIconComment = ""; + private string _classStroke = string.Empty; - protected override async Task OnInitializedAsync() + protected override async Task OnParametersSetAsync() { - _classStroke += Class; + _classStroke = "stroke-current"; - if (EnableComments) + if (!string.IsNullOrWhiteSpace(Class)) { - // HeroIcon: annotation (style: outlined, size: 64x64, stroke (colour): text-grey-500, stroke-width: 2) - _svgIconComment = $""; + _classStroke += $" {Class}"; } - var baseUri = NavigationManager.BaseUri; - var token = new CancellationToken(); - - var document = await Task.Run(() => { - return XDocument.Load($"{baseUri}_content/TailBlazor.HeroIcons/icons/{EnumExtension.GetEnumDescription(IconStyle)}/{EnumExtension.GetEnumDescription(Icon)}.svg"); - }); + if (EnableComments) + { + _svgIconComment = $""; + } + else + { + _svgIconComment = string.Empty; + } + var iconStyleName = EnumExtension.GetEnumDescription(IconStyle); + var iconName = EnumExtension.GetEnumDescription(Icon); + var resourceName = $"{ResourcePrefix}{iconStyleName}.{iconName}.svg"; - //XDocument document = - // await XDocument.LoadAsync($"{baseUri}_content/TailBlazor.HeroIcons/icons/{EnumExtension.GetEnumDescription(IconStyle)}/{EnumExtension.GetEnumDescription(Icon)}.svg", LoadOptions.None, token); + await using var resourceStream = IconAssembly.GetManifestResourceStream(resourceName) + ?? throw new InvalidOperationException($"Could not find embedded icon resource '{resourceName}'."); - XElement svg_Element = document.Root; + var document = await XDocument.LoadAsync(resourceStream, LoadOptions.PreserveWhitespace, CancellationToken.None); - svg_Element.SetAttributeValue("width", Width); - svg_Element.SetAttributeValue("height", Height); - svg_Element.SetAttributeValue("stroke", ""); - svg_Element.SetAttributeValue("class", _classStroke); + if (document.Root is null) + { + throw new InvalidOperationException($"The SVG document for icon '{iconName}' is empty."); + } - IEnumerable descendants = from path in svg_Element.Descendants() select path; + document.Root.SetAttributeValue("width", Width); + document.Root.SetAttributeValue("height", Height); + document.Root.SetAttributeValue("stroke", null); + document.Root.SetAttributeValue("class", _classStroke); - foreach (XElement path in descendants) + foreach (var path in document.Root.Descendants()) { if (path.Attribute("stroke-width") != null) { path.SetAttributeValue("stroke-width", StrokeWidth); } - if (path.Attribute("fill") != null) - { - path.SetAttributeValue("fill", StrokeWidth); - } } - _svgIcon = svg_Element.ToString(); + _svgIcon = document.Root.ToString(SaveOptions.DisableFormatting); } } }