mirror of
https://gerrit.wikimedia.org/r/mediawiki/skins/Vector.git
synced 2024-09-23 10:21:40 +00:00
Merge "Build the sticky header skeleton"
This commit is contained in:
commit
94d135ecfa
|
@ -5,7 +5,7 @@
|
|||
},
|
||||
{
|
||||
"resourceModule": "skins.vector.styles",
|
||||
"maxSize": "9.62 kB"
|
||||
"maxSize": "9.7 kB"
|
||||
},
|
||||
{
|
||||
"resourceModule": "skins.vector.legacy.js",
|
||||
|
|
|
@ -381,14 +381,6 @@ class Hooks {
|
|||
$bodyAttrs['class'] .= ' skin-vector-search-vue';
|
||||
}
|
||||
|
||||
if (
|
||||
VectorServices::getFeatureManager()->isFeatureEnabled(
|
||||
Constants::FEATURE_STICKY_HEADER
|
||||
)
|
||||
) {
|
||||
$bodyAttrs['class'] .= ' skin-vector-sticky-header';
|
||||
}
|
||||
|
||||
$config = $sk->getConfig();
|
||||
// Should we disable the max-width styling?
|
||||
if ( !self::isSkinVersionLegacy() && $sk->getTitle() && self::shouldDisableMaxWidth(
|
||||
|
|
|
@ -44,6 +44,10 @@ class SkinVector extends SkinMustache {
|
|||
/** @var int */
|
||||
private const MENU_TYPE_DROPDOWN = 2;
|
||||
private const MENU_TYPE_PORTAL = 3;
|
||||
private const NO_ICON = [
|
||||
'icon' => 'none',
|
||||
'class' => 'sticky-header-icon'
|
||||
];
|
||||
|
||||
/**
|
||||
* T243281: Code used to track clicks to opt-out link.
|
||||
|
@ -296,6 +300,24 @@ class SkinVector extends SkinMustache {
|
|||
Hooks::onSkinTemplateNavigation( $skin, $content_navigation );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate data needed to generate the sticky header.
|
||||
* Lack of i18n is intentional and will be done as part of follow up work.
|
||||
* @return array
|
||||
*/
|
||||
private function getStickyHeaderData() {
|
||||
return [
|
||||
'title' => 'Audre Lorde',
|
||||
'heading' => 'Introduction',
|
||||
'primary-action' => 'Primary action',
|
||||
'data-icon-start' => self::NO_ICON,
|
||||
'data-icon-end' => self::NO_ICON,
|
||||
'data-icons' => [
|
||||
self::NO_ICON, self::NO_ICON, self::NO_ICON, self::NO_ICON
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
@ -338,7 +360,9 @@ class SkinVector extends SkinMustache {
|
|||
|
||||
'sidebar-visible' => $this->isSidebarVisible(),
|
||||
|
||||
'is-language-in-header' => $this->isLanguagesInHeader(),
|
||||
'data-vector-sticky-header' => VectorServices::getFeatureManager()->isFeatureEnabled(
|
||||
Constants::FEATURE_STICKY_HEADER
|
||||
) ? $this->getStickyHeaderData() : false,
|
||||
] );
|
||||
|
||||
if ( $skin->getUser()->isRegistered() ) {
|
||||
|
|
1
includes/templates/Icon.mustache
Normal file
1
includes/templates/Icon.mustache
Normal file
|
@ -0,0 +1 @@
|
|||
<div class="mw-ui-icon mw-ui-icon-element mw-ui-icon-{{icon}} {{class}}"></div>
|
29
includes/templates/StickyHeader.mustache
Normal file
29
includes/templates/StickyHeader.mustache
Normal file
|
@ -0,0 +1,29 @@
|
|||
<header id="vector-sticky-header"
|
||||
class="vector-sticky-header {{#is-visible}}vector-sticky-header-visible{{/is-visible}}">
|
||||
<div class="vector-sticky-header-start">
|
||||
<div class="vector-sticky-header-icon-start">
|
||||
{{#data-icon-start}}
|
||||
{{>Icon}}
|
||||
{{/data-icon-start}}
|
||||
</div>
|
||||
<div class="vector-sticky-header-context-bar">
|
||||
<div class="vector-sticky-header-context-bar-primary">{{title}}</div>
|
||||
<div class="vector-sticky-header-context-bar-secondary">{{heading}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vector-sticky-header-end">
|
||||
<div class="vector-sticky-header-icons">
|
||||
{{#data-icons}}
|
||||
{{>Icon}}
|
||||
{{/data-icons}}
|
||||
</div>
|
||||
<div class="mw-ui-button">
|
||||
{{primary-action}}
|
||||
</div>
|
||||
<div class="vector-sticky-header-icon-end">
|
||||
{{#data-icon-end}}
|
||||
{{>Icon}}
|
||||
{{/data-icon-end}}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
|
@ -42,7 +42,6 @@
|
|||
{{#sidebar-visible}}checked{{/sidebar-visible}}>
|
||||
|
||||
{{>Header}}
|
||||
|
||||
<div class="mw-workspace-container">
|
||||
{{>Navigation}}
|
||||
<div class="mw-content-container">
|
||||
|
@ -98,3 +97,6 @@
|
|||
</div>
|
||||
</div> {{! END mw-page-container-inner }}
|
||||
</div> {{! END mw-page-container }}
|
||||
{{#data-vector-sticky-header}}
|
||||
{{>StickyHeader}}
|
||||
{{/data-vector-sticky-header}}
|
||||
|
|
|
@ -152,3 +152,9 @@
|
|||
|
||||
// Transitions
|
||||
@transition-duration-base: 100ms;
|
||||
|
||||
//
|
||||
// Layout
|
||||
//
|
||||
@max-width-page-container: unit( 1650px / @font-size-browser, em ); // 103.125em @ 16
|
||||
@padding-horizontal-page-container: unit( 30px / @font-size-browser, em ); // 1.875em @ 16
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
var collapsibleTabs = require( '../skins.vector.legacy.js/collapsibleTabs.js' ),
|
||||
vector = require( '../skins.vector.legacy.js/vector.js' ),
|
||||
stickyHeader = require( './stickyHeader.js' ),
|
||||
languageButton = require( './languageButton.js' ),
|
||||
initSearchLoader = require( './searchLoader.js' ).initSearchLoader,
|
||||
dropdownMenus = require( './dropdownMenus.js' ),
|
||||
|
@ -72,6 +73,7 @@ function main( window ) {
|
|||
initSearchLoader( document );
|
||||
searchToggle();
|
||||
languageButton();
|
||||
stickyHeader();
|
||||
}
|
||||
|
||||
main( window );
|
||||
|
|
8
resources/skins.vector.js/stickyHeader.js
Normal file
8
resources/skins.vector.js/stickyHeader.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
module.exports = function () {
|
||||
var header = document.getElementById( 'vector-sticky-header' );
|
||||
if ( !header ) {
|
||||
return;
|
||||
}
|
||||
// TODO: Use IntersectionObserver
|
||||
header.classList.add( 'vector-sticky-header-visible' );
|
||||
};
|
73
resources/skins.vector.styles/components/StickyHeader.less
Normal file
73
resources/skins.vector.styles/components/StickyHeader.less
Normal file
|
@ -0,0 +1,73 @@
|
|||
@import '../../common/variables.less';
|
||||
@import 'mediawiki.mixins.less';
|
||||
|
||||
.vector-sticky-header {
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: @z-index-header;
|
||||
transform: translateY( -100% );
|
||||
transition: transform 250ms linear;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: @max-width-page-container + @padding-horizontal-page-container + @padding-horizontal-page-container;
|
||||
margin: 0 auto;
|
||||
background: @background-color-base;
|
||||
background-color: #fffffff7;
|
||||
border-bottom: 1px solid @colorGray14;
|
||||
// FIXME: Should this adapt to different thresholds? Ask Alex!
|
||||
padding: 6px 8px 6px 10px;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
|
||||
@media ( min-width: @width-breakpoint-desktop ) {
|
||||
padding: 6px 25px;
|
||||
}
|
||||
|
||||
&-visible {
|
||||
transform: translateY( 0% );
|
||||
}
|
||||
|
||||
//
|
||||
// Layout
|
||||
//
|
||||
&-start {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&-end {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
//
|
||||
// Components
|
||||
//
|
||||
&-icons,
|
||||
&-context-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
margin: 0 15px;
|
||||
padding-left: 30px;
|
||||
}
|
||||
|
||||
&-context-bar {
|
||||
border-left: 1px solid #c8c8c8;
|
||||
}
|
||||
|
||||
&-context-bar-primary {
|
||||
padding-right: 15px;
|
||||
font-size: unit( 22 / @font-size-browser, em );
|
||||
}
|
||||
|
||||
&-context-bar-secondary {
|
||||
&:before {
|
||||
padding-right: 15px;
|
||||
content: '|';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -65,9 +65,7 @@
|
|||
|
||||
// Page container
|
||||
|
||||
@max-width-page-container: unit( 1650px / @font-size-browser, em ); // 103.125em @ 16
|
||||
@min-width-page-container--padded: @max-width-page-container + ( 2 * @padding-horizontal-page-container ); // 106.875em
|
||||
@padding-horizontal-page-container: unit( 30px / @font-size-browser, em ); // 1.875em @ 16
|
||||
|
||||
// Content containers
|
||||
|
||||
|
@ -147,12 +145,6 @@ body {
|
|||
// allow z-index to apply so search results overlay article
|
||||
position: relative;
|
||||
z-index: @z-index-header;
|
||||
|
||||
.skin-vector-sticky-header & {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: @background-color-base;
|
||||
}
|
||||
}
|
||||
|
||||
/* Searchbox */
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
@import './components/Sidebar.less';
|
||||
@import './components/LanguageButton.less';
|
||||
@import './components/UserLinks.less';
|
||||
@import './components/StickyHeader.less';
|
||||
}
|
||||
|
||||
@media all {
|
||||
|
|
|
@ -192,6 +192,7 @@
|
|||
"name": "resources/skins.vector.js/config.json",
|
||||
"callback": "Vector\\Hooks::getVectorResourceLoaderConfig"
|
||||
},
|
||||
"resources/skins.vector.js/stickyHeader.js",
|
||||
"resources/skins.vector.js/dropdownMenus.js",
|
||||
"resources/skins.vector.js/sidebar.js",
|
||||
"resources/skins.vector.legacy.js/collapsibleTabs.js",
|
||||
|
|
25
stories/StickyHeader.stories.data.js
Normal file
25
stories/StickyHeader.stories.data.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
import template from '!!raw-loader!../includes/templates/StickyHeader.mustache';
|
||||
import Icon from '!!raw-loader!../includes/templates/Icon.mustache';
|
||||
|
||||
const NO_ICON = {
|
||||
icon: 'none',
|
||||
class: 'sticky-header-icon'
|
||||
};
|
||||
|
||||
const data = {
|
||||
title: 'Audre Lorde',
|
||||
heading: 'Introduction',
|
||||
'primary-action': 'Primary action',
|
||||
'is-visible': true,
|
||||
'data-icon-start': NO_ICON,
|
||||
'data-icon-end': NO_ICON,
|
||||
'data-icons': [
|
||||
NO_ICON, NO_ICON, NO_ICON, NO_ICON
|
||||
]
|
||||
};
|
||||
|
||||
export const STICKY_HEADER_TEMPLATE_PARTIALS = {
|
||||
Icon
|
||||
};
|
||||
|
||||
export { template, data };
|
13
stories/StickyHeader.stories.js
Normal file
13
stories/StickyHeader.stories.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
import mustache from 'mustache';
|
||||
import '../resources/skins.vector.styles/components/StickyHeader.less';
|
||||
|
||||
import { template, data,
|
||||
STICKY_HEADER_TEMPLATE_PARTIALS } from './StickyHeader.stories.data';
|
||||
|
||||
export default {
|
||||
title: 'StickyHeader'
|
||||
};
|
||||
|
||||
export const stickyHeader = () => mustache.render(
|
||||
template, data, STICKY_HEADER_TEMPLATE_PARTIALS
|
||||
);
|
Loading…
Reference in a new issue