[modern] A new version of Vector with a new logo

Changes to support feature:
* ResourceLoaderSkinModule logo features are dropped
* New layout provided given the fork in layout between legacy and new.
* Legacy sidebar styles now pulled out
* breakpoint styles are not carried over from legacy Vector
The new Vector layout for now has one breakpoint.

Changes to storybook:
* The storybook script now pulls down image assets so that the logos can
be shown in storybook. The script is adjusted to make use of a static folder to
serve these images.

Note:
* The legacy mode is not touched as part of this patchset.
* The personal menu is unaffected by this patch and is out of scope.
* The alignment issue is noted, but will be solved at a later date.
* Changes to portal are out of scope.
* Adding storybook for modern descoped, given its not possible to load
both legacy layout and modern layout inside a storybook at current time.

Sample config:

$wgLogos = [
        'icon' => 'https://di-logo-sandbox.firebaseapp.com/img/globe.png',
        'tagline' => [
                'src' => 'https://di-logo-sandbox.firebaseapp.com/img/tagline/en-tagline-117-13.svg',
                'width' => 117,
                'height' => 13,
        ],
        '1x' => 'https://en.wikipedia.org/static/images/project-logos/enwiki.png',
        'wordmark' => [
                'src' => 'https://en.wikipedia.org/static/images/mobile/copyright/wikipedia-wordmark-en.svg',
                'width' => 116,
                'height' => 18,
        ],
];

Coauthor: Aron Manning

Bug: T246170
Change-Id: Ibc4b055150761388a6b78f9127da342c451ce0e7
This commit is contained in:
jdlrobson 2020-03-09 06:51:00 +01:00
parent db29a88ee0
commit 6a9ee465bc
15 changed files with 286 additions and 55 deletions

View File

@ -3,9 +3,14 @@ set -euo pipefail
IFS=$'\n\t'
mkdir -p .storybook/resolve-less-imports/mediawiki.ui
mkdir -p docs/ui/assets/
curl "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 -L "https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/core/+/master/resources/src/mediawiki.less/mediawiki.mixins.less?format=TEXT" | base64 --decode > .storybook/resolve-less-imports/mediawiki.mixins.less
curl -L "https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/core/+/master/resources/src/mediawiki.less/mediawiki.ui/variables.less?format=TEXT" | base64 --decode > .storybook/resolve-less-imports/mediawiki.ui/variables.less
curl -L "https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/core/+/master/resources/src/mediawiki.less/mediawiki.mixins.rotation.less?format=TEXT" | base64 --decode > .storybook/resolve-less-imports/mediawiki.mixins.rotation.less
curl -L "https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/core/+/master/resources/src/mediawiki.less/mediawiki.mixins.animation.less?format=TEXT" | base64 --decode > .storybook/resolve-less-imports/mediawiki.mixins.animation.less
curl -L "https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/core/+/master/resources/src/mediawiki.less/mediawiki.mixins.animation.less?format=TEXT" | base64 --decode > .storybook/resolve-less-imports/mediawiki.mixins.animation.less
curl "https://en.m.wikipedia.org/static/images/mobile/copyright/wikipedia-wordmark-en.svg" -o "docs/ui/assets/wordmark.svg"
curl "https://en.m.wikipedia.org/static/images/mobile/copyright/wikipedia.png" -o "docs/ui/assets/icon.png"
# FIXME: Update to en.wikipedia.org uris when available.
curl "https://di-logo-sandbox.firebaseapp.com/img/tagline/en-tagline-117-13.svg" -o "docs/ui/assets/tagline.svg"

View File

