mirror of
https://github.com/picocss/pico.git
synced 2025-04-20 16:46:14 -04:00
Add Scrollspy for docs
This commit is contained in:
parent
b90ffcd3e5
commit
1c11c4975b
15 changed files with 310 additions and 60 deletions
|
@ -1,4 +1,13 @@
|
|||
/*!
|
||||
* Add some magic to Pico docs
|
||||
*
|
||||
* Pico.css - https://picocss.com
|
||||
* Copyright 2019 - Licensed under MIT
|
||||
*/
|
||||
|
||||
// @prepros-append src/aside.js
|
||||
// @prepros-append src/theme-switcher.js
|
||||
// @prepros-append src/grid.js
|
||||
// @prepros-append src/color-picker.js
|
||||
// @prepros-append src/most-visible.js
|
||||
// @prepros-append src/scrollspy.js
|
||||
|
|
2
docs/js/pico.docs.min.js
vendored
2
docs/js/pico.docs.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -7,13 +7,16 @@
|
|||
|
||||
(function() {
|
||||
|
||||
// Close details if aside > nav have a scrollbar
|
||||
var nav = document.querySelector("aside nav");
|
||||
var navDetails = document.querySelectorAll("aside details");
|
||||
if (window.matchMedia("(min-width: 992px)").matches) {
|
||||
|
||||
if (nav.clientHeight < nav.scrollHeight) {
|
||||
for (var i = 1; i < navDetails.length; i++) {
|
||||
navDetails[i].removeAttribute("open");
|
||||
// Close details if aside > nav have a scrollbar
|
||||
var nav = document.querySelector("aside nav");
|
||||
var navDetails = document.querySelectorAll("aside details");
|
||||
|
||||
if (nav.clientHeight < nav.scrollHeight) {
|
||||
for (var i = 1; i < navDetails.length; i++) {
|
||||
navDetails[i].removeAttribute("open");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
161
docs/js/src/most-visible.js
Normal file
161
docs/js/src/most-visible.js
Normal file
|
@ -0,0 +1,161 @@
|
|||
/**
|
||||
* Most Visible v1.4.0
|
||||
*
|
||||
* @author Andy Palmer <andy@andypalmer.me>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
(function (root, factory) {
|
||||
// Universal Module Definition
|
||||
/* jshint strict:false */
|
||||
/* global define: false, module: false */
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define([], function () {
|
||||
return factory(root);
|
||||
});
|
||||
} else if (typeof module === 'object' && module.exports) {
|
||||
module.exports = factory(root);
|
||||
} else {
|
||||
root.mostVisible = factory(root);
|
||||
}
|
||||
}(typeof self !== 'undefined' ? self : this, function (window) {
|
||||
/* jshint unused: vars */
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* MostVisible constructor
|
||||
*
|
||||
* @param {NodeList|string} elements
|
||||
* @param {Object} options
|
||||
* @constructor
|
||||
*/
|
||||
function MostVisible(elements, options) {
|
||||
if (!(this instanceof MostVisible)) {
|
||||
return (new MostVisible(elements, options)).getMostVisible();
|
||||
}
|
||||
|
||||
if (typeof elements === 'string') {
|
||||
elements = document.querySelectorAll(elements);
|
||||
}
|
||||
|
||||
this.elements = elements;
|
||||
this.options = extend({}, MostVisible.defaults, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* MostVisible default options
|
||||
*
|
||||
* @namespace
|
||||
* @property {object} defaults Default options hash.
|
||||
* @property {boolean} defaults.percentage Whether to calculate visibility as a percentage of height.
|
||||
* @property {number} defaults.offset An offset to take into account when calculating visibility.
|
||||
*/
|
||||
MostVisible.defaults = {
|
||||
percentage: false,
|
||||
offset: 0
|
||||
};
|
||||
|
||||
MostVisible.prototype = {
|
||||
/**
|
||||
* Returns the most visible element from the instance's NodeList.
|
||||
*
|
||||
* @returns {Element} Most visible element.
|
||||
*/
|
||||
getMostVisible: function () {
|
||||
var element = null,
|
||||
viewportHeight = document.documentElement.clientHeight,
|
||||
maxVisible = 0;
|
||||
|
||||
for (var i = 0; i < this.elements.length; i++) {
|
||||
var currentVisible = this.getVisibleHeight(this.elements[i], viewportHeight);
|
||||
|
||||
if (currentVisible > maxVisible) {
|
||||
maxVisible = currentVisible;
|
||||
element = this.elements[i];
|
||||
}
|
||||
}
|
||||
|
||||
return element;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the visible height of an element.
|
||||
*
|
||||
* @param {Element} element Element to check the visibility of.
|
||||
* @param {number} viewportHeight
|
||||
* @returns {number} Visible height of the element in pixels or a percentage of the element's total height.
|
||||
*/
|
||||
getVisibleHeight: function (element, viewportHeight) {
|
||||
var rect = element.getBoundingClientRect(),
|
||||
rectTopOffset = rect.top - this.options.offset,
|
||||
rectBottomOffset = rect.bottom - this.options.offset,
|
||||
height = rect.bottom - rect.top,
|
||||
visible = {
|
||||
top: rectTopOffset >= 0 && rectTopOffset < viewportHeight,
|
||||
bottom: rectBottomOffset > 0 && rectBottomOffset < viewportHeight
|
||||
},
|
||||
visiblePx = 0;
|
||||
|
||||
if (visible.top && visible.bottom) {
|
||||
// Whole element is visible
|
||||
visiblePx = height;
|
||||
} else if (visible.top) {
|
||||
visiblePx = viewportHeight - rect.top;
|
||||
} else if (visible.bottom) {
|
||||
visiblePx = rectBottomOffset;
|
||||
} else if (height > viewportHeight && rectTopOffset < 0) {
|
||||
var absTop = Math.abs(rectTopOffset);
|
||||
|
||||
if (absTop < height) {
|
||||
// Part of the element is visible
|
||||
visiblePx = height - absTop;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.percentage) {
|
||||
return (visiblePx / height) * 100;
|
||||
}
|
||||
|
||||
return visiblePx;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
MostVisible.makeJQueryPlugin = function ($) {
|
||||
if (!$) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.fn.mostVisible = function (options) {
|
||||
var instance = new MostVisible(this.get(), options);
|
||||
return this.filter(instance.getMostVisible());
|
||||
};
|
||||
};
|
||||
*/
|
||||
|
||||
// Try adding the jQuery plugin to window.jQuery
|
||||
// MostVisible.makeJQueryPlugin(window.jQuery);
|
||||
|
||||
/**
|
||||
* Extends obj by adding the properties of all other objects passed to the function.
|
||||
*
|
||||
* @param {...Object} obj
|
||||
* @returns {Object} The extended object.
|
||||
*/
|
||||
function extend(obj) {
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
for (var key in arguments[i]) {
|
||||
if (arguments[i].hasOwnProperty(key)) {
|
||||
obj[key] = arguments[i][key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
//noinspection JSAnnotator
|
||||
return MostVisible;
|
||||
|
||||
}));
|
85
docs/js/src/scrollspy.js
Normal file
85
docs/js/src/scrollspy.js
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*!
|
||||
* Scrollspy
|
||||
* Automatically update nav targets based on scroll position
|
||||
*
|
||||
* Require `most-visible.js` from https://github.com/andyexeter/most-visible
|
||||
*
|
||||
* Pico.css - https://picocss.com
|
||||
* Copyright 2019 - Licensed under MIT
|
||||
*/
|
||||
|
||||
(function() {
|
||||
|
||||
/**
|
||||
* Config
|
||||
*/
|
||||
var scrollspy = {
|
||||
interval: 75, // Delay for detect scroll stop
|
||||
sections: '[role="document"] > section', // Target for sections
|
||||
nav: 'main aside nav', // Target for nav
|
||||
active: 'active', // .class for active element
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Init
|
||||
*/
|
||||
|
||||
if (window.matchMedia("(min-width: 992px)").matches) {
|
||||
activeNav();
|
||||
|
||||
scrollStop(
|
||||
function () {
|
||||
activeNav()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set active section in nav
|
||||
*/
|
||||
|
||||
function activeNav() {
|
||||
|
||||
// Get active section
|
||||
var section = mostVisible(scrollspy.sections).getAttribute('id');
|
||||
|
||||
// Remove all active states
|
||||
var allActive = document.querySelectorAll(scrollspy.nav + ' a.' + scrollspy.active);
|
||||
for (var i = 0; i < allActive.length; i++) {
|
||||
allActive[i].classList.remove(scrollspy.active);
|
||||
}
|
||||
|
||||
// Set active state
|
||||
var active = document.querySelector(scrollspy.nav + ' a[href="#' + section + '"]');
|
||||
active.classList.add(scrollspy.active);
|
||||
|
||||
// Open details parent
|
||||
active.parentNode.parentNode.parentNode.setAttribute('open', '');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Scroll stop
|
||||
* Detect when the user stop scrolling
|
||||
* Source: https://vanillajstoolkit.com/helpers/scrollstop/
|
||||
*
|
||||
* @param {Function} callback The function to run after scrolling
|
||||
*
|
||||
*/
|
||||
|
||||
function scrollStop(callback) {
|
||||
var isScrolling;
|
||||
window.addEventListener('scroll', function (event) {
|
||||
window.clearTimeout(isScrolling);
|
||||
isScrolling = setTimeout(function() {
|
||||
callback();
|
||||
}, scrollspy.interval);
|
||||
}, false);
|
||||
}
|
||||
|
||||
})();
|
Loading…
Add table
Add a link
Reference in a new issue