├── LICENSE ├── index.html ├── README.md ├── cloudy.svg ├── animatedshape.svg ├── styles.css ├── script.js ├── snow.svg └── worldmap.svg /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Rishi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Weather 7 | 8 | 9 | 10 | 11 | 12 |
13 |

Weather

14 | 18 | 19 | 31 |
32 |
33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Weather app 2 | 3 | A Basic Weather searching website made with 4 | * HTML5 5 | * CSS3 6 | * JavaScript (jQuery) Ajax 7 | * SVG backgrounds 8 | * Data from https://open-meteo.com/ (API) 9 | * Deployment in vercel. 10 | [The Deployed site, check it out.](bit.ly/weather-searcher) 11 | 12 | ## Installation 13 | 14 | Just clone it to your local directory. 15 | 16 | ```bash 17 | git clone https://github.com/Rishi-Sudhakar/weather.git 18 | ``` 19 | 20 | Now, you can just double click on the HTML file to run it locally in your device. If you just want to try it out, click on the [link.](bit.ly/weather-searcher) 21 | 22 | ## Some Screenshots 23 | 24 | ![Screenshot 2024-06-08 at 9 19 59 PM](https://github.com/Rishi-Sudhakar/weather/assets/79398572/2b9f3e38-92bf-4532-93b6-c6002ee8d04a) 25 | 26 | ![Screenshot 2024-06-08 at 9 20 41 PM](https://github.com/Rishi-Sudhakar/weather/assets/79398572/6f707434-ce7a-48f0-8841-12e22adee7c8) 27 | 28 | ![Screenshot 2024-06-08 at 9 21 11 PM](https://github.com/Rishi-Sudhakar/weather/assets/79398572/ae867b2c-03a9-4d43-965f-ac11cc19a579) 29 | 30 | 31 | 32 | ## Acknowledgments 33 | 34 | I would like to extend my sincere gratitude to the following resources and individuals: 35 | 36 | - [Open Meteo](https://open-meteo.com/) for providing the free API used in this project to fetch accurate weather data. 37 | - [BGJar](https://bgjar.com/) for providing high-quality free SVG images used for dynamic background animations in the web application. 38 | 39 | ## Easter?! 40 | 41 | Small details you might not notice. 42 | 43 | 44 | * **SVG Backgrounds** : If you look well, you might notice that the background changes based on cities with respect to their temperatures. It's just two for now (less than 30 degrees = Snow, More than 30 degrees = Cloudy), Expecting to add more in the future. 45 | * **Known issue** : World map svg is supposed to be the default background but the webpage just refreshes so soon moving it to the animated background. 46 | 47 | ## Contributing 48 | 49 | Pull requests are welcome. For major changes, please open an issue first 50 | to discuss what you would like to change. 51 | -------------------------------------------------------------------------------- /cloudy.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /animatedshape.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | /* Basic reset */ 2 | * { 3 | margin: 0; 4 | padding: 0; 5 | box-sizing: border-box; 6 | } 7 | 8 | body { 9 | font-family: 'Roboto', sans-serif; 10 | background: linear-gradient(to right, #6a11cb, #2575fc); 11 | display: flex; 12 | justify-content: center; 13 | align-items: center; 14 | height: 100vh; 15 | color: #fff; 16 | overflow: hidden; 17 | } 18 | 19 | .container { 20 | text-align: center; 21 | background: rgba(255, 255, 255, 0.1); 22 | padding: 20px; 23 | border-radius: 10px; 24 | box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3); 25 | backdrop-filter: blur(10px); 26 | width: 80%; 27 | max-width: 600px; 28 | animation: fadeIn 1s ease-in-out; 29 | } 30 | 31 | .title { 32 | margin-bottom: 20px; 33 | font-size: 2.5em; 34 | font-weight: 500; 35 | animation: bounceIn 1s ease-in-out; 36 | } 37 | 38 | .search-box { 39 | display: flex; 40 | justify-content: center; 41 | margin-bottom: 20px; 42 | } 43 | 44 | #city { 45 | padding: 10px; 46 | border: none; 47 | border-radius: 5px; 48 | margin-right: 10px; 49 | font-size: 1em; 50 | width: 70%; 51 | max-width: 300px; 52 | } 53 | 54 | #search { 55 | padding: 10px 20px; 56 | background-color: #4CAF50; 57 | color: white; 58 | border: none; 59 | border-radius: 5px; 60 | cursor: pointer; 61 | transition: background-color 0.3s, transform 0.2s; 62 | } 63 | 64 | #search:hover { 65 | background-color: #45a049; 66 | transform: scale(1.1); 67 | } 68 | 69 | .weather-data { 70 | margin-top: 20px; 71 | } 72 | 73 | .weather-card { 74 | background: rgba(255, 255, 255, 0.2); 75 | padding: 20px; 76 | border-radius: 10px; 77 | box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3); 78 | transition: transform 0.3s ease; 79 | animation: fadeIn 1s ease-in-out; 80 | } 81 | 82 | .weather-card:hover { 83 | transform: scale(1.05); 84 | } 85 | 86 | .weather-info { 87 | margin-top: 10px; 88 | animation: fadeIn 1s ease-in-out; 89 | } 90 | 91 | .hidden { 92 | display: none; 93 | } 94 | 95 | .background-animation { 96 | position: absolute; 97 | top: 0; 98 | left: 0; 99 | width: 100%; 100 | height: 100%; 101 | pointer-events: none; 102 | background: url('worldmap.svg') no-repeat center center/cover; 103 | opacity: 0.3; 104 | animation: moveBackground 20s linear infinite; 105 | } 106 | 107 | @keyframes fadeIn { 108 | from { 109 | opacity: 0; 110 | transform: translateY(-20px); 111 | } 112 | to { 113 | opacity: 1; 114 | transform: translateY(0); 115 | } 116 | } 117 | 118 | @keyframes bounceIn { 119 | from { 120 | opacity: 0; 121 | transform: scale(0.3); 122 | } 123 | 50% { 124 | opacity: 1; 125 | transform: scale(1.05); 126 | } 127 | to { 128 | transform: scale(1); 129 | } 130 | } 131 | 132 | @keyframes moveBackground { 133 | from { 134 | background-position: 0 0; 135 | } 136 | to { 137 | background-position: 100% 100%; 138 | } 139 | } 140 | 141 | .loader { 142 | border: 4px solid #f3f3f3; 143 | border-radius: 50%; 144 | border-top: 4px solid #3498db; 145 | width: 40px; 146 | height: 40px; 147 | animation: spin 2s linear infinite; 148 | margin: 20px auto; 149 | } 150 | 151 | @keyframes spin { 152 | 0% { transform: rotate(0deg); } 153 | 100% { transform: rotate(360deg); } 154 | } 155 | 156 | .hourly-forecast { 157 | margin-top: 20px; 158 | } 159 | 160 | .hourly-forecast-item { 161 | display: inline-block; 162 | margin: 5px; 163 | padding: 10px; 164 | background: rgba(255, 255, 255, 0.3); 165 | border-radius: 5px; 166 | text-align: center; 167 | transition: transform 0.3s ease; 168 | cursor: pointer; 169 | } 170 | 171 | .hourly-forecast-item:hover { 172 | transform: scale(1.1); 173 | } 174 | 175 | .daily-forecast { 176 | margin-top: 20px; 177 | display: flex; 178 | flex-wrap: wrap; 179 | justify-content: center; 180 | } 181 | 182 | .daily-forecast-item { 183 | background: rgba(255, 255, 255, 0.2); 184 | padding: 10px; 185 | border-radius: 10px; 186 | margin: 5px; 187 | text-align: center; 188 | width: 80px; 189 | transition: transform 0.3s ease; 190 | } 191 | 192 | .daily-forecast-item:hover { 193 | transform: scale(1.1); 194 | } 195 | 196 | .tooltip { 197 | position: relative; 198 | display: inline-block; 199 | } 200 | 201 | .tooltip .tooltiptext { 202 | visibility: hidden; 203 | width: 120px; 204 | background-color: black; 205 | color: #fff; 206 | text-align: center; 207 | border-radius: 6px; 208 | padding: 5px; 209 | position: absolute; 210 | z-index: 1; 211 | bottom: 125%; 212 | left: 50%; 213 | margin-left: -60px; 214 | opacity: 0; 215 | transition: opacity 0.3s; 216 | } 217 | 218 | .tooltip:hover .tooltiptext { 219 | visibility: visible; 220 | opacity: 1; 221 | } 222 | 223 | /* Additional background styles */ 224 | .bg-snow { 225 | background: url('snow.svg') no-repeat center center/cover; 226 | } 227 | 228 | .bg-cloudy { 229 | background: url('cloudy.svg') no-repeat center center/cover; 230 | } 231 | 232 | .bg-animated { 233 | background: url('animatedshape.svg') no-repeat center center/cover; 234 | } 235 | -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | const initialBackground = 'worldmap.svg'; 3 | const snowBackground = 'snow.svg'; 4 | const cloudyBackground = 'cloudy.svg'; 5 | const animatedBackground = 'animatedshape.svg'; 6 | 7 | // Function to set the background image 8 | function setBackground(image) { 9 | $('#background-animation').css('background-image', 'url(' + image + ')'); 10 | } 11 | 12 | // Initial background on page load 13 | setBackground(initialBackground); 14 | 15 | // Set the background to animatedshape.svg on page reload 16 | $(window).on('load', function() { 17 | setBackground(animatedBackground); 18 | }); 19 | 20 | $('#search').click(function(){ 21 | var city = $('#city').val(); 22 | if(city === "") { 23 | alert("Please enter a city name."); 24 | return; 25 | } 26 | 27 | $('#loader').removeClass('hidden'); 28 | $('#weather-data').addClass('hidden'); 29 | 30 | var geocodingUrl = 'https://nominatim.openstreetmap.org/search?format=json&q=' + city; 31 | 32 | $.ajax({ 33 | url: geocodingUrl, 34 | type: 'GET', 35 | dataType: 'json', 36 | success: function(data){ 37 | if(data.length > 0) { 38 | var location = data[0]; 39 | var latitude = location.lat; 40 | var longitude = location.lon; 41 | var weatherUrl = 'https://api.open-meteo.com/v1/forecast?latitude=' + latitude + '&longitude=' + longitude + '¤t_weather=true&hourly=temperature_2m,relative_humidity_2m,wind_speed_10m&daily=temperature_2m_max,temperature_2m_min,precipitation_sum&timezone=auto'; 42 | 43 | $.ajax({ 44 | url: weatherUrl, 45 | type: 'GET', 46 | dataType: 'json', 47 | success: function(weatherData){ 48 | var temperature = weatherData.current_weather.temperature; 49 | var windSpeed = weatherData.current_weather.windspeed; 50 | var humidity = weatherData.hourly.relative_humidity_2m[0]; 51 | 52 | // Change background based on temperature 53 | if (temperature < 30) { 54 | setBackground(snowBackground); 55 | } else { 56 | setBackground(cloudyBackground); 57 | } 58 | 59 | $('#city-name').text('Weather in ' + city); 60 | $('#temperature').html(' ' + temperature + '°C'); 61 | $('#wind-speed').html(' ' + windSpeed + ' m/s'); 62 | $('#humidity').html(' ' + humidity + '%'); 63 | 64 | var hourlyForecastHtml = ''; 65 | for(var i = 0; i < 6; i++) { 66 | hourlyForecastHtml += '
'; 67 | hourlyForecastHtml += '

