diff --git a/claro.info.yml b/claro.info.yml index eced30a..6adbcf0 100644 --- a/claro.info.yml +++ b/claro.info.yml @@ -82,6 +82,11 @@ libraries-override: component: css/components/dropbutton.css: false + classy/messages: + css: + component: + css/components/messages.css: false + classy/progress: css: component: @@ -123,6 +128,8 @@ libraries-extend: - claro/details-focus core/drupal.dropbutton: - claro/drupal-theme + core/drupal.message: + - claro/messages core/drupal.vertical-tabs: - claro/vertical-tabs core/drupal.tableselect: diff --git a/claro.libraries.yml b/claro.libraries.yml index c106d4b..7cd4a4d 100644 --- a/claro.libraries.yml +++ b/claro.libraries.yml @@ -222,3 +222,7 @@ views: css: component: css/dist/components/views-exposed-form.css: {} + +messages: + js: + js/messages.js: {} diff --git a/claro.theme b/claro.theme index b0ea4d0..0dd8d8b 100644 --- a/claro.theme +++ b/claro.theme @@ -852,3 +852,13 @@ function claro_preprocess_views_mini_pager(&$variables) { // @todo Revisit after https://www.drupal.org/node/3059232 is fixed. $variables['heading_id'] = Html::getUniqueId('pagination-heading'); } + +/** + * Implements hook_preprocess_HOOK() for status_messages. + */ +function claro_preprocess_status_messages(&$variables) { + $variables['title_ids'] = []; + foreach ($variables['message_list'] as $message_type => $messages) { + $variables['title_ids'][$message_type] = Html::getUniqueId("message-$message_type-title"); + } +} diff --git a/css/src/components/messages.css b/css/src/components/messages.css index 242dead..5a8866e 100644 --- a/css/src/components/messages.css +++ b/css/src/components/messages.css @@ -1,26 +1,122 @@ /** * Messages. */ + +:root { + --messages-padding: 1.5rem 1.5rem 2rem calc(1.5rem - 5px); + --messages-bg-color: #353641; + --messages-fg-color: var(--color-white); + --messages-border-radius: 2px; + --messages-border-width: 5px; + --messages--status-color: #42a877; + --messages--warning-color: #e0ac00; + --messages--error-color: #e34f4f; + --messages__link-color: var(--color-sunglow); + --messages__link--hover-color: var(--color-white); + --messages__icon-size: 1rem; + --messages__text-margin: calc(var(--messages__icon-size) + var(--space-l)); +} + .messages { - margin: 9px 0 10px 8px; /* LTR */ + box-sizing: border-box; + background-color: var(--messages-bg-color); + border-width: 0 0 0 var(--messages-border-width); + border-style: solid; + border-color: var(--messages-bg-color); + color: var(--messages-fg-color); + border-radius: var(--messages-border-radius); + padding: var(--messages-padding); + margin-bottom: var(--space-m); } + [dir="rtl"] .messages { - margin: 9px 8px 10px 0; + border-width: 0 var(--messages-border-width) 0 0; + padding: var(--space-l) calc(var(--space-l) - var(--messages-border-width)) var(--space-l) var(--space-l); +} + +.messages--error { + border-color: var(--messages--error-color); +} + +.messages--status { + border-color: var(--messages--status-color); +} + +.messages--warning { + border-color: var(--messages--warning-color); +} + +.messages__title { + margin: 0 0 0 var(--messages__text-margin); + font-size: var(--font-size-base); +} + +.messages--error .messages__header { + background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 14 14'%3E%3Cpath d='M3 11.1931L11.4501 2.99995' stroke='%23e34f4f' stroke-width='2'/%3E%3Ccircle cx='7' cy='7' r='6' fill='none' stroke='%23e34f4f' stroke-width='2'/%3E%3C/svg%3E%0A") no-repeat left center; +} + +.messages--status .messages__header { + background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 13'%3E%3Cpath d='M2 6.57143L5.6 10L14 2' fill='none' stroke='%2342a877' stroke-width='3'/%3E%3C/svg%3E%0A") no-repeat left center; +} + +.messages--warning .messages__header { + background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 4 14' fill='%23e0ac00'%3E%3Crect x='0.5' width='3' height='9'/%3E%3Ccircle cx='2' cy='12.5' r='1.5'/%3E%3C/svg%3E%0A") no-repeat left center; +} + +.messages__header { + display: flex; + align-items: center; + margin-bottom: var(--space-m); } + +@media screen and (min-width: 48rem) { + .messages__content { + margin-left: var(--messages__text-margin); + } + + [dir="rtl"] .messages__content { + margin-left: 0; + margin-right: var(--messages__text-margin); + } +} + +/* Adding 32px bottom padding only when messages with header. */ +.messages__header + .messages__content { + margin-bottom: var(--space-xs); +} + +.messages a { + color: var(--messages__link-color); + text-decoration: underline; +} + +.messages a:hover { + color: var(--messages__link--hover-color); +} + .messages pre { margin: 0; } -.messages h1, -.messages .heading-a, -.messages h2, -.messages .heading-b, -.messages h3, -.messages .heading-c, -.messages h4, -.messages .heading-d, -.messages h5, -.messages .heading-e, -.messages h6, -.messages .heading-f { - margin-top: 0; + +.messages__list { + margin: 0; + padding: 0; + list-style: none; +} + +.messages__item + .messages__item { + margin-top: var(--space-s); +} + +.messages-list { + padding-bottom: var(--space-l); +} + +@media screen and (-ms-high-contrast: active) { + .messages { + border-width: 1px 1px 1px var(--messages-border-width); + } + .messages__header { + filter: grayscale(1) brightness(1.5) contrast(10); + } } diff --git a/images/src/message--error.svg b/images/src/message--error.svg new file mode 100644 index 0000000..359c423 --- /dev/null +++ b/images/src/message--error.svg @@ -0,0 +1,4 @@ + + + + diff --git a/images/src/message--status.svg b/images/src/message--status.svg new file mode 100644 index 0000000..3789417 --- /dev/null +++ b/images/src/message--status.svg @@ -0,0 +1,3 @@ + + + diff --git a/images/src/message--warning.svg b/images/src/message--warning.svg new file mode 100644 index 0000000..44feca1 --- /dev/null +++ b/images/src/message--warning.svg @@ -0,0 +1,4 @@ + + + + diff --git a/js/messages.es6.js b/js/messages.es6.js new file mode 100644 index 0000000..43da959 --- /dev/null +++ b/js/messages.es6.js @@ -0,0 +1,31 @@ +/** + * @file + * Message template overrides. + */ + +Drupal.theme.message = ({ text }, { type, id }) => { + const messagesTypes = Drupal.Message.getMessageTypeLabels(); + const messageWrapper = document.createElement('div'); + + messageWrapper.setAttribute('class', `messages messages--${type}`); + messageWrapper.setAttribute( + 'role', + type === 'error' || type === 'warning' ? 'alert' : 'status', + ); + messageWrapper.setAttribute('aria-labelledby', `${id}-title`); + messageWrapper.setAttribute('data-drupal-message-id', id); + messageWrapper.setAttribute('data-drupal-message-type', type); + + messageWrapper.innerHTML = ` +
+

+ ${messagesTypes[type]} +

+
+
+ ${text} +
+ `; + + return messageWrapper; +}; diff --git a/js/messages.js b/js/messages.js new file mode 100644 index 0000000..22f60c5 --- /dev/null +++ b/js/messages.js @@ -0,0 +1,25 @@ +/** +* DO NOT EDIT THIS FILE. +* See the following change record for more information, +* https://www.drupal.org/node/2815083 +* @preserve +**/ + +Drupal.theme.message = function (_ref, _ref2) { + var text = _ref.text; + var type = _ref2.type, + id = _ref2.id; + + var messagesTypes = Drupal.Message.getMessageTypeLabels(); + var messageWrapper = document.createElement('div'); + + messageWrapper.setAttribute('class', 'messages messages--' + type); + messageWrapper.setAttribute('role', type === 'error' || type === 'warning' ? 'alert' : 'status'); + messageWrapper.setAttribute('aria-labelledby', id + '-title'); + messageWrapper.setAttribute('data-drupal-message-id', id); + messageWrapper.setAttribute('data-drupal-message-type', type); + + messageWrapper.innerHTML = '\n
\n

\n ' + messagesTypes[type] + '\n

\n
\n
\n ' + text + '\n
\n '; + + return messageWrapper; +}; \ No newline at end of file diff --git a/templates/misc/status-messages.html.twig b/templates/misc/status-messages.html.twig new file mode 100644 index 0000000..91207a5 --- /dev/null +++ b/templates/misc/status-messages.html.twig @@ -0,0 +1,72 @@ +{# +/** + * @file + * Theme override for status messages. + * + * Displays status, error, and warning messages, grouped by type. + * + * An invisible heading identifies the messages for assistive technology. + * Sighted users see a colored box. See http://www.w3.org/TR/WCAG-TECHS/H69.html + * for info. + * + * Add an ARIA label to the contentinfo area so that assistive technology + * user agents will better describe this landmark. + * + * Available variables: + * - message_list: List of messages to be displayed, grouped by type. + * - status_headings: List of all status types. + * - attributes: HTML attributes for the element, including: + * - class: HTML classes. + * - title_ids: A list of unique ids keyed by message type. + * + * @see claro_preprocess_status_messages(). + */ +#} +
+{% for type, messages in message_list %} + {% + set classes = [ + 'messages-list__item', + 'messages', + 'messages--' ~ type, + ] + %} + {% + set is_message_with_title = status_headings[type] + %} + {% + set is_message_with_icon = type in ['error', 'status', 'warning'] + %} + +
+ {% if type == 'error' %} +
+ {% endif %} + {% if is_message_with_title or is_message_with_icon %} +
+ {% if is_message_with_title %} +

+ {{ status_headings[type] }} +

+ {% endif %} +
+ {% endif %} +
+ {% if messages|length > 1 %} +
    + {% for message in messages %} +
  • {{ message }}
  • + {% endfor %} +
+ {% else %} + {{ messages|first }} + {% endif %} +
+ {% if type == 'error' %} +
+ {% endif %} +
+ {# Remove type specific classes. #} + {% set attributes = attributes.removeClass(classes) %} +{% endfor %} +