JSFiddle - React, Tailwind, and code Playground

by Yaroslav Samardak

HTML

<div id="state">
	<span class="title">Initializing</span>
	<div class="bar"></div>
</div>

<input type="file" id="file" />

CSS

body {
	padding: 0;
	margin: 0;
}

input {
	margin: 0 1em 1em;
}

#state {
	position: relative;
	overflow: hidden;
	background: #FFF;
	border-radius: 2px;
	box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12);
	margin: 1em;
	text-align: center;
	text-transform: uppercase;
	color: #FFF;
	padding: 1em .2em;
	background: #43A047;
}
#state.error {
	background: #F44336;
}

#state .bar {
	position: absolute;
	left: 0;
	top: 0;
	bottom: 0;
	width: 0;
	background: rgba(255,255,255,.3);
}

JavaScript

var eq = function() {

	var self = this;

	self.queue = {};
	self.force = {};
	self.fired = [];

	return {

		fire: function(event) {
			var queue = self.queue[event];

			if (typeof queue !== 'undefined') {
				while (queue.length) {
					(queue.shift())();
				}

				self.fired[event] = true;
			}

			queue = self.force[event];
			if (typeof queue !== 'undefined') {
				for (var i = 0; i < queue.length; i++) {
					queue[i]();
				}
			}
		},

		onSingle: function(event, callback) {
			if (self.fired[event] === true) {
				return callback();
			}

			if (typeof self.queue[event] === 'undefined') {
				self.queue[event] = [];
			}

			self.queue[event].push(callback);
		},

		on: function(event, callback) {
			if (typeof self.force[event] === 'undefined') {
				self.force[event] = [];
			}

			self.force[event].push(callback);
		}

	};

}();

function xhrPost(url, data, onProgressChanged, callback) {
	var xhr = new XMLHttpRequest();
	xhr.open('POST', url, true);
	xhr.onloadend = function() {
		if (xhr.status != 200) {
			callback(xhr.response, false, xhr);
		} else {
			callback(xhr.response, true, xhr);
		}
	};

	xhr.upload.onprogress = function(e) {
		onProgressChanged(Math.round((e.loaded / e.total) * 100));
	};

	var formData = new FormData();
	formData.append('file', data);
	xhr.send(formData);
}

eq.on('online', function() {
	title.innerText = 'Online';
	card.classList.remove('error');
});
eq.on('offline', function() {
	title.innerText = 'Offline';
	card.classList.add('error');
});

(function() {
	var oldState = -1;

	setInterval(function() {
		console.log(oldState, navigator.onLine);
		if (oldState !== navigator.onLine) {
			oldState = navigator.onLine;
			eq.fire(oldState ? 'online' : 'offline');
		}
	}, 250);
	
	var card = document.getElementById('state');
	var title = document.querySelector('#state .title')[0];
	var bar = document.querySelector('#state .bar')[0];
	var file = document.getElementById('file');
	
	file.onchange = function(e)...