<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Quick Weather App</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}
body {
background: #f0f4f8;
color: #333;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 20px;
}
.weather-card {
background: white;
padding: 30px;
border-radius: 16px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05);
width: 100%;
max-width: 400px;
text-align: center;
}
h1 {
font-size: 24px;
margin-bottom: 20px;
color: #1e293b;
}
.search-box {
display: flex;
gap: 8px;
margin-bottom: 15px;
}
input {
flex: 1;
padding: 10px 14px;
border: 1px solid #cbd5e1;
border-radius: 8px;
font-size: 16px;
outline: none;
}
input:focus {
border-color: #3b82f6;
}
button {
padding: 10px 16px;
background: #3b82f6;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-weight: 600;
transition: background 0.2s;
}
button:hover {
background: #2563eb;
}
.geo-btn {
width: 100%;
background: #10b981;
margin-bottom: 25px;
}
.geo-btn:hover {
background: #059669;
}
.hidden {
display: none !important;
}
/* Weather Info Display Styling */
.location-name {
font-size: 20px;
font-weight: 600;
color: #475569;
margin-bottom: 8px;
}
.temp-display {
font-size: 54px;
font-weight: 700;
color: #1e293b;
margin-bottom: 10px;
}
.condition {
font-size: 18px;
text-transform: capitalize;
color: #64748b;
margin-bottom: 20px;
}
.details-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
border-top: 1px solid #e2e8f0;
padding-top: 20px;
}
.detail-item {
background: #f8fafc;
padding: 10px;
border-radius: 8px;
font-size: 14px;
}
.detail-label {
color: #94a3b8;
margin-bottom: 4px;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.detail-value {
font-weight: 600;
color: #334155;
}
.error-msg {
color: #ef4444;
background: #fef2f2;
padding: 10px;
border-radius: 8px;
font-size: 14px;
margin-top: 15px;
}
</style>
</head>
<body>
<div class="weather-card">
<h1>Weather Forecast</h1>
<div class="search-box">
<input type="text" id="city-input" placeholder="Enter city name (e.g., Paris)">
<button id="search-btn">Search</button>
</div>
<button id="geo-btn" class="geo-btn">📍 Use Current Location</button>
<!-- Status/Error Box -->
<div id="status-message" class="error-msg hidden"></div>
<!-- Weather Display Block -->
<div id="weather-info" class="hidden">
<div class="location-name" id="display-location">---</div>
<div class="temp-display" id="display-temp">--°C</div>
<div class="condition" id="display-condition">---</div>
<div class="details-grid">
<div class="detail-item">
<div class="detail-label">Humidity</div>
<div class="detail-value" id="display-humidity">--%</div>
</div>
<div class="detail-item">
<div class="detail-label">Wind Speed</div>
<div class="detail-value" id="display-wind">-- km/h</div>
</div>
</div>
</div>
</div>
<script>
// Mapping Open-Meteo WMO weather codes to human-readable text
const weatherCodes = {
0: "Clear sky",
1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast",
45: "Fog", 48: "Depositing rime fog",
51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle",
61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain",
71: "Slight snow fall", 73: "Moderate snow fall", 75: "Heavy snow fall",
77: "Snow grains",
80: "Slight rain showers", 81: "Moderate rain showers", 82: "Violent rain showers",
85: "Slight snow showers", 86: "Heavy snow showers",
95: "Thunderstorm", 96: "Thunderstorm with slight hail", 99: "Thunderstorm with heavy hail"
};
const cityInput = document.getElementById('city-input');
const searchBtn = document.getElementById('search-btn');
const geoBtn = document.getElementById('geo-btn');
const statusMsg = document.getElementById('status-message');
const weatherInfo = document.getElementById('weather-info');
// Event Listeners
searchBtn.addEventListener('click', handleCitySearch);
cityInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') handleCitySearch(); });
geoBtn.addEventListener('click', handleGeolocation);
// Option 1: Search by City Name
async function handleCitySearch() {
const cityName = cityInput.value.trim();
if (!cityName) return showStatus("Please enter a city name.");
showStatus("Searching for city...", false);
try {
// Open-Meteo uses Geocoding API to convert city names to Latitude/Longitude
const geoUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(cityName)}&count=1&language=en&format=json`;
const response = await fetch(geoUrl);
const data = await response.json();
if (!data.results || data.results.length === 0) {
throw new Error("City not found. Try checking the spelling.");
}
const result = data.results[0];
const displayName = `${result.name}, ${result.country}`;
fetchWeatherData(result.latitude, result.longitude, displayName);
} catch (error) {
showStatus(error.message);
}
}
// Option 2: Get Browser Coordinates
function handleGeolocation() {
if (!navigator.geolocation) {
return showStatus("Geolocation is not supported by your browser.");
}
showStatus("Requesting location access...", false);
navigator.geolocation.getCurrentPosition(
(position) => {
const lat = position.coords.latitude;
const lon = position.coords.longitude;
fetchWeatherData(lat, lon, "Your Location");
},
(error) => {
showStatus("Location access denied or unavailable.");
}
);
}
// Main function to query the Weather API
async function fetchWeatherData(lat, lon, locationLabel) {
try {
const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}¤t=temperature_2m,relative_humidity_2m,weather_code,wind_speed_10m`;
const response = await fetch(weatherUrl);
if (!response.ok) throw new Error("Failed to retrieve weather data.");
const data = await response.json();
renderWeather(data.current, locationLabel);
} catch (error) {
showStatus(error.message);
}
}
// Display data onto the UI
function renderWeather(currentData, locationName) {
statusMsg.classList.add('hidden'); // Hide any errors
document.getElementById('display-location').textContent = locationName;
document.getElementById('display-temp').textContent = `${Math.round(currentData.temperature_2m)}°C`;
document.getElementById('display-humidity').textContent = `${currentData.relative_humidity_2m}%`;
document.getElementById('display-wind').textContent = `${currentData.wind_speed_10m} km/h`;
// Translate the WMO numeric weather code to descriptive text
const conditionText = weatherCodes[currentData.weather_code] || "Unknown Conditions";
document.getElementById('display-condition').textContent = conditionText;
weatherInfo.classList.remove('hidden');
}
// Helper to handle messages / errors
function showStatus(msg, isError = true) {
statusMsg.textContent = msg;
statusMsg.classList.remove('hidden');
if (isError) {
statusMsg.style.background = '#fef2f2';
statusMsg.style.color = '#ef4444';
weatherInfo.classList.add('hidden');
} else {
statusMsg.style.background = '#f0fdf4';
statusMsg.style.color = '#15803d';
}
}
</script>
</body>
</html>
Welcome there,
Do you have a question? Or are you posting this for I Built This ?
The more you say, the more we can help.