Merge "Add storybook to Vector"

This commit is contained in:
jenkins-bot 2020-01-31 15:01:44 +00:00 committed by Gerrit Code Review
commit 0c27e8deb8
24 changed files with 9403 additions and 105 deletions

4
.gitignore vendored
View File

@ -40,3 +40,7 @@ Thumbs.db
/.htaccess
/.htpasswd
.eslintcache
# storybook
/.storybook/resolve-less-imports/
/.storybook/integration.less

23
.storybook/common.less Normal file
View File

@ -0,0 +1,23 @@
@import '../variables.less';
@import 'integration.less';
@import 'icons.less';
body {
font-family: @font-family-sans;
}
a {
text-decoration: none;
}
ul {
padding: 0;
}
#mw-panel {
background-color: @background-color-secondary;
}
.printfooter {
display: none;
}

4
.storybook/config.js Normal file
View File

@ -0,0 +1,4 @@
import { configure } from '@storybook/html';
// automatically import all files ending in *.stories.js
configure(require.context('../stories', true, /\.stories\.js$/), module);

20
.storybook/icons.less Normal file
View File

@ -0,0 +1,20 @@
.mw-wiki-logo {
background-image: url(https://en.wikipedia.org/static/images/project-logos/enwiki-2x.png);
background-size: 135px auto;
}
.oo-ui-icon-bell {
opacity: 0.51;
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%3Ebell%3C/title%3E%3Cpath d=%22M16 7a5.38 5.38 0 0 0-4.46-4.85C11.6 1.46 11.53 0 10 0S8.4 1.46 8.46 2.15A5.38 5.38 0 0 0 4 7v6l-2 2v1h16v-1l-2-2zm-6 13a3 3 0 0 0 3-3H7a3 3 0 0 0 3 3z%22/%3E%3C/svg%3E");
}
.oo-ui-icon-tray {
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%3Etray%3C/title%3E%3Cpath d=%22M3 1a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm14 12h-4l-1 2H8l-1-2H3V3h14z%22/%3E%3C/svg%3E");
}
.uls-trigger {
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;
}

View File

@ -0,0 +1,54 @@
const path = require( 'path' );
module.exports = {
module: {
rules: [ {
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
// Beware of https://github.com/babel/babel-loader/issues/690. Changes to browsers require
// manual invalidation.
cacheDirectory: true
}
}
},
{
test: /\.css$/,
use: [ {
loader: 'style-loader'
}, {
loader: 'css-loader'
} ]
},
{
test: /\.(gif|png|jpe?g|svg)$/i,
issuer: /\.less$/,
loader: 'file-loader',
options: {
paths: [
path.resolve( __dirname, 'components/images' )
]
}
},
{
// in core some LESS imports don't specify filename
test: /\.less$/,
use: [ {
loader: 'style-loader'
}, {
loader: 'css-loader'
}, {
loader: 'less-loader',
options: {
relativeUrls: false,
paths: [
path.resolve( __dirname, 'resolve-less-imports' )
]
}
} ]
},
]
}
};

View File

@ -13,7 +13,7 @@ module.exports = function ( grunt ) {
},
all: [
'**/*.js{,on}',
'!{vendor,node_modules}/**'
'!{vendor,node_modules,docs}/**'
]
},
banana: conf.MessagesDirs,

11
dev-scripts/setup-storybook.sh Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
mkdir -p .storybook/resolve-less-imports/mediawiki.ui
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 "https://phabricator.wikimedia.org/source/mediawiki/browse/master/resources/src/mediawiki.less/mediawiki.mixins.less?view=raw" -o .storybook/resolve-less-imports/mediawiki.mixins.less -L
curl "https://phabricator.wikimedia.org/source/mediawiki/browse/master/resources/src/mediawiki.less/mediawiki.ui/variables.less?view=raw" -o .storybook/resolve-less-imports/mediawiki.ui/variables.less -L
curl "https://phabricator.wikimedia.org/source/mediawiki/browse/master/resources/src/mediawiki.less/mediawiki.mixins.rotation.less?view=raw" -o .storybook/resolve-less-imports/mediawiki.mixins.rotation.less -L
curl "https://phabricator.wikimedia.org/source/mediawiki/browse/master/resources/src/mediawiki.less/mediawiki.mixins.animation.less?view=raw" -o .storybook/resolve-less-imports/mediawiki.mixins.animation.less -L

