// src/scripts/hexColours.js // Computing:Box — Hex Colours logic (() => { /* ----------------------------- DOM ----------------------------- */ const colorGrid = document.getElementById("colorGrid"); const denaryEl = document.getElementById("denaryNumber"); const binaryEl = document.getElementById("binaryNumber"); const hexEl = document.getElementById("hexNumber"); const previewColor = document.getElementById("previewColor"); const previewInverted = document.getElementById("previewInverted"); const btnCustomHex = document.getElementById("btnCustomHex"); const btnCustomRGB = document.getElementById("btnCustomRGB"); const btnInvert = document.getElementById("btnInvert"); const btnRandom = document.getElementById("btnRandom"); const btnClear = document.getElementById("btnClear"); const toolboxToggle = document.getElementById("toolboxToggle"); const colorPage = document.getElementById("colorPage"); /* ----------------------------- STATE ----------------------------- */ // rgb[0]=Red, rgb[1]=Green, rgb[2]=Blue (Values 0-255) let rgb = [0, 0, 0]; let randomTimer = null; /* ----------------------------- BUILD UI ----------------------------- */ function buildGrid() { if (!colorGrid) return; colorGrid.innerHTML = ""; const colorClasses = ['text-red', 'text-green', 'text-blue']; for (let c = 0; c < 3; c++) { const group = document.createElement("div"); group.className = "colorGroup"; for (let i = 1; i >= 0; i--) { const col = document.createElement("div"); col.className = "hexCol"; let cardHTML = `
0
`; for (let j = 3; j >= 0; j--) { cardHTML += `
${1 << j}
`; } cardHTML += `
${16 ** i}
`; col.innerHTML = cardHTML; const incBtn = col.querySelector(`#colorInc-${c}-${i}`); const decBtn = col.querySelector(`#colorDec-${c}-${i}`); incBtn.addEventListener("click", () => { const weight = 16 ** i; rgb[c] = (rgb[c] + weight) % 256; updateUI(); }); decBtn.addEventListener("click", () => { const weight = 16 ** i; rgb[c] = (rgb[c] - weight + 256) % 256; updateUI(); }); group.appendChild(col); } colorGrid.appendChild(group); } } /* ----------------------------- UI UPDATE ----------------------------- */ function updateUI() { if (denaryEl) { denaryEl.innerHTML = ` ${rgb[0]} ${rgb[1]} ${rgb[2]} `; } const hexVals = rgb.map(v => v.toString(16).padStart(2, '0').toUpperCase()); const fullHexString = `#${hexVals.join('')}`; if (hexEl) { hexEl.innerHTML = ` #${hexVals[0]} ${hexVals[1]} ${hexVals[2]} `; } if (binaryEl) { binaryEl.innerHTML = ` ${rgb[0].toString(2).padStart(8, '0')} ${rgb[1].toString(2).padStart(8, '0')} ${rgb[2].toString(2).padStart(8, '0')} `; } if (previewColor) previewColor.style.backgroundColor = fullHexString; const invertedHexString = "#" + rgb.map(v => (255 - v).toString(16).padStart(2, '0').toUpperCase()).join(''); if (previewInverted) previewInverted.style.backgroundColor = invertedHexString; for (let c = 0; c < 3; c++) { const val = rgb[c]; const nibbles = [val % 16, Math.floor(val / 16)]; for (let i = 0; i < 2; i++) { const display = document.getElementById(`colorDisplay-${c}-${i}`); if (display) display.textContent = nibbles[i].toString(16).toUpperCase(); for (let j = 0; j < 4; j++) { const bulb = document.getElementById(`colorBulb-${c}-${i}-${j}`); if (bulb) { const isOn = (nibbles[i] & (1 << j)) !== 0; bulb.classList.toggle("on", isOn); } } } } } /* ----------------------------- ACTIONS ----------------------------- */ function clearAll() { rgb = [0, 0, 0]; updateUI(); } function setRandomOnce() { const arr = new Uint8Array(3); crypto.getRandomValues(arr); rgb = [arr[0], arr[1], arr[2]]; updateUI(); } function runRandomBriefly() { if (randomTimer) { clearInterval(randomTimer); randomTimer = null; } if (btnRandom) btnRandom.classList.add("btnRandomRunning"); const start = Date.now(); const durationMs = 1125; const tickMs = 80; randomTimer = setInterval(() => { setRandomOnce(); if (Date.now() - start >= durationMs) { clearInterval(randomTimer); randomTimer = null; if (btnRandom) btnRandom.classList.remove("btnRandomRunning"); } }, tickMs); } /* ----------------------------- EVENTS ----------------------------- */ btnCustomHex?.addEventListener("click", () => { let v = prompt("Enter a 6-character hex code (e.g. FF0055):"); if (v === null) return; v = v.replace(/\s+/g, "").replace(/^#/i, "").toUpperCase(); if (!/^[0-9A-F]{6}$/.test(v)) return alert("Invalid hex code. Please enter exactly 6 hexadecimal characters."); rgb = [ parseInt(v.substring(0, 2), 16), parseInt(v.substring(2, 4), 16), parseInt(v.substring(4, 6), 16) ]; updateUI(); }); btnCustomRGB?.addEventListener("click", () => { const v = prompt("Enter R, G, B values (0-255) separated by commas (e.g. 255, 128, 0):"); if (v === null) return; const parts = v.split(',').map(s => parseInt(s.trim(), 10)); if (parts.length !== 3 || parts.some(isNaN) || parts.some(n => n < 0 || n > 255)) { return alert("Invalid input. Please provide three numbers between 0 and 255."); } rgb = parts; updateUI(); }); btnInvert?.addEventListener("click", () => { rgb = rgb.map(v => 255 - v); updateUI(); }); btnClear?.addEventListener("click", clearAll); btnRandom?.addEventListener("click", runRandomBriefly); toolboxToggle?.addEventListener("click", () => { const isCollapsed = colorPage?.classList.contains("toolboxCollapsed"); colorPage.classList.toggle("toolboxCollapsed", !isCollapsed); toolboxToggle?.setAttribute("aria-expanded", isCollapsed ? "true" : "false"); }); /* ----------------------------- INIT ----------------------------- */ buildGrid(); updateUI(); })();