From aead3c28fc4b1ee8605a1d117f83e51eb33232c3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Oct 2025 15:45:36 +0000 Subject: [PATCH 1/2] Initial plan From 2dd652998efe119c686b041e3057d7716fdd6550 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Oct 2025 16:16:22 +0000 Subject: [PATCH 2/2] Add light/dark theme toggle and new operators (power, square root) Co-authored-by: haslam93 <36418598+haslam93@users.noreply.github.com> --- api/controller.js | 6 ++-- public/client.js | 33 +++++++++++++++++- public/default.css | 77 +++++++++++++++++++++++++++++++++++++++++ public/index.html | 8 ++++- test/arithmetic.test.js | 62 +++++++++++++++++++++++++++++++++ 5 files changed, 182 insertions(+), 4 deletions(-) diff --git a/api/controller.js b/api/controller.js index 949731c..3eb5bf8 100644 --- a/api/controller.js +++ b/api/controller.js @@ -16,6 +16,8 @@ exports.calculate = function(req, res) { 'subtract': function(a, b) { return a - b }, 'multiply': function(a, b) { return a * b }, 'divide': function(a, b) { return a / b }, + 'power': function(a, b) { return Math.pow(a, b) }, + 'sqrt': function(a) { return Math.sqrt(a) }, }; if (!req.query.operation) { @@ -29,13 +31,13 @@ exports.calculate = function(req, res) { } if (!req.query.operand1 || - !req.query.operand1.match(/^(-)?[0-9\.]+(e(-)?[0-9]+)?$/) || + !req.query.operand1.match(/^(-)?[0-9.]+(e(-)?[0-9]+)?$/) || req.query.operand1.replace(/[-0-9e]/g, '').length > 1) { throw new Error("Invalid operand1: " + req.query.operand1); } if (!req.query.operand2 || - !req.query.operand2.match(/^(-)?[0-9\.]+(e(-)?[0-9]+)?$/) || + !req.query.operand2.match(/^(-)?[0-9.]+(e(-)?[0-9]+)?$/) || req.query.operand2.replace(/[-0-9e]/g, '').length > 1) { throw new Error("Invalid operand2: " + req.query.operand2); } diff --git a/public/client.js b/public/client.js index 1d21fd9..6772aed 100644 --- a/public/client.js +++ b/public/client.js @@ -33,6 +33,12 @@ function calculate(operand1, operand2, operation) { case '/': uri += "?operation=divide"; break; + case '^': + uri += "?operation=power"; + break; + case '√': + uri += "?operation=sqrt"; + break; default: setError(); return; @@ -132,6 +138,31 @@ function equalPressed() { calculate(operand1, operand2, operation); } +// Theme toggle functionality +function initThemeToggle() { + // Check for saved theme preference or default to system preference + const savedTheme = localStorage.getItem('theme'); + if (savedTheme) { + document.body.setAttribute('data-theme', savedTheme); + } +} + +function toggleTheme() { + const currentTheme = document.body.getAttribute('data-theme'); + const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; + document.body.setAttribute('data-theme', newTheme); + localStorage.setItem('theme', newTheme); +} + +// Initialize theme on load +if (typeof document !== 'undefined') { + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', initThemeToggle); + } else { + initThemeToggle(); + } +} + // Enhanced keyboard support document.addEventListener('keydown', (event) => { // Handle keydown for special keys @@ -154,7 +185,7 @@ document.addEventListener('keypress', (event) => { } else if (event.key == '.') { decimalPressed(); event.preventDefault(); - } else if (event.key.match(/^[-*+/]$/)) { + } else if (event.key.match(/^[-*+/^]$/)) { operationPressed(event.key); event.preventDefault(); } else if (event.key == '=' || event.key == 'Enter') { diff --git a/public/default.css b/public/default.css index bd14feb..8c10729 100644 --- a/public/default.css +++ b/public/default.css @@ -42,6 +42,40 @@ } } +/* Manual theme override */ +body[data-theme="dark"] { + --primary-bg: #121212; + --calculator-bg: #1e1e1e; + --display-bg: #000000; + --display-text: #ffffff; + --button-bg: #2d2d2d; + --button-hover: #3d3d3d; + --button-active: #4d4d4d; + --text-primary: #ffffff; + --text-secondary: #adb5bd; +} + +body[data-theme="light"] { + --primary-bg: #f0f2f5; + --calculator-bg: #ffffff; + --display-bg: #1e1e1e; + --display-text: #ffffff; + --button-bg: #f8f9fa; + --button-hover: #e9ecef; + --button-active: #dee2e6; + --button-operator: #007bff; + --button-operator-hover: #0056b3; + --button-operator-active: #004085; + --button-equals: #28a745; + --button-equals-hover: #1e7e34; + --button-equals-active: #155724; + --button-clear: #dc3545; + --button-clear-hover: #c82333; + --button-clear-active: #bd2130; + --text-primary: #212529; + --text-secondary: #6c757d; +} + BODY { height: 100vh; width: 100vw; @@ -344,3 +378,46 @@ BODY { 0% { transform: translate(-50%, -50%) rotate(0deg); } 100% { transform: translate(-50%, -50%) rotate(360deg); } } + +/* Theme toggle button styling */ +.theme-toggle-container { + display: flex; + justify-content: flex-end; + margin-bottom: 1rem; + width: 100%; +} + +.theme-toggle-btn { + background: var(--button-bg); + border: none; + border-radius: 50%; + width: 44px; + height: 44px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all var(--transition-duration) ease; + box-shadow: var(--shadow-sm); + font-size: 1.5rem; + padding: 0; +} + +.theme-toggle-btn:hover { + background: var(--button-hover); + transform: scale(1.1); + box-shadow: var(--shadow-md); +} + +.theme-toggle-btn:active { + transform: scale(0.95); +} + +.theme-toggle-btn:focus-visible { + outline: none; + box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.4); +} + +.theme-icon { + user-select: none; +} diff --git a/public/index.html b/public/index.html index eaa7da7..dad3efd 100644 --- a/public/index.html +++ b/public/index.html @@ -9,6 +9,11 @@
+
+ +
0
@@ -16,7 +21,8 @@
- + + diff --git a/test/arithmetic.test.js b/test/arithmetic.test.js index deded48..cddfd9c 100644 --- a/test/arithmetic.test.js +++ b/test/arithmetic.test.js @@ -205,4 +205,66 @@ describe('Arithmetic', function () { }); }); }); + + describe('Power', function () { + it('raises a positive integer to a positive power', function (done) { + request.get('/arithmetic?operation=power&operand1=2&operand2=3') + .expect(200) + .end(function (err, res) { + expect(res.body).to.eql({ result: 8 }); + done(); + }); + }); + it('raises a positive integer to the power of 0', function (done) { + request.get('/arithmetic?operation=power&operand1=42&operand2=0') + .expect(200) + .end(function (err, res) { + expect(res.body).to.eql({ result: 1 }); + done(); + }); + }); + it('raises a number to a negative power', function (done) { + request.get('/arithmetic?operation=power&operand1=2&operand2=-2') + .expect(200) + .end(function (err, res) { + expect(res.body).to.eql({ result: 0.25 }); + done(); + }); + }); + it('raises a negative number to a power', function (done) { + request.get('/arithmetic?operation=power&operand1=-2&operand2=3') + .expect(200) + .end(function (err, res) { + expect(res.body).to.eql({ result: -8 }); + done(); + }); + }); + }); + + describe('Square Root', function () { + it('calculates square root of a positive integer', function (done) { + request.get('/arithmetic?operation=sqrt&operand1=9&operand2=0') + .expect(200) + .end(function (err, res) { + expect(res.body).to.eql({ result: 3 }); + done(); + }); + }); + it('calculates square root of a decimal', function (done) { + request.get('/arithmetic?operation=sqrt&operand1=2.25&operand2=0') + .expect(200) + .end(function (err, res) { + expect(res.body).to.eql({ result: 1.5 }); + done(); + }); + }); + it('calculates square root of zero', function (done) { + request.get('/arithmetic?operation=sqrt&operand1=0&operand2=0') + .expect(200) + .end(function (err, res) { + expect(res.body).to.eql({ result: 0 }); + done(); + }); + }); + }); });