Language button is quiet with focus, active and hover states

* Add mediawiki ui button styles to Vector and convert language
button to a quiet button
* Restore the arrow for language button with ULS
* Vertically align button to first line of header
* Add a storybook entry for LanguageButton

Additional changes:
* Fix issues revealed by storybook - menu dropdown should
reset generic typography rule for `ul` tags
* Allow quotes usage in storybook without disable rule

Bug: T268241
Change-Id: I483350084fb46a51c50af6aab78c62db6d02df89
This commit is contained in:
jdlrobson 2021-02-08 15:10:21 -08:00 committed by Jdlrobson
parent b97ff7e827
commit 8d8e2d85e6
18 changed files with 127 additions and 45 deletions

View File

@ -1,6 +1,7 @@
@import '../variables.less';
@import 'integration.less';
@import 'icons.less';
@import '../skinStyles/mediawiki.ui.icon.less';
body {
font-family: @font-family-sans;

View File

@ -18,3 +18,7 @@
background-image: linear-gradient(transparent,transparent),
url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2220%22 height=%2220%22 viewBox=%220 0 20 20%22%3E %3Ctitle%3E language %3C/title%3E %3Cpath d=%22M20 18h-1.44a.61.61 0 0 1-.4-.12.81.81 0 0 1-.23-.31L17 15h-5l-1 2.54a.77.77 0 0 1-.22.3.59.59 0 0 1-.4.14H9l4.55-11.47h1.89zm-3.53-4.31L14.89 9.5a11.62 11.62 0 0 1-.39-1.24q-.09.37-.19.69l-.19.56-1.58 4.19zm-6.3-1.58a13.43 13.43 0 0 1-2.91-1.41 11.46 11.46 0 0 0 2.81-5.37H12V4H7.31a4 4 0 0 0-.2-.56C6.87 2.79 6.6 2 6.6 2l-1.47.5s.4.89.6 1.5H0v1.33h2.15A11.23 11.23 0 0 0 5 10.7a17.19 17.19 0 0 1-5 2.1q.56.82.87 1.38a23.28 23.28 0 0 0 5.22-2.51 15.64 15.64 0 0 0 3.56 1.77zM3.63 5.33h4.91a8.11 8.11 0 0 1-2.45 4.45 9.11 9.11 0 0 1-2.46-4.45z%22/%3E %3C/svg%3E") !important;
}
.mw-ui-icon-wikimedia-language:before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Ctitle%3Elanguage%3C/title%3E%3Cg fill='%2354595d'%3E%3Cpath d='M20 18h-1.44a.61.61 0 01-.4-.12.81.81 0 01-.23-.31L17 15h-5l-1 2.54a.77.77 0 01-.22.3.59.59 0 01-.4.14H9l4.55-11.47h1.89zm-3.53-4.31L14.89 9.5a11.62 11.62 0 01-.39-1.24q-.09.37-.19.69l-.19.56-1.58 4.19zm-6.3-1.58a13.43 13.43 0 01-2.91-1.41 11.46 11.46 0 002.81-5.37H12V4H7.31a4 4 0 00-.2-.56C6.87 2.79 6.6 2 6.6 2l-1.47.5s.4.89.6 1.5H0v1.33h2.15A11.23 11.23 0 005 10.7a17.19 17.19 0 01-5 2.1q.56.82.87 1.38a23.28 23.28 0 005.22-2.51 15.64 15.64 0 003.56 1.77zM3.63 5.33h4.91a8.11 8.11 0 01-2.45 4.45 9.11 9.11 0 01-2.46-4.45z'/%3E%3C/g%3E%3C/svg%3E");
}

View File

