From 325cb339fdd5f4acce417e76d25eb5943132a5fa Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sat, 20 Jun 2026 19:48:20 +0100 Subject: [PATCH] nav: highlight active page with active class and aria-current Add PageHelpers.ActivePage extension and apply it to top-level nav items and the Account/Register + Account/Signin items in _LoginPartial, so the current route gets the active class and aria-current="page" for accessibility. --- src/Yavsc.Org/Helpers/PageHelpers.cs | 39 +++++++++++++++++++ .../Views/Shared/_LoginPartial.cshtml | 4 +- src/Yavsc.Org/Views/Shared/_Nav.cshtml | 8 ++-- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/Yavsc.Org/Helpers/PageHelpers.cs b/src/Yavsc.Org/Helpers/PageHelpers.cs index 670a9ad0..5cec1298 100644 --- a/src/Yavsc.Org/Helpers/PageHelpers.cs +++ b/src/Yavsc.Org/Helpers/PageHelpers.cs @@ -1,12 +1,51 @@ using System; using System.Collections.Generic; +using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.Extensions.Localization; namespace Yavsc.Server.Helpers { public static class PageHelpers { + /// + /// Returns "active" aria-current="page" when the current route matches the given + /// controller/action, otherwise an empty string. Use as an attribute value + /// inside a <a class="nav-link @..."> element. + /// Pass an empty controller (or "Home" with action "Index") to match the site root. + /// + public static IHtmlContent ActivePage(this ViewContext viewContext, string controller, string action = null) + { + var route = viewContext?.RouteData.Values; + if (route == null) return HtmlString.Empty; + + var currentController = route["controller"] as string; + var currentAction = route["action"] as string; + + // Normalize: empty or "Home" + ("Index" or null) both target the site root. + bool isHome = string.IsNullOrEmpty(controller) + || (string.Equals(controller, "Home", StringComparison.Ordinal) + && (action == null || string.Equals(action, "Index", StringComparison.Ordinal))); + + bool isCurrent; + if (isHome) + { + isCurrent = string.IsNullOrEmpty(currentController) + || string.Equals(currentController, "Home", StringComparison.Ordinal) + && (currentAction == null || string.Equals(currentAction, "Index", StringComparison.Ordinal)); + } + else + { + isCurrent = string.Equals(currentController, controller, StringComparison.Ordinal) + && (action == null || string.Equals(currentAction, action, StringComparison.Ordinal)); + } + + return isCurrent + ? (IHtmlContent)new HtmlString("active\" aria-current=\"page") + : HtmlString.Empty; + } + public static List CreateSelectListItems (this IStringLocalizer localisation, Type enumType, object selectedValue =null) { string selectedName = (selectedValue != null) ? enumType.GetEnumName(selectedValue) : null; diff --git a/src/Yavsc.Org/Views/Shared/_LoginPartial.cshtml b/src/Yavsc.Org/Views/Shared/_LoginPartial.cshtml index c3267c5d..8c41860a 100644 --- a/src/Yavsc.Org/Views/Shared/_LoginPartial.cshtml +++ b/src/Yavsc.Org/Views/Shared/_LoginPartial.cshtml @@ -49,10 +49,10 @@ else { } diff --git a/src/Yavsc.Org/Views/Shared/_Nav.cshtml b/src/Yavsc.Org/Views/Shared/_Nav.cshtml index 842d42e5..23dc76fb 100644 --- a/src/Yavsc.Org/Views/Shared/_Nav.cshtml +++ b/src/Yavsc.Org/Views/Shared/_Nav.cshtml @@ -13,10 +13,10 @@ background-attachment: fixed;">