JSFiddle - React, Tailwind, and code Playground

by positroid

HTML

<div class="control-panel">
  <label>
    <input type="checkbox" id="enableSwitch" checked> Enable at Night
  </label><br>
  <label>Segment Delay (ms):
    <input type="number" id="segmentDelay" value="200">
  </label><br>
  <label>On Time (ms):
    <input type="number" id="onTime" value="3000">
  </label><br>
  <button onclick="triggerSensor('bottom')">Motion at Bottom</button>
  <button onclick="triggerSensor('top')">Motion at Top</button>
</div>
<div id="leds">
  <p>LED Segments:</p>
  <!-- Creating LED segments explicitly -->
  <div class="led" id="led0"></div>
  <div class="led" id="led1"></div>
  <div class="led" id="led2"></div>
  <div class="led" id="led3"></div>
  <div class="led" id="led4"></div>
  <div class="led" id="led5"></div>
  <div class="led" id="led6"></div>
  <div class="led" id="led7"></div>
  <div the="led" id="led8"></div>
  <div class="led" id="led9"></div>
</div>

CSS

body {
  font-family: Arial, sans-serif;
  padding: 20px;
  background-color: #f4f4f9;
  color: #333;
}
label, button {
  font-size: 16px;
  margin: 10px 0;
}
input[type="number"], input[type="checkbox"] {
  margin-left: 5px;
}
.led {
  width: 30px;
  height: 30px;
  margin: 5px;
  display: inline-block;
  background-color: grey;
  transition: background-color 0.3s ease;
}
.led.on {
  background-color: #ffdd57; /* Yellow LED on color */
  box-shadow: 0 0 8px #ffdd57;
}
#leds {
  margin-top: 20px;
  padding: 10px;
  background: #eee;
  border-radius: 8px;
  display: flex;
  flex-wrap: wrap;
  justify-content: start;
  max-width: 480px;
}
.control-panel {
  margin-bottom: 20px;
}

JavaScript

let topIndex = 10, bottomIndex = -1, disableIndex = -1;
let swipe = true, on = false;
let lastSensor = false; // false: lower, true: upper
let bottomSensorState = false, topSensorState = false;
let minSegmentId = 0, maxSegmentId = 9;
let lastTime = Date.now(), lastScanTime = Date.now(), lastSwitchTime = Date.now();
let enableSwitchState;

function triggerSensor(location) {
  let currentTime = Date.now();
  lastScanTime = currentTime;
  lastSwitchTime = currentTime;
  enableSwitchState = document.getElementById('enableSwitch').checked;

  if (location === 'bottom') {
    bottomSensorState = true;
    topSensorState = false;
  } else {
    topSensorState = true;
    bottomSensorState = false;
  }
  checkSensors();
  topSensorState = false;
  bottomSensorState = false;
}

function updateSegments() {

  if (topIndex <= maxSegmentId) {
    document.getElementById('led' + topIndex).classList.add('on');
    topIndex++;
  }
  if (bottomIndex >= minSegmentId) {
    document.getElementById('led' + bottomIndex).classList.add('on');
    bottomIndex--;
  }

  if (swipe) {
    if (disableIndex > bottomIndex && bottomIndex != -1) {
      disableIndex = maxSegmentId + 1;
    }
    if (disableIndex <= maxSegmentId && disableIndex >= 0) {
      document.getElementById('led' + disableIndex).classList.remove('on');
      disableIndex++;
    }
  } else {
    if (disableIndex < topIndex && topIndex != maxSegmentId + 1) {
      disableIndex = -1;
    }
    if (disableIndex >= minSegmentId && disableIndex <= maxSegmentId) {
      document.getElementById('led' + disableIndex).classList.remove('on');
      disableIndex--;
    }
  }
}

function checkSensors() {
  if (bottomSensorState !== false || topSensorState !== false) {
    lastSensor = !topSensorState;

    if (enableSwitchState == false) return false; 

    // Position the indices for a correct on-swipe
    if (topSensorState && topIndex == (maxSegmentId+1)) {
      topIndex = minSegmentId;
    }
    if (bottomSensorState &&...