From d18d80ca0314c005db69f8416feca64207029245 Mon Sep 17 00:00:00 2001 From: Patrick Cartlidge Date: Mon, 16 Dec 2024 14:46:22 +0000 Subject: [PATCH] js functionality of accoridon within nav --- src/javascripts/application.mjs | 6 +- .../components/mobile-navigation.mjs | 102 ++++++++++++++++++ .../components/_mobile-navigation.scss | 44 ++++++++ src/stylesheets/components/_navigation.scss | 10 ++ src/stylesheets/main.scss | 1 + views/partials/_mobile-navigation.njk | 13 +++ views/partials/_navigation.njk | 14 +-- views/partials/_sub-navigation-items.njk | 2 +- 8 files changed, 182 insertions(+), 10 deletions(-) create mode 100644 src/javascripts/components/mobile-navigation.mjs create mode 100644 src/stylesheets/components/_mobile-navigation.scss create mode 100644 views/partials/_mobile-navigation.njk diff --git a/src/javascripts/application.mjs b/src/javascripts/application.mjs index 878882e013..758d2e5e49 100644 --- a/src/javascripts/application.mjs +++ b/src/javascripts/application.mjs @@ -20,7 +20,7 @@ import CookiesPage from './components/cookies-page.mjs' import Copy from './components/copy.mjs' import EmbedCard from './components/embed-card.mjs' import ExampleFrame from './components/example-frame.mjs' -import Navigation from './components/navigation.mjs' +import MobileNavigation from './components/mobile-navigation.mjs' import OptionsTable from './components/options-table.mjs' import ScrollContainer from './components/scroll-container.mjs' import Search from './components/search.mjs' @@ -54,8 +54,8 @@ createAll(AppTabs) createAll(Copy) new OptionsTable() -// Initialise mobile navigation -createAll(Navigation) +// Initialise mobile navigation (again) +createAll(MobileNavigation) // Initialise scrollable container handling createAll(ScrollContainer) diff --git a/src/javascripts/components/mobile-navigation.mjs b/src/javascripts/components/mobile-navigation.mjs new file mode 100644 index 0000000000..5552524399 --- /dev/null +++ b/src/javascripts/components/mobile-navigation.mjs @@ -0,0 +1,102 @@ +import { Component } from 'govuk-frontend' + +/** + * Mobile Navigation enhancement for Service Navigation component + */ +class MobileNavigation extends Component { + static moduleName = 'app-mobile-navigation' + + /** + * @param {Element} $root - HTML element + */ + constructor($root) { + super($root) + + this.templates = this.$root.querySelectorAll( + '.app-mobile-navigation__template' + ) + this.links = this.$root.querySelectorAll('a') + + Array.from(this.templates).forEach((template) => { + const templateClone = template.content.cloneNode(true) + let link + + if (template.parentNode.tagName === 'A') { + link = template.parentNode + link.removeChild(template) + } else { + link = template.parentNode.parentNode + template.parentNode.removeChild(template) + } + + const button = document.createElement('button') + button.classList.add('govuk-service-navigation__link') + button.classList.add('app-mobile-navigation__toggle-button') + button.setAttribute( + 'aria-expanded', + String( + link.parentNode.classList.contains( + 'govuk-service-navigation__item--active' + ) + ) + ) + button.textContent = link.textContent + + link.insertAdjacentElement('afterend', templateClone.firstElementChild) + link.insertAdjacentElement('afterend', button) + }) + + // A global const for storing a matchMedia instance which we'll use to detect when a screen size change happens + // Set the matchMedia to the govuk-frontend tablet breakpoint + + const x = getComputedStyle(document.documentElement).getPropertyValue( + '--govuk-frontend-breakpoint-tablet' + ) + + this.mql = window.matchMedia(`(min-width: ${x})`) + + // MediaQueryList.addEventListener isn't supported by Safari < 14 so we need + // to be able to fall back to the deprecated MediaQueryList.addListener + if ('addEventListener' in this.mql) { + this.mql.addEventListener('change', () => this.setHiddenStates()) + } else { + // @ts-expect-error Property 'addListener' does not exist + this.mql.addListener(() => this.setHiddenStates()) + } + + this.setHiddenStates() + this.setEventListener() + } + + /** + * Set up event delegation for button clicks + */ + setEventListener() { + this.$root.addEventListener( + 'click', + (e) => { + if (e.target.tagName === 'BUTTON') { + if (e.target.getAttribute('aria-expanded') === 'true') { + e.target.setAttribute('aria-expanded', 'false') + } else { + e.target.setAttribute('aria-expanded', 'true') + } + } + }, + { bubbles: true } + ) + } + + /** + * Hide links if viewport is below tablet + */ + setHiddenStates() { + if (!this.mql.matches) { + this.links.forEach((a) => a.setAttribute('hidden', '')) + } else { + this.links.forEach((a) => a.removeAttribute('hidden')) + } + } +} + +export default MobileNavigation diff --git a/src/stylesheets/components/_mobile-navigation.scss b/src/stylesheets/components/_mobile-navigation.scss new file mode 100644 index 0000000000..9d31c122ae --- /dev/null +++ b/src/stylesheets/components/_mobile-navigation.scss @@ -0,0 +1,44 @@ +.app-mobile-navigation__toggle-button { + @include govuk-media-query($from: tablet) { + display: none; + } + position: relative; + padding: 0; + border: 0; + + background: none; + font-size: inherit; +} + +.app-mobile-navigation__toggle-button::after { + content: ""; + box-sizing: border-box; + display: block; + position: absolute; + right: govuk-px-to-rem(-14px); + bottom: govuk-px-to-rem(10px); + width: govuk-px-to-rem(6px); + height: govuk-px-to-rem(6px); + border-top: govuk-px-to-rem(2px) solid; + border-right: govuk-px-to-rem(2px) solid; +} + +.app-mobile-navigation__toggle-button[aria-expanded="false"]::after { + transform: rotate(135deg); +} + +.app-mobile-navigation__toggle-button[aria-expanded="false"] ~ .app-navigation__list { + display: none; +} + +.app-mobile-navigation__toggle-button[aria-expanded="true"]::after { + transform: rotate(-45deg); +} + +.app-mobile-navigation__toggle-button[aria-expanded="true"] ~ .app-navigation__list { + @include govuk-media-query($until: tablet) { + display: block; + } + + display: none; +} diff --git a/src/stylesheets/components/_navigation.scss b/src/stylesheets/components/_navigation.scss index 01dca33300..17865e471e 100644 --- a/src/stylesheets/components/_navigation.scss +++ b/src/stylesheets/components/_navigation.scss @@ -1,5 +1,15 @@ $navigation-height: 50px; +.app-navigation__list-toggle { + @include govuk-media-query($from: tablet) { + display: none; + } +} + +.js-app-navigation__list--hidden { + display: none; +} + .app-navigation { border-bottom: 1px solid $govuk-border-colour; background-color: $app-light-grey; diff --git a/src/stylesheets/main.scss b/src/stylesheets/main.scss index af7ef73945..3aedd88a27 100644 --- a/src/stylesheets/main.scss +++ b/src/stylesheets/main.scss @@ -59,6 +59,7 @@ $app-code-color: #d13118; @import "components/highlight"; @import "components/image-card"; @import "components/masthead"; +@import "components/mobile-navigation"; @import "components/navigation"; @import "components/options"; @import "components/page-navigation"; diff --git a/views/partials/_mobile-navigation.njk b/views/partials/_mobile-navigation.njk new file mode 100644 index 0000000000..a042358d7f --- /dev/null +++ b/views/partials/_mobile-navigation.njk @@ -0,0 +1,13 @@ +{% macro mobileNavigation(params) %} + {% if params.items %} + + {% endif %} +{% endmacro %} \ No newline at end of file diff --git a/views/partials/_navigation.njk b/views/partials/_navigation.njk index c1e8b6d92f..77c0b0c9df 100644 --- a/views/partials/_navigation.njk +++ b/views/partials/_navigation.njk @@ -1,5 +1,5 @@ {% from "govuk/components/service-navigation/macro.njk" import govukServiceNavigation %} -{% from "_sub-navigation-items.njk" import subNavigationItems %} +{% from "_mobile-navigation.njk" import mobileNavigation %} {% set navigationItems = [] %} @@ -7,10 +7,10 @@ {% set navItem = {} %} {% if item.items %} - {% set subNavItemHtml = subNavigationItems({ items: item.items }) %} + {% set subNavItemHtml = mobileNavigation({ items: item.items }) %} {% set navItem = { href: item.href, - html: item.text + '', + html: item.text + '', active: permalink and permalink.startsWith(item.url), current: permalink === item.url } %} @@ -26,6 +26,8 @@ {% set navigationItems = navigationItems.concat(navItem) %} {% endfor %} -{{ govukServiceNavigation({ - navigation: navigationItems -}) }} \ No newline at end of file +
+ {{ govukServiceNavigation({ + navigation: navigationItems + }) }} +
diff --git a/views/partials/_sub-navigation-items.njk b/views/partials/_sub-navigation-items.njk index 22061a7d0d..031343a361 100644 --- a/views/partials/_sub-navigation-items.njk +++ b/views/partials/_sub-navigation-items.njk @@ -1,6 +1,6 @@ {% macro subNavigationItems(params) %} {% if params.items %} -