diff --git a/Hanzala Bhoraniya/Glass_Calculator/Assets/Icons/backspace-svgrepo-com.svg b/Hanzala Bhoraniya/Glass_Calculator/Assets/Icons/backspace-svgrepo-com.svg new file mode 100644 index 00000000..fdf629da --- /dev/null +++ b/Hanzala Bhoraniya/Glass_Calculator/Assets/Icons/backspace-svgrepo-com.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Hanzala Bhoraniya/Glass_Calculator/Assets/Icons/gemini-svg.svg b/Hanzala Bhoraniya/Glass_Calculator/Assets/Icons/gemini-svg.svg new file mode 100644 index 00000000..61631745 --- /dev/null +++ b/Hanzala Bhoraniya/Glass_Calculator/Assets/Icons/gemini-svg.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Hanzala Bhoraniya/Glass_Calculator/README.md b/Hanzala Bhoraniya/Glass_Calculator/README.md new file mode 100644 index 00000000..c58779d6 --- /dev/null +++ b/Hanzala Bhoraniya/Glass_Calculator/README.md @@ -0,0 +1,32 @@ +![Calculator Preview](./preview.png) +# 🧮 Glass Calculator + +A beautifully designed, fully functional web-based calculator featuring a modern **Glassmorphism** user interface. This project was built to practice DOM manipulation, JavaScript logic, and advanced CSS styling techniques. + +## ✨ Features + +* **Glassmorphism UI:** Built with translucent backgrounds, frosted glass effects (`backdrop-filter`), and subtle borders to create a sleek, modern look. +* **Animated Background:** Features a custom CSS `@keyframes` animation with moving ambient radial gradients. +* **Dynamic Display:** The calculator features a dual-display system. It shows your current equation on top and automatically calculates the live answer on the bottom as you type. +* **Full Functionality:** * Standard arithmetic operations (`+`, `-`, `×`, `÷`) + * Percentage calculations (`%`) + * Decimal support with logic to prevent multiple/invalid decimal placements + * Backspace and All Clear (`AC`) functionality + +## 🛠️ Tech Stack + +* **HTML5:** Semantic structure and layout. +* **CSS3:** Advanced styling, CSS Grid for the button layout, Flexbox, keyframe animations, and custom hover states. +* **JavaScript (Vanilla):** Event listeners, error handling (`try/catch`), string parsing, and calculation logic. + +## 🚀 What I Learned + +While building this project, I strengthened my skills in: +* **CSS Grid & Flexbox:** Precisely aligning the calculator buttons and display areas. +* **Event Delegation:** Handling clicks for all calculator buttons efficiently. +* **Edge-case Logic:** Writing JavaScript to handle weird user inputs (like pressing multiple decimals or operators in a row). + +## 👤 Author + +**Hanzala Bhoraniya** +* Part of the Web Development journey (Delta Projects) \ No newline at end of file diff --git a/Hanzala Bhoraniya/Glass_Calculator/index.html b/Hanzala Bhoraniya/Glass_Calculator/index.html new file mode 100644 index 00000000..d1ac17c4 --- /dev/null +++ b/Hanzala Bhoraniya/Glass_Calculator/index.html @@ -0,0 +1,49 @@ + + + + + + My Glass Calculator + + + + +
+

Glass Calculator

+
+
+
+

+

