diff --git a/. prettierrc b/.prettierrc similarity index 100% rename from . prettierrc rename to .prettierrc diff --git a/app/assets/sass/components/_definition-list.scss b/app/assets/sass/components/_definition-list.scss new file mode 100644 index 0000000..4f97263 --- /dev/null +++ b/app/assets/sass/components/_definition-list.scss @@ -0,0 +1,118 @@ +.definition-list { + $this: &; + + margin-bottom: 1em; + line-height: 1.5; + + @include nhsuk-font-size(19); + @include adjust-heading($size: 19); + + margin-bottom: 1em; + + &__title, + &__description { + display: block; + word-break: break-word; + } + + &__title { + font-weight: bold; + } + + &__description { + @include wysiwyg-content; + + margin-left: 0; + } + + &__group { + &:nth-last-child(n + 2) { + padding-bottom: nhsuk-spacing(3); + } + } + + &--small { + @include nhsuk-font-size(16); + @include adjust-heading($size: 16); + } + + &--inline { + #{$this}__title, + #{$this}__description { + display: inline; + } + + #{$this}__title { + margin-right: nhsuk-spacing(1); + } + + #{$this}__group { + padding-bottom: 0; + } + + #{$this}__description { + &:nth-of-type(n + 2) { + display: block; + } + } + + p { + display: inline-block; + margin-bottom: 0; + } + } + + &--separated { + @include nhsuk-media-query($from: tablet) { + #{$this}__group { + display: block; + + @supports (grid-area: auto) { + display: grid; + grid-template-columns: 200px 1fr; + grid-gap: 0 nhsuk-spacing(5); + } + } + + #{$this}__title { + grid-column-start: 1; + } + + #{$this}__description { + grid-column-start: 2; + } + } + } + + &--zebra-striped { + margin-bottom: nhsuk-spacing(3); + padding-top: 20px; + border-bottom: 2px solid $nhsuk-form-border-color; + + &__group { + border-top: 2px solid $nhsuk-form-border-color; + } + + & > :nth-child(odd) { + background-color: $color_nhsuk-white; + } + + & > :nth-child(even) { + background-color: $color_nhsuk-grey-4; + } + + #{$this}__group { + padding: nhsuk-spacing(3); + // border-bottom: 1px solid $nhsuk-form-border-color; + + &:last-child { + margin-bottom: 0; + border-bottom: 0; + } + + #{$this}__title { + margin-bottom: 0.5em; + } + } + } +} diff --git a/app/assets/sass/components/_icons.scss b/app/assets/sass/components/_icons.scss new file mode 100644 index 0000000..5e27b08 --- /dev/null +++ b/app/assets/sass/components/_icons.scss @@ -0,0 +1,71 @@ +.certificate-icon { + width: 38px; + height: 48px; + + .cls-1, .cls-2, .cls-3 { + fill: none; + } + + // .cls-3, .cls-4, .cls-2 { + // stroke-width: 2.4px; + // } + + .cls-2, .cls-3, .cls-4 { + stroke: #005eb8; + stroke-width: 2.4px; + stroke-linecap: round; + stroke-linejoin: round; + } + + .cls-5, .cls-4 { + fill: #f2f8fd; + } + + .cls-6 { + clip-path: url(#clippath); + } + + &--small { + width: 19px; + height: 25px; + + + // .cls-4, .cls-2, .cls-3 { + // stroke-width: 2px; + // } + + .cls-4, .cls-2, .cls-3 { + stroke: $color_nhsuk-grey-2; + stroke-width: 2px; + stroke-linecap: round; + stroke-linejoin: round; + } + } +} + +// Grey small + // .cls-1, .cls-2, .cls-3 { + // fill: none; + // } + + // .cls-3 { + // stroke-width: 1.2px; + // } + + // .cls-4, .cls-2 { + // stroke-width: .9px; + // } + + // .cls-4, .cls-2, .cls-3 { + // stroke: #aeb7bd; + // stroke-linecap: round; + // stroke-linejoin: round; + // } + + // .cls-4, .cls-5 { + // fill: #f2f8fd; + // } + + // .cls-6 { + // clip-path: url(#clippath); + // } diff --git a/app/assets/sass/components/_progress.scss b/app/assets/sass/components/_progress.scss index ce40d71..9d14870 100644 --- a/app/assets/sass/components/_progress.scss +++ b/app/assets/sass/components/_progress.scss @@ -46,6 +46,7 @@ margin-bottom: nhsuk-spacing(3); border-radius: 6px; border: 1px solid $color_nhsuk-green; + position: relative; } // &__action {} diff --git a/app/assets/sass/components/_quick-filters.scss b/app/assets/sass/components/_quick-filters.scss index 98c3c9a..53fda7d 100644 --- a/app/assets/sass/components/_quick-filters.scss +++ b/app/assets/sass/components/_quick-filters.scss @@ -26,8 +26,20 @@ } &__list-item { - margin: nhsuk-spacing(1) 0 !important; - padding: 0 nhsuk-spacing(1); + display: flex; + align-items: center; + min-height: 44px; + margin-bottom: nhsuk-spacing(2); + padding: 0 nhsuk-spacing(2); + + &:hover { + background-color: $color_nhsuk-grey-4; + border-radius: $nhsuk-border-radius; + } + + &:last-child { + margin-bottom: nhsuk-spacing(2); + } } &__order-filter { @@ -38,23 +50,37 @@ @include nhsuk-font($size: 16, $weight: bold, $line-height: 1); display: inline-block; - padding: nhsuk-spacing(1) nhsuk-spacing(2); + padding: 4px 14px; border: 1px solid $color_nhsuk-grey-3; border-radius: 3px; outline: 2px solid transparent; outline-offset: -2px; background-color: $color_nhsuk-white; + // background-color: $color_nhsuk-grey-5; color: $color_nhsuk-black; text-decoration: none; + &:visited { + color: $color_nhsuk-black; + } + &:focus { @include nhsuk-focused-button; + + border: 2px solid; + box-shadow: none; } &--active { + padding: 4px 6px 4px 5px; background-color: nhsuk-tint($color_nhsuk-blue, 80%); border-color: nhsuk-shade($color_nhsuk-blue, 30%); color: nhsuk-shade($color_nhsuk-blue, 30%); + + &:before { + content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='10' viewBox='0 0 12 10' fill='none'%3E%3Cpath d='M1.5 5.45455L4.83333 8L10.5 1' stroke='%23004281' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E"); + display: inline-block; + } } } } diff --git a/app/assets/sass/components/_rating.scss b/app/assets/sass/components/_rating.scss new file mode 100644 index 0000000..131cbed --- /dev/null +++ b/app/assets/sass/components/_rating.scss @@ -0,0 +1,74 @@ +.tel-rating { + $this: &; + @extend .nhsuk-u-font-size-16; + + display: flex; + align-items: center; + flex-wrap: wrap; + margin-bottom: nhsuk-spacing(3); + color: $nhsuk-secondary-text-color; + + &__container { + margin-bottom: nhsuk-spacing(2); + + } + + &__cover { + background: white; + height: 100%; + overflow: hidden; + position: absolute; + top: 0; + right: 0; + } + + &--star { + #{$this}__container { + padding: 0 nhsuk-spacing(3) 0 0; + } + + #{$this}__progress { + flex: 0; + height: 20px; + position: relative; + white-space: nowrap; + + svg { + width: 24px; + fill: gold; + } + + #{$this}__cover { + height: 20px; + mix-blend-mode: color; + } + } + + #{$this}__description {} + } + + &--progress-bar { + #{$this}__container { + width: 100%; + } + + #{$this}__progress { + overflow: hidden; + height: 8px; + margin-right: 6px; + margin-bottom: nhsuk-spacing(3); + border-radius: 6px; + border: 1px solid $color_nhsuk-green; + position: relative; + white-space: nowrap; + background-color: $color_nhsuk-green; + } + + #{$this}__completion {} + + #{$this}__cover { + height: 8px; + mix-blend-mode: background-color; + } + } +} diff --git a/app/assets/sass/components/_tel-list.scss b/app/assets/sass/components/_tel-list.scss new file mode 100644 index 0000000..bfd1161 --- /dev/null +++ b/app/assets/sass/components/_tel-list.scss @@ -0,0 +1,5 @@ +.tel-list li { + border-bottom: 1px solid $color_nhsuk-grey-4; + padding: nhsuk-spacing(3) nhsuk-spacing(0) nhsuk-spacing(0); + margin-bottom: nhsuk-spacing(5); +} diff --git a/app/assets/sass/components/_utilities.scss b/app/assets/sass/components/_utilities.scss index 9dbfdb9..9b59897 100644 --- a/app/assets/sass/components/_utilities.scss +++ b/app/assets/sass/components/_utilities.scss @@ -4,3 +4,7 @@ margin-top: 5px; margin-bottom: 5px; } + +.no-list-style { + @include no-list-style; +} diff --git a/app/assets/sass/components/nhsuk-overrides/_tel-learning-card.scss b/app/assets/sass/components/nhsuk-overrides/_tel-learning-card.scss new file mode 100644 index 0000000..11f0158 --- /dev/null +++ b/app/assets/sass/components/nhsuk-overrides/_tel-learning-card.scss @@ -0,0 +1,125 @@ +.tel-learning-listing { + $this: &; + + display: flex; + flex: 1; + flex-direction: column; + + &--course-card { + box-shadow: 4px 6px 0 0 #1C366A; + } + + &--learning-card { + border-radius: $global-radius; + overflow: hidden; + + & .nhsuk-card__content { + display: flex; + flex-direction: column; + flex: 1; + padding: nhsuk-spacing(4) 0 0 0; + } + + #{$this}__heading, + #{$this}__content { + padding: 0 nhsuk-spacing(4); + } + + #{$this}__catalogue { + padding: nhsuk-spacing(3) nhsuk-spacing(4); + } + + #{$this}__developed-with { + padding: nhsuk-spacing(1) nhsuk-spacing(4); + } + + #{$this}__footer { + flex: 1; + align-content: end; + } + } + + &__heading { + margin-bottom: nhsuk-spacing(3); + } + + &__heading-link {} + + &__heading-text { + @include nhsuk-font(19, $weight: normal); + @include adjust-heading(19); + + margin-bottom: nhsuk-spacing(0); + + @include nhsuk-media-query($from: tablet) { + @include adjust-heading(19); + } + } + + &__description > * { + @include nhsuk-font-size(16); + + margin-bottom: nhsuk-spacing(3); + } + + &__key-info { + display: flex; + // justify-content: space-between; + align-items: baseline; + } + + &__key-info__information__dl { + display: flex; + flex-wrap: wrap; + margin: 0 0 nhsuk-spacing(2) 0; + + .definition-list__group{ + margin: 0 nhsuk-spacing(3) nhsuk-spacing(1) 0; + flex: 1 0 max-content; + } + } + + &__key-info__status { + flex: 1 0 content; + + margin: 0 0 nhsuk-spacing(2) 0; + text-align: right; + } + + &__catalogue { + display: flex; + // justify-content: space-between; + border-top: 1px solid $nhsuk-border-color; + padding-top: nhsuk-spacing(3); + margin-bottom: nhsuk-spacing(3); + align-items: center; + } + + &__catalogue-link { + @include nhsuk-font-size(16); + + display: inline-block; + } + + &__catalogue-image { + width: 32Px; + height: 32px; + margin-right: nhsuk-spacing(3); + border: 1px solid $nhsuk-form-border-color; + border-radius: $global-radius; + + // @include nhsuk-media-query($from: tablet) { + // width: 54px; + // height: 54px; + // } + } + + &__developed-with { + @include nhsuk-font-size(14); + @include adjust-heading(14); + + // padding: nhsuk-spacing(2) nhsuk-spacing(4); + background: $color_nhsuk-blue; + color: $color_nhsuk-white; + } +} diff --git a/app/assets/sass/main.scss b/app/assets/sass/main.scss index 5ea916f..514f637 100755 --- a/app/assets/sass/main.scss +++ b/app/assets/sass/main.scss @@ -12,13 +12,18 @@ // Custom prototyping components @import 'components/certificate'; +@import 'components/definition-list'; +@import 'components/tel-list'; + @import 'components/featured-media'; @import 'components/form-elements'; +@import 'components/icons'; @import 'components/learning-log'; @import 'components/picture'; @import 'components/progress'; @import 'components/quick-filters'; @import 'components/search'; +@import 'components/rating'; @import 'components/user-entry'; @import 'components/utilities'; @@ -29,6 +34,7 @@ // NHSUK front-end overrides @import 'components/nhsuk-overrides/card'; +@import 'components/nhsuk-overrides/tel-learning-card'; @import 'components/nhsuk-overrides/expander'; @import 'components/nhsuk-overrides/list-border'; @import 'components/nhsuk-overrides/summary-list'; diff --git a/app/views/components/learning-card/README.md b/app/views/components/learning-card/README.md new file mode 100644 index 0000000..2419282 --- /dev/null +++ b/app/views/components/learning-card/README.md @@ -0,0 +1,189 @@ +# Task list + +## Guidance + +Find out more about the task-list component and when to use it in the [NHS digital service manual](https://service-manual.nhs.uk/design-system/components/tabs). + +## Quick start example + +[Preview the task list component](https://nhsuk.github.io/nhsuk-frontend/components/task-list/index.html) + +### HTML markup + +```html + +``` + +### Nunjucks macro + +```html +{% from 'components/task-list/macro.njk' import taskList %} + +{{ taskList({ + idPrefix: "your-health", + items: [ + { + title: { + text: "Exercise" + }, + href: "#", + status: { + text: "Completed", + classes: "nhsuk-task-list__status--completed" + } + }, + { + title: { + text: "Personal health" + }, + href: "#", + status: { + text: "Completed", + classes: "nhsuk-task-list__status--completed" + } + }, + { + title: { + text: "Family health history" + }, + hint: { + text: "Details of your parents and siblings" + }, + href: "#", + status: { + tag: { + text: "Incomplete", + classes: "nhsuk-tag--blue" + } + } + }, + { + title: { + text: "Smoking history" + }, + href: "#", + status: { + tag: { + text: "Incomplete", + classes: "nhsuk-tag--blue" + } + } + }, + { + title: { + text: "Blood test" + }, + status: { + text: "Cannot start yet", + classes: "nhsuk-task-list__status--cannot-start-yet" + } + } + ] +}) }} +``` + +## Nunjucks arguments + +The task list Nunjucks macro takes the following arguments: + +| Name | Type | Required | Description | +| -------------- | ------ | -------- | ------------------------------------------------------------------------------ | +| **items** | array | Yes | The items for each task within the task list component. See items. | +| **classes** | string | No | Classes to add to the `ul` container for the task list. | +| **attributes** | object | No | HTML attributes (for example data attributes) to add to the `ul` container for the task list. | +| **idPrefix** | string | No | Optional prefix. This is used to prefix the `id` attribute for the task list item tag and hint, separated by `-`. Defaults to `"task-list"`. | + +### Options for `items` array objects + +| Name | Type | Required | Description | +| -------------- | ------ | -------- | ----------------------------------------------------------------------------------------------- | +| **title** | object | Yes | The main title for the task within the task list component. See title. | +| **hint** | object | No | Can be used to add a hint to each task within the task list component. See items hint. | +| **status** | object | Yes | The status for each task within the task list component. See items status. | +| **href** | string | No | The value of the link’s `href` attribute for the task list item. | +| **classes** | object | No | Classes to add to the item `div`. | + +### Options for `title` object + +| Name | Type | Required | Description | +| -------------- | ------ | -------- | ----------------------------------------------------------------------------------------------- | +| **text** | string | Yes | Text to use within the title. If `html` is provided, the `text` argument will be ignored. | +| **html** | string | Yes | HTML to use within the title. If `html` is provided, the `text` argument will be ignored. | +| **classes** | object | No | Classes to add to the title wrapper. | + +### Options for `hint` object + +| Name | Type | Required | Description | +| -------------- | ------ | -------- | ----------------------------------------------------------------------------------------------- | +| **text** | string | Yes | Text to use within the hint. If `html` is provided, the `text` argument will be ignored. | +| **html** | string | Yes | HTML to use within the hint. If `html` is provided, the `text` argument will be ignored. | + +### Options for `status` object + +| Name | Type | Required | Description | +| -------------- | ------ | -------- | ----------------------------------------------------------------------------------------------- | +| **tag** | object | No | Can be used to add a tag to the status of the task within the task list component. See tag. | +| **text** | string | No | Text to use for the status, as an alternative to using a tag. If `html` or `tag` is provided, the `text` argument will be ignored. | +| **html** | string | No | HTML to use for the status, as an alternative to using a tag. If `html` or `tag` is provided, the `text` argument will be ignored. | +| **classes** | string | No | Classes to add to the status container. | + + +If you are using Nunjucks macros in production be aware that using `html` arguments, or ones ending with `html` can be a [security risk](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting). Read more about this in the [Nunjucks documentation](https://mozilla.github.io/nunjucks/api.html#user-defined-templates-warning). diff --git a/app/views/components/learning-card/macro.njk b/app/views/components/learning-card/macro.njk new file mode 100644 index 0000000..b74d811 --- /dev/null +++ b/app/views/components/learning-card/macro.njk @@ -0,0 +1,3 @@ +{% macro learningCard(params) %} + {%- include './template.njk' -%} +{% endmacro %} diff --git a/app/views/components/learning-card/template.njk b/app/views/components/learning-card/template.njk new file mode 100644 index 0000000..5b9ae6a --- /dev/null +++ b/app/views/components/learning-card/template.njk @@ -0,0 +1,60 @@ +{% from "../macros/attributes.njk" import nhsukAttributes %} +{% from "tag/macro.njk" import tag %} + +{% set headingLevel = params.headingLevel if params.headingLevel else 2 %} + +
+{%- if params.imgURL %} + {{ params.imgALT }} +{%- endif %} +
+ {%- if params.headingHtml %} + {{ params.headingHtml | safe }} + {%- else %} + + {%- if params.href and not params.feature %} + {{ params.heading | safe }} + {%- else %} + {%- if params.type %} + + {%- if params.type === 'non-urgent' %}Non-urgent advice: + {%- elseif params.type === 'urgent' %}Urgent advice: + {%- elseif params.type === 'emergency' %}Immediate action required: + {%- else %}Non-urgent advice:{% endif %} {{ params.heading }} + {%- else %} + {{ params.heading }} + {% endif %} + {%- endif %} + + {%- if params.type %} + +
+ {% endif %} + {%- endif %} + {%- if params.type %} +
+{%- endif %} +{%- if caller or params.descriptionHtml %} + {{ caller() if caller else params.descriptionHtml | safe }} +{%- elif params.HTML %} + {{ params.HTML | safe }} +{%- elif params.description %} +

{{ params.description | safe }}

+{%- else %} +{%- endif %} + {% if params.primary %} + + {% endif %} +
+
diff --git a/app/views/components/macros/attributes.njk b/app/views/components/macros/attributes.njk new file mode 100644 index 0000000..8ef9666 --- /dev/null +++ b/app/views/components/macros/attributes.njk @@ -0,0 +1,96 @@ +{# Adapted from https://github.com/alphagov/govuk-frontend/blob/main/packages/govuk-frontend/src/govuk/macros/attributes.njk #} + +{# + Renders component attributes as string + + * By default or using `optional: false`, attributes render as ` name="value"` + * Using `optional: true`, attributes with empty (`null`, `undefined` or `false`) values are omitted + * Using `optional: true`, attributes with `true` (boolean) values render `name` only without value + + {@link https://developer.mozilla.org/en-US/docs/Glossary/Boolean/HTML} + + @example + Output attribute ` aria-hidden="true"` when `true` (boolean) or `"true"` (string) + + ```njk + nhsukAttributes({ + "aria-hidden": true + }) + ``` + + @example + Output attribute ` aria-hidden="false"` when `false` (boolean) or `"false"` (string) + + ```njk + nhsukAttributes({ + "aria-hidden": false + }) + ``` + + @example + Output attribute ` hidden=""` when `null`, `undefined` or empty `""` (string) + + ```njk + nhsukAttributes({ + "hidden": undefined + }) + ``` + + @example + Output attribute ` hidden` as boolean attribute when optional and `true` + + ```njk + nhsukAttributes({ + hidden: { + value: true, + optional: true + }, + }) + ``` + + @example + Output empty string when optional and `null`, `undefined` or `false` + + ```njk + nhsukAttributes({ + hidden: { + value: undefined, + optional: true + }, + }) + ``` + + @private + @param {{ [attribute: string]: string | { value: string, optional?: boolean } } | string} attributes - Component attributes param +#} +{% macro nhsukAttributes(attributes) -%} + {#- Default attributes output -#} + {% set attributesHtml = attributes if attributes is string else "" %} + + {#- Append attribute name/value pairs -#} + {%- if attributes is mapping %} + {% for name, value in attributes %} + {#- Detect if this is a `safe` filtered value. Just pass the value through if so. -#} + {#- https://github.com/alphagov/govuk-frontend/issues/4937 -#} + {% if value is mapping and not [undefined, null].includes(value.val) and value.length %} + {% set value = value.val %} + {% endif %} + + {#- Set default attribute options -#} + {% set options = value if value is mapping else { + value: value, + optional: false + } %} + + {#- Output ` name` only (no value) for boolean attributes -#} + {% if options.optional === true and options.value === true %} + {% set attributesHtml = attributesHtml + " " + name | escape %} + {#- Skip optional empty attributes or output ` name="value"` pair by default -#} + {% elif (options.optional === true and not [undefined, null, false].includes(options.value)) or options.optional !== true %} + {% set attributesHtml = attributesHtml + " " + name | escape + '="' + options.value | escape + '"' %} + {% endif %} + {% endfor %} + {% endif -%} + + {{- attributesHtml | safe -}} +{%- endmacro %} diff --git a/app/views/components/macros/certificate-icon.njk b/app/views/components/macros/certificate-icon.njk new file mode 100644 index 0000000..1c6d693 --- /dev/null +++ b/app/views/components/macros/certificate-icon.njk @@ -0,0 +1,59 @@ +{% macro certificateIcon(classes='') %} + + + + + + + + + + + + + + {# + + + + + + + + + + + + + + + + + #} +{% endmacro %} diff --git a/app/views/components/macros/definition-list.njk b/app/views/components/macros/definition-list.njk new file mode 100644 index 0000000..fc3c00f --- /dev/null +++ b/app/views/components/macros/definition-list.njk @@ -0,0 +1,12 @@ +{% macro definitionList(groups=[], type='inline', additionalClasses='', size='') %} +
+ {% for group in groups %} +
+
{{ group.title | safe }}
+ {% for description in group.descriptions %} +
{{ description | safe }}
+ {% endfor %} +
+ {% endfor %} +
+{% endmacro %} diff --git a/app/views/components/macros/elearning-activity-information.njk b/app/views/components/macros/elearning-activity-information.njk new file mode 100644 index 0000000..232fb75 --- /dev/null +++ b/app/views/components/macros/elearning-activity-information.njk @@ -0,0 +1,94 @@ +{% from 'tag/macro.njk' import tag %} +{% from "components/macros/certificate-icon.njk" import certificateIcon %} +{% from "components/macros/definition-list.njk" import definitionList %} +{% from "components/rating.njk" import rating %} + +{# {% set definitionList1 = [ + { + title: "Type:", + descriptions: ["Course"] + }, + { + title: "Accessed:", + descriptions: ["22 Jan 2028"] + }] +%} #} + +{% macro elearningActivityInformation(progress, additionalClasses='') %} + {% if not progress or progress == 0 or progress == 'not-started' %} + {#

Not started

#} + +
+ {{ definitionList( + additionalClasses="tel-learning-listing__key-info__information__dl", + groups=[{ + title: "includes:", + descriptions: ["7 Activities", "with 1 certificate" + certificateIcon(classes="certificate-icon--small")] + }], + size="small") + }} +
+ + {#
+ includes 7 Activities + with 1 certificate + {{ certificateIcon() }} +
+ +
+ {{ certificateIcon(classes="certificate-icon--small") }} + Includes a certificate +
#} + {% elseif progress is number and progress < 100 %} + {#

In progress

#} + +
+
+ {{ definitionList( + additionalClasses="tel-learning-listing__key-info__information__dl", + groups=[ + { + title: "Type:", + descriptions: ["Course"] + }, + { + title: "Accessed:", + descriptions: ["22 Jan 2028"] + }], + size="small") + }} +
+ +
+ {{ tag({ text: "In progress", classes: "nhsuk-tag--blue" })}} +
+
+ + {{ rating(type='progress-bar', progress=progress) }} + + {% elseif progress == 100 or progress == 'complete' or progress == 'completed' %} + {#

Completed

#} + +
+
+ {{ definitionList( + additionalClasses="tel-learning-listing__key-info__information__dl", + groups=[ + { + title: "Type:", + descriptions: ["Course"] + }, + { + title: "Awarded:", + descriptions: ["22 Jan 2028"] + }], + size="small") + }} +
+ +
+ {{ tag({ text: "Completed", classes: "nhsuk-tag--green" })}} +
+
+ {% endif %} +{% endmacro %} diff --git a/app/views/components/quick-filters/macro.njk b/app/views/components/quick-filters/macro.njk new file mode 100644 index 0000000..d11c3eb --- /dev/null +++ b/app/views/components/quick-filters/macro.njk @@ -0,0 +1,3 @@ +{% macro quickFilters(params) %} + {%- include './template.njk' -%} +{% endmacro %} diff --git a/app/views/components/quick-filters/template.njk b/app/views/components/quick-filters/template.njk new file mode 100644 index 0000000..af31ab2 --- /dev/null +++ b/app/views/components/quick-filters/template.njk @@ -0,0 +1,40 @@ +{% from "../macros/attributes.njk" import nhsukAttributes %} + +{%- set useLinks = params.useLinks if params.useLinks is not undefined else false -%} +{%- set listHeading = params.listHeading if params.listHeading is not undefined else "Show" -%} + + diff --git a/app/views/components/rating.njk b/app/views/components/rating.njk new file mode 100644 index 0000000..cd11145 --- /dev/null +++ b/app/views/components/rating.njk @@ -0,0 +1,26 @@ +{% macro rating(type='star', progress, additionalClasses='') %} +
+
+
+ {% if type == 'star' %} + + + + + + + + + + + + {% endif %} + +
+
+
+
+ +
{{ (5 / 100 * progress) | int }} out of 5 (8 ratings )
+
+{% endmacro %} diff --git a/app/views/components/task-list/macro.njk b/app/views/components/task-list/macro.njk index d7c4837..fcede7b 100644 --- a/app/views/components/task-list/macro.njk +++ b/app/views/components/task-list/macro.njk @@ -1,3 +1,5 @@ +{# NOTE : This will have been added in the update to version 6.1.0 and will need to be compared and removed in a PR #} + {% macro taskList(params) %} {%- include './template.njk' -%} {% endmacro %} diff --git a/app/views/elements/data/learning-cards-params.njk b/app/views/elements/data/learning-cards-params.njk new file mode 100644 index 0000000..f152b14 --- /dev/null +++ b/app/views/elements/data/learning-cards-params.njk @@ -0,0 +1,237 @@ +{# Format content like the below +{% + set learningCardContent = { + lvl1: { + lvl2: '' + }, + } +%} + +I'll need content for each iof these: + + imageUrl: use unsplash image urls, images want to be 525w X 225h + title: '', + description: '', - max length of 125 characters + starRatingScore: '' - a number between 0 and 5 with 1 decimal place + starRating: '' - the starRatingScore as a percent + type: '' types should consist of either: article, catalogue, course or elearning + accessed: 'DD Month YYYY', + Progress: { + ['not started', 'in progress', 'complete'], + numberOfActivities: '' - a number less than 20, + numberOfActivitiesComplete: '' - a number less than or equal to the numberOfActivities, + progressPercent: '' - the numberOfActivitiesComplete as a percentage of numberOfActivities, + completedOn: 'DD Month YYYY' + }, + includesCertificate: yes/no, + parentCatalogue, + developedWith: "elearning for healthcare" + +For each type i'd like some different dumby information to be provided: + articles + - title + - description + - rating + - type + - accessed + - parentCatalogue + - developedWith + + catalogue + - imageUrl + - title + - description + - developedWith + + course + - title + - description + - rating + - type + - accessed + - Progress + - includesCertificate + - parentCatalogue + - developedWith + + elearning + - title + - description + - rating + - type + - accessed + - Progress + - includesCertificate + - parentCatalogue + - developedWith + +and I would like several of each with variying title content so I can see what this content will look like in varying states. titles should be between 80 and 180 charecters and go up in incriments of 25 charecters #} + + +{% set learningCardContent = { + articles: [ + { + title: 'Understanding the Basics of Medical Terminology in Clinical Practice for New Healthcare Workers', + description: 'A quick overview of key medical terms you’ll need on your first clinical rotation.', + starRatingScore: 4.2, + starRating: '84%', + type: 'article', + accessed: '05 June 2025', + parentCatalogue: 'Clinical Foundations', + developedWith: 'elearning for healthcare' + }, + { + title: 'Navigating Ethical Dilemmas in Complex Patient Care Situations as a Junior Practitioner in Hospitals', + description: 'Explore real-world ethical decisions faced by junior staff in hospitals.', + starRatingScore: 3.8, + starRating: '76%', + type: 'article', + accessed: '28 May 2025', + parentCatalogue: 'Ethics in Practice', + developedWith: 'elearning for healthcare' + }, + { + title: 'Communication Skills and Strategies for High-Stakes Conversations in Multidisciplinary Healthcare Teams', + description: 'Learn to lead and manage difficult conversations with colleagues.', + starRatingScore: 4.7, + starRating: '94%', + type: 'article', + accessed: '12 June 2025', + parentCatalogue: 'Team Working', + developedWith: 'elearning for healthcare' + } + ], + catalogue: [ + { + imageUrl: 'https://source.unsplash.com/525x225/?medicine,healthcare', + title: 'Clinical Specialties Catalogue for General Practice Trainees Covering All Core Learning Areas and Resources', + description: 'Explore learning modules, articles, and case studies across clinical specialties.', + developedWith: 'elearning for healthcare' + }, + { + imageUrl: 'https://source.unsplash.com/525x225/?hospital,training', + title: 'Comprehensive Learning Resources for Emergency Medicine and Trauma Care Skills with Practical Simulations', + description: 'This catalogue supports frontline workers in developing emergency response skills.', + developedWith: 'elearning for healthcare' + }, + { + imageUrl: 'https://source.unsplash.com/525x225/?doctor,nurse', + title: 'Patient Safety, Risk Management and Human Factors for Acute and Community Healthcare Providers', + description: 'A themed learning collection to enhance safety in patient care across all sectors.', + developedWith: 'elearning for healthcare' + } + ], + course: [ + { + title: 'Foundations of Safe Prescribing and Medicines Administration for New Prescribers in Primary Care Settings', + description: 'Learn safe, legal, and effective prescribing practices.', + starRatingScore: 4.5, + starRating: '90%', + type: 'course', + accessed: '01 June 2025', + Progress: { + status: 'in progress', + numberOfActivities: 12, + numberOfActivitiesComplete: 5, + progressPercent: '42%', + completedOn: '—' + }, + includesCertificate: 'yes', + parentCatalogue: 'Prescribing Competency', + developedWith: 'elearning for healthcare' + }, + { + title: 'Cultural Competency and Inclusive Care Delivery Across Diverse Populations in NHS and Allied Settings', + description: 'Explore how to provide inclusive care that respects diverse needs.', + starRatingScore: 4.0, + starRating: '80%', + type: 'course', + accessed: '25 May 2025', + Progress: { + status: 'not started', + numberOfActivities: 10, + numberOfActivitiesComplete: 0, + progressPercent: '0%', + completedOn: '—' + }, + includesCertificate: 'no', + parentCatalogue: 'Equality and Diversity', + developedWith: 'elearning for healthcare' + }, + { + title: 'Long-Term Condition Management Including Diabetes, Asthma, and Hypertension for Community Healthcare Staff', + description: 'In-depth review of managing long-term conditions in the community.', + starRatingScore: 4.9, + starRating: '98%', + type: 'course', + accessed: '03 June 2025', + Progress: { + status: 'complete', + numberOfActivities: 15, + numberOfActivitiesComplete: 15, + progressPercent: '100%', + completedOn: '10 June 2025' + }, + includesCertificate: 'yes', + parentCatalogue: 'Chronic Conditions', + developedWith: 'elearning for healthcare' + } + ], + elearning: [ + { + title: 'Interactive Scenario-Based eLearning for Recognising and Escalating Deteriorating Patients in Acute Wards', + description: 'Practise how to identify and act on early signs of deterioration.', + starRatingScore: 4.3, + starRating: '86%', + type: 'elearning', + accessed: '06 June 2025', + Progress: { + status: 'in progress', + numberOfActivities: 8, + numberOfActivitiesComplete: 3, + progressPercent: '38%', + completedOn: '—' + }, + includesCertificate: 'yes', + parentCatalogue: 'Acute Care Skills', + developedWith: 'elearning for healthcare' + }, + { + title: 'eLearning Series on Infection Prevention and Control in Healthcare Settings for Clinical and Non-Clinical Staff', + description: 'Learn key IPC practices to keep yourself and patients safe.', + starRatingScore: 3.9, + starRating: '78%', + type: 'elearning', + accessed: '29 May 2025', + Progress: { + status: 'not started', + numberOfActivities: 6, + numberOfActivitiesComplete: 0, + progressPercent: '0%', + completedOn: '—' + }, + includesCertificate: 'no', + parentCatalogue: 'Public Health and Safety', + developedWith: 'elearning for healthcare' + }, + { + title: 'Advanced eLearning on Mental Health Assessment, Crisis Intervention, and Safeguarding for Frontline Professionals', + description: 'Skills for assessing mental health and responding to crises effectively.', + starRatingScore: 4.8, + starRating: '96%', + type: 'elearning', + accessed: '08 June 2025', + Progress: { + status: 'complete', + numberOfActivities: 9, + numberOfActivitiesComplete: 9, + progressPercent: '100%', + completedOn: '10 June 2025' + }, + includesCertificate: 'yes', + parentCatalogue: 'Mental Health Awareness', + developedWith: 'elearning for healthcare' + } + ] + } +%} diff --git a/app/views/elements/definition-lists/index.html b/app/views/elements/definition-lists/index.html new file mode 100644 index 0000000..d3b4347 --- /dev/null +++ b/app/views/elements/definition-lists/index.html @@ -0,0 +1,95 @@ +{% from "components/macros/definition-list.njk" import definitionList %} +{# {% from "components/heading.njk" import heading %} #} + +{% extends "layouts/layout.html" %} + +{% block pageTitle %} + Definition Lists +{% endblock %} + +{% block header %} + {{ header({ + "service": { + "name": "TEL Prototype" + }, + "homeHref": "/", + "showNav": "false", + "classes": "", + "primaryLinks": [] + }) + }} +{% endblock %} + +{% block content %} +
+
+
+

Definition Lists

+ + {# Set DL content #} + {% set definitionList1 = [ + { + title: "Title 1 Lorem ipsum, dolor sit amet", + descriptions: ["Description 1 Lorem ipsum, dolor sit amet consectetur adipisicing elit. Nihil rem vel cum, magni asperiores, maxime sed perspiciatis voluptate, accusamus quae deleniti itaque! Illo doloribus, deserunt nesciunt suscipit et delectus earum?"] + }, + { + title: "Title 2 Lorem ipsum", + descriptions: ["Description 2 Lorem ipsum, dolor sit amet consectetur adipisicing elit. Nihil rem vel cum, magni asperiores, maxime sed perspiciatis voluptate, accusamus quae deleniti itaque! Illo doloribus, deserunt nesciunt suscipit et delectus earum?"] + }, + { + title: "Title 3 Lorem ipsum, dolor sit", + descriptions: ["Description 3 Lorem ipsum, dolor sit amet consectetur adipisicing elit. Nihil rem vel cum, magni asperiores, maxime sed perspiciatis voluptate, accusamus quae deleniti itaque! Illo doloribus, deserunt nesciunt suscipit et delectus earum?"] + }, + { + title: "Title 4 Lorem ipsum, dolor sit amet consectetur adipisicing elit", + descriptions: ["Description 4 Lorem ipsum, dolor sit amet consectetur adipisicing elit. Nihil rem vel cum, magni asperiores, maxime sed perspiciatis voluptate, accusamus quae deleniti itaque! Illo doloribus, deserunt nesciunt suscipit et delectus earum?"] + } + ] %} + + {% set definitionList2 = [ + { + title: "Title 1", + descriptions: ["Description 1", "Description 2", "Description 3"] + }, + { + title: "Title 2", + descriptions: ["Description 4", "Description 5"] + } + ] %} + + {# {{ heading("Definition Lists Example Page") }} #} + +
+

Inline

+ {{ definitionList(groups=definitionList1) }} +
+ +
+

Inline small

+ {{ definitionList(groups=definitionList1, size="small") }} +
+ +
+

Zebra striped

+ {{ definitionList(groups=definitionList1, additionalClasses="definition-list--zebra-striped") }} +
+ +
+

Zebra striped

+ {{ definitionList(groups=definitionList1, type="zebra-striped") }} +
+ +
+

Separated

+ {{ definitionList(groups=definitionList2, type="separated") }} +
+ +
+

Separated

+ {{ definitionList(groups=definitionList2, type="separated") }} +
+
+
+
+ +{% endblock %} diff --git a/app/views/elements/index.html b/app/views/elements/index.html index b49c3ba..26776eb 100644 --- a/app/views/elements/index.html +++ b/app/views/elements/index.html @@ -42,6 +42,15 @@
diff --git a/app/views/elements/learning-cards-v2/index.html b/app/views/elements/learning-cards-v2/index.html new file mode 100644 index 0000000..b3b34f2 --- /dev/null +++ b/app/views/elements/learning-cards-v2/index.html @@ -0,0 +1,135 @@ + +{# {%- from "elements/data/learning-cards-params.njk" import learningCardContent %} #} +{% from "components/rating.njk" import rating %} +{% from "components/macros/definition-list.njk" import definitionList %} +{% from "components/macros/elearning-activity-information.njk" import elearningActivityInformation %} + +{% extends 'layouts/layout.html' %} + + +{% block pageTitle %} + Learning cards +{% endblock %} + +{% block header %} + {{ header({ + "service": { + "name": "TEL Prototype" + }, + "homeHref": "/", + "showNav": "false", + "classes": "", + "primaryLinks": [] + }) + }} +{% endblock %} + +{% block content %} + + {% set learning_listing_heading %} +
+ +

+ Understanding the Basics of Medical Terminology in Clinical Practice for New Healthcare Workers +

+
+
+ {% endset%} + + {% macro learning_listing_content(progress, developedWith, starRating=45) %} +
+
+

Lorem ipsum dolor sit amet consectetur, adipisicing elit. In voluptatibus incidunt dolorem quas totam. Nemo sapiente aut eveniet, laboriosam modi itaque fugit. Cum non eaque impedit, delectus nemo maiores consequatur?

+

+
+ {{ rating(progress=starRating) }} +
+
+ + {{ elearningActivityInformation(progress) }} + +
+
+ + + {% endmacro %} + + +
+
+
+

Learning cards

+ +
+

Cards

+
+
    +
  • + {% call card({ + classes: "tel-learning-listing tel-learning-listing--learning-card", + imgURL: "https://assets.nhs.uk/prod/images/A_0218_exercise-main_FKW1X7.width-690.jpg", + headingHtml: learning_listing_heading + }) %} + {{ learning_listing_content(0) }} + {%- endcall %} +
  • + +
  • + {% call card({ + classes: "tel-learning-listing tel-learning-listing--learning-card tel-learning-listing--course-card", + imgURL: "https://assets.nhs.uk/prod/images/A_0218_exercise-main_FKW1X7.width-690.jpg", + headingHtml: learning_listing_heading + }) %} + {{ learning_listing_content(progress=90, developedWith=true, starRating=20) }} + {%- endcall %} +
  • + +
  • + {% call card({ + classes: "tel-learning-listing tel-learning-listing--learning-card tel-learning-listing--course-card", + imgURL: "https://assets.nhs.uk/prod/images/A_0218_exercise-main_FKW1X7.width-690.jpg", + headingHtml: learning_listing_heading + }) %} + {{ learning_listing_content(100) }} + {%- endcall %} +
  • +
+
+ +

Listings

+
+ +
    +
  • + {{ learning_listing_heading | safe }} + {{ learning_listing_content(0) }} +
  • + +
  • + {{ learning_listing_heading | safe }} + {{ learning_listing_content(80) }} +
  • + +
  • + {{ learning_listing_heading | safe }} + {{ learning_listing_content(100) }} +
  • +
+ +
+ +
+
+
+{% endblock %} diff --git a/app/views/elements/learning-cards/index.html b/app/views/elements/learning-cards/index.html new file mode 100644 index 0000000..0db9824 --- /dev/null +++ b/app/views/elements/learning-cards/index.html @@ -0,0 +1,188 @@ + +{%- from "elements/data/learning-cards-params.njk" import learningCardContent %} +{%- from "components/rating.njk" import rating -%} +{% from "components/macros/definition-list.njk" import definitionList %} +{% from "components/macros/certificate-icon.njk" import certificateIcon %} +{%- from 'tag/macro.njk' import tag %} + +{% extends 'layouts/layout.html' %} + + +{% block pageTitle %} + Learning cards +{% endblock %} + +{% block header %} + {{ header({ + "service": { + "name": "TEL Prototype" + }, + "homeHref": "/", + "showNav": "false", + "classes": "", + "primaryLinks": [] + }) + }} +{% endblock %} + +{% block content %} +
+
+
+

Learning cards

+ +
+

Example 1

+ +
+
    + + {#
  • +
    + + +
    + +
    Lorem ipsum dolor sit amet consectetur, adipisicing elit. In voluptatibus incidunt dolorem quas totam. Nemo sapiente aut eveniet, laboriosam modi itaque fugit. Cum non eaque impedit, delectus nemo maiores consequatur?
    +
    +
    + {{ rating(progress=100) }} +
    +
    5 out of 5 (8 ratings )
    +
    +
    + {% set definitionList1 = [ + { + title: "Type:", + descriptions: ["Article"] + }, + { + title: "Accessed:", + descriptions: ["DD Month YY"] + } + ] %} + + {{ definitionList(groups=definitionList1, size="small") }} + + {{ tag({ + text: "In progress", + classes: "nhsuk-tag--blue" + })}} + +
    +
    +
    + +
    + includes 7 Activities + with 1 certificate + {{ certificateIcon() }} +
    + +
    + {{ certificateIcon(classes="certificate-icon--small") }} + Includes a certificate +
    +
    + +
    + + +
    + +
  • #} + + {% for cardContent in learningCardContent.articles %} + + {% set headingHTMLContent %} +

    + + {{ cardContent['title'] }} + +

    + {% endset%} + +
  • + {% call card({ + classes: "tel-learning-card", + imgURL: "https://assets.nhs.uk/prod/images/A_0218_exercise-main_FKW1X7.width-690.jpg", + headingHtml: headingHTMLContent + }) %} + {#
    #} +
    + Lorem ipsum dolor sit amet consectetur, adipisicing elit. In voluptatibus incidunt dolorem quas totam. Nemo sapiente aut eveniet, laboriosam modi itaque fugit. Cum non eaque impedit, delectus nemo maiores consequatur? +
    +
    +
    + {{ rating(progress=100) }} +
    +
    5 out of 5 (8 ratings )
    +
    +
    + {# Set DL content #} + {% set definitionList1 = [ + { + title: "Type:", + descriptions: ["Article"] + }, + { + title: "Accessed:", + descriptions: ["DD Month YY"] + } + ] %} + + {{ definitionList(groups=definitionList1, size="small") }} + + {{ tag({ + text: "In progress", + classes: "nhsuk-tag--blue" + })}} + +
    +
    +
    + +
    + includes 7 Activities + with 1 certificate + {{ certificateIcon() }} +
    + +
    + {{ certificateIcon(classes="certificate-icon--small") }} + Includes a certificate +
    + {#
    +
    +
    Type:
    +
    Article
    +
    +
    +
    Accessed
    +
    DD Month YY
    +
    +
    In progress
    +
    #} +
    + + {#
    #} + {%- endcall %} +
  • + + {% endfor %} +
+
+ +
+
+
+
+{% endblock %} diff --git a/app/views/elements/quick-filters/index.html b/app/views/elements/quick-filters/index.html new file mode 100644 index 0000000..ca78acd --- /dev/null +++ b/app/views/elements/quick-filters/index.html @@ -0,0 +1,129 @@ + + + + + +{% extends 'layouts/layout.html' %} + + + +{% block pageTitle %} +DLS prototype +{% endblock %} + +{% block header %} +{{ header({ + "service": { + "name": "TEL Prototype" + }, + "homeHref": "/", + "showNav": "false", + "classes": "", + "primaryLinks": [] +}) +}} +{% endblock %} + + + +{% block beforeContent %} +{% endblock %} + +{% block content %} +{% from 'components/quick-filters/macro.njk' import quickFilters %} + + + +
+
+
+

Quick filters

+ +
+

Links

+ + {{ quickFilters({ + "useLinks": true, + "filterTitle": "Activity", + "listHeading": "Show", + "items": [ + { "text": "All", "href": "#", "active": true }, + { "text": "Confirmed", "href": "#" }, + { "text": "Sent for review", "href": "#" }, + { "text": "Review requested", "href": "#" }, + { "text": "In draft", "href": "#" } + ] + }) }} + + {{ quickFilters({ + "useLinks": true, + "filterTitle": "Activity", + "listHeading": "Show", + "items": [ + { "text": "All", "href": "#", "active": true }, + { "text": "Confirmed", "href": "#" }, + { "text": "Sent for review", "href": "#" }, + { "text": "Review requested", "href": "#" }, + { "text": "In draft", "href": "#" } + ] + }) }} + +
+ +
+

Buttons

+ + {{ quickFilters({ + "classes": "learning-log__activity-filter", + "filterTitle": "Activity", + "listHeading": "Show", + "items": [ + { "text": "All", "active": true }, + { "text": "Confirmed" }, + { "text": "Sent for review" }, + { "text": "Review requested" }, + { "text": "In draft" } + ] + }) }} + + {{ quickFilters({ + "listHeading": "Show", + "items": [ + { "text": "All", "active": true }, + { "text": "Confirmed" }, + { "text": "Sent for review" }, + { "text": "Review requested" }, + { "text": "In draft" } + ] + }) }} +
+
+
+ {% endblock %} + + + + {% block outerContent %} + {% endblock %} diff --git a/app/views/elements/search/index.html b/app/views/elements/search/index.html new file mode 100644 index 0000000..e69de29 diff --git a/app/views/index.html b/app/views/index.html index 5656b66..0405077 100755 --- a/app/views/index.html +++ b/app/views/index.html @@ -42,6 +42,43 @@
+ {% from 'select/macro.njk' import select %} + {{ select({ + id: "select-1", + name: "select-1", + label: { + text: "Label text goes here" + }, + attributes: 'multiple size="40"', + items: [ + { + value: 1, + text: "NHS.UK frontend option 1", + selected: true + }, + { + value: 2, + text: "NHS.UK frontend option 2" + }, + { + value: 3, + text: "NHS.UK frontend option 3" + }, + { + value: 4, + text: "NHS.UK frontend option 4" + }, + { + value: 5, + text: "NHS.UK frontend option 5" + }, + { + value: 6, + text: "NHS.UK frontend option 6" + } + ] + }) }} +
  • {{ card({