mirror of
https://github.com/okalachev/flix.git
synced 2025-08-17 09:06:11 +00:00
Create book and deploy it to the website (#6)
* Create book structure. * Add workflow for linting the markdown using markdownlint. * Add workflow for building the book with mdBook and deploying to the website. * Restyle mdBook and support GitHub-style alerts. * Add images zooming. * Add index, firmware structure and gyroscope articles.
This commit is contained in:
281
docs/zoom.js
Normal file
281
docs/zoom.js
Normal file
@@ -0,0 +1,281 @@
|
||||
/* https://github.com/spinningarrow/zoom-vanilla.js
|
||||
|
||||
The MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
+function () { "use strict";
|
||||
var OFFSET = 80
|
||||
|
||||
// From http://youmightnotneedjquery.com/#offset
|
||||
function offset(element) {
|
||||
var rect = element.getBoundingClientRect()
|
||||
var scrollTop = window.pageYOffset ||
|
||||
document.documentElement.scrollTop ||
|
||||
document.body.scrollTop ||
|
||||
0
|
||||
var scrollLeft = window.pageXOffset ||
|
||||
document.documentElement.scrollLeft ||
|
||||
document.body.scrollLeft ||
|
||||
0
|
||||
return {
|
||||
top: rect.top + scrollTop,
|
||||
left: rect.left + scrollLeft
|
||||
}
|
||||
}
|
||||
|
||||
function zoomListener() {
|
||||
var activeZoom = null
|
||||
var initialScrollPosition = null
|
||||
var initialTouchPosition = null
|
||||
|
||||
function listen() {
|
||||
document.body.addEventListener('click', function (event) {
|
||||
if (event.target.getAttribute('data-action') !== 'zoom' ||
|
||||
event.target.tagName !== 'IMG') return
|
||||
|
||||
zoom(event)
|
||||
})
|
||||
}
|
||||
|
||||
function zoom(event) {
|
||||
event.stopPropagation()
|
||||
|
||||
if (document.body.classList.contains('zoom-overlay-open')) return
|
||||
|
||||
if (event.metaKey || event.ctrlKey) return openInNewWindow()
|
||||
|
||||
closeActiveZoom({ forceDispose: true })
|
||||
|
||||
activeZoom = vanillaZoom(event.target)
|
||||
activeZoom.zoomImage()
|
||||
|
||||
addCloseActiveZoomListeners()
|
||||
}
|
||||
|
||||
function openInNewWindow() {
|
||||
window.open(event.target.getAttribute('data-original') ||
|
||||
event.target.currentSrc ||
|
||||
event.target.src,
|
||||
'_blank')
|
||||
}
|
||||
|
||||
function closeActiveZoom(options) {
|
||||
options = options || { forceDispose: false }
|
||||
if (!activeZoom) return
|
||||
|
||||
activeZoom[options.forceDispose ? 'dispose' : 'close']()
|
||||
removeCloseActiveZoomListeners()
|
||||
activeZoom = null
|
||||
}
|
||||
|
||||
function addCloseActiveZoomListeners() {
|
||||
// todo(fat): probably worth throttling this
|
||||
window.addEventListener('scroll', handleScroll)
|
||||
document.addEventListener('click', handleClick)
|
||||
document.addEventListener('keyup', handleEscPressed)
|
||||
document.addEventListener('touchstart', handleTouchStart)
|
||||
document.addEventListener('touchend', handleClick)
|
||||
}
|
||||
|
||||
function removeCloseActiveZoomListeners() {
|
||||
window.removeEventListener('scroll', handleScroll)
|
||||
document.removeEventListener('keyup', handleEscPressed)
|
||||
document.removeEventListener('click', handleClick)
|
||||
document.removeEventListener('touchstart', handleTouchStart)
|
||||
document.removeEventListener('touchend', handleClick)
|
||||
}
|
||||
|
||||
function handleScroll(event) {
|
||||
if (initialScrollPosition === null) initialScrollPosition = window.pageYOffset
|
||||
var deltaY = initialScrollPosition - window.pageYOffset
|
||||
if (Math.abs(deltaY) >= 40) closeActiveZoom()
|
||||
}
|
||||
|
||||
function handleEscPressed(event) {
|
||||
if (event.keyCode == 27) closeActiveZoom()
|
||||
}
|
||||
|
||||
function handleClick(event) {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
closeActiveZoom()
|
||||
}
|
||||
|
||||
function handleTouchStart(event) {
|
||||
initialTouchPosition = event.touches[0].pageY
|
||||
event.target.addEventListener('touchmove', handleTouchMove)
|
||||
}
|
||||
|
||||
function handleTouchMove(event) {
|
||||
if (Math.abs(event.touches[0].pageY - initialTouchPosition) <= 10) return
|
||||
closeActiveZoom()
|
||||
event.target.removeEventListener('touchmove', handleTouchMove)
|
||||
}
|
||||
|
||||
return { listen: listen }
|
||||
}
|
||||
|
||||
var vanillaZoom = (function () {
|
||||
var fullHeight = null
|
||||
var fullWidth = null
|
||||
var overlay = null
|
||||
var imgScaleFactor = null
|
||||
|
||||
var targetImage = null
|
||||
var targetImageWrap = null
|
||||
var targetImageClone = null
|
||||
|
||||
function zoomImage() {
|
||||
var img = document.createElement('img')
|
||||
img.onload = function () {
|
||||
fullHeight = Number(img.height)
|
||||
fullWidth = Number(img.width)
|
||||
zoomOriginal()
|
||||
}
|
||||
img.src = targetImage.currentSrc || targetImage.src
|
||||
}
|
||||
|
||||
function zoomOriginal() {
|
||||
targetImageWrap = document.createElement('div')
|
||||
targetImageWrap.className = 'zoom-img-wrap'
|
||||
targetImageWrap.style.position = 'absolute'
|
||||
targetImageWrap.style.top = offset(targetImage).top + 'px'
|
||||
targetImageWrap.style.left = offset(targetImage).left + 'px'
|
||||
|
||||
targetImageClone = targetImage.cloneNode()
|
||||
targetImageClone.style.visibility = 'hidden'
|
||||
|
||||
targetImage.style.width = targetImage.offsetWidth + 'px'
|
||||
targetImage.parentNode.replaceChild(targetImageClone, targetImage)
|
||||
|
||||
document.body.appendChild(targetImageWrap)
|
||||
targetImageWrap.appendChild(targetImage)
|
||||
|
||||
targetImage.classList.add('zoom-img')
|
||||
targetImage.setAttribute('data-action', 'zoom-out')
|
||||
|
||||
overlay = document.createElement('div')
|
||||
overlay.className = 'zoom-overlay'
|
||||
|
||||
document.body.appendChild(overlay)
|
||||
|
||||
calculateZoom()
|
||||
triggerAnimation()
|
||||
}
|
||||
|
||||
function calculateZoom() {
|
||||
targetImage.offsetWidth // repaint before animating
|
||||
|
||||
var originalFullImageWidth = fullWidth
|
||||
var originalFullImageHeight = fullHeight
|
||||
|
||||
var maxScaleFactor = originalFullImageWidth / targetImage.width
|
||||
|
||||
var viewportHeight = window.innerHeight - OFFSET
|
||||
var viewportWidth = window.innerWidth - OFFSET
|
||||
|
||||
var imageAspectRatio = originalFullImageWidth / originalFullImageHeight
|
||||
var viewportAspectRatio = viewportWidth / viewportHeight
|
||||
|
||||
if (originalFullImageWidth < viewportWidth && originalFullImageHeight < viewportHeight) {
|
||||
imgScaleFactor = maxScaleFactor
|
||||
} else if (imageAspectRatio < viewportAspectRatio) {
|
||||
imgScaleFactor = (viewportHeight / originalFullImageHeight) * maxScaleFactor
|
||||
} else {
|
||||
imgScaleFactor = (viewportWidth / originalFullImageWidth) * maxScaleFactor
|
||||
}
|
||||
}
|
||||
|
||||
function triggerAnimation() {
|
||||
targetImage.offsetWidth // repaint before animating
|
||||
|
||||
var imageOffset = offset(targetImage)
|
||||
var scrollTop = window.pageYOffset
|
||||
|
||||
var viewportY = scrollTop + (window.innerHeight / 2)
|
||||
var viewportX = (window.innerWidth / 2)
|
||||
|
||||
var imageCenterY = imageOffset.top + (targetImage.height / 2)
|
||||
var imageCenterX = imageOffset.left + (targetImage.width / 2)
|
||||
|
||||
var translateY = Math.round(viewportY - imageCenterY)
|
||||
var translateX = Math.round(viewportX - imageCenterX)
|
||||
|
||||
var targetImageTransform = 'scale(' + imgScaleFactor + ')'
|
||||
var targetImageWrapTransform =
|
||||
'translate(' + translateX + 'px, ' + translateY + 'px) translateZ(0)'
|
||||
|
||||
targetImage.style.webkitTransform = targetImageTransform
|
||||
targetImage.style.msTransform = targetImageTransform
|
||||
targetImage.style.transform = targetImageTransform
|
||||
|
||||
targetImageWrap.style.webkitTransform = targetImageWrapTransform
|
||||
targetImageWrap.style.msTransform = targetImageWrapTransform
|
||||
targetImageWrap.style.transform = targetImageWrapTransform
|
||||
|
||||
document.body.classList.add('zoom-overlay-open')
|
||||
}
|
||||
|
||||
function close() {
|
||||
document.body.classList.remove('zoom-overlay-open')
|
||||
document.body.classList.add('zoom-overlay-transitioning')
|
||||
|
||||
targetImage.style.webkitTransform = ''
|
||||
targetImage.style.msTransform = ''
|
||||
targetImage.style.transform = ''
|
||||
|
||||
targetImageWrap.style.webkitTransform = ''
|
||||
targetImageWrap.style.msTransform = ''
|
||||
targetImageWrap.style.transform = ''
|
||||
|
||||
if (!'transition' in document.body.style) return dispose()
|
||||
|
||||
targetImageWrap.addEventListener('transitionend', dispose)
|
||||
targetImageWrap.addEventListener('webkitTransitionEnd', dispose)
|
||||
}
|
||||
|
||||
function dispose() {
|
||||
targetImage.removeEventListener('transitionend', dispose)
|
||||
targetImage.removeEventListener('webkitTransitionEnd', dispose)
|
||||
|
||||
if (!targetImageWrap || !targetImageWrap.parentNode) return
|
||||
|
||||
targetImage.classList.remove('zoom-img')
|
||||
targetImage.style.width = ''
|
||||
targetImage.setAttribute('data-action', 'zoom')
|
||||
|
||||
targetImageClone.parentNode.replaceChild(targetImage, targetImageClone)
|
||||
targetImageWrap.parentNode.removeChild(targetImageWrap)
|
||||
overlay.parentNode.removeChild(overlay)
|
||||
|
||||
document.body.classList.remove('zoom-overlay-transitioning')
|
||||
}
|
||||
|
||||
return function (target) {
|
||||
targetImage = target
|
||||
return { zoomImage: zoomImage, close: close, dispose: dispose }
|
||||
}
|
||||
}())
|
||||
|
||||
zoomListener().listen()
|
||||
}()
|
Reference in New Issue
Block a user