User menu design tweaks

* Revises UserLinks.less according to the T285786 spec.

* Unsets 'createaccount' data in $content_navigation in favor creating
this link inside SkinVector which follows the same pattern as the Login
link. This is needed because the create account link needs to be on top
of the login link in the menu per T285786#7231671.

* Changes MenuDropdown.less to pad the anchor element instead of the li
element. This results in a more intuitive click target.

* Places an end margin on the search box to add space between the user
links and the search box.

Bug: T285786
Change-Id: Idb860e6b65c9f266a8027e3f486ccf4c4ec4ed3c
This commit is contained in:
Nicholas Ray 2021-07-22 15:20:15 -06:00
parent 245566386b
commit d8f62f780c
9 changed files with 130 additions and 61 deletions

View file

@ -184,11 +184,8 @@ class Hooks {
} else {
// Remove "Not logged in" from personal menu dropdown for anon users.
unset( $content_navigation['user-menu']['anonuserpage'] );
// Create account is pulled out into its own button and hidden at higher resolutions.
self::appendClassToListItem(
$content_navigation['user-menu']['createaccount'],
$COLLAPSE_MENU_ITEM_CLASS
);
// "Create account" link is handled manually by Vector
unset( $content_navigation['user-menu']['createaccount'] );
// "Login" link is handled manually by Vector
unset( $content_navigation['user-menu']['login'] );
}
@ -205,14 +202,25 @@ class Hooks {
$content_navigation['user-page']['userpage'],
$COLLAPSE_MENU_ITEM_CLASS
);
// Style the user page link as mw-ui-button.
self::addListItemClass(
$content_navigation['user-page']['userpage'],
[ 'mw-ui-button', 'mw-ui-quiet' ],
true
);
}
// Prefix user link items with associated icon.
$user_menu = $content_navigation['user-menu'];
// Loop through each menu to check/append its link classes.
foreach ( $user_menu as $menu_key => $menu_value ) {
$icon_name = $menu_value['icon'] ?? '';
self::addIconToListItem( $content_navigation['user-menu'][$menu_key], $icon_name );
// Don't show icons for anon menu items (besides login and create
// account).
if ( $sk->loggedin ) {
// Prefix user link items with associated icon.
$user_menu = $content_navigation['user-menu'];
// Loop through each menu to check/append its link classes.
foreach ( $user_menu as $menu_key => $menu_value ) {
$icon_name = $menu_value['icon'] ?? '';
self::addIconToListItem( $content_navigation['user-menu'][$menu_key], $icon_name );
}
}
} else {
// Remove user page from personal toolbar since it will be inside the personal menu for logged in

View file

@ -177,29 +177,43 @@ class SkinVector extends SkinMustache {
/**
* Returns HTML for the create account button inside the anon user links
* @param string[] $returnto array of query strings used to build the login link
* @param string[] $class array of CSS classes to add.
* @param bool $includeIcon Set true to include icon CSS classes.
* @return string
*/
private function getCreateAccountHTML( $returnto ) {
private function getCreateAccountHTML( $returnto, $class, $includeIcon ) {
$createAccountData = $this->buildCreateAccountData( $returnto );
$createAccountData['single-id'] = 'pt-createaccount';
$createAccountData['class'] = 'mw-ui-button mw-ui-quiet';
if ( $includeIcon ) {
$class = array_merge(
$class,
[
'mw-ui-icon mw-ui-icon-before',
'mw-ui-icon-wikimedia-' . ( $createAccountData[ 'icon' ] ?? '' )
]
);
}
$createAccountData['class'] = $class;
$htmlCreateAccount = $this->makeLink( 'create-account', $createAccountData );
return $htmlCreateAccount;
}
/**
* Returns HTML for the login button and learn more link inside the anon user menu
* Returns HTML for the create account button, login button and learn more link inside the anon user menu
* @param string[] $returnto array of query strings used to build the login link
* @param bool $useCombinedLoginLink if a combined login/signup link will be used
* @return string
*/
private function getLoginHTML( $returnto, $useCombinedLoginLink ) {
private function getAnonMenuBeforePortletHTML( $returnto, $useCombinedLoginLink ) {
// 'single-id' must be provided for `makeLink` to populate `title`, `accesskey` and other attributes
$loginData = $this->buildLoginData( $returnto, $useCombinedLoginLink );
$loginData['single-id'] = 'pt-login';
$loginData['class'] = [
'vector-menu-content-item',
'vector-menu-content-item-login',
'mw-ui-icon mw-ui-icon-before',
'mw-ui-icon-wikimedia-' . ( $loginData[ 'icon' ] ?? '' )
];
@ -212,6 +226,10 @@ class SkinVector extends SkinMustache {
$templateParser = $this->getTemplateParser();
return $templateParser->processTemplate( 'UserLinks__login', [
'htmlCreateAccount' => $this->getCreateAccountHTML( $returnto, [
'user-links-collapsible-item',
'vector-menu-content-item',
], true ),
'htmlLogin' => $this->makeLink( 'login', $loginData ),
'msgLearnMore' => $this->msg( 'vector-anon-user-menu-pages' ),
'htmlLearnMoreLink' => $this->msg( 'parentheses' )->
@ -230,6 +248,7 @@ class SkinVector extends SkinMustache {
$templateParser = $this->getTemplateParser();
$logoutLinkData['class'] = [
'vector-menu-content-item',
'vector-menu-content-item-logout',
'mw-ui-icon mw-ui-icon-before',
'mw-ui-icon-wikimedia-' . ( $logoutLinkData[ 'icon' ] ?? '' )
];
@ -249,7 +268,10 @@ class SkinVector extends SkinMustache {
private function getUserLinksTemplateData( $menuData, $isAnon, $searchBoxData ): array {
$returnto = $this->getReturnToParam();
$useCombinedLoginLink = $this->useCombinedLoginLink();
$htmlCreateAccount = $this->getCreateAccountHTML( $returnto );
$htmlCreateAccount = $this->getCreateAccountHTML( $returnto, [
'mw-ui-button',
'mw-ui-quiet'
], false );
$templateParser = $this->getTemplateParser();
$userMoreHtmlItems = $templateParser->processTemplate( 'UserLinks__more', [
@ -270,7 +292,10 @@ class SkinVector extends SkinMustache {
$userMenuData = $menuData[ 'data-user-menu' ];
if ( $isAnon ) {
$userMenuData[ 'html-before-portal' ] .= $this->getLoginHTML( $returnto, $useCombinedLoginLink );
$userMenuData[ 'html-before-portal' ] .= $this->getAnonMenuBeforePortletHTML(
$returnto,
$useCombinedLoginLink
);
} else {
// Appending as to not override data potentially set by the onSkinAfterPortlet hook.
$userMenuData[ 'html-after-portal' ] .= $this->getLogoutHTML();

View file

@ -1,6 +1,7 @@
<div class="vector-user-menu-create-account">{{{htmlCreateAccount}}}</div>
<div class="vector-user-menu-login">{{{htmlLogin}}}</div>
<div class="vector-user-menu-anon-editor">
<p>
{{{msgLearnMore}}} {{{htmlLearnMoreLink}}}:
{{{msgLearnMore}}} {{{htmlLearnMoreLink}}}
</p>
</div>

View file

@ -1,4 +1,4 @@
{{!-- The #pt-logout ID is required for the AJAX enabled logout in mediawiki.page.ready to work.}}
<div id="pt-logout" class="vector-user-menu-login">
<div id="pt-logout" class="vector-user-menu-logout">
{{{htmlLogout}}}
</div>
</div>

View file

@ -80,12 +80,13 @@
}
li {
padding: 0.625em;
padding: 0;
margin: 0;
text-align: left;
line-height: 1em;
a {
padding: 0.625em;
color: @color-link;
display: block;
white-space: nowrap;

View file

@ -1,5 +1,8 @@
@import '../../common/variables.less';
@font-size-user-links: unit( 14 / @font-size-browser, em ); // Equals `0.875em`.
@padding-horizontal-user-links: 12px;
.vector-user-links {
display: flex;
align-items: center;
@ -8,13 +11,15 @@
flex-shrink: 1;
.vector-user-menu-more {
font-size: @font-size-user-links;
.vector-menu-content-list {
display: flex;
align-items: center;
li {
padding-top: 0;
margin-left: 1em;
margin: 0;
white-space: nowrap;
a {
@ -33,17 +38,24 @@
}
}
}
.mw-ui-button {
// FIXME: Overrides mw-ui-button's `display: inline-block` property so that
// the text in the button is vertically centered. `.mw-ui-button` sets a
// min-height to the button, but should also vertically center the
// button's children.
display: flex;
align-items: center;
}
}
// Overrides personal menu styles for consolidated user links.
.vector-user-menu {
margin: 0 0 0 12px;
height: 100%;
h3 {
color: transparent; // overrides MediaWiki UI icon
height: 100%;
font-size: inherit;
}
.vector-menu-checkbox {
@ -61,63 +73,71 @@
left: unset;
right: 0;
border-top-width: 1px;
border-radius: 2px;
// T285786: Box shadow per design spec
box-shadow: 0 2px 2px 0 rgba( 0, 0, 0, 0.25 );
.user-links-collapsible-item {
@media ( min-width: @width-breakpoint-tablet ) {
display: none;
}
}
}
.vector-menu-content-list {
li {
width: 100%;
margin: 0;
&:hover {
background-color: @background-color-secondary;
}
&.user-links-collapsible-item {
@media ( min-width: @width-breakpoint-tablet ) {
display: none;
}
}
}
a {
display: block;
color: #000;
text-decoration: none;
}
}
// Copied from https://github.com/wikimedia/Vector/blob/master/resources/common/components/MenuDropdown.less#L88
.vector-user-menu-anon-editor,
.vector-user-menu-login {
padding: 0.625em;
margin: 0;
.vector-menu-content-item,
li > 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
// min-height instead of vertical padding allows menu items without an
// icon to still be 32px in height.
min-height: unit( 32px / @font-size-browser, em );
// Overrides .mw-ui-icon's `display: inline-block` property so that
// the text can be vertically centered.
display: flex;
align-items: center;
// Overrides .mw-ui-icon's `padding: 0` property so that the text is not
// 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;
text-decoration: none;
p,
span {
font-size: @font-size-tabs;
font-size: @font-size-user-links;
}
}
// "Login" and "Logout" links in user menu
.vector-user-menu-login {
// Set hover color for "Create account" and "Login" menu items.
&:hover {
background-color: @background-color-secondary;
}
}
&:first-child {
border-bottom: 1px solid @border-color-base;
}
.vector-menu-content-item-login {
border-bottom: 1px solid @border-color-base;
}
&:last-child {
border-top: 1px solid @border-color-base;
}
.vector-user-menu-anon-editor {
margin-top: 2px;
padding: @padding-horizontal-user-links;
color: @colorGray5;
font-size: @font-size-user-links;
a {
display: block;
color: #000;
text-decoration: none;
p {
margin: 0;
}
}
.vector-menu-content-item-logout {
border-top: 1px solid @border-color-base;
}
}
.vector-user-menu-logged-out h3 {

View file

@ -44,6 +44,7 @@
@min-width-search-desktop: unit( 350px / @font-size-browser / @font-size-base, em ); // 25em @ 16 & 0.875em
@max-width-search: unit( 500px / @font-size-browser / @font-size-base, em ); // 35.71428571em @ 16 & 0.875em
@margin-horizontal-search: unit( 40px / @font-size-browser / @font-size-base, em ); // 2.85714286em @ 16 & 0.875em
@margin-end-search: 12px;
// Personal menu
@ -438,7 +439,7 @@ body {
#p-search,
.skin-vector-consolidated-user-links #p-search {
margin: 0 0 0 @margin-horizontal-search;
margin: 0 @margin-end-search 0 @margin-horizontal-search;
// Support: IE 8, Firefox 18-, Chrome 19-, Safari 5.1-, Opera 19-, Android 4.4.4-.
width: 13.2em;
// Support: Modern browsers, responsive width.
@ -480,6 +481,7 @@ body {
// button at small resolutions.
position: relative;
margin-left: @padding-horizontal-tabs;
margin-right: @margin-end-search;
}
// Increase the start margin of the search box to account for the input

View file

@ -205,6 +205,7 @@
"vector": {
"+ext.echo.styles.alert": "skinStyles/ext.echo.styles.alert.less",
"+ext.uls.compactlinks": "skinStyles/ext.uls.compactlinks.less",
"+ext.uls.pt": "skinStyles/ext.uls.pt.less",
"jquery.tipsy": "skinStyles/jquery.tipsy.less",
"jquery.ui": [
"skinStyles/jquery.ui/jquery.ui.core.css",

View file

@ -0,0 +1,11 @@
// Add padding around uls trigger when in user links.
// !important as we always want to add extra margin when the uls trigger is inside the user links.
// Using !important is cleaner than having to rely on specificity.
.vector-user-links {
.uls-trigger {
// stylelint-disable-next-line declaration-no-important
margin-left: 12px !important;
// stylelint-disable-next-line declaration-no-important
margin-right: 12px !important;
}
}