View File

@ -4,7 +4,7 @@
string html-personal-menu content that appears as the first child of mw-head
string html-navigation-left-tabs that appears inside #left-navigation (namespaces and variants)
string html-navigation-right-tabs that appears inside #right-navigation (page actions and search)
string html-logo for site logo
string html-logo-attributes for site logo. Must be used inside tag e.g. `class="logo" lang="en-gb"`
string html-portals for portal(s) that appear in the main menu for Vector
}}
<div id="mw-navigation">

8889
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,23 @@
{
"private": true,
"scripts": {
"test": "grunt test",
"doc": "jsduck"
"storybook": "./dev-scripts/setup-storybook.sh && start-storybook -p 6006",
"test": "grunt test && npm run build-storybook",
"doc": "jsduck && npm run build-storybook",
"build-storybook": "./dev-scripts/setup-storybook.sh && build-storybook -o docs/"
},
"devDependencies": {
"@babel/core": "7.7.7",
"@storybook/html": "5.2.8",
"babel-loader": "8.0.6",
"eslint-config-wikimedia": "0.15.0",
"grunt": "1.0.4",
"grunt-banana-checker": "0.8.1",
"grunt-eslint": "22.0.0",
"grunt-stylelint": "0.13.0",
"less": "3.8.1",
"less-loader": "4.1.0",
"mustache": "3.0.1",
"stylelint-config-wikimedia": "0.8.0"
}
}

View File

@ -3,6 +3,7 @@
* prepended with @noflip in a comment block.
*
*/
@import '../../variables.less';
@import 'mediawiki.mixins.less';
/* Framework */

View File

@ -1,3 +1,5 @@
@import '../../variables.less';
/* Footer */
#footer {
margin-left: 10em;

View File

@ -1,3 +1,6 @@
@import '../../variables.less';
@import 'mediawiki.mixins.less';
/* Personal */
#p-personal {
position: absolute;

View File

@ -1,5 +1,6 @@
@import 'mediawiki.mixins.less';
@import 'mediawiki.ui/variables.less';
@import '../../variables.less';
/* Search */
#p-search {

11
stories/.eslintrc.json Normal file
View File

@ -0,0 +1,11 @@
{
"rules": {
"one-var": "off",
"single-quote": "off",
"quotes": "off"
},
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 6
}
}

83
stories/footer.stories.js Normal file
View File

