From 6a9ee465bcb379c0b6b49d4e65e15a79d480195f Mon Sep 17 00:00:00 2001 From: jdlrobson Date: Mon, 9 Mar 2020 06:51:00 +0100 Subject: [PATCH] [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 --- dev-scripts/setup-storybook.sh | 7 +- includes/VectorTemplate.php | 10 ++- includes/templates/Logo.mustache | 28 +++++++ includes/templates/index.mustache | 2 + package.json | 2 +- resources/skins.vector.styles/Logo.less | 39 ++++++++++ resources/skins.vector.styles/index.less | 1 + resources/skins.vector.styles/layout.less | 47 ++++++----- skin.json | 2 +- stories/Logo.stories.data.js | 78 +++++++++++++++++++ stories/Logo.stories.js | 27 +++++++ stories/Sidebar.stories.data.js | 2 +- stories/legacy.stories.js | 32 ++++++++ .../{skin.stories.js => skin.stories.data.js} | 40 ++-------- stories/types.js | 24 ++++++ 15 files changed, 286 insertions(+), 55 deletions(-) create mode 100644 includes/templates/Logo.mustache create mode 100644 resources/skins.vector.styles/Logo.less create mode 100644 stories/Logo.stories.data.js create mode 100644 stories/Logo.stories.js create mode 100644 stories/legacy.stories.js rename stories/{skin.stories.js => skin.stories.data.js} (77%) diff --git a/dev-scripts/setup-storybook.sh b/dev-scripts/setup-storybook.sh index 79979bd..542301b 100755 --- a/dev-scripts/setup-storybook.sh +++ b/dev-scripts/setup-storybook.sh @@ -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 \ No newline at end of file +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" diff --git a/includes/VectorTemplate.php b/includes/VectorTemplate.php index f7ac9ff..f956f2c 100644 --- a/includes/VectorTemplate.php +++ b/includes/VectorTemplate.php @@ -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', diff --git a/includes/templates/Logo.mustache b/includes/templates/Logo.mustache new file mode 100644 index 0000000..c7dc224 --- /dev/null +++ b/includes/templates/Logo.mustache @@ -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}} + +{{/data-logos}} diff --git a/includes/templates/index.mustache b/includes/templates/index.mustache index 5b14941..86c2e0a 100644 --- a/includes/templates/index.mustache +++ b/includes/templates/index.mustache @@ -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}}}
+{{>Logo}}
diff --git a/package.json b/package.json index afb45c7..1b4ea16 100644 --- a/package.json +++ b/package.json @@ -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/" }, diff --git a/resources/skins.vector.styles/Logo.less b/resources/skins.vector.styles/Logo.less new file mode 100644 index 0000000..cf2cb90 --- /dev/null +++ b/resources/skins.vector.styles/Logo.less @@ -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; +} diff --git a/resources/skins.vector.styles/index.less b/resources/skins.vector.styles/index.less index 8698e50..61fb8fa 100644 --- a/resources/skins.vector.styles/index.less +++ b/resources/skins.vector.styles/index.less @@ -5,6 +5,7 @@ @media screen { @import 'common.less'; @import 'layout.less'; + @import 'Logo.less'; @import 'PersonalMenu.less'; @import 'SearchBox.less'; @import 'VectorTabs.less'; diff --git a/resources/skins.vector.styles/layout.less b/resources/skins.vector.styles/layout.less index 109f2f5..bf90def 100644 --- a/resources/skins.vector.styles/layout.less +++ b/resources/skins.vector.styles/layout.less @@ -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. */ diff --git a/skin.json b/skin.json index c4a6710..243a501 100644 --- a/skin.json +++ b/skin.json @@ -51,7 +51,7 @@ }, "skins.vector.styles": { "class": "ResourceLoaderSkinModule", - "features": [ "elements", "content", "interface", "logo", "legacy" ], + "features": [ "elements", "content", "interface", "legacy" ], "targets": [ "desktop", "mobile" diff --git a/stories/Logo.stories.data.js b/stories/Logo.stories.data.js new file mode 100644 index 0000000..9472403 --- /dev/null +++ b/stories/Logo.stories.data.js @@ -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.} + */ +const LOGO_TEMPLATE_DATA = { + wordmarkTaglineIcon, + wordmarkIcon, + wordmarkOnly, + noLogo +}; + +export { LOGO_TEMPLATE_DATA, logoTemplate }; diff --git a/stories/Logo.stories.js b/stories/Logo.stories.js new file mode 100644 index 0000000..836df0d --- /dev/null +++ b/stories/Logo.stories.js @@ -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 +); diff --git a/stories/Sidebar.stories.data.js b/stories/Sidebar.stories.data.js index 4cbcb1a..0dda530 100644 --- a/stories/Sidebar.stories.data.js +++ b/stories/Sidebar.stories.data.js @@ -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: '#', diff --git a/stories/legacy.stories.js b/stories/legacy.stories.js new file mode 100644 index 0000000..9b4d41f --- /dev/null +++ b/stories/legacy.stories.js @@ -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 +); diff --git a/stories/skin.stories.js b/stories/skin.stories.data.js similarity index 77% rename from stories/skin.stories.js rename to stories/skin.stories.data.js index 3043df6..f0ebff5 100644 --- a/stories/skin.stories.js +++ b/stories/skin.stories.data.js @@ -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 = `
`; -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 ‘https://en.wikipedia.org/w/index.php?title=this&oldid=blah’`, - '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 ‘https://en.wikipedia.org/w/index.php?title=this&oldid=blah’`, 'html-catlinks': placeholder( 'Category links component from mediawiki core', 50 ) -}, NAVIGATION_TEMPLATE_DATA.loggedInWithVariantsAndOptOut ), TEMPLATE_PARTIALS ); +}; diff --git a/stories/types.js b/stories/types.js index c6edf37..9f1dd67 100644 --- a/stories/types.js +++ b/stories/types.js @@ -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