diff --git a/Index.md b/Index.md index 5fb8d6d5c..7dbd2c02b 100644 --- a/Index.md +++ b/Index.md @@ -111,3 +111,4 @@ | [Pomodoro Timer](https://github.com/Ayushparikh-code/Web-dev-mini-projects/tree/main/Pomodoro-Timer) | A simple Pomodoro Timer using React.js, where you can track the time spent on work and break. | | [TravelPro](https://github.com/Ayushparikh-code/Web-dev-mini-projects/tree/main/TravelPro) | A simple static website to enhance HTML & CSS skills | |[Audio Visualization with three.js](https://github.com/Ayushparikh-code/Web-dev-mini-projects/tree/main/Audio%20Visualization%20with%20three.js) | audio visualization using the powerful 3D graphics library, three.js | +| [Unit Converter](https://github.com/Ayushparikh-code/Web-dev-mini-projects/tree/main/Unit-Converter) | A beginner-friendly web app to convert length and weight units with instant results and unit swap support. | diff --git a/Unit-Converter/README.md b/Unit-Converter/README.md new file mode 100644 index 000000000..e41731aa4 --- /dev/null +++ b/Unit-Converter/README.md @@ -0,0 +1,34 @@ +# Unit Converter + +A beginner-friendly web app to convert units quickly. + +## Features + +- Convert **length** units: meter, kilometer, centimeter, mile, foot +- Convert **weight** units: kilogram, gram, pound, ounce +- Swap units with one click +- Instant conversion as you type +- Basic invalid-input handling + +## Tech Stack + +- HTML +- CSS +- JavaScript + +## How to Run + +1. Open the `Unit-Converter` folder. +2. Open `index.html` in your browser. + +No build tools or dependencies required. + +## Screenshot + +Add your screenshot file here: + +- `Unit-Converter/preview.jpeg` + +Then this README will render it: + +![Unit Converter Preview](preview.jpeg) diff --git a/Unit-Converter/index.html b/Unit-Converter/index.html new file mode 100644 index 000000000..720f47689 --- /dev/null +++ b/Unit-Converter/index.html @@ -0,0 +1,51 @@ + + + + + + Unit Converter + + + +
+

Unit Converter

+

Convert length and weight values instantly.

+ +
+ + + +
+
+ + +
+ +
+ + +
+ + + +
+ + +
+ +
+ + +
+
+ +

+
+
+ + + + diff --git a/Unit-Converter/preview.jpeg b/Unit-Converter/preview.jpeg new file mode 100644 index 000000000..303045c8f Binary files /dev/null and b/Unit-Converter/preview.jpeg differ diff --git a/Unit-Converter/script.js b/Unit-Converter/script.js new file mode 100644 index 000000000..d018abb2b --- /dev/null +++ b/Unit-Converter/script.js @@ -0,0 +1,97 @@ +const unitConfig = { + length: { + meter: 1, + kilometer: 1000, + centimeter: 0.01, + mile: 1609.34, + foot: 0.3048 + }, + weight: { + kilogram: 1, + gram: 0.001, + pound: 0.453592, + ounce: 0.0283495 + } +}; + +const categoryEl = document.getElementById("category"); +const fromValueEl = document.getElementById("fromValue"); +const toValueEl = document.getElementById("toValue"); +const fromUnitEl = document.getElementById("fromUnit"); +const toUnitEl = document.getElementById("toUnit"); +const swapBtn = document.getElementById("swapBtn"); +const messageEl = document.getElementById("message"); + +function formatUnitName(unit) { + return unit.charAt(0).toUpperCase() + unit.slice(1); +} + +function populateUnitOptions() { + const category = categoryEl.value; + const units = Object.keys(unitConfig[category]); + + fromUnitEl.innerHTML = ""; + toUnitEl.innerHTML = ""; + + units.forEach((unit, index) => { + const fromOption = document.createElement("option"); + fromOption.value = unit; + fromOption.textContent = formatUnitName(unit); + fromUnitEl.appendChild(fromOption); + + const toOption = document.createElement("option"); + toOption.value = unit; + toOption.textContent = formatUnitName(unit); + toUnitEl.appendChild(toOption); + + if (index === 1) { + toUnitEl.value = unit; + } + }); +} + +function convertValue() { + const rawValue = fromValueEl.value.trim(); + const inputValue = Number(rawValue); + + if (!rawValue) { + toValueEl.value = ""; + messageEl.textContent = ""; + return; + } + + if (Number.isNaN(inputValue)) { + toValueEl.value = ""; + messageEl.textContent = "Please enter a valid number."; + return; + } + + const category = categoryEl.value; + const fromUnit = fromUnitEl.value; + const toUnit = toUnitEl.value; + + const valueInBaseUnit = inputValue * unitConfig[category][fromUnit]; + const converted = valueInBaseUnit / unitConfig[category][toUnit]; + + toValueEl.value = converted.toFixed(6).replace(/\.?0+$/, ""); + messageEl.textContent = ""; +} + +function swapUnits() { + const previousFromUnit = fromUnitEl.value; + fromUnitEl.value = toUnitEl.value; + toUnitEl.value = previousFromUnit; + convertValue(); +} + +categoryEl.addEventListener("change", () => { + populateUnitOptions(); + convertValue(); +}); + +fromValueEl.addEventListener("input", convertValue); +fromUnitEl.addEventListener("change", convertValue); +toUnitEl.addEventListener("change", convertValue); +swapBtn.addEventListener("click", swapUnits); + +populateUnitOptions(); diff --git a/Unit-Converter/style.css b/Unit-Converter/style.css new file mode 100644 index 000000000..cc628e3eb --- /dev/null +++ b/Unit-Converter/style.css @@ -0,0 +1,118 @@ +:root { + --bg: #eef3f8; + --card: #ffffff; + --text: #1e293b; + --muted: #64748b; + --accent: #0f766e; + --accent-dark: #0b5a54; + --border: #d6e0eb; +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; + min-height: 100vh; + font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; + background: radial-gradient(circle at top, #f8fbff, var(--bg)); + color: var(--text); + display: grid; + place-items: center; + padding: 1rem; +} + +.container { + width: min(720px, 100%); +} + +h1 { + margin: 0 0 0.35rem; + font-size: clamp(1.8rem, 2.8vw, 2.2rem); + text-align: center; +} + +.subtitle { + margin: 0 0 1.25rem; + color: var(--muted); + text-align: center; +} + +.card { + background: var(--card); + border: 1px solid var(--border); + border-radius: 14px; + padding: 1rem; + box-shadow: 0 10px 24px rgba(15, 23, 42, 0.08); +} + +label { + display: block; + font-weight: 600; + margin-bottom: 0.4rem; +} + +select, +input, +button { + width: 100%; + padding: 0.65rem 0.75rem; + border-radius: 10px; + border: 1px solid #cbd5e1; + font-size: 1rem; +} + +input[readonly] { + background-color: #f8fafc; +} + +select:focus, +input:focus, +button:focus { + outline: 2px solid #99f6e4; + outline-offset: 2px; +} + +.converter-grid { + margin-top: 1rem; + display: grid; + gap: 0.9rem; + grid-template-columns: 1fr 1fr auto 1fr 1fr; + align-items: end; +} + +.field { + min-width: 0; +} + +#swapBtn { + width: auto; + background-color: var(--accent); + color: #fff; + border: none; + cursor: pointer; + padding: 0.65rem 1rem; + transition: background-color 0.2s ease; +} + +#swapBtn:hover { + background-color: var(--accent-dark); +} + +.message { + margin: 0.95rem 0 0; + min-height: 1.4rem; + color: #b42318; + font-size: 0.95rem; +} + +@media (max-width: 720px) { + .converter-grid { + grid-template-columns: 1fr; + } + + #swapBtn { + width: 100%; + } +}