JSFiddle - React, Tailwind, and code Playground

by Alexandru Gatea

HTML

<div class="time-selector">
  <div class="time-scale" id="scaleDigits">
    <input type="range" id="timeInput" min="0" max="1440" step="15" value="720">
  </div>
  <div class="time-controls">
    <button class="time-control decrease" id="decreaseTime"> - 15 min</button>
    <span class="current-time">Current Time: <span id="ctH">12</span>:<span id="ctM">00</span></span>
    <button class="time-control increase" id="increaseTime">+ 15 min</button>
  </div>

</div>

SCSS

*, *:after, *:before {
	box-sizing: border-box;
	margin: 0;
	padding: 0;
	font-family: "Lato", sans-serif;
	font-weight: 700;
}

$brandLight: #A59FB8;
$brandAccent:#42B98B;

$scaleWidth: 600px;
$minDigitsHeight: 6px;
$hrDigitsHeight: 10px;
$rangeThumbSize: 16px;
$rangeThumbColor: $brandAccent;
$rangeThumbBorderThickness: 2px;
$rangeThumbBorderColor: #fff;



body {
	background: #212121;
}

.time{
	&-selector{
		max-width: $scaleWidth;
		margin: 100px auto;
	}
	
	&-scale {
		display: flex;
		justify-content: space-between;
		align-items: center;
		position: relative;
		padding: 0 8px;
		
		&:before {
			content: "";
			display: block;
			width: calc(100% - 16px);
			height: 1px;
			top: 50%;
			left: 50%;
			transform: translate(-50%, -50%);
			background: $brandLight;
			position: absolute;
		}
		
		.digit {
			width: 1px;
			height: $minDigitsHeight;
			background: $brandLight;
			border-radius: 10px;
			
			&[data-time] {
				height: $hrDigitsHeight;
				position: relative;
				
				&:before {
					content: attr(data-time);
					position: absolute;
					bottom: 100%;
					left: 50%;
					transform: translate(-50%, -50%);
					font-size: 10px;
					color: $brandLight;
				}
			}
		}
	}
	
	&-controls {
		display: flex;
		align-items: center;
		justify-content: center;
		padding: 15px 0;
		
		
		.time-control {
			background: transparent;
			border: none;
			color: $brandLight;
			cursor: pointer;
			padding: 10px 20px;
			font-size: 14px;
			user-select: none;
			
			&.disabled {
				opacity: 0.3;
				pointer-events: none;
				cursor: default;
			}
		}
		
		.current-time {
			color: $brandAccent;
			padding: 0 30px;
			text-align: center;
			display: flex;
			justify-content: space-evenly;
			
			span {
				display: block;
				min-width: 20px;
				margin: 0 3px;
			}
		}
	}
}

.time-selector [type="range"] {
	position: absolute;
	width: 100%;
	left: 0;
	right: 0;
	z-index: 1;
}




/* style the range */
input[type=range] {
  -webkit-appearance: none;
  width:...

JavaScript

const scaleDigits = document.getElementById("scaleDigits");
const digitsInterval = 15;
const dayMinutes = 60 * 24;
const numberOfDigits = dayMinutes / digitsInterval;

let timeInput = document.getElementById('timeInput');
let decreaseTime = document.getElementById("decreaseTime");
let increaseTime = document.getElementById("increaseTime");


// generate scale digits
for (let i = 0; i < numberOfDigits + 1; i++) {

  let digit = document.createElement("span");
  digit.classList.add("digit");

  if (i % 4 === 0) {
    digit.setAttribute("data-time", i / 4);
  }

  scaleDigits.appendChild(digit);
}


// adjust the current time shown when the slider moves 
timeInput.addEventListener("input", () => {
  setTime();
});

// adjust the current time shown when the buttons are clicked
decreaseTime.addEventListener("click", () => {
  timeInput.stepDown();
  setTime();
});

increaseTime.addEventListener("click", () => {
  timeInput.stepUp();
  setTime();
});




function setTime() {
  let time = parseInt(timeInput.value);
  let hours = Math.floor(time / 60);
  let minutes = Math.floor(time % 60);


  if (hours < 10) {
    hours = "0" + hours;
  }
  if (minutes < 10) {
    minutes = "0" + minutes;
  }

  if (time === 1440) {
    hours = "23";
    minutes = "59";
  }

  document.getElementById("ctH").innerHTML = hours;
  document.getElementById("ctM").innerHTML = minutes;

  if (time === 0) {
    decreaseTime.classList.add("disabled");
  } else if (time === 1440) {
    increaseTime.classList.add("disabled");
  } else {
    increaseTime.classList.remove("disabled");
    decreaseTime.classList.remove("disabled");
  }
}