@x-govuk/nhsuk-eleventy-plugin 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +22 -0
- package/README.md +35 -0
- package/package.json +102 -0
- package/src/application.js +11 -0
- package/src/application.scss +2 -0
- package/src/components/_index.scss +12 -0
- package/src/components/attribution/_index.scss +13 -0
- package/src/components/blockquote/_index.scss +22 -0
- package/src/components/card-group/macro.njk +3 -0
- package/src/components/card-group/template.njk +26 -0
- package/src/components/code/_index.scss +153 -0
- package/src/components/contents-list/_index.scss +18 -0
- package/src/components/document-header/macro.njk +3 -0
- package/src/components/document-header/template.njk +10 -0
- package/src/components/document-list/macro.njk +3 -0
- package/src/components/document-list/template.njk +22 -0
- package/src/components/footnotes-list/_index.scss +55 -0
- package/src/components/heading/macro.njk +3 -0
- package/src/components/heading/template.njk +15 -0
- package/src/components/hero/_index.scss +17 -0
- package/src/components/hero/macro.njk +3 -0
- package/src/components/hero/template.njk +36 -0
- package/src/components/image/_index.scss +8 -0
- package/src/components/metadata/_index.scss +24 -0
- package/src/components/metadata/macro.njk +3 -0
- package/src/components/metadata/template.njk +50 -0
- package/src/components/prose-scope/_index.scss +72 -0
- package/src/components/prose-scope/macro.njk +3 -0
- package/src/components/prose-scope/template.njk +4 -0
- package/src/components/related/_index.scss +10 -0
- package/src/components/related/macro.njk +3 -0
- package/src/components/related/template.njk +17 -0
- package/src/components/search/_index.scss +120 -0
- package/src/components/search/search.js +133 -0
- package/src/components/sub-navigation/_index.scss +71 -0
- package/src/components/sub-navigation/macro.njk +3 -0
- package/src/components/sub-navigation/template.njk +27 -0
- package/src/data/eleventy-computed.js +17 -0
- package/src/data/options.js +49 -0
- package/src/events/generate-nhsuk-assets.js +57 -0
- package/src/filters/current-page.js +18 -0
- package/src/filters/index.js +21 -0
- package/src/filters/items-from-collection.js +73 -0
- package/src/filters/markdown.js +20 -0
- package/src/index.js +136 -0
- package/src/index.scss +5 -0
- package/src/layouts/base.njk +81 -0
- package/src/layouts/collection.njk +38 -0
- package/src/layouts/error.njk +11 -0
- package/src/layouts/feed.njk +32 -0
- package/src/layouts/hub.njk +31 -0
- package/src/layouts/page.njk +31 -0
- package/src/layouts/post.njk +47 -0
- package/src/layouts/product.njk +32 -0
- package/src/layouts/sitemap.njk +25 -0
- package/src/layouts/sub-navigation.njk +40 -0
- package/src/layouts/tag.njk +14 -0
- package/src/layouts/tags.njk +18 -0
- package/src/markdown-it/alert.js +36 -0
- package/src/markdown-it/deflist.js +16 -0
- package/src/markdown-it/figure.js +12 -0
- package/src/markdown-it/footnote.js +47 -0
- package/src/markdown-it/table.js +18 -0
- package/src/markdown-it.js +91 -0
- package/src/nunjucks.js +65 -0
- package/src/vendor/nhsuk-frontend/_index.scss +2 -0
- package/src/vendor/nhsuk-frontend/components/_index.scss +15 -0
- package/src/vendor/nhsuk-frontend/core/_index.scss +1 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{%- macro _authorLink(author) -%}
|
|
2
|
+
{%- if author.url -%}
|
|
3
|
+
<a class="nhsuk-link" href="{{ author.url }}">{{ author.name }}</a>
|
|
4
|
+
{%- else -%}
|
|
5
|
+
{{- author.name or author -}}
|
|
6
|
+
{%- endif -%}
|
|
7
|
+
{% endmacro -%}
|
|
8
|
+
|
|
9
|
+
<dl class="app-metadata nhsuk-u-reading-width">
|
|
10
|
+
{% if params.author %}
|
|
11
|
+
<div class="app-metadata__item">
|
|
12
|
+
<dt class="app-metadata__term">Posted by</dt>
|
|
13
|
+
<dd class="app-metadata__definition">
|
|
14
|
+
{%- if params.author is string or params.author is mapping -%}
|
|
15
|
+
{{- _authorLink(params.author) -}}
|
|
16
|
+
{%- else -%}
|
|
17
|
+
{%- for author in params.author -%}
|
|
18
|
+
{{- " and " if loop.last and loop.length > 1 else (", " if not loop.first) -}}
|
|
19
|
+
{{- _authorLink(author) -}}
|
|
20
|
+
{%- endfor -%}
|
|
21
|
+
{%- endif -%}
|
|
22
|
+
</dd>
|
|
23
|
+
</div>
|
|
24
|
+
{% endif %}
|
|
25
|
+
{% if params.date %}
|
|
26
|
+
<div class="app-metadata__item">
|
|
27
|
+
<dt class="app-metadata__term">Published</dt>
|
|
28
|
+
<dd class="app-metadata__definition">
|
|
29
|
+
<time datetime="{{ params.date | isoDate }}">{{ params.date | nhsukDate }}</time>
|
|
30
|
+
</dd>
|
|
31
|
+
</div>
|
|
32
|
+
{% endif %}
|
|
33
|
+
{% if params.modified %}
|
|
34
|
+
<div class="app-metadata__item">
|
|
35
|
+
<dt class="app-metadata__term">Last updated</dt>
|
|
36
|
+
<dd class="app-metadata__definition">
|
|
37
|
+
<time datetime="{{ params.modified | isoDate }}">{{ params.modified | nhsukDate }}</time>
|
|
38
|
+
</dd>
|
|
39
|
+
</div>
|
|
40
|
+
{% endif %}
|
|
41
|
+
{% if params.tags | length > 0 %}
|
|
42
|
+
<div class="app-metadata__item">
|
|
43
|
+
<dt class="app-metadata__term">Tagged</dt>
|
|
44
|
+
<dd class="app-metadata__definition">{% for tag in params.tags -%}
|
|
45
|
+
<a href="/tags/{{ tag | slug }}" class="nhsuk-link">{{ tag }}</a>
|
|
46
|
+
{%- if not loop.last %}, {% endif -%}
|
|
47
|
+
{%- endfor %}</dd>
|
|
48
|
+
</div>
|
|
49
|
+
{% endif %}
|
|
50
|
+
</dl>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
@use "../../vendor/nhsuk-frontend" as *;
|
|
2
|
+
|
|
3
|
+
@include nhsuk-exports("nhsuk-eleventy-plugin/components/prose-scope") {
|
|
4
|
+
.app-prose-scope {
|
|
5
|
+
@include nhsuk-responsive-margin(7, "bottom");
|
|
6
|
+
|
|
7
|
+
// Distinguish inserted text from that inside links
|
|
8
|
+
ins {
|
|
9
|
+
text-decoration-style: double;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Use NHS.UK pale yellow colour for highlighted text
|
|
13
|
+
mark {
|
|
14
|
+
background-color: nhsuk-colour("pale-yellow");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Use sensible defaults for embedded media
|
|
18
|
+
iframe,
|
|
19
|
+
img,
|
|
20
|
+
video {
|
|
21
|
+
height: auto;
|
|
22
|
+
max-width: 100%;
|
|
23
|
+
width: auto;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
a:focus > img {
|
|
27
|
+
@include nhsuk-focused-box;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Heading anchor
|
|
31
|
+
[class^="nhsuk-heading"][tabindex] {
|
|
32
|
+
outline: none;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
[class^="nhsuk-heading"][tabindex] .nhsuk-link {
|
|
36
|
+
text-decoration: none;
|
|
37
|
+
|
|
38
|
+
@include nhsuk-link-style-text;
|
|
39
|
+
|
|
40
|
+
&:hover::after,
|
|
41
|
+
:target &::after {
|
|
42
|
+
color: nhsuk-colour("grey-1");
|
|
43
|
+
content: "#";
|
|
44
|
+
font-variant: all-small-caps;
|
|
45
|
+
font-weight: normal;
|
|
46
|
+
margin-left: nhsuk-spacing(1);
|
|
47
|
+
opacity: 0.5;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Responsive table
|
|
52
|
+
.nhsuk-table[tabindex] {
|
|
53
|
+
display: block;
|
|
54
|
+
overflow-x: auto;
|
|
55
|
+
scrollbar-color: nhsuk-colour("grey-1") $nhsuk-border-colour;
|
|
56
|
+
scrollbar-width: thin;
|
|
57
|
+
|
|
58
|
+
&:focus,
|
|
59
|
+
&:focus-visible {
|
|
60
|
+
box-shadow:
|
|
61
|
+
0 0 0 #{$nhsuk-focus-width * 3} nhsuk-colour("black"),
|
|
62
|
+
0 0 0 #{$nhsuk-focus-width * 4} $nhsuk-focus-colour;
|
|
63
|
+
outline: #{$nhsuk-focus-width * 2} solid nhsuk-colour("grey-5");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
&:focus:not(:focus-visible) {
|
|
67
|
+
box-shadow: none;
|
|
68
|
+
outline: none;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
@use "../../vendor/nhsuk-frontend" as *;
|
|
2
|
+
|
|
3
|
+
@include nhsuk-exports("nhsuk-eleventy-plugin/components/related") {
|
|
4
|
+
.app-related {
|
|
5
|
+
border-top: 1px solid $nhsuk-border-colour;
|
|
6
|
+
|
|
7
|
+
@include nhsuk-responsive-margin(7, "bottom");
|
|
8
|
+
@include nhsuk-responsive-padding(4, "top");
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<aside class="app-related{% if layout == "collection" or layout == "page" or layout == "post" or layout == "sub-navigation" %} nhsuk-u-reading-width{% endif %}">
|
|
2
|
+
{% for related in ([params] if params is mapping else params) %}
|
|
3
|
+
<h2 class="nhsuk-heading-s nhsuk-u-margin-bottom-2">
|
|
4
|
+
{{- related.title or "Related" -}}
|
|
5
|
+
</h2>
|
|
6
|
+
{{ related.description | markdown if related.description }}
|
|
7
|
+
{% if related.items %}
|
|
8
|
+
<ul class="nhsuk-list">
|
|
9
|
+
{% for item in related.items %}
|
|
10
|
+
<li>
|
|
11
|
+
<a class="nhsuk-link" href="{{ item.href }}">{{ item.text }}</a>
|
|
12
|
+
</li>
|
|
13
|
+
{% endfor %}
|
|
14
|
+
</ul>
|
|
15
|
+
{% endif %}
|
|
16
|
+
{% endfor %}
|
|
17
|
+
</aside>
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
@use "../../vendor/nhsuk-frontend" as *;
|
|
2
|
+
|
|
3
|
+
// Site search using Accessible autocomplete
|
|
4
|
+
// Styles below are based on the default accessible autocomplete style sheet
|
|
5
|
+
|
|
6
|
+
$_icon-size: 28px;
|
|
7
|
+
$_input-padding-right: nhsuk-px-to-rem(12px + $_icon-size);
|
|
8
|
+
|
|
9
|
+
@include nhsuk-exports("nhsuk-eleventy-plugin/components/search") {
|
|
10
|
+
.nhsuk-header__search-form[hidden] {
|
|
11
|
+
display: none;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.app-search__wrapper {
|
|
15
|
+
background-color: $nhsuk-input-background-colour;
|
|
16
|
+
border-radius: $nhsuk-border-radius;
|
|
17
|
+
min-width: 260px;
|
|
18
|
+
position: relative;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.nhsuk-header__search-input.app-search__hint,
|
|
22
|
+
.nhsuk-header__search-input.app-search__input {
|
|
23
|
+
background-color: transparent;
|
|
24
|
+
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m20.7 19.3-4.1-4.1a7 7 0 1 0-1.4 1.4l4 4.1a1 1 0 0 0 1.5 0c.4-.4.4-1 0-1.4ZM6 11a5 5 0 1 1 10 0 5 5 0 0 1-10 0Z' fill='%23#{str-slice(#{$nhsuk-brand-colour}, 2)}'/></svg>");
|
|
25
|
+
background-position: top nhsuk-px-to-rem(4px) right nhsuk-px-to-rem(7px);
|
|
26
|
+
background-repeat: no-repeat;
|
|
27
|
+
background-size: nhsuk-px-to-rem($_icon-size);
|
|
28
|
+
border-radius: $nhsuk-border-radius;
|
|
29
|
+
padding-right: $_input-padding-right;
|
|
30
|
+
width: 100%;
|
|
31
|
+
|
|
32
|
+
&:focus {
|
|
33
|
+
background-position: top nhsuk-px-to-rem(3px) right nhsuk-px-to-rem(6px);
|
|
34
|
+
padding-right: $_input-padding-right;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.nhsuk-header__search-input.app-search__hint {
|
|
39
|
+
color: nhsuk-colour("grey-2");
|
|
40
|
+
position: absolute;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.app-search__menu {
|
|
44
|
+
background-color: nhsuk-colour("white");
|
|
45
|
+
border-radius: $nhsuk-border-radius;
|
|
46
|
+
color: $nhsuk-text-colour;
|
|
47
|
+
margin: 0;
|
|
48
|
+
max-height: 560px;
|
|
49
|
+
overflow-x: hidden;
|
|
50
|
+
padding: 0;
|
|
51
|
+
width: 100%;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.app-search__menu--visible {
|
|
55
|
+
display: block;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.app-search__menu--hidden {
|
|
59
|
+
display: none;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.app-search__menu--overlay {
|
|
63
|
+
box-shadow: 0 0 3px 0 rgba(nhsuk-colour("grey-1"), 0.5);
|
|
64
|
+
left: 0;
|
|
65
|
+
position: absolute;
|
|
66
|
+
top: 100%;
|
|
67
|
+
z-index: 100;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.app-search__option {
|
|
71
|
+
border-bottom: 1px solid nhsuk-colour("grey-5");
|
|
72
|
+
color: $nhsuk-secondary-text-colour;
|
|
73
|
+
cursor: pointer;
|
|
74
|
+
display: block;
|
|
75
|
+
margin: 0;
|
|
76
|
+
padding: nhsuk-spacing(3);
|
|
77
|
+
position: relative;
|
|
78
|
+
|
|
79
|
+
@include nhsuk-font($size: 16);
|
|
80
|
+
|
|
81
|
+
& > * {
|
|
82
|
+
pointer-events: none;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Add a transparent outline for when users change their colours.
|
|
87
|
+
.app-search__option--focused {
|
|
88
|
+
border-bottom-color: transparent;
|
|
89
|
+
outline: $nhsuk-focus-width solid transparent;
|
|
90
|
+
outline-offset: -$nhsuk-focus-width;
|
|
91
|
+
|
|
92
|
+
@include nhsuk-focused-text;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.app-search__option--no-results {
|
|
96
|
+
cursor: default;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.app-search__option-title {
|
|
100
|
+
text-decoration: underline;
|
|
101
|
+
|
|
102
|
+
@include nhsuk-link-style-default;
|
|
103
|
+
|
|
104
|
+
.app-search__option:hover & {
|
|
105
|
+
text-decoration: none;
|
|
106
|
+
|
|
107
|
+
@include nhsuk-link-style-hover;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.app-search__option--focused & {
|
|
111
|
+
color: $nhsuk-focus-text-colour;
|
|
112
|
+
text-decoration: none;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.app-search__option-title,
|
|
117
|
+
.app-search__option-metadata {
|
|
118
|
+
display: block;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import accessibleAutocomplete from 'accessible-autocomplete'
|
|
2
|
+
|
|
3
|
+
export class SearchElement extends HTMLElement {
|
|
4
|
+
constructor() {
|
|
5
|
+
super()
|
|
6
|
+
|
|
7
|
+
this.statusMessage = null
|
|
8
|
+
this.$container = this.querySelector('.nhsuk-header__search')
|
|
9
|
+
this.$searchForm = this.querySelector('.nhsuk-header__search-form')
|
|
10
|
+
this.$searchInput = this.querySelector('.nhsuk-header__search-input')
|
|
11
|
+
this.searchIndex = null
|
|
12
|
+
this.searchIndexUrl = this.getAttribute('index')
|
|
13
|
+
this.searchResults = []
|
|
14
|
+
this.searchTimeout = 10
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async fetchSearchIndex(indexUrl) {
|
|
18
|
+
this.statusMessage = 'Loading search index'
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const response = await fetch(indexUrl, {
|
|
22
|
+
signal: AbortSignal.timeout(this.searchTimeout * 1000)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
throw Error('Search index not found')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const json = await response.json()
|
|
30
|
+
this.statusMessage = 'No results found'
|
|
31
|
+
this.searchIndex = json
|
|
32
|
+
} catch (error) {
|
|
33
|
+
this.statusMessage = 'Failed to load search index'
|
|
34
|
+
console.error(this.statusMessage, error.message)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
findResults(searchQuery, searchIndex) {
|
|
39
|
+
return searchIndex.filter((item) => {
|
|
40
|
+
const regex = new RegExp(searchQuery, 'gi')
|
|
41
|
+
return (
|
|
42
|
+
item?.title?.match(regex) ||
|
|
43
|
+
item?.description?.match(regex) ||
|
|
44
|
+
item?.tokens?.match(regex)
|
|
45
|
+
)
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
renderResults(query, populateResults) {
|
|
50
|
+
if (!this.searchIndex) {
|
|
51
|
+
return populateResults(this.searchResults)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
this.searchResults = this.findResults(query, this.searchIndex).reverse()
|
|
55
|
+
|
|
56
|
+
populateResults(this.searchResults)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
handleOnConfirm(result) {
|
|
60
|
+
const path = result.url
|
|
61
|
+
if (!path) {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
window.location.href = path
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
handleNoResults() {
|
|
69
|
+
return this.statusMessage
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
inputValueTemplate(result) {
|
|
73
|
+
if (result) {
|
|
74
|
+
return result.title
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
suggestionTemplate(result) {
|
|
79
|
+
if (result) {
|
|
80
|
+
const container = document.createElement('span')
|
|
81
|
+
|
|
82
|
+
// Add title of result to container
|
|
83
|
+
const title = document.createElement('span')
|
|
84
|
+
title.className = 'app-search__option-title'
|
|
85
|
+
title.textContent = result.title
|
|
86
|
+
|
|
87
|
+
container.appendChild(title)
|
|
88
|
+
|
|
89
|
+
// Add section and/or data to container
|
|
90
|
+
if (result.date || result.section) {
|
|
91
|
+
const section = document.createElement('span')
|
|
92
|
+
section.className = 'app-search__option-metadata'
|
|
93
|
+
|
|
94
|
+
section.innerHTML =
|
|
95
|
+
result.date && result.section
|
|
96
|
+
? `${result.section}<br>${result.date}`
|
|
97
|
+
: result.section || result.date
|
|
98
|
+
|
|
99
|
+
container.appendChild(section)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return container.innerHTML
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async connectedCallback() {
|
|
107
|
+
if (!this.searchIndexUrl) {
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
await this.fetchSearchIndex(this.searchIndexUrl)
|
|
112
|
+
|
|
113
|
+
this.$searchForm.hidden = true
|
|
114
|
+
|
|
115
|
+
return accessibleAutocomplete({
|
|
116
|
+
element: this.$container,
|
|
117
|
+
id: this.$searchInput.id,
|
|
118
|
+
cssNamespace: 'app-search',
|
|
119
|
+
inputClasses: 'nhsuk-header__search-input nhsuk-input',
|
|
120
|
+
displayMenu: 'overlay',
|
|
121
|
+
minLength: 2,
|
|
122
|
+
confirmOnBlur: false,
|
|
123
|
+
placeholder: this.$searchInput.placeholder,
|
|
124
|
+
source: this.renderResults.bind(this),
|
|
125
|
+
onConfirm: this.handleOnConfirm,
|
|
126
|
+
templates: {
|
|
127
|
+
inputValue: this.inputValueTemplate,
|
|
128
|
+
suggestion: (value) => this.suggestionTemplate(value)
|
|
129
|
+
},
|
|
130
|
+
tNoResults: this.handleNoResults.bind(this)
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
@use "../../vendor/nhsuk-frontend" as *;
|
|
2
|
+
|
|
3
|
+
@include nhsuk-exports("nhsuk-eleventy-plugin/components/sub-navigation") {
|
|
4
|
+
.app-sub-navigation {
|
|
5
|
+
@include nhsuk-responsive-margin(7, "bottom");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.app-sub-navigation__heading {
|
|
9
|
+
color: $nhsuk-secondary-text-colour;
|
|
10
|
+
margin-bottom: 12px;
|
|
11
|
+
padding-top: nhsuk-spacing(1);
|
|
12
|
+
|
|
13
|
+
@include nhsuk-font(19, $line-height: 1.25, $weight: bold);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.app-sub-navigation__list {
|
|
17
|
+
@include nhsuk-font(16, $line-height: 1.25);
|
|
18
|
+
@include nhsuk-responsive-margin(4, "bottom");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.app-sub-navigation__item {
|
|
22
|
+
padding-bottom: nhsuk-spacing(1);
|
|
23
|
+
padding-top: nhsuk-spacing(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.app-sub-navigation__item--current {
|
|
27
|
+
border-left: $nhsuk-border-width solid $nhsuk-brand-colour;
|
|
28
|
+
margin-left: #{$nhsuk-gutter-half * -1};
|
|
29
|
+
padding-left: #{$nhsuk-gutter-half - $nhsuk-border-width};
|
|
30
|
+
|
|
31
|
+
.app-sub-navigation__link {
|
|
32
|
+
font-weight: $nhsuk-font-bold;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.app-sub-navigation__link {
|
|
37
|
+
@include nhsuk-link-style-default;
|
|
38
|
+
@include nhsuk-link-style-no-visited-state;
|
|
39
|
+
|
|
40
|
+
&:link {
|
|
41
|
+
text-decoration: none;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.app-sub-navigation__list--nested {
|
|
46
|
+
@include nhsuk-responsive-margin(2, "bottom");
|
|
47
|
+
@include nhsuk-responsive-margin(3, "top");
|
|
48
|
+
|
|
49
|
+
.app-sub-navigation__item {
|
|
50
|
+
display: flex;
|
|
51
|
+
gap: nhsuk-spacing(1);
|
|
52
|
+
list-style: none;
|
|
53
|
+
|
|
54
|
+
@include nhsuk-font(16, $line-height: 1.3);
|
|
55
|
+
|
|
56
|
+
&::before {
|
|
57
|
+
color: nhsuk-colour("grey-3");
|
|
58
|
+
content: "—";
|
|
59
|
+
margin-left: nhsuk-spacing(-3);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.app-sub-navigation__link {
|
|
64
|
+
font-weight: 400;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.app-sub-navigation__link[aria-current] {
|
|
69
|
+
font-weight: bold;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<nav class="app-sub-navigation{%- if params.classes %} {{ params.classes }}{% endif %}" aria-labelledby="sub-navigation-heading"
|
|
2
|
+
{%- for attribute, value in params.attributes %} {{ attribute }}="{{value}}"{% endfor %}>
|
|
3
|
+
<h2 class="nhsuk-u-visually-hidden" id="sub-navigation-heading">{{ params.visuallyHiddenTitle or "Pages in this section" }}</h2>
|
|
4
|
+
{% for theme, items in params.items | groupby("theme") %}
|
|
5
|
+
{% if theme != "undefined" %}
|
|
6
|
+
<h3 class="app-sub-navigation__heading">{{ theme }}</h3>
|
|
7
|
+
{% endif %}
|
|
8
|
+
<ul class="nhsuk-list app-sub-navigation__list">
|
|
9
|
+
{% for item in items %}
|
|
10
|
+
{% if item %}
|
|
11
|
+
<li class="app-sub-navigation__item{% if item.parent or item.current %} app-sub-navigation__item--current{% endif %}">
|
|
12
|
+
<a class="app-sub-navigation__link" href="{{ item.href }}"{% if item.current %} aria-current="true"{% endif %}>{{ item.text }}</a>
|
|
13
|
+
{% if item.parent and item.children | length > 0 %}
|
|
14
|
+
<ul class="app-sub-navigation__list--nested">
|
|
15
|
+
{% for child in item.children %}
|
|
16
|
+
<li class="app-sub-navigation__item">
|
|
17
|
+
<a class="app-sub-navigation__link" href="{{ child.href }}"{% if child.current %} aria-current="true"{% endif %}>{{ child.text }}</a>
|
|
18
|
+
</li>
|
|
19
|
+
{% endfor %}
|
|
20
|
+
</ul>
|
|
21
|
+
{% endif %}
|
|
22
|
+
</li>
|
|
23
|
+
{% endif %}
|
|
24
|
+
{% endfor %}
|
|
25
|
+
</ul>
|
|
26
|
+
{% endfor %}
|
|
27
|
+
</nav>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getNavigationKey,
|
|
3
|
+
getNavigationParent
|
|
4
|
+
} from '@x-govuk/govuk-eleventy-plugin/utils'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Set sensible defaults for eleventyNavigation
|
|
8
|
+
*
|
|
9
|
+
* @see {@link https://www.11ty.dev/docs/plugins/navigation/}
|
|
10
|
+
*/
|
|
11
|
+
export const eleventyComputed = {
|
|
12
|
+
eleventyNavigation: {
|
|
13
|
+
key: (data) => getNavigationKey(data),
|
|
14
|
+
parent: (data) => getNavigationParent(data),
|
|
15
|
+
excerpt: (data) => data.eleventyNavigation.excerpt || data.description
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import deepmerge from 'deepmerge'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Default option values
|
|
5
|
+
*
|
|
6
|
+
* @see {@link https://x-govuk.github.io/nhsuk-eleventy-plugin/options/}
|
|
7
|
+
*/
|
|
8
|
+
const defaults = {
|
|
9
|
+
homeKey: 'Home',
|
|
10
|
+
icons: {
|
|
11
|
+
mask: '/assets/favicons/favicon.svg',
|
|
12
|
+
shortcut: '/assets/favicons/favicon.ico',
|
|
13
|
+
touch: '/assets/favicons/apple-touch-icon.png'
|
|
14
|
+
},
|
|
15
|
+
stylesheets: [],
|
|
16
|
+
titleSuffix: 'NHS',
|
|
17
|
+
url: false,
|
|
18
|
+
templates: {
|
|
19
|
+
error404: true,
|
|
20
|
+
sitemap: true // Linked to from default 404 page
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function defaultPluginOptions(options, pathPrefix) {
|
|
25
|
+
options.pathPrefix = pathPrefix
|
|
26
|
+
|
|
27
|
+
// Let `true` mean the default title suffix (`true` is rendered as a string)
|
|
28
|
+
if (options.titleSuffix === true) {
|
|
29
|
+
delete options.titleSuffix
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (options.templates?.searchIndex) {
|
|
33
|
+
// Enable search in header
|
|
34
|
+
if (options.header) {
|
|
35
|
+
options.header.search = options.header?.search || true
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Add _searchIndexPath to enable search field to be initialised
|
|
39
|
+
options._searchIndexPath =
|
|
40
|
+
options.templates?.searchIndex?.permalink || '/search-index.json'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (options.templates?.feed) {
|
|
44
|
+
// Add _feedPath to enable feed to be linked to from page head
|
|
45
|
+
options._feedPath = options.templates?.feed?.permalink || '/feed.xml'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return deepmerge(defaults, options)
|
|
49
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import fs from 'node:fs/promises'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
|
|
4
|
+
import commonJs from '@rollup/plugin-commonjs'
|
|
5
|
+
import { nodeResolve } from '@rollup/plugin-node-resolve'
|
|
6
|
+
import terser from '@rollup/plugin-terser'
|
|
7
|
+
import { rollup } from 'rollup'
|
|
8
|
+
import * as sass from 'sass'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Generate NHS.UK Frontend assets
|
|
12
|
+
*
|
|
13
|
+
* @param {object} dir - Project directories
|
|
14
|
+
* @param {object} options - Plugin options
|
|
15
|
+
* @returns {Function} Eleventy event
|
|
16
|
+
*/
|
|
17
|
+
export async function generateAssets(dir, options) {
|
|
18
|
+
// Generate default CSS
|
|
19
|
+
// Ignored if custom stylesheets are used
|
|
20
|
+
if (options.stylesheets.length === 0) {
|
|
21
|
+
const inputFilePath = path.join(import.meta.dirname, '../application.scss')
|
|
22
|
+
const inputFile = await fs.readFile(inputFilePath)
|
|
23
|
+
const outputFile = `${dir.output}/assets/application.css`
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const result = sass.compileString(inputFile.toString(), {
|
|
27
|
+
importers: [new sass.NodePackageImporter()], // Imports with `pkg:`
|
|
28
|
+
loadPaths: ['./node_modules', '.'], // Imports without `pkg:`
|
|
29
|
+
quietDeps: true,
|
|
30
|
+
style: 'compressed'
|
|
31
|
+
})
|
|
32
|
+
fs.writeFile(outputFile, result.css)
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error(error)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Bundle JavaScript
|
|
39
|
+
try {
|
|
40
|
+
const jsFile = `${dir.output}/assets/application.js`
|
|
41
|
+
const bundle = await rollup({
|
|
42
|
+
input: path.join(import.meta.dirname, '../application.js'),
|
|
43
|
+
context: 'window',
|
|
44
|
+
plugins: [
|
|
45
|
+
nodeResolve(),
|
|
46
|
+
commonJs(),
|
|
47
|
+
terser({ format: { comments: false } })
|
|
48
|
+
]
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const { output } = await bundle.generate({ format: 'es' })
|
|
52
|
+
const { code } = output[0]
|
|
53
|
+
fs.writeFile(jsFile, code)
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error(error)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { currentPage as getCurrentPage } from '@x-govuk/govuk-eleventy-plugin/filters'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Indicate which is the current item in header navigation items
|
|
5
|
+
*
|
|
6
|
+
* @param {object} header - Header options
|
|
7
|
+
* @param {string} pageUrl - URL of current page
|
|
8
|
+
* @returns {Array} Header items
|
|
9
|
+
*/
|
|
10
|
+
export function currentPage(header, pageUrl) {
|
|
11
|
+
if (!header?.navigation?.items) {
|
|
12
|
+
return header
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
header.navigation.items = getCurrentPage(header.navigation.items, pageUrl)
|
|
16
|
+
|
|
17
|
+
return header
|
|
18
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export {
|
|
2
|
+
canonicalUrl,
|
|
3
|
+
govukDate, // Used by page templates in govuk-eleventy-plugin
|
|
4
|
+
govukDate as nhsukDate,
|
|
5
|
+
isoDate,
|
|
6
|
+
dateToRfc3339,
|
|
7
|
+
getNewestCollectionItemDate,
|
|
8
|
+
getNextNavigationItem,
|
|
9
|
+
getPreviousNavigationItem,
|
|
10
|
+
includes,
|
|
11
|
+
itemsFromNavigation,
|
|
12
|
+
itemsFromPagination,
|
|
13
|
+
noOrphans,
|
|
14
|
+
pretty,
|
|
15
|
+
sliceFromCollection,
|
|
16
|
+
smart,
|
|
17
|
+
tokenize
|
|
18
|
+
} from '@x-govuk/govuk-eleventy-plugin/filters'
|
|
19
|
+
export { currentPage } from './current-page.js'
|
|
20
|
+
export { itemsFromCollection } from './items-from-collection.js'
|
|
21
|
+
export { markdown } from './markdown.js'
|