From 889fbba6d4329168cf269d603b0fbfa2ab5d79a7 Mon Sep 17 00:00:00 2001 From: akdalin Date: Wed, 19 Nov 2025 07:49:59 +0000 Subject: [PATCH 1/2] Build v10 header component. Amend LinkViewModel to allow for nullable inputs. --- .../ViewComponents/HeaderViewComponent.cs | 37 ++++++ .../ViewModels/HeaderViewModel.cs | 89 +++++++++++++ .../ViewModels/LinkViewModel.cs | 6 +- .../Shared/Components/Header/Default.cshtml | 124 ++++++++++++++++++ 4 files changed, 253 insertions(+), 3 deletions(-) create mode 100644 NHSUKFrontendRazor/ViewComponents/HeaderViewComponent.cs create mode 100644 NHSUKFrontendRazor/ViewModels/HeaderViewModel.cs create mode 100644 NHSUKFrontendRazor/Views/Shared/Components/Header/Default.cshtml diff --git a/NHSUKFrontendRazor/ViewComponents/HeaderViewComponent.cs b/NHSUKFrontendRazor/ViewComponents/HeaderViewComponent.cs new file mode 100644 index 0000000..50a447e --- /dev/null +++ b/NHSUKFrontendRazor/ViewComponents/HeaderViewComponent.cs @@ -0,0 +1,37 @@ +namespace NHSUKFrontendRazor.ViewComponents +{ + using Microsoft.AspNetCore.Mvc; + using NHSUKFrontendRazor.ViewModels; + + /// + /// A ViewComponent that renders a Header. + /// + public class HeaderViewComponent : ViewComponent + { + public IViewComponentResult Invoke( + Organisation organisationDetails, + bool? isService = true, + AccountLinks? accountLinks = null, + List? navigationLinks = null, + Dictionary? theme = null, + LinkViewModel? searchLink = null, + string? searchFolder = null, + string? searchNavView = null, + string? searchControllerName = null) + { + theme ??= HeaderTheme.BLUE; + + accountLinks ??= new AccountLinks + ( + new LinkViewModel("myaccount", null, "My account", null), + new LinkViewModel("Home", "Logout", "Log out", null), + null + ); + + + var model = new HeaderViewModel(organisationDetails, isService, accountLinks, navigationLinks, theme, searchLink, searchFolder, searchNavView, searchControllerName); + + return View(model); + } + } +} diff --git a/NHSUKFrontendRazor/ViewModels/HeaderViewModel.cs b/NHSUKFrontendRazor/ViewModels/HeaderViewModel.cs new file mode 100644 index 0000000..a4183ca --- /dev/null +++ b/NHSUKFrontendRazor/ViewModels/HeaderViewModel.cs @@ -0,0 +1,89 @@ +namespace NHSUKFrontendRazor.ViewModels +{ + public class HeaderViewModel + { + public HeaderViewModel( + Organisation organisationDetails, + bool? isService, + AccountLinks? accountLinks, + List? navigationLinks, + Dictionary theme, + LinkViewModel searchLink, + string? searchFolder, + string? searchNavView, + string? searchControllerName + ) + { + OrganisationDetails = organisationDetails; + IsService = isService; + AccountLinks = accountLinks; + NavigationLinks = navigationLinks; + Theme = theme; + SearchLink = searchLink; + SearchFolder = searchFolder; + SearchNavView = searchNavView; + SearchControllerName = searchControllerName; + } + + public Organisation OrganisationDetails { get; set; } + + public bool? IsService { get; set; } + + public AccountLinks? AccountLinks { get; set; } + + public List? NavigationLinks { get; set; } + + public Dictionary Theme { get; set; } + + public LinkViewModel? SearchLink { get; set; } + + public string? SearchFolder { get; set; } + + public string? SearchNavView { get; set; } + + public string? SearchControllerName { get; set; } + + } + + public static class HeaderTheme + { + public static Dictionary BLUE = new Dictionary { { "header", "nhsuk-header" }, { "navigation", "nhsuk-header__navigation" } }; + public static Dictionary WHITE = new Dictionary { { "header", "nhsuk-header nhsuk-header--white" }, { "navigation", "nhsuk-header__navigation nhsuk-header__navigation--white" } }; + public static Dictionary MIXED = new Dictionary { { "header", "nhsuk-header nhsuk-header--white" }, { "navigation", "nhsuk-header__navigation" } }; + } + + public class Organisation + { + public Organisation( + string name, + string split, + string descriptor) + { + Name = name; + Split = split; + Descriptor = descriptor; + } + + public string? Name { get; set; } + public string? Split { get; set; } + public string? Descriptor { get; set; } + } + + public class AccountLinks + { + public AccountLinks( + LinkViewModel account, + LinkViewModel logout, + List? additionalLinks + ) + { + Account = account; + Logout = logout; + AdditionalLinks = additionalLinks; + } + + public LinkViewModel Account { get; set; } + public LinkViewModel Logout { get; set; } + public List? AdditionalLinks { get; set; } + } +} diff --git a/NHSUKFrontendRazor/ViewModels/LinkViewModel.cs b/NHSUKFrontendRazor/ViewModels/LinkViewModel.cs index ae7ce42..09d9503 100644 --- a/NHSUKFrontendRazor/ViewModels/LinkViewModel.cs +++ b/NHSUKFrontendRazor/ViewModels/LinkViewModel.cs @@ -4,15 +4,15 @@ namespace NHSUKFrontendRazor.ViewModels public class LinkViewModel { - public readonly string AspAction; + public readonly string? AspAction; public readonly string AspController; public readonly string LinkText; - public readonly Dictionary AspAllRouteData; + public readonly Dictionary? AspAllRouteData; - public LinkViewModel(string aspController, string aspAction, string linkText, Dictionary aspAllRouteData) + public LinkViewModel(string aspController, string? aspAction, string linkText, Dictionary? aspAllRouteData) { AspAction = aspAction; AspController = aspController; diff --git a/NHSUKFrontendRazor/Views/Shared/Components/Header/Default.cshtml b/NHSUKFrontendRazor/Views/Shared/Components/Header/Default.cshtml new file mode 100644 index 0000000..3c59446 --- /dev/null +++ b/NHSUKFrontendRazor/Views/Shared/Components/Header/Default.cshtml @@ -0,0 +1,124 @@ +@using NHSUKFrontendRazor.ViewModels +@model HeaderViewModel + +@{ + var org = Model.OrganisationDetails; +} + + \ No newline at end of file From e18bbda445d99676aa69d9180416b743625e3c1d Mon Sep 17 00:00:00 2001 From: akdalin Date: Wed, 19 Nov 2025 08:08:03 +0000 Subject: [PATCH 2/2] Add xml documentaion --- .../ViewComponents/HeaderViewComponent.cs | 3 +- .../ViewModels/HeaderViewModel.cs | 84 +++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/NHSUKFrontendRazor/ViewComponents/HeaderViewComponent.cs b/NHSUKFrontendRazor/ViewComponents/HeaderViewComponent.cs index 50a447e..7fcc063 100644 --- a/NHSUKFrontendRazor/ViewComponents/HeaderViewComponent.cs +++ b/NHSUKFrontendRazor/ViewComponents/HeaderViewComponent.cs @@ -4,7 +4,8 @@ namespace NHSUKFrontendRazor.ViewComponents using NHSUKFrontendRazor.ViewModels; /// - /// A ViewComponent that renders a Header. + /// A ViewComponent that renders the NHS header, which provides consistent branding, navigation, search, and account management links. + /// The header is a key part of the NHS.UK frontend design system. /// public class HeaderViewComponent : ViewComponent { diff --git a/NHSUKFrontendRazor/ViewModels/HeaderViewModel.cs b/NHSUKFrontendRazor/ViewModels/HeaderViewModel.cs index a4183ca..890dd24 100644 --- a/NHSUKFrontendRazor/ViewModels/HeaderViewModel.cs +++ b/NHSUKFrontendRazor/ViewModels/HeaderViewModel.cs @@ -2,6 +2,18 @@ namespace NHSUKFrontendRazor.ViewModels { public class HeaderViewModel { + /// + /// Initializes a new instance of the class. + /// + /// The details of the organisation for branding. + /// Indicates if the header is for a service or an organisation. + /// Links related to the user's account. + /// The primary navigation links for the header. + /// The color theme for the header and navigation. + /// A simple link for the header search form. + /// The folder for a component-based search view. + /// The view name for a component-based search. + /// The controller name for a component-based search. public HeaderViewModel( Organisation organisationDetails, bool? isService, @@ -25,26 +37,56 @@ public HeaderViewModel( SearchControllerName = searchControllerName; } + /// + /// Gets or sets the organisation details for header branding. + /// public Organisation OrganisationDetails { get; set; } + /// + /// Gets or sets a value indicating whether the header is for a service. + /// public bool? IsService { get; set; } + /// + /// Gets or sets the links for the account section of the header. + /// public AccountLinks? AccountLinks { get; set; } + /// + /// Gets or sets the list of primary navigation links. + /// public List? NavigationLinks { get; set; } + /// + /// Gets or sets the theme for the header, which controls CSS classes. + /// public Dictionary Theme { get; set; } + /// + /// Gets or sets the view model for a simple search link in the header. + /// public LinkViewModel? SearchLink { get; set; } + /// + /// Gets or sets the folder name for invoking a search ViewComponent. + /// public string? SearchFolder { get; set; } + /// + /// Gets or sets the view name for invoking a search ViewComponent. + /// public string? SearchNavView { get; set; } + /// + /// Gets or sets the controller name for invoking a search ViewComponent. + /// public string? SearchControllerName { get; set; } } + /// + /// Provides predefined themes for the NHS header component. + /// public static class HeaderTheme { public static Dictionary BLUE = new Dictionary { { "header", "nhsuk-header" }, { "navigation", "nhsuk-header__navigation" } }; @@ -52,8 +94,17 @@ public static class HeaderTheme public static Dictionary MIXED = new Dictionary { { "header", "nhsuk-header nhsuk-header--white" }, { "navigation", "nhsuk-header__navigation" } }; } + /// + /// Represents the details of an NHS organisation for display in the header. + /// public class Organisation { + /// + /// Initializes a new instance of the class. + /// + /// The main name of the organisation. + /// The secondary part of the organisation's name, often a location or type. + /// A descriptor for the organisation, such as a region or trust type. public Organisation( string name, string split, @@ -64,13 +115,35 @@ public Organisation( Descriptor = descriptor; } + /// + /// Gets or sets the primary name of the organisation (e.g., "Anytown"). + /// public string? Name { get; set; } + + /// + /// Gets or sets the split part of the organisation name (e.g., "Clinical Commissioning Group"). + /// public string? Split { get; set; } + + /// + /// Gets or sets the descriptor for the organisation (e.g., "NHS Trust"). + /// public string? Descriptor { get; set; } } + + /// + /// Represents the set of links related to user account management in the header. + /// public class AccountLinks { + + /// + /// Initializes a new instance of the class. + /// + /// The primary link to the user's account page. + /// The link to log the user out. + /// A list of any additional links related to the user's account. public AccountLinks( LinkViewModel account, LinkViewModel logout, @@ -82,8 +155,19 @@ public AccountLinks( AdditionalLinks = additionalLinks; } + /// + /// Gets or sets the primary link to the user's account page. + /// public LinkViewModel Account { get; set; } + + /// + /// Gets or sets the link used for logging out. + /// public LinkViewModel Logout { get; set; } + + /// + /// Gets or sets a list of additional account-related links. + /// public List? AdditionalLinks { get; set; } } }