JSFiddle - React, Tailwind, and code Playground

by jcubed111

HTML

<template id="sliderTemplate">
     <div class="vbar">
        <div class="topper"></div>
        <div class="sliderOuter">
            <div class="sliderInner"></div>
            <div class="sliderMarker"></div>
        </div>
        <div class="numberWrapper">
            <input class="numberBox" />
            <div class="arrowWrapper">
                <div class="arrow arrowUp">&#11205;</div>
                <div class="arrow arrowDown">&#11206;</div>
            </div>
        </div>
    </div>
 </template>

SCSS

@import url('https://fonts.googleapis.com/css?family=Inconsolata:400,700&display=swap');

*{
    box-sizing: border-box;
}

body{
    background: #181818;
}

.vbar{
    height: 376px; // This must be even! Otherwise positional math comes out weid.
    border-radius: 8px;
    border: 1px solid #000;
    background: #222;
    width: 90px;
    display: flex;
    flex-direction: column;
    padding: 5px;
    
    .topper,
    .numberWrapper{
        border-radius: 4px;
        overflow: hidden;
        height: 0px;
        flex-grow: 1;
        border: 1px solid #000;
    }
    
    .sliderOuter{
        $vMargin: 12px;
        height: 256px + $vMargin*2;
        position: relative;
        
        .sliderInner{
            box-sizing: content-box;
            height: 256px;
            background: linear-gradient(#ff0000, #000000);
            position: absolute;
            border: 1px solid #000;
            top: $vMargin - 1px;
            left: 3px;
            right: 3px;
            border-radius: 3px;
        }
        
        .sliderMarker{
            box-sizing: content-box;
            position: absolute;
            left: 0px;
            right: 0px;
            margin-top: $vMargin - 7px;
            top: 180px;
            height: 1px;
            border: 7px solid #ccc;
            background: transparent;
            border-top-color: transparent;
            border-bottom-color: transparent;
        }
    }
    
    .topper{
        background: rgb(75, 0, 0);
    }
    
    .numberWrapper{
        display: flex;
        
        .numberBox{
            margin: 0;
            box-sizing: border-box;
            border: 0px none;
            width: 0px;
            flex-shrink: 1;
            flex-grow: 1;
            background: #181818;
            color: #aaa;
            font-size: 23px;
            font-family: Inconsolata, monospace;
            padding: 5px 8px;
            letter-spacing: 1px;
        }
        
        .arrowWrapper{
      ...

JavaScript

function rgb(...args) { return 'rgb(' + args.map(a => ~~a).join(',') + ')'; }

class View{
	constructor() {
    	this.el = this.el();
    }
    
    $(s) {
    	return this.el.querySelector(s);
    }
}

class Color{
	constructor() {
        this.isRgb = true;
        this.value = [0, 0, 0, 255];
    }
    
    r() { return this.asRgb()[0]; }
    g() { return this.asRgb()[1]; }
    b() { return this.asRgb()[2]; }
    h() { return this.asHsv()[0]; }
    s() { return this.asHsv()[1]; }
    v() { return this.asHsv()[2]; }
    a() { return this.asRgb()[3]; }
    
    setR(v) {
    	this.convertToRgb();
        this.value[0] = v;
    }
    setG(v) {
    	this.convertToRgb();
        this.value[1] = v;
    }
    setB(v) {
    	this.convertToRgb();
        this.value[2] = v;
    }
    setH(v) {
    	this.convertToHsv();
        this.value[0] = v;
    }
    setS(v) {
    	this.convertToHsv();
        this.value[1] = v;
    }
    setV(v) {
    	this.convertToHsv();
        this.value[2] = v;
    }
    setA(v) {
    	this.value[3] = v;
    }
    
    convertToRgb() {
    	this.value = this.asRgb();
        this.isRgb = true;
    }
    convertToHsv() {
    	this.value = this.asHsv();
        this.isRgb = false;
    }

    asRgb() {
    	if(this.isRgb) {
        	return this.value.slice();
        }else{
        	let h, s, v;
            let [r, g, b, a] = this.value;
        	let max = Math.max(r, g, b);
        	let min = Math.min(r, g, b);
            if(max == min) {
            	h = 0;
            }else if(max == r) {
            	h = 60 * (0 + (g - b) / (max - min));
            }else if(max == g) {
            	h = 60 * (2 + (b - r) / (max - min));
            }else if(max == b) {
            	h = 60 * (4 + (r - g) / (max - min));
            }
            if(max == 0) {
            	s = 0;
            }else{
            	s = (max - min) / max * 100;
            }
            v = max / 255 * 100;
            return [+h.toFixed(0), +s.toFixed(1), +v.toFixed(1), a];
    ...