Add Scrollspy for docs

This commit is contained in:
Lucas 2019-12-11 08:46:32 +07:00
parent b90ffcd3e5
commit 1c11c4975b
15 changed files with 310 additions and 60 deletions

View file

@ -158,12 +158,16 @@ main > aside li a svg {
vertical-align: middle;
}
main > aside a:focus,
main > aside a.secondary:focus {
background-color: transparent;
color: var(--primary-hover);
}
main > aside a.active,
main > aside a.active:hover {
color: var(--primary);
}
main > aside details {
padding-bottom: .25rem;
border-bottom: none;
@ -184,12 +188,6 @@ main > aside details[open] summary {
color: var(--h3);
}
[role=document] section > h1,
[role=document] section > h2,
[role=document] section > h3 {
line-height: 1;
}
/**
* Docs: Documentation
*/
@ -395,7 +393,7 @@ body > nav {
box-shadow: 0px 1px 0 var(--nav-border);
}
body > nav li a {
body > nav a {
border-radius: 0;
}
@ -423,7 +421,7 @@ body > nav ul:first-of-type li:nth-of-type(2) {
/**
* Docs: Theme switcher
*/
button.switcher {
.switcher {
position: fixed;
right: 0.5rem;
bottom: 1rem;
@ -436,7 +434,7 @@ button.switcher {
box-shadow: var(--card-shadow);
}
button.switcher::after {
.switcher::after {
display: inline-block;
width: 1rem;
height: 1rem;
@ -448,7 +446,7 @@ button.switcher::after {
transition: transform 0.2s ease-in-out;
}
button.switcher i {
.switcher i {
display: inline-block;
max-width: 0;
padding: 0;
@ -458,27 +456,27 @@ button.switcher i {
white-space: nowrap;
}
button.switcher:hover, button.switcher:focus {
.switcher:hover, .switcher:focus {
max-width: 100%;
transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out, color 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
}
button.switcher:hover::after {
.switcher:hover::after {
transform: rotate(180deg);
}
button.switcher:hover i {
.switcher:hover i {
max-width: 100%;
padding: 0 0.5rem 0 0.25rem;
transition: max-width 0.2s ease-in-out, padding 0.2s ease-in-out;
}
button.switcher:focus {
.switcher:focus {
box-shadow: var(--card-shadow), 0 0 0 0.2rem var(--secondary-focus);
}
@media (min-width: 576px) {
button.switcher {
.switcher {
right: 1rem;
}
}

File diff suppressed because one or more lines are too long

View file

@ -79,7 +79,7 @@
<li><a href="#tooltips" class="secondary">Tooltips</a></li>
</ul>
</details>
<details>
<details open>
<summary>Extend</summary>
<ul>
<li>

View file

@ -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

File diff suppressed because one or more lines are too long

View file

@ -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
View 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
View 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);
}
})();

View file

@ -13,7 +13,7 @@ body > nav {
background-color: var(--nav-background);
box-shadow: 0px 1px 0 var(--nav-border);
li a {
a {
border-radius: 0;
}

View file

@ -2,7 +2,7 @@
* Docs: Theme switcher
*/
button.switcher {
.switcher {
position: fixed;
right: $spacing-gutter/2;
bottom: $spacing-gutter;

View file

@ -2,17 +2,19 @@
* Docs: Typography
*/
section > hgroup {
margin-bottom: $spacing-typography*2;
}
a[role=button] {
margin-right: $spacing-gutter/4;
margin-bottom: $spacing-typography;
}
[role=document] {
section > h1,
section > h2,
section > h3 {
line-height: 1;
}
}
section > hgroup {
margin-bottom: $spacing-typography*2;
}
a[role=button] {
margin-right: $spacing-gutter/4;
margin-bottom: $spacing-typography;
}
[role=document] {
section > h1,
section > h2,
section > h3 {
line-height: 1;
}
}

View file

@ -40,12 +40,14 @@ main > aside {
}
}
a,
a.secondary {
&:focus {
background-color: transparent;
color: var(--primary-hover);
}
a.secondary:focus {
background-color: transparent;
color: var(--primary-hover);
}
a.active,
a.active:hover {
color: var(--primary);
}
details {
@ -68,11 +70,3 @@ main > aside {
}
}
}
[role=document] {
section > h1,
section > h2,
section > h3 {
line-height: 1;
}
}

View file

@ -125,8 +125,6 @@
// Docs: Forms
//
#forms {
div.grid {
grid-row-gap: 0;
}
#forms div.grid {
grid-row-gap: 0;
}

View file

@ -80,6 +80,7 @@ div[role="document"] section a[href*="//"]:not([href*="https://picocss.com"]):no
content: '';
}
// Form grid
//