Skip to content

Instantly share code, notes, and snippets.

@sunmeat
Last active December 3, 2025 13:38
Show Gist options
  • Select an option

  • Save sunmeat/cd45ac1e855dd80a5e32505c32e020c4 to your computer and use it in GitHub Desktop.

Select an option

Save sunmeat/cd45ac1e855dd80a5e32505c32e020c4 to your computer and use it in GitHub Desktop.
прогноз погоди, статичні файли в папці wwwroot
створити папку wwwroot поряд з Program.cs проєкта
в папці wwwroot - папки css та js
Program.cs:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseStaticFiles(); // обробляє статичні файли з wwwroot https://learn.microsoft.com/ru-ru/aspnet/core/fundamentals/static-files?view=aspnetcore-10.0
app.Run(async (context) =>
{
context.Response.ContentType = "text/html; charset=utf-8";
await context.Response.SendFileAsync("wwwroot/index.html");
});
app.Run();
=============================================================================================================================
wwwroot / index.html: (створити файл!)
<!DOCTYPE html>
<html lang="uk">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Прогноз погоди в Україні</title>
<link rel="stylesheet" href="css/styles.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Comfortaa:wght@400;600;700&family=Roboto:wght@400;500&display=swap" rel="stylesheet">
</head>
<body>
<div class="container">
<header>
<h1>Прогноз погоди</h1>
</header>
<div class="search-box">
<input type="text" id="cityInput" placeholder="Введіть назву міста латинкою..." autocomplete="off">
<button id="searchBtn">Показати</button>
</div>
<div id="weather-grid" class="weather-grid">
<!-- тут будуть карточки погоди -->
</div>
<footer>
Дані з <a href="https://wttr.in" target="_blank">wttr.in</a> • Оновлюється автоматично
</footer>
</div>
<script src="js/script.js"></script>
</body>
</html>
=============================================================================================================================
wwwroot / css / styles.css: (створити файл!)
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Roboto', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #fff;
min-height: 100vh;
padding: 20px 0;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
header {
text-align: center;
margin-bottom: 40px;
}
h1 {
font-family: 'Comfortaa', cursive;
font-size: 3.5rem;
font-weight: 700;
margin-bottom: 10px;
text-shadow: 0 4px 10px rgba(0,0,0,0.3);
}
.subtitle {
font-size: 1.3rem;
opacity: 0.9;
}
.search-box {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 40px;
flex-wrap: wrap;
}
#cityInput {
padding: 14px 20px;
font-size: 1.1rem;
border: none;
border-radius: 50px;
width: 300px;
max-width: 100%;
outline: none;
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}
#searchBtn {
padding: 14px 30px;
font-size: 1.1rem;
background: #ff6b6b;
color: white;
border: none;
border-radius: 50px;
cursor: pointer;
font-weight: 600;
transition: all 0.3s;
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}
#searchBtn:hover {
background: #ff5252;
transform: translateY(-2px);
}
.weather-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 25px;
margin-bottom: 40px;
}
.card {
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 25px;
text-align: center;
box-shadow: 0 8px 32px rgba(0,0,0,0.2);
border: 1px solid rgba(255,255,255,0.1);
transition: transform 0.3s;
}
.card:hover {
transform: translateY(-10px);
}
.city-name {
font-family: 'Comfortaa', cursive;
font-size: 1.8rem;
margin-bottom: 10px;
}
.temp {
font-size: 3.5rem;
font-weight: 700;
margin: 10px 0;
}
.description {
font-size: 1.2rem;
text-transform: capitalize;
margin: 10px 0;
opacity: 0.9;
}
.details {
margin-top: 15px;
font-size: 0.95rem;
line-height: 1.6;
opacity: 0.85;
}
.loading {
text-align: center;
font-size: 1.2rem;
opacity: 0.8;
grid-column: 1 / -1;
}
footer {
text-align: center;
opacity: 0.8;
font-size: 0.9rem;
}
footer a {
color: #ffd93d;
text-decoration: none;
}
footer a:hover {
text-decoration: underline;
}
@media (max-width: 600px) {
h1 { font-size: 2.8rem; }
.search-box { flex-direction: column; align-items: center; }
#cityInput { width: 280px; }
}
=============================================================================================================================
wwwroot / js / script.js: (створити файл!)
const cities = ['Odesa', 'Kharkiv', 'Uzhhorod', 'Dnipro'];
const weatherGrid = document.getElementById('weather-grid');
const cityInput = document.getElementById('cityInput');
const searchBtn = document.getElementById('searchBtn');
async function loadWeather(city) {
const card = document.createElement('div');
card.className = 'card loading';
card.innerHTML = `<div class="city-name">${city === 'Odesa' ? 'Одеса' :
city === 'Kharkiv' ? 'Харків' :
city === 'Uzhhorod' ? 'Ужгород' :
city === 'Dnipro' ? 'Дніпро' : city}</div>
<div>Завантаження...</div>`;
weatherGrid.appendChild(card);
try {
const response = await fetch(`https://wttr.in/${city}?format=j1`);
const data = await response.json();
const temp = data.current_condition[0].temp_C;
const desc = data.current_condition[0].lang_uk[0]?.value || data.current_condition[0].weatherDesc[0].value;
const feelsLike = data.current_condition[0].FeelsLikeC;
const humidity = data.current_condition[0].humidity;
const wind = data.current_condition[0].windspeedKmph;
card.classList.remove('loading');
card.innerHTML = `
<div class="city-name">${city === 'Odesa' ? 'Одеса' :
city === 'Kharkiv' ? 'Харків' :
city === 'Uzhhorod' ? 'Ужгород' :
city === 'Dnipro' ? 'Дніпро' : city}</div>
<div class="temp">${temp}°C</div>
<div class="description">${desc}</div>
<div class="details">
Відчувається як ${feelsLike}°C<br>
Вологість: ${humidity}%<br>
Вітер: ${wind} км/год
</div>
`;
} catch (err) {
card.classList.remove('loading');
card.innerHTML = `<div class="city-name">${city}</div>
<div style="color:#ff6b6b">Не вдалося завантажити :(</div>`;
}
}
function loadDefaultCities() {
weatherGrid.innerHTML = '';
cities.forEach(city => loadWeather(city));
}
searchBtn.addEventListener('click', () => {
const city = cityInput.value.trim();
if (city) {
weatherGrid.innerHTML = '';
loadWeather(encodeURIComponent(city));
cityInput.value = '';
}
});
cityInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
searchBtn.click();
}
});
window.addEventListener('load', loadDefaultCities);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment