JSFiddle - React, Tailwind, and code Playground

by Arnold Daniels

HTML

<div class="calculator">
  <div class="screen">
    <div class="formula"></div>
    <div class="result"></div>
  </div>
  <div class="buttons">
    <button class="fn" fn="clear_all">CE</button>
    <button class="fn" fn="clear">C</button>
    <button class="fn" fn="del">&#9003;</button>
    <button class="fn op">&div;</button>
    <button class="num">7</button>
    <button class="num">8</button>
    <button class="num">9</button>
    <button class="fn op">&times;</button>
    <button class="num">4</button>
    <button class="num">5</button>
    <button class="num">6</button>
    <button class="fn op">&ndash;</button>
    <button class="num">1</button>
    <button class="num">2</button>
    <button class="num">3</button>
    <button class="fn op">+</button>
    <button class="num op" fn="inv">&pm;</button>
    <button class="num">0</button>
    <button class="num">.</button>
    <button class="res" fn="result">=</button>
  </div>
</div>

SCSS

@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;600&display=swap');

.calculator {
  width: 240px;
  box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.25);
  margin: 20px auto;
  font-family: "Roboto", Serif;

  .screen {
    height: 90px;
    padding: 20px;
    background-color: #78909C;
    color: #FFFFFF;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    gap: 5px;
    
    .formula {
      text-align: right;
      font-size: 14px;
    }
    .result {
      text-align: right;
      font-weight: 600;
      font-size: 26px;
      height: 26px;
      overflow: hidden;
    }
  }

  .buttons {
    display: flex;
    flex-flow: row wrap;
  }
  button {
    border: none;
    width: 60px;
    height: 60px;
    font-size: 16px;
    color: #5A747F;
    cursor: pointer;
    border-left: 1px solid #FFFFFF;
    border-bottom: 1px solid #FFFFFF;
    
    &.fn {
      background-color: #E4E9EC;
    }
    &.num {
      background-color: #FFFFFF;
      border-color: #E4E9EC;
    }
    &.op {
      font-size: 20px;
    }
    &.res {
      background-color: #FF6567;
      color: #FFFFFF;
      font-size: 24px;
      border: none;
      transform: scale(1.1);
    }
    &:nth-child(4n+1) {
      border-left: none;
    }
  }
}

JavaScript

for (const calculator of document.getElementsByClassName('calculator')) {
	initCalculator(calculator);
}

function initCalculator(calculator) {
	const formulaScreen = calculator.querySelector('.formula');
	const resultScreen = calculator.querySelector('.result');
	let inResultState = false;
  
  const operators = new Map([
    ['+', '+'],
    ['-', '-'],
    ['\u2013', '-'],
    ['\u00d7', '*'],
    ['\u00f7', '/'],
  ]);

	const functions = {
    clear_all: () => {
    	formulaScreen.innerText = "";
    	resultScreen.innerText = "";
    },
    clear: () => {
    	if (inResultState) functions.clear_all();
    	resultScreen.innerText = "";
    },
    del: () => {
    	if (inResultState) functions.clear_all();
    	resultScreen.innerText = resultScreen.innerText.slice(0, -1);
    },
    inv: () => {
    	if (inResultState) formulaScreen.innerText = "";
    	resultScreen.innerText = resultScreen.innerText.startsWith('-')
      	? resultScreen.innerText.slice(1)
        : '-' + resultScreen.innerText;
    },
    result: () => {
    	if (inResultState) formulaScreen.innerText = "";
        
    	formulaScreen.innerText = resultScreen.innerText !== ""
      	? formulaScreen.innerText + ' ' + resultScreen.innerText
        : formulaScreen.innerText.replace(/\D$/u, '');

      const code = formulaScreen.innerText
      	.replace(/[^\d\s\.]/g, char => operators.get(char))
        .replace(/(^|\s)\./g, " 0.");
      resultScreen.innerText = Function(`return (${code}) || ''`)();
    }
  }
  
  const appendOperator = operator => {
    if (formulaScreen.innerText === "" && resultScreen.innerText === "") return;

    const formula = resultScreen.innerText === "" ? formulaScreen.innerText.replace(/\D$/u, '') : formulaScreen.innerText;
    formulaScreen.innerText = (inResultState ? '' : formula + ' ') + resultScreen.innerText.replace(/\.$/, '') + ' ' + operator;
    resultScreen.innerText = "";
  }

	calculator.addEventListener("click", event => {
  	const fn =...