@ -0,0 +1,83 @@
import mustache from 'mustache';
import footerTemplate from '!!raw-loader!../includes/templates/Footer.mustache';
import { htmluserlangattributes, placeholder } from './utils';
import '../resources/skins.vector.styles/footer.less';
import '../.storybook/common.less';
export default {
title: 'Footer'
};
const FOOTER_ROWS = [
{
id: 'footer-info',
'array-items': [
{
id: 'footer-info-lastmod',
html: 'This page was last modified on 10 January 2020, at 21:24.'
},
{
id: 'footer-info-copyright',
html: `This text is available under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike Licence</a>;
additional terms may apply. See <a href="https://foundation.wikimedia.org/wiki/Special:MyLanguage/Terms_of_Use">Terms of Use</a> for details.`
}
]
},
{
id: 'footer-places',
'array-items': [
{
id: 'footer-places-privacy',
html: `<a href="https://foundation.wikimedia.org/wiki/Privacy_policy" class="extiw" title="wmf:Privacy policy">Privacy policy</a>`
},
{
id: 'footer-places-about',
html: `<a href="/wiki/Wikipedia:About" title="Wikipedia:About">About Wikipedia</a>`
},
{
id: 'footer-places-disclaimer',
html: `<a href="/wiki/Wikipedia:General_disclaimer" title="Wikipedia:General disclaimer">Disclaimers</a>`
},
{
id: 'footer-places-contact',
html: `<a href="//en.wikipedia.org/wiki/Wikipedia:Contact_us">Contact Wikipedia</a>`
},
{
id: 'footer-places-developers',
html: `<a href="https://www.mediawiki.org/wiki/Special:MyLanguage/How_to_contribute">Developers</a>`
},
{
id: 'footer-places-statslink',
html: `<a href="https://stats.wikimedia.org/v2/#/en.wikipedia.org">Statistics</a>`
},
{
id: 'footer-places-cookiestatement',
html: `<a href="https://foundation.wikimedia.org/wiki/Cookie_statement">Cookie statement</a>`
},
{
id: 'footer-places-mobileview',
html: `<a href="//en.m.wikipedia.org/w/index.php?title=Paris&amp;useskin=vector&amp;mobileaction=toggle_view_mobile" class="noprint stopMobileRedirectToggle">Mobile view</a>`
}
]
},
{
id: 'footer-icons',
'array-items': [
{
id: 'footer-copyrightico',
html: `<a href="https://wikimediafoundation.org/"><img src="https://wikipedia.org/static/images/wikimedia-button.png" srcset="https://wikipedia.org/static/images/wikimedia-button-1.5x.png 1.5x, https://wikipedia.org/static/images/wikimedia-button-2x.png 2x" width="88" height="31" alt="Wikimedia Foundation"/></a>`
},
{
id: 'footer-poweredbyico',
html: `<a href="https://www.mediawiki.org/"><img src="https://wikipedia.org/static/images/poweredby_mediawiki_88x31.png" alt="Powered by MediaWiki" srcset="https://wikipedia.org/static/images/poweredby_mediawiki_132x47.png 1.5x, https://wikipedia.org/static/images/poweredby_mediawiki_176x62.png 2x" width="88" height="31"/></a>`
}
]
}
];
export const footer = () => mustache.render( footerTemplate, {
'html-userlangattributes': htmluserlangattributes,
'html-hook-vector-before-footer': placeholder( 'output of VectorBeforeFooter hook (deprecated 1.35)', 20 ),
'array-footer-rows': FOOTER_ROWS
} );

67
stories/menu.stories.js Normal file
View File

@ -0,0 +1,67 @@
import mustache from 'mustache';
import vectorMenu from '!!raw-loader!../includes/templates/VectorMenu.mustache';
import '../resources/skins.vector.styles/navigation.less';
import '../.storybook/common.less';
import { htmluserlangattributes } from './utils';
export default {
title: 'Menu'
};
export const more = () => mustache.render( vectorMenu, {
'empty-portlet': '',
'msg-label': 'More',
'menu-id': 'p-cactions',
'menu-label-id': 'p-cactions-label',
'html-userlangattributes': htmluserlangattributes,
'html-items': `<li id="ca-delete">
<a href="/w/index.php?title=Main_Page&amp;action=delete"
title="Delete this page [⌃⌥d]" accesskey="d">Delete</a>
</li>
<li id="ca-move">
<a href="/w/index.php/Special:MovePage/Main_Page"
title="Move this page [⌃⌥m]" accesskey="m">Move</a>
</li>
<li id="ca-protect">
<a href="/w/index.php?title=Main_Page&amp;action=protect"
title="Protect this page [⌃⌥=]" accesskey="=">Protect</a>
</li>`
} );
export const variants = () => mustache.render( vectorMenu, {
'msg-label': '新加坡简体',
'menu-id': 'p-variants',
'menu-label-id': 'p-variants-label',
'html-userlangattributes': htmluserlangattributes,
'html-items': `<li id="ca-varlang-0">
<a href="/zh/%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD"
hreflang="zh" lang="zh">不转换</a></li>
<li id="ca-varlang-1">
<a href="/zh-hans/%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD"
hreflang="zh-Hans" lang="zh-Hans">简体</a>
</li>
<li id="ca-varlang-2">
<a href="/zh-hant/%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD"
hreflang="zh-Hant" lang="zh-Hant">繁體</a>
</li>
<li id="ca-varlang-3">
<a href="/zh-cn/%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD"
hreflang="zh-Hans-CN" lang="zh-Hans-CN">大陆简体</a>
</li>
<li id="ca-varlang-4">
<a href="/zh-hk/%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD"
hreflang="zh-Hant-HK" lang="zh-Hant-HK">香港繁體</a>
</li>
<li id="ca-varlang-5">
<a href="/zh-mo/%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD"
hreflang="zh-Hant-MO" lang="zh-Hant-MO">澳門繁體</a>
</li>
<li id="ca-varlang-7" class="selected">
<a href="/zh-sg/%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD"
hreflang="zh-Hans-SG" lang="zh-Hans-SG">新加坡简体</a>
</li>
<li id="ca-varlang-8">
<a href="/zh-tw/%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD"
hreflang="zh-Hant-TW" lang="zh-Hant-TW">臺灣正體</a>
</li>`
} );

