diff --git a/Constants/CssClassNames.cs b/Constants/CssClassNames.cs index c1b9ca7..8dd161a 100644 --- a/Constants/CssClassNames.cs +++ b/Constants/CssClassNames.cs @@ -1,7 +1,6 @@ -namespace Lombiq.BaseTheme.Constants +namespace Lombiq.BaseTheme.Constants; + +public static class CssClassNames { - public static class CssClassNames - { - public const string LayoutContentWithSidebar = "layoutContent_withSidebar"; - } + public const string LayoutContentWithSidebar = "layoutContent_withSidebar"; } diff --git a/Constants/FeatureIds.cs b/Constants/FeatureIds.cs index b61f214..220d1cd 100644 --- a/Constants/FeatureIds.cs +++ b/Constants/FeatureIds.cs @@ -1,7 +1,6 @@ -namespace Lombiq.BaseTheme.Constants +namespace Lombiq.BaseTheme.Constants; + +public static class FeatureIds { - public static class FeatureIds - { - public const string Area = "Lombiq.BaseTheme"; - } + public const string Area = "Lombiq.BaseTheme"; } diff --git a/Constants/ResourceNames.cs b/Constants/ResourceNames.cs index 783f5e3..ee17a60 100644 --- a/Constants/ResourceNames.cs +++ b/Constants/ResourceNames.cs @@ -1,10 +1,9 @@ -namespace Lombiq.BaseTheme.Constants +namespace Lombiq.BaseTheme.Constants; + +public static class ResourceNames { - public static class ResourceNames - { - private const string Prefix = FeatureIds.Area + "."; + private const string Prefix = FeatureIds.Area + "."; - public const string Site = Prefix + nameof(Site); - public const string Helpers = Prefix + nameof(Helpers); - } + public const string Site = Prefix + nameof(Site); + public const string Helpers = Prefix + nameof(Helpers); } diff --git a/Constants/ZoneNames.cs b/Constants/ZoneNames.cs index adb2d89..a33a586 100644 --- a/Constants/ZoneNames.cs +++ b/Constants/ZoneNames.cs @@ -1,18 +1,17 @@ -namespace Lombiq.BaseTheme.Constants +namespace Lombiq.BaseTheme.Constants; + +public static class ZoneNames { - public static class ZoneNames - { - public const string Header = nameof(Header); - public const string Navigation = nameof(Navigation); - public const string BeforeMain = nameof(BeforeMain); - public const string Featured = nameof(Featured); - public const string AsideFirst = nameof(AsideFirst); - public const string Messages = nameof(Messages); - public const string BeforeContent = nameof(BeforeContent); - public const string Content = nameof(Content); - public const string AfterContent = nameof(AfterContent); - public const string AsideSecond = nameof(AsideSecond); - public const string AfterMain = nameof(AfterMain); - public const string Footer = nameof(Footer); - } + public const string Header = nameof(Header); + public const string Navigation = nameof(Navigation); + public const string BeforeMain = nameof(BeforeMain); + public const string Featured = nameof(Featured); + public const string AsideFirst = nameof(AsideFirst); + public const string Messages = nameof(Messages); + public const string BeforeContent = nameof(BeforeContent); + public const string Content = nameof(Content); + public const string AfterContent = nameof(AfterContent); + public const string AsideSecond = nameof(AsideSecond); + public const string AfterMain = nameof(AfterMain); + public const string Footer = nameof(Footer); } diff --git a/Lombiq.BaseTheme.csproj b/Lombiq.BaseTheme.csproj index c2b31d4..eda2434 100644 --- a/Lombiq.BaseTheme.csproj +++ b/Lombiq.BaseTheme.csproj @@ -1,7 +1,7 @@ - net5.0 + net6.0 true $(DefaultItemExcludes);.git*;node_modules\**;Tests\** @@ -20,10 +20,10 @@ - - - - + + + + diff --git a/Models/ZoneDescriptor.cs b/Models/ZoneDescriptor.cs index d8f7748..a11637e 100644 --- a/Models/ZoneDescriptor.cs +++ b/Models/ZoneDescriptor.cs @@ -9,113 +9,112 @@ using System.Linq; using System.Threading.Tasks; -namespace Lombiq.BaseTheme.Models +namespace Lombiq.BaseTheme.Models; + +public class ZoneDescriptor { - public class ZoneDescriptor - { - public const string LayoutElementClassName = "layoutElement"; - public const string LeafClassName = LayoutElementClassName + "_leaf"; + public const string LayoutElementClassName = "layoutElement"; + public const string LeafClassName = LayoutElementClassName + "_leaf"; - public string ZoneName { get; set; } - public string ElementName { get; set; } - public bool WrapBody { get; set; } + public string ZoneName { get; set; } + public string ElementName { get; set; } + public bool WrapBody { get; set; } - public IEnumerable ChildrenBefore { get; init; } - public IEnumerable ChildrenAfter { get; init; } + public IEnumerable ChildrenBefore { get; init; } + public IEnumerable ChildrenAfter { get; init; } - public ZoneDescriptor(string zoneName = null, string elementName = null, bool wrapBody = false) + public ZoneDescriptor(string zoneName = null, string elementName = null, bool wrapBody = false) + { + ZoneName = zoneName; + ElementName = elementName; + WrapBody = wrapBody; + } + + public async Task DisplayZoneAsync( + ICssClassHolder classHolder, + RazorPage page, + string parent) + { + if (page.Model is not IZoneHolding model || + model.Zones[ZoneName] is not { } zone) { - ZoneName = zoneName; - ElementName = elementName; - WrapBody = wrapBody; + return new HtmlString(string.Empty); } - public async Task DisplayZoneAsync( - ICssClassHolder classHolder, - RazorPage page, - string parent) + ElementName ??= "div"; + + // The zone name should already be PascalCase. + var id = ZoneName.ToCamelCase(); + var layoutClassName = string.IsNullOrEmpty(parent) + ? "layout" + ZoneName + : FormattableString.Invariant($"layout{parent}__{id}"); + + var classNames = classHolder.ConcatenateZoneClasses( + ZoneName, + layoutClassName, + LayoutElementClassName, + ChildrenBefore?.Any() != true || ChildrenAfter?.Any() != true ? LeafClassName : null); + + var body = await page.DisplayAsync(zone); + if (WrapBody) { - if (page.Model is not IZoneHolding model || - model.Zones[ZoneName] is not { } zone) - { - return new HtmlString(string.Empty); - } - - ElementName ??= "div"; - - // The zone name should already be PascalCase. - var id = ZoneName.ToCamelCase(); - var layoutClassName = string.IsNullOrEmpty(parent) - ? "layout" + ZoneName - : FormattableString.Invariant($"layout{parent}__{id}"); - - var classNames = classHolder.ConcatenateZoneClasses( - ZoneName, - layoutClassName, - LayoutElementClassName, - ChildrenBefore?.Any() != true || ChildrenAfter?.Any() != true ? LeafClassName : null); - - var body = await page.DisplayAsync(zone); - if (WrapBody) - { - // If there is no parent then "body" becomes the BEM element, otherwise there already is an element so - // "Body" becomes a suffix to that. - var bodyWrapperClass = string.IsNullOrEmpty(parent) - ? layoutClassName + "__body" - : layoutClassName + "Body"; - - // This improves accessibility by providing a main landmark, see: - // https://dequeuniversity.com/rules/axe/4.2/bypass?application=axeAPI - var elementName = ZoneName == ZoneNames.Content ? "main" : "div"; - - body = new HtmlContentBuilder() - .AppendHtml(FormattableString.Invariant($"<{elementName} class=\"{bodyWrapperClass} {LeafClassName}\">")) - .AppendHtml(body) - .AppendHtml(FormattableString.Invariant($"")); - } - - return new HtmlContentBuilder() - .AppendHtml(FormattableString.Invariant($"<{ElementName} id=\"{id}\" class=\"{classNames}\">")) - .AppendHtml(await ConcatenateAsync(classHolder, page, ChildrenBefore, parent)) + // If there is no parent then "body" becomes the BEM element, otherwise there already is an element so + // "Body" becomes a suffix to that. + var bodyWrapperClass = string.IsNullOrEmpty(parent) + ? layoutClassName + "__body" + : layoutClassName + "Body"; + + // This improves accessibility by providing a main landmark, see: + // https://dequeuniversity.com/rules/axe/4.2/bypass?application=axeAPI + var elementName = ZoneName == ZoneNames.Content ? "main" : "div"; + + body = new HtmlContentBuilder() + .AppendHtml(FormattableString.Invariant($"<{elementName} class=\"{bodyWrapperClass} {LeafClassName}\">")) .AppendHtml(body) - .AppendHtml(await ConcatenateAsync(classHolder, page, ChildrenAfter, parent)) - .AppendHtml(FormattableString.Invariant($"")); + .AppendHtml(FormattableString.Invariant($"")); } - private Task ConcatenateAsync( - ICssClassHolder classHolder, - RazorPage page, - IEnumerable zoneDescriptors, - string parent) => - zoneDescriptors == null - ? Task.FromResult(new HtmlString(string.Empty)) - : ConcatenateInnerAsync(classHolder, page, zoneDescriptors, ZoneName, parent); - - private static async Task ConcatenateInnerAsync( - ICssClassHolder classHolder, - RazorPage page, - IEnumerable zoneDescriptors, - string zoneName, - string parent) - { - var builder = new HtmlContentBuilder(); + return new HtmlContentBuilder() + .AppendHtml(FormattableString.Invariant($"<{ElementName} id=\"{id}\" class=\"{classNames}\">")) + .AppendHtml(await ConcatenateAsync(classHolder, page, ChildrenBefore, parent)) + .AppendHtml(body) + .AppendHtml(await ConcatenateAsync(classHolder, page, ChildrenAfter, parent)) + .AppendHtml(FormattableString.Invariant($"")); + } - var newParent = string.IsNullOrEmpty(parent) - ? zoneName - : FormattableString.Invariant($"{parent}__{zoneName}"); + private Task ConcatenateAsync( + ICssClassHolder classHolder, + RazorPage page, + IEnumerable zoneDescriptors, + string parent) => + zoneDescriptors == null + ? Task.FromResult(new HtmlString(string.Empty)) + : ConcatenateInnerAsync(classHolder, page, zoneDescriptors, ZoneName, parent); + + private static async Task ConcatenateInnerAsync( + ICssClassHolder classHolder, + RazorPage page, + IEnumerable zoneDescriptors, + string zoneName, + string parent) + { + var builder = new HtmlContentBuilder(); - foreach (var zoneDescriptor in zoneDescriptors) - { - _ = builder.AppendHtml(await zoneDescriptor.DisplayZoneAsync(classHolder, page, newParent)); - } + var newParent = string.IsNullOrEmpty(parent) + ? zoneName + : FormattableString.Invariant($"{parent}__{zoneName}"); - return builder; + foreach (var zoneDescriptor in zoneDescriptors) + { + _ = builder.AppendHtml(await zoneDescriptor.DisplayZoneAsync(classHolder, page, newParent)); } - public static Task DisplayZonesAsync( - ICssClassHolder classHolder, - RazorPage page, - IEnumerable zoneDescriptors) => - ConcatenateInnerAsync(classHolder, page, zoneDescriptors, zoneName: null, parent: null); + return builder; } + + public static Task DisplayZonesAsync( + ICssClassHolder classHolder, + RazorPage page, + IEnumerable zoneDescriptors) => + ConcatenateInnerAsync(classHolder, page, zoneDescriptors, zoneName: null, parent: null); } diff --git a/ResourceManagementOptionsConfiguration.cs b/ResourceManagementOptionsConfiguration.cs index 3233bbb..24bc092 100644 --- a/ResourceManagementOptionsConfiguration.cs +++ b/ResourceManagementOptionsConfiguration.cs @@ -2,34 +2,33 @@ using Microsoft.Extensions.Options; using OrchardCore.ResourceManagement; -namespace Lombiq.BaseTheme -{ - public class ResourceManagementOptionsConfiguration : IConfigureOptions - { - private const string WwwRoot = "~/" + FeatureIds.Area + "/"; - private const string Css = WwwRoot + "css/"; - private const string Js = WwwRoot + "js/"; - private const string Vendors = WwwRoot + "vendors/"; +namespace Lombiq.BaseTheme; - private static readonly ResourceManifest _manifest = new(); +public class ResourceManagementOptionsConfiguration : IConfigureOptions +{ + private const string WwwRoot = "~/" + FeatureIds.Area + "/"; + private const string Css = WwwRoot + "css/"; + private const string Js = WwwRoot + "js/"; + private const string Vendors = WwwRoot + "vendors/"; - static ResourceManagementOptionsConfiguration() - { - _manifest.DefineResource("$" + nameof(FeatureIds.Area), FeatureIds.Area); + private static readonly ResourceManifest _manifest = new(); - _manifest - .DefineStyle(ResourceNames.Site) - .SetUrl(Css + "site.min.css", Css + "site.css"); + static ResourceManagementOptionsConfiguration() + { + _manifest.DefineResource("$" + nameof(FeatureIds.Area), FeatureIds.Area); - _manifest - .DefineScript(ResourceNames.Helpers) - .SetUrl(Js + "helpers.js"); + _manifest + .DefineStyle(ResourceNames.Site) + .SetUrl(Css + "site.min.css", Css + "site.css"); - _manifest - .DefineScript("bootstrap") - .SetUrl(Vendors + "bootstrap/js/bootstrap.min.js", Vendors + "bootstrap/js/bootstrap.js"); - } + _manifest + .DefineScript(ResourceNames.Helpers) + .SetUrl(Js + "helpers.js"); - public void Configure(ResourceManagementOptions options) => options.ResourceManifests.Add(_manifest); + _manifest + .DefineScript("bootstrap") + .SetUrl(Vendors + "bootstrap/js/bootstrap.min.js", Vendors + "bootstrap/js/bootstrap.js"); } + + public void Configure(ResourceManagementOptions options) => options.ResourceManifests.Add(_manifest); } diff --git a/Services/CssClassHolder.cs b/Services/CssClassHolder.cs index 896387d..576003e 100644 --- a/Services/CssClassHolder.cs +++ b/Services/CssClassHolder.cs @@ -1,26 +1,25 @@ using System.Collections.Generic; -namespace Lombiq.BaseTheme.Services -{ - public class CssClassHolder : ICssClassHolder - { - private readonly Dictionary> _zones = new(); +namespace Lombiq.BaseTheme.Services; - public ISet Body { get; } = new HashSet(); +public class CssClassHolder : ICssClassHolder +{ + private readonly Dictionary> _zones = new(); - public void AddClassToZone(string zoneName, string className) - { - var classes = _zones.GetMaybe(zoneName); + public ISet Body { get; } = new HashSet(); - if (classes == null) - { - classes = new(); - _zones[zoneName] = classes; - } + public void AddClassToZone(string zoneName, string className) + { + var classes = _zones.GetMaybe(zoneName); - classes.Add(className); + if (classes == null) + { + classes = new(); + _zones[zoneName] = classes; } - public ISet GetZoneClasses(string zoneName) => _zones.GetMaybe(zoneName) ?? new(); + classes.Add(className); } + + public ISet GetZoneClasses(string zoneName) => _zones.GetMaybe(zoneName) ?? new(); } diff --git a/Services/ICssClassHolder.cs b/Services/ICssClassHolder.cs index 494093b..cc06c98 100644 --- a/Services/ICssClassHolder.cs +++ b/Services/ICssClassHolder.cs @@ -1,40 +1,39 @@ using System.Collections.Generic; using System.Linq; -namespace Lombiq.BaseTheme.Services +namespace Lombiq.BaseTheme.Services; + +/// +/// Service for managing CSS classes to be rendered in the template. +/// +public interface ICssClassHolder { /// - /// Service for managing CSS classes to be rendered in the template. + /// Gets the classes associated with the <body> element. /// - public interface ICssClassHolder - { - /// - /// Gets the classes associated with the <body> element. - /// - ISet Body { get; } + ISet Body { get; } - /// - /// Adds a to the zone called . - /// - void AddClassToZone(string zoneName, string className); + /// + /// Adds a to the zone called . + /// + void AddClassToZone(string zoneName, string className); - /// - /// Returns the set of classes belonging to the zone called . You can use this to - /// remove classes if needed. - /// - ISet GetZoneClasses(string zoneName); - } + /// + /// Returns the set of classes belonging to the zone called . You can use this to + /// remove classes if needed. + /// + ISet GetZoneClasses(string zoneName); +} - public static class CssClassHolderExtensions - { - /// - /// Returns the string you can insert into the zone's template. - /// - public static string ConcatenateZoneClasses(this ICssClassHolder holder, string zoneName, params string[] additionalClasses) => - holder - .GetZoneClasses(zoneName) - .Concat(additionalClasses) - .WhereNot(string.IsNullOrEmpty) - .Join(); - } +public static class CssClassHolderExtensions +{ + /// + /// Returns the string you can insert into the zone's template. + /// + public static string ConcatenateZoneClasses(this ICssClassHolder holder, string zoneName, params string[] additionalClasses) => + holder + .GetZoneClasses(zoneName) + .Concat(additionalClasses) + .WhereNot(string.IsNullOrEmpty) + .Join(); } diff --git a/Services/MainMenuWidgetFilter.cs b/Services/MainMenuWidgetFilter.cs index 82d09e4..2ac684f 100644 --- a/Services/MainMenuWidgetFilter.cs +++ b/Services/MainMenuWidgetFilter.cs @@ -10,45 +10,44 @@ using System.Threading.Tasks; using static Lombiq.BaseTheme.Constants.ZoneNames; -namespace Lombiq.BaseTheme.Services +namespace Lombiq.BaseTheme.Services; + +public class MainMenuWidgetFilter : WidgetFilterBase { - public class MainMenuWidgetFilter : WidgetFilterBase - { - private readonly INavigationManager _navigationManager; - private readonly IActionContextAccessor _actionContextAccessor; - private readonly ICssClassHolder _cssClassHolder; + private readonly INavigationManager _navigationManager; + private readonly IActionContextAccessor _actionContextAccessor; + private readonly ICssClassHolder _cssClassHolder; - protected override string ZoneName => Navigation; - protected override string ViewName => WidgetTypes.MenuWidget; - protected override bool FrontEndOnly => true; + protected override string ZoneName => Navigation; + protected override string ViewName => WidgetTypes.MenuWidget; + protected override bool FrontEndOnly => true; - public MainMenuWidgetFilter( - IAuthorizationService authorizationService, - ILayoutAccessor layoutAccessor, - IShapeFactory shapeFactory, - INavigationManager navigationManager, - IActionContextAccessor actionContextAccessor, - ICssClassHolder cssClassHolder) - : base(requiredPermission: null, authorizationService, layoutAccessor, shapeFactory) - { - _navigationManager = navigationManager; - _actionContextAccessor = actionContextAccessor; - _cssClassHolder = cssClassHolder; - } + public MainMenuWidgetFilter( + IAuthorizationService authorizationService, + ILayoutAccessor layoutAccessor, + IShapeFactory shapeFactory, + INavigationManager navigationManager, + IActionContextAccessor actionContextAccessor, + ICssClassHolder cssClassHolder) + : base(requiredPermission: null, authorizationService, layoutAccessor, shapeFactory) + { + _navigationManager = navigationManager; + _actionContextAccessor = actionContextAccessor; + _cssClassHolder = cssClassHolder; + } - protected override async Task GetViewModelAsync() - { - // Add the