Implement Page, Workspace, Content, and Article Toolbar Containers

This patch closely follows the desired guidelines/desired
styles Alex Hollender has put forth in his prototype, but uses
multiple containers to achieve this look since our DOM order/structure
is different than the DOM structure in the prototype. The following
containers are used, but unlike his prototype, they are sometimes used
more than once:

* Page Container: Contains every other container and limits the overall
max-width of the white part of the page.

* Workspace Container: Contains the sidebar and content container. The
sidebar is displaced ~30 pixels to the start (left) of the workspace
container at all times.

* Content Container: Contains the content. The max-width of this changes
depending on whether you are on a special page/history page vs. other
pages.

* Article Toolbar Container: Contains the article toolbar. The max-width
of this is always the same as the max-width of the article content as we
don't want the toolbar to move when going from the article page to the
history/special page.

Changes to be aware:

* To test locally, `$wgVectorLayoutMaxWidth = true;`. This design is
temporarily feature flagged and defaults to being "off".

* Note that layout-max-width.less is a temporary file made to meet the
feature flag requirement of T246420 (intended to derisk the deployment).
After the deploy, we should merge most if not all of the rules into
layout.less where the max-width design will become the default.

* Per Jon's code review comment, I have relaxed the indenting of
skin.mustache to make the diff easier to reason about. If desired, the
correct indenting can be achieved in a (much less risky) follow-up
commit.

Bug: T246420
Bug: T153043
Change-Id: Ie49f629bc705850c6996164a516957476c034048
This commit is contained in:
Nicholas Ray 2020-06-23 12:02:32 -06:00
parent ac140d53e6
commit 092a2957af
8 changed files with 250 additions and 17 deletions

View File

