diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..e96d05a Binary files /dev/null and b/.DS_Store differ diff --git a/README.md b/README.md index cfe58cf..2d11bb8 100644 --- a/README.md +++ b/README.md @@ -1 +1,5 @@ -# js-project-weather-app \ No newline at end of file +# js-project-weather-app + +nordicweatherapp.netlify.app + +This was another team effort where we implemented all we have learnt on the individual recipe app project. We divided our work into two groups, CSS and Javascript. We coded the html together to make sure we all had a solid understanding of the structure first. On this project I was in the Javascript group. This was a great challenge. diff --git a/assets/Brokenclouds.png b/assets/Brokenclouds.png new file mode 100644 index 0000000..2d36da9 Binary files /dev/null and b/assets/Brokenclouds.png differ diff --git a/assets/Cloudy.jpg b/assets/Cloudy.jpg new file mode 100644 index 0000000..fa227ce Binary files /dev/null and b/assets/Cloudy.jpg differ diff --git a/assets/Fewclouds.png b/assets/Fewclouds.png new file mode 100644 index 0000000..3712512 Binary files /dev/null and b/assets/Fewclouds.png differ diff --git a/assets/Group 13.png b/assets/Group 13.png new file mode 100644 index 0000000..7e976b2 Binary files /dev/null and b/assets/Group 13.png differ diff --git a/assets/Group 15.png b/assets/Group 15.png new file mode 100644 index 0000000..3712512 Binary files /dev/null and b/assets/Group 15.png differ diff --git a/assets/Group 16.png b/assets/Group 16.png new file mode 100644 index 0000000..2d36da9 Binary files /dev/null and b/assets/Group 16.png differ diff --git a/assets/Night.png b/assets/Night.png new file mode 100644 index 0000000..3f64d17 Binary files /dev/null and b/assets/Night.png differ diff --git a/assets/Subtraction 2.png b/assets/Subtraction 2.png new file mode 100644 index 0000000..3f64d17 Binary files /dev/null and b/assets/Subtraction 2.png differ diff --git a/assets/Sunny.jpg b/assets/Sunny.jpg new file mode 100644 index 0000000..32d502d Binary files /dev/null and b/assets/Sunny.jpg differ diff --git a/assets/Sunny.png b/assets/Sunny.png new file mode 100644 index 0000000..7e976b2 Binary files /dev/null and b/assets/Sunny.png differ diff --git a/assets/Sunrise.jpg.avif b/assets/Sunrise.jpg.avif new file mode 100644 index 0000000..39aae02 Binary files /dev/null and b/assets/Sunrise.jpg.avif differ diff --git a/assets/Sunset.jpg.avif b/assets/Sunset.jpg.avif new file mode 100644 index 0000000..f3f7d4c Binary files /dev/null and b/assets/Sunset.jpg.avif differ diff --git a/assets/searchglass.png b/assets/searchglass.png new file mode 100644 index 0000000..a2d05f5 Binary files /dev/null and b/assets/searchglass.png differ diff --git a/assets/sun.jpg b/assets/sun.jpg new file mode 100644 index 0000000..73fa7c4 Binary files /dev/null and b/assets/sun.jpg differ diff --git a/dist/script.js b/dist/script.js new file mode 100644 index 0000000..2f948b1 --- /dev/null +++ b/dist/script.js @@ -0,0 +1,190 @@ +"use strict"; +// @ts-nocheck +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +document.addEventListener('DOMContentLoaded', function () { + // API information + const API_KEY = '3bad52890d7306cc268371520cbaace6'; + const BASE_URL = 'https://api.openweathermap.org/data/2.5/forecast'; + // List of default cities + const cities = ['Stockholm', 'Gothenburg', 'Oslo']; + let weeklyForecast = {}; + let currentCityIndex = 0; + function fetchWeather(city) { + return __awaiter(this, void 0, void 0, function* () { + try { + const response = yield fetch(`${BASE_URL}?q=${city}&units=metric&appid=${API_KEY}`); + const data = yield response.json(); + if (data.cod !== "200") { + throw new Error(data.message || "Failed to fetch weather data."); + } + return data; + } + catch (error) { + console.error(`Error fetching weather data for ${city}:`, error); + return null; + } + }); + } + function getDayName(dateString) { + const date = new Date(dateString); + const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; + return days[date.getDay()]; + } + function fetchAndStoreWeather(city) { + return __awaiter(this, void 0, void 0, function* () { + const data = yield fetchWeather(city); + if (!data || !data.list) { + return; + } + const todayData = data.list.find(entry => entry.dt_txt.includes("12:00:00")) || data.list[0]; + const todayDate = todayData.dt_txt.split(" ")[0]; + const sunriseTime = new Date(data.city.sunrise * 1000).toLocaleTimeString("sv-SE", { hour: "2-digit", minute: "2-digit" }); + const sunsetTime = new Date(data.city.sunset * 1000).toLocaleTimeString("sv-SE", { hour: "2-digit", minute: "2-digit" }); + const todayForecast = { + city: data.city.name, + day: getDayName(todayDate), + weather: todayData.weather[0].description, + icon: todayData.weather[0].icon, + temp: todayData.main.temp, + wind: todayData.wind.speed, + sunrise: sunriseTime, + sunset: sunsetTime, + }; + const dailyForecasts = {}; + data.list.forEach(entry => { + const date = entry.dt_txt.split(' ')[0]; + const hour = entry.dt_txt.split(' ')[1].split(':')[0]; + if (hour === '12' && date !== todayDate) { + dailyForecasts[date] = { + date: date, + day: getDayName(date), + icon: entry.weather[0].icon, + weather: entry.weather[0].description, + temp: entry.main.temp, + wind: entry.wind.speed, + }; + } + }); + const upcomingForecast = Object.values(dailyForecasts).slice(0, 4); + weeklyForecast[city] = { + today: todayForecast, + upcoming: upcomingForecast + }; + localStorage.setItem("weatherData", JSON.stringify(weeklyForecast)); + displayTodaysWeather(todayForecast); + displayWeeklyWeather(upcomingForecast); + updateBackground(todayForecast.weather, todayForecast.icon); + }); + } + function displayTodaysWeather(forecast) { + const weatherContent = document.getElementById('weather-content'); + if (!weatherContent) + return; + weatherContent.innerHTML = ` +
+ ${forecast.weather} +
+

