Author: Pedro Lucas Porcellis <porcellis@eletrotupi.com>
weather: introduce tabs and refactor weather js code
css/form.css | 1 css/tabs.css | 35 +++++++++++ css/weather.css | 4 + js/weather.js | 151 +++++++++++++++++++++++++++++++------------------- weather.html | 97 +++++++++++++++++++------------
diff --git a/css/form.css b/css/form.css index 4cccecf8f58d0e220a464e65e59660fb5a14b97c..6633485c729f50e396dd20a30ffa446792fa7b42 100644 --- a/css/form.css +++ b/css/form.css @@ -62,6 +62,7 @@ width: 100%; margin: 0 0 22px; padding: 8px 10px 7px; border: 2px solid transparent; + transition: background-color 0.2s ease; color: #fff; background-color: #00703c; diff --git a/css/tabs.css b/css/tabs.css new file mode 100644 index 0000000000000000000000000000000000000000..072e6cf32a9445ce90b5b7d2c1d695baf5ce2377 --- /dev/null +++ b/css/tabs.css @@ -0,0 +1,35 @@ +.tabs { + display: flex; + justify-content: center; + margin-bottom: 1rem; +} + +.tab-button { + flex: 1; + padding: 0.5rem 1rem; + color: #000; + background-color: #f8f9fa; + cursor: pointer; + font-size: 1rem; + transition: background-color 0.2s ease; + box-shadow: none; +} + +.tab-button:hover { + color: #fff; + background-color: #005a30; +} + +.tab-button.active { + background-color: #00703c; + color: #fff; +} + +.tab-content { + display: none; +} + +.tab-content.active { + display: block; +} + diff --git a/css/weather.css b/css/weather.css index f4d336fdf7d1efe39c1a976fc5c77e15d53f77bd..adc8317208f3f4e9c7669801171eaab2475c714d 100644 --- a/css/weather.css +++ b/css/weather.css @@ -1,3 +1,7 @@ .hidden { display: none; } + +#city-form button[type="submit"] { + margin-top: 5px; +} diff --git a/js/weather.js b/js/weather.js index 89b29b139b34f8b1e8eb69210aba92a897c71141..9b1b10d21547955911b1b77194b40aa9e81abc5f 100644 --- a/js/weather.js +++ b/js/weather.js @@ -1,71 +1,106 @@ -document.addEventListener("DOMContentLoaded", () => { - const weatherApiKey = ""; - const weatherContainer = document.getElementById("weather-info"); - const locationElement = document.getElementById("location"); - const temperatureElement = document.getElementById("temperature"); - const conditionsElement = document.getElementById("conditions"); - const loadingElement = document.getElementById("loading"); +const weatherApiKey = "20e17f827394ac7eeb484d06ff9e2527"; +const tabs = document.querySelectorAll(".tab-button"); +const tabContents = document.querySelectorAll(".tab-content"); - // Função para obter a geolocalização do usuário - const getUserLocation = () => { - if (navigator.geolocation) { - loadingElement.textContent = "Localização OK! Buscando dados de clima..."; +// Tabs stuff +const initializeTabs = () => { + tabs.forEach((tab) => { + tab.addEventListener("click", () => switchTab(tab)); + }); +} - navigator.geolocation.getCurrentPosition(fetchWeather, handleLocationError); - } else { - loadingElement.textContent = "Geolocalização não é suportada pelo seu navegador."; - } +const switchTab = (tab) => { + tabs.forEach((t) => t.classList.remove("active")); + tabContents.forEach((content) => content.classList.remove("active")); + + tab.classList.add("active"); + document.getElementById(tab.dataset.tab).classList.add("active"); +} + +const initializeApp = () => { + initializeTabs(); + getUserLocationWeather(); +} + +// Geo stuff + +const getUserLocationWeather = () => { + if (navigator.geolocation) { + navigator.geolocation.getCurrentPosition( + (position) => fetchWeatherByCoordinates(position.coords), + handleLocationError + ); + } else { + updateWeatherDisplay("location", "Geolocalização não suportada pelo navegador."); } +} - // Função para buscar os dados de clima - const fetchWeather = (position) => { - const { latitude, longitude } = position.coords; - const apiUrl = `https://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&units=metric&lang=pt_br&appid=${weatherApiKey}`; +function fetchWeatherByCoordinates(coords) { + const apiUrl = `https://api.openweathermap.org/data/2.5/weather?lat=${coords.latitude}&lon=${coords.longitude}&units=metric&lang=pt_br&appid=${weatherApiKey}`; + + fetch(apiUrl) + .then((response) => response.json()) + .then((data) => displayCurrentWeather(data)) + .catch(() => updateWeatherDisplay("location", "Erro ao obter o clima.")); +} + +const displayCurrentWeather = (data) => { + updateWeatherDisplay("location", `Cidade: ${data.name}`); + updateWeatherDisplay("temperature", `Temperatura: ${data.main.temp.toFixed(1)}°C`); + updateWeatherDisplay("conditions", `Condições: ${data.weather[0].description}`); +} + +const handleLocationError = (error) => { + const errorMessage = { + 1: "Permissão negada para acessar localização.", + 2: "Localização indisponível.", + 3: "Tempo de solicitação esgotado.", + }; + + updateWeatherDisplay("location", errorMessage[error.code] || "Erro desconhecido."); +} - fetch(apiUrl) - .then((response) => { - if (!response.ok) { - throw new Error("Erro ao buscar dados de clima."); - } - return response.json(); - }) - .then((data) => displayWeather(data)) - .catch((error) => { - loadingElement.textContent = "Erro ao buscar previsão do tempo."; - console.error(error); - }); +const updateWeatherDisplay = (elementId, textContent) => { + const element = document.getElementById(elementId); + if (element) { + element.textContent = textContent; } +} - // Função para exibir os dados de clima - const displayWeather = (data) => { - const { name } = data; - const { temp } = data.main; - const { description } = data.weather[0]; +// By city + +const initializeCitySearch = () => { + const cityForm = document.getElementById("city-form"); + cityForm.addEventListener("submit", handleCitySearch); +} + +const handleCitySearch = (event) => { + event.preventDefault(); - loadingElement.classList.add("hidden"); - weatherContainer.classList.remove("hidden"); + const cityInput = document.getElementById("city-input").value.trim(); - locationElement.textContent = name; - temperatureElement.textContent = `${temp.toFixed(1)}°C`; - conditionsElement.textContent = description; + if (cityInput) { + fetchWeatherByCity(cityInput); } +} + +const fetchWeatherByCity = (city) => { + const cityWeatherUrl = `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&lang=pt_br&appid=${weatherApiKey}`; - const handleLocationError = (error) => { - switch (error.code) { - case error.PERMISSION_DENIED: - loadingElement.textContent = "Permissão negada para acessar localização."; - break; - case error.POSITION_UNAVAILABLE: - loadingElement.textContent = "Localização indisponível."; - break; - case error.TIMEOUT: - loadingElement.textContent = "Tempo de solicitação esgotado."; - break; - default: - loadingElement.textContent = "Ocorreu um erro desconhecido."; - break; - } - } + fetch(cityWeatherUrl) + .then((response) => response.json()) + .then((data) => displayCityWeather(data)) + .catch(() => updateWeatherDisplay("city-location", "Erro ao buscar o clima para essa cidade.")); +} + +const displayCityWeather = (data) => { + updateWeatherDisplay("city-location", `Localização: ${data.name}`); + updateWeatherDisplay("city-temperature", `Temperatura: ${data.main.temp.toFixed(1)}°C`); + updateWeatherDisplay("city-conditions", `Condições: ${data.weather[0].description}`); +} - getUserLocation(); +// Rig everything and boot this fucking shit +document.addEventListener("DOMContentLoaded", () => { + initializeApp(); + initializeCitySearch(); }); diff --git a/weather.html b/weather.html index c8c56503cf76a04766adee8291eab259ea0c8c85..f5c99b769e9e53df8a2beb50a332722df5c94376 100644 --- a/weather.html +++ b/weather.html @@ -1,43 +1,64 @@ <!DOCTYPE html> <html lang="pt-br"> -<head> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>Previsão do Tempo</title> - <link rel="stylesheet" href="css/reset.css"> - <link rel="stylesheet" href="css/layout.css"> - <link rel="stylesheet" href="css/header.css"> - <link rel="stylesheet" href="css/footer.css"> - <link rel="stylesheet" href="css/weather.css"> -</head> -<body> - <header> - <h1>Previsão do Tempo</h1> - <button id="menuToggle">☰</button> - <nav> - <ul class="hidden"> - <li><a href="index.html">Início</a></li> - <li><a href="tasks.html">Tarefas</a></li> - <li><a href="weather.html">Previsão do Tempo</a></li> - </ul> - </nav> - </header> - <main> - <section id="weather"> - <h2>Veja o clima na sua região</h2> - <p id="loading">Carregando informações...</p> - <div id="weather-info" class="hidden"> - <p><strong>Local:</strong> <span id="location"></span></p> - <p><strong>Temperatura:</strong> <span id="temperature"></span></p> - <p><strong>Condições:</strong> <span id="conditions"></span></p> + <head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Previsão do Tempo</title> + <link rel="stylesheet" href="css/reset.css"> + <link rel="stylesheet" href="css/layout.css"> + <link rel="stylesheet" href="css/header.css"> + <link rel="stylesheet" href="css/form.css"> + <link rel="stylesheet" href="css/footer.css"> + <link rel="stylesheet" href="css/tabs.css"> + <link rel="stylesheet" href="css/weather.css"> + </head> + <body> + <header> + <h1>Previsão do Tempo</h1> + <button id="menuToggle">☰</button> + <nav> + <ul class="hidden"> + <li><a href="index.html">Início</a></li> + <li><a href="tasks.html">Tarefas</a></li> + <li><a href="weather.html">Previsão do Tempo</a></li> + </ul> + </nav> + </header> + + <main> + <h1>Previsão do Tempo</h1> + <div class="tabs"> + <button class="tab-button active" data-tab="current-weather">Clima Atual</button> + <button class="tab-button" data-tab="search-weather">Buscar por Cidade</button> + </div> + + <div class="tab-content active" id="current-weather"> + <div id="weather"> + <p id="location">Obtendo sua localização...</p> + <p id="temperature"></p> + <p id="conditions"></p> + </div> + </div> + + <div class="tab-content" id="search-weather"> + <form id="city-form"> + <label for="city-input">Digite o nome da cidade:</label> + <input type="text" id="city-input" placeholder="Ex.: Bagé" required /> + <button type="submit">Buscar Clima</button> + </form> + <div id="city-weather"> + <p id="city-location"></p> + <p id="city-temperature"></p> + <p id="city-conditions"></p> + </div> </div> - </section> - </main> - <footer> - <p>© 2025</p> - </footer> - <script src="js/menu.js" defer></script> - <script src="js/weather.js" defer></script> -</body> + </main> + + <footer> + <p>© 2025</p> + </footer> + <script src="js/menu.js" defer></script> + <script src="js/weather.js" defer></script> + </body> </html>