From e9409ef876ead65f1738fd14a6272350c220dfb7 Mon Sep 17 00:00:00 2001 From: Aaditya Agarwal <146380217+psy-duck1@users.noreply.github.com> Date: Wed, 22 Oct 2025 01:06:34 +0530 Subject: [PATCH 1/3] Refactor index.html for Weather Dashboard Updated the HTML structure and elements for the weather site, including changing the title to 'Weather Dashboard', modifying input fields, and enhancing the layout with new classes and sections. --- Javascript/Weather Site/index.html | 136 ++++++++++++++++++----------- 1 file changed, 86 insertions(+), 50 deletions(-) diff --git a/Javascript/Weather Site/index.html b/Javascript/Weather Site/index.html index 22640db..675fc00 100644 --- a/Javascript/Weather Site/index.html +++ b/Javascript/Weather Site/index.html @@ -1,61 +1,97 @@ - - - Weather App - + + + Weather Dashboard + -
-
-

Weather App

-
- - -
-
+ +
+
+
-
-
-
- weather icon -
--°C
-
--
+
+ +
+

Weather Dashboard

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

Loading...

+
+
+
+ --° + +
+
Loading weather data...
+
+ + +
+
+
🌡️
+
+

Feels Like

+
--°
+
+
+
+
💧
+
+

Humidity

+
--%
+
+
+
+
💨
+
+

Wind Speed

+
-- m/s
+
+
+
+
🎚️
+
+

Pressure

+
-- hPa
+
+
+
+
👁️
+
+

Visibility

+
-- km
+
+
+
+
☀️
+
+

UV Index

+
--
+
+
-
-
-
-
Location
-
--
-
-
-
Local Time
-
--
-
-
-
-
-
Humidity
-
--%
-
-
-
Wind
-
-- kph
-
-
-
Feels Like
-
--°C
-
-
-
Data from WeatherAPI.com
+ + +
+

5-Day Forecast

