<section class="buttons">
<button class="start">
turn on
</button>
<button class="end">
turn off
</button>
</section>
<section class="lights">
<div id='green' class="light green"></div>
<div id='yellow' class="light yellow"></div>
<div id='red' class="light red"></div>
</section>
section.buttons {
display: flex;
justify-content: center;
align-items: center;
margin-top: 20px;
gap: 8px;
button {
font-size: 20px;
}
}
.lights {
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
padding: 20px;
border-radius: 12px;
background-color: #06402b;
width: fit-content;
margin: 20px auto;
}
.light {
width: 100px;
height: 100px;
border: 2px solid black;
border-radius: 50%;
background-color: grey;
}
.active {
&.green {
background-color: green;
}
&.yellow {
background-color: yellow;
}
&.red {
background-color: red;
}
}
// state control
enum States {
green = "green",
yellow = "yellow",
red = "red"
}
const machine = {
initial: States.green,
states: {
green: {
on: { TIMER: { target: States.yellow, delay: 3000 } }
},
yellow: {
on: { TIMER: { target: States.red, delay: 1000 } }
},
red: {
on: { TIMER: { target: States.green, delay: 2000 } }
}
}
};
function createMachine(machine) {
return {
state: machine.initial,
preState: null,
init() {
this.state = machine.initial;
this.preState = null;
},
transition(state: States, action) {
return machine.states[state].on[action];
},
send(action) {
const nextState = this.transition(this.state, action);
this.preState = this.state;
this.state = nextState.target;
}
};
}
const service = createMachine(machine);
// ui
const startButton = document.querySelector("button.start");
const endButton = document.querySelector("button.end");
const [green, yellow, red] = document.querySelectorAll(".light");
const lights = { green, yellow, red };
let timer: ReturnType<typeof setTimeout>;
const updateState = (state, preState) => {
lights[preState]?.classList.remove("active");
lights[state]?.classList.add("active");
const { delay } = service.transition(state, "TIMER");
timer = setTimeout(() => {
service.send("TIMER");
updateState(service.state, service.preState);
}, delay);
};
startButton.addEventListener("click", () => {
if (timer) clearTimeout(timer);
updateState(service.state, service.preState);
});
endButton.addEventListener("click", () => {
clearTimeout(timer);
lights[service.state]?.classList.remove("active");
service.init();
});
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.