' + weatherData.hourly.time[i].substring(11, 16) + '

'; 68 | hourlyForecastHtml += '

' + weatherData.hourly.temperature_2m[i] + '°C

'; 69 | hourlyForecastHtml += '

' + weatherData.hourly.wind_speed_10m[i] + ' m/s

'; 70 | hourlyForecastHtml += 'Humidity: ' + weatherData.hourly.relative_humidity_2m[i] + '%'; 71 | hourlyForecastHtml += '
'; 72 | } 73 | $('#hourly-forecast').html(hourlyForecastHtml); 74 | 75 | var dailyForecastHtml = ''; 76 | for(var i = 0; i < 5; i++) { 77 | dailyForecastHtml += '
'; 78 | dailyForecastHtml += '

' + weatherData.daily.time[i].substring(5, 10) + '

'; 79 | dailyForecastHtml += '

' + weatherData.daily.temperature_2m_max[i] + '°C

'; 80 | dailyForecastHtml += '

' + weatherData.daily.temperature_2m_min[i] + '°C

'; 81 | dailyForecastHtml += '

' + weatherData.daily.precipitation_sum[i] + 'mm

'; 82 | dailyForecastHtml += '
'; 83 | } 84 | $('#daily-forecast').html(dailyForecastHtml); 85 | 86 | $('#weather-data').removeClass('hidden').hide().fadeIn(1000); 87 | $('#loader').addClass('hidden'); 88 | }, 89 | error: function(xhr, status, error){ 90 | $('#weather-data').html('

Error fetching weather data

').removeClass('hidden').hide().fadeIn(1000); 91 | $('#loader').addClass('hidden'); 92 | } 93 | }); 94 | } else { 95 | $('#weather-data').html('

City not found

').removeClass('hidden').hide().fadeIn(1000); 96 | $('#loader').addClass('hidden'); 97 | } 98 | }, 99 | error: function(xhr, status, error){ 100 | $('#weather-data').html('

Error fetching geolocation data

').removeClass('hidden').hide().fadeIn(1000); 101 | $('#loader').addClass('hidden'); 102 | } 103 | }); 104 | }); 105 | }); 106 | -------------------------------------------------------------------------------- /snow.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /worldmap.svg: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------