diff --git a/Domains/Frontend/MiniProjects/CSS-Gradient-Generator/README.md b/Domains/Frontend/MiniProjects/CSS-Gradient-Generator/README.md new file mode 100644 index 00000000..4d367d36 --- /dev/null +++ b/Domains/Frontend/MiniProjects/CSS-Gradient-Generator/README.md @@ -0,0 +1,21 @@ +# CSS Gradient Generator +**Contributor:** [Aerospace Prog](https://github.com/Aerospace-prog) + +## Description +An interactive and responsive tool to generate CSS linear and radial gradients. Users can select two primary colors, add multiple color stops, choose a gradient type (linear/radial) and direction, and even generate random gradients. The generated CSS code can be easily copied to the clipboard. + +## Features +- **Linear and Radial Gradients:** Choose between different gradient types. +- **Multiple Color Stops:** Add and remove additional colors to create complex gradients. +- **Customizable Colors:** Easily pick colors using color input fields. +- **Direction Control:** Set the direction for linear gradients. +- **Random Gradient Generator:** Get inspired with randomly generated gradients. +- **Instant Preview:** See your gradient changes in real-time. +- **Copy CSS:** One-click copy of the generated CSS code. +- **Responsive Design:** Works seamlessly across various screen sizes. + +## How to Run +1. Open `index.html` in your web browser. +2. Experiment with different colors, add color stops, select gradient types and directions. +3. Click "Generate Gradient" to apply your selections or "Random Gradient" for inspiration. +4. Click "Copy CSS" to copy the generated CSS to your clipboard. \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/CSS-Gradient-Generator/index.html b/Domains/Frontend/MiniProjects/CSS-Gradient-Generator/index.html new file mode 100644 index 00000000..cb425ef7 --- /dev/null +++ b/Domains/Frontend/MiniProjects/CSS-Gradient-Generator/index.html @@ -0,0 +1,54 @@ + + + + + + CSS Gradient Generator + + + +
+

CSS Gradient Generator

