From d6a80b96745b1c1722d170bbf7b2068c8acbe1f7 Mon Sep 17 00:00:00 2001 From: leah Date: Thu, 27 Aug 2026 02:06:52 -0400 Subject: [PATCH 1/2] Ufeat(lib): add mediawiki lib module (#1866) * feat(lib): add mediawiki lib module * fix(lib/mediawiki): remove site specific styling * refactor(lib/mediawiki)!: nest utilities under namespace * fix(lib/mediawiki): adjust border colors slightly * fix(lib/mediawiki): adjust borders further * feat(lib/mediawiki): use codex style guide (#1962) * feat(lib/mediawiki): use codex style guide to base colour choices * chore(lib/mediawiki): comment nits * fix(lib/mediawiki): change button quiet hover colours to fade accent * fix(mediawiki): remove redundant transparent variables * fix(lib/mediawiki): change tab list framed state colours to latte fade --------- Co-authored-by: uncenter * feat(lib/mediawiki): radio inputs * refactor(lib/mediawiki): move to versioned path --------- Co-authored-by: WalkQuackBack --- lib/mediawiki/v1.less | 534 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 534 insertions(+) create mode 100644 lib/mediawiki/v1.less diff --git a/lib/mediawiki/v1.less b/lib/mediawiki/v1.less new file mode 100644 index 0000000000..51dac9c797 --- /dev/null +++ b/lib/mediawiki/v1.less @@ -0,0 +1,534 @@ +#__mediawiki { + .reset() { + html.skin-theme-clientpref-night, html.skin-theme-clientpref-os { + /* Logo */ + .skin-invert-image img, + .skin-invert, + .oo-ui-iconElement-icon:not( + .oo-ui-image-progressive, + .oo-ui-image-destructive, + .oo-ui-checkboxInputWidget-checkIcon, + .oo-ui-image-invert, + .mw-no-invert + ), + .oo-ui-indicatorElement-indicator { + filter: none; + } + } + + /* MediaWiki only applies the following overrides on dark and automatic appearance settings, leaving broken elements with the light appearance. */ + + .hatnote:not(.notheme), + .dablink:not(.notheme), + .rellink:not(.notheme), + .infobox:not(.notheme) { + color: var(--color-base) !important; + background-color: var(--background-color-interactive-subtle) !important; + } + .infobox td:not(.notheme), + .infobox th:not(.notheme), + .infobox-above:not(.notheme), + .infobox p:not(.notheme), + .infobox > div:not(.notheme), + .infobox caption:not(.notheme), + .infobox--frwiki td:not(.notheme), + .infobox--frwiki th:not(.notheme), + .infobox--frwiki p:not(.notheme), + .infobox--frwiki > div:not(.notheme), + .infobox--frwiki caption:not(.notheme), + .sinottico th:not(.notheme), + .infobox-header:not(.notheme), + .skin-nightmode-reset-color:not(.notheme), + .navigation-box:not(.notheme), + .metadata:not(.notheme), + .quotebox:not(.notheme), + .side-box:not(.notheme), + .side-box div:not(.notheme), + .navbox:not(.notheme), + .navbox-subgroup:not(.notheme), + .navbox-group:not(.notheme), + .navbox-even:not(.notheme), + .navbox-abovebelow:not(.notheme), + .navbox-title:not(.notheme) { + background: inherit !important; + color: inherit !important; + border-color: var(--border-color-subtle) !important; + } + .ns-100 .mw-parser-output :not(.notheme, a) { + background: inherit !important; + color: inherit !important; + border-color: var(--border-color-subtle) !important; + } + } + + .base() { + --color-base: @text; + --color-base--hover: @text; + --color-emphasized: @text; + --color-subtle: @subtext0; + + --color-inverted: @base; + // Locked to base as it is often used on accent, + // The same as color-inverted in light mode, but does not change in dark mode. Use this for things that should be white in both modes. + --color-inverted-fixed: @base; + + --color-progressive: @accent; + --color-progressive--hover: lighten(@accent, 5%); + --color-progressive--active: darken(@accent, 10%); + --color-progressive--focus: darken(@accent, 10%); + + --color-destructive: @red; + --color-destructive--hover: @maroon; + --color-destructive--active: darken(@red, 4%); + --color-destructive--visited: spin(@red, 15); + + --color-visited: @lavender; + + --color-error: @red; + --color-warning: @yellow; + --color-success: @green; + --color-notice: @text; + + --color-icon-error: @red; + --color-icon-warning: @yellow; + --color-icon-success: @green; + --color-icon-notice: @subtext0; + + --color-content-added: @green; + --color-content-removed: @maroon; + --color-placeholder: @subtext0; + --color-disabled: @overlay2; + + --box-shadow-color-base: @overlay0; + --box-shadow-color-progressive--active: fade(@accent, 10%); + --box-shadow-color-progressive--focus: fade(@accent, 50%); + --box-shadow-color-progressive-selected: fade(@accent, 60%); + --box-shadow-color-progressive-selected--hover: fade(@accent, 70%); + --box-shadow-color-progressive-selected--active: fade(@accent, 80%); + --box-shadow-color-destructive--focus: fade(@accent, 50%); + --box-shadow-color-inverted: @base; + --box-shadow-color-alpha-base: rgba(0, 0, 0, 0.87); + --box-shadow-color-transparent: transparent; + + // Background colors for static elements (for page layout, sections, etc.) from here on. + --background-color-base: @base; + // The same as background-color-base in light mode, but does not change in dark mode. Use this for things that should be white in both modes. + --background-color-base-fixed: @catppuccin[@latte][@base]; + --background-color-neutral: @surface0; + --background-color-neutral-subtle: mix(@surface0, @base, 50%); + --background-color-interactive: @surface0; + --background-color-interactive--hover: @surface1; + --background-color-interactive--active: @surface2; + --background-color-interactive-subtle: mix(@surface0, @base, 50%); + --background-color-interactive-subtle--hover: @surface0; + --background-color-interactive-subtle--active: @surface1; + --background-color-disabled: @surface1; + --background-color-disabled-subtle: @surface0; + --background-color-inverted: @text; + + --background-color-progressive: @accent; + --background-color-progressive--hover: darken(@accent, 5%); + --background-color-progressive--active: darken(@accent, 10%); + --background-color-progressive--focus: lighten(@accent, 10%); + --background-color-progressive-subtle: mix(@accent, @base, 30%); + --background-color-progressive-subtle--hover: lighten( + mix(@accent, @base, 30%), + 5% + ); + --background-color-progressive-subtle--active: lighten( + mix(@accent, @base, 30%), + 10% + ); + + --background-color-destructive: @red; + --background-color-destructive--hover: darken(@red, 5%); + --background-color-destructive--active: darken(@red, 10%); + --background-color-destructive--focus: lighten(@accent, 10%); + --background-color-destructive-subtle: mix(@red, @base, 30%); + --background-color-destructive-subtle--hover: lighten( + mix(@red, @base, 30%), + 5% + ); + --background-color-destructive-subtle--active: lighten( + mix(@red, @base, 30%), + 10% + ); + + --background-color-error: @red; + --background-color-error--hover: darken(@red, 5%); + --background-color-error--active: darken(@red, 10%); + --background-color-error-subtle: mix(@red, @base, 30%); + --background-color-error-subtle--hover: lighten(mix(@red, @base, 30%), 5%); + --background-color-error-subtle--active: lighten( + mix(@red, @base, 30%), + 10% + ); + + --background-color-warning-subtle: mix(@yellow, @base, 30%); + --background-color-success-subtle: mix(@green, @base, 30%); + --background-color-notice-subtle: mix(@text, @base, 30%); + + --background-color-content-added: mix(@blue, @base, 30%); + --background-color-content-removed: mix(@yellow, @base, 30%); + + --background-color-backdrop-light: fade(@base, 65%); + --background-color-backdrop-dark: fade(@text, 65%); + + --background-color-button-quiet--hover: fade(@accent, 2.7%); + --background-color-button-quiet--active: fade(@accent, 8.2%); + + --background-color-input-binary--checked: @accent; + + --background-color-tab-list-item-framed--hover: fade( + @catppuccin[@latte][@base], + 30% + ); + --background-color-tab-list-item-framed--active: fade( + @catppuccin[@latte][@base], + 65% + ); + + --border-base: 1px solid var(--border-color-base); + --border-subtle: 1px solid var(--border-color-subtle); + + --border-color-base: @overlay0; + --border-color-emphasized: @text; + --border-color-subtle: @surface2; + --border-color-muted: @surface1; + --border-color-interactive: @overlay0; + --border-color-interactive--hover: @overlay1; + --border-color-interactive--active: @overlay2; + --border-color-disabled: @overlay0; + --border-color-inverted: @base; + // The same as color-inverted in light mode, but does not change in dark mode. Use this for things that should be white in both modes. + --border-color-inverted-fixed: @catppuccin[@latte][@base]; + + --border-color-progressive: var(--color-progressive); + --border-color-progressive--hover: var(--color-progressive--hover); + --border-color-progressive--active: var(--color-progressive--active); + --border-color-progressive--focus: var(--color-progressive--focus); + --border-color-destructive: var(--color-destructive); + --border-color-destructive--hover: var(--color-destructive--hover); + --border-color-destructive--active: var(--color-destructive--active); + --border-color-destructive--focus: var(--color-destructive--focus); + --border-color-error: var(--color-error); + --border-color-error--hover: var(--color-error--hover); + --border-color-error--active: var(--color-error--active); + --border-color-warning: var(--color-warning); + --border-color-warning--hover: var(--color-warning--hover); + --border-color-warning--active: var(--color-warning--active); + --border-color-success: var(--color-success); + --border-color-notice: var(--color-notice); + --border-color-content-added: var(--color-content-added); + --border-color-content-removed: var(--color-content-removed); + + --border-color-divider: @overlay1; + --border-color-input--hover: var(--border-color-interactive); + --border-color-input-binary: var(--border-color-interactive); + --border-color-input-binary--hover: var(--border-color-progressive--hover); + --border-color-input-binary--active: var( + --border-color-progressive--active + ); + --border-color-input-binary--focus: var(--border-color-progressive--focus); + --border-color-input-binary--checked: var(--border-color-progressive); + + /* Other */ + + .infobox { + border-color: @surface2; + } + + [style="color:white;"], [style*="color:#ffffff"] { + color: @text !important; + } + .mw-collapsible-toggle-default { + &::before, &::after { + color: @subtext0; + } + } + + a { + &:focus { + outline-color: @accent; + } + } + + .mw-parser-output { + a.external { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + } + + /* Math equations */ + .mwe-math-element img.skin-invert { + filter: @text-filter; + } + + /* OOUI */ + .oo-ui-indicator-down { + filter: @text-filter !important; + } + .oo-ui-image-invert.oo-ui-icon-check, .mw-ui-icon-check-invert::before { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + + .oo-ui-radioInputWidget [type="radio"] + span { + background-color: @text; + } + + .cdx-radio__input:enabled:checked + .cdx-radio__icon, + .oo-ui-radioInputWidget [type="radio"]:checked + span { + background-color: @base; + } + + /* View source */ + textarea { + background-color: @mantle; + color: @text; + } + + /* View history */ + .flaggedrevs-color-1 { + background-color: fade(@blue, 10%); + } + + /* Language search and settings */ + .uls-search, + .uls-filtersuggestion, + .uls-lcd, + #uls-settings-block.uls-settings-block--vector-2022.uls-settings-block--with-add-languages, + #language-settings-dialog, + #languagesettings-settings-panel, + .uls-language-settings-close-block { + background-color: @mantle; + } + .uls-language-block a { + color: @accent; + } + .uls-search-label, + #uls-settings-block.uls-settings-block--vector-2022 + > button.uls-add-languages-button, + #uls-settings-block.uls-settings-block--vector-2022 + > button.uls-language-settings-button, + #uls-settings-block.uls-settings-block--vector-2022 + > button.uls-language-settings-button:hover, + .uls-icon-close, + .uls-languagefilter-clear { + filter: @text-filter; + } + .uls-sub-panel, .language-settings-buttons { + border-color: @surface1; + } + .uls-language-block > ul > li:hover { + background-color: @surface0; + } + .languagesettings-menu .menu-section.active { + background-color: @surface1; + } + + /* Page preview */ + .mwe-popups .mwe-popups-extract[dir="ltr"]::after { + background-image: linear-gradient(to right, transparent, @base 50%); + } + .mwe-popups .mwe-popups-extract[dir="rtl"]::after { + background-image: linear-gradient(to left, transparent, @base 50%); + } + + /* Icons */ + + .vector-page-titlebar + .mw-portlet-lang + .vector-dropdown-label.cdx-button--action-progressive.cdx-button--weight-quiet::after { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}") !important; + filter: none; + } + + .vector-icon { + filter: none !important; + + &.mw-ui-icon-wikimedia-menu { + @svg: escape( + '' + ); + content: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-ellipsis { + @svg: escape( + '' + ); + content: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-appearance { + @svg: escape( + '' + ); + content: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-expand { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}") !important; + } + + &.mw-ui-icon-wikimedia-language-progressive { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}") !important; + } + + &.mw-ui-icon-wikimedia-language { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}") !important; + } + + &.mw-ui-icon-wikimedia-listBullet { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}") !important; + } + + &.mw-ui-icon-wikimedia-fullScreen { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-userAvatar { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-watchlist { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-tray { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-bell { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-star { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-userTalk { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-sandbox { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-settings { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-unStar { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-labFlask { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-userContributions { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-logOut { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-search { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-edit { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-history { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-speechBubbles { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + + &.mw-ui-icon-wikimedia-editLock { + @svg: escape( + '' + ); + background-image: url("data:image/svg+xml,@{svg}"); + } + } + } +} From 7fba4b34fa82270e1c98bcd84bbd20a8b4480251 Mon Sep 17 00:00:00 2001 From: leah Date: Sun, 30 Aug 2026 20:51:39 -0400 Subject: [PATCH 2/2] docs: add userstyles review tips page (#2005) Co-authored-by: leah Co-authored-by: WalkQuackBack --- .../contributing/maintainers/reviewing.md | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 docs/src/content/docs/contributing/maintainers/reviewing.md diff --git a/docs/src/content/docs/contributing/maintainers/reviewing.md b/docs/src/content/docs/contributing/maintainers/reviewing.md new file mode 100644 index 0000000000..c0c9074ced --- /dev/null +++ b/docs/src/content/docs/contributing/maintainers/reviewing.md @@ -0,0 +1,28 @@ +--- +title: Reviewing userstyles +description: Notes for performing thorough new userstyle reviews. +sidebar: + order: 1 +--- + +A key tenant of the userstyles philosophy is starting with a complete version. Generally, we avoid merging new userstyles that do not fully theme the target application. Note that fully theming a set of (core) pages of the application, while _fully_ not theming other pages of the application, is acceptable. The reasoning for this strict policy is that userstyles maintainers come and go and it is difficult to depend on continued maintenance down the road. If a userstyle isn't initially complete, it is unlikely that more of it will be completed later. + +## Inspecting the user interface + +- Inspect login/signup pages. A small part of websites, but nice to theme nonetheless. +- Be careful around hover and active states of buttons and button-like components. +- Internal links referenced in the website's footer are often good test pages if you aren't familiar with the site. +- Settings and profile pages are often missed details. +- Small details with input elements to note are borders, hover/active/focus borders, placeholder text and icons (the former should be themed by the standard library's defaults, but not always). + +## Reviewing source code + +Even if a userstyle is well-_themed_, it's also important that it is maintainable and _written_ well. For example, if a userstyle themes a website by targeting individual element selectors, but the website primarily makes use of a set of CSS variables under the hood, it's generally worth switching to the latter. + +- Organization is key. Some strategies include organization by page or component type (e.g. buttons and inputs in one section, cards and surfaces in another, etc.). Consistent comment annotations is best. +- Importantly, ensure palette colors are used aptly and appropriately. +- Avoid overcorrections of palette colors, such as `darken` or `lighten` operations in large amounts (`darken` by 30% produces a color that is relatively distinct from the pastel palette). + +## Writing feedback and review comments + +When leaving a comment pointing out issues discovered in a review, it is important to make suggestions digestible and actionable. Provide links to relevant pages, descriptions of steps to access a certain component, and screenshots.