frontend-1

commit 7be86760ce28bb8302c0f11b7ec6ce4642db24f5

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>