${Math.round(forecast.temp)}°C

+

${forecast.city}

+

${forecast.weather}

+
+

Sunrise: ${forecast.sunrise}

+

Sunset: ${forecast.sunset}

+
+ `; + } + function displayWeeklyWeather(forecastList) { + const forecastTable = document.querySelector("#weather-forecast table"); + if (!forecastTable) + return; + const rows = forecastTable.getElementsByTagName("tr"); + if (!rows || rows.length === 0) + return; + forecastList.forEach((forecast, index) => { + if (index < rows.length) { + const dayCell = rows[index].querySelector(`#day${index + 1}`); + if (dayCell) + dayCell.textContent = forecast.day; + const iconCell = rows[index].querySelector(`#iconday${index + 1}`); + if (iconCell) { + iconCell.innerHTML = `${forecast.weather}`; + } + const tempCell = rows[index].querySelector(`#tempday${index + 1}`); + if (tempCell) + tempCell.textContent = `${Math.round(forecast.temp)}°C`; + const windCell = rows[index].querySelector(`#windday${index + 1}`); + if (windCell) + windCell.textContent = `${forecast.wind} m/s`; + } + }); + } + function updateBackground(weatherDescription, iconCode) { + const container = document.querySelector('.container'); + if (!container) + return; + container.classList.remove('rainy', 'cloudy', 'clear', 'snowy', 'daytime', 'nighttime'); + const isDaytime = iconCode.endsWith('d'); + container.classList.add(isDaytime ? 'daytime' : 'nighttime'); + if (weatherDescription.includes('rain') || weatherDescription.includes('drizzle')) { + container.classList.add('rainy'); + } + else if (weatherDescription.includes('cloud')) { + container.classList.add('cloudy'); + } + else if (weatherDescription.includes('clear')) { + container.classList.add('clear'); + } + else if (weatherDescription.includes('snow')) { + container.classList.add('snowy'); + } + } + function cycleCity() { + currentCityIndex = (currentCityIndex + 1) % cities.length; + const city = cities[currentCityIndex]; + fetchAndStoreWeather(city); + } + function initializeEventListeners() { + const searchButton = document.getElementById("search-button"); + const inputField = document.getElementById("input-field"); + const nextSideButton = document.getElementById('next-side-button'); + if (searchButton) { + searchButton.addEventListener("click", function () { + if (inputField && inputField.value.trim()) { + fetchAndStoreWeather(inputField.value.trim()); + } + }); + } + if (inputField) { + inputField.addEventListener("keydown", function (event) { + if (event.key === "Enter" && inputField.value.trim()) { + fetchAndStoreWeather(inputField.value.trim()); + } + }); + } + if (nextSideButton) { + nextSideButton.addEventListener('click', cycleCity); + } + else { + console.error("Could not find button with ID 'next-side-button'"); + } + } + initializeEventListeners(); + fetchAndStoreWeather("Stockholm"); + const savedData = localStorage.getItem("weatherData"); + if (savedData) { + try { + weeklyForecast = JSON.parse(savedData); + } + catch (e) { + console.error("Failed to parse saved weather data:", e); + } + } +}); diff --git a/index.html b/index.html new file mode 100644 index 0000000..c7e4b1a --- /dev/null +++ b/index.html @@ -0,0 +1,106 @@ + + + + + + + + + Weather App + + + + +
+

