From 8da2cb3d2487401ece2ad84bedf7254e1951c2d9 Mon Sep 17 00:00:00 2001 From: alex-ju Date: Mon, 30 Apr 2018 13:14:19 +0100 Subject: [PATCH] Add header component --- src/header/_header.scss | 290 +++++++++++++++++++++++++++++ src/header/header.js | 57 ++++++ src/header/header.njk | 3 + src/header/header.yaml | 132 +++++++++++++ src/header/index.njk | 167 +++++++++++++++++ src/header/macro.njk | 3 + src/header/template.njk | 79 ++++++++ src/icons/govuk-logotype-crown.png | Bin 0 -> 952 bytes 8 files changed, 731 insertions(+) create mode 100644 src/header/_header.scss create mode 100644 src/header/header.js create mode 100644 src/header/header.njk create mode 100644 src/header/header.yaml create mode 100644 src/header/index.njk create mode 100644 src/header/macro.njk create mode 100644 src/header/template.njk create mode 100644 src/icons/govuk-logotype-crown.png diff --git a/src/header/_header.scss b/src/header/_header.scss new file mode 100644 index 0000000000..caccd0f406 --- /dev/null +++ b/src/header/_header.scss @@ -0,0 +1,290 @@ +@import "../globals/tools/exports"; +@import "../globals/tools/compatibility"; +@import "../globals/tools/iff"; + +@import "../globals/settings/colours-palette"; +@import "../globals/settings/colours-applied"; +@import "../globals/settings/compatibility"; +@import "../globals/settings/spacing"; +@import "../globals/settings/measurements"; + +@import "../globals/helpers/media-queries"; +@import "../globals/helpers/focusable"; +@import "../globals/helpers/spacing"; +@import "../globals/helpers/device-pixels"; +@import "../globals/helpers/grid"; +@import "../globals/helpers/shape-arrow"; + +@import "../globals/helpers/typography"; +@import "../globals/settings/typography-font-stacks"; +@import "../globals/settings/typography-font"; +@import "../globals/settings/typography-responsive"; + +@include govuk-exports("header") { + + $govuk-header-background: $govuk-black; + $govuk-header-border-color: $govuk-blue; + $govuk-header-border-width: $govuk-spacing-scale-2; + $govuk-header-text: $govuk-white; + $govuk-header-link: $govuk-white; + $govuk-header-link-hover: $govuk-white; + $govuk-header-link-active: #1d8feb; + $govuk-header-nav-item-border-color: #2e3133; + + .govuk-header { + @include govuk-font-regular-16; + + border-bottom: $govuk-spacing-scale-2 solid $govuk-white; + color: $govuk-header-text; + background: $govuk-header-background; + + } + + .govuk-header--full-width { + padding: 0 $govuk-spacing-scale-3; + border-color: $govuk-header-border-color; + } + + .govuk-header__container { + position: relative; + margin-bottom: -$govuk-header-border-width; + padding-top: $govuk-spacing-scale-2; + border-bottom: $govuk-header-border-width solid $govuk-header-border-color; + } + + .govuk-header__logotype { + margin-right: $govuk-spacing-scale-1; + } + + .govuk-header__logotype-crown { + margin-right: 1px; + fill: currentColor; + vertical-align: middle; + } + + .govuk-header__logotype-crown-fallback-image { + width: 36px; + height: 32px; + border: 0; + vertical-align: middle; + } + + .govuk-header__title { + @include govuk-font-regular-24; + } + + .govuk-header__link { + @include govuk-focusable-fill; + + text-decoration: none; + + &:link, + &:visited { + color: $govuk-header-link; + } + + &:hover { + text-decoration: underline; + } + + &:focus { + color: $govuk-black; + } + + // alphagov/govuk_template includes a specific a:link:focus selector + // designed to make unvisited links a slightly darker blue when focussed, so + // we need to override the text colour for that combination of selectors. + @include govuk-compatibility(govuk_template) { + &:link:focus { + @include govuk-text-colour; + } + } + } + + .govuk-header__link--homepage { + // Font size needs to be set on the link so that the box sizing is correct + // in Firefox + @include govuk-typography-common; + @include govuk-typography-weight-bold; + + display: inline-block; + font-size: 30px; // We don't have a mixin that produces 30px font size + line-height: 30px; + + &:link, + &:visited { + margin-bottom: -1px; // Negate transparent bottom border + border-bottom: 1px solid transparent; + text-decoration: none; + } + + &:hover, + &:active { + border-bottom-color: currentColor; + } + } + + .govuk-header__link--service-name { + display: inline-block; + margin-bottom: $govuk-spacing-scale-2; + @include govuk-font-bold-24; + } + + .govuk-header__logo { + @include govuk-responsive-margin($govuk-spacing-responsive-2, "bottom"); + padding-right: $govuk-spacing-scale-8; + + @include mq ($from: desktop) { + display: inline-block; + width: 33.33%; + padding-right: 0; + vertical-align: top; + } + } + + .govuk-header__proposition { + @include mq ($from: desktop) { + display: inline-block; + width: 66.66%; + } + } + + .govuk-header__menu-button { + @include govuk-font-regular-16; + position: absolute; + top: $govuk-spacing-scale-4; + right: 0; + margin: 0; + padding: 0; + border: 0; + color: $govuk-header-link; + background: none; + + &:hover { + text-decoration: underline; + } + + &::after { + @include govuk-shape-arrow($direction: down, $base: 10px); + content: ""; + display: inline-block; + margin-left: $govuk-spacing-scale-1; + } + + @include govuk-focusable; + + @include mq ($from: tablet) { + top: $govuk-spacing-scale-3; + } + + @include mq ($from: desktop) { + display: none; + } + } + + .govuk-header__menu-button--open { + &::after { + @include govuk-shape-arrow($direction: up, $base: 10px); + display: inline-block; + } + } + + .govuk-header__navigation { + @include govuk-responsive-margin($govuk-spacing-responsive-2, "bottom"); + display: none; + margin: 0; + padding: 0; + list-style: none; + + @include mq ($from: desktop) { + display: block; + } + } + + .govuk-header__navigation--open { + display: block; + } + + .govuk-header__navigation--right { + @include mq ($from: desktop) { + margin: 0; + padding: $govuk-spacing-scale-1 0; + text-align: right; + } + } + + .govuk-header__navigation--no-service-name { + padding-top: $govuk-spacing-scale-7; + } + + .govuk-header__navigation-item { + padding: $govuk-spacing-scale-2 0; + border-bottom: 1px solid $govuk-header-nav-item-border-color; + + @include mq ($from: desktop) { + display: inline-block; + margin-right: $govuk-spacing-scale-3; + padding: $govuk-spacing-scale-1 0; + border: 0; + } + + a { + @include govuk-font-bold-16; + white-space: nowrap; + } + } + + .govuk-header__navigation-item--active { + a { + &:link, + &:hover, + &:visited { + color: $govuk-header-link-active; + } + } + } + + .govuk-header__navigation-item:last-child { + margin-right: 0; + } + + @include mq($media-type: print) { + .app-header { + border-bottom-width: 0; + color: $govuk-black; + background: transparent; + } + + // Hide the inverted crown when printing in browsers that don't support SVG. + .app-header__logotype-crown-fallback-image { + display: none; + } + + .app-header__link { + &:link, + &:visited { + color: $govuk-black; + } + + // Do not append link href to GOV.UK link when printing (e.g. '(/)') + &:after { + display: none; + } + } + } + + // Begin adjustments for font baseline offset + // These should be removed when the font is updated with the correct baseline + .govuk-header__logotype-crown, + .govuk-header__logotype-crown-fallback-image { + position: relative; + top: -4px; + } + + .govuk-header { + $offset: 3px; + padding-top: $offset; + } + // End adjustments + +} diff --git a/src/header/header.js b/src/header/header.js new file mode 100644 index 0000000000..b840428404 --- /dev/null +++ b/src/header/header.js @@ -0,0 +1,57 @@ +import '../globals/polyfills/Function/prototype/bind' +import '../globals/polyfills/Event' // addEventListener and event.target normaliziation + +function Header ($module) { + this.$module = $module +} + +Header.prototype.init = function () { + // Check for module + var $module = this.$module + if (!$module) { + return + } + + // Check for button + var $toggleButton = $module.querySelector('.js-header-toggle') + if (!$toggleButton) { + return + } + + // Handle $toggleButton click events + $toggleButton.addEventListener('click', this.handleClick.bind(this)) +} + +/** +* Toggle class +* @param {object} node element +* @param {string} className to toggle +*/ +Header.prototype.toggleClass = function (node, className) { + if (node.classList.contains(className)) { + node.classList.remove(className) + } else { + node.classList.add(className) + } +} + +/** +* An event handler for click event on $toggleButton +* @param {object} event event +*/ +Header.prototype.handleClick = function (event) { + var $module = this.$module + var $toggleButton = event.target || event.srcElement + var $target = $module.querySelector('#' + $toggleButton.getAttribute('aria-controls')) + + // If a button with aria-controls, handle click + if ($toggleButton && $target) { + this.toggleClass($target, 'govuk-header__navigation--open') + this.toggleClass($toggleButton, 'govuk-header__menu-button--open') + + $toggleButton.setAttribute('aria-expanded', $toggleButton.getAttribute('aria-expanded') !== 'true') + $target.setAttribute('aria-hidden', $target.getAttribute('aria-hidden') === 'false') + } +} + +export default Header diff --git a/src/header/header.njk b/src/header/header.njk new file mode 100644 index 0000000000..735c313c18 --- /dev/null +++ b/src/header/header.njk @@ -0,0 +1,3 @@ +{% from "header/macro.njk" import govukHeader %} + +{{ govukHeader() }} diff --git a/src/header/header.yaml b/src/header/header.yaml new file mode 100644 index 0000000000..295c440ec3 --- /dev/null +++ b/src/header/header.yaml @@ -0,0 +1,132 @@ +previewLayout: full-width +accessibilityCriteria: | + Text and links in the Header must: + - have a text contrast ratio higher than 4.5:1 against the background colour to meet [WCAG AA](https://www.w3.org/TR/WCAG20/#visual-audio-contrast-contrast) + + Links in the Header must: + - accept focus + - be focusable with a keyboard + - be usable with a keyboard + - indicate when they have focus + - change in appearance when touched (in the touch-down state) + - change in appearance when hovered + - have visible text + + Images in the Header must: + - be presentational when linked to from accompanying text (crown icon). + + Landmarks and Roles in the Header should: + - have a role of `banner` at the root of the component (
) (https://www.w3.org/TR/wai-aria-1.1/#banner) + +examples: +- name: default + description: The standard header as used on information pages on GOV.UK + data: + homepageUrl: / + containerClasses: govuk-width-container + +- name: with-service-name + description: If your service is more than a few pages long, you can help users understand where they are by adding the service name. + data: + homepageUrl: / + serviceName: Service Name + serviceUrl: /components/header + containerClasses: govuk-width-container + +- name: with-navigation + data: + homepageUrl: / + containerClasses: govuk-width-container + navigation: + - href: '#1' + text: 'Navigation item 1' + active: true + - href: '#2' + text: 'Navigation item 2' + - href: '#3' + text: 'Navigation item 3' + - href: '#4' + text: 'Navigation item 4' + +- name: with-service-name-and-navigation + description: If you need to include basic navigation, contact or account management links. + readme: false + data: + homepageUrl: / + serviceName: Service Name + serviceUrl: /components/header + containerClasses: govuk-width-container + navigation: + - href: '#1' + text: 'Navigation item 1' + active: true + - href: '#2' + text: 'Navigation item 2' + - href: '#3' + text: 'Navigation item 3' + - href: '#4' + text: 'Navigation item 4' + +- name: with-large-navigation + readme: false + description: An edge case example with a large number of navitation items with long names used to test wrapping + data: + homepageUrl: / + containerClasses: govuk-width-container + navigation: + - href: '/browse/benefits' + text: 'Benefits' + - href: '/browse/births-deaths-marriages' + text: 'Births, deaths, marriages and care' + - href: '/browse/business' + text: 'Business and self-employed' + - href: '/browse/childcare-parenting' + text: 'Childcare and parenting' + - href: '/browse/citizenship' + text: 'Citizenship and living in the UK' + - href: '/browse/justice' + text: 'Crime, justice and the law' + - href: '/browse/disabilities' + text: 'Disabled people' + - href: '/browse/driving' + text: 'Driving and transport' + - href: '/browse/education' + text: 'Education and learning' + - href: '/browse/employing-people' + text: 'Employing people' + - href: '/browse/environment-countryside' + text: 'Environment and countryside' + - href: '/browse/housing-local-services' + text: 'Housing and local services' + - href: '/browse/tax' + text: 'Money and tax' + - href: '/browse/abroad' + text: 'Passports, travel and living abroad' + - href: '/browse/visas-immigration' + text: 'Visas and immigration' + - href: '/browse/working' + text: 'Working, jobs and pensions' + +- name: full-width + readme: false + data: + homepageUrl: / + classes: govuk-header--full-width + navigationClasses: govuk-header__navigation--right + title: Product Name + +- name: full-width-with-navigation + readme: false + data: + homepageUrl: / + classes: govuk-header--full-width + navigationClasses: govuk-header__navigation--right + title: Product Name + navigation: + - href: '#1' + text: 'Navigation item 1' + active: true + - href: '#2' + text: 'Navigation item 2' + - href: '#3' + text: 'Navigation item 3' diff --git a/src/header/index.njk b/src/header/index.njk new file mode 100644 index 0000000000..a3954f16da --- /dev/null +++ b/src/header/index.njk @@ -0,0 +1,167 @@ +{% if isReadme %} + {% set parentTemplate = "readme.njk" %} +{% else %} + {% set parentTemplate = "component.njk" %} +{% endif %} + +{% extends parentTemplate %} + +{# Commented out blocks below inherit from views/component.njk #} + +{# componentName #} +{% block componentDescription %} + The header component is used at the top of every GOV.UK page, to help users navigate. +{% endblock %} +{# examples #} + +{# override link to design system here if it's different to base url + componentName #} +{# {% set componentGuidanceLink = 'new link here' %} #} + +{% block componentArguments %} +{% from "table/macro.njk" import govukTable %} +{{ govukTable({ + 'firstCellIsHeader': true, + 'head' : [ + { + text: 'Name' + }, + { + text: 'Type' + }, + { + text: 'Required' + }, + { + text: 'Description' + } + ], + 'rows' : [ + [ + { + text: 'meta' + }, + { + text: 'object' + }, + { + text: 'No' + }, + { + text: 'Object containing parameters for the meta navigation' + } + ], + [ + { + text: 'meta.items[]' + }, + { + text: 'array' + }, + { + text: 'No' + }, + { + text: 'Array of items for use in the meta section of the footer' + } + ], + [ + { + text: 'navigation' + }, + { + text: 'array' + }, + { + text: 'No' + }, + { + text: 'Array of items for use in the navigation section of the footer' + } + ], + [ + { + text: 'navigation[].title' + }, + { + text: 'string' + }, + { + text: 'No' + }, + { + text: 'Title for a section' + } + ], + [ + { + text: 'navigation[].columns' + }, + { + text: 'integer' + }, + { + text: 'No' + }, + { + text: 'Amount of columns to display items in' + } + ], + [ + { + text: 'navigation[].items' + }, + { + text: 'array' + }, + { + text: 'No' + }, + { + text: 'Array of items to display in the list' + } + ], + [ + { + text: 'attributes' + }, + { + text: 'object' + }, + { + text: 'No' + }, + { + text: 'Will add attributes to the footer component root' + } + ], + [ + { + text: 'classes' + }, + { + text: 'string' + }, + { + text: 'No' + }, + { + text: 'Will add classes to the footer component root' + } + ], + [ + { + text: 'containerClasses' + }, + { + text: 'string' + }, + { + text: 'No' + }, + { + text: 'Classes that can be added to the container, useful if you want to make the footer full width.' + } + ] + ] +})}} +{% endblock %} diff --git a/src/header/macro.njk b/src/header/macro.njk new file mode 100644 index 0000000000..d863b7831d --- /dev/null +++ b/src/header/macro.njk @@ -0,0 +1,3 @@ +{% macro govukHeader(params) %} + {%- include "./template.njk" -%} +{% endmacro %} diff --git a/src/header/template.njk b/src/header/template.njk new file mode 100644 index 0000000000..df8e3aa03c --- /dev/null +++ b/src/header/template.njk @@ -0,0 +1,79 @@ +{% from "phase-banner/macro.njk" import govukPhaseBanner %} + + diff --git a/src/icons/govuk-logotype-crown.png b/src/icons/govuk-logotype-crown.png new file mode 100644 index 0000000000000000000000000000000000000000..a6cdbfd47bb38a671780708d0845f2e27b2c0743 GIT binary patch literal 952 zcmV;p14sOcP)B`#GemB2q!0kS2YQV`Yfr{WAINd*Hk}e^NnW2vfrJd0`O7N0ZGFi9p)8& zNwEUcfvPe(yC_e)%Ggu^)ANcy(^&{Xz&Y2%2+*7pf4iijM|;jBnL2NQWyT4=V0+uJd4c0pm@lKex zA<)yM1m-gPE5Av;vJlH_%z8W)7PFD&oB|?_gF<0iDKdw2zqP#Q|+jgh%6| z0|Zn9{gw{{b;)wY%T{L{Y*U?qcQmovoM!2z1tY+$oSiqv&j75*2xtWm65Xs4nPp!9 zFEh^`U}nkLI5xoZD43_?unV!z(O7^Q;GqF8q*(!`0Zl*XR|TMu*I$4pW2O8H_Wcm3 z5zvvQJTW+H{-U2b$vvq>#yFeE(j`AOMbei9<74u@$InY4gk=d}i=>&+Ujvffh7hhL zP4-fRwKvDtrxI|tcf*m48II{4$x=0D6m?@pZGMLl$&T1}cM87L&1)mj5E)!I)<6QZ z&d;{UUt6g$Cb|QbUypbV_SFR}9Wx2{jS?*cdLzSnpa|Rp&I3Em{{UP8Rs(N5R-5<1 zIy>yJ#~AeyZm)fns4h+2ZVPVuIW0LB(zf3du|9c}s3+t289iQ%9sAl{Zbv-vOz>8| z58RC!SQBvCx|co6YTznx!|%PoW$T=_O{wAD^(dHE1fJw=&uvz$2lfH$qtuh=ABf)j zfp=N5C{sK9z82VTAJ}JZ-zWloaYqHV*!Xyc{^4jjIx^(PE!z^G06-s5tfY~hGQeY? z1=tD