@ -9,7 +9,7 @@ rm -f .storybook/resolve-imports/mediawiki.skin.variables.less
cp resources/mediawiki.less/mediawiki.skin.variables.less .storybook/resolve-imports/
# Fetch resources via curl, `-sSL` silently, Show only errors, Location header and also with a 3XX response code.
curl -sS "https://en.wikipedia.org/w/load.php?only=styles&skin=vector&debug=true&modules=ext.echo.styles.badge|ext.uls.pt|wikibase.client.init|mediawiki.skinning.interface" -o .storybook/integration.less
curl -sS "https://en.wikipedia.org/w/load.php?only=styles&skin=vector&debug=true&modules=ext.echo.styles.badge|ext.uls.pt|wikibase.client.init|mediawiki.skinning.interface|mediawiki.ui.icon|mediawiki.ui.button" -o .storybook/integration.less
curl -sSL "https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/core/+/master/resources/src/mediawiki.less/mediawiki.skin.defaults.less?format=TEXT" | base64 --decode > .storybook/resolve-imports/mediawiki.skin.defaults.less
curl -sSL "https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/core/+/master/resources/src/mediawiki.less/mediawiki.mixins.less?format=TEXT" | base64 --decode > .storybook/resolve-imports/mediawiki.mixins.less
curl -sSL "https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/core/+/master/resources/src/mediawiki.less/mediawiki.ui/variables.less?format=TEXT" | base64 --decode > .storybook/resolve-imports/mediawiki.ui/variables.less

View File

@ -252,7 +252,8 @@ class SkinVector extends SkinMustache {
count( $this->getLanguages() )
)->parse();
// Adds language icon
$portletData['heading-class'] .= ' mw-ui-icon mw-ui-icon-before mw-ui-icon-wikimedia-language';
$portletData['heading-class'] .= ' mw-ui-icon mw-ui-icon-before '
. 'mw-ui-icon-wikimedia-language mw-ui-button mw-ui-quiet';
// Adds .mw-interlanguage-selector (ext.uls.interface attaches click
// handler to this selector).
$portletData['heading-class'] .= ' mw-interlanguage-selector';

View File

@ -1,27 +1,22 @@
@import 'mediawiki.ui/mixins.buttons.less';
// The use of mixins.buttons requires @font-size-base to be defined for this to work in Storybook
@import '../../variables.less';
// mw-body-header class can be removed when language button is the default.
// e.g. upon removal of SkinVector::isLanguagesInHeader
.mw-body-header .mw-portlet-lang {
.mw-ui-button-states();
.vector-menu-heading {
color: inherit;
// In future this should use wvui
.mw-ui-button();
padding-right: 30px;
// make sure label is center aligned.
display: flex;
align-items: center;
// Special treatment for language button, based on Vector font-size
font-size: @font-size-base;
// avoid sub pixel rendering
line-height: 1.493em;
// reset padding styles in MenuDropdown.less with right padding for arrow.
padding: 0 30px 0 8px;
// Prevent select of span text "X languages"
user-select: none;
&:after {
top: 0;
}
&:hover,
&:focus {
color: inherit;
}
}
.vector-menu-content {
@ -44,6 +39,14 @@
}
}
// Disable border-radius when dropdown menu open
.client-nojs {
.mw-portlet-lang:hover .vector-menu-heading,
.vector-menu-checkbox:checked + .vector-menu-heading {
border-radius: 0;
}
}
// mw-body-header class can be removed when language button is the default.
// e.g. upon removal of SkinVector::isLanguagesInHeader
.client-js .mw-body-header {
@ -53,11 +56,6 @@
// Remove the ULS language icon provided by ext.uls.compactlinks.less as we
// are already providing no-js users an icon.
background-image: none;
&:after {
// Don't show dropdown arrow.
content: none;
}
}
// When the ext.uls.interface module is loaded, we hide the fallback menu and

View File

@ -72,6 +72,11 @@
visibility: visible;
}
ul {
// display list style images introduced in typography.less.
list-style: none;
}
li {
padding: 0;
margin: 0;

View File

@ -83,7 +83,12 @@ body {
.mixin-clearfix();
#p-lang-btn {
@height-lang-button: 1.25em;
float: right;
.box-sizing( border-box );
height: @height-lang-button;
// should be vertically aligned.
margin-top: ( ( @font-size-heading-1 * @line-height-heading ) - @height-lang-button ) / 2;
}
}

View File

