Tiget - Tags are better than folders

by joplomacedo

HTML

<div class="layer is-inactive">
	<div class="box">
		<p class="logo">Tiget</p>
		
		<div class="box_content">
			<div class="input_wrapper">
				<input class="input input--suggest">
				<input class="input input--real">
			</div>
			
			<div class="tags_box">
				<span class="tag is-added">web-development</span>
				<span class="tag is-added">web-developments</span>
				<span class="tag">frontend</span>
				<span class="tag">react</span>
				<span class="tag">learn</span>
				<span class="tag">vue</span>
				<span class="tag">courses</span>
				<span class="tag">backend</span>
				<span class="tag">design</span>
				<span class="tag">misc</span>
				<span class="tag">...</span>
			</div>
			
			<button>Done</button>
		</div>
		
		<div class="shortcuts">
			<p class="shortcuts__title">Shortcuts</p>
			<table class="shortcuts__table">
				<tr>
					<td class="">
						<span class="shortcuts__key">CMD</span> + <span class="shortcuts__key">T</span>
					</td>
					<td>
						Open/Close Tiget
					</td>
				</tr>
				<tr>
					<td class="">
						<span class="shortcuts__key">Esc</span>
					</td>
					<td>
						Close Tiget
					</td>
				</tr>
			<table>
		</div>
		
	</div>
</div>

CSS

*,
*:after,
*:before {
  box-sizing: border-box;
  font: inherit;
  padding: 0;
  margin: 0;
  border: 0;
  border-radius: 0;
  background-color: transparent;
  outline: none;
  color: inherit;
  text-decoration: none;
}

ul,
ol,
li {
  list-style: none;
}

input,
select,
textarea {
  max-width: 100%;
}

.layer {
	position: fixed;
	top: 0;
	bottom: 0;
	left: 0;
	right: 0;
	font-family: system-ui, sans-serif;
	display: flex;
	justify-content: center;
	align-items: flex-start;
	padding: 2em;
	background-color: rgba(0,0,0,.1);
}


.layer.is-inactive {
	display: none;
}

.box {
	max-width: 30em;
}

.logo {
	font-size: 13px;
	font-weight: 600;
	margin-bottom: 3px;
}

.box_content {
	border-radius: 3px;
}

.input_wrapper {
	position: relative;
	margin-bottom: 1em;
}

.input {
	width: 100%;
	border: 1px solid #ccc;
	padding: 1em;
	border-radius: 2px;
}

.input--suggest {
	position: absolute;
	top: 0;
	left: 0;
	pointer-events: none;
	color: #aaa;
}

.input--real {
	position: relative;
	background-color: transparent;
}

.tags_box {
	line-height: 2.1;
}


.tag {
	display: inline-block;
	line-height: 1.4;
	background: #eee;
	padding: .1em .3em;
	border-radius: 2px;
	cursor: pointer;
	margin-right: .1em;
}

.shortcuts {
	position: fixed;
	bottom: 3em;
	right: 3em;
	font-size: .8em;
}

.shortcuts__title {
	font-weight: 600;
	margin-bottom: .15em;
}

.shortcuts__key {
    font-size: .84em;
    padding: .15em .4em;
    display: inline-block;
    background: #cecece;
    border-radius: 2px;
    font-weight: 600;
    color: black;
}

JavaScript

//TODO
// merge tags. and  suggest merging tags when theyre very similar

//base
const w = window;
const d = document;

function isNodeList( $el ) {
	return NodeList.prototype.isPrototypeOf($el);
}

function q( arg0, arg1 ) {
	return (arg1 || d).querySelectorAll(arg0);
}

function qs( arg0, arg1 ) {
	return (arg1 || d).querySelector(arg0);
}

function ael( $el, evt, cb, uc ) {
	(isNodeList($el) ? $el : [$el]).forEach(node => {
		node.addEventListener(evt, cb, uc);
	});
}

function activate($el) {
	(isNodeList($el) ? $el : [$el]).forEach(node => {
		node.classList.remove('is-inactive');
		node.classList.add('is-active');
	});
}

function deactivate($el) {
	(isNodeList($el) ? $el : [$el]).forEach(node => {
		node.classList.remove('is-active');
		node.classList.add('is-inactive');
	});
}

function togglevate( $el ) {
	(isNodeList($el) ? $el : [$el]).forEach(node => {
		node.classList.toggle('is-active');
		node.classList.toggle('is-inactive');
	});
}


//code
const $layer = qs('.layer');

const key_space = 'Space';
const key_t = 'KeyT';
const key_tab = 'Tab';
const key_enter = 'Enter';
const key_escape = 'Escape';

const keydowned_keys = {};

ael(w, 'keydown', ( e ) => {
	keydowned_keys[e.code] = 1;
	
	if ( key_space in keydowned_keys &&
	 	 key_t in keydowned_keys
	) {
		togglevate($layer);
	}
	
	if ( e.code === key_escape ) {
		deactivate($layer);
	}
});

ael(w, 'keyup', ( e ) => {
	delete keydowned_keys[e.code];
});


const tags = [
	'web-development',
	'web-developments',
	'frontend',
	'react',
	'learn',
	'vue',
	'courses',
	'backend',
	'design',
	'misc'
].sort();

let suggested_tag = '';
const selected_tags = [];

const $input = qs('.input--real');
const $suggest = qs('.input--suggest');

function clearSuggestion () {
	suggested_tag = false;
	$suggest.value = '';
}


ael($input, 'keydown', function ( e ) {
	e.stopPropagation();
	
	if ( e.code == key_tab ) {
		e.preventDefault();
	
		if ( suggested_tag ) {
			$input.value =...