diff --git a/assets/_src/js/_faq.js b/assets/_src/js/_faq.js new file mode 100644 index 0000000..7d93797 --- /dev/null +++ b/assets/_src/js/_faq.js @@ -0,0 +1,63 @@ + +//=include vendor/toc.js +//=include vendor/affix.js + +var Faq = (function(w, d, $) { + + 'use strict' + + var app, _private, _config + + _config = { + faqQuestion: $('.faq__question'), + faqAnswer: $('.faq__answer'), + faqTitle: $('.faq__title'), + faqTocColumn: $('.grid__col--toc'), + faqToc: $('#toc'), + minWidth: 768 // $screen-sm + } + + _private = { + faqToggle: function() { + _config.faqQuestion.click(function() { + $(this).toggleClass('open'); + $(this).next(_config.faqAnswer).toggleClass('open'); + }); + }, + faqTocInit: function() { + _config.faqToc.toc({ + 'selectors': _config.faqTitle, // elements to use as headings + 'container': 'body', // element to find all selectors in + 'highlightOffset': 100, // offset to trigger the next headline + }); + }, + faqTocSticky: function() { + var win = $(window); + + win.on('load resize',function(e) { + if (_private.isWide()) { + _config.faqToc.affix({ + offset: { + top: ( _config.faqTocColumn.offset().top + 20 ), + bottom: ( $('.section-faq:last-child').outerHeight(true) + 40 ) + } + }); + } + }); + }, + isWide: function() { + return $(window).width() >= _config.minWidth; + } + } + + app = { + init: function() { + _private.faqToggle(); + _private.faqTocInit(); + _private.faqTocSticky(); + } + } + + return app + +})(window, document, jQuery) diff --git a/assets/_src/js/ascribe.js b/assets/_src/js/ascribe.js index 0d2ca34..66ff5b2 100644 --- a/assets/_src/js/ascribe.js +++ b/assets/_src/js/ascribe.js @@ -1,8 +1,11 @@ +//=include _faq.js + $(document).ready(function(){ + Faq.init(); + slider(); - featuredFAQ(); marketplaces(); tourNav(); mobileNav(); @@ -39,11 +42,7 @@ $(document).ready(function(){ }); } - function featuredFAQ() { - $('.featured-faqs dt').click(function() { - $(this).next('dd').toggleClass('open'); - }); - } + function marketplaces() { $('.top-tab').click(function(){ $('.top-tab').removeClass('active'); diff --git a/assets/_src/js/vendor/affix.js b/assets/_src/js/vendor/affix.js new file mode 100644 index 0000000..b1d8d2c --- /dev/null +++ b/assets/_src/js/vendor/affix.js @@ -0,0 +1,162 @@ +/* ======================================================================== + * Bootstrap: affix.js v3.3.6 + * http://getbootstrap.com/javascript/#affix + * ======================================================================== + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // AFFIX CLASS DEFINITION + // ====================== + + var Affix = function (element, options) { + this.options = $.extend({}, Affix.DEFAULTS, options) + + this.$target = $(this.options.target) + .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) + .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) + + this.$element = $(element) + this.affixed = null + this.unpin = null + this.pinnedOffset = null + + this.checkPosition() + } + + Affix.VERSION = '3.3.6' + + Affix.RESET = 'affix affix-top affix-bottom' + + Affix.DEFAULTS = { + offset: 0, + target: window + } + + Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) { + var scrollTop = this.$target.scrollTop() + var position = this.$element.offset() + var targetHeight = this.$target.height() + + if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false + + if (this.affixed == 'bottom') { + if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom' + return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom' + } + + var initializing = this.affixed == null + var colliderTop = initializing ? scrollTop : position.top + var colliderHeight = initializing ? targetHeight : height + + if (offsetTop != null && scrollTop <= offsetTop) return 'top' + if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom' + + return false + } + + Affix.prototype.getPinnedOffset = function () { + if (this.pinnedOffset) return this.pinnedOffset + this.$element.removeClass(Affix.RESET).addClass('affix') + var scrollTop = this.$target.scrollTop() + var position = this.$element.offset() + return (this.pinnedOffset = position.top - scrollTop) + } + + Affix.prototype.checkPositionWithEventLoop = function () { + setTimeout($.proxy(this.checkPosition, this), 1) + } + + Affix.prototype.checkPosition = function () { + if (!this.$element.is(':visible')) return + + var height = this.$element.height() + var offset = this.options.offset + var offsetTop = offset.top + var offsetBottom = offset.bottom + var scrollHeight = Math.max($(document).height(), $(document.body).height()) + + if (typeof offset != 'object') offsetBottom = offsetTop = offset + if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element) + if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element) + + var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom) + + if (this.affixed != affix) { + if (this.unpin != null) this.$element.css('top', '') + + var affixType = 'affix' + (affix ? '-' + affix : '') + var e = $.Event(affixType + '.bs.affix') + + this.$element.trigger(e) + + if (e.isDefaultPrevented()) return + + this.affixed = affix + this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null + + this.$element + .removeClass(Affix.RESET) + .addClass(affixType) + .trigger(affixType.replace('affix', 'affixed') + '.bs.affix') + } + + if (affix == 'bottom') { + this.$element.offset({ + top: scrollHeight - height - offsetBottom + }) + } + } + + + // AFFIX PLUGIN DEFINITION + // ======================= + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.affix') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.affix', (data = new Affix(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.affix + + $.fn.affix = Plugin + $.fn.affix.Constructor = Affix + + + // AFFIX NO CONFLICT + // ================= + + $.fn.affix.noConflict = function () { + $.fn.affix = old + return this + } + + + // AFFIX DATA-API + // ============== + + $(window).on('load', function () { + $('[data-spy="affix"]').each(function () { + var $spy = $(this) + var data = $spy.data() + + data.offset = data.offset || {} + + if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom + if (data.offsetTop != null) data.offset.top = data.offsetTop + + Plugin.call($spy, data) + }) + }) + +}(jQuery); diff --git a/assets/_src/js/vendor/toc.js b/assets/_src/js/vendor/toc.js new file mode 100644 index 0000000..cef6942 --- /dev/null +++ b/assets/_src/js/vendor/toc.js @@ -0,0 +1,197 @@ +/*! + * toc - jQuery Table of Contents Plugin + * v0.3.2 + * http://projects.jga.me/toc/ + * copyright Greg Allen 2014 + * MIT License + */ +/*! + * smooth-scroller - Javascript lib to handle smooth scrolling + * v0.1.2 + * https://github.com/firstandthird/smooth-scroller + * copyright First+Third 2014 + * MIT License + */ +//smooth-scroller.js + +(function($) { + $.fn.smoothScroller = function(options) { + options = $.extend({}, $.fn.smoothScroller.defaults, options); + var el = $(this); + + $(options.scrollEl).animate({ + scrollTop: el.offset().top - $(options.scrollEl).offset().top - options.offset + }, options.speed, options.ease, function() { + var hash = el.attr('id'); + + if (hash.length) { + document.location.hash = hash; + } + + el.trigger('smoothScrollerComplete'); + }); + + return this; + }; + + $.fn.smoothScroller.defaults = { + speed: 400, + ease: 'swing', + scrollEl: 'body,html', + offset: 0 + }; + + $('body').on('click', '[data-smoothscroller]', function(e) { + e.preventDefault(); + var href = $(this).attr('href'); + + if (href.indexOf('#') === 0) { + $(href).smoothScroller(); + } + }); +}(jQuery)); + +(function($) { + var verboseIdCache = {}; + $.fn.toc = function(options) { + var self = this; + var opts = $.extend({}, jQuery.fn.toc.defaults, options); + + var container = $(opts.container); + var headings = $(opts.selectors, container); + var activeClassName = opts.activeClass; + + var headingOffsets = function() { + var offsets = []; + headings.each(function(i, heading) { + var $h = $(heading); + offsets.push($h.offset().top - opts.highlightOffset); + }); + return offsets; + }; + + var scrollTo = function(e, callback) { + if (opts.smoothScrolling && typeof opts.smoothScrolling === 'function') { + e.preventDefault(); + var elScrollTo = $(e.target).attr('href'); + + opts.smoothScrolling(elScrollTo, opts, callback); + } + $('li', self).removeClass(activeClassName); + $(e.target).parent().addClass(activeClassName); + }; + + //highlight on scroll + var timeout; + var highlightOnScroll = function(e) { + if (timeout) { + clearTimeout(timeout); + } + timeout = setTimeout(function() { + var top = $(window).scrollTop(), + highlighted, closest = Number.MAX_VALUE, + index = 0 + offsets = headingOffsets(); + + for (var i = 0, c = offsets.length; i < c; i++) { + var currentClosest = Math.abs(offsets[i] - top); + if (currentClosest < closest) { + index = i; + closest = currentClosest; + } + } + + $('li', self).removeClass(activeClassName); + highlighted = $('li:eq(' + index + ')', self).addClass(activeClassName); + opts.onHighlight(highlighted); + }, 50); + }; + if (opts.highlightOnScroll) { + $(window).bind('scroll', highlightOnScroll); + highlightOnScroll(); + } + + return this.each(function() { + //build TOC + var el = $(this); + var ul = $(opts.listType); + + headings.each(function(i, heading) { + var $h = $(heading); + + var anchorName = opts.anchorName(i, heading, opts.prefix); + + //add anchor + if (heading.id !== anchorName) { + var anchor = $('').attr('id', anchorName).insertBefore($h); + } + + //build TOC item + var a = $('') + .text(opts.headerText(i, heading, $h)) + .attr('href', '#' + anchorName) + .bind('click', function(e) { + $(window).unbind('scroll', highlightOnScroll); + scrollTo(e, function() { + $(window).bind('scroll', highlightOnScroll); + }); + el.trigger('selected', $(this).attr('href')); + }); + + var li = $('
  • ') + .addClass(opts.itemClass(i, heading, $h, opts.prefix)) + .append(a); + + ul.append(li); + }); + el.html(ul); + }); + }; + + + jQuery.fn.toc.defaults = { + container: 'body', + listType: '
      ', + selectors: 'h1,h2,h3', + smoothScrolling: function(target, options, callback) { + $(target).smoothScroller({ + offset: options.scrollToOffset + }).on('smoothScrollerComplete', function() { + callback(); + }); + }, + scrollToOffset: 0, + prefix: 'toc', + activeClass: 'toc-active', + onHighlight: function() {}, + highlightOnScroll: true, + highlightOffset: 100, + anchorName: function(i, heading, prefix) { + if (heading.id.length) { + return heading.id; + } + + var candidateId = $(heading).text().replace(/[^a-z0-9]/ig, ' ').replace(/\s+/g, '-').toLowerCase(); + if (verboseIdCache[candidateId]) { + var j = 2; + + while (verboseIdCache[candidateId + j]) { + j++; + } + candidateId = candidateId + '-' + j; + + } + verboseIdCache[candidateId] = true; + + return prefix + '-' + candidateId; + }, + headerText: function(i, heading, $heading) { + return $heading.text(); + }, + itemClass: function(i, heading, $heading, prefix) { + return prefix + '-' + $heading[0].tagName.toLowerCase(); + } + + }; + +})(jQuery); diff --git a/assets/_src/less/ascribe.less b/assets/_src/less/ascribe.less index 8fff20c..1dc9095 100644 --- a/assets/_src/less/ascribe.less +++ b/assets/_src/less/ascribe.less @@ -31,6 +31,7 @@ @import 'ascribe/_team.less'; @import 'ascribe/_blog.less'; @import 'ascribe/_testimonials.less'; +@import 'ascribe/_faq.less'; @import '_page-api.less'; @@ -372,45 +373,6 @@ } } -.faq { - - > h1 { margin-top: 0; } - - dl,dt,dd { - margin: 0; - padding: 0; - } - - dd:not(:last-child) { - margin-bottom: @spacer; - } - - dt { - &:extend(.bold); - } - - .featured-faqs { - - dt { - color: @pink; - cursor: pointer; - } - dd { - max-height:0; - overflow-y:hidden; - transition: .2s ease-out; - margin-bottom: @spacer; - - &.open { - max-height: 800px; - } - } - } - .regular-faqs { - - } -} - .values { padding-bottom: @spacer; diff --git a/assets/_src/less/ascribe/_faq.less b/assets/_src/less/ascribe/_faq.less new file mode 100644 index 0000000..d953aaa --- /dev/null +++ b/assets/_src/less/ascribe/_faq.less @@ -0,0 +1,156 @@ + +.section-faq { + padding-top: @spacer; + padding-bottom: @spacer; +} + +.faq { + margin-left: 20px; +} + + +// +// FAQ Section Title +// +.faq__title { + &:extend(.h2); + margin-top: 0; +} + + +// +// FAQ Question +// +.faq__question { + &:extend(.bold); + display: block; + margin-top: 0; + margin-bottom: (@spacer / 2); + cursor: pointer; + + .caret { + margin-left: -20px; + margin-right: 10px; + } + + &.open .caret { + transform: rotate(90deg); + } +} + + +// +// FAQ Answer +// +.faq__answer { + transition: .2s ease-out; + transform-origin: top; + height: 0; + overflow: hidden; + margin-left: 0; + + &.open { + animation: openQuestion .15s ease-out forwards; + } +} + +@keyframes openQuestion { + 0% { + transform: scaleY(0); + opacity: 0; + } + 100% { + transform: scaleY(1); + opacity: 1; + height: 100%; + } +} + + +// +// Featured FAQ modifier +// +.faq--featured { + .faq__question { + color: @pink; + } +} + +.caret { + display: inline-block; + width: 0; + height: 0; + border-style: solid; + border-width: 5px 0 5px 6px; + border-color: transparent transparent transparent @greySocial; + transition: .15s ease-out; +} + +.grid__col--toc { + position: relative; + + @media (@screen-sm) { + flex: 0 0 33% !important; + } +} + + +// +// Table of Contents +// +#toc { + margin-top: @spacer; + + &.affix { + top: 0; + padding-top: @spacer; + } + + ul { + &:extend(.list-unstyled all); + + li, + a { + line-height: @line-height-base; + } + + li { + display: inline-block; + + @media (@screen-sm) { + display: block; + } + } + + a { + &:extend(.h4); + color: @link-color; + display: block; + margin: 0; + padding: 8px 12px; + + @media (@screen-sm) { + padding: 6px 0; + } + + &:active, + &:focus { + outline: 0; + } + } + + a:hover, + a:focus, + .toc-active a { + color: @link-hover-color; + } + } +} + + +// +// Affix.js helpers +// +.affix { + position: fixed !important; +} diff --git a/assets/_src/less/ascribe/_typography.less b/assets/_src/less/ascribe/_typography.less index 7c138cc..f52a52a 100644 --- a/assets/_src/less/ascribe/_typography.less +++ b/assets/_src/less/ascribe/_typography.less @@ -105,6 +105,11 @@ h1, h2, h3, h4, h5, h6, color: @black; } +.page-title { + margin-top: 0; + text-align: center; +} + // Reset fonts for relevant elements diff --git a/content-main.php b/content-main.php index b52fb41..3a8bbbc 100644 --- a/content-main.php +++ b/content-main.php @@ -1,4 +1,26 @@ -
      - loopSubtemplates(); ?> + +
      + + +
      + +

      + +
      +
      +
      +
      + +
      + loopSubtemplates(); ?> +
      + +
      + loopSubtemplates(); + + } ?> +
      diff --git a/controller/classes/Subtemplate.php b/controller/classes/Subtemplate.php index 8b7f3ab..4d1164b 100644 --- a/controller/classes/Subtemplate.php +++ b/controller/classes/Subtemplate.php @@ -664,43 +664,63 @@ class Subtemplate { return $result; } + + + // + // Subtemplate: FAQs + // public function faq($subtemplateTitle) { - $featuredFAQ = '"; + } + + // create ID for section jumps from lowercased & sanitized title + $subtemplateTitleID = strtolower(sanitize_html_class($subtemplateTitle)); + + $result = "
      +

      {$subtemplateTitle}

      {$featuredFAQ} {$regularFAQ}
      "; return $result; } + + public function values($subtemplateTitle) { $values = ''; if (have_rows('ascribe_values')) { @@ -724,6 +744,8 @@ class Subtemplate { return $result; } + + public function careers($subtemplateTitle) { $args = array( 'post_type' => 'career', @@ -752,6 +774,8 @@ class Subtemplate { return $result; } + + public function mediaDetail($subtemplateTitle) { $image = get_sub_field('image')['url']; diff --git a/package.json b/package.json index 31e84e0..899bc1b 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ }, "dependencies": { "normalize-css": ">=2.3.1", - "normalize-opentype.css": ">=0.2.4" + "normalize-opentype.css": ">=0.2.4", + "toc": "jgallen23/toc" }, "devDependencies": { "browser-sync": "^2.10.0",