├── favicon.ico
├── screenshot
└── screenshot.png
├── LICENCE
├── index.html
├── README.md
├── style.css
└── script.js
/favicon.ico:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/screenshot/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YALDAKHOSHPEY/Calculator_pro/HEAD/screenshot/screenshot.png
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 [Yaldakhoshpey]
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Advanced Scientific Calculator
7 |
8 |
9 |
10 |
11 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🧮 Advanced Scientific Calculator
2 |
3 | A beautiful and fully functional scientific calculator built with HTML, CSS, and JavaScript.
4 | It includes a scientific expression evaluator, a calculation history panel, and a stopwatch timer — all inside a responsive and visually modern UI.
5 |
6 | ---
7 |
8 | ## ✨ Features
9 |
10 | - ✅ Scientific functions: sin, cos, tan, log, ln, √, ^, !, π, e, mod, abs, exp, and more
11 | - ✅ Calculation history (up to 20 operations)
12 | - ✅ Stopwatch timer with start/stop and reset
13 | - ✅ Red/black modern theme with yellow hover effects
14 | - ✅ Responsive layout for mobile and desktop
15 | - ✅ Built without any external libraries — pure HTML/CSS/JavaScript
16 |
17 | ---
18 |
19 | ## 📸 Screenshots
20 |
21 | 
22 |
23 | ---
24 |
25 | ## Live Demo
26 |
27 | [Click here ☺️](https://yaldakhoshpey.github.io/Calculator_pro/)
28 |
29 | ## 📁 Project Structure
30 |
31 | ``` text
32 | advanced-calculator/
33 | ├── index.html # Main HTML structure
34 | ├── style.css # Calculator & layout styling
35 | ├── app.js # Calculator logic & interactions
36 | ├── screenshot.png # UI screenshot for README preview
37 | ├── README.md # Project documentation
38 | └── assets/ # (Optional) icons, images, fonts etc.
39 | ```
40 | ---
41 |
42 | ## 📄 License
43 |
44 | This project is licensed under the [MIT License](./LICENSE).
45 |
46 | ---
47 |
48 | **made by *Yalda Khoshpey***
49 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | /* Reset & base */
2 | * {
3 | box-sizing: border-box;
4 | }
5 |
6 | body {
7 | margin: 0;
8 | font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
9 | background: #121212;
10 | color: #eee;
11 | display: flex;
12 | justify-content: center;
13 | align-items: center;
14 | min-height: 100vh;
15 | padding: 20px;
16 | }
17 |
18 | .container {
19 | display: flex;
20 | gap: 30px;
21 | flex-wrap: wrap;
22 | max-width: 1000px;
23 | width: 100%;
24 | }
25 |
26 | /* Calculator */
27 | .calculator {
28 | background: linear-gradient(145deg, #b71c1c, #7f0000);
29 | border-radius: 25px;
30 | box-shadow: 0 0 30px #b71c1caa;
31 | padding: 25px;
32 | width: 350px;
33 | display: flex;
34 | flex-direction: column;
35 | }
36 |
37 | .display {
38 | background: #2a0000;
39 | border-radius: 15px;
40 | padding: 20px;
41 | font-size: 2.5rem;
42 | color: #ffebee;
43 | text-align: right;
44 | min-height: 60px;
45 | overflow-x: auto;
46 | font-weight: 700;
47 | user-select: none;
48 | margin-bottom: 25px;
49 | }
50 |
51 | .buttons {
52 | display: grid;
53 | grid-template-columns: repeat(6, 1fr);
54 | gap: 15px;
55 | }
56 |
57 | button {
58 | background: linear-gradient(145deg, #e53935, #b71c1c);
59 | border: none;
60 | border-radius: 15px;
61 | padding: 18px 0;
62 | font-size: 1.1rem;
63 | color: #fff;
64 | cursor: pointer;
65 | box-shadow: 0 5px 10px #7f0000cc;
66 | transition: all 0.25s ease;
67 | user-select: none;
68 | }
69 |
70 | button:hover {
71 | background: linear-gradient(145deg, #ffeb3b, #fbc02d);
72 | color: #121212;
73 | box-shadow: 0 6px 15px #ffeb3bcc;
74 | transform: scale(1.1);
75 | }
76 |
77 | button:active {
78 | transform: scale(0.95);
79 | }
80 |
81 | button.equal {
82 | grid-column: span 6;
83 | background: linear-gradient(145deg, #ffb300, #ff6f00);
84 | font-weight: 700;
85 | color: #121212;
86 | box-shadow: 0 5px 15px #ff6f00cc;
87 | }
88 |
89 | button.equal:hover {
90 | background: linear-gradient(145deg, #fff176, #ffca28);
91 | box-shadow: 0 6px 18px #fff176cc;
92 | }
93 |
94 | /* Sidebar */
95 | .sidebar {
96 | background: #1b1b1b;
97 | border-radius: 25px;
98 | padding: 25px;
99 | width: 280px;
100 | box-shadow: 0 0 30px #b71c1caa;
101 | display: flex;
102 | flex-direction: column;
103 | gap: 30px;
104 | user-select: none;
105 | }
106 |
107 | .sidebar h2 {
108 | margin-top: 0;
109 | margin-bottom: 15px;
110 | font-weight: 700;
111 | color: #ff5252;
112 | text-align: center;
113 | }
114 |
115 | /* History */
116 | .history {
117 | max-height: 280px;
118 | overflow-y: scroll;
119 | }
120 |
121 | #historyList {
122 | list-style: none;
123 | padding-left: 0;
124 | margin: 0 0 15px 0;
125 | max-height: 200px;
126 | overflow-y: auto;
127 | border: 1px solid #7f0000;
128 | border-radius: 10px;
129 | background: #2a0000;
130 | }
131 |
132 | #historyList li {
133 | padding: 8px 12px;
134 | border-bottom: 1px solid #7f0000;
135 | font-size: 0.95rem;
136 | color: #f44336;
137 | }
138 |
139 | #historyList li:last-child {
140 | border-bottom: none;
141 | }
142 |
143 | #clearHistoryBtn {
144 | width: 100%;
145 | background: #b71c1c;
146 | border: none;
147 | border-radius: 12px;
148 | padding: 10px;
149 | font-weight: 700;
150 | cursor: pointer;
151 | color: #fff;
152 | transition: all 0.25s ease;
153 | }
154 |
155 | #clearHistoryBtn:hover {
156 | background: #ffeb3b;
157 | color: #121212;
158 | }
159 |
160 | /* Timer */
161 | .timer {
162 | text-align: center;
163 | }
164 |
165 | #timerDisplay {
166 | font-size: 2rem;
167 | font-weight: 700;
168 | background: #2a0000;
169 | border-radius: 15px;
170 | padding: 15px 0;
171 | color: #ffeb3b;
172 | margin-bottom: 15px;
173 | user-select: none;
174 | }
175 |
176 | .timer-buttons button {
177 | background: #b71c1c;
178 | border: none;
179 | color: white;
180 | font-weight: 700;
181 | padding: 10px 18px;
182 | margin: 0 10px;
183 | border-radius: 12px;
184 | cursor: pointer;
185 | transition: all 0.25s ease;
186 | min-width: 80px;
187 | }
188 |
189 | .timer-buttons button:hover {
190 | background: #ffeb3b;
191 | color: #121212;
192 | }
193 |
194 | .timer-buttons button:active {
195 | transform: scale(0.95);
196 | }
197 |
198 | /* Responsive */
199 | @media (max-width: 800px) {
200 | .container {
201 | flex-direction: column;
202 | align-items: center;
203 | }
204 | .calculator, .sidebar {
205 | width: 100%;
206 | max-width: 400px;
207 | }
208 | .buttons {
209 | grid-template-columns: repeat(4, 1fr);
210 | }
211 | button.equal {
212 | grid-column: span 4;
213 | }
214 | }
215 |
216 |
--------------------------------------------------------------------------------
/script.js:
--------------------------------------------------------------------------------
1 | const buttons = [
2 | 'C', '←', '(', ')', 'π', 'e',
3 | 'sin', 'cos', 'tan', 'log', 'ln', '√',
4 | '7', '8', '9', '/', '^', '%',
5 | '4', '5', '6', '*', 'exp', '!',
6 | '1', '2', '3', '-', 'abs', 'mod',
7 | '0', '.', '+', '='
8 | ];
9 |
10 | const display = document.getElementById('display');
11 | const buttonsContainer = document.getElementById('buttons');
12 | const historyList = document.getElementById('historyList');
13 | const clearHistoryBtn = document.getElementById('clearHistoryBtn');
14 |
15 | let input = '';
16 | let history = [];
17 |
18 | // Timer
19 | const timerDisplay = document.getElementById('timerDisplay');
20 | const startStopBtn = document.getElementById('startStopBtn');
21 | const resetBtn = document.getElementById('resetBtn');
22 |
23 | let timerInterval = null;
24 | let timerStart = null;
25 | let elapsed = 0;
26 |
27 | // Factorial
28 | function factorial(n) {
29 | if (n < 0) return NaN;
30 | if (n === 0 || n === 1) return 1;
31 | let res = 1;
32 | for (let i = 2; i <= n; i++) res *= i;
33 | return res;
34 | }
35 |
36 | // Display
37 | function updateDisplay() {
38 | display.textContent = input || '0';
39 | }
40 |
41 | // History
42 | function addHistory(entry) {
43 | history.push(entry);
44 | if (history.length > 20) history.shift(); // limit to 20
45 | renderHistory();
46 | }
47 |
48 | function renderHistory() {
49 | historyList.innerHTML = '';
50 | history.slice().reverse().forEach(item => {
51 | const li = document.createElement('li');
52 | li.textContent = item;
53 | historyList.appendChild(li);
54 | });
55 | }
56 |
57 | clearHistoryBtn.addEventListener('click', () => {
58 | history = [];
59 | renderHistory();
60 | });
61 |
62 | // Calculation
63 | function calculate(expr) {
64 | try {
65 | let replaced = expr
66 | .replace(/π/g, Math.PI)
67 | .replace(/e/g, Math.E)
68 | .replace(/√/g, 'Math.sqrt')
69 | .replace(/sin/g, 'Math.sin')
70 | .replace(/cos/g, 'Math.cos')
71 | .replace(/tan/g, 'Math.tan')
72 | .replace(/log/g, 'Math.log10')
73 | .replace(/ln/g, 'Math.log')
74 | .replace(/exp/g, 'Math.exp')
75 | .replace(/abs/g, 'Math.abs')
76 | .replace(/mod/g, '%')
77 | .replace(/\^/g, '**');
78 |
79 | // Replace factorials
80 | while (replaced.includes('!')) {
81 | replaced = replaced.replace(/(\d+)!/, (_, num) => factorial(parseInt(num)));
82 | }
83 |
84 | // Percent handling
85 | replaced = replaced.replace(/(\d+)%/g, '($1/100)');
86 |
87 | const result = Function('"use strict"; return (' + replaced + ')')();
88 |
89 | if (
90 | result === undefined ||
91 | result === Infinity ||
92 | Number.isNaN(result)
93 | ) {
94 | return 'Error';
95 | }
96 |
97 | return Math.round(result * 1e12) / 1e12;
98 | } catch (e) {
99 | return 'Error';
100 | }
101 | }
102 |
103 | // Button handling
104 | function handleClick(val) {
105 | if (val === 'C') {
106 | input = '';
107 | } else if (val === '←') {
108 | input = input.slice(0, -1);
109 | } else if (val === '=') {
110 | const res = calculate(input);
111 | addHistory(`${input} = ${res}`);
112 | input = res.toString();
113 | } else {
114 | if (input === 'Error') input = '';
115 | input += val;
116 | }
117 | updateDisplay();
118 | }
119 |
120 | // Create buttons
121 | buttons.forEach(btn => {
122 | const button = document.createElement('button');
123 | button.textContent = btn;
124 | if (btn === '=') button.classList.add('equal');
125 | button.addEventListener('click', () => handleClick(btn));
126 | buttonsContainer.appendChild(button);
127 | });
128 |
129 | updateDisplay();
130 | renderHistory(); // Initial rendering of history
131 |
132 | // --- TIMER ---
133 | function formatTime(ms) {
134 | const totalSeconds = Math.floor(ms / 1000);
135 | const h = Math.floor(totalSeconds / 3600).toString().padStart(2, '0');
136 | const m = Math.floor((totalSeconds % 3600) / 60).toString().padStart(2, '0');
137 | const s = (totalSeconds % 60).toString().padStart(2, '0');
138 | return `${h}:${m}:${s}`;
139 | }
140 |
141 | function startTimer() {
142 | if (timerInterval) return;
143 | timerStart = Date.now() - elapsed;
144 | timerInterval = setInterval(() => {
145 | elapsed = Date.now() - timerStart;
146 | timerDisplay.textContent = formatTime(elapsed);
147 | }, 1000);
148 | startStopBtn.textContent = 'Stop';
149 | }
150 |
151 | function stopTimer() {
152 | if (!timerInterval) return;
153 | clearInterval(timerInterval);
154 | timerInterval = null;
155 | startStopBtn.textContent = 'Start';
156 | }
157 |
158 | startStopBtn.addEventListener('click', () => {
159 | if (timerInterval) stopTimer();
160 | else startTimer();
161 | });
162 | resetBtn.addEventListener('click', () => {
163 | stopTimer();
164 | elapsed = 0;
165 | timerDisplay.textContent = '00:00:00';
166 | });
167 |
--------------------------------------------------------------------------------