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");
}
}