diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 5748c295fa..9bcd3eb96c 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -51,6 +51,8 @@ Changelog * Fix: Fix horizontal positioning of rich text inline toolbar (Thibaud Colas) * Fix: Ensure that `DecimalBlock` correctly handles `None`, when `required=False`, values (Natarajan Balaji) * Fix: Close the userbar when clicking its toggle (Albina Starykova) + * Fix: Add a border around the userbar menu in Windows high-contrast mode so it can be identified (Albina Starykova) + * Fix: Make sure browser font resizing applies to the userbar (Albina Starykova) * Docs: Add custom permissions section to permissions documentation page (Dan Hayden) * Docs: Add documentation for how to get started with contributing translations for the Wagtail admin (Ogunbanjo Oluwadamilare) * Docs: Officially recommend `fnm` over `nvm` in development documentation (LB (Ben) Johnston) @@ -89,6 +91,8 @@ Changelog * Maintenance: Update `tsconfig` to better support modern TypeScript development and clean up some code quality issues via Eslint (Loveth Omokaro) * Maintenance: Set up Stimulus application initialisation according to RFC 78 (LB (Ben) Johnston) * Maintenance: Refactor submit-on-change search filters for image and document listings to use Stimulus (LB (Ben) Johnston) + * Maintenance: Switch userbar to initialise a Web Component to avoid styling clashes (Albina Starykova) + * Maintenance: Refactor userbar stylesheets to use the same CSS loading as the rest of the admin (Albina Starykova) 4.1.2 (xx.xx.xxxx) - IN DEVELOPMENT diff --git a/client/src/entrypoints/admin/userbar.js b/client/src/entrypoints/admin/userbar.js index 8b150c46ff..b4200e2653 100644 --- a/client/src/entrypoints/admin/userbar.js +++ b/client/src/entrypoints/admin/userbar.js @@ -5,154 +5,166 @@ // This component implements a roving tab index for keyboard navigation // Learn more about roving tabIndex: https://w3c.github.io/aria-practices/#kbd_roving_tabindex -document.addEventListener('DOMContentLoaded', () => { - const userbar = document.querySelector('[data-wagtail-userbar]'); - const trigger = userbar.querySelector('[data-wagtail-userbar-trigger]'); - const list = userbar.querySelector('[role=menu]'); - const listItems = list.querySelectorAll('li'); - const isActiveClass = 'is-active'; +class Userbar extends HTMLElement { + connectedCallback() { + const template = document.getElementById('wagtail-userbar-template'); + const shadowRoot = this.attachShadow({ + mode: 'open', + }); + shadowRoot.appendChild(template.content.cloneNode(true)); + // Removes the template from html after it's being used + template.remove(); - // querySelector for all items that can be focused - // tabIndex has been removed for roving tabindex compatibility - // source: https://stackoverflow.com/questions/1599660/which-html-elements-can-receive-focus - const focusableItemSelector = `a[href], + const userbar = shadowRoot.querySelector('[data-wagtail-userbar]'); + const trigger = userbar.querySelector('[data-wagtail-userbar-trigger]'); + const list = userbar.querySelector('[role=menu]'); + const listItems = list.querySelectorAll('li'); + const isActiveClass = 'is-active'; + + // Avoid Web Component FOUC while stylesheets are loading. + userbar.style.display = 'none'; + + // querySelector for all items that can be focused + // tabIndex has been removed for roving tabindex compatibility + // source: https://stackoverflow.com/questions/1599660/which-html-elements-can-receive-focus + const focusableItemSelector = `a[href], button:not([disabled]), input:not([disabled])`; - // eslint-disable-next-line @typescript-eslint/no-use-before-define - trigger.addEventListener('click', toggleUserbar, false); - - // make sure userbar is hidden when navigating back - // eslint-disable-next-line @typescript-eslint/no-use-before-define - window.addEventListener('pageshow', hideUserbar, false); - - // Handle keyboard events on the trigger - // eslint-disable-next-line @typescript-eslint/no-use-before-define - userbar.addEventListener('keydown', handleTriggerKeyDown); - // eslint-disable-next-line @typescript-eslint/no-use-before-define - list.addEventListener('focusout', handleFocusChange); - - // eslint-disable-next-line @typescript-eslint/no-use-before-define - resetItemsTabIndex(); // On initialisation, all menu items should be disabled for roving tab index - - function showUserbar(shouldFocus) { - userbar.classList.add(isActiveClass); - trigger.setAttribute('aria-expanded', 'true'); // eslint-disable-next-line @typescript-eslint/no-use-before-define - list.addEventListener('click', sandboxClick, false); - // eslint-disable-next-line @typescript-eslint/no-use-before-define - window.addEventListener('click', clickOutside, false); + trigger.addEventListener('click', toggleUserbar, false); - // Start handling keyboard input now that the userbar is open. + // make sure userbar is hidden when navigating back // eslint-disable-next-line @typescript-eslint/no-use-before-define - userbar.addEventListener('keydown', handleUserbarItemsKeyDown, false); + window.addEventListener('pageshow', hideUserbar, false); - // The userbar has role=menu which means that the first link should be focused on popup - // For weird reasons shifting focus only works after some amount of delay - // Which is why we are forced to use setTimeout - if (shouldFocus) { - // Find the first focusable element (if any) and focus it - if (list.querySelector(focusableItemSelector)) { - setTimeout(() => { - // eslint-disable-next-line @typescript-eslint/no-use-before-define - setFocusToFirstItem(); - }, 300); // Less than 300ms doesn't seem to work + // Handle keyboard events on the trigger + // eslint-disable-next-line @typescript-eslint/no-use-before-define + userbar.addEventListener('keydown', handleTriggerKeyDown); + // eslint-disable-next-line @typescript-eslint/no-use-before-define + list.addEventListener('focusout', handleFocusChange); + + // eslint-disable-next-line @typescript-eslint/no-use-before-define + resetItemsTabIndex(); // On initialisation, all menu items should be disabled for roving tab index + + function showUserbar(shouldFocus) { + userbar.classList.add(isActiveClass); + trigger.setAttribute('aria-expanded', 'true'); + // eslint-disable-next-line @typescript-eslint/no-use-before-define + list.addEventListener('click', sandboxClick, false); + // eslint-disable-next-line @typescript-eslint/no-use-before-define + window.addEventListener('click', clickOutside, false); + + // Start handling keyboard input now that the userbar is open. + // eslint-disable-next-line @typescript-eslint/no-use-before-define + userbar.addEventListener('keydown', handleUserbarItemsKeyDown, false); + + // The userbar has role=menu which means that the first link should be focused on popup + // For weird reasons shifting focus only works after some amount of delay + // Which is why we are forced to use setTimeout + if (shouldFocus) { + // Find the first focusable element (if any) and focus it + if (list.querySelector(focusableItemSelector)) { + setTimeout(() => { + // eslint-disable-next-line @typescript-eslint/no-use-before-define + setFocusToFirstItem(); + }, 300); // Less than 300ms doesn't seem to work + } } } - } - function hideUserbar() { - userbar.classList.remove(isActiveClass); - trigger.setAttribute('aria-expanded', 'false'); - // eslint-disable-next-line @typescript-eslint/no-use-before-define - list.addEventListener('click', sandboxClick, false); - // eslint-disable-next-line @typescript-eslint/no-use-before-define - window.removeEventListener('click', clickOutside, false); + function hideUserbar() { + userbar.classList.remove(isActiveClass); + trigger.setAttribute('aria-expanded', 'false'); + // eslint-disable-next-line @typescript-eslint/no-use-before-define + list.addEventListener('click', sandboxClick, false); + // eslint-disable-next-line @typescript-eslint/no-use-before-define + window.removeEventListener('click', clickOutside, false); - // Cease handling keyboard input now that the userbar is closed. - // eslint-disable-next-line @typescript-eslint/no-use-before-define - userbar.removeEventListener('keydown', handleUserbarItemsKeyDown, false); - } - - function toggleUserbar(e2) { - e2.stopPropagation(); - if (userbar.classList.contains(isActiveClass)) { - hideUserbar(); - } else { - showUserbar(true); + // Cease handling keyboard input now that the userbar is closed. + // eslint-disable-next-line @typescript-eslint/no-use-before-define + userbar.removeEventListener('keydown', handleUserbarItemsKeyDown, false); } - } - function isFocusOnItems() { - return ( - document.activeElement && - !!document.activeElement.closest('.wagtail-userbar-items') - ); - } + function toggleUserbar(e2) { + e2.stopPropagation(); + if (userbar.classList.contains(isActiveClass)) { + hideUserbar(); + } else { + showUserbar(true); + } + } - /** Reset all focusable menu items to `tabIndex = -1` */ - function resetItemsTabIndex() { - listItems.forEach((listItem) => { + function isFocusOnItems() { + return ( + shadowRoot.activeElement && + !!shadowRoot.activeElement.closest('.w-userbar-nav') + ); + } + + /** Reset all focusable menu items to `tabIndex = -1` */ + function resetItemsTabIndex() { + listItems.forEach((listItem) => { + // eslint-disable-next-line no-param-reassign + listItem.firstElementChild.tabIndex = -1; + }); + } + + /** Focus element using a roving tab index */ + function focusElement(el) { + resetItemsTabIndex(); // eslint-disable-next-line no-param-reassign - listItem.firstElementChild.tabIndex = -1; - }); - } - - /** Focus element using a roving tab index */ - function focusElement(el) { - resetItemsTabIndex(); - // eslint-disable-next-line no-param-reassign - el.tabIndex = 0; - setTimeout(() => { - el.focus(); - }, 100); // Workaround, changing focus only works after a timeout - } - - function setFocusToTrigger() { - setTimeout(() => trigger.focus(), 300); - resetItemsTabIndex(); - } - - function setFocusToFirstItem() { - if (listItems.length > 0) { - focusElement(listItems[0].firstElementChild); + el.tabIndex = 0; + setTimeout(() => { + el.focus(); + }, 100); // Workaround, changing focus only works after a timeout } - } - function setFocusToLastItem() { - if (listItems.length > 0) { - focusElement(listItems[listItems.length - 1].firstElementChild); + function setFocusToTrigger() { + setTimeout(() => trigger.focus(), 300); + resetItemsTabIndex(); } - } - function setFocusToNextItem() { - listItems.forEach((element, idx) => { - // Check which item is currently focused - if (element.firstElementChild === document.activeElement) { - if (idx + 1 < listItems.length) { - focusElement(listItems[idx + 1].firstElementChild); - } else { - // Loop around - setFocusToFirstItem(); - } + function setFocusToFirstItem() { + if (listItems.length > 0) { + focusElement(listItems[0].firstElementChild); } - }); - } + } - function setFocusToPreviousItem() { - listItems.forEach((element, idx) => { - // Check which item is currently focused - if (element.firstElementChild === document.activeElement) { - if (idx > 0) { - focusElement(listItems[idx - 1].firstElementChild); - } else { - setFocusToLastItem(); - } + function setFocusToLastItem() { + if (listItems.length > 0) { + focusElement(listItems[listItems.length - 1].firstElementChild); } - }); - } + } - /** + function setFocusToNextItem() { + listItems.forEach((element, idx) => { + // Check which item is currently focused + if (element.firstElementChild === shadowRoot.activeElement) { + if (idx + 1 < listItems.length) { + focusElement(listItems[idx + 1].firstElementChild); + } else { + // Loop around + setFocusToFirstItem(); + } + } + }); + } + + function setFocusToPreviousItem() { + listItems.forEach((element, idx) => { + // Check which item is currently focused + if (element.firstElementChild === shadowRoot.activeElement) { + if (idx > 0) { + focusElement(listItems[idx - 1].firstElementChild); + } else { + setFocusToLastItem(); + } + } + }); + } + + /** This handler is responsible for keyboard input when items inside the userbar are focused. It should only listen when the userbar is open. @@ -160,94 +172,96 @@ document.addEventListener('DOMContentLoaded', () => { - Shifting focus using the arrow / home / end keys. - Closing the menu when 'Escape' is pressed. */ - function handleUserbarItemsKeyDown(event) { - // Only handle keyboard input if the userbar is open - if (trigger.getAttribute('aria-expanded') === 'true') { - if (event.key === 'Escape') { - hideUserbar(); - setFocusToTrigger(); - return false; - } + function handleUserbarItemsKeyDown(event) { + // Only handle keyboard input if the userbar is open + if (trigger.getAttribute('aria-expanded') === 'true') { + if (event.key === 'Escape') { + hideUserbar(); + setFocusToTrigger(); + return false; + } - // List items are in focus, move focus if needed - if (isFocusOnItems()) { + // List items are in focus, move focus if needed + if (isFocusOnItems()) { + switch (event.key) { + case 'ArrowDown': + event.preventDefault(); + setFocusToNextItem(); + return false; + case 'ArrowUp': + event.preventDefault(); + setFocusToPreviousItem(); + return false; + case 'Home': + event.preventDefault(); + setFocusToFirstItem(); + return false; + case 'End': + event.preventDefault(); + setFocusToLastItem(); + return false; + default: + break; + } + } + } + return true; + } + + function handleFocusChange(event) { + // Is the focus is still in the menu? If so, don't to anything + if ( + event.relatedTarget == null || + (event.relatedTarget && event.relatedTarget.closest('.w-userbar-nav')) + ) { + return; + } + // List items not in focus - the menu should close + resetItemsTabIndex(); + hideUserbar(); + } + + /** + This handler is responsible for opening the userbar with the arrow keys + if it's focused and not open yet. It should always be listening. + */ + function handleTriggerKeyDown(event) { + // Check if the userbar is focused (but not open yet) and should be opened by keyboard input + if ( + trigger === document.activeElement && + trigger.getAttribute('aria-expanded') === 'false' + ) { switch (event.key) { - case 'ArrowDown': - event.preventDefault(); - setFocusToNextItem(); - return false; case 'ArrowUp': event.preventDefault(); - setFocusToPreviousItem(); - return false; - case 'Home': + showUserbar(false); + + // Workaround for focus bug + // Needs extra delay to account for the userbar open animation. Otherwise won't focus properly. + setTimeout(() => setFocusToLastItem(), 300); + break; + case 'ArrowDown': event.preventDefault(); - setFocusToFirstItem(); - return false; - case 'End': - event.preventDefault(); - setFocusToLastItem(); - return false; + showUserbar(false); + + // Workaround for focus bug + // Needs extra delay to account for the userbar open animation. Otherwise won't focus properly. + setTimeout(() => setFocusToFirstItem(), 300); + break; default: break; } } } - return true; - } - function handleFocusChange(event) { - // Is the focus is still in the menu? If so, don't to anything - if ( - event.relatedTarget == null || - (event.relatedTarget && - event.relatedTarget.closest('.wagtail-userbar-nav')) - ) { - return; + function sandboxClick(e2) { + e2.stopPropagation(); } - // List items not in focus - the menu should close - resetItemsTabIndex(); - hideUserbar(); - } - /** - This handler is responsible for opening the userbar with the arrow keys - if it's focused and not open yet. It should always be listening. - */ - function handleTriggerKeyDown(event) { - // Check if the userbar is focused (but not open yet) and should be opened by keyboard input - if ( - trigger === document.activeElement && - trigger.getAttribute('aria-expanded') === 'false' - ) { - switch (event.key) { - case 'ArrowUp': - event.preventDefault(); - showUserbar(false); - - // Workaround for focus bug - // Needs extra delay to account for the userbar open animation. Otherwise won't focus properly. - setTimeout(() => setFocusToLastItem(), 300); - break; - case 'ArrowDown': - event.preventDefault(); - showUserbar(false); - - // Workaround for focus bug - // Needs extra delay to account for the userbar open animation. Otherwise won't focus properly. - setTimeout(() => setFocusToFirstItem(), 300); - break; - default: - break; - } + function clickOutside() { + hideUserbar(); } } +} - function sandboxClick(e2) { - e2.stopPropagation(); - } - - function clickOutside() { - hideUserbar(); - } -}); +customElements.define('wagtail-userbar', Userbar); diff --git a/client/tailwind.config.js b/client/tailwind.config.js index 0f4869efd1..67266466a6 100644 --- a/client/tailwind.config.js +++ b/client/tailwind.config.js @@ -146,7 +146,8 @@ module.exports = { */ plugin(({ addBase }) => { addBase({ - ':root': { + /** Support for web components */ + ':root, :host': { '--w-font-sans': fontFamily.sans.join(', '), '--w-font-mono': fontFamily.mono.join(', '), ...generateColorVariables(colors), diff --git a/docs/releases/4.2.md b/docs/releases/4.2.md index ad9b561108..e540794cb6 100644 --- a/docs/releases/4.2.md +++ b/docs/releases/4.2.md @@ -70,6 +70,8 @@ This feature was developed by Sage Abdullah. * Fix horizontal positioning of rich text inline toolbar (Thibaud Colas) * Ensure that `DecimalBlock` correctly handles `None`, when `required=False`, values (Natarajan Balaji) * Close the userbar when clicking its toggle (Albina Starykova) + * Add a border around the userbar menu in Windows high-contrast mode so it can be identified (Albina Starykova) + * Make sure browser font resizing applies to the userbar (Albina Starykova) ### Documentation @@ -113,6 +115,8 @@ This feature was developed by Sage Abdullah. * Move `identity` JavaScript util into shared utils folder (LB (Ben Johnston)) * Remove unnecessary declaration of function to determine URL query params, instead use `URLSearchParams` (Loveth Omokaro) * Update `tsconfig` to better support modern TypeScript development and clean up some code quality issues via Eslint (Loveth Omokaro) + * Switch userbar to initialise a Web Component to avoid styling clashes (Albina Starykova) + * Refactor userbar stylesheets to use the same CSS loading as the rest of the admin (Albina Starykova) ## Upgrade considerations @@ -152,3 +156,15 @@ Python code that uses the `InlinePanel` panel type is not affected by this chang ### `WAGTAILADMIN_GLOBAL_PAGE_EDIT_LOCK` setting is now `WAGTAILADMIN_GLOBAL_EDIT_LOCK` The `WAGTAILADMIN_GLOBAL_PAGE_EDIT_LOCK` setting has been renamed to [`WAGTAILADMIN_GLOBAL_EDIT_LOCK`](wagtailadmin_global_edit_lock). + +### Wagtail userbar as a web component + +The [`wagtailuserbar`](wagtailuserbar_tag) template tag now initialises the userbar as a [Web Component](https://developer.mozilla.org/en-US/docs/Web/Web_Components), with a `wagtail-userbar` custom element using shadow DOM to apply styles without any collisions with the host page. + +For any site customising the position of the userbar, target the styles to `wagtail-userbar::part(userbar)` instead of `.wagtail-userbar`. For example: + +```css +wagtail-userbar::part(userbar) { + bottom: 30px; +} +``` diff --git a/docs/topics/writing_templates.md b/docs/topics/writing_templates.md index 9f34b555bd..17aecba065 100644 --- a/docs/topics/writing_templates.md +++ b/docs/topics/writing_templates.md @@ -223,7 +223,7 @@ This tag provides a contextual flyout menu for logged-in users. The menu gives e This tag may be used on standard Django views, without page object. The user bar will contain one item pointing to the admin. -We recommend putting the tag near the top of the `
` element to allow keyboard users to reach it. You should consider putting the tag after any `[skip links](https://webaim.org/techniques/skipnav/)` but before the navigation and main content of your page. +We recommend putting the tag near the top of the `` element to allow keyboard users to reach it. You should consider putting the tag after any [skip links](https://webaim.org/techniques/skipnav/)` but before the navigation and main content of your page. ```html+django {% load wagtailuserbar %} @@ -254,11 +254,10 @@ By default, the User Bar appears in the bottom right of the browser window, inse The userbar can be positioned where it works best with your design. Alternatively, you can position it with a CSS rule in your own CSS files, for example: ```css -.wagtail-userbar { - top: 200px !important; - left: 10px !important; +wagtail-userbar::part(userbar) { + bottom: 30px; } -``` +``` ## Varying output between preview and live diff --git a/wagtail/admin/static_src/wagtailadmin/scss/userbar.scss b/wagtail/admin/static_src/wagtailadmin/scss/userbar.scss index c1581e5825..5dc3d53d0d 100644 --- a/wagtail/admin/static_src/wagtailadmin/scss/userbar.scss +++ b/wagtail/admin/static_src/wagtailadmin/scss/userbar.scss @@ -2,6 +2,9 @@ @use 'sass:math'; @use 'sass:string'; +@tailwind base; +@tailwind components; + @import '../../../../../client/scss/settings'; @import '../../../../../client/scss/tools'; @@ -12,15 +15,10 @@ $size-home-button: 3.5em; $position: 2em; $width-arrow: 0.6em; -$box-shadow-props: 0 0 1px 0 rgba(107, 214, 230, 1); +$box-shadow-props: 0 0 1px 0 rgba(107, 214, 230, 1), + 0 1px 10px 0 rgba(107, 214, 230, 0.7); $max-items: 12; $userbar-radius: 6px; -$color-black: #000; -$color-white: #fff; -$color-grey-1: #262626; - -// Classnames will start with this parameter, eg .wagtail- -$namespace: 'wagtail'; // Possible positions for the userbar to exist in. These are set through the // {% wagtailuserbar 'bottom-left' %} template tag. @@ -50,23 +48,16 @@ $positions: ( // ============================================================================= // Wagtail userbar proper // ============================================================================= -.#{$namespace}-userbar-reset { - all: initial; - // Copy our font sans variable so it can be used without Tailwind. - --w-font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, - Roboto, 'Helvetica Neue', Arial, sans-serif, Apple Color Emoji, - 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; -} - -.#{$namespace}-userbar { +.w-userbar { position: fixed; z-index: 9999; - // stylelint-disable-next-line declaration-no-important - font-size: initial !important; + font-size: initial; line-height: initial; margin: 0; padding: 0; - display: block; + // Stop hiding the userbar once stylesheets are loaded. + // stylelint-disable-next-line declaration-no-important + display: block !important; border: 0; width: auto; height: auto; @@ -77,34 +68,32 @@ $positions: ( } @media print { - .#{$namespace}-userbar { + .w-userbar { display: none; } } -// stylelint-disable declaration-no-important -.#{$namespace}-userbar-trigger { - all: initial; +.w-userbar-trigger { display: flex; align-items: center; justify-content: center; width: $size-home-button; height: $size-home-button; - margin: 0 !important; + margin: 0; overflow: hidden; background-color: $color-white; border: 2px solid transparent; border-radius: 50%; color: $color-black; - padding: 0 !important; + padding: 0; cursor: pointer; - box-shadow: $box-shadow-props, 0 1px 10px 0 rgba(107, 214, 230, 0.7); + box-shadow: $box-shadow-props; transition: all 0.2s ease-in-out; - font-size: 16px; - text-decoration: none !important; + font-size: 1rem; + text-decoration: none; position: relative; - .#{$namespace}-userbar-help-text { + .w-userbar-help-text { // Visually hide the help text clip: rect(0 0 0 0); clip-path: inset(50%); @@ -115,9 +104,9 @@ $positions: ( width: 1px; } - .#{$namespace}-icon:before { + .w-icon:before { transition: color 0.2s ease; - font-size: 32px; + font-size: 2rem; width: auto; margin: 0; } @@ -127,8 +116,7 @@ $positions: ( } } -.#{$namespace}-userbar-items { - all: revert; +.w-userbar-items { display: block; list-style: none; position: absolute; @@ -136,17 +124,17 @@ $positions: ( min-width: 210px; visibility: hidden; font-family: $font-sans; - font-size: 14px; + font-size: 0.875rem; padding-inline-start: 0; text-decoration: none; - .#{$namespace}-userbar.is-active & { + .w-userbar.is-active & { visibility: visible; } } // Arrow -.#{$namespace}-userbar-items:after { +.w-userbar-items:after { content: ''; position: absolute; width: 0; @@ -157,29 +145,28 @@ $positions: ( transition-timing-function: cubic-bezier(0.55, 0, 0.1, 1); @media (prefers-reduced-motion: reduce) { - transition: none !important; + transition: none; } - .#{$namespace}-userbar.is-active & { + .w-userbar.is-active & { opacity: 1; transform: translateY(0); transition-delay: 0.3s; } } -.#{$namespace}-userbar-nav { - background: transparent !important; +.w-userbar-nav { + background: transparent; padding: 0; - margin: 0 !important; - display: block !important; + margin: 0; + display: block; - .#{$namespace}-action { + .w-action { background: transparent; } } -.#{$namespace}-userbar__item { - all: revert; +.w-userbar__item { margin: 0; background-color: $color-grey-1; opacity: 0; @@ -187,14 +174,14 @@ $positions: ( transition-duration: 0.125s; transition-timing-function: cubic-bezier(0.55, 0, 0.1, 1); font-family: $font-sans; - font-size: 16px !important; - text-decoration: none !important; + font-size: 1rem; + text-decoration: none; @media (prefers-reduced-motion: reduce) { - transition: none !important; + transition: none; // Force disable transitions for all items - transition-delay: 0s !important; + transition-delay: 0s; } &:first-child { @@ -224,14 +211,14 @@ $positions: ( } a, - .#{$namespace}-action { + .w-action { color: $color-white; display: block; - text-decoration: none !important; - transform: none !important; - transition: none !important; - margin: 0 !important; - font-size: 14px !important; + text-decoration: none; + transform: none; + transition: none; + margin: 0; + font-size: 0.875rem; &:hover, &:focus { @@ -250,7 +237,7 @@ $positions: ( } } - .#{$namespace}-icon { + .w-icon { position: relative; &:before { @@ -263,7 +250,7 @@ $positions: ( a, button { - font-size: 14px !important; + font-size: 0.875rem; text-align: start; padding: 0.8em; } @@ -279,9 +266,17 @@ $positions: ( //Media for Windows High Contrast @media (forced-colors: $media-forced-colours) { - .#{$namespace}-userbar-icon { + .w-userbar-icon { fill: $system-color-link-text; } + + .w-userbar__item { + border: 1px solid $system-color-button-text; + } + + .w-userbar-items::after { + border: $width-arrow solid Canvas; + } } // ============================================================================= @@ -293,17 +288,17 @@ $positions: ( $horizontal: map.get($attrs, horizontal); $arrow: map.get($attrs, arrow); - .#{$namespace}-userbar--#{$pos} { + .w-userbar--#{$pos} { #{$vertical}: $position; #{$horizontal}: $position; - .#{$namespace}-userbar-items { + .w-userbar-items { #{$vertical}: 100%; #{$horizontal}: 0; padding-#{$vertical}: $width-arrow * 2; } - .#{$namespace}-userbar-nav .#{$namespace}-userbar__item { + .w-userbar-nav .w-userbar__item { @if $vertical == 'bottom' { transform: translateY(1em); } @else { @@ -311,21 +306,21 @@ $positions: ( } } - .#{$namespace}-userbar-items:after { + .w-userbar-items:after { #{$vertical}: 2px; #{$horizontal}: math.div($size-home-button, 2) - math.div($width-arrow, 2); border-#{$arrow}-color: $color-grey-1; @if $vertical == 'bottom' { - transform: translateY(-$width-arrow); + transform: translateY($width-arrow); } @if $vertical == 'top' { transform: translateY($width-arrow); } } - &.is-active .#{$namespace}-userbar__item { + &.is-active .w-userbar__item { @for $i from 1 through $max-items { @if $vertical == 'bottom' { &:nth-last-child(#{$i}) { @@ -348,7 +343,7 @@ $positions: ( // ============================================================================= // Active state for the list items comes last. -.#{$namespace}-userbar.is-active .#{$namespace}-userbar__item { +.w-userbar.is-active .w-userbar__item { transform: translateY(0); opacity: 1; } diff --git a/wagtail/admin/templates/wagtailadmin/userbar/base.html b/wagtail/admin/templates/wagtailadmin/userbar/base.html index 3c66cff763..bdee3a39f0 100644 --- a/wagtail/admin/templates/wagtailadmin/userbar/base.html +++ b/wagtail/admin/templates/wagtailadmin/userbar/base.html @@ -1,10 +1,10 @@ {% load wagtailadmin_tags i18n %} -