+
+
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + diff --git a/Hanzala Bhoraniya/Glass_Calculator/preview.png b/Hanzala Bhoraniya/Glass_Calculator/preview.png new file mode 100644 index 00000000..e269e925 Binary files /dev/null and b/Hanzala Bhoraniya/Glass_Calculator/preview.png differ diff --git a/Hanzala Bhoraniya/Glass_Calculator/script.js b/Hanzala Bhoraniya/Glass_Calculator/script.js new file mode 100644 index 00000000..56c401ae --- /dev/null +++ b/Hanzala Bhoraniya/Glass_Calculator/script.js @@ -0,0 +1,126 @@ +let display = document.querySelector("#calculator-display"); +let upperDisplay = document.querySelector("#upper-text"); +let lowerDisplay = document.querySelector("#lower-text"); +let nums = document.querySelectorAll(".nums"); +let operator = document.querySelectorAll(".operator"); +let action = document.querySelectorAll(".action"); +let allBtns = document.querySelector("#all-btns"); +let btns = document.querySelectorAll(".btns"); +let backspace = document.querySelector("#backspace"); +let validOperators = ["+", "-", "×", "÷"]; +// All functions defination. +function clearAll() { + upperDisplay.innerText = ""; + lowerDisplay.innerText = ""; + upperDisplay.classList.remove("small-text"); + lowerDisplay.classList.add("small-text"); +} +function getAns(number) { + try { + if (validOperators.includes(number[number.length - 1])) { + number = number.slice(0, -1); + } + number = number.replaceAll("÷", "/").replaceAll("×", "*"); + return eval(number); + } catch (error) { + console.log(error); + return "error"; + } +} +function parts(text) { + return text.split(/[\×\÷\+\-]/); +} +// All other logic +allBtns.addEventListener("click", (event) => { + if (event.target.classList.contains("btns")) { + if (event.target.classList.contains("action")) { + if (event.target.innerText === `AC`) { + clearAll(); + } else if (event.target.innerText === "=") { + lowerDisplay.innerText = `=${getAns(upperDisplay.innerText)}`; + // adding and removing class. + lowerDisplay.classList.remove("small-text"); + upperDisplay.classList.add("small-text"); + } else if (event.target.innerText === "%") { + let equationArr = parts(upperDisplay.innerText); + let percentNum = equationArr[equationArr.length - 1] / 100; + let lastNumLength = equationArr[equationArr.length - 1].length; + let firstText = upperDisplay.innerText.slice(0, -lastNumLength); + upperDisplay.innerText = firstText + percentNum; + lowerDisplay.innerText = `=${getAns(upperDisplay.innerText)}`; + } else if (event.target === backspace) { + upperDisplay.innerText = upperDisplay.innerText.slice(0, -1); + if (upperDisplay.innerText === "") { + lowerDisplay.innerText = ""; + return; + } + lowerDisplay.innerText = `=${getAns(upperDisplay.innerText)}`; + } + } else if (event.target.classList.contains("operator")) { + if (upperDisplay.innerText === "0" || upperDisplay.innerText === "") { + upperDisplay.innerText = ""; + } else if ( + validOperators.includes( + upperDisplay.innerText[upperDisplay.innerText.length - 1], + ) + ) { + upperDisplay.innerText = + upperDisplay.innerText.slice(0, -1) + event.target.innerText; + } else if (upperDisplay.classList.contains("small-text")) { + upperDisplay.classList.remove("small-text"); + lowerDisplay.classList.add("small-text"); + lowerDisplay.innerText = `=${getAns(upperDisplay.innerText)}`; + upperDisplay.innerText = + lowerDisplay.innerText.slice(1) + event.target.innerText; + } else { + upperDisplay.innerText += event.target.innerText; + } + } else if (event.target.classList.contains("nums")) { + if (event.target.innerText === ".") { + //1. cheking if the last charedter is alredy dot but then also user is pressing dot btn again do notiong. + if ((upperDisplay.innerText[upperDisplay.innerText.length - 1] === ".")) { + upperDisplay.innerText = + upperDisplay.innerText.slice(0, -1) + event.target.innerText; + // upperDisplay.innerText += event.target.innerText; + } + //2. cheking if the last element is the a opeator then write 0. insted of directly writing decimal after a valid operator. + else if (validOperators.includes(upperDisplay.innerText[upperDisplay.innerText.length - 1])) { + upperDisplay.innerText += "0."; + } + //3. cheking if the number which currently user is typing alredy consist dot if yes then do noting. + else if (upperDisplay.innerText.includes(".") && upperDisplay.innerText.length > 0) { + let decimalArr = parts(upperDisplay.innerText); + if (!(decimalArr[decimalArr.length - 1].includes("."))) { + upperDisplay.innerText += "."; + } + } + //4. cheking if the user is pressing the dot as his first num then we will write 0. inted of just writing dot which will create an err. + else if (upperDisplay.innerText === "" || upperDisplay.innerText === "0") { + upperDisplay.innerText = "0."; + } + else { + upperDisplay.innerText += event.target.innerText + } + } + else if (upperDisplay.innerText === "0" || upperDisplay.innerText === "") { + if (event.target.innerText === "0") { + upperDisplay.innerText = 0; + } + else { + upperDisplay.innerText = event.target.innerText; + lowerDisplay.innerText = `=${getAns(upperDisplay.innerText)}`; + } + } + else { + if (upperDisplay.classList.contains("small-text")) { + upperDisplay.classList.remove("small-text"); + lowerDisplay.classList.add("small-text"); + clearAll(); + upperDisplay.innerText = lowerDisplay.innerText.slice(1); + } + upperDisplay.innerText += event.target.innerText; + lowerDisplay.innerText = `=${getAns(upperDisplay.innerText)}`; + } + } + } +}); diff --git a/Hanzala Bhoraniya/Glass_Calculator/style.css b/Hanzala Bhoraniya/Glass_Calculator/style.css new file mode 100644 index 00000000..6f9d92eb --- /dev/null +++ b/Hanzala Bhoraniya/Glass_Calculator/style.css @@ -0,0 +1,223 @@ +body { + background-color: #0d0a20; + font-family: inter; + background-image: + radial-gradient( + circle at 10% 40%, + rgba(114, 28, 238, 0.6) 0%, + transparent 50% + ), + radial-gradient( + circle at 90% 60%, + rgba(220, 38, 146, 0.6) 0%, + transparent 50% + ), + radial-gradient( + circle at 50% 120%, + rgba(31, 142, 240, 0.5) 0%, + transparent 60% + ); + background-size: 200% 200%; + animation: animateBg 10s ease-in-out infinite; + min-height: 100vh; + min-width: 100vw; + margin: 0; + padding: 0; + /* flex properties */ + display: flex; + /* justify-content: center; */ + align-items: center; + flex-direction: column; +} +h1, +button { + font-family: poppins; +} +h1 { + color: rgba(255, 255, 255, 0.87); + text-align: center; + /* margin: 0; */ +} +@keyframes animateBg { + 0% { + background-position: 0% 50%; + } + 25% { + background-position: 50% 100%; + } + 50% { + background-position: 100% 50%; + } + 75% { + background-position: 50% 0%; + } + 100% { + background-position: 0% 50%; + } +} +@keyframes animateBorder { + from { + transform: translate(-50%,-50%) rotate(0deg); + } + to { + transform: translate(-50%,-50%) rotate(360deg); + } +} +#header-text { + /* background-color: black; */ +} +#calculator-display { + font-family: monospace; + width: 100%; + background-color: rgba(255, 255, 255, 0.15); + /* background-color: rgba(0, 0, 0, 0.2); */ + min-height: 140px; + margin: 0 auto; + border-radius: 0.75rem; + border: 1.5px solid rgba(255, 255, 255, 0.3); + font-size: 3.5rem; + color: rgba(255, 255, 255, 0.87); + display: flex; + flex-direction: column; + justify-content: flex-end; + align-items: flex-end; + padding: 1rem; + box-sizing: border-box; + line-height: 0.7; + overflow: hidden; +} +.display-text { + flex: 1; + margin: 0; + line-height: 1; + /* background-color: green; */ + padding: 0; +} +#upper-text { + /* background-color: green; */ + max-height: 50%; + transition: 0.15s ease-in-out; +} +#lower-text { + /* background-color: black; */ + max-height: 50%; + transition: 0.15s ease-in-out; +} +.small-text { + font-size: 2rem; + color: rgba(255, 255, 255, 0.6); +} +#all-btns { + /* background-color: green; */ + height: auto; + flex-grow: 1; + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + grid-template-rows: 1fr 1fr 1fr 1fr 1fr; + gap: 0.8rem; +} +.btns { + border-radius: 0.75rem; + background-color: rgba(255, 255, 255, 0.15); + font-size: 1.7rem; + font-family: "Space mono"; + font-weight: 400; +} +.nums { + background-color: rgba(255, 255, 255, 0.87); + border: 2px rgba(255, 255, 255, 0.2); + transition: 0.05s ease-in-out; +} +.operator { + box-shadow: inset 0 0 15px 0 rgba(255, 255, 255, 0.2); + border: 2px solid rgb(255, 150, 50, 0.5); + transition: 0.05s ease-in-out; +} +.action { + box-shadow: inset 0 0 15px 0 rgba(255, 255, 255, 0.2); + border: 2px solid rgba(50, 200, 255, 0.5); + transition: 0.05s ease-in-out; +} +.nums:hover { + background-color: rgba(255, 255, 255); + box-shadow: 0 0 15px 0 rgba(255, 255, 255, 0.2); + transform: scale(1.01); +} +.operator:hover { + background-color: rgba(255, 250, 50, 0.15); + box-shadow: 0 0 10px 0 rgba(255, 250, 50, 0.4); + transform: scale(1.01); +} +.action:hover { + background-color: rgba(50, 200, 255, 0.15); + box-shadow: 0 0 15px 0 rgba(50, 200, 255, 0.5); + transform: scale(1.01); +} +#backspace img { + width: 1.77rem; + height: auto; + filter: invert(1); + pointer-events: none; +} +#backspace { + display: flex; + justify-content: center; + align-items: center; +} +.zero { + grid-area: 5/1/6/3; +} +.one { + grid-area: 4/1/5/2; +} +.two { + grid-area: 4/2/5/3; +} +.three { + grid-area: 4/3/5/4; +} +.four { + grid-area: 3/1/4/2; +} +.five { + grid-area: 3/2/4/3; +} +.six { + grid-area: 3/3/4/4; +} +.seven { + grid-area: 2/1/3/2; +} +.eight { + grid-area: 2/2/3/3; +} +.nine { + grid-area: 2/3/3/4; +} +.dot { + grid-area: 5/3/6/4; +} +#equal { + grid-area: 5/4/6/5; +} +#calculator { + height: auto; + min-height: 550px; + width: 100%; + max-width: 420px; + background-color: rgba(255, 255, 255, 0.15); + backdrop-filter: blur(15px); + -webkit-backdrop-filter: blur(15px); + border: 2px solid rgba(255, 255, 255, 0.3); + border-radius: 0.85rem; + padding: 1.4rem; + box-shadow: + 0px 8px 32px 0px rgba(0, 0, 0, 0.3), + inset 0 0 25px 0 rgba(255, 255, 255, 0.1); + /* margin-bottom: 0rem; */ + /* flex properties */ + display: flex; + flex-direction: column; + justify-content: space-between; + gap: 1.4rem; +}