diff --git a/bedrock/externalpages/templates/externalpages/pocket/about.html b/bedrock/externalpages/templates/externalpages/pocket/about.html index 9a413cc92c..b92db01d2c 100644 --- a/bedrock/externalpages/templates/externalpages/pocket/about.html +++ b/bedrock/externalpages/templates/externalpages/pocket/about.html @@ -63,3 +63,6 @@ {% endblock %} +{% block js %} + {{ js_bundle('pocket-nav') }} +{% endblock %} diff --git a/bedrock/externalpages/templates/externalpages/pocket/base.html b/bedrock/externalpages/templates/externalpages/pocket/base.html index a5020225f8..22bc557aad 100644 --- a/bedrock/externalpages/templates/externalpages/pocket/base.html +++ b/bedrock/externalpages/templates/externalpages/pocket/base.html @@ -34,17 +34,8 @@ {% block page_title %}{% endblock page_title %} | Pocket - {# - NOTE: These URLs cannot use the `url(..)` pattern as that will include the - "/external/pocket/" in the path, but since these are proxied from - getpocket.com, that would result in a 404. - #} - {# Lang: {{ LANG }} #} - {# #} -
{% block content %}{% endblock %}
+
{% block content %}{% endblock %}
+ + {% block js %}{% endblock %} + diff --git a/bedrock/externalpages/templates/externalpages/pocket/includes/mobile-nav.html b/bedrock/externalpages/templates/externalpages/pocket/includes/mobile-nav.html new file mode 100644 index 0000000000..3e8f698b44 --- /dev/null +++ b/bedrock/externalpages/templates/externalpages/pocket/includes/mobile-nav.html @@ -0,0 +1,45 @@ +{# + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. +#} + +
+ +
diff --git a/bedrock/externalpages/templates/externalpages/pocket/includes/nav.html b/bedrock/externalpages/templates/externalpages/pocket/includes/nav.html index f4461dbcbd..38d418b89e 100644 --- a/bedrock/externalpages/templates/externalpages/pocket/includes/nav.html +++ b/bedrock/externalpages/templates/externalpages/pocket/includes/nav.html @@ -1,13 +1,21 @@ +{# + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. +#} + {# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -#} +{% include 'externalpages/pocket/includes/mobile-nav.html' %} +
diff --git a/media/css/externalpages/pocket/components/_mobile-nav.scss b/media/css/externalpages/pocket/components/_mobile-nav.scss new file mode 100644 index 0000000000..ceda62dcff --- /dev/null +++ b/media/css/externalpages/pocket/components/_mobile-nav.scss @@ -0,0 +1,249 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +@import '~@mozilla-protocol/core/protocol/css/includes/lib'; +@import '../utils/variables'; + +$icon-path: '/media/img/externalpages/pocket/mobile-nav/'; + +// variables from pocket +$easing-accelerate: cubic-bezier(0.4, 0, 1, 1); +$easing-decelerate: cubic-bezier(0, 0, 0.2, 1); + +// this class will be added to the body to disable scroll while the nav is open +.mobile-nav-open { + overflow: hidden; +} + +.mobile-nav-wrapper { + background: rgba(26, 26, 26, 0.4) none repeat scroll 0 0; + bottom: 0; + display: none; + left: 0; + mix-blend-mode: normal; + opacity: 0; + pointer-events: none; + position: fixed; + right: 0; + transition: opacity 150ms $easing-accelerate, transform 75ms $easing-accelerate; + top: 0; + z-index: 20; + + &.active { + display: block; + pointer-events: auto; + } +} + +.mobile-nav { + background: $color-white; + border-radius: 0; + bottom: 0; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12); + left: 0; + max-height: 100%; + max-width: 256px; + overflow-y: scroll; + position: absolute; + right: auto; + top: 0; + transform: translateX(-256px); + transition: all 250ms $easing-decelerate; + width: 100%; + + &.active { + opacity: 1; + transform: translateX(0); + transition: all 250ms $easing-decelerate; + } + + .mobile-nav-close { + align-items: center; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); + border-bottom: 1px solid #d9d9d9; + display: flex; + height: 64px; + margin-bottom: 8px; + padding: 0; + + &:focus, + &:focus-within { + border: 1px solid $color-action-primary; + } + + .mobile-nav-close-btn { + @include image-replaced; + background: url('#{$icon-path}/back-btn.svg') no-repeat transparent; + border: none; + color: $color-text-primary; + height: $spacing-lg; + margin: 0 $spacing-sm; + outline: none; + width: $spacing-lg; + } + } +} + +.mobile-nav-list { + background: $color-white; + display: flex; + flex-direction: column; + font-family: $font-sans; + font-size: 16px; + font-weight: 500; + list-style: none; + margin: 0; + padding: 0; + + .mobile-nav-list-item { + margin: 0; + padding: 0; + width: 100%; + + .mobile-nav-list-link { + align-items: center; + color: $color-text-primary; + fill: currentColor; + line-height: 24px; + display: inline-flex; + padding: 12px 16px; + position: relative; + text-decoration: none; + transition: background-color 100ms ease-out; + width: 100%; + + &::before { + background-repeat: no-repeat; + content: ''; + height: $spacing-lg; + width: $spacing-xl; + } + + &.home { + &::before { + background-image: url('#{$icon-path}home-icon.svg'); + } + + &:hover::before { + background-image: url('#{$icon-path}home-icon-active.svg'); + } + } + + &.my-list { + &::before { + background-image: url('#{$icon-path}my-list-icon.svg'); + } + + &:hover::before { + background-image: url('#{$icon-path}my-list-icon-active.svg'); + } + } + + &.discover { + &::before { + background-image: url('#{$icon-path}discover-icon.svg'); + } + + &:hover::before { + background-image: url('#{$icon-path}discover-icon-active.svg'); + } + } + + &.collections { + &::before { + background-image: url('#{$icon-path}collections-icon.svg'); + } + + &:hover::before { + background-image: url('#{$icon-path}collections-icon-active.svg'); + } + } + + &.archive { + &::before { + background-image: url('#{$icon-path}archive-icon.svg'); + } + + &:hover::before { + background-image: url('#{$icon-path}archive-icon-active.svg'); + } + } + + &.favorites { + &::before { + background-image: url('#{$icon-path}favorites-icon.svg'); + } + + &:hover::before { + background-image: url('#{$icon-path}favorites-icon-active.svg'); + } + } + + &.highlights { + &::before { + background-image: url('#{$icon-path}highlights-icon.svg'); + } + + &:hover::before { + background-image: url('#{$icon-path}highlights-icon-active.svg'); + } + } + + &.articles { + &::before { + background-image: url('#{$icon-path}articles-icon.svg'); + } + + &:hover::before { + background-image: url('#{$icon-path}articles-icon-active.svg'); + } + } + + &.videos { + &::before { + background-image: url('#{$icon-path}videos-icon.svg'); + } + + &:hover::before { + background-image: url('#{$icon-path}videos-icon-active.svg'); + } + } + + &.tags { + &::before { + background-image: url('#{$icon-path}tags-icon.svg'); + } + + &:hover::before { + background-image: url('#{$icon-path}tags-icon-active.svg'); + } + } + + &:focus, + &:focus-within { + border: 1px solid $color-action-primary; + } + + &:hover:not(.selected):not(.disabled) { + background-color: $color-action-primary; + color: $color-white; + } + + &.selected { + background-color: $color-nav-current; + color: $color-action-primary; + } + + .beta { + border: 1px solid #1eabf9; + border-radius: 4px; + color: #1eabf9; + font-size: 11px; + font-weight: 500; + margin-left: 8px; + padding: 0 5px; + } + } + } +} diff --git a/media/css/externalpages/pocket/components/_nav.scss b/media/css/externalpages/pocket/components/_nav.scss index a0f3549fa2..82f3a163ec 100644 --- a/media/css/externalpages/pocket/components/_nav.scss +++ b/media/css/externalpages/pocket/components/_nav.scss @@ -3,6 +3,7 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. @import '../utils/variables'; +@import './mobile-nav'; $image-path: '/media/img/externalpages/pocket'; @@ -24,15 +25,20 @@ $image-path: '/media/img/externalpages/pocket'; .global-nav-mobile-menu-btn { display: block; - margin-left: calc($spacing075 * -1); - width: 48px; - height: 48px; + margin-left: -$spacing-sm; + width: 36px; + height: 36px; position: relative; line-height: 110%; border: none; border-radius: 4px; transition: all 0.15s ease-out; + &:focus, + &:focus-within { + border: 1px solid $color-action-primary; + } + &.inline { background: none; padding: 0; @@ -46,6 +52,7 @@ $image-path: '/media/img/externalpages/pocket'; margin-bottom: -2px; display: inline-block; margin-top: -4px; + pointer-events: none; vertical-align: middle; } @@ -57,9 +64,9 @@ $image-path: '/media/img/externalpages/pocket'; .pocket-logo { display: inline-block; position: relative; + margin-left: 8px; margin-right: 0; - margin-left: calc($spacing075 * -1); - padding: $spacing050 $spacing050; + padding: 8px 0; line-height: 1; &:focus { @@ -89,6 +96,10 @@ $image-path: '/media/img/externalpages/pocket'; background-image: url('#{$image-path}/pocket-logo-light-mode.svg'); width: 94px; height: 24px; + + span { + @include visually-hidden; + } } &.logged-in .logo { @@ -128,10 +139,10 @@ $image-path: '/media/img/externalpages/pocket'; white-space: nowrap; .page-navigation-list { + @include text-body-md; margin: 0; padding: 0; list-style-type: none; - font-size: 16px; display: none; .page-navigation-list-item { @@ -148,7 +159,7 @@ $image-path: '/media/img/externalpages/pocket'; .page-navigation-list-item-link { font-weight: 500; - line-height: 24px; + line-height: $spacing-lg; text-decoration: none; padding: 20px; position: relative; @@ -161,12 +172,12 @@ $image-path: '/media/img/externalpages/pocket'; display: block; box-sizing: border-box; position: absolute; - left: $spacing025; - right: $spacing025; - top: $spacing050; - bottom: $spacing050; + left: $spacing-xs; + right: $spacing-xs; + top: $spacing-sm; + bottom: $spacing-sm; border: 2px solid $color-action-primary; - border-radius: 4px; + border-radius: $border-radius-sm; } } @@ -189,7 +200,7 @@ $image-path: '/media/img/externalpages/pocket'; bottom: 0; left: 10px; right: 10px; - height: 4px; + height: $spacing-xs; background-color: $color-action-primary; } @@ -201,9 +212,7 @@ $image-path: '/media/img/externalpages/pocket'; .nav-link { display: none; position: relative; - padding: $spacing075 $spacing050; vertical-align: middle; - line-height: 110%; font-weight: 500; text-decoration: none; color: $color-text-primary; @@ -223,7 +232,7 @@ $image-path: '/media/img/externalpages/pocket'; top: -2px; bottom: -2px; border: 2px solid $color-action-primary; - border-radius: 4px; + border-radius: $border-radius-sm; } } @@ -237,11 +246,11 @@ $image-path: '/media/img/externalpages/pocket'; } &.login-link { - margin-right: $spacing150; + margin-right: $spacing-lg; } &.signup-link { - border-radius: 4px; + border-radius: $border-radius-sm; padding: 12px; transition: all 0.15s ease-out; cursor: pointer; @@ -264,14 +273,19 @@ $image-path: '/media/img/externalpages/pocket'; line-height: 0; vertical-align: middle; margin-top: 0; - height: 24px; + height: $spacing-lg; + color: $color-text-primary; svg { height: 100%; } + span { + @include visually-hidden; + } + @media #{$mq-md} { - margin-top: -4px; display: none; + margin-top: -$spacing-xs; } } diff --git a/media/css/externalpages/pocket/utils/_variables.scss b/media/css/externalpages/pocket/utils/_variables.scss index c2ab8f9252..4a61624a78 100644 --- a/media/css/externalpages/pocket/utils/_variables.scss +++ b/media/css/externalpages/pocket/utils/_variables.scss @@ -13,6 +13,7 @@ $color-text-dark-grey: #333; $color-button-red: #e7132f; $color-text-cyan: #5dcfca; $color-background-grey: #f0f0f0; +$color-nav-current: #e0f0ef; $box-shadow-sm: 0 2px 12px rgba(0, 0, 0, 0.08); $mq-md: '(min-width: 720px)'; $mq-lg: '(min-width: 1024px)'; diff --git a/media/img/externalpages/pocket/mobile-nav/archive-icon-active.svg b/media/img/externalpages/pocket/mobile-nav/archive-icon-active.svg new file mode 100644 index 0000000000..5c7985868b --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/archive-icon-active.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/archive-icon.svg b/media/img/externalpages/pocket/mobile-nav/archive-icon.svg new file mode 100644 index 0000000000..2834540b8b --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/archive-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/articles-icon-active.svg b/media/img/externalpages/pocket/mobile-nav/articles-icon-active.svg new file mode 100644 index 0000000000..ffc1b7d8be --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/articles-icon-active.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/articles-icon.svg b/media/img/externalpages/pocket/mobile-nav/articles-icon.svg new file mode 100644 index 0000000000..dabf5fd9a0 --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/articles-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/back-btn.svg b/media/img/externalpages/pocket/mobile-nav/back-btn.svg new file mode 100644 index 0000000000..de850f0c8d --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/back-btn.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/collections-icon-active.svg b/media/img/externalpages/pocket/mobile-nav/collections-icon-active.svg new file mode 100644 index 0000000000..2bdbf38bc7 --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/collections-icon-active.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/collections-icon.svg b/media/img/externalpages/pocket/mobile-nav/collections-icon.svg new file mode 100644 index 0000000000..add4a3e47e --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/collections-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/discover-icon-active.svg b/media/img/externalpages/pocket/mobile-nav/discover-icon-active.svg new file mode 100644 index 0000000000..73b3e535bb --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/discover-icon-active.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/discover-icon.svg b/media/img/externalpages/pocket/mobile-nav/discover-icon.svg new file mode 100644 index 0000000000..bf35f6d739 --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/discover-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/favorites-icon-active.svg b/media/img/externalpages/pocket/mobile-nav/favorites-icon-active.svg new file mode 100644 index 0000000000..d29985a1e7 --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/favorites-icon-active.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/favorites-icon.svg b/media/img/externalpages/pocket/mobile-nav/favorites-icon.svg new file mode 100644 index 0000000000..7e2a84a3e3 --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/favorites-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/highlights-icon-active.svg b/media/img/externalpages/pocket/mobile-nav/highlights-icon-active.svg new file mode 100644 index 0000000000..737c889285 --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/highlights-icon-active.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/highlights-icon.svg b/media/img/externalpages/pocket/mobile-nav/highlights-icon.svg new file mode 100644 index 0000000000..480e61f78c --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/highlights-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/home-icon-active.svg b/media/img/externalpages/pocket/mobile-nav/home-icon-active.svg new file mode 100644 index 0000000000..a9e48a8e38 --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/home-icon-active.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/home-icon.svg b/media/img/externalpages/pocket/mobile-nav/home-icon.svg new file mode 100644 index 0000000000..1e6095a712 --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/home-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/my-list-icon-active.svg b/media/img/externalpages/pocket/mobile-nav/my-list-icon-active.svg new file mode 100644 index 0000000000..242804fd80 --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/my-list-icon-active.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/my-list-icon.svg b/media/img/externalpages/pocket/mobile-nav/my-list-icon.svg new file mode 100644 index 0000000000..9cf813e457 --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/my-list-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/tags-icon-active.svg b/media/img/externalpages/pocket/mobile-nav/tags-icon-active.svg new file mode 100644 index 0000000000..f1162d27e0 --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/tags-icon-active.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/tags-icon.svg b/media/img/externalpages/pocket/mobile-nav/tags-icon.svg new file mode 100644 index 0000000000..441f547c73 --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/tags-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/videos-icon-active.svg b/media/img/externalpages/pocket/mobile-nav/videos-icon-active.svg new file mode 100644 index 0000000000..2b8295a26b --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/videos-icon-active.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/img/externalpages/pocket/mobile-nav/videos-icon.svg b/media/img/externalpages/pocket/mobile-nav/videos-icon.svg new file mode 100644 index 0000000000..cb14ecdd1d --- /dev/null +++ b/media/img/externalpages/pocket/mobile-nav/videos-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/js/externalpages/pocket/mobile-nav.es6.js b/media/js/externalpages/pocket/mobile-nav.es6.js new file mode 100644 index 0000000000..00a484826b --- /dev/null +++ b/media/js/externalpages/pocket/mobile-nav.es6.js @@ -0,0 +1,103 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +const navOpenBtn = document.querySelector('.global-nav-mobile-menu-btn'); +const mobileNavWrapper = document.querySelector('.mobile-nav-wrapper'); +const mobileNav = document.querySelector('.mobile-nav'); +const navCloseBtn = document.querySelector('.mobile-nav-close-btn'); +const contentWrapper = document.querySelector('body'); + +const TAB = 9; +const ESC = 27; + +function detectClickOutside(event) { + if (!mobileNav.contains(event.target) && event.target !== navOpenBtn) { + handleMenuClose(); + } +} + +function handleMenuOpen() { + mobileNavWrapper.classList.add('active'); + mobileNav.setAttribute('aria-expanded', true); + contentWrapper.classList.add('mobile-nav-open'); + document.addEventListener('click', detectClickOutside); + window.addEventListener('keydown', handleKeyDown); + + // move focus to close button when modal is opened, need to use setTimeout to get the animation working correctly + setTimeout(function () { + mobileNavWrapper.style.opacity = 1; + mobileNav.classList.add('active'); + navCloseBtn.focus(); + }, 10); +} + +function handleMenuClose() { + mobileNav.classList.remove('active'); + mobileNav.setAttribute('aria-expanded', false); + mobileNavWrapper.style.opacity = 0; + document.removeEventListener('click', detectClickOutside); + window.removeEventListener('keydown', handleKeyDown); + + // move focus to close button when modal is closed need to use setTimeout to get the animation working correctly + setTimeout(function () { + mobileNavWrapper.classList.remove('active'); + contentWrapper.classList.remove('mobile-nav-open'); + navCloseBtn.focus(); + }, 250); +} + +function handleKeyDown(e) { + const focusableElements = Array.prototype.slice.call( + mobileNav.querySelectorAll( + 'a[href], button:not([disabled]), [tabindex="0"]' + ) + ); + + function handleBackwardTab() { + if (document.activeElement === focusableElements[0]) { + e.preventDefault(); + focusableElements[focusableElements.length - 1].focus(); + } else { + e.preventDefault(); + focusableElements[ + focusableElements.indexOf(document.activeElement) - 1 + ].focus(); + } + } + function handleForwardTab() { + if ( + document.activeElement === + focusableElements[focusableElements.length - 1] + ) { + e.preventDefault(); + focusableElements[0].focus(); + } else { + e.preventDefault(); + focusableElements[ + focusableElements.indexOf(document.activeElement) + 1 + ].focus(); + } + } + + // function handleForwardTab(){} + switch (e.keyCode) { + case TAB: + if (e.shiftKey) { + handleBackwardTab(); + } else { + handleForwardTab(); + } + break; + case ESC: + handleMenuClose(); + break; + default: + break; + } +} + +navOpenBtn.addEventListener('click', handleMenuOpen, false); +navCloseBtn.addEventListener('click', handleMenuClose, false); diff --git a/media/static-bundles.json b/media/static-bundles.json index 18cc7346cb..25cf5258a1 100644 --- a/media/static-bundles.json +++ b/media/static-bundles.json @@ -1558,6 +1558,12 @@ ], "name": "product_pocket" }, + { + "files": [ + "js/externalpages/pocket/mobile-nav.es6.js" + ], + "name": "pocket-nav" + }, { "files": [ "js/firefox/enterprise/landing.js"