diff --git a/samples/calc-02/index.css b/samples/calc-02/index.css index 80f123f..a56fd69 100644 --- a/samples/calc-02/index.css +++ b/samples/calc-02/index.css @@ -87,15 +87,16 @@ body { grid-area: display; position: relative; padding: clamp(12px, 1.5vw, 16px); + padding-bottom: clamp(4px, 0.6vw, 8px); background: linear-gradient(180deg, var(--display), var(--display2)); color: var(--displayText); font-family: "Courier New", monospace; overflow: hidden; - height: clamp(112px, 18vw, 160px); - max-height: 140px; + height: auto; + min-height: clamp(112px, 18vw, 124px); + max-height: none; align-self: start; margin-bottom: 0; - min-height: 0; } .display-grid { @@ -108,7 +109,7 @@ body { .stack-cell { display: grid; - grid-template-columns: 2.2ch 1fr; + grid-template-columns: 2.2ch 1fr auto; align-items: center; gap: 12px; font-size: clamp(18px, 3vw, 30px); @@ -283,7 +284,7 @@ button { text-shadow: 0 1px 0 rgba(0, 0, 0, 0.35); cursor: pointer; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 3px 0 rgba(0, 0, 0, 0.28); - transition: transform 120ms ease, filter 120ms ease, box-shadow 120ms ease; + transition: transform 120ms ease, filter 120ms ease, box-shadow 120ms ease, opacity 120ms ease; line-height: 1; } @@ -304,6 +305,57 @@ button:active { transform: translateY(2px); } +.stack-copy-button { + padding: 4px; + border-radius: 999px; + min-width: 24px; + width: 24px; + height: 24px; + display: inline-grid; + place-items: center; + opacity: 0; + pointer-events: none; + transform: scale(0.9); + background: transparent; + box-shadow: none; + color: rgba(31, 42, 18, 0.58); + margin-left: 6px; +} + +.stack-cell:last-child { + margin-bottom: 4px; +} + +.stack-copy-button svg { + width: 13px; + height: 13px; + fill: currentColor; + display: block; +} + +.stack-copy-button.is-visible { + opacity: 0.7; + pointer-events: auto; + transform: scale(1); +} + +.stack-copy-button:hover { + opacity: 1; + filter: none; + color: rgba(31, 42, 18, 0.85); +} + +.stack-copy-button:active { + transform: translateY(2px) scale(1); + color: rgba(31, 42, 18, 0.95); +} + +.stack-copy-button:focus-visible { + outline: 1px solid rgba(31, 42, 18, 0.35); + outline-offset: 2px; +} + + .key-default { background: linear-gradient(180deg, var(--btnTop), var(--btnBottom)); color: #eef2f7; @@ -385,6 +437,7 @@ button:active { .display-panel { padding: 10px; + padding-bottom: 8px; } .stack-cell { @@ -392,6 +445,11 @@ button:active { gap: 8px; } + .stack-copy-button { + padding: 5px 7px; + min-width: 28px; + } + button { border-radius: 10px; padding: 8px 6px; diff --git a/samples/calc-02/index.html b/samples/calc-02/index.html index bc724aa..8166124 100644 --- a/samples/calc-02/index.html +++ b/samples/calc-02/index.html @@ -13,10 +13,10 @@
-
T:
-
Z:
-
Y:
-
X:
+
T:
+
Z:
+
Y:
+
X:
diff --git a/samples/calc-02/index.js b/samples/calc-02/index.js index f248e45..3c0e082 100644 --- a/samples/calc-02/index.js +++ b/samples/calc-02/index.js @@ -16,6 +16,13 @@ const stackEls = { X: document.getElementById('stackX'), }; +const stackCopyButtons = { + T: document.querySelector('[data-copy-stack="T"]'), + Z: document.querySelector('[data-copy-stack="Z"]'), + Y: document.querySelector('[data-copy-stack="Y"]'), + X: document.querySelector('[data-copy-stack="X"]'), +}; + const keypadGrid = document.getElementById('keypadGrid'); const functionsGrid = document.getElementById('functionsGrid'); const trigoGrid = document.getElementById('trigoGrid'); @@ -113,16 +120,40 @@ function getStackLine(indexFromTop) { return indexFromTop >= 0 && indexFromTop < calc.stack.length ? calc.stack[indexFromTop] : ''; } +function getStackDisplayValue(label) { + if (label === 'X') { + return calc.isEditing ? calc.inputValue : (calc.formatNumber(getStackLine(0)) || ''); + } + if (label === 'Y') { + return calc.isEditing ? (calc.formatNumber(getStackLine(0)) || '') : (calc.formatNumber(getStackLine(1)) || ''); + } + if (label === 'Z') { + return calc.isEditing ? (calc.formatNumber(getStackLine(1)) || '') : (calc.formatNumber(getStackLine(2)) || ''); + } + return calc.isEditing ? (calc.formatNumber(getStackLine(2)) || '') : (calc.formatNumber(getStackLine(3)) || ''); +} + +function updateCopyButtons() { + for (const label of ['T', 'Z', 'Y', 'X']) { + const value = getStackDisplayValue(label); + const button = stackCopyButtons[label]; + if (!button) continue; + button.classList.toggle('is-visible', Boolean(value)); + button.disabled = !value; + button.setAttribute('aria-hidden', value ? 'false' : 'true'); + } +} + function render() { normalizeStack(); const isPortrait = window.matchMedia('(orientation: portrait)').matches || window.innerWidth <= 860; calculatorEl?.classList.toggle('portrait', isPortrait); calculatorEl?.classList.toggle('landscape', !isPortrait); - const editingValue = calc.isEditing ? calc.inputValue : ''; - stackEls.X.textContent = calc.isEditing ? editingValue : (calc.formatNumber(getStackLine(0)) || ''); - stackEls.Y.textContent = calc.isEditing ? (calc.formatNumber(getStackLine(0)) || '') : (calc.formatNumber(getStackLine(1)) || ''); - stackEls.Z.textContent = calc.isEditing ? (calc.formatNumber(getStackLine(1)) || '') : (calc.formatNumber(getStackLine(2)) || ''); - stackEls.T.textContent = calc.isEditing ? (calc.formatNumber(getStackLine(2)) || '') : (calc.formatNumber(getStackLine(3)) || ''); + stackEls.X.textContent = getStackDisplayValue('X'); + stackEls.Y.textContent = getStackDisplayValue('Y'); + stackEls.Z.textContent = getStackDisplayValue('Z'); + stackEls.T.textContent = getStackDisplayValue('T'); + updateCopyButtons(); modeButton.textContent = calc.angleMode; } @@ -244,6 +275,17 @@ function buildGrid(container, keys) { keys.forEach((key) => container.appendChild(createKeyButton(key))); } +async function copyStackValue(label) { + const value = getStackDisplayValue(label); + if (!value) return; + try { + await navigator.clipboard.writeText(value); + setStatus(`Copied ${label}`); + } catch (error) { + setStatus('Copy unavailable', true); + } +} + function handleKeyboard(event) { if (event.defaultPrevented) return; const key = event.key; @@ -321,6 +363,12 @@ window.addEventListener('scroll', () => { }, true); window.addEventListener('click', (event) => { + const stackCopyButton = event.target.closest('.stack-copy-button'); + if (stackCopyButton) { + const label = stackCopyButton.dataset.copyStack; + if (label) copyStackValue(label); + return; + } if (modeMenuEl && !event.target.closest('.mode-menu') && event.target !== modeButton) { closeModeMenu(); }