diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b3338de..83f06364 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Refurbished preview pages to mirror NHSUK and GOVUK design system websites +- Added `ds_code` to render a block of code - Added `ds_list` for plain lists, bullet lists, and numberedlists +- Added `ds_paragraph` for creating a normal `
` body paragraph, and `lead_paragraph` to `fixed_elements` for creating a page-top introductory paragraph
+- Added `ds_inset_text` for differentiating a block of text (e.g. quotes) from the surrounding content
+- Added `ds_grid` for building grid layout
+
+### Fixed
+
+- Fixed the broken cypress test for the footer
## [0.12.0] - 2026-02-02
diff --git a/app/assets/stylesheets/design_system/_hljs.scss b/app/assets/stylesheets/design_system/_hljs.scss
new file mode 100644
index 00000000..cc9dc0ef
--- /dev/null
+++ b/app/assets/stylesheets/design_system/_hljs.scss
@@ -0,0 +1,131 @@
+/*!
+ Theme: StackOverflow Light
+ Description: Light theme as used on stackoverflow.com
+ Author: stackoverflow.com
+ Maintainer: @Hirse
+ Website: https://github.com/StackExchange/Stacks
+ License: MIT
+ Updated: 2021-05-15
+
+ Updated for @stackoverflow/stacks v0.64.0
+ Code Blocks: /blob/v0.64.0/lib/css/components/_stacks-code-blocks.less
+ Colors: /blob/v0.64.0/lib/css/exports/_stacks-constants-colors.less
+*/
+
+.hljs {
+ /* var(--highlight-color) */
+ color: #2f3337;
+ /* var(--highlight-bg) */
+ background: #f6f6f6;
+}
+
+.hljs-subst {
+ /* var(--highlight-color) */
+ color: #2f3337;
+}
+
+.hljs-comment {
+ /* var(--highlight-comment) */
+ color: #656e77;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-meta .hljs-keyword,
+.hljs-doctag,
+.hljs-section {
+ /* var(--highlight-keyword) */
+ color: #015692;
+}
+
+.hljs-attr {
+ /* var(--highlight-attribute); */
+ color: #015692;
+}
+
+.hljs-attribute {
+ /* var(--highlight-symbol) */
+ color: #803378;
+}
+
+.hljs-name,
+.hljs-type,
+.hljs-number,
+.hljs-selector-id,
+.hljs-quote,
+.hljs-template-tag {
+ /* var(--highlight-namespace) */
+ color: #b75501;
+}
+
+.hljs-selector-class {
+ /* var(--highlight-keyword) */
+ color: #015692;
+}
+
+.hljs-string,
+.hljs-regexp,
+.hljs-symbol,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-link,
+.hljs-selector-attr {
+ /* var(--highlight-variable) */
+ color: #54790d;
+}
+
+.hljs-meta,
+.hljs-selector-pseudo {
+ /* var(--highlight-keyword) */
+ color: #015692;
+}
+
+.hljs-built_in,
+.hljs-title,
+.hljs-literal {
+ /* var(--highlight-literal) */
+ color: #b75501;
+}
+
+.hljs-bullet,
+.hljs-code {
+ /* var(--highlight-punctuation) */
+ color: #535a60;
+}
+
+.hljs-meta .hljs-string {
+ /* var(--highlight-variable) */
+ color: #54790d;
+}
+
+.hljs-deletion {
+ /* var(--highlight-deletion) */
+ color: #c02d2e;
+}
+
+.hljs-addition {
+ /* var(--highlight-addition) */
+ color: #2f6f44;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-formula,
+.hljs-operator,
+.hljs-params,
+.hljs-property,
+.hljs-punctuation,
+.hljs-tag {
+ /* purposely ignored */
+}
+
+pre code.hljs {
+ display: block;
+ white-space: pre;
+}
diff --git a/app/assets/stylesheets/design_system/govuk.scss b/app/assets/stylesheets/design_system/govuk.scss
index 8cc58c1a..f9a5a718 100644
--- a/app/assets/stylesheets/design_system/govuk.scss
+++ b/app/assets/stylesheets/design_system/govuk.scss
@@ -5,6 +5,7 @@
);
// Use extreme caution when making any design system level style changes or additions here.
+@use 'hljs';
.app-header-layout {
display: flex;
@@ -67,3 +68,40 @@
border: none;
cursor: pointer;
}
+
+.app-example__code {
+ background-color: #f6f6f6;
+ box-sizing: border-box;
+ max-width: 100%;
+ min-width: 0;
+ padding: 10px;
+ padding-top: 2.75rem;
+ position: relative;
+ width: 100%;
+}
+
+.app-example__scroll {
+ box-sizing: border-box;
+ width: 100%;
+ max-width: 100%;
+ min-width: 0;
+ overflow-x: auto;
+ overflow-y: auto;
+ padding: 0.5rem;
+}
+
+.app-example__code pre {
+ margin: 0;
+ min-width: min-content;
+}
+
+.app-example__copy-button {
+ @extend .govuk-button;
+ @extend .govuk-button--inverse;
+ font-size: 0.875rem;
+ line-height: 1.25;
+ margin: 0;
+ position: absolute;
+ top: 0.5rem;
+ right: 0.5rem;
+}
diff --git a/app/assets/stylesheets/design_system/nhsuk.scss b/app/assets/stylesheets/design_system/nhsuk.scss
index ee4c09b9..5a2ac141 100644
--- a/app/assets/stylesheets/design_system/nhsuk.scss
+++ b/app/assets/stylesheets/design_system/nhsuk.scss
@@ -3,3 +3,64 @@
@use 'nhsuk-frontend-10.3.1/components';
// Use extreme caution when making any design system level style changes or additions here.
+@use 'hljs';
+
+// Code example block: fixed gray box, only __scroll + content scroll (like GOV.UK app-example).
+.app-example__code {
+ background-color: #f6f6f6;
+ box-sizing: border-box;
+ max-width: 100%;
+ min-width: 0;
+ padding: 10px;
+ padding-top: 2.75rem;
+ position: relative;
+ width: 100%;
+}
+
+.app-example__scroll {
+ box-sizing: border-box;
+ width: 100%;
+ max-width: 100%;
+ min-width: 0;
+ overflow-x: auto;
+ overflow-y: auto;
+ padding: 0.5rem;
+}
+
+.app-example__code pre {
+ margin: 0;
+ min-width: min-content;
+}
+
+.app-example__copy-button {
+ @extend .nhsuk-button;
+ @extend .nhsuk-button--reverse;
+ @extend .nhsuk-button--small;
+ margin: 0;
+ position: absolute;
+ top: 0.5rem;
+ right: 0.5rem;
+ background-color: rgb(255, 255, 255);
+ color: rgb(0, 127, 59);
+ border-top-color: rgb(0, 127, 59);
+ border-top-style: solid;
+ border-top-width: 1px;
+ border-right-color: rgb(0, 127, 59);
+ border-right-style: solid;
+ border-right-width: 1px;
+ border-bottom-color: rgb(0, 127, 59);
+ border-bottom-style: solid;
+ border-bottom-width: 0px;
+ border-left-color: rgb(0, 127, 59);
+ border-left-style: solid;
+ border-left-width: 1px;
+ border-radius: 3px;
+ box-shadow: rgb(0, 127, 59) 0px 4px 0px 0px;
+ outline-style: none;
+ font-family: "Frutiger W01";
+ font-size: 14px;
+ font-weight: 400;
+ line-height: 24px;
+ text-align: center;
+ text-decoration: none;
+}
diff --git a/app/helpers/design_system_helper.rb b/app/helpers/design_system_helper.rb
index e6df2741..fadcff13 100644
--- a/app/helpers/design_system_helper.rb
+++ b/app/helpers/design_system_helper.rb
@@ -136,4 +136,8 @@ def ds_list(type: :default, **options, &block)
def ds_inset_text(text = nil, ...)
DesignSystem::Registry.builder(brand, 'inset_text', self).render_inset_text(text, ...)
end
+
+ def ds_code(code, language)
+ DesignSystem::Registry.builder(brand, 'code', self).render_code(code, language)
+ end
end
diff --git a/app/javascript/design_system/controllers/clipboard_controller.js b/app/javascript/design_system/controllers/clipboard_controller.js
new file mode 100644
index 00000000..942d8673
--- /dev/null
+++ b/app/javascript/design_system/controllers/clipboard_controller.js
@@ -0,0 +1,41 @@
+// app/javascript/controllers/clipboard_controller.js
+import { Controller } from '@hotwired/stimulus'
+
+export default class extends Controller {
+ static targets = ['source', 'buttonText']
+
+ // Copies the selected text to the clipboard.
+ copy () {
+ if (navigator.clipboard && this.hasSourceTarget) {
+ // The selected text to be copied.
+ const copytext = this.sourceTarget.value || this.sourceTarget.innerText
+
+ navigator.clipboard.writeText(copytext)
+ .then(() => {
+ // Fired when the text is successfully copied to the clipboard.
+ this.showCopiedMessage()
+ }).catch(err => {
+ // Fired if an error occurs while copying the text to the clipboard.
+ console.error('Failed to copy text: ', err)
+ })
+ } else {
+ // Fired if the Clipboard API is not available or the source target is missing.
+ console.error('Clipboard API not available or source target missing')
+ }
+ }
+
+ showCopiedMessage () {
+ // The text to be displayed in the button.
+ this.buttonTextTarget.textContent = 'Copied!'
+
+ // The time interval after which the button text should be reset to "Copy".
+ const resetInterval = 2000
+
+ // Resets the button text to "Copy" after the specified time interval.
+ const resetButtonText = () => {
+ this.buttonTextTarget.textContent = 'Copy'
+ }
+
+ setTimeout(resetButtonText, resetInterval)
+ }
+}
diff --git a/app/javascript/design_system/controllers/code_highlight_controller.js b/app/javascript/design_system/controllers/code_highlight_controller.js
new file mode 100644
index 00000000..b6972563
--- /dev/null
+++ b/app/javascript/design_system/controllers/code_highlight_controller.js
@@ -0,0 +1,9 @@
+import { Controller } from '@hotwired/stimulus'
+import hljs from 'highlight.js'
+
+// Connects to data-controller="code-highlight"
+export default class extends Controller {
+ connect () {
+ hljs.highlightElement(this.element)
+ }
+}
diff --git a/app/javascript/design_system/index.js b/app/javascript/design_system/index.js
index 58d0f40a..48b7a8ff 100644
--- a/app/javascript/design_system/index.js
+++ b/app/javascript/design_system/index.js
@@ -1,10 +1,14 @@
// Import and register all your controllers
+import ClipboardController from './controllers/clipboard_controller'
+import CodeHighlightController from './controllers/code_highlight_controller'
import HelloWorldController from './controllers/hello_world_controller'
import ShowPasswordController from './controllers/show_password_controller'
import Timeago from '@stimulus-components/timeago'
// Register design system controllers with Stimulus
export const registerControllers = (application) => {
+ application.register('ds--clipboard', ClipboardController)
+ application.register('ds--code-highlight', CodeHighlightController)
application.register('ds--hello-world', HelloWorldController)
application.register('ds--show-password', ShowPasswordController)
application.register('timeago', Timeago)
diff --git a/app/views/layouts/govuk/application.html.erb b/app/views/layouts/govuk/application.html.erb
index 4eff5c15..3aa201ce 100644
--- a/app/views/layouts/govuk/application.html.erb
+++ b/app/views/layouts/govuk/application.html.erb
@@ -53,7 +53,7 @@