View File

@ -0,0 +1,49 @@
import mustache from 'mustache';
import navTemplate from '!!raw-loader!../includes/templates/Navigation.mustache';
import '../.storybook/common.less';
import '../resources/skins.vector.styles/navigation.less';
import { loggedOut, loggedInWithEcho } from './personalNavigation.stories';
import { viewTabs, namespaceTabs } from './tabs.stories';
import { more, variants } from './menu.stories';
import { simpleSearch } from './searchBox.stories';
import { navigationPortal, otherProjects, toolbox, langlinks } from './portal.stories';
import { placeholder } from './utils';
const HOOKINFO = 'Portals can be added, removed or reordered using SidebarBeforeOutput hook';
export default {
title: 'Navigation (Header + Main Menu)'
};
export const navigationLoggedOutWithVariants = () => mustache.render( navTemplate,
{
'html-personalmenu': loggedOut(),
'html-navigation-left-tabs': namespaceTabs() + variants(),
'html-navigation-right-tabs': `${viewTabs()} ${simpleSearch()}`,
'html-portals': `${navigationPortal().innerHTML}
${toolbox().innerHTML}
${otherProjects().innerHTML}
${langlinks().innerHTML}
${placeholder( HOOKINFO, 60 )}
`,
'html-navigation-heading': 'Navigation menu',
'html-logo-attributes': `class="mw-wiki-logo" href="/wiki/Main_Page" title="Visit the main page"`
}
);
export const navigationLoggedInWithMore = () => mustache.render( navTemplate,
{
'html-personalmenu': loggedInWithEcho(),
'html-navigation-left-tabs': namespaceTabs(),
'html-navigation-right-tabs': `${viewTabs()} ${more()} ${simpleSearch()}`,
'html-portals': `${navigationPortal().innerHTML}
${toolbox().innerHTML}
${otherProjects().innerHTML}
${langlinks().innerHTML}
${placeholder( HOOKINFO, 60 )}
`,
'html-navigation-heading': 'Navigation menu',
'html-logo-attributes': `class="mw-wiki-logo" href="/wiki/Main_Page" title="Visit the main page"`
}
);

View File

