Add tags
This commit is contained in:
@ -1,27 +1,23 @@
|
||||
import jump from '../deps/jump'
|
||||
import { select, selectAll, easeOutQuint } from '../deps/utils'
|
||||
|
||||
const menu = select('.hamburger')
|
||||
const links = select('.sidebar__links')
|
||||
const sections = selectAll('.sidebar__section')
|
||||
const ACTIVE_CLASS = 'is-active'
|
||||
|
||||
const toggle = () => {
|
||||
const els = [menu, links]
|
||||
els.forEach(el => el.classList.toggle(ACTIVE_CLASS))
|
||||
menu.setAttribute('aria-expanded', menu.classList.contains(ACTIVE_CLASS) ? 'true' : 'false')
|
||||
if (window.innerWidth <= 991) {
|
||||
const els = [menu, links]
|
||||
els.forEach(el => el.classList.toggle(ACTIVE_CLASS))
|
||||
menu.setAttribute('aria-expanded', menu.classList.contains(ACTIVE_CLASS) ? 'true' : 'false')
|
||||
}
|
||||
}
|
||||
|
||||
menu.addEventListener('click', toggle)
|
||||
|
||||
links.addEventListener('click', e => {
|
||||
setTimeout(toggle, 40)
|
||||
if (e.target.classList.contains('sidebar__link')) {
|
||||
e.preventDefault()
|
||||
jump(e.target.getAttribute('href'), {
|
||||
duration: 750,
|
||||
offset: window.innerWidth <= 768 ? -64 : -32,
|
||||
easing: easeOutQuint
|
||||
})
|
||||
setTimeout(toggle, 100)
|
||||
}
|
||||
})
|
||||
|
||||
@ -35,4 +31,13 @@ document.addEventListener('click', e => {
|
||||
}
|
||||
})
|
||||
|
||||
EventHub.on('Tag.click', data => {
|
||||
sections.forEach(section => {
|
||||
section.style.display = 'block'
|
||||
if (section.dataset.type !== data.type && data.type !== 'all') {
|
||||
section.style.display = 'none'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
export default { toggle }
|
||||
13
src/js/components/Snippet.js
Normal file
13
src/js/components/Snippet.js
Normal file
@ -0,0 +1,13 @@
|
||||
import { selectAll } from '../deps/utils'
|
||||
|
||||
const snippets = selectAll('.snippet')
|
||||
EventHub.on('Tag.click', data => {
|
||||
snippets.forEach(snippet => {
|
||||
snippet.style.display = 'block'
|
||||
if (data.type === 'all') return
|
||||
const tags = selectAll('.tags__tag', snippet)
|
||||
if (!selectAll('.tags__tag', snippet).some(el => el.dataset.type === data.type)) {
|
||||
snippet.style.display = 'none'
|
||||
}
|
||||
})
|
||||
})
|
||||
14
src/js/components/Tag.js
Normal file
14
src/js/components/Tag.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { select, selectAll, on } from '../deps/utils'
|
||||
|
||||
const tagButtons = selectAll('button.tags__tag')
|
||||
|
||||
const onClick = function() {
|
||||
tagButtons.forEach(button => button.classList.remove('is-active'))
|
||||
this.classList.add('is-active')
|
||||
|
||||
EventHub.emit('Tag.click', {
|
||||
type: this.dataset.type
|
||||
})
|
||||
}
|
||||
|
||||
tagButtons.forEach(button => on(button, 'click', onClick))
|
||||
@ -1,196 +0,0 @@
|
||||
;(function(global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined'
|
||||
? (module.exports = factory())
|
||||
: typeof define === 'function' && define.amd ? define(factory) : (global.Jump = factory())
|
||||
})(this, function() {
|
||||
'use strict'
|
||||
|
||||
// Robert Penner's easeInOutQuad
|
||||
|
||||
// find the rest of his easing functions here: http://robertpenner.com/easing/
|
||||
// find them exported for ES6 consumption here: https://github.com/jaxgeller/ez.js
|
||||
|
||||
var easeInOutQuad = function easeInOutQuad(t, b, c, d) {
|
||||
t /= d / 2
|
||||
if (t < 1) return c / 2 * t * t + b
|
||||
t--
|
||||
return -c / 2 * (t * (t - 2) - 1) + b
|
||||
}
|
||||
|
||||
var _typeof =
|
||||
typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol'
|
||||
? function(obj) {
|
||||
return typeof obj
|
||||
}
|
||||
: function(obj) {
|
||||
return obj &&
|
||||
typeof Symbol === 'function' &&
|
||||
obj.constructor === Symbol &&
|
||||
obj !== Symbol.prototype
|
||||
? 'symbol'
|
||||
: typeof obj
|
||||
}
|
||||
|
||||
var jumper = function jumper() {
|
||||
// private variable cache
|
||||
// no variables are created during a jump, preventing memory leaks
|
||||
|
||||
var element = void 0 // element to scroll to (node)
|
||||
|
||||
var start = void 0 // where scroll starts (px)
|
||||
var stop = void 0 // where scroll stops (px)
|
||||
|
||||
var offset = void 0 // adjustment from the stop position (px)
|
||||
var easing = void 0 // easing function (function)
|
||||
var a11y = void 0 // accessibility support flag (boolean)
|
||||
|
||||
var distance = void 0 // distance of scroll (px)
|
||||
var duration = void 0 // scroll duration (ms)
|
||||
|
||||
var timeStart = void 0 // time scroll started (ms)
|
||||
var timeElapsed = void 0 // time spent scrolling thus far (ms)
|
||||
|
||||
var next = void 0 // next scroll position (px)
|
||||
|
||||
var callback = void 0 // to call when done scrolling (function)
|
||||
|
||||
// scroll position helper
|
||||
|
||||
function location() {
|
||||
return window.scrollY || window.pageYOffset
|
||||
}
|
||||
|
||||
// element offset helper
|
||||
|
||||
function top(element) {
|
||||
return element.getBoundingClientRect().top + start
|
||||
}
|
||||
|
||||
// rAF loop helper
|
||||
|
||||
function loop(timeCurrent) {
|
||||
// store time scroll started, if not started already
|
||||
if (!timeStart) {
|
||||
timeStart = timeCurrent
|
||||
}
|
||||
|
||||
// determine time spent scrolling so far
|
||||
timeElapsed = timeCurrent - timeStart
|
||||
|
||||
// calculate next scroll position
|
||||
next = easing(timeElapsed, start, distance, duration)
|
||||
|
||||
// scroll to it
|
||||
window.scrollTo(0, next)
|
||||
|
||||
// check progress
|
||||
timeElapsed < duration
|
||||
? window.requestAnimationFrame(loop) // continue scroll loop
|
||||
: done() // scrolling is done
|
||||
}
|
||||
|
||||
// scroll finished helper
|
||||
|
||||
function done() {
|
||||
// account for rAF time rounding inaccuracies
|
||||
window.scrollTo(0, start + distance)
|
||||
|
||||
// if scrolling to an element, and accessibility is enabled
|
||||
if (element && a11y) {
|
||||
// add tabindex indicating programmatic focus
|
||||
element.setAttribute('tabindex', '-1')
|
||||
|
||||
// focus the element
|
||||
element.focus()
|
||||
}
|
||||
|
||||
// if it exists, fire the callback
|
||||
if (typeof callback === 'function') {
|
||||
callback()
|
||||
}
|
||||
|
||||
// reset time for next jump
|
||||
timeStart = false
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
function jump(target) {
|
||||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}
|
||||
|
||||
// resolve options, or use defaults
|
||||
duration = options.duration || 1000
|
||||
offset = options.offset || 0
|
||||
callback = options.callback // "undefined" is a suitable default, and won't be called
|
||||
easing = options.easing || easeInOutQuad
|
||||
a11y = options.a11y || false
|
||||
|
||||
// cache starting position
|
||||
start = location()
|
||||
|
||||
// resolve target
|
||||
switch (typeof target === 'undefined' ? 'undefined' : _typeof(target)) {
|
||||
// scroll from current position
|
||||
case 'number':
|
||||
element = undefined // no element to scroll to
|
||||
a11y = false // make sure accessibility is off
|
||||
stop = start + target
|
||||
break
|
||||
|
||||
// scroll to element (node)
|
||||
// bounding rect is relative to the viewport
|
||||
case 'object':
|
||||
element = target
|
||||
stop = top(element)
|
||||
break
|
||||
|
||||
// scroll to element (selector)
|
||||
// bounding rect is relative to the viewport
|
||||
case 'string':
|
||||
element = document.querySelector(target)
|
||||
stop = top(element)
|
||||
break
|
||||
}
|
||||
|
||||
// resolve scroll distance, accounting for offset
|
||||
distance = stop - start + offset
|
||||
|
||||
// resolve duration
|
||||
switch (_typeof(options.duration)) {
|
||||
// number in ms
|
||||
case 'number':
|
||||
duration = options.duration
|
||||
break
|
||||
|
||||
// function passed the distance of the scroll
|
||||
case 'function':
|
||||
duration = options.duration(distance)
|
||||
break
|
||||
}
|
||||
|
||||
// start the loop
|
||||
window.requestAnimationFrame(loop)
|
||||
}
|
||||
|
||||
// expose only the jump method
|
||||
return jump
|
||||
}
|
||||
|
||||
// export singleton
|
||||
|
||||
var singleton = jumper()
|
||||
|
||||
return (() => {
|
||||
let scrolling
|
||||
const end = () => (scrolling = false)
|
||||
return (to, options = {}) => {
|
||||
if (scrolling) return
|
||||
const scrollY = window.scrollY || window.pageYOffset
|
||||
if (to !== '.header') location.hash = to
|
||||
scroll(0, scrollY)
|
||||
scrolling = true
|
||||
setTimeout(end, options.duration || 0)
|
||||
return singleton(to, options)
|
||||
}
|
||||
})()
|
||||
})
|
||||
@ -1,8 +1,34 @@
|
||||
export const select = s => document.querySelector(s)
|
||||
export const selectAll = s => [].slice.call(document.querySelectorAll(s))
|
||||
export const select = (s, parent = document) => parent.querySelector(s)
|
||||
|
||||
export const selectAll = (s, parent = document) => [].slice.call(parent.querySelectorAll(s))
|
||||
|
||||
export const scrollY = () => window.scrollY || window.pageYOffset
|
||||
|
||||
export const easeOutQuint = (t, b, c, d) => c * ((t = t / d - 1) * t ** 4 + 1) + b
|
||||
|
||||
export const on = (el, evt, fn, opts = {}) => {
|
||||
const delegatorFn = e => e.target.matches(opts.target) && fn.call(e.target, e)
|
||||
el.addEventListener(evt, opts.target ? delegatorFn : fn, opts.options || false)
|
||||
if (opts.target) return delegatorFn
|
||||
}
|
||||
|
||||
export const createEventHub = () => ({
|
||||
hub: Object.create(null),
|
||||
emit(event, data) {
|
||||
;(this.hub[event] || []).forEach(handler => handler(data))
|
||||
},
|
||||
on(event, handler) {
|
||||
if (!this.hub[event]) this.hub[event] = []
|
||||
this.hub[event].push(handler)
|
||||
},
|
||||
off(event, handler) {
|
||||
const i = (this.hub[event] || []).findIndex(h => h === handler)
|
||||
if (i > -1) this.hub[event].splice(i, 1)
|
||||
}
|
||||
})
|
||||
|
||||
window.EventHub = createEventHub()
|
||||
|
||||
/*
|
||||
* Make iOS behave normally.
|
||||
*/
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
// Deps
|
||||
import 'normalize.css'
|
||||
import 'prismjs'
|
||||
import feather from 'feather-icons'
|
||||
feather.replace()
|
||||
|
||||
// CSS
|
||||
import '../css/deps/prism.css'
|
||||
@ -10,5 +12,7 @@ import '../css/index.scss'
|
||||
import './deps/polyfills'
|
||||
|
||||
// Components
|
||||
import Menu from './components/Menu'
|
||||
import Sidebar from './components/Sidebar'
|
||||
import BackToTopButton from './components/BackToTopButton'
|
||||
import Tag from './components/Tag'
|
||||
import Snippet from './components/Snippet'
|
||||
|
||||
Reference in New Issue
Block a user