From 6740eace8ba1310f6bba7c9574dee35b67a3eee3 Mon Sep 17 00:00:00 2001 From: alistair3149 Date: Sat, 4 Jan 2025 19:32:27 -0500 Subject: [PATCH] =?UTF-8?q?feat(Echo):=20=E2=9C=A8=20update=20Echo=20for?= =?UTF-8?q?=201.43?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/skins.citizen.scripts/echo.js | 160 +++++---- .../extensions/Echo/ext.echo.special.less | 138 +------- .../Echo/ext.echo.styles.alert.less | 4 +- .../Echo/ext.echo.styles.notifications.less | 30 +- .../Echo/ext.echo.styles.special.less | 43 +-- .../extensions/Echo/ext.echo.ui.desktop.less | 42 --- skinStyles/extensions/Echo/ext.echo.ui.less | 322 +++--------------- 7 files changed, 140 insertions(+), 599 deletions(-) diff --git a/resources/skins.citizen.scripts/echo.js b/resources/skins.citizen.scripts/echo.js index 3ae79076b..e78dd9789 100644 --- a/resources/skins.citizen.scripts/echo.js +++ b/resources/skins.citizen.scripts/echo.js @@ -7,103 +7,101 @@ * TODO: Switch to mw.hook( 'ext.echo.NotificationBadgeWidget.onInitialize' ) when we drop 1.39 support */ function init() { - mw.hook( 'ext.echo.NotificationBadgeWidget.onInitialize' ).add( () => { - if ( document.querySelectorAll( '#pt-notifications-alert a, #pt-notifications-notice a' ).length !== 2 ) { - return; - } + if ( document.querySelectorAll( '#pt-notifications-alert a, #pt-notifications-notice a' ).length !== 2 ) { + return; + } - const notifications = document.getElementById( 'p-notifications' ); - // Clone the icons so we can insert it back afterwards - const alertIcon = notifications.querySelector( '#pt-notifications-alert > a > .citizen-ui-icon' ).cloneNode(); - const noticeIcon = notifications.querySelector( '#pt-notifications-notice > a > .citizen-ui-icon' ).cloneNode(); + const notifications = document.getElementById( 'p-notifications' ); + // Clone the icons so we can insert it back afterwards + const alertIcon = notifications.querySelector( '#pt-notifications-alert > a > .citizen-ui-icon' ).cloneNode(); + const noticeIcon = notifications.querySelector( '#pt-notifications-notice > a > .citizen-ui-icon' ).cloneNode(); - // When the Echo button is clicked, all of its children are reset back to the initial state. - // This will re-upgrade the children of the Echo button - const callChildSupportServices = ( anchor ) => { - const badge = anchor.parentElement; - // Wrap label in a span - const label = document.createElement( 'span' ); - label.textContent = anchor.textContent; - anchor.replaceChildren( label ); - // Add icon span back - if ( badge.id === 'pt-notifications-alert' ) { - anchor.prepend( alertIcon ); - anchor.classList.remove( 'oo-ui-icon-bell' ); - } else if ( badge.id === 'pt-notifications-notice' ) { - anchor.prepend( noticeIcon ); - anchor.classList.remove( 'oo-ui-icon-tray' ); - } - }; + // When the Echo button is clicked, all of its children are reset back to the initial state. + // This will re-upgrade the children of the Echo button + const callChildSupportServices = ( anchor ) => { + const badge = anchor.parentElement; + // Wrap label in a span + const label = document.createElement( 'span' ); + label.textContent = anchor.textContent; + anchor.replaceChildren( label ); + // Add icon span back + if ( badge.id === 'pt-notifications-alert' ) { + anchor.prepend( alertIcon ); + anchor.classList.remove( 'oo-ui-icon-bell' ); + } else if ( badge.id === 'pt-notifications-notice' ) { + anchor.prepend( noticeIcon ); + anchor.classList.remove( 'oo-ui-icon-tray' ); + } + }; - // Upgrade the Echo badge - // This only needs to be run once at the Echo button init - const setupFosterHome = ( badge, anchor ) => { - badge.classList.add( 'mw-list-item' ); - anchor.classList.remove( 'mw-echo-notifications-badge' ); - anchor.classList.add( 'citizen-header__button', 'citizen-echo-notification-badge' ); - callChildSupportServices( anchor ); - }; + // Upgrade the Echo badge + // This only needs to be run once at the Echo button init + const setupFosterHome = ( badge, anchor ) => { + badge.classList.add( 'mw-list-item' ); + anchor.classList.remove( 'mw-echo-notifications-badge' ); + anchor.classList.add( 'citizen-header__button', 'citizen-echo-notification-badge' ); + callChildSupportServices( anchor ); + }; - // Whenever Echo kicks its children out from the button, undo what Echo did. - const abuseObserver = new MutationObserver( ( mutations ) => { - for ( const mutation of mutations ) { - if ( mutation.type === 'childList' ) { - const removedNodes = mutation.removedNodes; - if ( removedNodes.length === 0 ) { + // Whenever Echo kicks its children out from the button, undo what Echo did. + const abuseObserver = new MutationObserver( ( mutations ) => { + for ( const mutation of mutations ) { + if ( mutation.type === 'childList' ) { + const removedNodes = mutation.removedNodes; + if ( removedNodes.length === 0 ) { + return; + } + for ( const removedNode of removedNodes ) { + if ( !( removedNode instanceof HTMLSpanElement ) || !removedNode.classList.contains( 'citizen-ui-icon' ) ) { return; } - for ( const removedNode of removedNodes ) { - if ( !( removedNode instanceof HTMLSpanElement ) || !removedNode.classList.contains( 'citizen-ui-icon' ) ) { - return; - } - const anchor = mutation.target; - callChildSupportServices( anchor ); - } + const anchor = mutation.target; + callChildSupportServices( anchor ); } } - } ); + } + } ); - // Observe for Echo button init, it will only happen once per icon (so twice) - let initObserved = 0; - const initObserver = new MutationObserver( ( mutations ) => { - for ( const mutation of mutations ) { - // All Echo buttons are observed by abuseObserver, disconnect observer. - if ( initObserved >= 2 ) { - initObserver.disconnect(); + // Observe for Echo button init, it will only happen once per icon (so twice) + let initObserved = 0; + const initObserver = new MutationObserver( ( mutations ) => { + for ( const mutation of mutations ) { + // All Echo buttons are observed by abuseObserver, disconnect observer. + if ( initObserved >= 2 ) { + initObserver.disconnect(); + } + if ( mutation.type === 'childList' ) { + const addedNodes = mutation.addedNodes; + if ( addedNodes.length === 0 ) { + return; } - if ( mutation.type === 'childList' ) { - const addedNodes = mutation.addedNodes; - if ( addedNodes.length === 0 ) { + for ( const addedNode of addedNodes ) { + if ( !addedNode.classList.contains( 'mw-echo-ui-notificationBadgeButtonPopupWidget' ) ) { return; } - for ( const addedNode of addedNodes ) { - if ( !addedNode.classList.contains( 'mw-echo-ui-notificationBadgeButtonPopupWidget' ) ) { - return; + const anchor = addedNode.firstElementChild; + // Upgrade the badge immediately before Echo kicks its children out + setupFosterHome( addedNode, anchor ); + // Observe Echo button + abuseObserver.observe( + anchor, + { + childList: true, + subtree: true } - const anchor = addedNode.firstElementChild; - // Upgrade the badge immediately before Echo kicks its children out - setupFosterHome( addedNode, anchor ); - // Observe Echo button - abuseObserver.observe( - anchor, - { - childList: true, - subtree: true - } - ); - initObserved++; - } + ); + initObserved++; } } - } ); - initObserver.observe( - notifications, - { - childList: true, - subtree: true - } - ); + } } ); + initObserver.observe( + notifications, + { + childList: true, + subtree: true + } + ); } module.exports = init; diff --git a/skinStyles/extensions/Echo/ext.echo.special.less b/skinStyles/extensions/Echo/ext.echo.special.less index 2e530f3be..bfeb1ae7a 100644 --- a/skinStyles/extensions/Echo/ext.echo.special.less +++ b/skinStyles/extensions/Echo/ext.echo.special.less @@ -3,146 +3,12 @@ * * SkinStyles for Extension:Echo * Module: ext.echo.special - * Version: REL1_35 347c30e + * Version: REL1_43 * - * Date: 2023-06-29 + * Date: 2025-01-04 */ // Disable sticky header since it collides with Echo sticky header #citizen-page-header-sticky-sentinel { display: none; } - -/* mw.echo.ui.DatedSubGroupListWidget.less */ -.mw-echo-ui-subGroupListWidget { - &-header-row { - // More aligned - display: flex; - align-items: center; - - &-markAllReadButton { - // Revert responsive font size tweak from Echo - // As it breaks alignment - font-size: revert !important; - } - } -} - -.mw-echo-ui-datedSubGroupListWidget { - .mw-body-content &-title { - margin: 0; - - &-primary { - font-size: var( --font-size-small ); - // Align with Citizen label styles - color: var( --color-subtle ); - letter-spacing: 0.05em; - } - - &-secondary { - color: var( --color-subtle ); - } - } -} - -/* mw.echo.ui.NotificationsInboxWidget.less */ -.mw-echo-ui-notificationsInboxWidget { - max-width: none; - - &-sidebar { - padding-top: var( --space-sm ); // align with toolbarWrapper - padding-right: var( --space-lg ); - } - - &-main { - &-toolbar-top { - margin-bottom: 0 !important; - - .mw-echo-ui-notificationsInboxWidget-row { - display: table-row !important; - // Fix misalign - text-align: left; - } - } - - .mw-echo-ui-notificationItemWidget { - border-radius: var( --border-radius-base ); - } - } - - &-toolbarWrapper { - max-width: ~'calc( 100vw - var(--padding-page) * 2 )'; - height: auto; - padding: var( --space-sm ) 0; - // Mimic Citizen sticky header - margin: 0; - margin-bottom: var( --space-md ); - overflow-x: auto; - background-color: var( --color-surface-0 ); - filter: opacity( 0.9 ); - -webkit-backdrop-filter: saturate( 50% ) blur( 16px ); - backdrop-filter: saturate( 50% ) blur( 16px ); - border-bottom: var( --border-width-base ) solid var( --border-color-base ); - box-shadow: none; - } -} - -.mw-echo-ui-notificationsInboxWidget-cell-placeholder, -.mw-echo-ui-notificationsInboxWidget-main-toolbar-settings, -.mw-echo-ui-notificationsInboxWidget-main-toolbar-pagination { - display: table-cell !important; -} - -/* mw.echo.ui.PageNotificationsOptionWidget.less */ -.mw-echo-ui-pageNotificationsOptionWidget { - &.oo-ui-optionWidget { - padding: var( --space-xs ) var( --space-sm ); - border-radius: var( --border-radius-base ); - - &-highlighted { - color: var( --color-emphasized ); - background-color: var( --color-surface-3 ); - } - - &-selected { - color: var( --color-progressive ); - background-color: var( --background-color-progressive-subtle ); - } - - &-selected&-highlighted, - &-pressed&-highlighted { - color: var( --color-progressive--hover ); - background-color: var( --background-color-progressive-subtle ); - } - } - - &-label-count { - color: var( --color-subtle ); - background-color: var( --color-surface-3 ); - - .oo-ui-optionWidget-selected & { - color: var( --color-progressive ); - } - } -} - -/* mw.echo.ui.CrossWikiUnreadFilterWidget.less */ -.mw-echo-ui-crossWikiUnreadFilterWidget { - // HACK: Make it sticky - position: -webkit-sticky; - position: sticky; - top: var( --space-sm ); - padding: var( --space-md ); - border-color: var( --border-color-base ); - border-radius: var( --border-radius-medium ); - - &-title { - font-size: var( --font-size-x-large ); - font-weight: var( --font-weight-semi-bold ); - color: var( --color-emphasized ); - } - - &-subtitle { - color: var( --color-subtle ); - } -} diff --git a/skinStyles/extensions/Echo/ext.echo.styles.alert.less b/skinStyles/extensions/Echo/ext.echo.styles.alert.less index 6efe87f66..a0bc7c3b8 100644 --- a/skinStyles/extensions/Echo/ext.echo.styles.alert.less +++ b/skinStyles/extensions/Echo/ext.echo.styles.alert.less @@ -3,9 +3,9 @@ * * SkinStyles for Extension:Echo * Module: ext.echo.styles.alert - * Version: REL1_39 + * Version: REL1_43 * - * Date: 2024-02-27 + * Date: 2025-01-04 */ @import '../../../resources/variables.less'; diff --git a/skinStyles/extensions/Echo/ext.echo.styles.notifications.less b/skinStyles/extensions/Echo/ext.echo.styles.notifications.less index 533f34d7e..00b1d1cec 100644 --- a/skinStyles/extensions/Echo/ext.echo.styles.notifications.less +++ b/skinStyles/extensions/Echo/ext.echo.styles.notifications.less @@ -3,33 +3,7 @@ * * SkinStyles for Extension:Echo * Module: ext.echo.styles.notifications - * Version: REL1_35 347c30e + * Version: REL1_43 * - * Date: 2021-08-11 + * Date: 2024-01-04 */ - -/* mw.echo.notifications.less */ -.mw-echo-state { - .mw-echo-notification { - color: var( --color-subtle ); - background-color: var( --color-surface-0 ); - } - - .mw-echo-notifications { - background-color: var( --color-surface-1 ); - } - - .mw-echo-content { - .mw-echo-title { - color: var( --color-emphasized ); - } - - .mw-echo-payload { - color: var( --color-subtle ); - } - - .mw-echo-notification-footer { - color: var( --color-subtle ); - } - } -} diff --git a/skinStyles/extensions/Echo/ext.echo.styles.special.less b/skinStyles/extensions/Echo/ext.echo.styles.special.less index 6b94c2b64..2413e1572 100644 --- a/skinStyles/extensions/Echo/ext.echo.styles.special.less +++ b/skinStyles/extensions/Echo/ext.echo.styles.special.less @@ -3,46 +3,7 @@ * * SkinStyles for Extension:Echo * Module: ext.echo.styles.special - * Version: REL1_35 347c30e + * Version: REL1_43 * - * Date: 2021-08-11 + * Date: 2025-01-04 */ - -.mw-echo-date-section { - color: var( --color-subtle ); - border-bottom-color: var( --border-color-base ); -} - -.mw-echo-special-navbar-bottom { - border-top-color: var( --border-color-base ); -} - -.mw-echo-special-notifications { - .mw-echo-notification { - background-color: var( --color-surface-2 ); - - &:hover { - background-color: var( --color-surface-2--hover ); - } - - &:active { - background-color: var( --color-surface-2--active ); - } - - &-unread { - color: var( --color-base ); - - .mw-echo-markAsReadButton { - opacity: var( --opacity-icon-base ); - - &:hover { - opacity: var( --opacity-icon-base--hover ); - } - - &:active { - opacity: var( --opacity-icon-base--selected ); - } - } - } - } -} diff --git a/skinStyles/extensions/Echo/ext.echo.ui.desktop.less b/skinStyles/extensions/Echo/ext.echo.ui.desktop.less index c429b9bfc..3fbe98be1 100644 --- a/skinStyles/extensions/Echo/ext.echo.ui.desktop.less +++ b/skinStyles/extensions/Echo/ext.echo.ui.desktop.less @@ -10,48 +10,6 @@ .mw-echo-ui-notificationBadgeButtonPopupWidget { &-popup { - filter: none; // disable filter drop shadow - - > .oo-ui-popupWidget-popup { - > .oo-ui-popupWidget { - &-head { - border-bottom-color: var( --border-color-base ); - - > .oo-ui-iconWidget { - opacity: var( --opacity-icon-base ); - } - - > .oo-ui-labelElement-label { - padding-top: 0.15em; // compensate font size changes - font-size: 1rem; - font-weight: var( --font-weight-semi-bold ); - } - } - - &-body { - max-width: 100% !important; // do not overflow the screen - overscroll-behavior: contain; // do not overscoll outside - } - - &-footer { - border-top-color: var( --border-color-base ); - - .mw-echo-ui-notificationBadgeButtonPopupWidget-footer-buttons { - display: flex; - - .oo-ui-buttonElement { - display: block; - width: 100%; // Buttons fill up the empty space - - &:last-child { - border-left-color: var( --border-color-base ); - } - } - } - } - } - } - > .oo-ui-popupWidget-anchor { display: none; // the anchor overflow the viewport } diff --git a/skinStyles/extensions/Echo/ext.echo.ui.less b/skinStyles/extensions/Echo/ext.echo.ui.less index 48c190b62..6be34c824 100644 --- a/skinStyles/extensions/Echo/ext.echo.ui.less +++ b/skinStyles/extensions/Echo/ext.echo.ui.less @@ -3,9 +3,9 @@ * * SkinStyles for Extension:Echo * Module: ext.echo.ui - * Version: REL1_35 347c30e + * Version: REL1_43 * - * Date: 2023-05-27 + * Date: 2025-01-04 */ @import '../../../resources/variables.less'; @@ -15,22 +15,52 @@ display: none; } -.mw-echo-ui-notificationBadgeButtonPopupWidget-popup { - top: unset !important; - bottom: var( --header-size ) !important; - margin: var( --space-xs ); - box-shadow: var( --box-shadow-drop-xx-large ); +.skin-citizen { + .mw-echo-ui-notificationBadgeButtonPopupWidget-popup { + top: unset !important; + bottom: var( --header-size ) !important; + margin: var( --space-xs ); + box-shadow: var( --box-shadow-drop-xx-large ); + + @media ( min-width: @min-width-breakpoint-desktop ) { + bottom: 0 !important; + left: var( --header-size ) !important; + } + + .oo-ui-popupWidget-body { + height: auto !important; + max-height: ~'calc( var( --header-card-maxheight ) - 2 * 3.1428571em )'; // 3.1428571em = height of .oo-ui-popupWidget-head & .oo-ui-popupWidget-footer + } + + > .oo-ui-popupWidget-popup { + > .oo-ui-popupWidget-head { + display: flex; + align-items: center; + height: auto; + min-height: @size-300; + padding-inline: var( --space-md ); + background: var( --color-surface-1 ); + border-bottom-color: transparent; + + > .oo-ui-iconWidget { + float: none; + margin: 0; + } - .oo-ui-popupWidget-body { - height: auto !important; - max-height: ~'calc( var( --header-card-maxheight ) - 2 * 3.1428571em )'; // 3.1428571em = height of .oo-ui-popupWidget-head & .oo-ui-popupWidget-footer - } -} + > .oo-ui-labelElement-label { + flex-grow: 1; + margin-left: var( --space-xs ); + font-weight: var( --font-weight-semi-bold ); + line-height: var( --line-height-xx-small ); + color: var( --color-emphasized ); + } -@media ( min-width: @min-width-breakpoint-desktop ) { - .mw-echo-ui-notificationBadgeButtonPopupWidget-popup { - bottom: 0 !important; - left: var( --header-size ) !important; + .mw-echo-ui-notificationsWidget-markAllReadButton { + position: relative; + margin: 0; + } + } + } } } @@ -54,259 +84,13 @@ z-index: @z-index-overlay; // Higher than header } -/* mw.echo.ui.NotificationItemWidget.less */ -.mw-echo-ui-notificationItemWidget { - background-color: var( --color-surface-3 ); - border-color: var( --border-color-base ); - - &:hover { - background-color: var( --color-surface-2--hover ); - } - - &:active { - background-color: var( --color-surface-2--active ); - } - - &:last-child { - border-bottom-color: var( --border-color-base ); - } - - &-unread { - background-color: var( --color-surface-1 ); - - &:hover { - background-color: var( --color-surface-2--hover ); - } - } - - &-notify { - &-description { - color: var( --color-subtle ); - } - } - - &-icon { - img { - width: 24px; // It looks nicer - } - } - - &-content { - &-message { - &-header { - color: var( --color-emphasized ); - } - - &-body { - color: var( --color-subtle ); - } - } - - &-table { - display: block; - } - - &-actions { - display: flex; // Table row does not align things properly - align-items: center; - - & > &-buttons.oo-ui-buttonSelectWidget { - display: block; - margin-right: 0; - } - - .mw-echo-ui-menuItemWidget-prioritized { - border-radius: var( --border-radius-small ); - - &:hover { - background-color: var( --background-color-button-quiet--hover ); - } - - &:active { - background-color: var( --background-color-button-quiet--active ); - } - } - - &-menu { - opacity: var( --opacity-icon-base ); - - &:hover { - opacity: var( --opacity-icon-base--hover ); - } - - &:active { - opacity: var( --opacity-icon-base--selected ); - } - } - - &-timestamp { - display: block; - color: var( --color-subtle ); - opacity: 1; - } - } - } - - &-bundled { - .mw-echo-ui-notificationItemWidget-content { - .mw-echo-ui-notificationItemWidget { - &-content-message { - &-header { - em { - color: var( --color-subtle ); - } - } - } - } - } - } - - &-initiallyUnseen { - -webkit-animation-name: unseen-fadeout-to-read; - animation-name: unseen-fadeout-to-read; - - &.mw-echo-ui-notificationItemWidget-unread { - -webkit-animation-name: unseen-fadeout-to-unread; - animation-name: unseen-fadeout-to-unread; - } - } -} - -@-webkit-keyframes unseen-fadeout-to-unread { - from { - background-color: var( --color-surface-2 ); - } - - to { - background-color: var( --color-surface-1 ); - } -} - -@keyframes unseen-fadeout-to-unread { - from { - background-color: var( --color-surface-2 ); - } - - to { - background-color: var( --color-surface-1 ); - } -} - -@-webkit-keyframes unseen-fadeout-to-read { - from { - background-color: var( --color-surface-2 ); - } - - to { - background-color: var( --color-surface-3 ); - } -} - -@keyframes unseen-fadeout-to-read { - from { - background-color: var( --color-surface-2 ); - } - - to { - background-color: var( --color-surface-3 ); - } -} - -/* mw.echo.ui.ToggleReadCircleButtonWidget.less */ -.mw-echo-ui-toggleReadCircleButtonWidget { - &-circle { - background-color: var( --color-progressive ); - - &-unread { - background-color: var( --color-surface-2 ); - border-color: var( --border-color-base ); - } - } - - &:hover .mw-echo-ui-toggleReadCircleButtonWidget-circle { - background-color: var( --color-progressive--hover ); - - &-unread { - background-color: var( --color-surface-2--hover ); - } - } - - &:active .mw-echo-ui-toggleReadCircleButtonWidget-circle { - background-color: var( --color-progressive--active ); - - &-unread { - background-color: var( --color-surface-2--active ); - } - } -} - -/* mw.echo.ui.CrossWikiNotificationItemWidget.less */ -.mw-echo-ui-crossWikiNotificationItemWidget, -.mw-echo-ui-bundleNotificationItemWidget { - &-separator { - border-bottom-color: var( --border-color-base ); - } - - &-group { - background-color: var( --color-surface-2 ); - } - - .mw-echo-ui-subGroupListWidget-header { - &-row-title { - color: var( --color-subtle ); - } - } -} - -/* mw.echo.ui.NotificationsListWidget.less */ -.mw-echo-ui-notificationsListWidget { - > a, - &:hover > a { - color: var( --color-subtle ); - } - - &:not( :hover ) a, - #p-personal &:not( :hover ) a.new { - color: var( --color-subtle ); - } -} - /* mw.echo.ui.PlaceholderItemWidget.less */ .mw-echo-ui-placeholderItemWidget { - background-color: var( --color-surface-1 ); -} - -/* mw.echo.ui.MenuItemWidget.less */ -.mw-echo-ui-menuItemWidget { - // First selector is polyfill for MW 1.35 - > .oo-ui-labelElement-label, - > .oo-ui-buttonElement-button > .oo-ui-labelElement-label { - color: var( --color-emphasized ); - } - - &-prioritized { - opacity: var( --opacity-icon-base ); - - &:hover { - opacity: var( --opacity-icon-base--hover ); - } - - &:active { - opacity: var( --opacity-icon-base--selected ); - } - } - - &-dynamic-action { - &:hover { - background-color: var( --color-surface-1 ); - } - - .mw-echo-ui-menuItemWidget-description { - color: var( --color-subtle ); - } - } - - .mw-echo-ui-actionMenuPopupWidget-menu:hover { - background-color: var( --color-surface-2--hover ); - } + display: grid; + place-content: center; + min-height: @size-800; + padding: var( --space-sm ) var( --space-md ); + color: var( --color-subtle ); + text-align: center; + background-color: transparent; }