@ -0,0 +1,31 @@
import mustache from 'mustache';
import personalMenu from '!!raw-loader!../includes/templates/PersonalMenu.mustache';
import { htmluserlangattributes } from './utils';
import '../resources/skins.vector.styles/personalNavigation.less';
import '../.storybook/common.less';
export default {
title: 'Personal Navigation'
};
export const loggedOut = () => mustache.render( personalMenu, {
'msg-label': 'Personal tools',
'html-userlangattributes': htmluserlangattributes,
'html-loggedin': '<li id="pt-anonuserpage">Not logged in</li>',
'html-personal-tools': `<li id="pt-anontalk"><a href="/wiki/Special:MyTalk" title="Discussion about edits from this IP address [⌃⌥n]" accesskey="n">Talk</a></li><li id="pt-anoncontribs"><a href="/wiki/Special:MyContributions" title="A list of edits made from this IP address [⌃⌥y]" accesskey="y">Contributions</a></li><li id="pt-createaccount"><a href="/w/index.php?title=Special:CreateAccount&amp;returnto=Main+Page" title="You are encouraged to create an account and log in; however, it is not mandatory">Create account</a></li><li id="pt-login"><a href="/w/index.php?title=Special:UserLogin&amp;returnto=Main+Page" title="You're encouraged to log in; however, it's not mandatory. [⌃⌥o]" accesskey="o">Log in</a></li>`
} );
export const loggedInWithEcho = () => mustache.render( personalMenu, {
'msg-label': 'Personal tools',
'html-userlangattributes': htmluserlangattributes,
'html-loggedin': '',
'html-personal-tools': `<li id="pt-userpage"><a href="/wiki/User:Jdlrobson" dir="auto" title="Your user page [⌃⌥.]" accesskey=".">Jdlrobson</a></li><li id="pt-notifications-alert"><a href="/wiki/Special:Notifications" class="mw-echo-notifications-badge mw-echo-notification-badge-nojs oo-ui-icon-bell mw-echo-notifications-badge-all-read" data-counter-num="0" data-counter-text="0" title="Your alerts">Alerts (0)</a></li><li id="pt-notifications-notice"><a href="/wiki/Special:Notifications" class="mw-echo-notifications-badge mw-echo-notification-badge-nojs oo-ui-icon-tray" data-counter-num="3" data-counter-text="3" title="Your notices">Notices (3)</a></li><li id="pt-mytalk"><a href="/wiki/User_talk:Jdlrobson" title="Your talk page [⌃⌥n]" accesskey="n">Talk</a></li><li id="pt-sandbox"><a href="/wiki/User:Jdlrobson/sandbox" title="Your sandbox">Sandbox</a></li><li id="pt-preferences"><a href="/wiki/Special:Preferences" title="Your preferences">Preferences</a></li><li id="pt-betafeatures"><a href="/wiki/Special:Preferences#mw-prefsection-betafeatures" title="Beta features">Beta</a></li><li id="pt-watchlist"><a href="/wiki/Special:Watchlist" title="A list of pages you are monitoring for changes [⌃⌥l]" accesskey="l">Watchlist</a></li><li id="pt-mycontris"><a href="/wiki/Special:Contributions/Jdlrobson" title="A list of your contributions [⌃⌥y]" accesskey="y">Contributions</a></li><li id="pt-logout"><a href="/w/index.php?title=Special:UserLogout&amp;returnto=Main+Page&amp;returntoquery=useskin%3Dvector" title="Log out">Log out</a></li>`
} );
export const loggedInWithULS = () => mustache.render( personalMenu, {
'msg-label': 'Personal tools',
'html-userlangattributes': htmluserlangattributes,
'html-lang-selector': '<li class="uls-trigger active"><a href="#">English</a></li>',
'html-loggedin': '',
'html-personal-tools': `<li id="pt-userpage"><a href="/wiki/User:Jdlrobson" dir="auto" title="Your user page [⌃⌥.]" accesskey=".">Jdlrobson</a></li><li id="pt-notifications-alert"><a href="/wiki/Special:Notifications" class="mw-echo-notifications-badge mw-echo-notification-badge-nojs oo-ui-icon-bell mw-echo-notifications-badge-all-read" data-counter-num="0" data-counter-text="0" title="Your alerts">Alerts (0)</a></li><li id="pt-notifications-notice"><a href="/wiki/Special:Notifications" class="mw-echo-notifications-badge mw-echo-notification-badge-nojs oo-ui-icon-tray" data-counter-num="3" data-counter-text="3" title="Your notices">Notices (3)</a></li><li id="pt-mytalk"><a href="/wiki/User_talk:Jdlrobson" title="Your talk page [⌃⌥n]" accesskey="n">Talk</a></li><li id="pt-sandbox"><a href="/wiki/User:Jdlrobson/sandbox" title="Your sandbox">Sandbox</a></li><li id="pt-preferences"><a href="/wiki/Special:Preferences" title="Your preferences">Preferences</a></li><li id="pt-betafeatures"><a href="/wiki/Special:Preferences#mw-prefsection-betafeatures" title="Beta features">Beta</a></li><li id="pt-watchlist"><a href="/wiki/Special:Watchlist" title="A list of pages you are monitoring for changes [⌃⌥l]" accesskey="l">Watchlist</a></li><li id="pt-mycontris"><a href="/wiki/Special:Contributions/Jdlrobson" title="A list of your contributions [⌃⌥y]" accesskey="y">Contributions</a></li><li id="pt-logout"><a href="/w/index.php?title=Special:UserLogout&amp;returnto=Main+Page&amp;returntoquery=useskin%3Dvector" title="Log out">Log out</a></li>`
} );

98
stories/portal.stories.js Normal file
View File