@ -5,7 +5,7 @@
},
{
"resourceModule": "skins.vector.styles",
"maxSize": "8.2 kB"
"maxSize": "8.5 kB"
},
{
"resourceModule": "skins.vector.icons",

View File

@ -67,6 +67,11 @@ final class Constants {
public const CONFIG_KEY_DEFAULT_SIDEBAR_VISIBLE_FOR_ANONYMOUS_USER =
'VectorDefaultSidebarVisibleForAnonymousUser';
/**
* @var string
*/
public const CONFIG_KEY_LAYOUT_MAX_WIDTH = 'VectorLayoutMaxWidth';
/**
* @var string
*/

View File

@ -212,6 +212,11 @@ class Hooks {
if ( $skinVersionLookup->isLegacy() ) {
$bodyAttrs['class'] .= ' skin-vector-legacy';
return;
}
if ( self::getConfig( Constants::CONFIG_KEY_LAYOUT_MAX_WIDTH ) ) {
$bodyAttrs['class'] .= ' skin-vector-max-width';
}
}

View File

@ -40,6 +40,9 @@
{{{html-headelement}}}
<div class="mw-page-container">
<div class="mw-page-container-inner">
<div id="mw-page-base" class="mw-header-placeholder noprint"></div>
<input
@ -48,6 +51,8 @@
class="mw-checkbox-hack-checkbox"
{{#sidebar-visible}}checked{{/sidebar-visible}}>
<div class="mw-workspace-container">
<div class="mw-content-container">
{{! `role` is unnecessary but kept to support selectors in any gadgets or user styles. }}
<!-- Please do not use role attribute as CSS selector, it is deprecated. -->
<main id="content" class="mw-body" role="main">
@ -79,6 +84,8 @@
</div>
</main>
{{{html-dataAfterContent}}}
</div> {{! END mw-content-container }}
</div> {{! END mw-workspace-container }}
<header class="mw-header">
<label
@ -91,8 +98,9 @@
tabindex="0">
{{msg-vector-action-toggle-sidebar}}
</label>
{{#data-sidebar}}{{>Sidebar}}{{/data-sidebar}}
<div class="mw-workspace-container mw-sidebar-container">
{{#data-sidebar}}{{>Sidebar}}{{/data-sidebar}}
</div>
{{>Logo}}
</header>
@ -100,16 +108,23 @@
<h2>{{{html-navigation-heading}}}</h2>
<div id="mw-head">
{{#data-personal-menu}}{{>Menu}}{{/data-personal-menu}}
<div id="left-navigation">
{{#data-namespace-tabs}}{{>Menu}}{{/data-namespace-tabs}}
{{#data-variants}}{{>Menu}}{{/data-variants}}
</div>
<div id="right-navigation">
{{#data-page-actions}}{{>Menu}}{{/data-page-actions}}
{{#data-page-actions-more}}{{>Menu}}{{/data-page-actions-more}}
{{#data-search-box}}{{>SearchBox}}{{/data-search-box}}
<div class="mw-content-container mw-article-toolbar-container">
<div id="left-navigation">
{{#data-namespace-tabs}}{{>Menu}}{{/data-namespace-tabs}}
{{#data-variants}}{{>Menu}}{{/data-variants}}
</div>
<div id="right-navigation">
{{#data-page-actions}}{{>Menu}}{{/data-page-actions}}
{{#data-page-actions-more}}{{>Menu}}{{/data-page-actions-more}}
{{#data-search-box}}{{>SearchBox}}{{/data-search-box}}
</div>
</div>
</div>
</div>
{{#data-footer}}{{>Footer}}{{/data-footer}}
<div class="mw-workspace-container mw-footer-container">
{{#data-footer}}{{>Footer}}{{/data-footer}}
</div>
</div> {{! END mw-page-container-inner }}
</div> {{! END mw-page-container }}
{{{html-printtail}}}

View File

@ -71,12 +71,10 @@
// used in Minerva's DropDownList. See enableCssAnimations() in skin.vector.js/index.js for context
// and additional details on how this class is added.
.vector-animations-ready {
// Enable sidebar transitions on desktop width only.
// Enable transition on all widths by default.
.mw-sidebar {
@media ( min-width: @width-breakpoint-desktop ) {
@timing: @transition-duration-base ease-out;
.transition( transform @timing, opacity @timing, visibility @timing; );
}
@timing: @transition-duration-base ease-out;
.transition( transform @timing, opacity @timing, visibility @timing; );
}
// Enable sidebar button transitions.

View File

@ -0,0 +1,205 @@
@import '../../variables.less';
@import 'mediawiki.mixins.less';
// Putting a `skin-vector-max-width` class on the body and wrapping the rules
// herein enables the ability to feature flag the max-width design. This is
// listed in the acceptance criteria of T246420. In other words, if this class
// is present, the max-width design will appear. Without this class, max-width
// design will not appear. In either case, the appearance should not be broken.
.skin-vector-max-width {
@background-color-secondary--modern: #f8f9fa;
@min-width-page-container: 600px;
@max-width-page-container: 1650px;
@padding-horizontal-page-container: 30px;
@min-width-page-container--padded: @max-width-page-container + ( 2 * @padding-horizontal-page-container );
@background-color-page-container: @background-color-base;
@max-width-workspace-container: 1440px;
@max-width-content-container: 960px;
// TODO: Remove @padding-content in variables.less when the max-width layout
// becomes the default layout since the value is different between legacy and
// latest.
@padding-content: 1.25em 0.5em 1.5em 0.5em;
// We want ~60px of space between the end of the sidebar and the start of the
// content container for aesthetic reasons. The sidebar is already displaced
// -30px so we simply add 30px of space to the width of the sidebar.
@margin-start-content: @width-grid-column-one + unit( 30px / @font-size-browser, em );
// Page container's total horizontal padding in em units.
@padding-horizontal-page-container-total: 2 * unit( @padding-horizontal-page-container / @font-size-browser, em );
// Equivalent to 1432px. This determines the maximum width breakpoint at which
// the content will have a fixed start margin applied to it when the sidebar
// is open. The content can shift its position when the sidebar is open/closed
// at or below this breakpoint and will maintain its position above this
// breakpoint.
@max-width-margin-start-content: ( 2 * @margin-start-content ) + @padding-horizontal-page-container-total + ( unit( @max-width-content-container / @font-size-browser, em ) );
@border-color-sidebar: @background-color-secondary--modern;
// Style overrides for existing elements. Mostly overrides layout.less rules.
background-color: @background-color-secondary--modern;
.mw-body {
border-left: 0;
border-bottom: 0;
padding: @padding-content;
}
.parsoid-body {
padding: @padding-content;
}
.mw-header {
padding-left: 0;
padding-right: 0;
}
.mw-body,
#mw-data-after-content,
#left-navigation,
.mw-footer {
margin-left: 0;
}
#mw-head {
width: auto;
left: 0;
right: 0;
}
#left-navigation {
margin-top: 0;
margin-bottom: 0;
}
#right-navigation {
margin-top: 0;
}
#p-personal {
right: 0;
}
#p-search {
margin-right: 0;
}
#p-namespaces {
background-image: none;
padding-left: 0;
}
#mw-panel {
background-image: linear-gradient( to bottom, @background-color-base 0%, @background-color-secondary--modern 10%, @background-color-secondary--modern 90%, @background-color-base 100% );
// Sidebar is displaced from the workspace container so that the
// sidebar is flush with the edge of the screen at small widths.
left: -@padding-horizontal-page-container;
margin-top: 0;
// To avoid the white part of the gradient colliding with the sidebar links
// we apply top and bottom padding.
padding-top: 8px;
padding-bottom: 40px;
}
.mw-footer {
padding: 0;
}
// Container logic.
.mw-page-container {
min-width: @min-width-page-container;
max-width: @max-width-page-container;
margin-left: auto;
margin-right: auto;
padding: 0 @padding-horizontal-page-container;
overflow: hidden;
background-color: @background-color-page-container;
}
// Used as a container for absolutely positioned elements.
.mw-page-container-inner {
position: relative;
}
.mw-workspace-container {
max-width: @max-width-workspace-container;
margin-left: auto;
margin-right: auto;
}
.mw-content-container {
max-width: @max-width-content-container;
margin-left: auto;
margin-right: auto;
}
.mw-article-toolbar-container {
margin-top: @height-header;
// Clear the floats on #left-navigation and #right-navigation.
.mixin-clearfix();
}
.mw-sidebar-container {
position: absolute;
top: 0;
left: 0;
right: 0;
}
.mw-footer-container {
margin-top: 50px;
margin-bottom: 50px;
padding: 32px 0;
border-top: @border-base;
}
// For container logic specific to special pages and history pages.
&.action-history,
&.ns-special {
// Allow the max-width of content on history/special pages to be wider than
// the max-width of content on article pages.
.mw-content-container {
max-width: none;
}
// We want to keep the max-width of the article-toolbar-container the
// same max-width as the article page's content container in order to
// prevent it from moving when going from an article page to a
// history/special page.
.mw-article-toolbar-container {
max-width: @max-width-content-container;
}
// Adjusts the content when sidebar is open regardless of the viewport width.
.mw-checkbox-hack-checkbox:checked ~ .mw-workspace-container .mw-content-container {
margin-left: @margin-start-content;
}
}
// Responsive overrides.
@media ( min-width: @min-width-page-container--padded ) {
@border-color: @border-color-sidebar;
.mw-page-container {
border-left: 1px solid @border-color;
border-right: 1px solid @border-color;
}
}
@media ( max-width: @max-width-margin-start-content ) {
// Adjusts the content and mw-article-toolbar-container.
.mw-checkbox-hack-checkbox:checked ~ .mw-workspace-container .mw-content-container,
.mw-checkbox-hack-checkbox:checked ~ #mw-navigation .mw-content-container {
margin-left: @margin-start-content;
}
.mw-sidebar {
// Remove sidebar transition at smaller widths.
.transition( none );
}
}
@media ( min-width: ( @max-width-workspace-container + ( 2 * @padding-horizontal-page-container ) ) ) {
#mw-panel {
background: none;
border-right: 1px solid @border-color-sidebar;
}
}
}

View File

@ -6,6 +6,7 @@
@media screen {
@import 'common/normalize.less';
@import 'layout.less';
@import 'layout-max-width.less';
@import 'common/typography.less';
// Components

View File

@ -159,6 +159,10 @@
},
"VectorDefaultSidebarVisibleForAnonymousUser": {
"value": false
},
"VectorLayoutMaxWidth": {
"value": false,
"description": "@var boolean Enables the max-width layout for the latest version of Vector. This is intended to be a very short-lived feature flag whose sole purpose is to derisk the deployment of T246420. It should be removed (and made the default) as quickly as possible."
}
},
"ServiceWiringFiles": [