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)
+{
+
+
+
+
+
+
+
+
+
+
+
+}