JSFiddle - React, Tailwind, and code Playground

by danya_postfactum

HTML

<div class="pages">
    <div class="page"></div>
    <div class="page"></div>
    <div class="page"></div>
    <div class="page"></div>
</div>
<ul class="menu">
    <li>Page 1</li>
    <li>Page 2</li>
    <li>Page 3</li>
    <li>Page 4</li>
</ul>

CSS

html, body{
    min-height: 100%;
    width: 100%;
    margin: 0;
    padding: 0;
}
html{
    height: 100%;
}
.pages{
    height: 100%;
    overflow: visible;
    position: relative;
    top: 0;
    transition: top 0.5s;
}
.page{
    height: 100%;
    min-height: 100vh;
}
.page:nth-child(1){
    background: aqua;
}
.page:nth-child(2){
    background: greenyellow;
}
.page:nth-child(3){
    background: yellow;
}
.page:nth-child(4){
    background: blueviolet;
}
.menu{
    position: fixed;
    display: none;
    left: 10px;
    top: 50%;
    transform: translateY(-50%);
}
.menu li{
    cursor: pointer;
}
.menu .active{
    color: red;
}

JavaScript

function PageController() {
	this.pageContainer = document.querySelector('.pages');
	this.pages = this.pageContainer.children;
	this.menuContainer = document.querySelector('.menu');
	this.menuItems = this.menuContainer.children;
	this.current = -1;
	this.addEventListeners();

	document.body.style.height = '100%';
	document.body.style.overflow = 'hidden';
	this.menuContainer.style.display = 'block';
	document.body.scrollTop = 0;

	this.scrollTo(0);
}

PageController.prototype.addEventListeners = function() {
	var controller = this;
	window.addEventListener('wheel', function(e) {
		if (e.deltaY > 0) {
			controller.scrollDown();
		} else {
			controller.scrollUp();
		}
	});
	document.addEventListener('keydown', function(e) {
		switch (e.keyCode) {
			case 33: // DOM_VK_PAGE_UP
			case 38: // DOM_VK_UP
				controller.scrollUp();
				break;
			case 34: // DOM_VK_PAGE_DOWN
			case 40: // DOM_VK_DOWN
			case 32: // DOM_VK_SPACE
				controller.scrollDown();
				break;
			case 36: // DOM_VK_HOME
				controller.scrollTo(0);
				break;
			case 35: // DOM_VK_END
				controller.scrollTo(controller.pages.length - 1);
				break;
			default:
				return;
		}
		e.preventDefault();
	});
	for (var i = 0; i < this.menuItems.length; i++) {
		this.menuItems[i].setAttribute('data-index', i);
		this.menuItems[i].addEventListener('click', function(e) {
			e.preventDefault();
			controller.scrollTo(this.getAttribute('data-index'));
		});
	}
};

PageController.prototype.scrollTo = function(index) {
	index = Math.min(this.pages.length -1, Math.max(0, index)); // limit to [0;length-1]
	if (this.current == index)
		return false;
	if (this.current != -1)
		this.menuItems[this.current].classList.remove('active');
	this.current = index;
	this.menuItems[this.current].classList.add('active');
	this.pageContainer.style.top = (- this.current * 100) + '%';
	this
};

PageController.prototype.scrollUp = function() {
	return this.scrollTo(this.current - 1);
};

PageController.prototype.scrollDown =...