@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.
Files changed (68) hide show
  1. package/LICENSE.txt +22 -0
  2. package/README.md +35 -0
  3. package/package.json +102 -0
  4. package/src/application.js +11 -0
  5. package/src/application.scss +2 -0
  6. package/src/components/_index.scss +12 -0
  7. package/src/components/attribution/_index.scss +13 -0
  8. package/src/components/blockquote/_index.scss +22 -0
  9. package/src/components/card-group/macro.njk +3 -0
  10. package/src/components/card-group/template.njk +26 -0
  11. package/src/components/code/_index.scss +153 -0
  12. package/src/components/contents-list/_index.scss +18 -0
  13. package/src/components/document-header/macro.njk +3 -0
  14. package/src/components/document-header/template.njk +10 -0
  15. package/src/components/document-list/macro.njk +3 -0
  16. package/src/components/document-list/template.njk +22 -0
  17. package/src/components/footnotes-list/_index.scss +55 -0
  18. package/src/components/heading/macro.njk +3 -0
  19. package/src/components/heading/template.njk +15 -0
  20. package/src/components/hero/_index.scss +17 -0
  21. package/src/components/hero/macro.njk +3 -0
  22. package/src/components/hero/template.njk +36 -0
  23. package/src/components/image/_index.scss +8 -0
  24. package/src/components/metadata/_index.scss +24 -0
  25. package/src/components/metadata/macro.njk +3 -0
  26. package/src/components/metadata/template.njk +50 -0
  27. package/src/components/prose-scope/_index.scss +72 -0
  28. package/src/components/prose-scope/macro.njk +3 -0
  29. package/src/components/prose-scope/template.njk +4 -0
  30. package/src/components/related/_index.scss +10 -0
  31. package/src/components/related/macro.njk +3 -0
  32. package/src/components/related/template.njk +17 -0
  33. package/src/components/search/_index.scss +120 -0
  34. package/src/components/search/search.js +133 -0
  35. package/src/components/sub-navigation/_index.scss +71 -0
  36. package/src/components/sub-navigation/macro.njk +3 -0
  37. package/src/components/sub-navigation/template.njk +27 -0
  38. package/src/data/eleventy-computed.js +17 -0
  39. package/src/data/options.js +49 -0
  40. package/src/events/generate-nhsuk-assets.js +57 -0
  41. package/src/filters/current-page.js +18 -0
  42. package/src/filters/index.js +21 -0
  43. package/src/filters/items-from-collection.js +73 -0
  44. package/src/filters/markdown.js +20 -0
  45. package/src/index.js +136 -0
  46. package/src/index.scss +5 -0
  47. package/src/layouts/base.njk +81 -0
  48. package/src/layouts/collection.njk +38 -0
  49. package/src/layouts/error.njk +11 -0
  50. package/src/layouts/feed.njk +32 -0
  51. package/src/layouts/hub.njk +31 -0
  52. package/src/layouts/page.njk +31 -0
  53. package/src/layouts/post.njk +47 -0
  54. package/src/layouts/product.njk +32 -0
  55. package/src/layouts/sitemap.njk +25 -0
  56. package/src/layouts/sub-navigation.njk +40 -0
  57. package/src/layouts/tag.njk +14 -0
  58. package/src/layouts/tags.njk +18 -0
  59. package/src/markdown-it/alert.js +36 -0
  60. package/src/markdown-it/deflist.js +16 -0
  61. package/src/markdown-it/figure.js +12 -0
  62. package/src/markdown-it/footnote.js +47 -0
  63. package/src/markdown-it/table.js +18 -0
  64. package/src/markdown-it.js +91 -0
  65. package/src/nunjucks.js +65 -0
  66. package/src/vendor/nhsuk-frontend/_index.scss +2 -0
  67. package/src/vendor/nhsuk-frontend/components/_index.scss +15 -0
  68. package/src/vendor/nhsuk-frontend/core/_index.scss +1 -0