+
+
+
+ + +
+
+ + + + +
+
+ +
+ +
+ + +
+ + +
+
+ + +
+
+ + + \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/CSS-Gradient-Generator/script.js b/Domains/Frontend/MiniProjects/CSS-Gradient-Generator/script.js new file mode 100644 index 00000000..d9370728 --- /dev/null +++ b/Domains/Frontend/MiniProjects/CSS-Gradient-Generator/script.js @@ -0,0 +1,109 @@ +document.addEventListener('DOMContentLoaded', () => { + const color1Input = document.getElementById('color1'); + const color2Input = document.getElementById('color2'); + const directionSelect = document.getElementById('direction'); + const generateBtn = document.getElementById('generate-btn'); + const gradientPreview = document.querySelector('.gradient-preview'); + const cssOutput = document.getElementById('css-output'); + const copyBtn = document.getElementById('copy-btn'); + const gradientTypeSelect = document.getElementById('gradient-type'); + const addColorStopBtn = document.getElementById('add-color-stop'); + const colorStopsContainer = document.getElementById('color-stops-container'); + const randomBtn = document.getElementById('random-btn'); + + let colorStops = []; + + function updateGradient() { + const gradientType = gradientTypeSelect.value; + const colors = [color1Input.value, ...colorStops.map(cs => cs.input.value), color2Input.value]; + const direction = directionSelect.value; + + let gradientCSS; + if (gradientType === 'linear') { + gradientCSS = `linear-gradient(${direction}, ${colors.join(', ')})`; + } else { + // For radial, direction can be 'circle at center', 'ellipse at center', etc. or just 'circle', 'ellipse' + // For simplicity, we'll use 'circle at center' for now or just omit if direction is not shape-based + const radialShape = direction.includes('deg') ? 'circle' : direction; // Simple heuristic + gradientCSS = `radial-gradient(${radialShape}, ${colors.join(', ')})`; + } + + gradientPreview.style.background = gradientCSS; + cssOutput.value = `background: ${gradientCSS};`; + } + + function addColorStop() { + const newColorStop = { + id: `color-stop-${colorStops.length}`, + input: document.createElement('input'), + removeBtn: document.createElement('button') + }; + + newColorStop.input.type = 'color'; + newColorStop.input.value = '#ffffff'; // Default to white + newColorStop.input.addEventListener('input', updateGradient); + + newColorStop.removeBtn.textContent = 'X'; + newColorStop.removeBtn.className = 'remove-color-stop'; + newColorStop.removeBtn.onclick = () => { + colorStopsContainer.removeChild(newColorStop.input); + colorStopsContainer.removeChild(newColorStop.removeBtn); + colorStops = colorStops.filter(cs => cs.id !== newColorStop.id); + updateGradient(); + }; + + colorStopsContainer.appendChild(newColorStop.input); + colorStopsContainer.appendChild(newColorStop.removeBtn); + colorStops.push(newColorStop); + updateGradient(); + } + + function generateRandomColor() { + const randomColor = '#' + Math.floor(Math.random()*16777215).toString(16); + return randomColor.padEnd(7, '0'); // Ensure 6 characters + } + + function generateRandomGradient() { + color1Input.value = generateRandomColor(); + color2Input.value = generateRandomColor(); + + // Clear existing color stops + colorStops.forEach(cs => { + colorStopsContainer.removeChild(cs.input); + colorStopsContainer.removeChild(cs.removeBtn); + }); + colorStops = []; + + // Add 0-2 random color stops + const numRandomStops = Math.floor(Math.random() * 3); // 0, 1, or 2 + for (let i = 0; i < numRandomStops; i++) { + addColorStop(); + colorStops[i].input.value = generateRandomColor(); + } + + const directions = ['to right', 'to left', 'to top', 'to bottom', '45deg', '90deg', '135deg', '180deg']; + directionSelect.value = directions[Math.floor(Math.random() * directions.length)]; + + const gradientTypes = ['linear', 'radial']; + gradientTypeSelect.value = gradientTypes[Math.floor(Math.random() * gradientTypes.length)]; + + updateGradient(); + } + + // Initial gradient update + updateGradient(); + + color1Input.addEventListener('input', updateGradient); + color2Input.addEventListener('input', updateGradient); + directionSelect.addEventListener('change', updateGradient); + gradientTypeSelect.addEventListener('change', updateGradient); + generateBtn.addEventListener('click', updateGradient); + addColorStopBtn.addEventListener('click', addColorStop); + randomBtn.addEventListener('click', generateRandomGradient); + + copyBtn.addEventListener('click', () => { + cssOutput.select(); + document.execCommand('copy'); + alert('CSS copied to clipboard!'); + }); +}); \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/CSS-Gradient-Generator/style.css b/Domains/Frontend/MiniProjects/CSS-Gradient-Generator/style.css new file mode 100644 index 00000000..7498207c --- /dev/null +++ b/Domains/Frontend/MiniProjects/CSS-Gradient-Generator/style.css @@ -0,0 +1,265 @@ +body { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + display: flex; + justify-content: center; + align-items: center; + min-height: 100vh; + margin: 0; + background: linear-gradient(to right, #6a11cb, #2575fc); /* Modern background */ + color: #333; +} + +.container { + background-color: #fff; + background-image: linear-gradient(to bottom right, #ffffff, #f0f0f0); + padding: 30px; + border-radius: 15px; + box-shadow: 0 15px 40px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(255, 255, 255, 0.6) inset; + text-align: center; + width: 90%; + max-width: 700px; + box-sizing: border-box; + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); +} + +h1 { + color: #1a2a6c; /* Darker, more prominent heading */ + margin-bottom: 25px; + font-size: 2.2em; +} + +.gradient-preview { + width: 100%; + height: 180px; + border-radius: 10px; + margin-bottom: 30px; + border: 2px solid #eee; + box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.05); +} + +.controls { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 20px; + margin-bottom: 30px; +} + +.control-group { + display: flex; + flex-direction: column; + align-items: flex-start; + margin-bottom: 15px; +} + +.controls label { + margin-bottom: 8px; + font-weight: 600; + color: #555; + font-size: 1.1em; +} + +.controls input[type="color"] { + width: 70px; + height: 35px; + border: 2px solid #b0b0b0; + border-radius: 8px; + cursor: pointer; + transition: all 0.3s ease; + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2), 0 1px rgba(255, 255, 255, 0.7); +} + +.controls input[type="color"]:hover { + border-color: #007bff; + transform: translateY(-1px); + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2), 0 3px 8px rgba(0, 123, 255, 0.2); +} + +.controls select { + width: 180px; + padding: 10px 12px; + border: 1px solid #b0b0b0; + border-radius: 8px; + font-size: 1em; + background-color: #f9f9f9; + appearance: none; + -webkit-appearance: none; + background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23007bff%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-6.5%200-12.3%203.2-16.1%208.1-3.8%204.9-4.6%2011-2.4%2017.4l133.7%20160.5c2.7%203.4%206.2%205.4%2010.1%205.4s7.4-2%2010.1-5.4L289.4%2094.3c2.2-6.4%201.4-12.5-2.4-17.4z%22%2F%3E%3C%2Fsvg%3E'); + background-repeat: no-repeat; + background-position: right 10px center; + background-size: 12px; + cursor: pointer; + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px rgba(255, 255, 255, 0.7); + transition: all 0.3s ease; +} + +.controls select:hover { + border-color: #007bff; + transform: translateY(-1px); + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 3px 8px rgba(0, 123, 255, 0.2); +} + +.controls button { + background-image: linear-gradient(to bottom, #007bff, #0056b3); + color: white; + padding: 12px 25px; + border: none; + border-radius: 6px; + cursor: pointer; + font-size: 1.05em; + font-weight: 600; + transition: all 0.3s ease; + margin-top: 10px; + box-shadow: 0 4px 15px rgba(0, 123, 255, 0.3); + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); +} + +.controls button:hover { + background-image: linear-gradient(to bottom, #0056b3, #003f7f); + transform: translateY(-2px) scale(1.02); + box-shadow: 0 6px 20px rgba(0, 123, 255, 0.4); +} + +#random-btn { + background-image: linear-gradient(to bottom, #28a745, #1e7e34); +} + +#random-btn:hover { + background-image: linear-gradient(to bottom, #1e7e34, #155d27); +} + +#add-color-stop { + background-image: linear-gradient(to bottom, #6c757d, #5a6268); +} + +#add-color-stop:hover { + background-image: linear-gradient(to bottom, #5a6268, #494f54); +} + +.output { + margin-top: 30px; +} + +.output textarea { + width: calc(100% - 20px); + padding: 15px; + border: 1px solid #b0b0b0; + border-radius: 10px; + font-family: 'Fira Code', 'Courier New', Courier, monospace; + font-size: 0.95em; + resize: vertical; + margin-bottom: 15px; + background-color: #f8f8f8; + color: #333; + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px rgba(255, 255, 255, 0.7); + transition: all 0.3s ease; +} + +.output textarea:focus { + border-color: #007bff; + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 0 3px rgba(0, 123, 255, 0.2); + outline: none; +} + +.output button { + background-image: linear-gradient(to bottom, #6f42c1, #5935a1); + color: white; + padding: 12px 25px; + border: none; + border-radius: 6px; + cursor: pointer; + font-size: 1.05em; + font-weight: 600; + transition: all 0.3s ease; + box-shadow: 0 4px 15px rgba(111, 66, 193, 0.3); + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); +} + +.output button:hover { + background-image: linear-gradient(to bottom, #5935a1, #462a80); + transform: translateY(-2px) scale(1.02); + box-shadow: 0 6px 20px rgba(111, 66, 193, 0.4); +} + +/* Responsive adjustments */ +@media (max-width: 768px) { + .container { + padding: 20px; + } + + h1 { + font-size: 1.8em; + } + + .controls { + flex-direction: column; + align-items: stretch; + } + + .controls select, .controls button { + width: 100%; + margin-top: 10px; + } + + .control-group { + width: 100%; + align-items: center; + } + + .controls input[type="color"] { + margin: 0 5px 10px; + } +} + +@media (max-width: 480px) { + h1 { + font-size: 1.5em; + } + + .gradient-preview { + height: 120px; + } + + .controls button, .output button { + padding: 10px 20px; + font-size: 1em; + } +} + + +.toast-notification { + visibility: hidden; + min-width: 250px; + background-color: #333; + color: #fff; + text-align: center; + border-radius: 8px; + padding: 16px; + position: fixed; + z-index: 1; + left: 50%; + bottom: 30px; + transform: translateX(-50%); + font-size: 1.1em; + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); + opacity: 0; + transition: opacity 0.3s, bottom 0.3s; +} + +.toast-notification.show { + visibility: visible; + animation: fadein 0.5s, fadeout 0.5s 2.5s; + bottom: 50px; + opacity: 1; +} + +@keyframes fadein { + from {bottom: 30px; opacity: 0;} + to {bottom: 50px; opacity: 1;} +} + +@keyframes fadeout { + from {bottom: 50px; opacity: 1;} + to {bottom: 30px; opacity: 0;} +} \ No newline at end of file