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 @@
+
+
+
@@ -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();
+ });
+ });
+ });
});