@ -144,6 +144,7 @@ class VectorTemplate extends BaseTemplate {
// It should be followed by the name of the hook in hyphenated lowercase.
//
// Conditionally used values must use null to indicate absence (not false or '').
$mainPageHref = Skin::makeMainPageUrl();
$commonSkinData = [
'html-headelement' => $this->get( 'headelement', '' ),
'html-sitenotice' => $this->get( 'sitenotice', null ),
@ -189,6 +190,13 @@ class VectorTemplate extends BaseTemplate {
],
'html-navigation-heading' => $this->getMsg( 'navigation-heading' ),
'data-search-box' => $this->buildSearchProps(),
// Header
'data-logos' => ResourceLoaderSkinModule::getAvailableLogos( $this->config ),
'msg-sitetitle' => $this->getMsg( 'sitetitle' )->text(),
'msg-sitesubtitle' => $this->getMsg( 'sitesubtitle' )->text(),
'main-page-href' => $mainPageHref,
'data-sidebar' => $this->buildSidebar(),
] + $this->getMenuProps();
@ -320,7 +328,7 @@ class VectorTemplate extends BaseTemplate {
}
return [
'has-logo' => true,
'has-logo' => $this->isLegacy,
'html-logo-attributes' => Xml::expandAttributes(
Linker::tooltipAndAccesskeyAttribs( 'p-logo' ) + [
'class' => 'mw-wiki-logo',

View File

@ -0,0 +1,28 @@
{{!
LogoDefinition logo
string main-page-href link to the main page
string msg-sitesubtitle the contents of the sitesubtitle message key
}}
{{#data-logos}}
<a href="{{main-page-href}}" class="mw-logo">
{{#icon}}
{{! alt is provided for valid HTML but given aria-hidden not needed. }}
<img class="mw-logo-icon" src="{{.}}" alt=""
aria-hidden="true" height="50" width="50">
{{/icon}}
<span class="mw-logo-container">
{{#wordmark}}
<img class="mw-logo-wordmark" alt="{{msg-sitetitle}}"
src="{{src}}" width="{{width}}" height="{{height}}">
{{/wordmark}}
{{^wordmark}}
<strong class="mw-logo-wordmark">{{msg-sitetitle}}</strong>
{{/wordmark}}
{{#tagline}}
<img class="mw-logo-tagline"
alt="{{msg-sitesubtitle}}"
src="{{src}}" width="{{width}}" height="{{height}}">
{{/tagline}}
</span>
</a>
{{/data-logos}}

View File

@ -22,6 +22,7 @@
string html-dataAfterContent
string html-navigation-heading heading for entire navigation that is usually hidden to screen
readers
LogoOptions data-logos
MenuDefinition data-personal-menu See PersonalMenu.mustache for documentation.
object data-namespace-tabs. See VectorTabs.mustache for documentation.
object data-variants. See VectorMenu.mustache for documentation.
@ -70,6 +71,7 @@
{{{html-dataAfterContent}}}
<header class="mw-header">
{{>Logo}}
</header>
<div id="mw-navigation">

View File

@ -10,7 +10,7 @@
"lint:styles": "stylelint \"**/*.{less,css}\"",
"lint:i18n": "banana-checker --requireLowerCase=0 i18n/",
"doc": "jsdoc -c jsdoc.json && npm run build-storybook",
"storybook": "bash ./dev-scripts/setup-storybook.sh && start-storybook -p 6006",
"storybook": "bash ./dev-scripts/setup-storybook.sh && start-storybook -p 6006 -s docs/ui/",
"build-storybook": "bash ./dev-scripts/setup-storybook.sh && build-storybook -o docs/ui",
"svgmin": "svgo --config=.svgo.yml -q -r -f resources/"
},

View File

@ -0,0 +1,39 @@
@import '../../variables.less';
@import 'mediawiki.mixins.less';
.mw-logo {
.flex-display();
// If icon is not configured, ensure that the logo still takes up available
// space allocated by layout.
height: 100%;
// Center vertically.
align-items: center;
}
.mw-logo-icon {
// For browsers which do not support flexbox we float left.
// This will be ignored in flexbox browsers.
float: left;
margin-right: 10px;
}
.mw-logo-container {
// For browsers which do not support flexbox we float left.
// This will be ignored in flexbox browsers.
// The two children `div`s will lay out in a row.
float: left;
}
// Note for 3rd parties where no wgLogos['wordmark'] is defined
// the site title is not clipped. We may need to revisit this later
// for projects with long site titles.
.mw-logo-wordmark {
font-size: 1.4em;
}
.mw-logo-tagline {
// For browsers which do not support flexbox.
display: block;
margin-top: 5px;
font-size: 0.7em;
}

View File

@ -5,6 +5,7 @@
@media screen {
@import 'common.less';
@import 'layout.less';
@import 'Logo.less';
@import 'PersonalMenu.less';
@import 'SearchBox.less';
@import 'VectorTabs.less';

View File

@ -6,41 +6,44 @@
// Modern layout variables
@height-tabs: 2.5em; // Keep in sync with .vectorTabs height
@margin-top-sidebar: 0.5em;
// Header sizes defined in the description of T246170 and comment T246170#5957100
@padding-horizontal-header: 24px;
@padding-top-header: 10px;
@padding-bottom-header: 5px;
@height-header--inner: 54px;
@height-logo-icon: 50px; // Logo sizes per specification in T245190.
@height-header: @height-header--inner +
@padding-top-header + @padding-bottom-header; // 54px + 10px + 5px = 69px;
@padding-left-sidebar: 0.5em;
@padding-horizontal-header: @margin-end-portal +
@padding-left-sidebar +
( @margin-start-nav-main-body / @font-size-nav-main-heading );
@padding-vertical-header: 0.125em;
@margin-top-header: 0.625em;
@margin-bottom-header: 0.3125em;
@height-logo-icon: 3.125em; // Logo sizes per specification in T245190.
@height-header: @height-logo-icon +
@margin-top-header + @margin-bottom-header +
2 * @padding-vertical-header;
@width-grid-column-one: 11em;
/* Space for header above content */
.mw-header-placeholder {
// Reserve space for the absolute positioned header and tabs.
height: @height-header; // Pixels.
padding-bottom: @height-tabs; // Different unit: em.
height: @height-header + @height-tabs;
}
/* Header layout */
.mw-header {
position: absolute;
z-index: @z-index-header;
top: 0;
left: 0;
right: 0;
height: @height-header--inner;
// Padding is outside the sizing box (content-box).
padding: @padding-top-header @padding-horizontal-header @padding-bottom-header;
// A height is set to account for projects where no icon is set.
height: @height-logo-icon;
margin: @margin-top-header 0 @margin-bottom-header;
padding: @padding-vertical-header @padding-horizontal-header;
// Vertical centering of header elements (IE>=11), requires flex.
// Non-flex fallback for IE<=9: float rule on the child elements.
.flex-display();
// https://caniuse.com/#search=align-items
align-items: center;
z-index: @z-index-header;
}
/* Main column */
@ -96,10 +99,18 @@
#mw-panel {
position: absolute;
z-index: @z-index-sidebar;
top: 0;
width: @width-grid-column-one;
top: @height-header;
left: 0;
width: @width-grid-column-one;
.box-sizing( border-box );
margin-top: @margin-top-sidebar;
padding-left: @padding-left-sidebar;
z-index: @z-index-sidebar;
}
#footer {
margin-left: @width-grid-column-one;
margin-top: 0;
}
#footer, /* FIXME: Remove 2 weeks after deployment. */

View File

@ -51,7 +51,7 @@
},
"skins.vector.styles": {
"class": "ResourceLoaderSkinModule",
"features": [ "elements", "content", "interface", "logo", "legacy" ],
"features": [ "elements", "content", "interface", "legacy" ],
"targets": [
"desktop",
"mobile"

View File

@ -0,0 +1,78 @@
import logoTemplate from '!!raw-loader!../includes/templates/Logo.mustache';
/**
* @type {LogoOptions}
*/
const wordmark = {
src: '/assets/wordmark.svg',
width: 116,
height: 18
};
/**
* @type {LogoOptions}
*/
const tagline = {
src: '/assets/tagline.svg',
width: 117,
height: 13
};
/**
* @type {string}
*/
const icon = '/assets/icon.png';
/**
* @type {LogoTemplateData}
*/
const wordmarkTaglineIcon = {
'data-logos': {
wordmark, tagline, icon
},
'msg-sitetitle': 'Wikipedia',
'msg-sitesubtitle': 'the free encyclopedia'
};
/**
* @type {LogoTemplateData}
*/
const wordmarkIcon = {
'data-logos': {
wordmark, icon
},
'msg-sitetitle': 'Wikipedia',
'msg-sitesubtitle': 'the free encyclopedia'
};
/**
* @type {LogoTemplateData}
*/
const wordmarkOnly = {
'data-logos': {
wordmark
},
'msg-sitetitle': 'Wikipedia',
'msg-sitesubtitle': 'the free encyclopedia'
};
/**
* @type {LogoTemplateData}
*/
const noLogo = {
'data-logos': {},
'msg-sitetitle': 'Wikipedia',
'msg-sitesubtitle': 'the free encyclopedia'
};
/**
* @type {Object.<string, LogoTemplateData>}
*/
const LOGO_TEMPLATE_DATA = {
wordmarkTaglineIcon,
wordmarkIcon,
wordmarkOnly,
noLogo
};
export { LOGO_TEMPLATE_DATA, logoTemplate };

27
stories/Logo.stories.js Normal file
View File

@ -0,0 +1,27 @@
import mustache from 'mustache';
import { logoTemplate, LOGO_TEMPLATE_DATA } from './Logo.stories.data';
import '../resources/skins.vector.styles/Logo.less';
export default {
title: 'Logo'
};
export const logo = () => mustache.render(
logoTemplate,
LOGO_TEMPLATE_DATA.wordmarkTaglineIcon
);
export const logoWordmarkIcon = () => mustache.render(
logoTemplate,
LOGO_TEMPLATE_DATA.wordmarkIcon
);
export const logoWordmark = () => mustache.render(
logoTemplate,
LOGO_TEMPLATE_DATA.wordmarkOnly
);
export const noLogo = () => mustache.render(
logoTemplate,
LOGO_TEMPLATE_DATA.noLogo
);

View File

@ -19,7 +19,7 @@ export const SIDEBAR_DATA = {
'html-logo-attributes': HTML_LOGO_ATTRIBUTES
},
withPortalsAndOptOut: {
'has-logo': true,
'has-logo': false,
'array-portals-first': PORTALS.navigation,
'data-emphasized-sidebar-action': {
href: '#',

32
stories/legacy.stories.js Normal file
View File

@ -0,0 +1,32 @@
import mustache from 'mustache';
import '../resources/skins.vector.styles/legacy.less';
import legacySkinTemplate from '!!raw-loader!../includes/templates/legacy.mustache';
import {
LEGACY_TEMPLATE_DATA,
NAVIGATION_TEMPLATE_DATA,
TEMPLATE_PARTIALS
} from './skin.stories.data';
export default {
title: 'Skin (legacy)'
};
export const vectorLegacyLoggedOut = () => mustache.render(
legacySkinTemplate,
Object.assign(
{},
LEGACY_TEMPLATE_DATA,
NAVIGATION_TEMPLATE_DATA.loggedOutWithVariants
),
TEMPLATE_PARTIALS
);
export const vectorLegacyLoggedIn = () => mustache.render(
legacySkinTemplate,
Object.assign(
{},
LEGACY_TEMPLATE_DATA,
NAVIGATION_TEMPLATE_DATA.loggedInWithMoreActions
),
TEMPLATE_PARTIALS
);

View File

@ -1,18 +1,15 @@
import mustache from 'mustache';
import { htmluserlangattributes } from './utils';
import skinTemplate from '!!raw-loader!../includes/templates/index.mustache';
import legacySkinTemplate from '!!raw-loader!../includes/templates/legacy.mustache';
import { placeholder } from './utils';
import '../resources/skins.vector.styles/index.less';
import { PERSONAL_MENU_TEMPLATE_DATA, personalMenuTemplate } from './PersonalMenu.stories.data';
import { pageActionsData, namespaceTabsData, vectorTabsTemplate } from './VectorTabs.stories.data';
import { vectorMenuTemplate, moreData, variantsData } from './VectorMenu.stories.data';
import { searchBoxData, searchBoxTemplate } from './SearchBox.stories.data';
import { SIDEBAR_DATA, SIDEBAR_TEMPLATE_PARTIALS, sidebarTemplate } from './Sidebar.stories.data';
import { FOOTER_TEMPLATE_DATA, footerTemplate } from './Footer.stories.data';
import { logoTemplate } from './Logo.stories.data';
const NAVIGATION_TEMPLATE_DATA = {
export const NAVIGATION_TEMPLATE_DATA = {
loggedInWithVariantsAndOptOut: {
'data-personal-menu': PERSONAL_MENU_TEMPLATE_DATA.loggedInWithEcho,
'data-namespace-tabs': namespaceTabsData,
@ -45,7 +42,8 @@ const NAVIGATION_TEMPLATE_DATA = {
}
};
const TEMPLATE_PARTIALS = Object.assign( {}, SIDEBAR_TEMPLATE_PARTIALS, {
export const TEMPLATE_PARTIALS = Object.assign( {}, SIDEBAR_TEMPLATE_PARTIALS, {
Logo: logoTemplate,
SearchBox: searchBoxTemplate,
Sidebar: sidebarTemplate,
VectorTabs: vectorTabsTemplate,
@ -54,10 +52,6 @@ const TEMPLATE_PARTIALS = Object.assign( {}, SIDEBAR_TEMPLATE_PARTIALS, {
Footer: footerTemplate
} );
export default {
title: 'Skin'
};
const HTML_INDICATORS = `<div class="mw-indicators mw-body-content">
<div id="mw-indicator-good-star" class="mw-indicator">
<a href="/wiki/Wikipedia:Good_articles"
@ -77,7 +71,7 @@ const HTML_INDICATORS = `<div class="mw-indicators mw-body-content">
</div>
`;
export const vectorLegacyLoggedOut = () => mustache.render( legacySkinTemplate, Object.assign( {
export const LEGACY_TEMPLATE_DATA = {
'html-title': 'Vector 2019',
'page-isarticle': true,
'msg-tagline': 'From Wikipedia, the free encyclopedia',
@ -99,27 +93,9 @@ export const vectorLegacyLoggedOut = () => mustache.render( legacySkinTemplate,
'html-dataAfterContent': placeholder( 'Extensions can add here e.g. Related Articles.', 100 ),
'html-indicators': HTML_INDICATORS,
'html-subtitle': placeholder( 'Extensions can configure subtitle', 20 )
}, NAVIGATION_TEMPLATE_DATA.loggedOutWithVariants ), TEMPLATE_PARTIALS );
};
export const vectorLegacyLoggedIn = () => mustache.render( legacySkinTemplate, Object.assign( {
'html-title': 'Vector 2019',
'page-isarticle': true,
'msg-tagline': 'From Wikipedia, the free encyclopedia',
'html-userlangattributes': htmluserlangattributes,
'msg-jumptonavigation': 'Jump to navigation',
'msg-jumptosearch': 'Jump to search',
// site specific
'data-footer': FOOTER_TEMPLATE_DATA,
'html-sitenotice': placeholder( 'a site notice or central notice banner may go here', 70 ),
// article dependent
'html-bodycontent': placeholder( 'Article content goes here' ),
'html-printfooter': `Retrieved from <a dir="ltr" href="#">https://en.wikipedia.org/w/index.php?title=this&oldid=blah</a>`,
'html-catlinks': placeholder( 'Category links component from mediawiki core', 50 )
}, NAVIGATION_TEMPLATE_DATA.loggedInWithMoreActions ), TEMPLATE_PARTIALS );
export const vectorLoggedIn = () => mustache.render( skinTemplate, Object.assign( {
export const MODERN_TEMPLATE_DATA = {
'html-title': 'Vector 2020',
'page-isarticle': true,
'msg-tagline': 'From Wikipedia, the free encyclopedia',
@ -135,4 +111,4 @@ export const vectorLoggedIn = () => mustache.render( skinTemplate, Object.assign
'html-bodycontent': placeholder( 'Article content goes here' ),
'html-printfooter': `Retrieved from <a dir="ltr" href="#">https://en.wikipedia.org/w/index.php?title=this&oldid=blah</a>`,
'html-catlinks': placeholder( 'Category links component from mediawiki core', 50 )
}, NAVIGATION_TEMPLATE_DATA.loggedInWithVariantsAndOptOut ), TEMPLATE_PARTIALS );
};

View File

@ -1,3 +1,27 @@
/**
* @typedef {Object} LogoOptions
* @prop {string} src of logo. Can be relative, absolute or data uri.
* @prop {string} [alt] text of logo.
* @prop {number} width of asset
* @prop {number} height of asset
*/
/**
* @typedef {Object} ResourceLoaderSkinModuleLogos
* @prop {string} [icon] e.g. Wikipedia globe
* @prop {LogoOptions} [wordmark] e.g. Legacy Vector logo
* @prop {LogoOptions} [tagline] e.g. Legacy Vector logo
*/
/**
* @typedef {Object} LogoTemplateData
* @prop {ResourceLoaderSkinModuleLogos} data-logos as configured,
* the return value of ResourceLoaderSkinModule::getAvailableLogos.
* @prop {string} msg-sitetitle alternate text for wordmark
href the url to navigate to on click.
* @prop {string} msg-sitesubtitle alternate text for tagline.
*/
/**
* @typedef {Object} MenuDefinition
* @prop {string} id