diff --git a/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavViewModel.cs b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavViewModel.cs new file mode 100644 index 000000000..28ae8f060 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavViewModel.cs @@ -0,0 +1,21 @@ +namespace LearningHub.Nhs.WebUI.Models.SideMenu +{ + using System.Collections.Generic; + using Microsoft.AspNetCore.Routing; + + /// + /// Defines the . + /// + public class SideNavViewModel + { + /// + /// Gets or sets the Groups. + /// + public List Groups { get; set; } = []; + + /// + /// Gets or sets the RouteData. + /// + public RouteValueDictionary RouteData { get; set; } = []; + } +} diff --git a/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationConfiguration.cs b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationConfiguration.cs new file mode 100644 index 000000000..9f95fc173 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationConfiguration.cs @@ -0,0 +1,114 @@ +namespace LearningHub.Nhs.WebUI.Models.SideMenu +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Microsoft.AspNetCore.Routing; + + /// + /// Defines the . + /// + public static class SideNavigationConfiguration + { + /// + /// GetGroupedMenus. + /// + /// IEnumerable. + public static IEnumerable GetGroupedMenus() + { + return new List + { + new SideNavigationGroup + { + GroupTitle = "Account", + Items = new List + { + new SideNavigationItem + { + Text = "Personal details", + Controller = "Account", + Action = "PersonalDetails", + IsActive = route => MatchRoute(route, "Account", "PersonalDetails"), + }, + new SideNavigationItem + { + Text = "My employment", + Controller = "Account", + Action = "MyEmployment", + IsActive = route => MatchRoute(route, "Account", "MyEmployment"), + }, + new SideNavigationItem + { + Text = "Security", + Controller = "Account", + Action = "Security", + IsActive = route => MatchRoute(route, "Account", "Security"), + }, + new SideNavigationItem + { + Text = "Notification", + Controller = "Account", + Action = "Notification", + IsActive = route => MatchRoute(route, "Account", "Notification"), + }, + }, + }, + new SideNavigationGroup + { + GroupTitle = "Activity", + Items = new List + { + new SideNavigationItem + { + Text = "Recent", + Controller = "Activity", + Action = "Recent", + IsActive = route => MatchRoute(route, "Activity", "Recent"), + }, + new SideNavigationItem + { + Text = "Bookmark", + Controller = "Activity", + Action = "Bookmark", + IsActive = route => MatchRoute(route, "Activity", "Bookmark"), + }, + new SideNavigationItem + { + Text = "Certificates", + Controller = "Activity", + Action = "Certificates", + IsActive = route => MatchRoute(route, "Activity", "Certificates"), + }, + new SideNavigationItem + { + Text = "Learning history", + Controller = "Activity", + Action = "Learninghistory", + IsActive = route => MatchRoute(route, "Activity", "Learninghistory"), + }, + }, + }, + }; + } + + /// + /// GetMenuGroupByTitle. + /// + /// title. + /// string. + public static SideNavigationGroup? GetMenuGroupByTitle(string title) + { + return GetGroupedMenus().FirstOrDefault(g => + string.Equals(g.GroupTitle, title, StringComparison.OrdinalIgnoreCase)); + } + + private static bool MatchRoute(RouteValueDictionary route, string controller, string action) + { + var currentController = route["controller"]?.ToString(); + var currentAction = route["action"]?.ToString(); + + return string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase) && + string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase); + } + } +} diff --git a/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationGroup.cs b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationGroup.cs new file mode 100644 index 000000000..ff35ed8f7 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationGroup.cs @@ -0,0 +1,20 @@ +namespace LearningHub.Nhs.WebUI.Models.SideMenu +{ + using System.Collections.Generic; + + /// + /// Defines the . + /// + public class SideNavigationGroup + { + /// + /// Gets or sets a value indicating GroupTitle. + /// + public string GroupTitle { get; set; } = string.Empty; + + /// + /// Gets or sets a Items. + /// + public List Items { get; set; } = []; + } +} diff --git a/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationItem.cs b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationItem.cs new file mode 100644 index 000000000..156e90893 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationItem.cs @@ -0,0 +1,31 @@ +namespace LearningHub.Nhs.WebUI.Models.SideMenu +{ + using System; + using Microsoft.AspNetCore.Routing; + + /// + /// Defines the . + /// + public class SideNavigationItem + { + /// + /// Gets or sets a value indicating Text. + /// + public string Text { get; set; } = string.Empty; + + /// + /// Gets or sets a value indicating Controller. + /// + public string Controller { get; set; } = string.Empty; + + /// + /// Gets or sets a value indicating Action. + /// + public string Action { get; set; } = "Index"; + + /// + /// Gets or sets a value indicating IsActiven. + /// + public Func IsActive { get; set; } + } +} diff --git a/LearningHub.Nhs.WebUI/Styles/nhsuk/layout.scss b/LearningHub.Nhs.WebUI/Styles/nhsuk/layout.scss index 25b84b7d4..671d7316b 100644 --- a/LearningHub.Nhs.WebUI/Styles/nhsuk/layout.scss +++ b/LearningHub.Nhs.WebUI/Styles/nhsuk/layout.scss @@ -1,4 +1,3 @@ -@use "../abstracts/all" as *; @use "nhsuk" as *; body { @@ -104,6 +103,129 @@ li.autosuggestion-option:last-of-type { border-bottom: none !important; } +/* side navigation styles */ +.side-nav__list { + list-style: none; + margin: 0; + padding: 0; + border-right: 1px solid #d8dde0; +} + +.side-nav__item { + padding: 12px 16px; + border-bottom: 1px solid #d8dde0; +} + +.side-nav__item--active a { + font-weight: bold; + text-decoration: underline; +} + +.side-nav__toggle, +.side-nav__close { + display: none; + background: #e8f0f7; + color: #005eb8; + border: none; + font-size: 16px; + padding: 10px 16px; + border-radius: 25px; + margin: 10px; + cursor: pointer; +} + +.menu-icon { + display: inline-flex; + justify-content: center; + align-items: center; + width: 20px; + height: 20px; + box-sizing: border-box; + padding: 0; + border: 1px solid #d8dde0; + border-radius: 50%; + background-color: white; + transition: background-color 0.3s ease; +} + + +.side-nav__container { + position: fixed; + top: 0; + left: 0; + width: 80%; + max-width: 320px; + height: 100%; + background-color: #e8f0f7; + border-right: 40px solid #005eb8; + box-sizing: border-box; + transform: translateX(-100%); + transition: transform 0.3s ease-in-out; + z-index: 1000; + box-shadow: 4px 0 10px rgba(0, 0, 0, 0.1); + display: flex; + flex-direction: column; + overflow: visible; +} + + +.side-nav__close { + position: relative; + right: -35px; + z-index: 2; + align-self: flex-end; + text-align: right; +} + + +.nav-toggle:checked + label.side-nav__toggle + .side-nav__container { + transform: translateX(0); +} + + +.nav-toggle:checked + label .menu-icon { + transform: rotate(180deg); +} + + + +/* large desktop */ +@media (min-width: px2rem(990)) { + + .nhsuk-header__navigation-item--current a { + border-bottom: 4px solid $nhsuk-grey-lighter; + font-weight: normal; + } + + .nhsuk-header__navigation-link { + position: relative; + } + + .nhsuk-header__navigation-item:last-child { + margin-right: 16px; + } +} + +@media (min-width: px2rem(768)) { + .nav-toggle, + .side-nav__toggle, + .side-nav__close { + display: none !important; + } + + .side-nav__container { + position: static; + transform: none !important; + height: auto; + box-shadow: none; + display: block; + width: auto; + background-color: #ffffff; + border-right: none; + } +} + + /* small desktop */ @media (max-width: px2rem(989)) { .autosuggestion-menu { @@ -115,11 +237,114 @@ li.autosuggestion-option:last-of-type { .autosuggestion-menu { top: 100%; } + + .nhsuk-header__not-mobile { + display: none; + } + + .nhsuk-header__mobile-only-nav { + display: flex; + order: 1; + justify-content: space-around; + gap: 0 px2rem(16); + align-items: flex-start; + flex-wrap: wrap; + width: px2rem(166); + } + + .nhsuk-header__mobile-only-nav .nhsuk-header__menu { + margin-right: px2rem(12); + } + + .nhsuk-header__mobile-only-nav .nhsuk-header__search-toggle { + margin-left: px2rem(12); + } + + .nhsuk-header__break { + display: none; + } + + .nhsuk-header__mobile-break { + display: block; + width: 100%; + height: 0; + } + + .nhsuk-header__link--service { + flex-direction: column; + align-items: flex-start; + } + + .nhsuk-header__notification-dot { + top: px2rem(13); + left: px2rem(100); + } + + .nhsuk-header__service-name { + padding: px2rem(12) 0 0; + } + + .nhsuk-header__search-toggle { + position: relative; + height: px2rem(40); + order: 2; + padding: px2rem(7) px2rem(10) 0; + margin: 0 + } + + .nhsuk-header__search .nhsuk-search__submit { + padding-top: nhsuk-spacing(1); + } + + .nhsuk-header__menu { + order: 3; + } + + .nhsuk-header__search { + order: 4; + width: 100%; + flex-grow: 1; + margin: px2rem(16) px2rem(-16) 0; + border-bottom: 1px solid $color_nhsuk-grey-4; + } + + #header-mobile-search-control { + display: block; + opacity: 0; + position: absolute; + } + + #header-mobile-search-control:checked ~ .nhsuk-header__search .nhsuk-header__search-wrap { + display: block; + } + + .nhsuk-width-container.nhsuk-header__container.app-width-container { + padding-bottom: 0; + } + + + .side-nav__toggle, .side-nav__close { + display: inline-block; + } + + .side-nav__close { + background-color: transparent; + } + + .nav-toggle:checked + label.side-nav__toggle .menu-icon, + .nav-toggle:checked + label.side-nav__toggle + .side-nav__container .side-nav__close .menu-icon { + background-color: #e8f0f7; + } } /* mobile */ @media (max-width: px2rem(640)) { .autosuggestion-menu { top: 100%; + + } +} + } } + diff --git a/LearningHub.Nhs.WebUI/ViewComponents/SideNavViewComponent.cs b/LearningHub.Nhs.WebUI/ViewComponents/SideNavViewComponent.cs new file mode 100644 index 000000000..232e54349 --- /dev/null +++ b/LearningHub.Nhs.WebUI/ViewComponents/SideNavViewComponent.cs @@ -0,0 +1,36 @@ +namespace LearningHub.Nhs.WebUI.ViewComponents +{ + using System.Collections.Generic; + using System.Linq; + using LearningHub.Nhs.WebUI.Models.SideMenu; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + + /// + /// Initializes a new instance of the class. + /// + public class SideNavViewComponent : ViewComponent + { + /// + /// The Invoke. + /// + /// group Title. + /// A representing the result of the synchronous operation. + public IViewComponentResult Invoke(string? groupTitle = null) + { + var routeData = this.ViewContext.RouteData.Values; + var groups = string.IsNullOrEmpty(groupTitle) + ? SideNavigationConfiguration.GetGroupedMenus().ToList() + : SideNavigationConfiguration.GetMenuGroupByTitle(groupTitle) is { } singleGroup + ? new List { singleGroup } + : new List(); + + var viewModel = new SideNavViewModel + { + Groups = groups, + RouteData = routeData, + }; + return this.View(viewModel); + } + } +} diff --git a/LearningHub.Nhs.WebUI/Views/Shared/Components/SideNav/Default.cshtml b/LearningHub.Nhs.WebUI/Views/Shared/Components/SideNav/Default.cshtml new file mode 100644 index 000000000..bef06e64d --- /dev/null +++ b/LearningHub.Nhs.WebUI/Views/Shared/Components/SideNav/Default.cshtml @@ -0,0 +1,33 @@ +@using LearningHub.Nhs.WebUI.Models.SideMenu +@model SideNavViewModel + +@foreach (var group in Model.Groups) +{ + + + + + +
+ + + +
+ +}