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 4cb2822fe..79762964b 100644 --- a/LearningHub.Nhs.WebUI/Styles/nhsuk/layout.scss +++ b/LearningHub.Nhs.WebUI/Styles/nhsuk/layout.scss @@ -254,6 +254,94 @@ button[data-toggle="modal"] { 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)) { @@ -271,6 +359,26 @@ li.autosuggestion-option:last-of-type { } } +@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)) { @@ -495,6 +603,20 @@ li.autosuggestion-option:last-of-type { .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 */ @@ -596,5 +718,5 @@ li.autosuggestion-option:last-of-type { .autosuggestion-menu { top: 100%; - } + } } \ No newline at end of file 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) +{ + + + + + +
+ + + +
+ +}