@ -0,0 +1,98 @@
import mustache from 'mustache';
import portalTemplate from '!!raw-loader!../includes/templates/Portal.mustache';
import '../resources/skins.vector.styles/navigation.less';
import '../.storybook/common.less';
import { placeholder, htmluserlangattributes } from './utils';
export default {
title: 'Portals'
};
const wrapPortlet = ( data ) => {
const node = document.createElement( 'div' );
node.setAttribute( 'id', 'mw-panel' );
node.innerHTML = mustache.render( portalTemplate, data );
return node;
};
const portletAfter = ( html ) => {
return `<div class="after-portlet after-portlet-tb">${html}</div>`;
};
export const portal = () => wrapPortlet(
{
'portal-id': 'p-example',
'html-tooltip': 'Message tooltip-p-example acts as tooltip',
'msg-label': 'Portal title',
'msg-label-id': 'p-example-label',
'html-userlangattributes': htmluserlangattributes,
'html-portal-content': `<ul>
<li><a href='#'>A list of links</a></li>
<li><a href='#'>with ids</a></li>
<li><a href='#'>on each list item</a></li>
</ul>`,
'html-after-portal': portletAfter(
placeholder( `<p>Beware: The <a href="https://codesearch.wmflabs.org/search/?q=BaseTemplateAfterPortlet&i=nope&files=&repos=">BaseTemplateAfterPortlet hook</a> can be used to inject arbitary HTML here for any portlet.</p>`, 60 )
)
}
);
export const navigationPortal = () => wrapPortlet(
{
'portal-id': 'p-navigation',
'msg-label': 'Navigation',
'msg-label-id': 'p-navigation-label',
'html-userlangattributes': htmluserlangattributes,
'html-portal-content': `<ul>
<li id="n-mainpage-description"><a href="/wiki/Main_Page" title="Visit the main page [⌃⌥z]" accesskey="z">Main page</a></li><li id="n-contents"><a href="/wiki/Wikipedia:Contents" title="Guides to browsing Wikipedia">Contents</a></li><li id="n-featuredcontent"><a href="/wiki/Wikipedia:Featured_content" title="Featured content the best of Wikipedia">Featured content</a></li><li id="n-currentevents"><a href="/wiki/Portal:Current_events" title="Find background information on current events">Current events</a></li><li id="n-randompage"><a href="/wiki/Special:Random" title="Load a random page [x]" accesskey="x">Random page</a></li><li id="n-sitesupport"><a href="https://donate.wikimedia.org/wiki/Special:FundraiserRedirector?utm_source=donate&amp;utm_medium=sidebar&amp;utm_campaign=C13_en.wikipedia.org&amp;uselang=en" title="Support us">Donate</a></li><li id="n-shoplink"><a href="//shop.wikimedia.org" title="Visit the Wikipedia store">Wikipedia store</a></li>
</ul>`,
'html-after-portal': portletAfter( placeholder( 'Possible hook output (navigation)', 50 ) )
}
);
export const toolbox = () => wrapPortlet(
{
'portal-id': 'p-tb',
'html-tooltip': 'A message tooltip-p-tb must exist for this to appear',
'msg-label': 'Tools',
'msg-label-id': 'p-tb-label',
'html-userlangattributes': htmluserlangattributes,
'html-portal-content': `<ul>
<li id="t-whatlinkshere"><a href="/wiki/Special:WhatLinksHere/Spain" title="A list of all wiki pages that link here [⌃⌥j]" accesskey="j">What links here</a></li><li id="t-recentchangeslinked"><a href="/wiki/Special:RecentChangesLinked/Spain" rel="nofollow" title="Recent changes in pages linked from this page [k]" accesskey="k">Related changes</a></li><li id="t-upload"><a href="/wiki/Wikipedia:File_Upload_Wizard" title="Upload files [u]" accesskey="u">Upload file</a></li><li id="t-specialpages"><a href="/wiki/Special:SpecialPages" title="A list of all special pages [q]" accesskey="q">Special pages</a></li><li id="t-permalink"><a href="/w/index.php?title=Spain&amp;oldid=935087243" title="Permanent link to this revision of the page">Permanent link</a></li><li id="t-info"><a href="/w/index.php?title=Spain&amp;action=info" title="More information about this page">Page information</a></li><li id="t-wikibase"><a href="https://www.wikidata.org/wiki/Special:EntityPage/Q29" title="Link to connected data repository item [g]" accesskey="g">Wikidata item</a></li><li id="t-cite"><a href="/w/index.php?title=Special:CiteThisPage&amp;page=Spain&amp;id=935087243" title="Information on how to cite this page">Cite this page</a></li>
</ul>`,
'html-after-portal': portletAfter( placeholder( 'Possible hook output (tb)', 50 ) )
}
);
export const langlinks = () => wrapPortlet(
{
'portal-id': 'p-lang',
'html-tooltip': 'A message tooltip-p-lang must exist for this to appear',
'msg-label': 'In other languages',
'msg-label-id': 'p-lang-label',
'html-userlangattributes': htmluserlangattributes,
'html-portal-content': `<ul>
<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><li class="interlanguage-link interwiki-an">
</ul>`,
'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 )}`
)
}
);
export const otherProjects = () => wrapPortlet(
{
'portal-id': 'p-wikibase-otherprojects',
'html-tooltip': 'A message tooltip-p-lang must exist for this to appear',
'msg-label': 'In other projects',
'msg-label-id': 'p-wikibase-otherprojects-label',
'html-userlangattributes': htmluserlangattributes,
'html-portal-content': `<ul>
<li class="wb-otherproject-link wb-otherproject-commons"><a href="https://commons.wikimedia.org/wiki/Category:Spain" hreflang="en">Wikimedia Commons</a></li><li class="wb-otherproject-link wb-otherproject-wikinews"><a href="https://en.wikinews.org/wiki/Category:Spain" hreflang="en">Wikinews</a></li><li class="wb-otherproject-link wb-otherproject-wikiquote"><a href="https://en.wikiquote.org/wiki/Spain" hreflang="en">Wikiquote</a></li><li class="wb-otherproject-link wb-otherproject-wikivoyage"><a href="https://en.wikivoyage.org/wiki/Spain" hreflang="en">Wikivoyage</a></li></ul>`,
'html-after-portal': ''
}
);