@@ -0,0 +1,73 @@
1
+ import {
2
+ isoDate,
3
+ markdown,
4
+ nhsukDate,
5
+ sliceFromCollection,
6
+ smart
7
+ } from './index.js'
8
+
9
+ function isCollectionData(array) {
10
+ if (!Array.isArray(array) || array.length === 0) {
11
+ return false
12
+ }
13
+
14
+ return array.every((item) => {
15
+ return (
16
+ typeof item === 'object' &&
17
+ item !== null &&
18
+ Object.prototype.hasOwnProperty.call(item, 'content') &&
19
+ Object.prototype.hasOwnProperty.call(item, 'data') &&
20
+ Object.prototype.hasOwnProperty.call(item, 'page') &&
21
+ Object.prototype.hasOwnProperty.call(item, 'rawInput')
22
+ )
23
+ })
24
+ }
25
+
26
+ function getDescriptionHtml(item) {
27
+ let html = ''
28
+
29
+ if (item.date) {
30
+ const classes = item.description
31
+ ? 'nhsuk-body-s nhsuk-u-margin-bottom-2'
32
+ : 'nhsuk-body-s'
33
+
34
+ html += `<p class="${classes}"><time class="nhsuk-u-secondary-text-colour" datetime="${isoDate(item.date)}">${nhsukDate(item.date)}</time></p>`
35
+ }
36
+
37
+ if (item.description) {
38
+ html += `<p class="nhsuk-card__description">${markdown(item.description, 'inline')}</p>`
39
+ }
40
+
41
+ return html
42
+ }
43
+
44
+ /**
45
+ * Transform list of posts (that may be in a collection) to `items` array that * can be consumed by NHS.UK Frontend card components
46
+ *
47
+ * @param {Array} array - Eleventy collection data
48
+ * @param {number} [n] - Number of items to slice from collection
49
+ * @returns {Array<object>} `items` array
50
+ */
51
+ export function itemsFromCollection(array, n) {
52
+ if (isCollectionData(array)) {
53
+ array = array.map((item) => {
54
+ return {
55
+ href: item.url,
56
+ date: item.data.date,
57
+ title: item.data.title,
58
+ description: item.data.description,
59
+ image: item.data.image
60
+ }
61
+ })
62
+ }
63
+
64
+ array = array.map((item) => ({
65
+ href: item.href,
66
+ heading: smart(item.title),
67
+ descriptionHtml: getDescriptionHtml(item),
68
+ ...(item.image && { imgURL: item.image.src }),
69
+ ...(item.image && { imgALT: item.image.alt })
70
+ }))
71
+
72
+ return sliceFromCollection(array, n)
73
+ }
@@ -0,0 +1,20 @@
1
+ import { normalise } from '@x-govuk/govuk-eleventy-plugin/utils'
2
+
3
+ import { md } from '../markdown-it.js'
4
+
5
+ /**
6
+ * Convert Markdown into NHS.UK Frontend-compliant HTML
7
+ *
8
+ * @param {string} string - Markdown string
9
+ * @param {string} value - If `inline`, renders HTML without paragraph tags
10
+ * @returns {string} HTML
11
+ */
12
+ export function markdown(string, value) {
13
+ string = normalise(string, '')
14
+
15
+ if (value === 'inline') {
16
+ return md().renderInline(string)
17
+ }
18
+
19
+ return md().render(string)
20
+ }
package/src/index.js ADDED
@@ -0,0 +1,136 @@
1
+ import path from 'node:path'
2
+
3
+ import { EleventyHtmlBasePlugin } from '@11ty/eleventy'
4
+ import eleventyNavigation from '@11ty/eleventy-navigation'
5
+ import { addCollections } from '@x-govuk/govuk-eleventy-plugin/collections'
6
+ import { scssExtension } from '@x-govuk/govuk-eleventy-plugin/extensions'
7
+ import {
8
+ FeedTemplate,
9
+ PageNotFoundTemplate,
10
+ SearchIndexTemplate,
11
+ SitemapTemplate,
12
+ TagsTemplate,
13
+ TagTemplate
14
+ } from '@x-govuk/govuk-eleventy-plugin/templates'
15
+ import { getLayoutTemplates } from '@x-govuk/govuk-eleventy-plugin/utils'
16
+
17
+ import { eleventyComputed } from './data/eleventy-computed.js'
18
+ import { defaultPluginOptions } from './data/options.js'
19
+ import { generateAssets } from './events/generate-nhsuk-assets.js'
20
+ import * as filters from './filters/index.js'
21
+ import { md } from './markdown-it.js'
22
+ import { nunjucksConfig } from './nunjucks.js'
23
+
24
+ export const layoutFilenames = [
25
+ 'base.njk',
26
+ 'collection.njk',
27
+ 'error.njk',
28
+ 'feed.njk',
29
+ 'hub.njk',
30
+ 'page.njk',
31
+ 'post.njk',
32
+ 'product.njk',
33
+ 'sitemap.njk',
34
+ 'sub-navigation.njk',
35
+ 'tag.njk',
36
+ 'tags.njk'
37
+ ]
38
+
39
+ export const pageFilenames = ['404.md', 'sitemap.md', 'tag.md', 'tags.md']
40
+
41
+ export async function nhsukEleventyPlugin(eleventyConfig, pluginOptions = {}) {
42
+ const { pathPrefix } = eleventyConfig
43
+
44
+ // Plugin options
45
+ const options = defaultPluginOptions(pluginOptions, pathPrefix)
46
+
47
+ // Libraries
48
+ eleventyConfig.setLibrary('md', md(options))
49
+ eleventyConfig.setLibrary('njk', nunjucksConfig(eleventyConfig))
50
+
51
+ // Collections
52
+ await addCollections(eleventyConfig)
53
+
54
+ // Extensions and template formats
55
+ eleventyConfig.addExtension('scss', scssExtension)
56
+ eleventyConfig.addTemplateFormats('scss')
57
+
58
+ // Virtual layout templates
59
+ const baseDirectory = path.join(import.meta.dirname, '..')
60
+ const templates = await getLayoutTemplates(
61
+ eleventyConfig,
62
+ layoutFilenames,
63
+ baseDirectory
64
+ )
65
+ for (const [virtualPath, template] of Object.entries(templates)) {
66
+ eleventyConfig.addTemplate(virtualPath, template)
67
+ }
68
+
69
+ // Virtual page templates
70
+ if (options.templates?.error404) {
71
+ eleventyConfig.addTemplate(
72
+ '404.11ty.js',
73
+ new PageNotFoundTemplate(options.templates?.error404)
74
+ )
75
+ }
76
+
77
+ if (options.templates?.feed) {
78
+ eleventyConfig.addTemplate(
79
+ 'feed.11ty.js',
80
+ new FeedTemplate(options.templates?.feed, {
81
+ url: options?.url
82
+ })
83
+ )
84
+ }
85
+
86
+ if (options.templates?.searchIndex) {
87
+ eleventyConfig.addTemplate(
88
+ 'search-index.11ty.js',
89
+ new SearchIndexTemplate(options.templates.searchIndex)
90
+ )
91
+ }
92
+
93
+ if (options.templates?.sitemap) {
94
+ eleventyConfig.addTemplate(
95
+ 'sitemap.11ty.js',
96
+ new SitemapTemplate(options.templates.sitemap)
97
+ )
98
+ }
99
+
100
+ if (options.templates?.tags) {
101
+ const slugify = eleventyConfig.getFilter('slugify')
102
+
103
+ eleventyConfig.addTemplate(
104
+ 'tags.11ty.js',
105
+ new TagsTemplate(options.templates.tags)
106
+ )
107
+
108
+ eleventyConfig.addTemplate(
109
+ 'tag.11ty.js',
110
+ new TagTemplate({ ...options.templates.tags, slugify })
111
+ )
112
+ }
113
+
114
+ // Filters
115
+ for (const [name, filter] of Object.entries(filters)) {
116
+ eleventyConfig.addFilter(name, filter)
117
+ }
118
+
119
+ // Global data
120
+ eleventyConfig.addGlobalData('options', options)
121
+ eleventyConfig.addGlobalData('eleventyComputed', eleventyComputed)
122
+
123
+ // Passthrough
124
+ eleventyConfig.addPassthroughCopy({
125
+ 'node_modules/nhsuk-frontend/dist/nhsuk/assets': 'assets'
126
+ })
127
+
128
+ // Plugins
129
+ eleventyConfig.addPlugin(EleventyHtmlBasePlugin)
130
+ eleventyConfig.addPlugin(eleventyNavigation)
131
+
132
+ // Events
133
+ eleventyConfig.on('eleventy.after', async ({ dir }) => {
134
+ generateAssets(dir, options)
135
+ })
136
+ }
package/src/index.scss ADDED
@@ -0,0 +1,5 @@
1
+ // NHS.UK Frontend components
2
+ @forward "vendor/nhsuk-frontend";
3
+
4
+ // NHS.UK Eleventy Plugin components
5
+ @forward "components";
@@ -0,0 +1,81 @@
1
+ {% extends "nhsuk/template.njk" %}
2
+
3
+ {% set themeColor = options.themeColor | default("#005eb8", true) -%}
4
+
5
+ {#- Set the opengraphImageUrl in parent template to either the one
6
+ from the page metadata or else fallback to the generic one from options. -#}
7
+ {% set opengraphImage = image if image.opengraphImage else opengraphImage %}
8
+ {% set opengraphImageUrl = (opengraphImage.src | canonicalUrl) if opengraphImage else options.opengraphImageUrl %}
9
+
10
+ {# Pagination #}
11
+ {% set pageNumber = pagination.pageNumber + 1 %}
12
+ {% set pageCount = pagination.pages | length %}
13
+
14
+ {# Navigation #}
15
+ {% set breadcrumbItems = collections.all | eleventyNavigationBreadcrumb(eleventyNavigation.key, { includeSelf: includeInBreadcrumbs, allowMissing: true }) | itemsFromNavigation(page.url, options) if eleventyNavigation.key %}
16
+ {% set showBreadcrumbs = options.showBreadcrumbs != false and breadcrumbItems | length > 0 %}
17
+
18
+ {% from "nhsuk/components/breadcrumb/macro.njk" import breadcrumb as nhsukBreadcrumb %}
19
+ {% from "nhsuk/components/footer/macro.njk" import footer as nhsukFooter %}
20
+ {% from "nhsuk/components/header/macro.njk" import header as nhsukHeader %}
21
+ {% from "nhsuk/components/images/macro.njk" import image as nhsukImage %}
22
+ {% from "nhsuk/components/pagination/macro.njk" import pagination as nhsukPagination %}
23
+
24
+ {% from "components/card-group/macro.njk" import appCardGroup with context %}
25
+ {% from "components/document-header/macro.njk" import appDocumentHeader %}
26
+ {% from "components/document-list/macro.njk" import appDocumentList %}
27
+ {% from "components/heading/macro.njk" import appHeading %}
28
+ {% from "components/hero/macro.njk" import appHero with context %}
29
+ {% from "components/metadata/macro.njk" import appMetadata %}
30
+ {% from "components/prose-scope/macro.njk" import appProseScope %}
31
+ {% from "components/related/macro.njk" import appRelated with context %}
32
+ {% from "components/sub-navigation/macro.njk" import appSubNavigation %}
33
+
34
+ {% block headIcons %}
35
+ {%- if options.icons.shortcut %}<link rel="icon" href="{{ options.icons.shortcut }}" sizes="any">{% endif %}
36
+ {%- if options.icons.mask %}<link rel="mask-icon" href="{{ options.icons.mask }}" color="{{ themeColor }}">{% endif %}
37
+ {%- if options.icons.touch %}<link rel="apple-touch-icon" href="{{ options.icons.touch }}">{% endif %}
38
+ {% endblock %}
39
+
40
+ {% block head %}
41
+ <script src="/assets/application.js" type="module"></script>
42
+
43
+ {% for stylesheet in options.stylesheets %}
44
+ <link rel="stylesheet" href="{{ stylesheet }}">
45
+ {% else %}
46
+ <link rel="stylesheet" href="{{ "/assets/application.css" }}">
47
+ {% endfor %}
48
+
49
+ {% if options._feedPath %}<link rel="alternate" type="application/atom+xml" href="{{ options._feedPath }}" >{% endif %}
50
+
51
+ {% if options.url %}<meta property="og:url" content="{{ page.url | canonicalUrl }}">{% endif %}
52
+ <meta property="og:title" content="{{ title }}">
53
+ {% if description %}<meta property="og:description" name="description" content="{{ description | markdown("inline") | striptags(true) }}">{% endif %}
54
+ {% if opengraphImage.src %}<meta name="og:image" content="{{ opengraphImage.src | canonicalUrl }}">
55
+ {% endif %}
56
+ {% if opengraphImage.alt %}<meta property="og:image:alt" content="{{ opengraphImage.alt }}">{% endif %}
57
+ {% endblock %}
58
+
59
+ {% block pageTitle %}
60
+ {{- title if title -}}
61
+ {{- " (page " + pageNumber + " of " + pageCount + ")" if pageCount > 1 -}}
62
+ {{- " - " + options.titleSuffix if options.titleSuffix -}}
63
+ {% endblock %}
64
+
65
+ {% block header %}
66
+ {% if options._searchIndexPath %}
67
+ <app-search index="{{ options._searchIndexPath | htmlBaseUrl }}">
68
+ {{ nhsukHeader(options.header | currentPage(page.url)) }}
69
+ </app-search>
70
+ {% else %}
71
+ {{ nhsukHeader(options.header | currentPage(page.url)) }}
72
+ {% endif %}
73
+ {% endblock %}
74
+
75
+ {% block footer %}
76
+ {{ nhsukFooter(options.footer) }}
77
+ {% endblock %}
78
+
79
+ {% block bodyEnd %}
80
+ {% block scripts %}{% endblock %}
81
+ {% endblock %}
@@ -0,0 +1,38 @@
1
+ {% extends "layouts/base.njk" %}
2
+
3
+ {% block beforeContent %}
4
+ {{ nhsukBreadcrumb({
5
+ items: breadcrumbItems
6
+ }) if showBreadcrumbs }}
7
+ {% endblock %}
8
+
9
+ {% block content %}
10
+ {{ appDocumentHeader({
11
+ caption: caption,
12
+ title: title,
13
+ description: description
14
+ }) }}
15
+
16
+ {{ appProseScope(content) if content }}
17
+
18
+ {{ appHeading({
19
+ level: 2,
20
+ size: "l",
21
+ title: paginationHeading
22
+ }) if paginationHeading }}
23
+
24
+ {{ appDocumentList({
25
+ headingLevel: 3 if paginationHeading else 2,
26
+ items: pagination.items
27
+ }) }}
28
+
29
+ {{ nhsukPagination({
30
+ classes: "nhsuk-u-reading-width",
31
+ previousUrl: pagination.href.previous,
32
+ previousPage: pagination.page.previous | length + " items",
33
+ nextUrl: pagination.href.next,
34
+ nextPage: pagination.page.next | length + " items"
35
+ }) if pagination.pages.length > 1 }}
36
+
37
+ {{ appRelated(related) if related }}
38
+ {% endblock %}
@@ -0,0 +1,11 @@
1
+ {% extends "layouts/base.njk" %}
2
+
3
+ {% block content %}
4
+ {{ appHeading({
5
+ caption: caption,
6
+ title: title,
7
+ description: description
8
+ }) }}
9
+
10
+ {{ appProseScope(content) if content }}
11
+ {% endblock %}
@@ -0,0 +1,32 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <feed xmlns="http://www.w3.org/2005/Atom" xml:base="{{ options.url }}">
3
+ <title>{{ title or options.homeKey }}</title>
4
+ <link href="{{ page.url | canonicalUrl }}" rel="self"/>
5
+ <link href="{{ options.url }}"/>
6
+ <updated>{{ collections[collection.name] | getNewestCollectionItemDate | dateToRfc3339 }}</updated>
7
+ <id>{{ options.url }}</id>
8
+ {% for item in collections[collection.name] | sliceFromCollection(collection.limit) %}
9
+ {% set absolutePostUrl = item.url | canonicalUrl %}
10
+ <entry>
11
+ <title>{{ item.data.title }}</title>
12
+ <link href="{{ absolutePostUrl }}"/>
13
+ <updated>{{ item.date | dateToRfc3339 }}</updated>
14
+ <id>{{ absolutePostUrl }}</id>
15
+ {% for author in item.data.authors or [item.data.author] %}
16
+ <author>
17
+ <name>{{ author.name }}</name>
18
+ {% if author.url %}
19
+ <uri>{{ author.url }}</uri>
20
+ {% endif %}
21
+ </author>
22
+ {% endfor %}
23
+ <content xml:lang="{{ language or "en" }}" type="html">
24
+ <![CDATA[
25
+ {% if item.data.image %}<figure><img src="{{ item.data.image.src | canonicalUrl }}" alt="{{ item.data.image.alt }}">{% if item.data.image.caption %}<figcaption>{{ item.data.image.caption | markdown }}</figcaption>
26
+ {% endif %}</figure>{% endif %}
27
+ {{- item.templateContent | renderTransforms(item.data.page) }}
28
+ ]]>
29
+ </content>
30
+ </entry>
31
+ {% endfor %}
32
+ </feed>
@@ -0,0 +1,31 @@
1
+ {% extends "layouts/base.njk" %}
2
+
3
+ {% block beforeContent %}
4
+ {{ nhsukBreadcrumb({
5
+ items: breadcrumbItems
6
+ }) if showBreadcrumbs }}
7
+ {% endblock %}
8
+
9
+ {% block content %}
10
+ {{ appDocumentHeader({
11
+ caption: caption,
12
+ title: title,
13
+ description: description
14
+ }) }}
15
+
16
+ {{ appProseScope(content) if content }}
17
+
18
+ {% for group in groups %}
19
+ {{ appHeading({
20
+ level: 2,
21
+ size: "l",
22
+ caption: group.caption,
23
+ title: group.title,
24
+ description: group.description
25
+ }) if group.title }}
26
+
27
+ {{ appCardGroup(group) if group.items }}
28
+ {% endfor %}
29
+
30
+ {{ appRelated(related) if related }}
31
+ {% endblock %}
@@ -0,0 +1,31 @@
1
+ {% extends "layouts/base.njk" %}
2
+
3
+ {% block beforeContent %}
4
+ {{ nhsukBreadcrumb({
5
+ items: breadcrumbItems
6
+ }) if showBreadcrumbs }}
7
+ {% endblock %}
8
+
9
+ {% block content %}
10
+ {{ appDocumentHeader({
11
+ caption: caption,
12
+ title: title,
13
+ description: description
14
+ }) }}
15
+
16
+ {{ appProseScope(content) if content }}
17
+
18
+ {% if showPagination %}
19
+ {% set previous = collections.navigation | eleventyNavigation(sectionKey or options.homeKey) | getPreviousNavigationItem(page.url) %}
20
+ {% set next = collections.navigation | eleventyNavigation(sectionKey or options.homeKey) | getNextNavigationItem(page.url) %}
21
+ {{ nhsukPagination({
22
+ classes: "nhsuk-u-reading-width",
23
+ previousUrl: previous.url if previous,
24
+ previousPage: previous.title if previous,
25
+ nextUrl: next.url if next,
26
+ nextPage: next.title if next
27
+ }) }}
28
+ {% endif %}
29
+
30
+ {{ appRelated(related) if related }}
31
+ {% endblock %}
@@ -0,0 +1,47 @@
1
+ {% extends "layouts/base.njk" %}
2
+
3
+ {% block beforeContent %}
4
+ {{ nhsukBreadcrumb({
5
+ items: breadcrumbItems
6
+ }) if showBreadcrumbs }}
7
+ {% endblock %}
8
+
9
+ {% block content %}
10
+ {{ appDocumentHeader({
11
+ caption: caption,
12
+ title: title,
13
+ date: date
14
+ }) }}
15
+
16
+ {{ appMetadata({
17
+ date: date,
18
+ modified: modified,
19
+ author: author,
20
+ tags: tags
21
+ }) }}
22
+
23
+ {% call appProseScope() %}
24
+ {{ nhsukImage({
25
+ classes: "app-image--full",
26
+ src: image.src,
27
+ alt: image.alt,
28
+ caption: image.caption | markdown("inline")
29
+ }) if image }}
30
+
31
+ {{ content }}
32
+ {% endcall %}
33
+
34
+ {% if showPagination %}
35
+ {% set previous = collections.navigation | eleventyNavigation(sectionKey or options.homeKey) | getPreviousNavigationItem(page.url) %}
36
+ {% set next = collections.navigation | eleventyNavigation(sectionKey or options.homeKey) | getNextNavigationItem(page.url) %}
37
+ {{ nhsukPagination({
38
+ classes: "nhsuk-u-reading-width",
39
+ previousUrl: previous.url if previous,
40
+ previousPage: previous.title if previous,
41
+ nextUrl: next.url if next,
42
+ nextPage: next.title if next
43
+ }) }}
44
+ {% endif %}
45
+
46
+ {{ appRelated(related) if related }}
47
+ {% endblock %}
@@ -0,0 +1,32 @@
1
+ {% extends "layouts/base.njk" %}
2
+
3
+ {% block main %}
4
+ {{ appHero({
5
+ caption: caption,
6
+ title: title,
7
+ headingClasses: headingClasses,
8
+ description: description,
9
+ image: image,
10
+ startButton: startButton
11
+ }) }}
12
+
13
+ <main class="nhsuk-main-wrapper" id="maincontent">
14
+ <div class="nhsuk-width-container">
15
+ {% for group in groups %}
16
+ {{ appHeading({
17
+ level: 2,
18
+ size: "l",
19
+ caption: group.caption,
20
+ title: group.title,
21
+ description: group.description
22
+ }) if group.title }}
23
+
24
+ {{ appCardGroup(group) if group.items }}
25
+ {% endfor %}
26
+
27
+ {{ appProseScope(content) if content }}
28
+
29
+ {{ appRelated(related) if related }}
30
+ </div>
31
+ </main>
32
+ {% endblock %}
@@ -0,0 +1,25 @@
1
+ {% extends "layouts/base.njk" %}
2
+
3
+ {% block content %}
4
+ {{ appHeading({
5
+ caption: caption,
6
+ title: title,
7
+ description: description
8
+ }) }}
9
+
10
+ {{ appProseScope(content) if content }}
11
+
12
+ {% for item in collections.sitemap | eleventyNavigation(options.homeKey) %}
13
+ <nav class="nhsuk-contents-list">
14
+ <h2 class="nhsuk-heading-m nhsuk-u-margin-bottom-2">
15
+ <a class="nhsuk-link" href="{{ item.url | canonicalUrl | pretty }}">{{ item.title | smart }}</a>
16
+ </h2>
17
+ {% if item.excerpt %}
18
+ <p class="nhsuk-body">{{ item.excerpt | markdown("inline") | striptags(true) }}</p>
19
+ {% endif %}
20
+ {{ collections.sitemap | eleventyNavigation(item.key) | eleventyNavigationToHtml({
21
+ listElement: "ol"
22
+ }) | safe }}
23
+ </nav>
24
+ {% endfor %}
25
+ {% endblock %}
@@ -0,0 +1,40 @@
1
+ {% extends "layouts/base.njk" %}
2
+
3
+ {% block beforeContent %}
4
+ {{ nhsukBreadcrumb({
5
+ items: breadcrumbItems
6
+ }) if showBreadcrumbs }}
7
+ {% endblock %}
8
+
9
+ {% block content %}
10
+ <div class="nhsuk-grid-row">
11
+ <div class="nhsuk-grid-column-one-quarter">
12
+ {{ appSubNavigation({
13
+ items: collections.navigation | eleventyNavigation(sectionKey or options.homeKey) | itemsFromNavigation(page.url, { pathPrefix: options.pathPrefix }, true)
14
+ }) }}
15
+ </div>
16
+ <div class="nhsuk-grid-column-three-quarters">
17
+ {{ appDocumentHeader({
18
+ caption: caption,
19
+ title: title,
20
+ description: description
21
+ }) }}
22
+
23
+ {{ appProseScope(content) if content }}
24
+
25
+ {% if showPagination %}
26
+ {% set previous = collections.navigation | eleventyNavigation(sectionKey or options.homeKey) | getPreviousNavigationItem(page.url) %}
27
+ {% set next = collections.navigation | eleventyNavigation(sectionKey or options.homeKey) | getNextNavigationItem(page.url) %}
28
+ {{ nhsukPagination({
29
+ classes: "nhsuk-u-reading-width",
30
+ previousUrl: previous.url if previous,
31
+ previousPage: previous.title if previous,
32
+ nextUrl: next.url if next,
33
+ nextPage: next.title if next
34
+ }) }}
35
+ {% endif %}
36
+
37
+ {{ appRelated(related) if related }}
38
+ </div>
39
+ </div>
40
+ {% endblock %}
@@ -0,0 +1,14 @@
1
+ {% extends "layouts/base.njk" %}
2
+
3
+ {% block content %}
4
+ {{ appHeading({
5
+ caption: caption,
6
+ title: title,
7
+ description: description
8
+ }) }}
9
+
10
+ {{ appDocumentList({
11
+ headingLevel: 3 if paginationHeading else 2,
12
+ items: collections[tag] | reverse
13
+ }) }}
14
+ {% endblock %}
@@ -0,0 +1,18 @@
1
+ {% extends "layouts/base.njk" %}
2
+
3
+ {% block content %}
4
+ {{ appHeading({
5
+ caption: caption,
6
+ title: title,
7
+ description: description
8
+ }) }}
9
+
10
+ <ul class="nhsuk-list nhsuk-list--bullet">
11
+ {% for tag in collections.tags %}
12
+ <li>
13
+ <a class="nhsuk-link" href="{{ tag | slug }}">{{ tag }}</a>
14
+ ({{ collections[tag] | length }})
15
+ </li>
16
+ {% endfor %}
17
+ </ul>
18
+ {% endblock %}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Render a GitHub-style alert
3
+ *
4
+ * @param {Function} md - markdown-it instance
5
+ */
6
+ export function alertRules(md) {
7
+ const { rules } = md.renderer
8
+
9
+ rules.alert_open = function (tokens, idx) {
10
+ const { title, type } = tokens[idx].meta
11
+
12
+ const visuallyHiddenTitle = type.charAt(0).toUpperCase() + type.slice(1)
13
+ const hasCustomTitle = title !== visuallyHiddenTitle
14
+
15
+ if (['caution', 'important', 'warning'].includes(type)) {
16
+ let html = `<div class="nhsuk-warning-callout app-warning-callout--${type}">`
17
+
18
+ // Warning callout always shows a heading, either a custom title,
19
+ // else the type of alert
20
+ html += hasCustomTitle
21
+ ? `<h3 class="nhsuk-warning-callout__label"><span class="nhsuk-u-visually-hidden">${visuallyHiddenTitle}: </span>${title}</h3>`
22
+ : `<h3 class="nhsuk-warning-callout__label">${visuallyHiddenTitle}</h3>`
23
+
24
+ return html
25
+ }
26
+
27
+ let html = `<div class="nhsuk-inset-text app-inset-text--${type}">`
28
+
29
+ // Inset text only shows a heading if there is a custom title
30
+ html += hasCustomTitle
31
+ ? `<h3 class="nhsuk-heading-m"><span class="nhsuk-u-visually-hidden">${visuallyHiddenTitle}: </span>${title}</h3>`
32
+ : `<span class="nhsuk-u-visually-hidden">${visuallyHiddenTitle}: </span>`
33
+
34
+ return html
35
+ }
36
+ }