+
+ +
-
- - -
-
+ - + From b792fb86a227cca387ccaaa42cd4cd17c91d07a3 Mon Sep 17 00:00:00 2001 From: Aaditya Agarwal <146380217+psy-duck1@users.noreply.github.com> Date: Wed, 22 Oct 2025 01:07:35 +0530 Subject: [PATCH 2/3] Refactor CSS for improved styling and responsiveness Updated styles for the weather site with new variables, animations, and responsive design. --- Javascript/Weather Site/style.css | 413 +++++++++++++++++++++++------- 1 file changed, 318 insertions(+), 95 deletions(-) diff --git a/Javascript/Weather Site/style.css b/Javascript/Weather Site/style.css index e4c1897..dc4aa33 100644 --- a/Javascript/Weather Site/style.css +++ b/Javascript/Weather Site/style.css @@ -1,130 +1,353 @@ :root { - --bg: #0f1724; - --glass: rgba(255, 255, 255, 0.04); - --accent: #60a5fa; - --muted: #9aa7b2; + --glass-bg: rgba(255, 255, 255, 0.1); + --glass-border: rgba(255, 255, 255, 0.2); + --text-primary: #ffffff; + --text-secondary: rgba(255, 255, 255, 0.8); + --shadow: 0 8px 32px rgba(0, 0, 0, 0.1); + --border-radius: 20px; + --transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); } -* { box-sizing: border-box; } +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} body { - margin: 0; - font-family: Inter, system-ui; - min-height: 100vh; - background: linear-gradient(180deg, #071025 0%, #0b1626 100%); - color: #e6eef6; - display: flex; - align-items: center; - justify-content: center; - padding: 24px; + font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; + min-height: 100vh; + background: linear-gradient(135deg, #1e3a8a 0%, #7c3aed 50%, #ec4899 100%); + background-size: 400% 400%; + animation: gradientShift 15s ease infinite; + color: var(--text-primary); + overflow-x: hidden; +} + +@keyframes gradientShift { + 0% { background-position: 0% 50%; } + 50% { background-position: 100% 50%; } + 100% { background-position: 0% 50%; } +} + +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +.container { + max-width: 1200px; + margin: 0 auto; + padding: 20px; +} + +/* Header Styles */ +.header { + text-align: center; + margin-bottom: 30px; + animation: fadeIn 0.8s ease-out; +} + +.header h1 { + font-size: clamp(2rem, 4vw, 3.5rem); + font-weight: 700; + margin-bottom: 20px; + text-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); } -.app { - max-width: 720px; - width: 100%; - background: rgba(255, 255, 255, 0.02); - border-radius: 16px; - padding: 20px; - box-shadow: 0 10px 30px rgba(2, 6, 23, 0.6); +.search-container { + display: flex; + justify-content: center; + gap: 10px; + margin-bottom: 20px; } -header { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 16px; +.search-input { + padding: 15px 20px; + border: none; + border-radius: 25px; + background: var(--glass-bg); + backdrop-filter: blur(10px); + border: 1px solid var(--glass-border); + color: var(--text-primary); + font-size: 16px; + width: 300px; + max-width: 100%; + transition: var(--transition); } -header h1 { - font-size: 20px; - margin: 0; +.search-input::placeholder { + color: var(--text-secondary); } -.controls { - display: flex; - gap: 8px; +.search-input:focus { + outline: none; + border-color: rgba(255, 255, 255, 0.4); + transform: scale(1.02); } -.controls input { - padding: 10px 12px; - border-radius: 10px; - border: 1px solid rgba(255, 255, 255, 0.06); - background: var(--glass); - color: inherit; - width: 220px; +.search-btn { + padding: 15px 25px; + border: none; + border-radius: 25px; + background: var(--glass-bg); + backdrop-filter: blur(10px); + border: 1px solid var(--glass-border); + color: var(--text-primary); + cursor: pointer; + font-size: 16px; + transition: var(--transition); } -.controls button { - padding: 10px 14px; - border-radius: 10px; - border: none; - background: var(--accent); - color: #06243a; - font-weight: 600; - cursor: pointer; +.search-btn:hover { + background: rgba(255, 255, 255, 0.2); + transform: scale(1.05); } -.card { - display: flex; - gap: 20px; - align-items: center; - padding: 18px; - border-radius: 12px; - background: rgba(255, 255, 255, 0.02); +/* Glass Card Base Style */ +.glass-card { + background: var(--glass-bg); + backdrop-filter: blur(10px); + border: 1px solid var(--glass-border); + border-radius: var(--border-radius); + box-shadow: var(--shadow); + padding: 25px; + transition: var(--transition); + animation: fadeIn 0.8s ease-out; } -.left { text-align: center; } -.icon { width: 96px; height: 96px; margin: auto; } -.temp { font-size: 36px; font-weight: 700; } -.cond { font-size: 14px; color: var(--muted); } +.glass-card:hover { + transform: translateY(-5px); + box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15); +} -.details { flex: 1; } -.row { display: flex; justify-content: space-between; } -.meta { display: flex; gap: 12px; margin-top: 10px; } +/* Main Weather Card */ +.main-weather { + text-align: center; + margin-bottom: 30px; + animation-delay: 0.2s; +} -.meta .m { - background: rgba(255, 255, 255, 0.02); - padding: 10px; - border-radius: 8px; - min-width: 100px; - text-align: center; +.city-name { + font-size: clamp(1.5rem, 3vw, 2.5rem); + font-weight: 600; + margin-bottom: 10px; } -.muted { color: var(--muted); font-size: 13px; } -.small { font-size: 12px; } +.date-time { + color: var(--text-secondary); + font-size: 1.1rem; + margin-bottom: 20px; +} -.loader { - height: 6px; - background: rgba(255, 255, 255, 0.04); - border-radius: 6px; - overflow: hidden; - margin-top: 12px; +.weather-icon { + font-size: clamp(4rem, 8vw, 8rem); + margin: 20px 0; + display: block; } -.loader > i { - display: block; - height: 100%; - width: 0; - background: linear-gradient(90deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.2)); - animation: load 1.2s linear infinite; +.temperature { + font-size: clamp(3rem, 6vw, 5rem); + font-weight: 700; + margin: 20px 0; + display: flex; + align-items: center; + justify-content: center; + gap: 20px; } -@keyframes load { - 0% { width: 0; } - 50% { width: 60%; } - 100% { width: 0; } +.temp-toggle { + padding: 8px 15px; + border: none; + border-radius: 15px; + background: rgba(255, 255, 255, 0.2); + color: var(--text-primary); + cursor: pointer; + font-size: 1rem; + transition: var(--transition); } -.error { - background: #4c1f1f; - color: #ffdede; - padding: 10px; - border-radius: 8px; - margin-top: 12px; +.temp-toggle:hover { + background: rgba(255, 255, 255, 0.3); + transform: scale(1.05); } -@media (max-width: 560px) { - .controls { flex-direction: column; } - .controls input { width: 100%; } - .card { flex-direction: column; align-items: flex-start; } +.weather-description { + font-size: 1.3rem; + color: var(--text-secondary); + text-transform: capitalize; +} + +/* Weather Details Grid */ +.weather-details { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 20px; + margin-bottom: 30px; +} + +.detail-card { + display: flex; + align-items: center; + gap: 15px; + animation-delay: 0.4s; +} + +.detail-icon { + font-size: 2rem; +} + +.detail-info h3 { + font-size: 0.9rem; + color: var(--text-secondary); + margin-bottom: 5px; +} + +.detail-info .value { + font-size: 1.3rem; + font-weight: 600; +} + +/* Forecast Section */ +.forecast-section { + animation-delay: 0.6s; +} + +.forecast-section h2 { + text-align: center; + margin-bottom: 20px; + font-size: 1.8rem; +} + +.forecast-container { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 15px; + overflow-x: auto; + padding-bottom: 10px; +} + +.forecast-card { + text-align: center; + padding: 20px 15px; + animation-delay: 0.8s; +} + +.forecast-day { + font-weight: 600; + margin-bottom: 10px; + font-size: 1rem; +} + +.forecast-icon { + font-size: 2.5rem; + margin: 10px 0; +} + +.forecast-temps { + display: flex; + justify-content: space-between; + margin-top: 10px; +} + +.high-temp { + font-weight: 600; +} + +.low-temp { + color: var(--text-secondary); +} + +/* Loading Spinner */ +.loading { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + display: none; + justify-content: center; + align-items: center; + z-index: 1000; +} + +.spinner { + width: 50px; + height: 50px; + border: 3px solid rgba(255, 255, 255, 0.3); + border-top: 3px solid #ffffff; + border-radius: 50%; + animation: spin 1s linear infinite; +} + +/* Error Message */ +.error-message { + background: rgba(239, 68, 68, 0.2); + border: 1px solid rgba(239, 68, 68, 0.4); + border-radius: 15px; + padding: 15px; + margin: 20px 0; + text-align: center; + color: #fef2f2; + display: none; + animation: fadeIn 0.5s ease-out; +} + +/* Responsive Design */ +@media (max-width: 768px) { + .container { + padding: 15px; + } + + .search-container { + flex-direction: column; + align-items: center; + } + + .search-input { + width: 100%; + margin-bottom: 10px; + } + + .weather-details { + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + } + + .forecast-container { + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + } + + .temperature { + flex-direction: column; + gap: 10pax; + } +} + +@media (max-width: 480px) { + .weather-details { + grid-template-columns: 1fr; + } + + .forecast-container { + grid-template-columns: repeat(2, 1fr); + } + + .detail-card { + justify-content: center; + text-align: center; + flex-direction: column; + gap: 10px; + } } From 70c7c6930593babed6093f04abc390b4f75eb633 Mon Sep 17 00:00:00 2001 From: Aaditya Agarwal <146380217+psy-duck1@users.noreply.github.com> Date: Wed, 22 Oct 2025 01:08:39 +0530 Subject: [PATCH 3/3] Integrate OpenWeather API and enhance UI features Refactored weather fetching logic and added support for OpenWeather API. Introduced temperature unit toggle and improved error handling. --- Javascript/Weather Site/script.js | 290 +++++++++++++++++++++++++----- 1 file changed, 245 insertions(+), 45 deletions(-) diff --git a/Javascript/Weather Site/script.js b/Javascript/Weather Site/script.js index d870f40..b1b8158 100644 --- a/Javascript/Weather Site/script.js +++ b/Javascript/Weather Site/script.js @@ -1,61 +1,261 @@ -const API_KEY = "f45d51406f914de6899151327251010"; -const BASE = "https://api.weatherapi.com/v1/current.json"; // Use HTTPS to avoid browser blocks +let currentUnit = 'celsius'; +let currentWeatherData = null; +let currentForecastData = null; +const API_KEY = 'bd5e378503939ddaee76f12ad7a97608'; +const WEATHER_API_URL = 'https://api.openweathermap.org/data/2.5/weather'; +const FORECAST_API_URL = 'https://api.openweathermap.org/data/2.5/forecast'; -const $ = (id) => document.getElementById(id); -const searchBtn = $("search"); -const qInput = $("q"); -const loadingEl = $("loading"); -const errorEl = $("error"); +// Weather condition to icon mapping +const weatherIcons = { + 'Clear': '☀️', + 'Clouds': '☁️', + 'Rain': '🌧️', + 'Drizzle': '🌦️', + 'Thunderstorm': '⛈️', + 'Snow': '🌨️', + 'Mist': '🌫️', + 'Fog': '🌫️', + 'Haze': '🌫️' +}; -async function fetchWeather(q) { - errorEl.style.display = "none"; - loadingEl.style.display = "block"; +// Gradient colors for different weather conditions +const weatherGradients = { + 'Clear': 'linear-gradient(135deg, #fbbf24 0%, #f59e0b 50%, #ea580c 100%)', + 'Clouds': 'linear-gradient(135deg, #6b7280 0%, #4b5563 50%, #374151 100%)', + 'Rain': 'linear-gradient(135deg, #3b82f6 0%, #2563eb 50%, #1e40af 100%)', + 'Drizzle': 'linear-gradient(135deg, #3b82f6 0%, #2563eb 50%, #1e40af 100%)', + 'Thunderstorm': 'linear-gradient(135deg, #1f2937 0%, #374151 50%, #4b5563 100%)', + 'Snow': 'linear-gradient(135deg, #e5e7eb 0%, #d1d5db 50%, #9ca3af 100%)', + 'default': 'linear-gradient(135deg, #1e3a8a 0%, #7c3aed 50%, #ec4899 100%)' +}; - try { - const url = `${BASE}?key=${API_KEY}&q=${encodeURIComponent(q)}&aqi=yes`; - const res = await fetch(url); +// DOM elements +const elements = { + loading: document.getElementById('loading'), + errorMessage: document.getElementById('errorMessage'), + cityInput: document.getElementById('cityInput'), + searchBtn: document.getElementById('searchBtn'), + cityName: document.getElementById('cityName'), + dateTime: document.getElementById('dateTime'), + weatherIcon: document.getElementById('weatherIcon'), + temperature: document.getElementById('temperature'), + tempToggle: document.getElementById('tempToggle'), + weatherDescription: document.getElementById('weatherDescription'), + feelsLike: document.getElementById('feelsLike'), + humidity: document.getElementById('humidity'), + windSpeed: document.getElementById('windSpeed'), + pressure: document.getElementById('pressure'), + visibility: document.getElementById('visibility'), + uvIndex: document.getElementById('uvIndex'), + forecastContainer: document.getElementById('forecastContainer') +}; - if (!res.ok) throw new Error(`HTTP ${res.status}`); +// Utility functions +function showLoading() { + elements.loading.style.display = 'flex'; +} + +function hideLoading() { + elements.loading.style.display = 'none'; +} + +function showError(message) { + elements.errorMessage.textContent = message; + elements.errorMessage.style.display = 'block'; + setTimeout(() => { + elements.errorMessage.style.display = 'none'; + }, 5000); +} + +function getWeatherIcon(condition) { + return weatherIcons[condition] || '🌤️'; +} + +function convertTemp(temp, unit) { + if (unit === 'fahrenheit') { + return Math.round((temp * 9/5) + 32); + } + return Math.round(temp); +} - const data = await res.json(); - render(data); - } catch (err) { - showError(err.message); - } finally { - loadingEl.style.display = "none"; - } +function formatDate() { + const now = new Date(); + const options = { + weekday: 'long', + year: 'numeric', + month: 'long', + day: 'numeric', + hour: '2-digit', + minute: '2-digit' + }; + return now.toLocaleDateString('en-US', options); } -function render(data) { - if (!data || !data.location) return showError("Invalid response"); +function updateBackground(weatherCondition) { + const gradient = weatherGradients[weatherCondition] || weatherGradients.default; + document.body.style.background = gradient; + document.body.style.backgroundSize = '400% 400%'; +} - $("location").textContent = `${data.location.name}, ${data.location.country}`; - $("localtime").textContent = data.location.localtime || "--"; - $("temp").textContent = `${data.current.temp_c}°C`; - $("condition").textContent = data.current.condition.text; - $("humidity").textContent = `${data.current.humidity}%`; - $("wind").textContent = `${data.current.wind_kph} kph`; - $("feelslike").textContent = `${data.current.feelslike_c}°C`; +// API functions +async function fetchWeather(city) { + try { + const response = await fetch(`${WEATHER_API_URL}?q=${city}&appid=${API_KEY}&units=metric`); + if (!response.ok) { + throw new Error(`Weather data not found for "${city}". Please check the city name and try again.`); + } + const data = await response.json(); + return data; + } catch (error) { + throw new Error(error.message || 'Failed to fetch weather data. Please try again.'); + } +} - const iconUrl = data.current.condition.icon.startsWith("//") - ? "https:" + data.current.condition.icon - : data.current.condition.icon; +async function fetchForecast(city) { + try { + const response = await fetch(`${FORECAST_API_URL}?q=${city}&appid=${API_KEY}&units=metric`); + if (!response.ok) { + throw new Error('Failed to fetch forecast data'); + } + const data = await response.json(); + return data; + } catch (error) { + throw new Error('Failed to fetch forecast data. Please try again.'); + } +} - $("icon").src = iconUrl; - $("icon").alt = data.current.condition.text; +// Display functions +function displayWeather(data) { + currentWeatherData = data; + + elements.cityName.textContent = `${data.name}, ${data.sys.country}`; + elements.dateTime.textContent = formatDate(); + + const condition = data.weather[0].main; + elements.weatherIcon.textContent = getWeatherIcon(condition); + + const temp = convertTemp(data.main.temp, currentUnit); + const unit = currentUnit === 'celsius' ? '°C' : '°F'; + elements.temperature.textContent = `${temp}${unit}`; + + elements.weatherDescription.textContent = data.weather[0].description; + + // Update details + const feelsLikeTemp = convertTemp(data.main.feels_like, currentUnit); + elements.feelsLike.textContent = `${feelsLikeTemp}${unit}`; + elements.humidity.textContent = `${data.main.humidity}%`; + elements.windSpeed.textContent = `${Math.round(data.wind.speed * 10) / 10} m/s`; + elements.pressure.textContent = `${data.main.pressure} hPa`; + elements.visibility.textContent = data.visibility ? `${Math.round(data.visibility / 1000)} km` : 'N/A'; + + // UV Index is not available in the free API, so we'll show N/A + elements.uvIndex.textContent = 'N/A'; + + // Update background based on weather + updateBackground(condition); } -function showError(msg) { - errorEl.style.display = "block"; - errorEl.className = "error"; - errorEl.textContent = msg; +function displayForecast(data) { + currentForecastData = data; + elements.forecastContainer.innerHTML = ''; + + // Group forecast data by day (every 8th item represents a new day as data is every 3 hours) + const dailyForecasts = []; + for (let i = 0; i < data.list.length; i += 8) { + if (dailyForecasts.length >= 5) break; + dailyForecasts.push(data.list[i]); + } + + dailyForecasts.forEach((forecast, index) => { + const forecastCard = document.createElement('div'); + forecastCard.className = 'glass-card forecast-card'; + + const date = new Date(forecast.dt * 1000); + const dayName = index === 0 ? 'Today' : date.toLocaleDateString('en-US', { weekday: 'long' }); + + const condition = forecast.weather[0].main; + const icon = getWeatherIcon(condition); + const highTemp = convertTemp(forecast.main.temp_max, currentUnit); + const lowTemp = convertTemp(forecast.main.temp_min, currentUnit); + const unit = currentUnit === 'celsius' ? '°C' : '°F'; + + forecastCard.innerHTML = ` +
${dayName}
+
${icon}
+
${forecast.weather[0].description}
+
+ ${highTemp}${unit} + ${lowTemp}${unit} +
+ `; + + elements.forecastContainer.appendChild(forecastCard); + }); } -searchBtn.addEventListener("click", () => - fetchWeather(qInput.value || "London") -); -qInput.addEventListener("keydown", (e) => { - if (e.key === "Enter") fetchWeather(qInput.value || "London"); +function updateTemperatureDisplay() { + if (currentWeatherData) { + displayWeather(currentWeatherData); + } + if (currentForecastData) { + displayForecast(currentForecastData); + } +} + +// Main functions +async function loadWeatherData(city) { + showLoading(); + elements.errorMessage.style.display = 'none'; + + try { + const [weatherData, forecastData] = await Promise.all([ + fetchWeather(city), + fetchForecast(city) + ]); + + displayWeather(weatherData); + displayForecast(forecastData); + } catch (error) { + showError(error.message); + } finally { + hideLoading(); + } +} + +function handleSearch() { + const city = elements.cityInput.value.trim(); + if (city) { + loadWeatherData(city); + elements.cityInput.value = ''; + } +} + +function toggleTemperatureUnit() { + currentUnit = currentUnit === 'celsius' ? 'fahrenheit' : 'celsius'; + elements.tempToggle.textContent = currentUnit === 'celsius' ? '°F' : '°C'; + updateTemperatureDisplay(); +} + +// Update time every minute +function updateTime() { + elements.dateTime.textContent = formatDate(); +} + +// Event listeners +elements.searchBtn.addEventListener('click', handleSearch); +elements.cityInput.addEventListener('keypress', (e) => { + if (e.key === 'Enter') { + handleSearch(); + } }); +elements.tempToggle.addEventListener('click', toggleTemperatureUnit); -fetchWeather(qInput.value || "London"); +// Initialize app +document.addEventListener('DOMContentLoaded', () => { + // Load default city (London) + loadWeatherData('London'); + + // Update time every minute + setInterval(updateTime, 60000); + updateTime(); +});