JSFiddle - React, Tailwind, and code Playground

by thelifeisyours

HTML

<main>
  <div id="digitiser-container">
    <div id="shift-num-left" class="button"> &lt; </div>
    <div id="shift-char-left" class="button"> &lt; </div>
    <div id="char-container"></div>
    <div id="num-container"></div>
    <div id="shift-num-right" class="button"> &gt; </div>
    <div id="shift-char-right" class="button"> &gt; </div>
  </div>
  <div id="textarea-container">
    <div class="title">Text to be encoded</div>
    <textarea id="textarea-input-encode"></textarea>

    <div class="title">Text to be decode</div>
    <textarea id="textarea-input-decode"></textarea>
  </div>
</main>

CSS

body {
	font-family: areal, sans-serif;
	font-weight: 700;
}

#digitiser-container {
	display: grid;
	grid-template-columns: 2rem 1fr 2rem;
	grid-template-rows: 2.5rem 2.5rem;
	grid-row-gap: 0.25rem;
	column-gap: 0.5rem;
	margin: 0.5rem;
	width: max-content;
}

#char-container{
	grid-column: 2;
	grid-row: 1;
}

#num-container{
	grid-column: 2;
	grid-row: 2;
}

#char-container, #num-container {
	display: flex;
	flex-direction: row;
	justify-content: space-between;
}

.char-item, .num-item {
	min-width: 2rem;
	height: 2rem;
	margin-left: 0.25rem;
	margin-right: 0.25rem;
	display: flex;
	justify-content: center;
	align-items: center;
	
	border: solid 1px gray;
	border-radius: 4px;
	color: white;
}

.button {
	display: flex;
	justify-content: center;
	align-items: center;
	
	width: fit-content;
	padding: 0.5rem;
	
	border: solid 1px gray;
	border-radius: 4px;
	cursor: pointer;
}

.button:hover {
	background: skyblue;
}

#shift-char-left, #shift-char-right {
	grid-row: 1;
}

#shift-num-left, #shift-num-right {
	grid-row: 2;
}

textarea {
	min-width: 50rem;
	min-height: 15rem;
}

JavaScript

class TLIY_Cipher {
	constructor() {
		this.data = {
			chars: "abcdefghijklmnopqrstuvwxyz".toUpperCase().split(''),
			nums: "abcdefghijklmnopqrstuvwxyz".toUpperCase().split('').map((_, index) => {return index+1}),
			isEncoding: false,
			color: {
				freq: 0.2,
				scale: 1.2,
			},
		}
		
		this.elements = {
			char: {
				container: document.querySelector('#char-container'),
				shiftLeft: document.querySelector('#shift-char-left'),
				shiftRight: document.querySelector('#shift-char-right'),
				input: document.querySelector('#textarea-input-encode'),
			},
			num: {
				container: document.querySelector('#num-container'),
				shiftLeft: document.querySelector('#shift-num-left'),
				shiftRight: document.querySelector('#shift-num-right'),
				input: document.querySelector('#textarea-input-decode'),
			},
			display: {
				chars: [],
				nums: [],
			},
		}
		
		this.setup()
		console.log(this)
	}
	
	setup() {
		console.log(":::setup")
		this.initDisplayElements()
		this.initDisplayStyles()
		this.updateDisplay()
		this.addEventListeners()
	}
	
	addEventListeners() {
		//Shift buttons
		this.elements.char.shiftLeft.addEventListener('click', () => {
			this.shiftLeft(this.data.chars)
			this.updateDisplay()
		})
		
		this.elements.char.shiftRight.addEventListener('click', () => {
			this.shiftRight(this.data.chars)
			this.updateDisplay()
		})
		
		this.elements.num.shiftLeft.addEventListener('click', () => {
			this.shiftLeft(this.data.nums)
			this.updateDisplay()
		})
		
		this.elements.num.shiftRight.addEventListener('click', () => {
			this.shiftRight(this.data.nums)
			this.updateDisplay()
		})
		
		//Input listener
		this.elements.char.input.addEventListener('keyup', () => {
			this.isEncoding = true;
			this.encode()
		})
		
		this.elements.num.input.addEventListener('keyup', () => {
			this.isEncoding = false;
			this.decode()
		})
	}
	
	initDisplayElements() {
		console.log(":::initDisplayElements")
		this.data.chars.forEach((char, index) =>...