Simplify how we generate icons and button classes in Vector

- Separate icon classes from button classes in user links/language
- Upgrades the personal tools language button preference to
a mw-ui-button with icon
- Adds a generic selector for dropdown menus without an icon
- Cleans up user links CSS now mw-list-item class is available
- Removes icon hack CSS

Bug: T289630
Bug: T283757
Change-Id: Ib518858e06549f252d73d57fd4768f446cc561b9
This commit is contained in:
jdlrobson 2021-08-26 12:47:02 -07:00 committed by Jdlrobson
parent 877e001ea9
commit b88f2970f7
11 changed files with 116 additions and 53 deletions

View File

@ -220,6 +220,49 @@ class Hooks {
}
}
/**
* Make an icon
*
* @internal for use inside Vector skin.
* @param string $name
* @return string of HTML
*/
public static function makeButtonIcon( $name ) {
// Html::makeLink will pass this through rawElement
return '<span class="mw-ui-icon mw-ui-icon-' . $name . '"></span>';
}
/**
* Updates user interface preferences for modern Vector to upgrade icon/button menu items.
*
* @param SkinTemplate $sk
* @param array &$content_navigation
* @param string $menu identifier
*/
private static function updateMenuItems( $sk, &$content_navigation, $menu ) {
foreach ( $content_navigation[$menu] as $key => $item ) {
$hasButton = $item['button'] ?? false;
$hideText = $item['text-hidden'] ?? false;
$icon = $item['icon'] ?? '';
unset( $item['button'] );
unset( $item['icon'] );
unset( $item['text-hidden'] );
if ( $hasButton ) {
$item['link-class'][] = 'mw-ui-button mw-ui-quiet';
}
if ( $icon ) {
if ( $hideText ) {
$item['link-class'][] = 'mw-ui-icon mw-ui-icon-element mw-ui-icon-' . $icon;
} else {
$item['link-html'] = self::makeButtonIcon( $icon );
}
}
$content_navigation[$menu][$key] = $item;
}
}
/**
* Upgrades Vector's watch action to a watchstar.
* This is invoked inside SkinVector, not via skin registration, as skin hooks
@ -251,6 +294,21 @@ class Hooks {
self::updateUserLinksItems( $sk, $content_navigation );
}
}
if ( !self::isSkinVersionLegacy() ) {
// Upgrade preferences and notifications to icon buttons
// for extensions that have opted in.
if ( isset( $content_navigation['user-interface-preferences'] ) ) {
self::updateMenuItems(
$sk, $content_navigation, 'user-interface-preferences'
);
}
if ( isset( $content_navigation['notifications'] ) ) {
self::updateMenuItems(
$sk, $content_navigation, 'notifications'
);
}
}
}
}

View File

@ -514,12 +514,10 @@ class SkinVector extends SkinMustache {
'label' => $label,
// ext.uls.interface attaches click handler to this selector.
'checkbox-class' => ' mw-interlanguage-selector ',
'html-vector-heading-icon' => Hooks::makeButtonIcon( 'wikimedia-language' ),
'heading-class' =>
' vector-menu-heading ' .
' mw-ui-icon ' .
' mw-ui-icon-before ' .
' mw-ui-icon-wikimedia-language ' .
' mw-ui-button mw-ui-quiet '
' mw-ui-button mw-ui-quiet'
];
// Adds class to hide language button
@ -533,6 +531,7 @@ class SkinVector extends SkinMustache {
/**
* helper for applying Vector menu classes to portlets
*
* @param array $portletData returned by SkinMustache to decorate
* @param int $type representing one of the menu types (see MENU_TYPE_* constants)
* @return array modified version of portletData input
@ -557,12 +556,21 @@ class SkinVector extends SkinMustache {
$portletData['class'] .= $this->loggedin ?
' vector-user-menu-logged-in' :
' vector-user-menu-logged-out';
$portletData['heading-class'] .= ' mw-ui-icon mw-ui-icon-element';
$portletData['heading-class'] .= ' mw-ui-button mw-ui-quiet mw-ui-icon mw-ui-icon-element';
$portletData['heading-class'] .= $this->loggedin ?
' mw-ui-icon-wikimedia-userAvatar' :
' mw-ui-icon-wikimedia-ellipsis';
}
}
switch ( $portletData['id'] ) {
case 'p-variants':
case 'p-cactions':
$portletData['class'] .= ' vector-menu-dropdown-noicon';
break;
default:
break;
}
if ( $portletData['id'] === 'p-lang' && $this->isLanguagesInHeader() ) {
$portletData = $this->createULSLanguageButton( $portletData );
}

View File

@ -1,7 +1,7 @@
<header class="mw-header">
<label
id="mw-sidebar-button"
class="mw-checkbox-hack-button mw-ui-icon mw-ui-icon-element"
class="mw-checkbox-hack-button mw-ui-icon mw-ui-button mw-ui-quiet mw-ui-icon-element"
for="mw-sidebar-checkbox"
role="button"
aria-controls="mw-panel"

View File

@ -1 +1,3 @@
<div class="mw-ui-icon mw-ui-icon-element mw-ui-icon-{{icon}} {{class}}"></div>
<a {{#href}}href="{{.}}"{{/href}} class="mw-ui-button mw-ui-quiet mw-ui-icon mw-ui-icon-element mw-ui-icon-{{icon}} {{class}}">
{{#label}}<span>{{*}}</span>{{/label}}
</a>

View File

@ -12,8 +12,8 @@
data-event-name="ui.dropdown-{{id}}"
class="{{#checkbox-class}}{{.}}{{/checkbox-class}} vector-menu-checkbox" aria-labelledby="{{id}}-label" />
{{/is-dropdown}}
<h3 id="{{id}}-label" {{#heading-class}}class="{{.}}"{{/heading-class}}>
<span>{{label}}</span>
<h3 id="{{id}}-label" {{#heading-class}}class="{{.}}"{{/heading-class}}>{{!
}}{{{html-vector-heading-icon}}} <span>{{label}}</span>
{{#is-dropdown}}
<span class="vector-menu-checkbox-expanded">{{msg-vector-menu-checkbox-expanded}}</span>
<span class="vector-menu-checkbox-collapsed">{{msg-vector-menu-checkbox-collapsed}}</span>

View File

@ -24,7 +24,7 @@
</form>
</div>
{{#is-collapsible}}
<a class="mw-ui-icon mw-ui-icon-wikimedia-search mw-ui-icon-element search-toggle"
<a class="mw-ui-button mw-ui-quiet mw-ui-icon mw-ui-icon-wikimedia-search mw-ui-icon-element search-toggle"
href="{{href-search}}">
<span>{{msg-search}}</span>
</a>

View File

@ -15,15 +15,6 @@
display: block;
.box-sizing( border-box );
&:not( .mw-ui-icon ) {
// `padding-top` needs to scale with font-size.
padding-top: 1.25em;
padding-left: 8px;
padding-right: unit( 24 / @font-size-tabs / @font-size-browser, em );
font-size: @font-size-tabs;
font-weight: normal;
}
&:after {
content: '';
background-image: url( images/arrow-down.svg );
@ -166,9 +157,23 @@
// When the browser supports :checked, display it
display: block;
}
}
// FIXME: `mw-portlet-` selectors are for cached HTML. Remove after 1 week. (T283757)
.mw-portlet-variants,
.mw-portlet-cactions,
.vector-menu-dropdown-noicon {
h3 {
// `padding-top` needs to scale with font-size.
padding-top: 1.25em;
padding-left: 8px;
padding-right: unit( 24 / @font-size-tabs / @font-size-browser, em );
font-size: @font-size-tabs;
font-weight: normal;
}
// Add focus state to legacy menu dropdown buttons (i.e. p-variants, p-cactions)
&:focus + h3 {
.vector-menu-checkbox:focus + h3 {
// Simulate browser focus ring
outline: dotted 1px; // Firefox style
outline: auto -webkit-focus-ring-color; // Webkit style

View File

@ -4,6 +4,8 @@
// TODO: `#p-lang-btn` Can be changed to `.mw-portlet-lang` when languages-in-header is the default.
#p-lang-btn {
// FIXME [review whether margin-top is needed] center vertically in heading.
margin-top: 2px;
.box-sizing( border-box );
height: @height-lang-button;
@ -21,10 +23,6 @@
user-select: none;
// Remove opacity on language button (it applies to more menu because of label color).
opacity: 1;
// mw-ui-icon resets the button border.
border: 1px solid transparent;
// center vertically in heading.
margin-top: 2px;
span {
// Special treatment for language button, based on Vector font-size

View File

@ -33,13 +33,6 @@
opacity: 1;
}
}
&:focus {
// Next three rules from OOUI, frameless, icon-only button widget.
border-color: @border-color-base--focus;
outline: 0;
box-shadow: @box-shadow-base--focus;
}
}
// Use the MediaWiki checkbox hack class from checkboxHack.less. This class exists on the

View File

@ -23,8 +23,12 @@
white-space: nowrap;
a {
color: #000;
color: @color-base;
text-decoration: none;
.mw-ui-icon {
margin-right: 4px;
}
}
// Below tablet threshold, all menu items except the notification icons will collapse into the user menu
@ -63,9 +67,7 @@
}
}
// Overrides personal menu styles for consolidated user links.
.vector-user-menu {
height: 100%;
// Override ".emptyPortlet" class to ensure user menu isn't hidden
&.emptyPortlet {
@ -73,17 +75,13 @@
}
.vector-menu-heading {
color: transparent; // overrides MediaWiki UI icon
height: 100%;
line-height: 0; // T288540: Override language specific line height so user menu spacing is correct.
}
.mw-ui-icon ~ span {
.mixin-screen-reader-text();
}
.vector-menu-checkbox {
// FIXME: This variable is currently not available in mediawiki core, but defined in the icons specification.
@icon-background-color--selected: rgba( 0, 0, 0, 0.03 );
// The mw-ui-icon hover effect does not work on the checkbox hack so must be applied explicitly.
&:hover + h3 {
background-color: @icon-background-color--selected;
// FIXME: For cached HTML only.
&.mw-ui-icon > span {
color: transparent;
}
}
@ -105,15 +103,16 @@
}
}
.vector-menu-content-list {
li {
width: 100%;
margin: 0;
}
// FIXME: Remove `li` selector when T289163 is addressed.
li,
.mw-list-item {
width: 100%;
}
// FIXME: Remove `li > a` selector when T289163 is addressed.
li > a,
.vector-menu-content-item,
li > a {
.mw-list-item > a {
// Overrides .mw-ui-icon's `min-height` property to have a computed
// min-height of 32px. This matches the design spec of having an icon that
// is 20px in height + 6px of top padding + 6px of bottom padding. Using
@ -128,7 +127,7 @@
// at the edge of the menu. Apply the padding on the link element instead
// of the li element to maximize the click target.
padding: 0 @padding-horizontal-user-links;
color: #000;
color: @color-base;
text-decoration: none;
span {

View File

@ -109,11 +109,11 @@ class SkinVectorTest extends MediaWikiIntegrationTestCase {
$namespaces['class']
);
$this->assertSame(
'mw-portlet mw-portlet-variants vector-menu vector-menu-dropdown',
'mw-portlet mw-portlet-variants vector-menu-dropdown-noicon vector-menu vector-menu-dropdown',
$variants['class']
);
$this->assertSame(
'mw-portlet mw-portlet-cactions vector-menu vector-menu-dropdown',
'mw-portlet mw-portlet-cactions vector-menu-dropdown-noicon vector-menu vector-menu-dropdown',
$actions['class']
);
$this->assertSame(