View File

@ -0,0 +1,19 @@
import mustache from 'mustache';
import searchBox from '!!raw-loader!../includes/templates/SearchBox.mustache';
import '../resources/skins.vector.styles/search.less';
import '../.storybook/common.less';
export default {
title: 'Search'
};
export const simpleSearch = () => mustache.render( searchBox, {
searchActionURL: '/w/index.php',
searchHeaderAttrsHTML: 'dir="ltr" lang="en-GB"',
searchInputLabel: 'Search',
searchDivID: 'simpleSearch',
searchInputHTML: '<input type="search" name="search" placeholder="Search Wikipedia" title="Search Wikipedia [⌃⌥f]" accesskey="f" id="searchInput" autocomplete="off">',
titleHTML: '<input type="hidden" value="Special:Search" name="title">',
fallbackSearchButtonHTML: '<input type="submit" name="fulltext" value="Search" title="Search pages for this text" id="mw-searchButton" class="searchButton mw-fallbackSearchButton"/>',
searchButtonHTML: '<input type="submit" name="go" value="Go" title="Go to a page with this exact name if it exists" id="searchButton" class="searchButton">'
} );

75
stories/skin.stories.js Normal file
View File

@ -0,0 +1,75 @@
import mustache from 'mustache';
import { htmluserlangattributes } from './utils';
import skinTemplate from '!!raw-loader!../includes/templates/index.mustache';
import { placeholder } from './utils';
import '../resources/skins.vector.styles/screen.less';
import { navigationLoggedOutWithVariants, navigationLoggedInWithMore } from './navigation.stories';
import { footer } from './footer.stories';
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"
title="This is a good article. Follow the link for more information.">
<img alt="This is a good article. Follow the link for more information."
src="//upload.wikimedia.org/wikipedia/en/thumb/9/94/Symbol_support_vote.svg/19px-Symbol_support_vote.svg.png" decoding="async" width="19" height="20"
srcset="//upload.wikimedia.org/wikipedia/en/thumb/9/94/Symbol_support_vote.svg/29px-Symbol_support_vote.svg.png 1.5x, //upload.wikimedia.org/wikipedia/en/thumb/9/94/Symbol_support_vote.svg/39px-Symbol_support_vote.svg.png 2x" data-file-width="180" data-file-height="185" />
</a>
</div>
<div id="mw-indicator-pp-autoreview" class="mw-indicator">
<a href="/wiki/Wikipedia:Protection_policy#pending"
title="All edits by unregistered and new users are subject to review prior to becoming visible to unregistered users">
<img alt="Page protected with pending changes" src="//upload.wikimedia.org/wikipedia/en/thumb/b/b7/Pending-protection-shackle.svg/20px-Pending-protection-shackle.svg.png"
decoding="async" width="20" height="20" srcset="//upload.wikimedia.org/wikipedia/en/thumb/b/b7/Pending-protection-shackle.svg/30px-Pending-protection-shackle.svg.png 1.5x, //upload.wikimedia.org/wikipedia/en/thumb/b/b7/Pending-protection-shackle.svg/40px-Pending-protection-shackle.svg.png 2x" data-file-width="512" data-file-height="512" />
</a>
</div>
</div>
`;
export const vector2019LoggedOut = () => mustache.render( skinTemplate, {
'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',
'html-navigation': navigationLoggedOutWithVariants(),
// site specific
'html-footer': footer(),
'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 ),
// extension dependent..
'html-hook-vector-before-footer': placeholder( 'VectorBeforeFooter hook output', 100 ),
'html-dataAfterContent': placeholder( 'Extensions can add here e.g. Related Articles.', 100 ),
'html-indicators': HTML_INDICATORS,
'html-subtitle': placeholder( 'Extensions can configure subtitle', 20 )
} );
export const vector2019LoggedIn = () => mustache.render( skinTemplate, {
'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',
'html-navigation': navigationLoggedInWithMore(),
// site specific
'html-footer': footer(),
'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 )
} );

38
stories/tabs.stories.js Normal file
View File

@ -0,0 +1,38 @@
import mustache from 'mustache';
import { htmluserlangattributes } from './utils';
import vectorTabsTemplate from '!!raw-loader!../includes/templates/VectorTabs.mustache';
import '../resources/skins.vector.styles/tabs.less';
import '../.storybook/common.less';
export default {
title: 'Tabs'
};
export const viewTabs = () => mustache.render( vectorTabsTemplate, {
'tabs-id': 'p-views',
'empty-portlet': '',
'label-id': 'p-views-label',
'msg-label': 'Views',
'html-userlangattributes': htmluserlangattributes,
'html-items': `<li id="ca-view" class="collapsible selected">
<a href="/wiki/Main_Page">Read</a>
</li>
<li id="ca-viewsource" class="collapsible">
<a href="/w/index.php?title=Main_Page&amp;action=edit" title="This page is protected.
You can view its source [e]" accesskey="e">View source</a></li>
<li id="ca-history" class="collapsible">
<a href="/w/index.php?title=Main_Page&amp;action=history" title="Past revisions of this page [⌃⌥h]" accesskey="h">View history</a>
</li>
<li id="ca-unwatch" class="collapsible icon mw-watchlink"><a href="/w/index.php?title=Main_Page&amp;action=unwatch" data-mw="interface" title="Remove this page from your watchlist [⌃⌥w]" accesskey="w">Unwatch</a></li>
`
} );
export const namespaceTabs = () => mustache.render( vectorTabsTemplate, {
'tabs-id': 'p-namespaces',
'empty-portlet': '',
'label-id': 'p-namespaces-label',
'msg-label': 'Namespaces',
'html-userlangattributes': htmluserlangattributes,
'html-items': `<li id="ca-nstab-main" class="selected"><a href="/wiki/Main_Page" title="View the content page [⌃⌥c]" accesskey="c">Main page</a></li>
<li id="ca-talk"><a href="/wiki/Talk:Main_Page" rel="discussion" title="Discussion about the content page [⌃⌥t]" accesskey="t">Talk (3)</a></li>`
} );

9
stories/utils.js Normal file
View File

@ -0,0 +1,9 @@
const placeholder = ( msg, height ) => {
return `<div style="width: 100%; height: ${height || 200}px; margin-bottom: 2px;
font-size: 12px; padding: 8px; box-sizing: border-box;
display: flex; background: #eee; align-items: center;justify-content: center;">${msg}</div>`;
};
const htmluserlangattributes = `dir="ltr" lang="en-GB"`;
export { placeholder, htmluserlangattributes };