From 26814bee3cde83ee7c32388ab9dbe59c4dfc81ec Mon Sep 17 00:00:00 2001 From: MatMoul Date: Sat, 25 Apr 2026 00:04:33 +0200 Subject: [PATCH] feat(hp48): color-code keypad and inline error display --- samples/hp48/index.html | 154 +++++++++++++++++++++++++++------------- 1 file changed, 104 insertions(+), 50 deletions(-) diff --git a/samples/hp48/index.html b/samples/hp48/index.html index a4b3bd1..53caab0 100644 --- a/samples/hp48/index.html +++ b/samples/hp48/index.html @@ -16,6 +16,20 @@ --key-text: #f2f2f2; --accent: #8cff6d; --border: #111; + --key-number: #5a5a5a; + --key-number-2: #444; + --key-arithmetic: #7f5c24; + --key-arithmetic-2: #5f4216; + --key-trig: #2d6d73; + --key-trig-2: #1f4f54; + --key-stack: #6b4a8f; + --key-stack-2: #4f356b; + --key-special: #3d5d8a; + --key-special-2: #2c4464; + --key-danger: #8a3f3f; + --key-danger-2: #632d2d; + --key-enter: #5d8a3d; + --key-enter-2: #45662e; } * { box-sizing: border-box; } @@ -124,34 +138,6 @@ padding: 14px; } - .title { - color: #fff; - margin: 0 0 10px; - font-size: 14px; - text-transform: uppercase; - letter-spacing: 0.08em; - } - - .keypad-labels { - display: grid; - grid-template-columns: 4fr 3fr 2fr; - gap: 12px; - margin-bottom: 10px; - } - - .keypad-label { - color: #d8d8d8; - font-size: 11px; - font-weight: bold; - letter-spacing: 0.08em; - text-transform: uppercase; - text-align: center; - padding: 6px 8px; - border-radius: 999px; - background: rgba(255, 255, 255, 0.05); - border: 1px solid rgba(255, 255, 255, 0.08); - } - .keypad-wrap { display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 3fr) minmax(0, 2fr); @@ -185,11 +171,41 @@ min-height: 46px; } - .keypad button.active-toggle { + .keypad button.active-toggle, + .active-toggle { background: linear-gradient(180deg, #6a8c52, #49693a); color: #fff; } + .key-number { + background: linear-gradient(180deg, var(--key-number), var(--key-number-2)); + } + + .key-arithmetic { + background: linear-gradient(180deg, var(--key-arithmetic), var(--key-arithmetic-2)); + } + + .key-trigonometry { + background: linear-gradient(180deg, var(--key-trig), var(--key-trig-2)); + } + + .key-stack { + background: linear-gradient(180deg, var(--key-stack), var(--key-stack-2)); + } + + .key-special { + background: linear-gradient(180deg, var(--key-special), var(--key-special-2)); + } + + .key-danger { + background: linear-gradient(180deg, var(--key-danger), var(--key-danger-2)); + } + + .key-enter { + background: linear-gradient(180deg, var(--key-enter), var(--key-enter-2)); + font-weight: bold; + } + .keypad-group button.enter-tall { grid-row: span 2; } @@ -230,12 +246,9 @@ min-height: 40px; } - .error { - margin-top: 10px; - min-height: 20px; - color: #ff8a8a; - font-family: "Courier New", monospace; - font-size: 13px; + .display-error { + color: #8a2a1c; + font-weight: bold; } @@ -244,7 +257,6 @@ padding: 16px; } - .keypad-labels, .keypad-wrap { gap: 8px; } @@ -265,7 +277,6 @@ border-radius: 16px; } - .keypad-labels, .keypad-wrap { grid-template-columns: 1fr; } @@ -297,12 +308,6 @@
-
Calculator Keys
-
@@ -319,7 +324,6 @@
-
@@ -331,7 +335,6 @@ const stackEl = document.getElementById('stack'); const displayEl = document.getElementById('display'); - const errorEl = document.getElementById('error'); const modeLabel = document.getElementById('modeLabel'); const functionsKeypadEl = document.getElementById('functionsKeypad'); const numbersKeypadEl = document.getElementById('numbersKeypad'); @@ -344,6 +347,7 @@ let openMenuName = null; let isMovingStackItem = false; let stackSnapshotBeforeMove = null; + let currentErrorMessage = ''; function getKeypadLayout() { return { @@ -427,6 +431,42 @@ }; } + function getKeyClassName(key) { + if (key.type === 'input') { + return 'key-number'; + } + + if (key.value === 'clear') { + return 'key-danger'; + } + + if (key.value === 'enter') { + return 'key-enter'; + } + + if (key.type === 'special') { + return 'key-special'; + } + + const stackCommands = new Set(['neg']); + const arithmeticCommands = new Set(['add', 'sub', 'mul', 'div', 'mod', 'pow', 'sqr', 'sqrt', 'recip', 'log', 'ln']); + const trigonometryCommands = new Set(['sin', 'cos', 'tan', 'asin', 'acos', 'atan']); + + if (stackCommands.has(key.value)) { + return 'key-stack'; + } + + if (arithmeticCommands.has(key.value)) { + return 'key-arithmetic'; + } + + if (trigonometryCommands.has(key.value)) { + return 'key-trigonometry'; + } + + return ''; + } + function renderKeypadGroup(groupEl, layout) { groupEl.innerHTML = ''; const occupied = new Set(); @@ -449,6 +489,10 @@ const button = document.createElement('button'); button.textContent = key.label; + const keyClassName = getKeyClassName(key); + if (keyClassName) { + button.classList.add(keyClassName); + } button.style.gridColumn = String(colIndex + 1); button.style.gridRow = `${rowIndex + 1} / span ${key.rowspan || 1}`; if (key.rowspan && key.rowspan > 1) { @@ -591,7 +635,8 @@ execute(key.value); } } catch (error) { - errorEl.textContent = error.message; + currentErrorMessage = error.message; + render(); } } @@ -719,17 +764,23 @@ } stackEl.innerHTML = lines.join(''); - if (calc.isEditing) { + if (currentErrorMessage) { + displayEl.textContent = `ERROR: ${currentErrorMessage}`; + displayEl.classList.add('display-error'); + } else if (calc.isEditing) { displayEl.textContent = `ENTERING: ${calc.inputValue}`; + displayEl.classList.remove('display-error'); } else if (isMovingStackItem && hasStackSelection()) { displayEl.textContent = `MOVING: ${['X', 'Y', 'Z', 'T'][stackCursor] || '?'}`; + displayEl.classList.remove('display-error'); } else if (hasStackSelection()) { displayEl.textContent = `SELECTED: ${['X', 'Y', 'Z', 'T'][stackCursor] || '?'}`; + displayEl.classList.remove('display-error'); } else { displayEl.textContent = 'READY'; + displayEl.classList.remove('display-error'); } modeLabel.textContent = calc.angleMode; - errorEl.textContent = ''; renderKeypad(); } @@ -773,10 +824,12 @@ clearStackSelection(); calc.command(name); } + currentErrorMessage = ''; syncInputFromState(); render(); } catch (error) { - errorEl.textContent = error.message; + currentErrorMessage = error.message; + render(); } } @@ -960,7 +1013,8 @@ execute(action.value); } } catch (error) { - errorEl.textContent = error.message; + currentErrorMessage = error.message; + render(); } }