diff --git a/CHANGELOG.txt b/CHANGELOG.txt index ddbc617cba7b..537b80427999 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -14,6 +14,7 @@ Changelog * Add `copy_for_translation_done` signal when a page is copied for translation (Arnar Tumi Þorsteinsson) * Remove reduced opacity for draft page title in listings (Inju Michorius) * Adopt more compact representation for StreamField definitions in migrations (Matt Westcott) + * Implement a new design for locale labels in listings (Albina Starykova) * Fix: Make `WAGTAILIMAGES_CHOOSER_PAGE_SIZE` setting functional again (Rohit Sharma) * Fix: Enable `richtext` template tag to convert lazy translation values (Benjamin Bach) * Fix: Ensure permission labels on group permissions page are translated where available (Matt Westcott) diff --git a/client/scss/components/_a11y-result.scss b/client/scss/components/_a11y-result.scss index caf97c80b6a7..84a62e28e740 100644 --- a/client/scss/components/_a11y-result.scss +++ b/client/scss/components/_a11y-result.scss @@ -1,10 +1,12 @@ .w-a11y-result__row { @include box; padding: theme('spacing.4'); + display: flex; + justify-content: space-between; } .w-a11y-result__header { - margin: 0; + margin: 0 0 theme('spacing.[0.5]'); width: 100%; display: flex; justify-content: space-between; @@ -21,40 +23,34 @@ font-weight: theme('fontWeight.semibold'); } -.w-a11y-result__container { - display: flex; - flex-wrap: wrap; - gap: theme('spacing.[2.5]'); - padding-top: theme('spacing.3'); -} - -.w-a11y-result__subtotal_count { - color: theme('colors.icon-primary'); - width: theme('spacing.5'); - text-align: center; - font-size: theme('fontSize.11'); - font-weight: theme('fontWeight.normal'); +.w-a11y-result__help { + color: theme('colors.text-placeholder'); + font-size: theme('fontSize.14'); .w-dialog--userbar & { - font-size: theme('fontSize.14'); + font-size: theme('fontSize.16'); } } .w-a11y-result__selector { display: flex; align-items: center; - background: theme('colors.surface-field-inactive'); - color: theme('colors.text-context'); + justify-content: center; + background: theme('colors.surface-page'); border-radius: theme('borderRadius.DEFAULT'); - padding: theme('spacing.[1.5]'); + margin-top: calc(theme('spacing.[2.5]') * -1); + margin-inline-end: calc(theme('spacing.[2.5]') * -1); + height: theme('spacing.[7.5]'); + width: theme('spacing.[7.5]'); &:hover, &:focus { - background: theme('colors.surface-button-default'); - color: theme('colors.text-button'); + background: theme('colors.surface-header'); .w-a11y-result__icon { - fill: theme('colors.text-button'); + @apply w-scale-110; + + fill: theme('colors.text-context'); } } @@ -64,11 +60,12 @@ } .w-a11y-result__icon { + @apply w-transition hover:w-transform; + flex-shrink: 0; fill: theme('colors.surface-button-default'); height: theme('spacing.[3.5]'); width: theme('spacing.[3.5]'); - margin-inline-end: theme('spacing.[1.5]'); } .w-a11y-result__count { diff --git a/client/scss/components/_status-tag.scss b/client/scss/components/_status-tag.scss index 8d165683b863..4c6b613543aa 100644 --- a/client/scss/components/_status-tag.scss +++ b/client/scss/components/_status-tag.scss @@ -29,10 +29,12 @@ } &--label { - color: theme('colors.text-context'); - background: theme('colors.border-button-small-outline-default'); - border: theme('colors.border-button-small-outline-default'); - font-weight: 500; + padding: theme('spacing.[0.5]') theme('spacing.2'); + color: theme('colors.text-status-label'); + font-weight: theme('fontWeight.medium'); + background: theme('colors.surface-status-label'); + border: 1px solid theme('colors.text-status-label'); + border-radius: theme('borderRadius.xl'); } } diff --git a/client/src/entrypoints/admin/preview-panel.js b/client/src/entrypoints/admin/preview-panel.js index 353ac846f575..bb426eabd587 100644 --- a/client/src/entrypoints/admin/preview-panel.js +++ b/client/src/entrypoints/admin/preview-panel.js @@ -9,9 +9,6 @@ import { gettext } from '../../utils/gettext'; const runAccessibilityChecks = async (onClickSelector) => { const a11yRowTemplate = document.querySelector('#w-a11y-result-row-template'); - const a11ySelectorTemplate = document.querySelector( - '#w-a11y-result-selector-template', - ); const checksPanel = document.querySelector('[data-checks-panel]'); const config = getAxeConfiguration(document.body); const toggleCounter = document.querySelector( @@ -21,13 +18,7 @@ const runAccessibilityChecks = async (onClickSelector) => { '[data-side-panel="checks"] [data-a11y-result-count]', ); - if ( - !a11yRowTemplate || - !a11ySelectorTemplate || - !config || - !toggleCounter || - !panelCounter - ) { + if (!a11yRowTemplate || !config || !toggleCounter || !panelCounter) { return; } @@ -60,7 +51,6 @@ const runAccessibilityChecks = async (onClickSelector) => { results, config, a11yRowTemplate, - a11ySelectorTemplate, onClickSelector, ); }; diff --git a/client/src/includes/a11y-result.ts b/client/src/includes/a11y-result.ts index 3b208f450d46..3ae2becef2a1 100644 --- a/client/src/includes/a11y-result.ts +++ b/client/src/includes/a11y-result.ts @@ -39,10 +39,14 @@ export const sortAxeViolations = (violations: Result[]) => * Wagtail's Axe configuration object. This should reflect what's returned by * `wagtail.admin.userbar.AccessibilityItem.get_axe_configuration()`. */ +interface ErrorMessage { + error_name: string; + help_text: string; +} interface WagtailAxeConfiguration { context: ElementContext; options: RunOptions; - messages: Record; + messages: Record; } /** @@ -78,7 +82,6 @@ export const renderA11yResults = ( results: AxeResults, config: WagtailAxeConfiguration, a11yRowTemplate: HTMLTemplateElement, - a11ySelectorTemplate: HTMLTemplateElement, onClickSelector: (selectorName: string, event: MouseEvent) => void, ) => { // Reset contents ahead of rendering new results. @@ -87,54 +90,42 @@ export const renderA11yResults = ( if (results.violations.length) { const sortedViolations = sortAxeViolations(results.violations); - sortedViolations.forEach((violation, violationIndex) => { - container.appendChild(a11yRowTemplate.content.cloneNode(true)); - const currentA11yRow = container.querySelectorAll( - '[data-a11y-result-row]', - )[violationIndex]; - - const a11yErrorName = currentA11yRow.querySelector( - '[data-a11y-result-name]', - ) as HTMLSpanElement; - a11yErrorName.id = `w-a11y-result__name-${violationIndex}`; - // Display custom error messages supplied by Wagtail if available, - // fallback to default error message from Axe - a11yErrorName.textContent = - config.messages[violation.id] || violation.help; - const a11yErrorCount = currentA11yRow.querySelector( - '[data-a11y-result-count]', - ) as HTMLSpanElement; - a11yErrorCount.textContent = `${violation.nodes.length}`; + let nodeCounter = 0; + sortedViolations.forEach((violation) => { + violation.nodes.forEach((node) => { + container.appendChild(a11yRowTemplate.content.cloneNode(true)); - const a11yErrorContainer = currentA11yRow.querySelector( - '[data-a11y-result-container]', - ) as HTMLDivElement; - - violation.nodes.forEach((node, nodeIndex) => { - a11yErrorContainer.appendChild( - a11ySelectorTemplate.content.cloneNode(true), - ); - const currentA11ySelector = - a11yErrorContainer.querySelectorAll( - '[data-a11y-result-selector]', - )[nodeIndex]; + const currentA11yRow = container.querySelectorAll( + '[data-a11y-result-row]', + )[nodeCounter]; + nodeCounter += 1; - currentA11ySelector.setAttribute('aria-describedby', a11yErrorName.id); - const currentA11ySelectorText = currentA11ySelector.querySelector( - '[data-a11y-result-selector-text]', + const a11yErrorName = currentA11yRow.querySelector( + '[data-a11y-result-name]', ) as HTMLSpanElement; + a11yErrorName.id = `w-a11y-result__name-${nodeCounter}`; + // Display custom error messages supplied by Wagtail if available, + // fallback to default error message from Axe + a11yErrorName.textContent = + config.messages[violation.id].error_name || violation.help; + const a11yErrorHelp = currentA11yRow.querySelector( + '[data-a11y-result-help]', + ) as HTMLDivElement; + a11yErrorHelp.textContent = + config.messages[violation.id].help_text || ''; + // Special-case when displaying accessibility results within the admin interface. const selectorName = toSelector( node.target[0] === '#preview-iframe' ? node.target[1] : node.target[0], ); - // Remove unnecessary details before displaying selectors to the user - currentA11ySelectorText.textContent = selectorName.replace( - /\[data-block-key="\w{5}"\]/, - '', - ); - currentA11ySelector.addEventListener( + + const a11ySelector = currentA11yRow.querySelector( + '[data-a11y-result-selector]', + ) as HTMLButtonElement; + a11ySelector.setAttribute('aria-describedby', a11yErrorName.id); + a11ySelector?.addEventListener( 'click', onClickSelector.bind(null, selectorName), ); diff --git a/client/src/includes/userbar.ts b/client/src/includes/userbar.ts index 7ad2e0048e3b..c24db5f85a32 100644 --- a/client/src/includes/userbar.ts +++ b/client/src/includes/userbar.ts @@ -360,21 +360,12 @@ export class Userbar extends HTMLElement { const a11yRowTemplate = this.shadowRoot.querySelector( '#w-a11y-result-row-template', ); - const a11ySelectorTemplate = - this.shadowRoot.querySelector( - '#w-a11y-result-selector-template', - ); const a11yOutlineTemplate = this.shadowRoot.querySelector( '#w-a11y-result-outline-template', ); - if ( - !accessibilityResultsBox || - !a11yRowTemplate || - !a11ySelectorTemplate || - !a11yOutlineTemplate - ) { + if (!accessibilityResultsBox || !a11yRowTemplate || !a11yOutlineTemplate) { return; } @@ -458,7 +449,6 @@ export class Userbar extends HTMLElement { results, config, a11yRowTemplate, - a11ySelectorTemplate, onClickSelector, ); } else { diff --git a/client/src/tokens/colorThemes.js b/client/src/tokens/colorThemes.js index 68a0738e0c50..fbae8dd2493d 100644 --- a/client/src/tokens/colorThemes.js +++ b/client/src/tokens/colorThemes.js @@ -100,6 +100,12 @@ const light = [ textUtility: 'w-text-surface-button-critical-hover', cssVariable: '--w-color-surface-button-critical-hover', }, + 'surface-status-label': { + value: 'var(--w-color-info-50)', + bgUtility: 'w-bg-surface-status-label', + textUtility: 'w-text-surface-status-label', + cssVariable: '--w-color-surface-status-label', + }, }, }, { @@ -189,6 +195,12 @@ const light = [ textUtility: 'w-text-text-button-critical-outline-hover', cssVariable: '--w-color-text-button-critical-outline-hover', }, + 'text-status-label': { + value: 'var(--w-color-info-100)', + bgUtility: 'w-bg-text-status-label', + textUtility: 'w-text-text-status-label', + cssVariable: '--w-color-text-status-label', + }, }, }, { @@ -358,6 +370,12 @@ const dark = [ textUtility: 'w-text-surface-button-critical-hover', cssVariable: '--w-color-surface-button-critical-hover', }, + 'surface-status-label': { + value: 'var(--w-color-grey-600)', + bgUtility: 'w-bg-surface-status-label', + textUtility: 'w-text-surface-status-label', + cssVariable: '--w-color-surface-status-label', + }, }, }, { @@ -447,6 +465,12 @@ const dark = [ textUtility: 'w-text-text-button-critical-outline-hover', cssVariable: '--w-color-text-button-critical-outline-hover', }, + 'text-status-label': { + value: 'var(--w-color-info-75)', + bgUtility: 'w-bg-text-status-label', + textUtility: 'w-text-text-status-label', + cssVariable: '--w-color-text-status-label', + }, }, }, { diff --git a/client/src/tokens/colorVariables.test.js b/client/src/tokens/colorVariables.test.js index 5d1b251828de..1785ed457a2a 100644 --- a/client/src/tokens/colorVariables.test.js +++ b/client/src/tokens/colorVariables.test.js @@ -80,7 +80,7 @@ describe('generateColorVariables', () => { "--w-color-grey-800-lightness": "11.4%", "--w-color-grey-800-saturation": "0%", "--w-color-info-100": "hsl(var(--w-color-info-100-hue) var(--w-color-info-100-saturation) var(--w-color-info-100-lightness))", - "--w-color-info-100-hue": "calc(var(--w-color-info-125-hue) - 1)", + "--w-color-info-100-hue": "calc(var(--w-color-info-125-hue) - 0.1)", "--w-color-info-100-lightness": "calc(var(--w-color-info-125-lightness) + 6.5%)", "--w-color-info-100-saturation": "calc(var(--w-color-info-125-saturation) + 0.7%)", "--w-color-info-125": "hsl(var(--w-color-info-125-hue) var(--w-color-info-125-saturation) var(--w-color-info-125-lightness))", @@ -91,6 +91,10 @@ describe('generateColorVariables', () => { "--w-color-info-50-hue": "calc(var(--w-color-info-125-hue) + 2.2)", "--w-color-info-50-lightness": "calc(var(--w-color-info-125-lightness) + 65.9%)", "--w-color-info-50-saturation": "calc(var(--w-color-info-125-saturation) + 15.1%)", + "--w-color-info-75": "hsl(var(--w-color-info-75-hue) var(--w-color-info-75-saturation) var(--w-color-info-75-lightness))", + "--w-color-info-75-hue": "calc(var(--w-color-info-125-hue) + 0.4)", + "--w-color-info-75-lightness": "calc(var(--w-color-info-125-lightness) + 36.3%)", + "--w-color-info-75-saturation": "calc(var(--w-color-info-125-saturation) - 27.4%)", "--w-color-positive-100": "hsl(var(--w-color-positive-100-hue) var(--w-color-positive-100-saturation) var(--w-color-positive-100-lightness))", "--w-color-positive-100-hue": "162.1", "--w-color-positive-100-lightness": "31.6%", @@ -213,6 +217,7 @@ describe('generateThemeColorVariables', () => { "--w-color-surface-menu-item-active": "var(--w-color-primary-200)", "--w-color-surface-menus": "var(--w-color-primary)", "--w-color-surface-page": "var(--w-color-white)", + "--w-color-surface-status-label": "var(--w-color-info-50)", "--w-color-surface-tooltip": "var(--w-color-primary-200)", "--w-color-text-button": "var(--w-color-white)", "--w-color-text-button-critical-outline-hover": "var(--w-color-critical-200)", @@ -228,6 +233,7 @@ describe('generateThemeColorVariables', () => { "--w-color-text-link-hover": "var(--w-color-secondary-400)", "--w-color-text-meta": "var(--w-color-grey-400)", "--w-color-text-placeholder": "var(--w-color-grey-400)", + "--w-color-text-status-label": "var(--w-color-info-100)", } `); }); @@ -260,6 +266,7 @@ describe('generateThemeColorVariables', () => { "--w-color-surface-menu-item-active": "var(--w-color-grey-700)", "--w-color-surface-menus": "var(--w-color-grey-800)", "--w-color-surface-page": "var(--w-color-grey-600)", + "--w-color-surface-status-label": "var(--w-color-grey-600)", "--w-color-surface-tooltip": "var(--w-color-grey-500)", "--w-color-text-button": "var(--w-color-white)", "--w-color-text-button-critical-outline-hover": "var(--w-color-critical-50)", @@ -275,6 +282,7 @@ describe('generateThemeColorVariables', () => { "--w-color-text-link-hover": "var(--w-color-secondary-75)", "--w-color-text-meta": "var(--w-color-grey-150)", "--w-color-text-placeholder": "var(--w-color-grey-200)", + "--w-color-text-status-label": "var(--w-color-info-75)", } `); }); diff --git a/client/src/tokens/colors.js b/client/src/tokens/colors.js index 0cede50b82ea..3fe6911b552d 100644 --- a/client/src/tokens/colors.js +++ b/client/src/tokens/colors.js @@ -212,13 +212,22 @@ const staticColors = { }, 100: { hex: '#1D7792', - hsl: 'hsl(193 66.9% 34.3%)', + hsl: 'hsl(193.9 66.9% 34.3%)', bgUtility: 'w-bg-info-100', textUtility: 'w-text-info-100', cssVariable: '--w-color-info-100', usage: 'Background and icons for information messages', contrastText: 'white', }, + 75: { + hex: '#80B6C7', + hsl: 'hsl(194.4, 38.8%, 64.1%)', + bgUtility: 'w-bg-info-75', + textUtility: 'w-text-info-75', + cssVariable: '--w-color-info-75', + usage: 'Info text in the dark theme', + contrastText: 'primary', + }, 50: { hex: '#E2F5FC', hsl: 'hsl(196.2 81.3% 93.7%)', diff --git a/docs/_static/wagtail_colors_tables.txt b/docs/_static/wagtail_colors_tables.txt index 327557f08793..fb3014a1acec 100644 --- a/docs/_static/wagtail_colors_tables.txt +++ b/docs/_static/wagtail_colors_tables.txt @@ -1,4 +1,4 @@ -

Make sure to test any customisations against our Contrast Grid. Try out your own customisations with this interactive style editor:

Static colours

VariableUsage
--w-color-blackShadows only
--w-color-grey-800Backgrounds for panels in dark theme
--w-color-grey-700Backgrounds for panels in dark theme
--w-color-grey-600Body copy, user content
--w-color-grey-500Panels, dividers in dark mode
--w-color-grey-400Help text, placeholders, meta text, neutral state indicators
--w-color-grey-200Dividers, button borders
--w-color-grey-150Field borders
--w-color-grey-100Dividers, panel borders
--w-color-grey-50Background for panels, row highlights
--w-color-whitePage backgrounds, Panels, Button text
--w-color-primaryWagtail branding, Panels, Headings, Buttons, Labels
--w-color-primary-200Accent for elements used in conjunction with primary colour in sidebar
--w-color-secondaryPrimary buttons, action links
--w-color-secondary-600Hover states for two-tone buttons
--w-color-secondary-400Two-tone buttons, hover states
--w-color-secondary-100UI element highlights over dark backgrounds
--w-color-secondary-75UI element highlights over dark text
--w-color-secondary-50Button backgrounds, highlighted fields background
--w-color-info-125Hover background only, for information messages
--w-color-info-100Background and icons for information messages
--w-color-info-50Background only, for information messages
--w-color-positive-100Positive states
--w-color-positive-50Background only, for positive states
--w-color-warning-100Background and icons for potentially dangerous states
--w-color-warning-50Background only, for potentially dangerous states
--w-color-critical-200Dangerous actions or states (over light background), errors
--w-color-critical-100Dangerous actions or states (over dark background)
--w-color-critical-50Background only, for dangerous states

Light & dark theme colours

LightDarkVariable
Surfaces - General
--w-color-surface-page
--w-color-surface-field
--w-color-surface-field-inactive
--w-color-surface-header
--w-color-surface-menus
--w-color-surface-menu-item-active
--w-color-surface-tooltip
--w-color-surface-button-default
--w-color-surface-button-hover
--w-color-surface-button-inactive
--w-color-surface-button-outline-hover
--w-color-surface-button-critical-hover
Text
--w-color-text-button
--w-color-text-label-menus-default
--w-color-text-label-menus-active
--w-color-text-label
--w-color-text-context
--w-color-text-meta
--w-color-text-placeholder
--w-color-text-link-default
--w-color-text-link-hover
--w-color-text-button-outline-default
--w-color-text-button-outline-hover
--w-color-text-highlight
--w-color-text-error
--w-color-text-button-critical-outline-hover
Icons
--w-color-icon-primary
--w-color-icon-primary-hover
--w-color-icon-secondary
--w-color-icon-secondary-hover
Borders
--w-color-border-furniture
--w-color-border-button-small-outline-default
--w-color-border-field-default
--w-color-border-field-inactive
--w-color-border-field-hover
--w-color-border-button-outline-default
--w-color-border-button-outline-hover
Misc
--w-color-focus
--w-color-box-shadow-md
+}

Static colours

VariableUsage
--w-color-blackShadows only
--w-color-grey-800Backgrounds for panels in dark theme
--w-color-grey-700Backgrounds for panels in dark theme
--w-color-grey-600Body copy, user content
--w-color-grey-500Panels, dividers in dark mode
--w-color-grey-400Help text, placeholders, meta text, neutral state indicators
--w-color-grey-200Dividers, button borders
--w-color-grey-150Field borders
--w-color-grey-100Dividers, panel borders
--w-color-grey-50Background for panels, row highlights
--w-color-whitePage backgrounds, Panels, Button text
--w-color-primaryWagtail branding, Panels, Headings, Buttons, Labels
--w-color-primary-200Accent for elements used in conjunction with primary colour in sidebar
--w-color-secondaryPrimary buttons, action links
--w-color-secondary-600Hover states for two-tone buttons
--w-color-secondary-400Two-tone buttons, hover states
--w-color-secondary-100UI element highlights over dark backgrounds
--w-color-secondary-75UI element highlights over dark text
--w-color-secondary-50Button backgrounds, highlighted fields background
--w-color-info-125Hover background only, for information messages
--w-color-info-100Background and icons for information messages
--w-color-info-75Info text in the dark theme
--w-color-info-50Background only, for information messages
--w-color-positive-100Positive states
--w-color-positive-50Background only, for positive states
--w-color-warning-100Background and icons for potentially dangerous states
--w-color-warning-50Background only, for potentially dangerous states
--w-color-critical-200Dangerous actions or states (over light background), errors
--w-color-critical-100Dangerous actions or states (over dark background)
--w-color-critical-50Background only, for dangerous states

Light & dark theme colours

LightDarkVariable
Surfaces - General
--w-color-surface-page
--w-color-surface-field
--w-color-surface-field-inactive
--w-color-surface-header
--w-color-surface-menus
--w-color-surface-menu-item-active
--w-color-surface-tooltip
--w-color-surface-button-default
--w-color-surface-button-hover
--w-color-surface-button-inactive
--w-color-surface-button-outline-hover
--w-color-surface-button-critical-hover
--w-color-surface-status-label
Text
--w-color-text-button
--w-color-text-label-menus-default
--w-color-text-label-menus-active
--w-color-text-label
--w-color-text-context
--w-color-text-meta
--w-color-text-placeholder
--w-color-text-link-default
--w-color-text-link-hover
--w-color-text-button-outline-default
--w-color-text-button-outline-hover
--w-color-text-highlight
--w-color-text-error
--w-color-text-button-critical-outline-hover
--w-color-text-status-label
Icons
--w-color-icon-primary
--w-color-icon-primary-hover
--w-color-icon-secondary
--w-color-icon-secondary-hover
Borders
--w-color-border-furniture
--w-color-border-button-small-outline-default
--w-color-border-field-default
--w-color-border-field-inactive
--w-color-border-field-hover
--w-color-border-button-outline-default
--w-color-border-button-outline-hover
Misc
--w-color-focus
--w-color-box-shadow-md
diff --git a/docs/releases/6.2.md b/docs/releases/6.2.md index d523264d04cf..7e9bef204dcf 100644 --- a/docs/releases/6.2.md +++ b/docs/releases/6.2.md @@ -24,6 +24,7 @@ depth: 1 * Add `copy_for_translation_done` signal when a page is copied for translation (Arnar Tumi Þorsteinsson) * Remove reduced opacity for draft page title in listings (Inju Michorius) * Adopt more compact representation for StreamField definitions in migrations (Matt Westcott) + * Implement a new design for locale labels in listings (Albina Starykova) ### Bug fixes diff --git a/wagtail/admin/templates/wagtailadmin/shared/side_panels/checks.html b/wagtail/admin/templates/wagtailadmin/shared/side_panels/checks.html index 85f17b73b92e..523a31b177c8 100644 --- a/wagtail/admin/templates/wagtailadmin/shared/side_panels/checks.html +++ b/wagtail/admin/templates/wagtailadmin/shared/side_panels/checks.html @@ -1,23 +1,22 @@ {% load i18n wagtailadmin_tags %} - - -
-

{% trans 'Issues found' %}0

+

+ {% trans 'Issues found' %}0 +

{{ axe_configuration|json_script:"accessibility-axe-configuration" }} diff --git a/wagtail/admin/templates/wagtailadmin/userbar/item_accessibility.html b/wagtail/admin/templates/wagtailadmin/userbar/item_accessibility.html index 75e4c0d91a78..b735f859a233 100644 --- a/wagtail/admin/templates/wagtailadmin/userbar/item_accessibility.html +++ b/wagtail/admin/templates/wagtailadmin/userbar/item_accessibility.html @@ -17,19 +17,17 @@ {# Contents of the dialog created in JS based on these templates. #} - diff --git a/wagtail/admin/tests/test_userbar.py b/wagtail/admin/tests/test_userbar.py index 98528bddef05..b56670681c68 100644 --- a/wagtail/admin/tests/test_userbar.py +++ b/wagtail/admin/tests/test_userbar.py @@ -208,22 +208,32 @@ def test_messages(self): config = self.get_config() self.assertIsInstance(config.get("messages"), dict) self.assertEqual( - config["messages"]["empty-heading"], - "Empty heading found. Use meaningful text for screen reader users.", + config["messages"]["empty-heading"]["error_name"], + "Empty heading found", + ) + self.assertEqual( + config["messages"]["empty-heading"]["help_text"], + "Use meaningful text for screen reader users", ) def test_custom_message(self): class CustomMessageAccessibilityItem(AccessibilityItem): # Override via class attribute axe_messages = { - "empty-heading": "Headings should not be empty!", + "empty-heading": { + "error_name": "Headings should not be empty!", + "help_text": "Use meaningful text!", + }, } # Override via method def get_axe_messages(self, request): return { **super().get_axe_messages(request), - "color-contrast-enhanced": "Increase colour contrast!", + "color-contrast-enhanced": { + "error_name": "Insufficient colour contrast!", + "help_text": "Ensure contrast ratio of at least 4.5:1", + }, } with hooks.register_temporarily( @@ -234,8 +244,14 @@ def get_axe_messages(self, request): self.assertEqual( config["messages"], { - "empty-heading": "Headings should not be empty!", - "color-contrast-enhanced": "Increase colour contrast!", + "empty-heading": { + "error_name": "Headings should not be empty!", + "help_text": "Use meaningful text!", + }, + "color-contrast-enhanced": { + "error_name": "Insufficient colour contrast!", + "help_text": "Ensure contrast ratio of at least 4.5:1", + }, }, ) diff --git a/wagtail/admin/userbar.py b/wagtail/admin/userbar.py index e1f64ea24c8d..af8db8f2c184 100644 --- a/wagtail/admin/userbar.py +++ b/wagtail/admin/userbar.py @@ -67,26 +67,38 @@ class AccessibilityItem(BaseItem): #: to use as the error messages. If an enabled rule does not exist in this #: dictionary, Axe's error message for the rule will be used as fallback. axe_messages = { - "button-name": _( - "Button text is empty. Use meaningful text for screen reader users." - ), - "empty-heading": _( - "Empty heading found. Use meaningful text for screen reader users." - ), - "empty-table-header": _( - "Table header text is empty. Use meaningful text for screen reader users." - ), - "frame-title": _( - "Empty frame title found. Use a meaningful title for screen reader users." - ), - "heading-order": _("Incorrect heading hierarchy. Avoid skipping levels."), - "input-button-name": _( - "Input button text is empty. Use meaningful text for screen reader users." - ), - "link-name": _( - "Link text is empty. Use meaningful text for screen reader users." - ), - "p-as-heading": _("Misusing paragraphs as headings. Use proper heading tags."), + "button-name": { + "error_name": _("Button text is empty"), + "help_text": _("Use meaningful text for screen reader users"), + }, + "empty-heading": { + "error_name": _("Empty heading found"), + "help_text": _("Use meaningful text for screen reader users"), + }, + "empty-table-header": { + "error_name": _("Table header text is empty"), + "help_text": _("Use meaningful text for screen reader users"), + }, + "frame-title": { + "error_name": _("Empty frame title found"), + "help_text": _("Use a meaningful title for screen reader users"), + }, + "heading-order": { + "error_name": _("Incorrect heading hierarchy"), + "help_text": _("Avoid skipping levels"), + }, + "input-button-name": { + "error_name": _("Input button text is empty"), + "help_text": _("Use meaningful text for screen reader users"), + }, + "link-name": { + "error_name": _("Link text is empty"), + "help_text": _("Use meaningful text for screen reader users"), + }, + "p-as-heading": { + "error_name": _("Misusing paragraphs as headings"), + "help_text": _("Use proper heading tags"), + }, } def get_axe_include(self, request):