diff --git a/app/assets/scripts/modules/StickyHeader.js b/app/assets/scripts/modules/StickyHeader.js index b345fd0..e57b467 100644 --- a/app/assets/scripts/modules/StickyHeader.js +++ b/app/assets/scripts/modules/StickyHeader.js @@ -1,11 +1,20 @@ import $ from 'jquery'; import waypoints from '../../../../node_modules/waypoints/lib/noframework.waypoints'; +import smoothScroll from 'jquery-smooth-scroll'; class StickyHeader { constructor() { this.siteHeader = $(".site-header"); this.headerTriggerElement = $(".large-hero__title"); this.createHeaderWaypoint(); + this.pageSections = $(".page-section"); + this.headerLinks = $(".primary-nav a"); + this.createPageSectionWaypoints(); + this.addSmoothScrolling(); + } + + addSmoothScrolling() { + this.headerLinks.smoothScroll(); } createHeaderWaypoint() { @@ -21,6 +30,36 @@ class StickyHeader { } }); } + + createPageSectionWaypoints() { + var that = this; + this.pageSections.each(function() { + var currentPageSection = this; + new Waypoint({ + element: currentPageSection, + handler: function(direction) { + if (direction == "down") { + var matchingHeaderLink = currentPageSection.getAttribute("data-matching-link"); + that.headerLinks.removeClass("is-current-link"); + $(matchingHeaderLink).addClass("is-current-link"); + } + }, + offset: "18%" + }); + + new Waypoint({ + element: currentPageSection, + handler: function(direction) { + if (direction == "up") { + var matchingHeaderLink = currentPageSection.getAttribute("data-matching-link"); + that.headerLinks.removeClass("is-current-link"); + $(matchingHeaderLink).addClass("is-current-link"); + } + }, + offset: "-40%" + }); + }); + } } export default StickyHeader; \ No newline at end of file diff --git a/app/assets/styles/modules/_primary-nav.css b/app/assets/styles/modules/_primary-nav.css index 4d522f1..22affe4 100644 --- a/app/assets/styles/modules/_primary-nav.css +++ b/app/assets/styles/modules/_primary-nav.css @@ -48,6 +48,10 @@ font-size: 1rem; padding: 12px 0; background-color: transparent; + + &.is-current-link { + color: #fabb69; + } } } } \ No newline at end of file diff --git a/app/index.html b/app/index.html index 32addd9..f95ecbc 100644 --- a/app/index.html +++ b/app/index.html @@ -28,9 +28,9 @@ @@ -56,7 +56,7 @@

One trip away.

-
+

The first trip we planned was our own.

Ever since, we’ve been working to make travel better for everyone.

@@ -85,7 +85,7 @@

Here’s how we got started&helli

-
+

Our Features

@@ -124,7 +124,7 @@

Survival Kit

-
+

Real Testimonials

diff --git a/app/temp/scripts/App.js b/app/temp/scripts/App.js index a822cca..9a36d9f 100644 --- a/app/temp/scripts/App.js +++ b/app/temp/scripts/App.js @@ -10769,6 +10769,10 @@ var _noframework2 = _interopRequireDefault(_noframework); + var _jquerySmoothScroll = __webpack_require__(6); + + var _jquerySmoothScroll2 = _interopRequireDefault(_jquerySmoothScroll); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -10780,9 +10784,18 @@ this.siteHeader = (0, _jquery2.default)(".site-header"); this.headerTriggerElement = (0, _jquery2.default)(".large-hero__title"); this.createHeaderWaypoint(); + this.pageSections = (0, _jquery2.default)(".page-section"); + this.headerLinks = (0, _jquery2.default)(".primary-nav a"); + this.createPageSectionWaypoints(); + this.addSmoothScrolling(); } _createClass(StickyHeader, [{ + key: 'addSmoothScrolling', + value: function addSmoothScrolling() { + this.headerLinks.smoothScroll(); + } + }, { key: 'createHeaderWaypoint', value: function createHeaderWaypoint() { var that = this; @@ -10797,6 +10810,37 @@ } }); } + }, { + key: 'createPageSectionWaypoints', + value: function createPageSectionWaypoints() { + var that = this; + this.pageSections.each(function () { + var currentPageSection = this; + new Waypoint({ + element: currentPageSection, + handler: function handler(direction) { + if (direction == "down") { + var matchingHeaderLink = currentPageSection.getAttribute("data-matching-link"); + that.headerLinks.removeClass("is-current-link"); + (0, _jquery2.default)(matchingHeaderLink).addClass("is-current-link"); + } + }, + offset: "18%" + }); + + new Waypoint({ + element: currentPageSection, + handler: function handler(direction) { + if (direction == "up") { + var matchingHeaderLink = currentPageSection.getAttribute("data-matching-link"); + that.headerLinks.removeClass("is-current-link"); + (0, _jquery2.default)(matchingHeaderLink).addClass("is-current-link"); + } + }, + offset: "-40%" + }); + }); + } }]); return StickyHeader; @@ -10804,5 +10848,330 @@ exports.default = StickyHeader; +/***/ }, +/* 6 */ +/***/ function(module, exports, __webpack_require__) { + + var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! + * jQuery Smooth Scroll - v2.0.0 - 2016-07-31 + * https://github.com/kswedberg/jquery-smooth-scroll + * Copyright (c) 2016 Karl Swedberg + * Licensed MIT + */ + + (function(factory) { + if (true) { + // AMD. Register as an anonymous module. + !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(2)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + } else if (typeof module === 'object' && module.exports) { + // CommonJS + factory(require('jquery')); + } else { + // Browser globals + factory(jQuery); + } + }(function($) { + + var version = '2.0.0'; + var optionOverrides = {}; + var defaults = { + exclude: [], + excludeWithin: [], + offset: 0, + + // one of 'top' or 'left' + direction: 'top', + + // if set, bind click events through delegation + // supported since jQuery 1.4.2 + delegateSelector: null, + + // jQuery set of elements you wish to scroll (for $.smoothScroll). + // if null (default), $('html, body').firstScrollable() is used. + scrollElement: null, + + // only use if you want to override default behavior + scrollTarget: null, + + // fn(opts) function to be called before scrolling occurs. + // `this` is the element(s) being scrolled + beforeScroll: function() {}, + + // fn(opts) function to be called after scrolling occurs. + // `this` is the triggering element + afterScroll: function() {}, + + // easing name. jQuery comes with "swing" and "linear." For others, you'll need an easing plugin + // from jQuery UI or elsewhere + easing: 'swing', + + // speed can be a number or 'auto' + // if 'auto', the speed will be calculated based on the formula: + // (current scroll position - target scroll position) / autoCoeffic + speed: 400, + + // coefficient for "auto" speed + autoCoefficient: 2, + + // $.fn.smoothScroll only: whether to prevent the default click action + preventDefault: true + }; + + var getScrollable = function(opts) { + var scrollable = []; + var scrolled = false; + var dir = opts.dir && opts.dir === 'left' ? 'scrollLeft' : 'scrollTop'; + + this.each(function() { + var el = $(this); + + if (this === document || this === window) { + return; + } + + if (document.scrollingElement && (this === document.documentElement || this === document.body)) { + scrollable.push(document.scrollingElement); + + return false; + } + + if (el[dir]() > 0) { + scrollable.push(this); + } else { + // if scroll(Top|Left) === 0, nudge the element 1px and see if it moves + el[dir](1); + scrolled = el[dir]() > 0; + + if (scrolled) { + scrollable.push(this); + } + // then put it back, of course + el[dir](0); + } + }); + + if (!scrollable.length) { + this.each(function() { + // If no scrollable elements and has scroll-behavior:smooth because + // "When this property is specified on the root element, it applies to the viewport instead." + // and "The scroll-behavior property of the … body element is *not* propagated to the viewport." + // → https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior + if (this === document.documentElement && $(this).css('scrollBehavior') === 'smooth') { + scrollable = [this]; + } + + // If still no scrollable elements, fall back to , + // if it's in the jQuery collection + // (doing this because Safari sets scrollTop async, + // so can't set it to 1 and immediately get the value.) + if (!scrollable.length && this.nodeName === 'BODY') { + scrollable = [this]; + } + }); + } + + // Use the first scrollable element if we're calling firstScrollable() + if (opts.el === 'first' && scrollable.length > 1) { + scrollable = [scrollable[0]]; + } + + return scrollable; + }; + + $.fn.extend({ + scrollable: function(dir) { + var scrl = getScrollable.call(this, {dir: dir}); + + return this.pushStack(scrl); + }, + firstScrollable: function(dir) { + var scrl = getScrollable.call(this, {el: 'first', dir: dir}); + + return this.pushStack(scrl); + }, + + smoothScroll: function(options, extra) { + options = options || {}; + + if (options === 'options') { + if (!extra) { + return this.first().data('ssOpts'); + } + + return this.each(function() { + var $this = $(this); + var opts = $.extend($this.data('ssOpts') || {}, extra); + + $(this).data('ssOpts', opts); + }); + } + + var opts = $.extend({}, $.fn.smoothScroll.defaults, options); + + var clickHandler = function(event) { + var escapeSelector = function(str) { + return str.replace(/(:|\.|\/)/g, '\\$1'); + }; + + var link = this; + var $link = $(this); + var thisOpts = $.extend({}, opts, $link.data('ssOpts') || {}); + var exclude = opts.exclude; + var excludeWithin = thisOpts.excludeWithin; + var elCounter = 0; + var ewlCounter = 0; + var include = true; + var clickOpts = {}; + var locationPath = $.smoothScroll.filterPath(location.pathname); + var linkPath = $.smoothScroll.filterPath(link.pathname); + var hostMatch = location.hostname === link.hostname || !link.hostname; + var pathMatch = thisOpts.scrollTarget || (linkPath === locationPath); + var thisHash = escapeSelector(link.hash); + + if (thisHash && !$(thisHash).length) { + include = false; + } + + if (!thisOpts.scrollTarget && (!hostMatch || !pathMatch || !thisHash)) { + include = false; + } else { + while (include && elCounter < exclude.length) { + if ($link.is(escapeSelector(exclude[elCounter++]))) { + include = false; + } + } + + while (include && ewlCounter < excludeWithin.length) { + if ($link.closest(excludeWithin[ewlCounter++]).length) { + include = false; + } + } + } + + if (include) { + if (thisOpts.preventDefault) { + event.preventDefault(); + } + + $.extend(clickOpts, thisOpts, { + scrollTarget: thisOpts.scrollTarget || thisHash, + link: link + }); + + $.smoothScroll(clickOpts); + } + }; + + if (options.delegateSelector !== null) { + this + .off('click.smoothscroll', options.delegateSelector) + .on('click.smoothscroll', options.delegateSelector, clickHandler); + } else { + this + .off('click.smoothscroll') + .on('click.smoothscroll', clickHandler); + } + + return this; + } + }); + + $.smoothScroll = function(options, px) { + if (options === 'options' && typeof px === 'object') { + return $.extend(optionOverrides, px); + } + var opts, $scroller, scrollTargetOffset, speed, delta; + var scrollerOffset = 0; + var offPos = 'offset'; + var scrollDir = 'scrollTop'; + var aniProps = {}; + var aniOpts = {}; + + if (typeof options === 'number') { + opts = $.extend({link: null}, $.fn.smoothScroll.defaults, optionOverrides); + scrollTargetOffset = options; + } else { + opts = $.extend({link: null}, $.fn.smoothScroll.defaults, options || {}, optionOverrides); + + if (opts.scrollElement) { + offPos = 'position'; + + if (opts.scrollElement.css('position') === 'static') { + opts.scrollElement.css('position', 'relative'); + } + } + } + + scrollDir = opts.direction === 'left' ? 'scrollLeft' : scrollDir; + + if (opts.scrollElement) { + $scroller = opts.scrollElement; + + if (!(/^(?:HTML|BODY)$/).test($scroller[0].nodeName)) { + scrollerOffset = $scroller[scrollDir](); + } + } else { + $scroller = $('html, body').firstScrollable(opts.direction); + } + + // beforeScroll callback function must fire before calculating offset + opts.beforeScroll.call($scroller, opts); + + scrollTargetOffset = (typeof options === 'number') ? options : + px || + ($(opts.scrollTarget)[offPos]() && + $(opts.scrollTarget)[offPos]()[opts.direction]) || + 0; + + aniProps[scrollDir] = scrollTargetOffset + scrollerOffset + opts.offset; + speed = opts.speed; + + // automatically calculate the speed of the scroll based on distance / coefficient + if (speed === 'auto') { + + // $scroller[scrollDir]() is position before scroll, aniProps[scrollDir] is position after + // When delta is greater, speed will be greater. + delta = Math.abs(aniProps[scrollDir] - $scroller[scrollDir]()); + + // Divide the delta by the coefficient + speed = delta / opts.autoCoefficient; + } + + aniOpts = { + duration: speed, + easing: opts.easing, + complete: function() { + opts.afterScroll.call(opts.link, opts); + } + }; + + if (opts.step) { + aniOpts.step = opts.step; + } + + if ($scroller.length) { + $scroller.stop().animate(aniProps, aniOpts); + } else { + opts.afterScroll.call(opts.link, opts); + } + }; + + $.smoothScroll.version = version; + $.smoothScroll.filterPath = function(string) { + string = string || ''; + + return string + .replace(/^\//, '') + .replace(/(?:index|default).[a-zA-Z]{3,4}$/, '') + .replace(/\/$/, ''); + }; + + // default options + $.fn.smoothScroll.defaults = defaults; + + })); + + + /***/ } /******/ ]); \ No newline at end of file diff --git a/app/temp/styles/styles.css b/app/temp/styles/styles.css index d677cfb..6c69256 100644 --- a/app/temp/styles/styles.css +++ b/app/temp/styles/styles.css @@ -1325,6 +1325,10 @@ Instead edit gulp/templates/sprite */ padding: 12px 0; background-color: transparent; } + + .primary-nav a.is-current-link { + color: #fabb69; + } } .reveal-item { diff --git a/package.json b/package.json index 483f251..ac3095b 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "dependencies": { "ajv": "^5.5.2", "ajv-keywords": "^2.1.1", - "jquery-smooth-scroll": "2.2.0", + "jquery-smooth-scroll": "^2.2.0", "lazysizes": "4.0.0-rc3", "normalize.css": "7.0.0", "picturefill": "3.0.2",