Weather App

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

Weather Forecast

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
4-day weather forecast
+
+
+ + + + + + + + \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 0000000..807d061 --- /dev/null +++ b/script.js @@ -0,0 +1,234 @@ +document.addEventListener('DOMContentLoaded', function () { + // API information + const API_KEY = '3bad52890d7306cc268371520cbaace6'; + const BASE_URL = 'https://api.openweathermap.org/data/2.5/forecast'; + + // List of default cities + const cities = ['Stockholm', 'Gothenburg', 'Oslo']; + let weeklyForecast = {}; + let currentCityIndex = 0; + + // Function to fetch weather data from the API + async function fetchWeather(city) { + try { + const response = await fetch(`${BASE_URL}?q=${city}&units=metric&appid=${API_KEY}`); + const data = await response.json(); + + if (data.cod !== "200") { + throw new Error(data.message); + } + + return data; + } catch (error) { + console.error(`Error fetching weather data for ${city}:`, error); + return null; + } + } + + // Function to get the day name from a date + function getDayName(dateString) { + const date = new Date(dateString); + const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; + return days[date.getDay()]; + } + + async function fetchAndStoreWeather(city) { + const data = await fetchWeather(city); + if (!data || !data.list) { + return; + } + + + // Extract today's forecast + const todayData = data.list.find(entry => entry.dt_txt.includes("12:00:00")) || data.list[0]; + const todayDate = todayData.dt_txt.split(" ")[0]; // Extract 'YYYY-MM-DD' + const sunriseTime = new Date(data.city.sunrise * 1000).toLocaleTimeString("sv-SE", { hour: "2-digit", minute: "2-digit" }); + const sunsetTime = new Date(data.city.sunset * 1000).toLocaleTimeString("sv-SE", { hour: "2-digit", minute: "2-digit" }); + + // Create today's forecast object + const todayForecast = { + city: data.city.name, + day: getDayName(todayDate), + weather: todayData.weather[0].description, + icon: todayData.weather[0].icon, + temp: todayData.main.temp, + wind: todayData.wind.speed, + sunrise: sunriseTime, + sunset: sunsetTime, + }; + + // 4-day forecast. Group forecast entries by day to get one entry per day + const dailyForecasts = {}; + + data.list.forEach(entry => { + const date = entry.dt_txt.split(' ')[0]; + const hour = entry.dt_txt.split(' ')[1].split(':')[0]; + + // Use noon (12:00) forecasts for consistency + if (hour === '12') { + // Skip today's date + if (date !== todayDate) { + dailyForecasts[date] = { + date: date, + day: getDayName(date), + icon: entry.weather[0].icon, + weather: entry.weather[0].description, + temp: entry.main.temp, + wind: entry.wind.speed, + }; + } + } + }); + + // Convert to array and take the first 4 days + const upcomingForecast = Object.values(dailyForecasts).slice(0, 4); + + // Store forecasts + weeklyForecast[city] = { + today: todayForecast, + upcoming: upcomingForecast + }; + + // Store in localStorage for persistence + localStorage.setItem("weatherData", JSON.stringify(weeklyForecast)); + + // Update UI + displayTodaysWeather(todayForecast); + displayWeeklyWeather(upcomingForecast); + + // Set background based on weather + updateBackground(todayForecast.weather, todayForecast.icon); + } + + // Function to display today's weather in the UI + function displayTodaysWeather(forecast) { + const weatherContent = document.getElementById('weather-content'); + if (!weatherContent) return; + + // Create HTML with the OpenWeatherMap icon + weatherContent.innerHTML = ` +
+ ${forecast.weather} +
+

${Math.round(forecast.temp)}°C

+

${forecast.city}

+

${forecast.weather}

+
+

Sunrise: ${forecast.sunrise}

+

Sunset: ${forecast.sunset}

+
+ `; + } + + // Function to display the weekly forecast in the UI + function displayWeeklyWeather(forecastList) { + const forecastTable = document.querySelector("#weather-forecast table"); + if (!forecastTable) return; + + const rows = forecastTable.getElementsByTagName("tr"); + if (!rows || rows.length === 0) return; + + forecastList.forEach((forecast, index) => { + if (index < rows.length) { + // Update day + const dayCell = rows[index].querySelector(`#day${index + 1}`); + if (dayCell) { + dayCell.textContent = forecast.day; + } + + // Update icon using OpenWeatherMap icon + const iconCell = rows[index].querySelector(`#iconday${index + 1}`); + if (iconCell) { + iconCell.innerHTML = `${forecast.weather}`; + } + + // Update temp and wind + const tempCell = rows[index].querySelector(`#tempday${index + 1}`); + if (tempCell) { + tempCell.textContent = `${Math.round(forecast.temp)}°C`; + } + + const windCell = rows[index].querySelector(`#windday${index + 1}`); + if (windCell) { + windCell.textContent = `${forecast.wind} m/s`; + } + } + }); + } + + // Function to update the background based on weather conditions + function updateBackground(weatherDescription, iconCode) { + const container = document.querySelector('.container'); + if (!container) return; + + // Remove previous weather classes + container.classList.remove('rainy', 'cloudy', 'clear', 'snowy', 'daytime', 'nighttime'); + + // Determine if it's day or night from the icon code (ends with d for day, n for night) + const isDaytime = iconCode.endsWith('d'); + container.classList.add(isDaytime ? 'daytime' : 'nighttime'); + + // Add appropriate weather class + if (weatherDescription.includes('rain') || weatherDescription.includes('drizzle')) { + container.classList.add('rainy'); + } else if (weatherDescription.includes('cloud')) { + container.classList.add('cloudy'); + } else if (weatherDescription.includes('clear')) { + container.classList.add('clear'); + } else if (weatherDescription.includes('snow')) { + container.classList.add('snowy'); + } + } + + // Function to cycle through default cities + function cycleCity() { + currentCityIndex = (currentCityIndex + 1) % cities.length; + const city = cities[currentCityIndex]; + fetchAndStoreWeather(city); + } + + + // Event listeners + function initializeEventListeners() { + const searchButton = document.getElementById("search-button"); + const inputField = document.getElementById("input-field"); + const nextSideButton = document.getElementById('next-side-button'); + + if (searchButton) { + searchButton.addEventListener("click", function () { + if (inputField && inputField.value.trim()) { + fetchAndStoreWeather(inputField.value.trim()); + } + }); + } + + if (inputField) { + inputField.addEventListener("keydown", function (event) { + if (event.key === "Enter" && inputField.value.trim()) { + fetchAndStoreWeather(inputField.value.trim()); + } + }); + } + + if (nextSideButton) { + nextSideButton.addEventListener('click', cycleCity); + } else { + console.error("Could not find button with ID 'next-side-button'"); + } + } + + + initializeEventListeners(); + fetchAndStoreWeather("Stockholm"); + + const savedData = localStorage.getItem("weatherData"); + if (savedData) { + try { + weeklyForecast = JSON.parse(savedData); + } catch (e) { + console.error("Failed to parse saved weather data:", e); + } + } +}); + + diff --git a/script.ts b/script.ts new file mode 100644 index 0000000..69cf91f --- /dev/null +++ b/script.ts @@ -0,0 +1,231 @@ +// @ts-nocheck + +document.addEventListener('DOMContentLoaded', function () { + // API information + const API_KEY = '3bad52890d7306cc268371520cbaace6'; + const BASE_URL = 'https://api.openweathermap.org/data/2.5/forecast'; + + // List of default cities + const cities = ['Stockholm', 'Gothenburg', 'Oslo']; + let weeklyForecast = {}; + let currentCityIndex = 0; + + + interface WeatherApiResponse { + cod: string; + message?: string; + list: any[]; + city: { + name: string; + sunrise: number; + sunset: number; + }; + } + + async function fetchWeather(city: string): Promise { + try { + const response = await fetch(`${BASE_URL}?q=${city}&units=metric&appid=${API_KEY}`); + const data: WeatherApiResponse = await response.json(); + + if (data.cod !== "200") { + throw new Error(data.message || "Failed to fetch weather data."); + } + + return data; + } catch (error) { + console.error(`Error fetching weather data for ${city}:`, error); + return null; + } + } + + function getDayName(dateString) { + const date = new Date(dateString); + const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; + return days[date.getDay()]; + } + + async function fetchAndStoreWeather(city) { + const data = await fetchWeather(city); + if (!data || !data.list) { + return; + } + + const todayData = data.list.find(entry => entry.dt_txt.includes("12:00:00")) || data.list[0]; + const todayDate = todayData.dt_txt.split(" ")[0]; + const sunriseTime = new Date(data.city.sunrise * 1000).toLocaleTimeString("sv-SE", { hour: "2-digit", minute: "2-digit" }); + const sunsetTime = new Date(data.city.sunset * 1000).toLocaleTimeString("sv-SE", { hour: "2-digit", minute: "2-digit" }); + + const todayForecast = { + city: data.city.name, + day: getDayName(todayDate), + weather: todayData.weather[0].description, + icon: todayData.weather[0].icon, + temp: todayData.main.temp, + wind: todayData.wind.speed, + sunrise: sunriseTime, + sunset: sunsetTime, + }; + + const dailyForecasts = {}; + + data.list.forEach(entry => { + const date = entry.dt_txt.split(' ')[0]; + const hour = entry.dt_txt.split(' ')[1].split(':')[0]; + + if (hour === '12' && date !== todayDate) { + dailyForecasts[date] = { + date: date, + day: getDayName(date), + icon: entry.weather[0].icon, + weather: entry.weather[0].description, + temp: entry.main.temp, + wind: entry.wind.speed, + }; + } + }); + + const upcomingForecast = Object.values(dailyForecasts).slice(0, 4); + + weeklyForecast[city] = { + today: todayForecast, + upcoming: upcomingForecast + }; + + localStorage.setItem("weatherData", JSON.stringify(weeklyForecast)); + + displayTodaysWeather(todayForecast); + displayWeeklyWeather(upcomingForecast); + updateBackground(todayForecast.weather, todayForecast.icon); + } + + function displayTodaysWeather(forecast) { + const weatherContent = document.getElementById('weather-content'); + if (!weatherContent) return; + + weatherContent.innerHTML = ` +
+ ${forecast.weather} +
+

${Math.round(forecast.temp)}°C

+

${forecast.city}

+

${forecast.weather}

+
+

Sunrise: ${forecast.sunrise}

+

Sunset: ${forecast.sunset}

+
+ `; + } + + function displayWeeklyWeather(forecastList) { + const forecastTable = document.querySelector("#weather-forecast table"); + if (!forecastTable) return; + + const rows = forecastTable.getElementsByTagName("tr"); + if (!rows || rows.length === 0) return; + + forecastList.forEach((forecast, index) => { + if (index < rows.length) { + const dayCell = rows[index].querySelector(`#day${index + 1}`); + if (dayCell) dayCell.textContent = forecast.day; + + const iconCell = rows[index].querySelector(`#iconday${index + 1}`); + if (iconCell) { + iconCell.innerHTML = `${forecast.weather}`; + } + + const tempCell = rows[index].querySelector(`#tempday${index + 1}`); + if (tempCell) tempCell.textContent = `${Math.round(forecast.temp)}°C`; + + const windCell = rows[index].querySelector(`#windday${index + 1}`); + if (windCell) windCell.textContent = `${forecast.wind} m/s`; + } + }); + } + + function updateBackground(weatherDescription, iconCode) { + const container = document.querySelector('.container'); + if (!container) return; + + container.classList.remove('rainy', 'cloudy', 'clear', 'snowy', 'daytime', 'nighttime'); + + const isDaytime = iconCode.endsWith('d'); + container.classList.add(isDaytime ? 'daytime' : 'nighttime'); + + if (weatherDescription.includes('rain') || weatherDescription.includes('drizzle')) { + container.classList.add('rainy'); + } else if (weatherDescription.includes('cloud')) { + container.classList.add('cloudy'); + } else if (weatherDescription.includes('clear')) { + container.classList.add('clear'); + } else if (weatherDescription.includes('snow')) { + container.classList.add('snowy'); + } + } + + function cycleCity() { + currentCityIndex = (currentCityIndex + 1) % cities.length; + const city = cities[currentCityIndex]; + fetchAndStoreWeather(city); + } + + function initializeEventListeners() { + const searchButton = document.getElementById("search-button"); + const inputField = document.getElementById("input-field"); + const nextSideButton = document.getElementById('next-side-button'); + + if (searchButton) { + searchButton.addEventListener("click", function () { + if (inputField && inputField.value.trim()) { + fetchAndStoreWeather(inputField.value.trim()); + } + }); + } + + if (inputField) { + inputField.addEventListener("keydown", function (event) { + if (event.key === "Enter" && inputField.value.trim()) { + fetchAndStoreWeather(inputField.value.trim()); + } + }); + } + + if (nextSideButton) { + nextSideButton.addEventListener('click', cycleCity); + } else { + console.error("Could not find button with ID 'next-side-button'"); + } + } + + initializeEventListeners(); + fetchAndStoreWeather("Stockholm"); + + const savedData = localStorage.getItem("weatherData"); + if (savedData) { + try { + weeklyForecast = JSON.parse(savedData); + } catch (e) { + console.error("Failed to parse saved weather data:", e); + } + } +}); + + + + + + + + + + + + + + + + + + + + + diff --git a/style.css b/style.css new file mode 100644 index 0000000..4b4b406 --- /dev/null +++ b/style.css @@ -0,0 +1,214 @@ +/* Global styling*/ + +* { + padding: 0; + margin: 0; + box-sizing: border-box; +} + +body { + font-family: 'Roboto', sans-serif; + background-color: #f0f8ff; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + /*full height of the viewpoint - it will take up the entire vertical height of the user's screen*/ +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + + +/*App styling*/ +.container { + background: linear-gradient(135deg, #a2c2e8, #f6e6f6); + display: flex; + align-items: center; + flex-direction: column; + max-width: 320px; + width: 100%; + height: 600px; + margin: 100px auto; + border: none; + border-radius: 10px; + position: relative; + overflow: hidden; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); +} + + +#main-icon { + width: 60px; + height: 60px; + margin: 15px auto; + display: block; + margin: 25px auto 20px auto; + position: relative; + top: 15px; +} + + +.overlay { + width: 100%; + height: 60%; + background: rgba(3, 10, 85, 0.45); + clip-path: ellipse(120% 92% at 50% 0%); +} + +.weather-content { + position: absolute; + top: 30%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 2; + /* Puts content above image*/ + color: #ffffff; +} + +.input-container { + color: #ffffff; + position: absolute; + top: 5%; + left: 50%; + transform: translateX(-50%); + display: flex; + align-items: center; + border: 1px solid #ffffff; + width: fit-content; + border-radius: 8px; + z-index: 2; +} + +input { + background-color: inherit; + color: #ffffff; + padding: 8px 16px; + font-size: 0.8rem; + text-decoration: none; + text-align: left; + border: none; + outline: none; +} + +input::placeholder { + color: #dedede; +} + +#search-button { + border: 1px solid transparent; + width: 40px; + height: 38px; + display: flex; + align-items: center; + justify-content: center; + background: transparent; + cursor: pointer; + color: #ffffff; +} + +#search-button img { + width: 24px; + height: 24px; + border-left: 1px solid #ffffff; +} + +#next-side-button { + margin: 40px 0; + border: none; + width: 70px; + height: 70px; + background-color: rgb(32, 32, 136); + color: white; + font-size: 20px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + cursor: pointer; + z-index: 2; + position: absolute; + /* Allows precise positioning */ + top: 46%; + /* Center vertically */ + right: 10px; + /* Align to the right */ + transform: translateY(-50%); + /* Adjust to true center */ +} + +/*Weather content styling*/ +#temperature { + font-size: 40px; + font-weight: 300; +} + +#city { + font-size: 35px; + font-weight: 300; +} + +#time { + font-size: 18px; + font-weight: 300; + margin: 6px 0 8px 0; +} + +#weather, +#sunrise, +#sunset { + font-size: 15px; + font-weight: 300; + margin: 6px 0; +} + +#sunrise { + margin-right: 10px; +} + +.sunrise-sunset { + display: flex; +} + +.weather-forecast { + color: #333; + position: absolute; + top: 76%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 2; + /* Puts content above image */ +} + +.weather-forecast table { + width: 100%; + text-align: center; + border-collapse: collapse; +} + +.weather-forecast td { + padding: 6px 12px; + font-size: 16 px; +} + + +.weather-forecast img { + display: flex; + width: 40px; + height: 40px; + top: 0; + left: 25%; +} + +#next-side-button:hover { + background-color: #1976d2; +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e0e9742 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES6", + "outDir": "./dist", + "strict": true + }, + "include": [ + "*.ts" + ], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file