@ -25,6 +25,7 @@
"skins.vector.js"
],
"styles": [
"mediawiki.ui.button",
"skins.vector.styles",
"skins.vector.icons",
"mediawiki.ui.icon"

View File

@ -1,6 +1,6 @@
// The .mw-page-container class is used to restrict this to the modern Vector.
// This element is not needed in legacy Vector.
.mw-page-container .mw-ui-icon:before {
.mw-portlet-lang .mw-ui-icon:before {
// mw-ui-icon in core defaults to 24x24. The style guide now requests 20x20.
background-size: 20px auto;
width: 20px;

View File

@ -7,6 +7,9 @@
"env": {
"browser": true
},
"rules": {
"quotes": "off"
},
"parserOptions": {
"sourceType": "module"
}

View File

@ -1,5 +1,3 @@
/* eslint-disable quotes */
import { htmlUserLanguageAttributes } from './utils';
import footerTemplate from '!!raw-loader!../includes/templates/Footer.mustache';
import footerRowTemplate from '!!raw-loader!../includes/templates/Footer__row.mustache';

View File

@ -0,0 +1,31 @@
/**
* @external MenuDefinition
*/
import { placeholder, htmlUserLanguageAttributes, portletAfter } from './utils';
/**
* @type {MenuDefinition}
*/
export const languageData = {
id: 'p-lang-btn',
// both classes needed for this to render correctly
class: 'mw-portlet-lang vector-menu-dropdown',
// mw-interlanguage-selector must be present to operate in ULS mode.
// icon classes and button classes
'heading-class': 'vector-menu-heading mw-interlanguage-selector ' +
'mw-ui-icon mw-ui-icon-before mw-ui-icon-wikimedia-language ' +
'mw-ui-button mw-ui-quiet',
'html-tooltip': 'A message tooltip-p-lang must exist for this to appear',
label: '10 languages',
'html-user-language-attributes': htmlUserLanguageAttributes,
'html-items': `
<li class="interlanguage-link interwiki-ace">
<a href="https://ace.wikipedia.org/wiki/Seupanyo"
title="Seupanyo Achinese" lang="ace" hreflang="ace" class="interlanguage-link-target">Acèh</a>
</li><li class="interlanguage-link interwiki-kbd"><a href="https://kbd.wikipedia.org/wiki/%D0%AD%D1%81%D0%BF%D0%B0%D0%BD%D0%B8%D1%8D" title="Эспаниэ Kabardian" lang="kbd" hreflang="kbd" class="interlanguage-link-target">Адыгэбзэ</a></li><li class="interlanguage-link interwiki-ady"><a href="https://ady.wikipedia.org/wiki/%D0%98%D1%81%D0%BF%D0%B0%D0%BD%D0%B8%D0%B5" title="Испание Adyghe" lang="ady" hreflang="ady" class="interlanguage-link-target">Адыгабзэ</a></li><li class="interlanguage-link interwiki-af"><a href="https://af.wikipedia.org/wiki/Spanje" title="Spanje Afrikaans" lang="af" hreflang="af" class="interlanguage-link-target">Afrikaans</a></li><li class="interlanguage-link interwiki-ak"><a href="https://ak.wikipedia.org/wiki/Spain" title="Spain Akan" lang="ak" hreflang="ak" class="interlanguage-link-target">Akan</a></li><li class="interlanguage-link interwiki-als"><a href="https://als.wikipedia.org/wiki/Spanien" title="Spanien Alemannisch" lang="gsw" hreflang="gsw" class="interlanguage-link-target">Alemannisch</a></li><li class="interlanguage-link interwiki-am"><a href="https://am.wikipedia.org/wiki/%E1%8A%A5%E1%88%B5%E1%8D%93%E1%8A%95%E1%8B%AB" title="እስፓንያ Amharic" lang="am" hreflang="am" class="interlanguage-link-target">አማርኛ</a></li><li class="interlanguage-link interwiki-ang"><a href="https://ang.wikipedia.org/wiki/Sp%C4%93onland" title="Spēonland Old English" lang="ang" hreflang="ang" class="interlanguage-link-target">Ænglisc</a></li><li class="interlanguage-link interwiki-ab"><a href="https://ab.wikipedia.org/wiki/%D0%98%D1%81%D0%BF%D0%B0%D0%BD%D0%B8%D0%B0" title="Испаниа Abkhazian" lang="ab" hreflang="ab" class="interlanguage-link-target">Аҧсшәа</a></li><li class="interlanguage-link interwiki-ar badge-Q17437798 badge-goodarticle" title="good article"><a href="https://ar.wikipedia.org/wiki/%D8%A5%D8%B3%D8%A8%D8%A7%D9%86%D9%8A%D8%A7" title="إسبانيا Arabic" lang="ar" hreflang="ar" class="interlanguage-link-target">العربية</a></li>
`,
'html-after-portal': portletAfter(
`<span class="wb-langlinks-edit wb-langlinks-link"><a href="https://www.wikidata.org/wiki/Special:EntityPage/Q29#sitelinks-wikipedia" title="Edit interlanguage links (provided by WikiBase extension)" class="wbc-editpage">Edit links</a></span></div>
${placeholder( `<p>Further hook output possible (lang)</p>`, 60 )}`
)
};

View File

@ -0,0 +1,44 @@
import mustache from 'mustache';
import '../resources/skins.vector.styles/LanguageButton.less';
import { vectorMenuTemplate } from './MenuDropdown.stories.data';
import { languageData } from './LanguageButton.stories.data';
export default {
title: 'LanguageButton'
};
// mw-page-container is needed to enable the 20x20 icon
// mw-body-header can be removed when VectorLanguageInHeader is true and
// old language inside portal in modern Vector is no longer supported.
const CONTAINER_CLASS_MODERN_VECTOR = 'mw-body-header mw-page-container';
/**
* It allows us to support old and new renderings.
*
* @param {string|HTMLElement} htmlOrElement
* @param {string} className of containing element
* @return {HTMLElement}
*/
const wrapLanguageButton = ( htmlOrElement, className ) => {
const node = document.createElement( 'div' );
node.setAttribute( 'class', className );
if ( typeof htmlOrElement === 'string' ) {
node.innerHTML = htmlOrElement;
} else {
node.appendChild( htmlOrElement );
}
return node;
};
export const languageButton = () => mustache.render( vectorMenuTemplate, languageData );
export const languageButtonWhenULSEnabled = () => wrapLanguageButton(
wrapLanguageButton(
wrapLanguageButton(
mustache.render( vectorMenuTemplate, languageData ),
'vector-menu--hide-dropdown'
),
CONTAINER_CLASS_MODERN_VECTOR
),
'client-js'
);

View File

@ -1,9 +1,6 @@
/**
* @external MenuDefinition
*/
/* eslint-disable quotes */
import menuTemplate from '!!raw-loader!../includes/templates/Menu.mustache';
import { htmlUserLanguageAttributes } from './utils';

View File

@ -1,14 +1,11 @@
/**
* @external MenuDefinition
*/
/* eslint-disable quotes */
import mustache from 'mustache';
import { vectorMenuTemplate as portalTemplate } from './MenuDropdown.stories.data';
import '../resources/skins.vector.styles/MenuPortal.less';
import '../.storybook/common.less';
import { placeholder, htmlUserLanguageAttributes } from './utils';
import { placeholder, htmlUserLanguageAttributes, portletAfter } from './utils';
/**
* @param {MenuDefinition} data
@ -21,14 +18,6 @@ export const wrapPortlet = ( data ) => {
return node;
};
/**
* @param {string} html
* @return {string}
*/
const portletAfter = ( html ) => {
return `<div class="after-portlet after-portlet-tb">${html}</div>`;
};
/**
* @type {Object.<string, MenuDefinition>}
*/

View File

@ -1,5 +1,3 @@
/* eslint-disable quotes */
/**
* @external Indicator
*/

View File

@ -54,6 +54,7 @@
* @property {string} id
* @property {string} label
* @property {string} html-items
* @property {string} [heading-class]
* @property {string} [html-tooltip]
* @property {string} [class] of menu
* @property {string} [html-user-language-attributes]

View File

@ -1,5 +1,3 @@
/* eslint-disable quotes */
/**
* @param {string} msg
* @param {number} [height=200]
@ -11,6 +9,14 @@ const placeholder = ( msg, height ) => {
display: flex; background: #eee; align-items: center;justify-content: center;">${msg}</div>`;
};
/**
* @param {string} html
* @return {string}
*/
const portletAfter = ( html ) => {
return `<div class="after-portlet after-portlet-tb">${html}</div>`;
};
const htmlUserLanguageAttributes = `dir="ltr" lang="en-GB"`;
export { placeholder, htmlUserLanguageAttributes };
export { placeholder, htmlUserLanguageAttributes, portletAfter };