HTML_dashboard / index.html
andrewammann's picture
Update index.html
747692d verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Weather Dashboard</title>
<!-- Bootstrap CSS for styling -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Leaflet CSS for map -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
<style>
body {
background-color: #f4f6fa;
font-family: Arial, sans-serif;
}
.header {
text-align: center;
padding: 20px;
background-color: #007bff;
color: white;
border-radius: 8px;
margin-bottom: 20px;
}
.metric-card {
background-color: #ffffff;
padding: 15px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
text-align: center;
margin-bottom: 15px;
}
#map {
height: 400px;
border-radius: 8px;
margin-bottom: 20px;
}
.footer {
font-size: 12px;
text-align: center;
margin-top: 30px;
padding: 15px;
background-color: #e9ecef;
border-radius: 8px;
}
.city-section {
margin-bottom: 20px;
}
.weather-table {
width: 100%;
border-collapse: collapse;
}
.weather-table th, .weather-table td {
border: 1px solid #dee2e6;
padding: 8px;
text-align: center;
}
.weather-table th {
background-color: #f8f9fa;
}
</style>
</head>
<body>
<!-- Header -->
<div class="header">
<h1>🌍 Global Weather Dashboard</h1>
<p>Powered by Open-Meteo API</p>
<img src="https://via.placeholder.com/100x50.png?text=Logo" alt="Logo" style="margin-top: 10px;">
</div>
<!-- Main Content -->
<div class="container">
<!-- Input Form -->
<div class="row mb-4">
<div class="col-md-6">
<label for="cityInput" class="form-label">Enter city names (comma-separated):</label>
<input type="text" class="form-control" id="cityInput" placeholder="e.g., New York, London, Tokyo" value="New York, London, Tokyo">
</div>
<div class="col-md-3">
<label for="citySelect" class="form-label">Or select a city:</label>
<select class="form-select" id="citySelect">
<option value="">Select a city</option>
<option value="New York">New York</option>
<option value="London">London</option>
<option value="Tokyo">Tokyo</option>
<option value="Sydney">Sydney</option>
<option value="Paris">Paris</option>
<option value="Dubai">Dubai</option>
<option value="Singapore">Singapore</option>
</select>
</div>
<div class="col-md-3 align-self-end">
<button class="btn btn-primary w-100" onclick="fetchWeather()">Fetch Weather</button>
</div>
</div>
<!-- Map -->
<h3>City Locations</h3>
<div id="map"></div>
<!-- Weather Data -->
<div id="weatherData"></div>
</div>
<!-- Footer -->
<div class="footer">
<p>Weather data by <a href="https://open-meteo.com" target="_blank">Open-Meteo.com</a> under <a href="https://creativecommons.org/licenses/by/4.0/" target="_blank">CC BY 4.0</a> |
For non-commercial use only |
<a href="https://github.com/open-meteo/open-meteo" target="_blank">Source Code</a> |
Contact: <a href="mailto:[email protected]">[email protected]</a></p>
</div>
<!-- Scripts -->
<!-- Leaflet JS for map -->
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
<script>
// Weather code to icon mapping
const weatherIcons = {
0: "☀️", 1: "🌤️", 2: "⛅", 3: "☁️", 61: "🌧️", 71: "❄️"
};
// Initialize Leaflet map
const map = L.map('map').setView([0, 0], 2);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
// Fetch weather data
async function fetchWeather() {
const cityInput = document.getElementById('cityInput').value;
const citySelect = document.getElementById('citySelect').value;
let cities = citySelect ? [citySelect] : cityInput.split(',').map(city => city.trim()).filter(city => city);
cities = [...new Set(cities)]; // Remove duplicates
if (cities.length === 0) {
alert("Please enter or select at least one city.");
return;
}
const weatherDataDiv = document.getElementById('weatherData');
weatherDataDiv.innerHTML = '<p>Loading weather data...</p>';
const coordinates = [];
// Clear existing markers
map.eachLayer(layer => {
if (layer instanceof L.Marker) map.removeLayer(layer);
});
for (const city of cities) {
try {
// Fetch coordinates
const geoUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(city)}&count=1&language=en&format=json`;
const geoResponse = await fetch(geoUrl);
const geoData = await geoResponse.json();
if (geoData.results && geoData.results.length > 0) {
const { latitude, longitude, country, timezone } = geoData.results[0];
coordinates.push({ city, lat: latitude, lon: longitude, country, timezone });
// Fetch weather data
const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&daily=temperature_2m_max,temperature_2m_min,precipitation_probability_mean,weathercode&current_weather=true&temperature_unit=fahrenheit&timezone=auto`;
const weatherResponse = await fetch(weatherUrl);
const weatherData = await weatherResponse.json();
// Add marker to map
L.marker([latitude, longitude])
.addTo(map)
.bindPopup(`<b>${city}</b><br>Temp: ${weatherData.current_weather.temperature}°F<br>Country: ${country}`);
// Render weather data
const current = weatherData.current_weather;
const daily = weatherData.daily;
const localTime = new Date().toLocaleString('en-US', { timeZone: timezone });
let html = `
<div class="city-section">
<h4>🌆 Weather for ${city}</h4>
<p>📍 ${city}, ${country} (Lat: ${latitude.toFixed(2)}, Lon: ${longitude.toFixed(2)})</p>
<p>🕒 Local Time: ${localTime}</p>
<h5>Current Weather</h5>
<div class="row">
<div class="col-md-4">
<div class="metric-card">
<p><strong>Temperature</strong></p>
<p>${current.temperature} °F</p>
</div>
</div>
<div class="col-md-4">
<div class="metric-card">
<p><strong>Wind Speed</strong></p>
<p>${current.windspeed} km/h</p>
</div>
</div>
<div class="col-md-4">
<div class="metric-card">
<p><strong>Condition</strong></p>
<p>${weatherIcons[current.weathercode] || '🌫️'} ${current.weathercode}</p>
</div>
</div>
</div>
<h5>7-Day Forecast</h5>
<table class="weather-table">
<tr>
<th>Date</th>
<th>Max Temp (°F)</th>
<th>Min Temp (°F)</th>
<th>Precipitation Prob (%)</th>
<th>Condition</th>
</tr>
`;
for (let i = 0; i < daily.time.length; i++) {
html += `
<tr>
<td>${new Date(daily.time[i]).toLocaleDateString()}</td>
<td>${daily.temperature_2m_max[i].toFixed(1)}</td>
<td>${daily.temperature_2m_min[i].toFixed(1)}</td>
<td>${(daily.precipitation_probability_mean[i] * 100).toFixed(0)}</td>
<td>${weatherIcons[daily.weathercode[i]] || '🌫️'}</td>
</tr>
`;
}
html += `</table></div>`;
weatherDataDiv.innerHTML += html;
} else {
weatherDataDiv.innerHTML += `<div class="alert alert-danger">Could not find coordinates for ${city}.</div>`;
}
} catch (error) {
weatherDataDiv.innerHTML += `<div class="alert alert-danger">Error fetching data for ${city}: ${error.message}</div>`;
}
}
// Adjust map to fit all markers
if (coordinates.length > 0) {
const bounds = L.latLngBounds(coordinates.map(c => [c.lat, c.lon]));
map.fitBounds(bounds, { padding: [50, 50] });
}
}
</script>
</body>
</html>