diff --git a/calculator-app/README.md b/calculator-app/README.md new file mode 100644 index 00000000..57a6055b --- /dev/null +++ b/calculator-app/README.md @@ -0,0 +1,171 @@ +# Calculator App + +A modern, responsive calculator web application built with HTML, CSS, and JavaScript. This calculator supports basic arithmetic operations, decimal calculations, and includes advanced features like sign changes and comprehensive error handling. + +![Calculator App](https://img.shields.io/badge/Status-Complete-brightgreen) +![HTML5](https://img.shields.io/badge/HTML5-E34F26?style=flat&logo=html5&logoColor=white) +![CSS3](https://img.shields.io/badge/CSS3-1572B6?style=flat&logo=css3&logoColor=white) +![JavaScript](https://img.shields.io/badge/JavaScript-F7DF1E?style=flat&logo=javascript&logoColor=black) + +## โœจ Features + +### Core Features +- **Digital Display**: Shows current number entered or result of last operation +- **Number Input**: Enter numbers up to 8 digits long (0-9) +- **Basic Operations**: Addition (+), Subtraction (-), Multiplication (ร—), Division (รท) +- **Clear Functions**: + - **C**: Clear last number or operation + - **AC**: Clear all and reset to 0 +- **Error Handling**: Shows "ERR" for invalid operations or results exceeding 8 digits + +### Bonus Features +- **Decimal Support**: Floating point numbers up to 3 decimal places +- **Sign Change**: +/- button to toggle between positive and negative numbers +- **Keyboard Support**: Full keyboard input support +- **Responsive Design**: Works on desktop, tablet, and mobile devices +- **Visual Feedback**: Button hover effects and animations + +## ๐Ÿš€ Demo + +Open `index.html` in your web browser to see the calculator in action! + +## ๐Ÿ“ Project Structure + +``` +calculator-app/ +โ”œโ”€โ”€ index.html # Main HTML structure +โ”œโ”€โ”€ styles.css # CSS styling and responsive design +โ”œโ”€โ”€ script.js # JavaScript functionality and logic +โ””โ”€โ”€ README.md # Project documentation +``` + +## ๐Ÿ› ๏ธ Installation & Setup + +1. **Clone or Download**: Get the project files to your local machine +2. **Open**: Simply open `index.html` in any modern web browser +3. **That's it!** No additional dependencies or build steps required + +### Alternative: Live Server (Recommended for Development) + +If you have VS Code with Live Server extension: +1. Right-click on `index.html` +2. Select "Open with Live Server" +3. The calculator will open in your browser with auto-reload + +## ๐ŸŽฎ Usage + +### Mouse/Touch Controls +- Click number buttons (0-9) to enter numbers +- Click operation buttons (+, -, ร—, รท) to perform calculations +- Click = to calculate the result +- Click C to clear the last entry +- Click AC to clear everything +- Click +/- to change the sign of the current number +- Click . to add decimal point + +### Keyboard Controls +| Key | Action | +|-----|--------| +| 0-9 | Enter numbers | +| + | Addition | +| - | Subtraction | +| * | Multiplication | +| / | Division | +| = or Enter | Calculate result | +| . | Decimal point | +| Escape | Clear all (AC) | +| Backspace | Clear last (C) | + +## ๐Ÿ”ง Technical Details + +### Constraints & Limitations +- **No `eval()` function**: All calculations are performed using proper arithmetic operations +- **8-digit limit**: Numbers exceeding 8 digits will show "ERR" +- **3 decimal places**: Decimal precision limited to 3 places +- **Error handling**: Division by zero and overflow conditions are handled gracefully + +### Browser Compatibility +- โœ… Chrome 60+ +- โœ… Firefox 55+ +- โœ… Safari 12+ +- โœ… Edge 79+ + +## ๐Ÿ“ฑ Responsive Design + +The calculator is fully responsive and adapts to different screen sizes: +- **Desktop**: Full-size calculator with hover effects +- **Tablet**: Medium-size layout optimized for touch +- **Mobile**: Compact layout with larger touch targets + +## ๐ŸŽจ Customization + +### Changing Colors +Edit the CSS variables in `styles.css`: +```css +/* Main colors */ +.calculator { background: #2c3e50; } +.btn-operator { background: #e74c3c; } +.btn-equals { background: #27ae60; } +.btn-clear { background: #f39c12; } +``` + +### Modifying Button Layout +The grid layout can be adjusted in the `.buttons` class: +```css +.buttons { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 15px; +} +``` + +## ๐Ÿ› Error Handling + +The calculator handles several error conditions: + +1. **Division by Zero**: Shows "ERR" and resets after 2 seconds +2. **Overflow**: Numbers exceeding 8 digits show "ERR" +3. **Invalid Operations**: Malformed calculations are caught and handled +4. **Display Formatting**: Long numbers are formatted with commas for readability + +## ๐Ÿค Contributing + +Feel free to contribute to this project! Here are some ways you can help: + +1. **Bug Reports**: Found a bug? Open an issue with details +2. **Feature Requests**: Have an idea? Suggest new features +3. **Code Improvements**: Submit pull requests with enhancements +4. **Documentation**: Help improve this README + +### Development Setup +1. Fork the repository +2. Make your changes +3. Test thoroughly +4. Submit a pull request + +## ๐Ÿ“„ License + +This project is open source and available under the [MIT License](LICENSE). + +## ๐Ÿ™‹โ€โ™‚๏ธ Support + +If you encounter any issues or have questions: +1. Check the existing issues in the repository +2. Create a new issue with detailed information +3. Include screenshots if applicable + +## ๐Ÿ”ฎ Future Enhancements + +Potential features for future versions: +- [ ] Scientific calculator functions (sin, cos, tan, etc.) +- [ ] Memory functions (M+, M-, MR, MC) +- [ ] History of calculations +- [ ] Themes and color customization +- [ ] Unit conversions +- [ ] Export/share results + +--- + +**Made with โค๏ธ using HTML, CSS, and JavaScript** + +*This calculator was built as part of the App Ideas collection, focusing on clean code, user experience, and responsive design.* \ No newline at end of file diff --git a/calculator-app/index.html b/calculator-app/index.html new file mode 100644 index 00000000..4cf1a951 --- /dev/null +++ b/calculator-app/index.html @@ -0,0 +1,49 @@ + + + + + + Calculator App + + + +
+
+
0
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + \ No newline at end of file diff --git a/calculator-app/script.js b/calculator-app/script.js new file mode 100644 index 00000000..162c68fa --- /dev/null +++ b/calculator-app/script.js @@ -0,0 +1,276 @@ +class Calculator { + constructor() { + this.display = document.querySelector('.display-screen'); + this.buttons = document.querySelector('.buttons'); + this.currentNumber = '0'; + this.previousNumber = null; + this.operation = null; + this.waitingForOperand = false; + this.maxDigits = 8; + + this.init(); + } + + init() { + this.buttons.addEventListener('click', this.handleButtonClick.bind(this)); + this.updateDisplay(); + } + + handleButtonClick(event) { + const button = event.target; + + if (!button.classList.contains('btn')) return; + + if (button.hasAttribute('data-number')) { + this.inputNumber(button.getAttribute('data-number')); + } else if (button.hasAttribute('data-action')) { + const action = button.getAttribute('data-action'); + this.handleAction(action); + } + } + + inputNumber(number) { + if (this.waitingForOperand) { + this.currentNumber = number; + this.waitingForOperand = false; + } else { + // Check if we're at the digit limit + const currentLength = this.currentNumber.replace('.', '').length; + if (currentLength >= this.maxDigits) { + return; + } + + this.currentNumber = this.currentNumber === '0' ? number : this.currentNumber + number; + } + + this.updateDisplay(); + } + + handleAction(action) { + switch (action) { + case 'clear-all': + this.clearAll(); + break; + case 'clear': + this.clear(); + break; + case 'sign': + this.changeSign(); + break; + case 'decimal': + this.inputDecimal(); + break; + case 'add': + case 'subtract': + case 'multiply': + case 'divide': + this.performOperation(action); + break; + case 'calculate': + this.calculate(); + break; + } + } + + clearAll() { + this.currentNumber = '0'; + this.previousNumber = null; + this.operation = null; + this.waitingForOperand = false; + this.updateDisplay(); + } + + clear() { + if (this.operation && this.waitingForOperand) { + // If last action was an operation, clear it and show previous number + this.operation = null; + this.waitingForOperand = false; + this.currentNumber = this.previousNumber || '0'; + this.previousNumber = null; + } else { + // Clear current number + this.currentNumber = '0'; + } + this.updateDisplay(); + } + + changeSign() { + if (this.currentNumber !== '0') { + this.currentNumber = this.currentNumber.charAt(0) === '-' + ? this.currentNumber.slice(1) + : '-' + this.currentNumber; + this.updateDisplay(); + } + } + + inputDecimal() { + if (this.waitingForOperand) { + this.currentNumber = '0.'; + this.waitingForOperand = false; + } else if (this.currentNumber.indexOf('.') === -1) { + this.currentNumber += '.'; + } + this.updateDisplay(); + } + + performOperation(nextOperation) { + const inputValue = parseFloat(this.currentNumber); + + if (this.previousNumber === null) { + this.previousNumber = inputValue; + } else if (this.operation) { + const currentValue = this.previousNumber || 0; + const newValue = this.performCalculation(this.operation, currentValue, inputValue); + + if (this.isError(newValue)) { + this.showError(); + return; + } + + this.currentNumber = String(newValue); + this.previousNumber = newValue; + } + + this.waitingForOperand = true; + this.operation = nextOperation; + this.updateDisplay(); + } + + calculate() { + const inputValue = parseFloat(this.currentNumber); + + if (this.previousNumber !== null && this.operation) { + const newValue = this.performCalculation(this.operation, this.previousNumber, inputValue); + + if (this.isError(newValue)) { + this.showError(); + return; + } + + this.currentNumber = String(newValue); + this.previousNumber = null; + this.operation = null; + this.waitingForOperand = true; + this.updateDisplay(); + } + } + + performCalculation(operation, firstOperand, secondOperand) { + switch (operation) { + case 'add': + return firstOperand + secondOperand; + case 'subtract': + return firstOperand - secondOperand; + case 'multiply': + return firstOperand * secondOperand; + case 'divide': + if (secondOperand === 0) { + return NaN; + } + return firstOperand / secondOperand; + default: + return secondOperand; + } + } + + isError(value) { + if (isNaN(value) || !isFinite(value)) { + return true; + } + + // Check if result exceeds 8 digits (excluding decimal point) + const stringValue = String(Math.abs(value)); + const integerPart = stringValue.split('.')[0]; + + return integerPart.length > this.maxDigits; + } + + showError() { + this.display.textContent = 'ERR'; + this.display.classList.add('error'); + + setTimeout(() => { + this.display.classList.remove('error'); + this.clearAll(); + }, 2000); + } + + formatNumber(number) { + const parts = number.split('.'); + const integerPart = parts[0]; + const decimalPart = parts[1]; + + // Format integer part with commas for readability + const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ','); + + if (decimalPart !== undefined) { + // Limit decimal places to 3 + const limitedDecimal = decimalPart.slice(0, 3); + return formattedInteger + '.' + limitedDecimal; + } + + return formattedInteger; + } + + updateDisplay() { + // Remove commas for internal calculations + const cleanNumber = this.currentNumber.replace(/,/g, ''); + + // Format for display + if (cleanNumber === '0' || cleanNumber === '' || cleanNumber === '-0') { + this.display.textContent = '0'; + } else { + this.display.textContent = this.formatNumber(cleanNumber); + } + } +} + +// Initialize calculator when DOM is loaded +document.addEventListener('DOMContentLoaded', () => { + new Calculator(); +}); + +// Keyboard support +document.addEventListener('keydown', (event) => { + const key = event.key; + let button = null; + + if (key >= '0' && key <= '9') { + button = document.querySelector(`[data-number="${key}"]`); + } else { + switch (key) { + case '+': + button = document.querySelector('[data-action="add"]'); + break; + case '-': + button = document.querySelector('[data-action="subtract"]'); + break; + case '*': + button = document.querySelector('[data-action="multiply"]'); + break; + case '/': + event.preventDefault(); // Prevent browser search + button = document.querySelector('[data-action="divide"]'); + break; + case '=': + case 'Enter': + button = document.querySelector('[data-action="calculate"]'); + break; + case '.': + button = document.querySelector('[data-action="decimal"]'); + break; + case 'Escape': + button = document.querySelector('[data-action="clear-all"]'); + break; + case 'Backspace': + button = document.querySelector('[data-action="clear"]'); + break; + } + } + + if (button) { + button.click(); + button.classList.add('btn-active'); + setTimeout(() => button.classList.remove('btn-active'), 100); + } +}); \ No newline at end of file diff --git a/calculator-app/styles.css b/calculator-app/styles.css new file mode 100644 index 00000000..0f0d4e54 --- /dev/null +++ b/calculator-app/styles.css @@ -0,0 +1,157 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Arial', sans-serif; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + min-height: 100vh; + display: flex; + justify-content: center; + align-items: center; + padding: 20px; +} + +.calculator { + background: #2c3e50; + border-radius: 20px; + padding: 20px; + box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3); + width: 100%; + max-width: 400px; +} + +.display { + background: #1a252f; + border-radius: 15px; + padding: 20px; + margin-bottom: 20px; + box-shadow: inset 0 3px 10px rgba(0, 0, 0, 0.3); +} + +.display-screen { + color: #ffffff; + font-size: 2.5rem; + font-weight: 300; + text-align: right; + min-height: 60px; + display: flex; + align-items: center; + justify-content: flex-end; + word-wrap: break-word; + overflow-wrap: break-word; +} + +.buttons { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 15px; +} + +.btn { + background: #34495e; + border: none; + border-radius: 15px; + color: #ffffff; + font-size: 1.2rem; + font-weight: 500; + padding: 20px; + cursor: pointer; + transition: all 0.2s ease; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); + user-select: none; +} + +.btn:hover { + transform: translateY(-2px); + box-shadow: 0 6px 15px rgba(0, 0, 0, 0.3); +} + +.btn:active { + transform: translateY(0); + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); +} + +.btn-number { + background: #34495e; +} + +.btn-number:hover { + background: #4a6274; +} + +.btn-operator { + background: #e74c3c; +} + +.btn-operator:hover { + background: #c0392b; +} + +.btn-equals { + background: #27ae60; + grid-column: span 2; +} + +.btn-equals:hover { + background: #229954; +} + +.btn-clear { + background: #f39c12; +} + +.btn-clear:hover { + background: #d68910; +} + +.btn-zero { + grid-column: span 2; +} + +/* Error state */ +.error { + color: #e74c3c !important; + animation: shake 0.5s ease-in-out; +} + +@keyframes shake { + 0%, 100% { transform: translateX(0); } + 25% { transform: translateX(-5px); } + 75% { transform: translateX(5px); } +} + +/* Responsive design */ +@media (max-width: 480px) { + .calculator { + padding: 15px; + margin: 10px; + } + + .display-screen { + font-size: 2rem; + min-height: 50px; + } + + .btn { + padding: 15px; + font-size: 1.1rem; + } + + .buttons { + gap: 10px; + } +} + +@media (max-width: 360px) { + .display-screen { + font-size: 1.8rem; + } + + .btn { + padding: 12px; + font-size: 1rem; + } +} \ No newline at end of file