Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions Javascript/Weather Site/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Weather App</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="app">
<header>
<h1>Weather App</h1>
<div class="controls">
<input id="q" type="text" placeholder="Enter city name" value="London">
<button id="search">Search</button>
</div>
</header>

<section id="output">
<div class="card" id="card">
<div class="left">
<img src="" alt="weather icon" id="icon" class="icon">
<div class="temp" id="temp">--°C</div>
<div class="cond" id="condition">--</div>
</div>
<div class="details">
<div class="row">
<div>
<div class="muted">Location</div>
<div id="location" class="small">--</div>
</div>
<div>
<div class="muted">Local Time</div>
<div id="localtime" class="small">--</div>
</div>
</div>
<div class="meta">
<div class="m">
<div class="muted">Humidity</div>
<div id="humidity">--%</div>
</div>
<div class="m">
<div class="muted">Wind</div>
<div id="wind">-- kph</div>
</div>
<div class="m">
<div class="muted">Feels Like</div>
<div id="feelslike">--°C</div>
</div>
</div>
<div id="extra" class="small muted">Data from WeatherAPI.com</div>
</div>
</div>
<div id="loading" class="loader" style="display:none"><i></i></div>
<div id="error" style="display:none"></div>
</section>
</main>

<script src="script.js"></script>
</body>
</html>
61 changes: 61 additions & 0 deletions Javascript/Weather Site/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
const API_KEY = "f45d51406f914de6899151327251010";
const BASE = "https://api.weatherapi.com/v1/current.json"; // Use HTTPS to avoid browser blocks

const $ = (id) => document.getElementById(id);
const searchBtn = $("search");
const qInput = $("q");
const loadingEl = $("loading");
const errorEl = $("error");

async function fetchWeather(q) {
errorEl.style.display = "none";
loadingEl.style.display = "block";

try {
const url = `${BASE}?key=${API_KEY}&q=${encodeURIComponent(q)}&aqi=yes`;
const res = await fetch(url);

if (!res.ok) throw new Error(`HTTP ${res.status}`);

const data = await res.json();
render(data);
} catch (err) {
showError(err.message);
} finally {
loadingEl.style.display = "none";
}
}

function render(data) {
if (!data || !data.location) return showError("Invalid response");

$("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`;

const iconUrl = data.current.condition.icon.startsWith("//")
? "https:" + data.current.condition.icon
: data.current.condition.icon;

$("icon").src = iconUrl;
$("icon").alt = data.current.condition.text;
}

function showError(msg) {
errorEl.style.display = "block";
errorEl.className = "error";
errorEl.textContent = msg;
}

searchBtn.addEventListener("click", () =>
fetchWeather(qInput.value || "London")
);
qInput.addEventListener("keydown", (e) => {
if (e.key === "Enter") fetchWeather(qInput.value || "London");
});

fetchWeather(qInput.value || "London");
130 changes: 130 additions & 0 deletions Javascript/Weather Site/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
:root {
--bg: #0f1724;
--glass: rgba(255, 255, 255, 0.04);
--accent: #60a5fa;
--muted: #9aa7b2;
}

* { 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;
}

.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);
}

header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
}

header h1 {
font-size: 20px;
margin: 0;
}

.controls {
display: flex;
gap: 8px;
}

.controls input {
padding: 10px 12px;
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.06);
background: var(--glass);
color: inherit;
width: 220px;
}

.controls button {
padding: 10px 14px;
border-radius: 10px;
border: none;
background: var(--accent);
color: #06243a;
font-weight: 600;
cursor: pointer;
}

.card {
display: flex;
gap: 20px;
align-items: center;
padding: 18px;
border-radius: 12px;
background: rgba(255, 255, 255, 0.02);
}

.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); }

.details { flex: 1; }
.row { display: flex; justify-content: space-between; }
.meta { display: flex; gap: 12px; margin-top: 10px; }

.meta .m {
background: rgba(255, 255, 255, 0.02);
padding: 10px;
border-radius: 8px;
min-width: 100px;
text-align: center;
}

.muted { color: var(--muted); font-size: 13px; }
.small { font-size: 12px; }

.loader {
height: 6px;
background: rgba(255, 255, 255, 0.04);
border-radius: 6px;
overflow: hidden;
margin-top: 12px;
}

.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;
}

@keyframes load {
0% { width: 0; }
50% { width: 60%; }
100% { width: 0; }
}

.error {
background: #4c1f1f;
color: #ffdede;
padding: 10px;
border-radius: 8px;
margin-top: 12px;
}

@media (max-width: 560px) {
.controls { flex-direction: column; }
.controls input { width: 100%; }
.card { flex-direction: column; align-items: flex-start; }
}
Loading