diff --git a/i18n/en.json b/i18n/en.json index 0b27e6b..393d3fd 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -5,5 +5,9 @@ "skinname-monobook": "MonoBook", "monobook-desc": "The classic MediaWiki skin since 2004, named after the black-and-white photo of a book in the page background", "monobook.css": "/* CSS placed here will affect users of the MonoBook skin */", - "monobook.js": "/* Any JavaScript here will be loaded for users using the MonoBook skin */" + "monobook.js": "/* Any JavaScript here will be loaded for users using the MonoBook skin */", + "monobook-jumptotop": "back to top", + "monobook-jumptopersonal": "user tools", + "monobook-more-actions": "More", + "monobook-cactions-label": "Page actions" } diff --git a/i18n/qqq.json b/i18n/qqq.json index fc43d72..e7f5fc8 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -10,5 +10,9 @@ "skinname-monobook": "{{name}}", "monobook-desc": "{{desc|what=skin|name=MonoBook|url=https://www.mediawiki.org/wiki/Skin:MonoBook}}", "monobook.css": "{{optional}}\nCSS applied to users using MonoBook skin.", - "monobook.js": "{{optional}}\nJS for users using MonoBook skin." + "monobook.js": "{{optional}}\nJS for users using MonoBook skin.", + "monobook-jumptotop": "Label for mobile link icon to jump to top of page", + "monobook-jumptopersonal": "Label for mobile link icon to jump to user tools", + "monobook-more-actions": "Label for the less-important or rarer actions that are hidden from the usual tabs on mobile interfaces (like moving the page, or for sysops deleting or protecting the page). {{Identical|More}}", + "monobook-cactions-label": "Header for the content actions menu (tabs on the top of the page)" } diff --git a/includes/MonoBookTemplate.php b/includes/MonoBookTemplate.php index be3412c..d30a43b 100644 --- a/includes/MonoBookTemplate.php +++ b/includes/MonoBookTemplate.php @@ -96,7 +96,7 @@ class MonoBookTemplate extends BaseTemplate { 'dir' => $this->get( 'dir' ) ], Html::element( 'h2', [], $this->getMsg( 'navigation-heading' )->text() ) . - $this->getBox( 'cactions', $this->data['content_actions'], 'views' ) . + $this->getCactions() . $this->getBox( 'personal', $this->getPersonalTools(), 'personaltools' ) . Html::rawElement( 'div', [ 'class' => 'portlet', 'id' => 'p-logo', 'role' => 'banner' ], Html::element( 'a', @@ -107,7 +107,19 @@ class MonoBookTemplate extends BaseTemplate { + Linker::tooltipAndAccesskeyAttribs( 'p-logo' ) ) ) . - $this->getRenderedSidebar() + Html::rawElement( 'div', [ 'id' => 'sidebar' ], $this->getRenderedSidebar() ) . + $this->getMobileNavigationIcon( + 'sidebar', + $this->getMsg( 'jumptonavigation' )->text() + ) . + $this->getMobileNavigationIcon( + 'p-personal', + $this->getMsg( 'monobook-jumptopersonal' )->text() + ) . + $this->getMobileNavigationIcon( + 'globalWrapper', + $this->getMsg( 'monobook-jumptotop' )->text() + ) ); $html .= ''; @@ -124,6 +136,80 @@ class MonoBookTemplate extends BaseTemplate { echo $html; } + /** + * Create a wrapped link to create a mobile toggle/jump icon + * Needs to be an on-page link (as opposed to drawing something on the fly for an + * onclick event) for no-js support. + * + * @param string $target link target + * @param string $title icon title + * + * @return string html empty link block + */ + protected function getMobileNavigationIcon( $target, $title ) { + return Html::element( 'a', [ + 'href' => "#$target", + 'title' => $title, + 'class' => 'menu-toggle', + 'id' => "$target-toggle" + ] ); + } + + /** + * Generate the cactions (content actions) tabs, as well as a second set of spoof tabs for mobile + * + * @return string html + */ + protected function getCactions() { + $html = ''; + $allTabs = $this->data['content_actions']; + $tabCount = count( $allTabs ); + + // Normal cactions + if ( $tabCount > 2 ) { + $html .= $this->getBox( 'cactions', $allTabs, 'monobook-cactions-label' ); + } else { + // Is redundant with spoof, hide normal cactions entirely in mobile + $html .= $this->getBox( 'cactions', $allTabs, 'monobook-cactions-label', + [ 'extra-classes' => 'nomobile' ] + ); + } + + // Mobile cactions tabs + $tabs = $this->data['content_navigation']['namespaces']; + foreach ( $tabs as $tab => $attribs ) { + $tabs[$tab]['id'] = $attribs['id'] . '-mobile'; + $tabs[$tab]['title'] = $attribs['text']; + } + + if ( $tabCount !== 1 ) { + // Is not special page or stuff, append a 'more' + $tabs['more'] = [ + 'text' => $this->getMsg( 'monobook-more-actions' )->text(), + 'href' => '#p-cactions', + 'id' => 'ca-more' + ]; + } + $tabs['toolbox'] = [ + 'text' => $this->getMsg( 'toolbox' )->text(), + 'href' => '#p-tb', + 'id' => 'ca-tools', + 'title' => $this->getMsg( 'toolbox' )->text() + ]; + if ( $this->data['language_urls'] !== false ) { + $tabs['languages'] = [ + 'text' => $this->getMsg( 'otherlanguages' )->text(), + 'href' => '#p-lang', + 'id' => 'ca-languages', + 'title' => $this->getMsg( 'otherlanguages' )->text() + ]; + } + + $html .= $this->getBox( 'cactions-mobile', $tabs, 'monobook-cactions-label' ); + + return $html; + } + /** * Generate the full sidebar * diff --git a/includes/SkinMonoBook.php b/includes/SkinMonoBook.php index 8dcd7f5..7cbb80f 100644 --- a/includes/SkinMonoBook.php +++ b/includes/SkinMonoBook.php @@ -40,13 +40,21 @@ class SkinMonoBook extends SkinTemplate { function setupSkinUserCss( OutputPage $out ) { parent::setupSkinUserCss( $out ); + $out->addMeta( 'viewport', + 'width=device-width, initial-scale=1.0, ' . + 'user-scalable=yes, minimum-scale=0.25, maximum-scale=5.0' + ); + $out->addModuleStyles( [ 'mediawiki.skinning.interface', 'mediawiki.skinning.content.externallinks', 'skins.monobook.styles' ] ); - // TODO: Migrate all of these + // TODO: Migrate all of these (get RL support for conditional IE) + // Force desktop styles in IE 8-; no support for @media widths + $out->addStyle( $this->stylename . '/resources/screen-desktop.css', 'screen', 'lt IE 9' ); + // Miscellanious fixes $out->addStyle( $this->stylename . '/resources/IE60Fixes.css', 'screen', 'IE 6' ); $out->addStyle( $this->stylename . '/resources/IE70Fixes.css', 'screen', 'IE 7' ); } diff --git a/resources/images/icon-chat.gif b/resources/images/icon-chat.gif new file mode 100644 index 0000000..f776a4a Binary files /dev/null and b/resources/images/icon-chat.gif differ diff --git a/resources/images/icon-chat.svg b/resources/images/icon-chat.svg new file mode 100644 index 0000000..59a6767 --- /dev/null +++ b/resources/images/icon-chat.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/icon-globe.gif b/resources/images/icon-globe.gif new file mode 100644 index 0000000..512c465 Binary files /dev/null and b/resources/images/icon-globe.gif differ diff --git a/resources/images/icon-globe.svg b/resources/images/icon-globe.svg new file mode 100644 index 0000000..efcf873 --- /dev/null +++ b/resources/images/icon-globe.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/icon-page.gif b/resources/images/icon-page.gif new file mode 100644 index 0000000..2ee8c34 Binary files /dev/null and b/resources/images/icon-page.gif differ diff --git a/resources/images/icon-page.svg b/resources/images/icon-page.svg new file mode 100644 index 0000000..b4499f6 --- /dev/null +++ b/resources/images/icon-page.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/resources/images/icon-search.gif b/resources/images/icon-search.gif new file mode 100644 index 0000000..09fb7f4 Binary files /dev/null and b/resources/images/icon-search.gif differ diff --git a/resources/images/icon-search.svg b/resources/images/icon-search.svg new file mode 100644 index 0000000..e672f56 --- /dev/null +++ b/resources/images/icon-search.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/icon-tools.gif b/resources/images/icon-tools.gif new file mode 100644 index 0000000..440dcf8 Binary files /dev/null and b/resources/images/icon-tools.gif differ diff --git a/resources/images/icon-tools.svg b/resources/images/icon-tools.svg new file mode 100644 index 0000000..65c5b56 --- /dev/null +++ b/resources/images/icon-tools.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/icon-triangle-down.gif b/resources/images/icon-triangle-down.gif new file mode 100644 index 0000000..d827e53 Binary files /dev/null and b/resources/images/icon-triangle-down.gif differ diff --git a/resources/images/icon-triangle-down.svg b/resources/images/icon-triangle-down.svg new file mode 100644 index 0000000..4edd92a --- /dev/null +++ b/resources/images/icon-triangle-down.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/resources/images/icon-triangle-ltr.gif b/resources/images/icon-triangle-ltr.gif new file mode 100644 index 0000000..cfc4e96 Binary files /dev/null and b/resources/images/icon-triangle-ltr.gif differ diff --git a/resources/images/icon-triangle-ltr.svg b/resources/images/icon-triangle-ltr.svg new file mode 100644 index 0000000..e4e3841 --- /dev/null +++ b/resources/images/icon-triangle-ltr.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/resources/images/icon-triangle-rtl.gif b/resources/images/icon-triangle-rtl.gif new file mode 100644 index 0000000..ed82cd2 Binary files /dev/null and b/resources/images/icon-triangle-rtl.gif differ diff --git a/resources/images/icon-triangle-rtl.svg b/resources/images/icon-triangle-rtl.svg new file mode 100644 index 0000000..ee04d66 --- /dev/null +++ b/resources/images/icon-triangle-rtl.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/resources/images/icon-triangle-up.gif b/resources/images/icon-triangle-up.gif new file mode 100644 index 0000000..9c2c4c9 Binary files /dev/null and b/resources/images/icon-triangle-up.gif differ diff --git a/resources/images/icon-triangle-up.svg b/resources/images/icon-triangle-up.svg new file mode 100644 index 0000000..88d024d --- /dev/null +++ b/resources/images/icon-triangle-up.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/resources/images/user.gif b/resources/images/icon-user.gif similarity index 100% rename from resources/images/user.gif rename to resources/images/icon-user.gif diff --git a/resources/images/user.svg b/resources/images/icon-user.svg similarity index 100% rename from resources/images/user.svg rename to resources/images/icon-user.svg diff --git a/resources/images/icons-sourcefile.svg b/resources/images/icons-sourcefile.svg new file mode 100644 index 0000000..9fc119f --- /dev/null +++ b/resources/images/icons-sourcefile.svg @@ -0,0 +1,1299 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/screen-common.less b/resources/screen-common.less index efe1648..347a8e4 100644 --- a/resources/screen-common.less +++ b/resources/screen-common.less @@ -211,21 +211,8 @@ table.rimage { /* ** the personal toolbar */ - -#p-personal h3 { - .hidden(); - - li { - color: #2f6fab; - - a { - color: #005896; - } - - &.active { - font-weight: bold; - } - } +#p-personal li.active { + font-weight: bold; } /* Don't lowercase username */ @@ -238,14 +225,6 @@ li#pt-anonuserpage { color: @text-grey; } -/* -** the page-related actions- page/talk, edit etc -*/ - -#p-cactions h3 { - .hidden() -} - /* Override text-transform on languages where capitalization is significant */ .capitalize-all-nouns .portlet h3, .capitalize-all-nouns #p-personal ul, @@ -355,6 +334,7 @@ div.multipageimagenavbox { margin-left: 2em; margin-right: 2em; } + hr { margin: 6px; } diff --git a/resources/screen-desktop.css b/resources/screen-desktop.css index bdaaf62..3130da5 100644 --- a/resources/screen-desktop.css +++ b/resources/screen-desktop.css @@ -1,5 +1,9 @@ /* ** Desktop-specific styles for MonoBook +** +** Must remain simple css (not less) for IE8- support; ResourceLoader does not support +** conditional IE loading, and so we cannot depend on it for anything here as this file +** is also loaded directly, bypassing ResourceLoader, in those browsers. */ div#column-content { @@ -110,7 +114,6 @@ input.searchButton { left: 0; top: 0; z-index: 3; - width: 100%; white-space: nowrap; padding: 0; @@ -121,6 +124,11 @@ input.searchButton { line-height: 1.2em; } +#p-personal h3 { + position: absolute; + top: -9999px; +} + #p-personal .portlet, #p-personal .pBody { z-index: 0; @@ -154,6 +162,7 @@ input.searchButton { z-index: 0; border: 0; padding: 0; + color: #2f6fab; display: inline; margin-left: 1em; line-height: 1.2em; @@ -161,6 +170,7 @@ input.searchButton { } #p-personal li a { + color: #005896; text-decoration: none; padding-bottom: 0.2em; } @@ -177,14 +187,19 @@ input.searchButton { /* The icon in front of the username / login link */ li#pt-userpage, li#pt-anonuserpage { - background-image: url( images/user.gif ); + background-image: url( images/icon-user.gif ); /* @embed */ - background-image: linear-gradient( transparent, transparent ), url( images/user.svg ); + background-image: linear-gradient( transparent, transparent ), url( images/icon-user.svg ); background-position: top left; background-repeat: no-repeat; padding-left: 20px; } +#p-lang { + position: relative; + z-index: 3; +} + /* ** the page-related actions- page/talk, edit etc */ @@ -203,6 +218,11 @@ li#pt-anonuserpage { font-size: 95%; } +#p-cactions h3 { + position: absolute; + top: -9999px; +} + #p-cactions ul { list-style-type: none; list-style-image: none; @@ -212,8 +232,8 @@ li#pt-anonuserpage { display: inline; border: 1px solid #aaa; border-bottom: 0; + margin: 0 0.5em 0 0; padding: 0 0 1em 0; - margin: 0 0.3em 0 0; overflow: visible; background: #fff; } @@ -223,6 +243,11 @@ li#pt-anonuserpage { font-weight: bold; } +#p-cactions li.selected a { + z-index: 3; + background-color: #fff; +} + #p-cactions li a { background-color: #fbfbfb; color: #002bb8; @@ -235,15 +260,6 @@ li#pt-anonuserpage { text-transform: lowercase; } -#p-cactions li.selected a { - z-index: 3; - background-color: #fff; -} - -#p-cactions .new a { - color: #ba0000; -} - #p-cactions li a:hover { z-index: 3; text-decoration: none; @@ -258,11 +274,24 @@ li#pt-anonuserpage { padding-right: 0.5em; } +#p-cactions .new a { + color: #c20; +} + #p-cactions #ca-addsection a { padding-left: 0.4em; padding-right: 0.4em; } +#p-cactions .pBody { + font-size: 1em; + background-color: transparent; + color: inherit; + border-collapse: inherit; + border: 0; + padding: 0; +} + /* offsets to distinguish the tab groups */ li#ca-talk { margin-right: 1.6em; @@ -275,18 +304,12 @@ li#ca-print { margin-left: 1.6em; } -#p-cactions .pBody { - font-size: 1em; - background-color: transparent; - color: inherit; - border-collapse: inherit; - border: 0; - padding: 0; -} - -#p-lang { - position: relative; - z-index: 3; +/* +** mobile toggles; not used here +*/ +#p-cactions-mobile, +.menu-toggle { + display: none; } /* diff --git a/resources/screen-mobile.less b/resources/screen-mobile.less new file mode 100644 index 0000000..070d18d --- /dev/null +++ b/resources/screen-mobile.less @@ -0,0 +1,304 @@ +/* +** Mobile styles for MonoBook +*/ + +@import 'variables.less'; + +div#column-content { + padding-top: 6em; +} + +.mw-body { + border-right: 0; + border-left: 0; +} + +/* +** Navigation +*/ +@top-position: 5px; +@block-size: 35px; + +.menu-toggle { + display: block; + width: @block-size; + height: @block-size; + background: @content-background; + border: solid 1px @orange-border; + box-sizing: border-box; + background-position: 50% 50%; + background-repeat: no-repeat; + z-index: 4; +} + +#sidebar-toggle { + .background-image-svg( 'images/icon-triangle-down.svg', 'images/icon-triangle-down.gif' ); + position: absolute; + top: @top-position; + left: 1em; +} + +#p-personal-toggle { + .background-image-svg( 'images/icon-user.svg', 'images/icon-user.gif' ); + position: absolute; + top: @top-position; + right: 1em; +} + +#globalWrapper-toggle { + .background-image-svg( 'images/icon-triangle-up.svg', 'images/icon-triangle-up.gif' ); + margin: 1em auto; +} + +/* +** search +*/ +#p-search { + position: absolute; + z-index: 3; + top: @top-position; + left: 0; + width: 100%; + padding: 0 @block-size + 20px; + box-sizing: border-box; + + h3 { + .hidden(); + } +} + +#searchBody { + border: solid 1px @orange-border; + background-color: @content-background; + height: @block-size; + box-sizing: border-box; +} + +#searchform { + position: relative; + width: 100%; + padding: 3px 42px 3px 9px; + box-sizing: border-box; +} + +#searchInput { + width: 100%; + height: @block-size - 8px; + border: solid 1px @content-border; + padding: 0 0.25em; + box-sizing: border-box; +} + +#searchGoButton { + position: absolute; + box-sizing: border-box; + top: 1px; + right: 6px; + height: @block-size - 4px; + width: @block-size; + text-indent: -99999px; + border: 0; + background: none; + .background-image-svg( 'images/icon-search.svg', 'images/icon-search.gif' ); + background-position: 50% 50%; + background-repeat: no-repeat; + cursor: pointer; +} + +#mw-searchButton { + display: none; +} + +/* +** site nav +*/ +#p-cactions, +#p-personal, +.generated-sidebar, +#p-tb, +#p-lang { + margin: 1em; + overflow: visible; + + .pBody { + border: solid 1px @content-border; + background: @content-background; + padding: 0.5em; + } + + ul { + margin: 0; + } + + li { + display: inline-block; + border-left: solid 1px @content-border; + padding: 0 0.5em; + white-space: nowrap; + + &:first-child { + border-left: 0; + padding-left: 0; + } + + // wtf echo + &#pt-notifications-alert, + &#pt-notifications-notice { + border-left: 0; + } + + &.selected { + font-weight: bold; + + a { + color: @text-color; + } + } + } +} + +/* +** fake cactions +*/ +#p-cactions-mobile { + position: absolute; + top: 3.75em; + left: 0; + padding: 0 1em; + width: 100%; + box-sizing: border-box; + + h3 { + display: none; + } + + ul { + margin: 0; + list-style: none; + } + + li { + display: inline-block; + border: 1px solid @content-border; + border-bottom: 0; + margin-right: 0.5em; + height: 2.5em; + + a { + .icon-tab(); + display: block; + position: relative; + padding: 0.5em 1em 0.75em; + background-color: #fbfbfb; + .background-image-svg( 'images/icon-page.svg', 'images/icon-page.gif' ); + background-position: 50% 50%; + background-repeat: no-repeat; + text-transform: lowercase; + } + + &#ca-talk-mobile a { + .background-image-svg( 'images/icon-chat.svg', 'images/icon-chat.gif' ); + } + + &#ca-more { + border: 0; + + a { + background-color: transparent; + .background-image-svg( 'images/icon-triangle-ltr.svg', 'images/icon-triangle-ltr.gif' ); + background-position: 100% 40%; + text-indent: 0; + padding-left: 0.5em; + padding-right: 1.35em; + width: auto; + } + } + + &#ca-languages a { + .background-image-svg( 'images/icon-globe.svg', 'images/icon-globe.gif' ); + } + + &#ca-tools a { + .background-image-svg( 'images/icon-tools.svg', 'images/icon-tools.gif' ); + } + + &.selected { + border-color: @orange-border; + font-weight: bold; + } + + &.selected a, + &:hover a { + z-index: 3; + background-color: @content-background; + text-decoration: none; + } + + &#ca-languages, + &#ca-tools { + float: right; + margin-right: 0; + margin-left: 0.5em; + } + } +} + +/* +** footer +*/ +#footer li { + margin-left: 0; +} + +#f-poweredbyico, +#f-copyrightico { + display: inline; + margin: 0 0.5em; +} + +/* +** images +*/ +div.thumb { + float: none; + margin: 1em auto; +} + +div.tright { + margin-left: 0; + padding-left: 0; +} + +div.tleft { + margin-right: 0; + padding-right: 0; +} + +.thumbinner { + width: 100% !important; /* stylelint-disable-line declaration-no-important */ + box-sizing: border-box; +} + +.mw-body-content { + overflow: auto; +} + +/* Keep images from overflowing */ +.mw-body-content img { + height: auto !important; /* stylelint-disable-line declaration-no-important */ + max-width: 100% !important; /* stylelint-disable-line declaration-no-important */ +} + +/* +** table of contents +*/ +#toc, +.toc, +.mw-warning { + width: 100%; + box-sizing: border-box; +} + +.nomobile { + display: none; +} diff --git a/resources/variables.less b/resources/variables.less index 9ae222b..78ae733 100644 --- a/resources/variables.less +++ b/resources/variables.less @@ -20,3 +20,11 @@ top: -9999px; left: 0; } + +// The mobile icon cactions tabs +.icon-tab() { + text-indent: -99999px; + background-position: 50% 50%; + background-repeat: no-repeat; + width: 1em; +} diff --git a/skin.json b/skin.json index d63cbe8..d867bbf 100644 --- a/skin.json +++ b/skin.json @@ -2,6 +2,7 @@ "name": "MonoBook", "author": [ "Gabriel Wicke", + "Isarra Yos", "..." ], "url": "https://www.mediawiki.org/wiki/Skin:MonoBook", @@ -10,7 +11,7 @@ "license-name": "GPL-2.0-or-later", "type": "skin", "requires": { - "MediaWiki": ">= 1.25.0" + "MediaWiki": ">= 1.29.0" }, "ValidSkinNames": { "monobook": "MonoBook" @@ -25,12 +26,16 @@ }, "ResourceModules": { "skins.monobook.styles": { + "targets": [ "desktop", "mobile" ], "styles": { "resources/screen-common.less": { "media": "screen" }, "resources/screen-desktop.css": { - "media": "screen" + "media": "screen and (min-width: 851px)" + }, + "resources/screen-mobile.less": { + "media": "screen and (max-width: 850px)" } } }