diff --git a/TagHelpers/BsIconTagHelper.cs b/TagHelpers/BsIconTagHelper.cs new file mode 100644 index 0000000..6b28216 --- /dev/null +++ b/TagHelpers/BsIconTagHelper.cs @@ -0,0 +1,127 @@ +using Microsoft.AspNetCore.Razor.TagHelpers; +using System.Threading.Tasks; + +namespace AcdiuTools.TagHelpers +{ + /// + /// SVG Sprite 封装标签 + /// 用法: + /// + [HtmlTargetElement("bsicon")] + public class BsIconTagHelper : TagHelper + { + // 路径指向你存放总 SVG 的位置 + /// + /// 表示用于引用图标符号的 SVG矢量图库文件的相对路径 + /// + /// 此路径应指向包含所有 图标定义的SVG文件
+ /// 如果图标库被移动或升级,则需要更新该值
+ const string spritePath = "/lib/bootstrap-icons-1.13.1/bootstrap-icons.svg"; + + /// + /// 图标名称 (必填) + /// + [HtmlAttributeName("i")] + public required string IconName { get; set; } + + /// + /// 宽度 (默认为空,若为空时设置了高度,则使用高度的值,否则为元素 ClassName 添加 w-1r 以使其默认宽度为 1rem) + /// + [HtmlAttributeName("w")] + public string Width { get; set; } = string.Empty; + + /// + /// 高度 (默认为空,若为空时设置了宽度,则使用宽度的值,否则为元素 ClassName 添加 h-1r 以使其默认高度为 1rem) + /// + [HtmlAttributeName("h")] + public string Height { get; set; } = string.Empty; + + /// + /// 填充颜色 (默认 currentColor 即当前元素颜色) + /// + [HtmlAttributeName("f")] + public string Fill { get; set; } = "currentColor"; + + /// + /// 自定义 class 名称,允许用户添加额外的样式类 (默认空) + /// + [HtmlAttributeName("cn")] + public string ClassName { get; set; } = string.Empty; + + /// + /// 根据指定的图标名称和属性,处理标签助手以渲染SVG矢量图标 + /// + /// 若未指定图标名称或为空,则输出被抑制且不生成SVG
+ /// 渲染后,该方法会将原始标签替换为<svg>元素并设置标准的SVG属性
+ /// 包括类名、宽度、高度、填充颜色和图标ID名称。该SVG引用了 中的图标
+ /// 使用<use>元素引用的矢量图形
+ /// 用于标签辅助程序执行的上下文,包含当前HTML标签及其属性的相关信息 + /// 标签辅助器的输出,用于修改渲染的HTML元素及其内容 + public override void Process(TagHelperContext context, TagHelperOutput output) + { + if (string.IsNullOrWhiteSpace(IconName)) + { + output.SuppressOutput(); // 如果没写图标名,则不渲染 + return; + } + + // 1. 将外层标签替换为 + output.TagName = "svg"; + output.TagMode = TagMode.StartTagAndEndTag; + + // 2. 设置 SVG 基础属性 + // 如果设置了 w 或 h,则优先使用它们,否则使用 wh 的值 + // 设定机制: + // 如果 w 和 h 中任意一个不为空,则使用不为空的 w 或 h 的值同时设置宽高; + // 如果 w 和 h 都不为空,则分别使用它们设置宽高; + // 如果 w 和 h 都为空,则为其添加默认的 w-1r 和 h-1r 类以设置默认宽高为 1rem + if (!string.IsNullOrWhiteSpace(Width) || !string.IsNullOrWhiteSpace(Height)) + { + // 如果用户设置了宽或高,则不添加默认的 w-1r 和 h-1r 类 + output.Attributes.SetAttribute("width", !string.IsNullOrWhiteSpace(Width) ? Width : Height); + output.Attributes.SetAttribute("height", !string.IsNullOrWhiteSpace(Height) ? Height : Width); + + // 继续添加用户自定义的 ClassName(如果有的话) + output.Attributes.SetAttribute("class", MergeClassNames(string.IsNullOrWhiteSpace(ClassName) ? "" : $"{ClassName}")); + } + else + { + // 如果没有设置宽高,则添加默认的 w-1r 和 h-1r 类并与用户自定义的 ClassName 合并 + // 如果提供了 ClassName,则判断是否为空,如果不为空则将其与默认的 w-1r 和 h-1r 类合并 + // 合并时使用 HashSet 来去重,确保不会重复添加相同的类名 + output.Attributes.SetAttribute("class", MergeClassNames(ClassName)); + } + + output.Attributes.SetAttribute("fill", Fill); + output.Attributes.SetAttribute("viewBox", "0 0 16 16"); // 保证矢量对齐 + //output.Attributes.SetAttribute("xmlns", "http://www.w3.org/2000/svg"); + + // 3. 构造内部的 节点 + var content = $@""; + + output.Content.SetHtmlContent(content); + } + + /// + /// 合并类名的方法,确保默认的 w-1r 和 h-1r 类与用户提供的 ClassName 合并且去重 + /// + /// 用户提供的类名 + /// 合并且去重后的类名字符串 + public static string MergeClassNames(string userClassName) + { + // 定义默认的类列表 + var defaultClasses = new HashSet { "w-1r", "h-1r" }; + // 如果用户提供了 ClassName,则将其拆分成单个类并添加到集合中 + if (!string.IsNullOrWhiteSpace(userClassName)) + { + var userClasses = userClassName.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + foreach (var cls in userClasses) + { + defaultClasses.Add(cls); + } + } + // 将集合中的类名合并成一个字符串返回 + return string.Join(" ", defaultClasses); + } + } +} \ No newline at end of file diff --git a/Views/Shared/_Layout.cshtml b/Views/Shared/_Layout.cshtml index 84d0c14..6bb7123 100644 --- a/Views/Shared/_Layout.cshtml +++ b/Views/Shared/_Layout.cshtml @@ -9,7 +9,7 @@ - + @@ -29,10 +29,12 @@ diff --git a/wwwroot/ac/ac.css b/wwwroot/ac/ac.css index 008eb1d..8ae9214 100644 --- a/wwwroot/ac/ac.css +++ b/wwwroot/ac/ac.css @@ -5,8 +5,8 @@ /* 桌面: 1024px - 1920px */ /* 4K屏: 3840px */ /* --- 核心字号缩放逻辑 --- */ - /* 逻辑:在移动端最小为 14px,在 1024px 以上开始线性增长,到 4K 达到 24px */ - /* 公式:clamp(最小值, 首选值, 最大值) */ + /* 逻辑: 在移动端最小为 14px,在 1024px 以上开始线性增长,到 4K 达到 24px */ + /* 公式: clamp(最小值, 首选值, 最大值) */ font-size: 14px; } @@ -62,4 +62,17 @@ font-weight: bold; color: var(--bs-primary) !important; border-bottom: 2px solid var(--bs-primary); +} + +.p-r-t { + position: relative; + top: -1px; +} + +.w-1r { + width: 1rem; +} + +.h-1r { + height: 1rem; } \ No newline at end of file