From 3c5b7024982a420a61825fcc4f8f15e1d36f776f Mon Sep 17 00:00:00 2001 From: iamfannyhenriques Date: Tue, 24 Sep 2024 23:56:06 +0200 Subject: [PATCH 1/7] started with project weather-app --- index.html | 29 +++++++++++++++++++++++++++++ script.js | 25 +++++++++++++++++++++++++ style.css | 30 ++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 index.html create mode 100644 script.js create mode 100644 style.css diff --git a/index.html b/index.html new file mode 100644 index 000000000..18e448c4d --- /dev/null +++ b/index.html @@ -0,0 +1,29 @@ + + + + + + + + WeathertheweatherApp + + + +
+
+
+

Temp

+

location

+
+
+

forecast for the following 4 days

+
    forecast
+
+
+ +
+ + + + + \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 000000000..0e8c8fcfe --- /dev/null +++ b/script.js @@ -0,0 +1,25 @@ + +const BASE_URL = 'https://api.openweathermap.org/data/2.5/forecast?q=Stockholm,Sweden&units=metric&appid=' +const API_KEY = '1bd3fe8b6571a9e92c6d24232e62bdc8' + +const URL = `${BASE_URL}${API_KEY}` + +console.log(URL) + +const weatherLocation = document.getElementById("location") +const temperature = document.getElementById("temp") + +fetch(URL) + .then(response => response.json()) + .then(data => { + console.log(data.list[0].main.temp) + + const stockholm = data.city.name + const stockholmTemp = data.list[0].main.temp + + weatherLocation.innerText = stockholm + temperature.innerText = stockholmTemp + + }) + + diff --git a/style.css b/style.css new file mode 100644 index 000000000..df6e619e0 --- /dev/null +++ b/style.css @@ -0,0 +1,30 @@ +body { + background-color: lightblue; + margin: 30px; + text-align: center; +} + +.weather-card { + width: 414px; + height: 896px; + border: 1px solid black; + margin: 0 auto; + border-radius: 20px; + box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.3); + display: flex; + flex-direction: column; +} + +.location-card { + background-color: gray; + width: 100%; + height: 50%; + border-radius: 20px 20px 0 0; +} + +.forecast-card { + background-color: white; + width: 100%; + height: 50%; + border-radius: 0 0 20px 20px; +} \ No newline at end of file From f653a468e393b50678b7c374a8a9b5e10c1f5660 Mon Sep 17 00:00:00 2001 From: iamfannyhenriques Date: Fri, 27 Sep 2024 16:50:16 +0200 Subject: [PATCH 2/7] fetched current weather from the baseurl --- index.html | 11 ++++- kladd | 0 script.js | 118 +++++++++++++++++++++++++++++++++++++++++++++++++---- style.css | 48 +++++++++++++++++++--- 4 files changed, 162 insertions(+), 15 deletions(-) create mode 100644 kladd diff --git a/index.html b/index.html index 18e448c4d..c35938dad 100644 --- a/index.html +++ b/index.html @@ -5,6 +5,12 @@ + + + + WeathertheweatherApp @@ -12,8 +18,11 @@
-

Temp

+

Temp

location

+

condition

+

sunrise

+

sunset

forecast for the following 4 days

diff --git a/kladd b/kladd new file mode 100644 index 000000000..e69de29bb diff --git a/script.js b/script.js index 0e8c8fcfe..2a4a35985 100644 --- a/script.js +++ b/script.js @@ -1,25 +1,127 @@ -const BASE_URL = 'https://api.openweathermap.org/data/2.5/forecast?q=Stockholm,Sweden&units=metric&appid=' +//STEP 1: constructing the BASE URL +const BASE_URL = 'https://api.openweathermap.org/data/2.5/weather?q=Stockholm,Sweden&units=metric&appid=' const API_KEY = '1bd3fe8b6571a9e92c6d24232e62bdc8' const URL = `${BASE_URL}${API_KEY}` console.log(URL) -const weatherLocation = document.getElementById("location") -const temperature = document.getElementById("temp") +//STEP 2: URL for Weather Forecast +const FORECAST_URL = 'https://api.openweathermap.org/data/2.5/forecast?q=Stockholm,Sweden&units=metric&appid=' +const forecastURL = `${FORECAST_URL}${API_KEY}` + +console.log(forecastURL) + + +// DOM Selectors +const weatherLocation = document.getElementById("location"); +const temperature = document.getElementById("temp"); +const weatherCondition = document.getElementById("condition"); +const sunriseDisplay = document.getElementById("sunriseID"); +const sunsetDisplay = document.getElementById("sunsetID"); + +//FUNCTIONS +// Function to convert UNIX timestamp to readable time format +const convertUnixToTime = (unixTimestamp) => { + const date = new Date(unixTimestamp * 1000); + //Round the number to a format without seconds + return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); +}; + +//Function to make the background adapt to the weathercondition +const makeElementSunny = (element) => { + element.classList.remove("weather-card") + element.classList.add("weather-card-sunny") +} +//Fetching data from the IPA for current weather fetch(URL) .then(response => response.json()) .then(data => { - console.log(data.list[0].main.temp) + console.log(data); + + const stockholm = data.name; + const stockholmTemp = data.main.temp; + const roundedTemp = Math.round(stockholmTemp); + const displayCondition = data.weather[0].description;; - const stockholm = data.city.name - const stockholmTemp = data.list[0].main.temp + //changing the innerHTML for city, temp and condition. + weatherLocation.innerText = `${stockholm}`; + temperature.innerHTML = + `${roundedTemp}°C`; + weatherCondition.innerText = `${displayCondition}`; - weatherLocation.innerText = stockholm - temperature.innerText = stockholmTemp + //Get the sunrise and sunset + const sunriseTime = convertUnixToTime(data.sys.sunrise); + const sunsetTime = convertUnixToTime(data.sys.sunset); + + // Display sunrise and sunset times + sunriseDisplay.innerText = `Sunrise ${sunriseTime}`; + sunsetDisplay.innerText = `Sunset ${sunsetTime}`; + + // switch(displayCondition) { + // case "Clear": + // makeElementSunny(document.getElementById("--")) + // break + // case "Cloudy": + // ... + // break + // } + + // if (displayCondition == "Clear") { + // makeElementSunny(document.getElementById("--")) + // } else if() }) + .catch(error => console.error('Error fetching data:', error)); + + +//Fetching data from the forecastURL +fetch(forecastURL) + .then(response => response.json()) + .then(data => { + console.log(data) + + + // Helper function to format timestamp to date string (YYYY-MM-DD) + const formatDate = (timestamp) => { + const date = new Date(timestamp * 1000); + return date.toISOString().split('T')[0]; // Get only the date part + }; + + // Initialize an object to hold daily min and max temps + const dailyTemps = {}; + + // Iterate through the weather forecast + data.list.forEach((forecast) => { + const date = formatDate(forecast.dt); + const minTemp = forecast.main.temp_min; + const maxTemp = forecast.main.temp_max; + + // Initialize the entry for the date if it doesn't exist + if (!dailyTemps[date]) { + dailyTemps[date] = { min: minTemp, max: maxTemp }; + } else { + // Update the min and max temps for the day + dailyTemps[date].min = Math.min(dailyTemps[date].min, minTemp); + dailyTemps[date].max = Math.max(dailyTemps[date].max, maxTemp); + } + }); + + // Extract the next four days' temperatures + const nextFourDays = Object.entries(dailyTemps).slice(0, 4).map(([date, temps]) => ({ + date, + min: temps.min, + max: temps.max, + })); + + console.log(nextFourDays); // Output the result + }) + .catch(error => { + console.error('Error fetching weather data:', error); // Handle errors + }); + + diff --git a/style.css b/style.css index df6e619e0..783dbe091 100644 --- a/style.css +++ b/style.css @@ -1,30 +1,66 @@ body { - background-color: lightblue; + background-color: lightgray; margin: 30px; text-align: center; + font-family: "Roboto", sans-serif; + font-weight: 300; + font-style: normal; } .weather-card { width: 414px; height: 896px; - border: 1px solid black; margin: 0 auto; - border-radius: 20px; box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.3); display: flex; flex-direction: column; + background-color: white; +} + +.weather-card-sunny { + width: 414px; + height: 896px; + margin: 0 auto; + box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.3); + display: flex; + flex-direction: column; + background-color: yellow; } .location-card { - background-color: gray; + background: linear-gradient(90deg, #8589FF 0%, #E8E9FF 100%); + ; width: 100%; height: 50%; - border-radius: 20px 20px 0 0; + color: white; +} + +.temp { + font-size: 120px; + display: inline-block; + position: relative; + line-height: 140.63px; + margin-top: 30px; + margin-bottom: 0; +} + +/* making the unit be positioned at the top of the temp-number */ +.temp-unit { + font-size: 40px; + display: inline-block; + bottom: 100%; + left: 0; + transform: translateY(-50px); + margin-left: 1px; +} + +/* Display sunrise and sunset on the same line */ +.sunrise-sunset { + display: inline; } .forecast-card { background-color: white; width: 100%; height: 50%; - border-radius: 0 0 20px 20px; } \ No newline at end of file From b429b1d4b2a678bf7546c44416ebed73af1eb627 Mon Sep 17 00:00:00 2001 From: iamfannyhenriques Date: Sun, 29 Sep 2024 22:23:39 +0200 Subject: [PATCH 3/7] added a switch-function --- .DS_Store | Bin 0 -> 6148 bytes assets/.DS_Store | Bin 0 -> 6148 bytes assets/design-2/Clouds.png | Bin 0 -> 9170 bytes assets/design-2/Moon.png | Bin 0 -> 8102 bytes assets/design-2/broken-clouds.png | Bin 0 -> 8571 bytes assets/design-2/rain.png | Bin 0 -> 2140 bytes assets/design-2/sun-100.png | Bin 0 -> 1336 bytes assets/design-2/sun.png | Bin 0 -> 9055 bytes index.html | 23 +++- kladd | 0 script.js | 127 ++++++++++++------ style.css | 207 ++++++++++++++++++++---------- 12 files changed, 246 insertions(+), 111 deletions(-) create mode 100644 .DS_Store create mode 100644 assets/.DS_Store create mode 100644 assets/design-2/Clouds.png create mode 100644 assets/design-2/Moon.png create mode 100644 assets/design-2/broken-clouds.png create mode 100644 assets/design-2/rain.png create mode 100644 assets/design-2/sun-100.png create mode 100644 assets/design-2/sun.png delete mode 100644 kladd diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ee653b59c599f22dc852bd0968cf1cdb6c39732b GIT binary patch literal 6148 zcmeHK%Z}496uq7)Gs%n)U4WPkQY5xjX<-l`Hl=hHEZ9sCEC7|HiI_kdmn5a2s#3PV zKky4I`4fHz&b3{sY0H)wA>YV8e%xbUpEPz&M4~^9x1^CLlQ zk|>7Ds~1TY$yr}cv#3y9Uw1gJ;|`nG=kwd$mUn!7f6?;h_d0i5-kk^C#lm&2-Msbi zbof3UXYz{*ngq5dWtR;u;VTNYC4KbsES1??v@_>`63QroG@qzVXAo#i>B<%diNp=~ ztx9x7aSHh6G^G(RA&F56j4-BXjs0zneMA$mQanTOWBPzv3~q^fiP9MTDP9AL;2|;g3|1P|)`3i20e}rOD?^$8HZaFC*fUsZL=Q}8 zDo|5}xnc-SN4sbIdIl?vnoh!8K7^TBm>Y^vvtxWuxs&K=w7FHlDo|HoS67>S{-6B) z{$D5AnpMCm@Lwq)8UugO$CAw1y0JJuYdxelNNns^X;c(s<~UXbK8lZ!l%db#0%G*ien1qj%E5`#@4C-t$y!;|ND{ugpt>1$fm`dd|K?C6K?pM;*C$+ehj%f zilOVKC4nT61d>1!_z40$v(>5#*Q}F35=a8y1ayBWEUI;A=W1IAD@y^WBX*mytygB9 zQ$p*|&XprH@u^gwDv@G{PiKD#zdE#Y_34mEJ|tHDN?ycPXZ&LBklHotB#;F91T^=h zjrIJ$=U-+p$v2m*l0XvpuLNYYd|WR0b#b0{Ec&$fXVX bc+ocf>d?+rqiDZPr{+b#fMk^feu2OzpyW0a literal 0 HcmV?d00001 diff --git a/assets/design-2/Clouds.png b/assets/design-2/Clouds.png new file mode 100644 index 0000000000000000000000000000000000000000..d805d8427fcc75b9a34fbd550786e709b45b3645 GIT binary patch literal 9170 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 literal 0 HcmV?d00001 diff --git a/assets/design-2/Moon.png b/assets/design-2/Moon.png new file mode 100644 index 0000000000000000000000000000000000000000..e389df60fb36310f963d698f5644e40c05879693 GIT binary patch literal 8102 zcmX|mc|4R~^#9B>m_Zp!$U4TFHMdxJoN2xC2Mn{e=UfeUs{rDYHtI&3`oQt^G|*Qb(} zo^}WiI^lY^?6VH8+O(VgRo`y@9ttT?v$J!%OV?uW=0Rs?w>X;Rd%L`JqTp)Cjp}5k zjCre=hK}FhOwhrmWci09(CBae4Z&D75Ps1*KQ=N%wax`bhXFy-5lKAfn+@?*s-O5% z3JP8ckkhIWdnuH0DPMjC6~C9;TN)fXJMbLmFshOn4g_6+QOSNPOl+4={_IA{bKk$>jRl2N8=IhI$X>fa+WY())@|g0D&he$cetut-L!orNI0AAwNzi13e^ z{5u+NA*~$&Lr8VUgAo=OhH@Ultib_Gj6D2%x-sYre&?|)BZ=c7&9HTVE@hDehA9?? zB+YT|ZA>4sd|&Jpj{4~RWkMvP^Z7%5L~N`zlsnvk{Q>^%`_3Tl0P2%oEtr~NtQQt7 zbftcGJH>lXPcS9uj8})vx7*wDXMj_WB8ofOIZ~9!syrIg9m{39sh1eym;3pT;y_Sm z5saz7tmL2H`Nk~h$Fn)zm3@}XYP2Wra!_aCSn7I`+5RU1Z`?%*4y0z4)0&0_Fh^Z{ z{4U{Y{z=PuCE9>r=_`4dntt&#DmT5@^~3RzpVrM_+f|>2)8JM3cRSiM;R=IAyZuip z`1HCBF?GK9*dS;my8ZE}TN1rou+nQd2`=bjyXt?PIgTO*dC5*z(ih3^X-GCbmT#~6 z?L5N-PK19qp}pf^J-6=TboNrPtyJ8y0xa0DSQTZj#^7%)y;kM_-+wSJ=0bVtFRoRo zN1VFB0c~N0xzcK2&L;8^?We^Cg+Sn6FsKanC)9$$qLTerZ=yaTmZAdbk!`+dyXau& zGaJ)gcuWAw>)N7{cA3LP|KapLcUYSVQi9;Cw`fMA zk7u_(mE-~}97Nu7fm!EVR(x(aF6~y_IuK zw$fYT$9`LBIaUCeAO@DxuX~r$m2x5MMP7zcK+yz^{3P7i~@bA2Wr`aHs!{8+w>u-lGET6kSZGmQ|wC zzx00Tvy^lSL_5sTfj_~*g|O?GS8fLl9&O?>(}p3yx~HHdF7o&7pBL9Vt{9#^=@Ml}s1RHgk70+B1Y8QvD9w5Ieogm~{JKA| z%y%CI?G#$PZ7N&vd~yZzN{4C$ai#RIz{1Ta#)SO*=aZ+M&aYR6>J~Z)xfR4_p~OS$ z^0+XAQ!izlknv~qjROUsB=JQOwQTJ3{h8eizW6izz2&!HGh&O`)Ux@B(ZW~eZxz-s*HP4R3D@e4*3ZHQRgH568Txj_j^t-M;;!)+* zH;<0irX1&W+5{kofJ96=DmTk11uEzYtv`p&!i>wa)WzB-fOy09YKJzXR>WWI@Z^ZU4Q zoYjMZCZ;Dy5bib9iHp2GH_`UI-`q7kTFd`=`0E4^^rJX(wnl;f_6+&k^AYvo3DNrK zdC7+gErGI7yKc8GXU2l2CgKAb!}cUJIdQ$+;vI&f|$V+%M;iyUR;^4Jie!Ol!0T2DaDr|B+QBl zK4u>zh2QS?+NlMgtlRlu5HU8@&2mn0_U|-bW7X2`xL=BJ_!BVKz`K<(xV5?5&h5kD*43ZgQr}x0l znOpUgD+Z|tY1a4um~v>C6tD;XPrH5u_V}K{feYUR=>!0%7GkTA!|rr<2=%pnW(Ula zfsr9t-|7A|{iBa=b4dvX45?+W5XI^Y#ZSpR)A=Wh!fZIn!4z#qdOj1%iVYAvq98f? z51I%+lyBYzR)R)bSk-Nrk4~#~5=VC+&Hz+0Z$Sb_S1_gk`o_yg+)#rQJ2NHZ< zdr$}>PyDhIt+S|HefRGdm7zDe(lc?G%TSZlx!?rd%ZLDa2m+Rii6Eqw^7edAqFsyI zhbIDFn2kA4Fzu)kl1;1Rn72JfA`uceE0lP`s|I>L$Z1J`Z4e|E`a0QJeMgN#R^>fThB?T9mk0mZl)Tl%L}K#r_j|n*)~j>g)p_vhGduMx+4ald$Y7oqc3){G0fT^IfoWIx z?uUIT;3gPY3GmosC?1gCDDl3+VFT4$v!f3led%EUjC-G=PT2gk-{y!}e?DrocN&L; z)v%IX%~ze6pQinh+DjEVp!?UCG#5NB1Y4Cv_rQEbZ#zT5_VAh{=Z6gZ&$-{ag#2*r zmxbA&8YHn%0>M;-La)=h-4Y7cW{k9?g^MY3Z;{W*)&OkcH5-)`ZAYDS34Leudcl~) z0ycz8CprK0lzm&DV~9QV3g#=z8LC6kg)pJSN5_16o@(0!?Cp6D+=S6s9XQZJ2g{=p z@&_4Vtqm*?0XCp#%DRJDD4yk?E5!~%IrS~R2Sk*G^xW8U=RfyTmm&p8MTwsaZc8dm z`|~3@m1*!pEXLvAFoG7A)wL|N{K*Jc#|(gnN5TO@*gq`lKgW&|WIUV5?i3Cd+zQ+o z06)Rx{QA)sJWuC-y}AAd4}ub5&MBnqCuKK|I7H}z*fEqaNG__pNc;CrTGZjBz}S~9 z>oPr9lkuVz&3oue&?@==Au0R6Q8%}eN46gi1(8D|ta+i*>}?$A%H!+gtqUo_*JRVw zmh|tyfyEI;KZ(6!gG0HqdWkm>0fiJ2b;x)0>TC{f_fwY1yR&yU@ECJQ5X%0=(+s(X z^k!cf(On0eN;n%@-gblXKohM6wFLdAecz#%F_x&km4md2{N0}_MZN#Xiaz8Kl_1=z zsq!@QwpZUdL_h{;jK;{IfBa;xk^}?8)O6iGW~N^ElEzMFsm$p7f* z@7>=WAD94$H9@kYbNcFd*0NnPZP?0}aPkNVOf1nEY?NERW^3#^pDq{k0=Nxr79fHY zZ^`Gq;w@3Y+yIvYn!cHFS+IFN> z0|3whM`CT0hS!EAa|2I9k>grmy*i$tmFITL1GWh70)Ta&MF%-nXD+M5noK~1>a?p1 zi{`F5p96)UP5`I1HPn13N7Jf^M%(LvAbyCv-e(RqS)dF zgCYa8V~KNgDeb)N%D-mgugqKhV-O9dNOtn)fZMGzg~ZV4=o#y=KwiiwTd}B@qEaMW z%qd6(XT=HKU^mjYhz|C3?v^kahnlIwYtjC6Ff~25E>T0Cwd>RA-D*oTbWx{l8*q~i;75o(aYc5apowKeD%X9b_ifhE{yGu;P?pa;vtN*j}U0yjxC6-978#Svn5!kHGI_WsLT#-pZ@$zQH>r9n-Ky~ zP$$FSdgAtq)lI#)Jx?7zeC%0BHA^m(eTF7Gc)8-QNdCR2X7bTZAEu?cz0)b2;n{vxk_F@2}gb2F;d&}lswJwFbN4T+9(tn84PU3X8 zwq=3SQu*Rpwig&Z5pj+)oqnEsz9KS-PdyWBe&c+g-&pfQ8X5Ehn^Edk%RQ>S?tlviT73&ja91t5>#_%GQd#SA^7&{0j?iEkMI2Pr6pg( z<)3GvP1XxA?1=1WQy6ijGH91aOAlW&VtMfuH#k2u^$-;PV2azQ@`pWThuW5h?cYd8 z=vJbp= zPlZY*J5PCtdX290zIsZ`&|M8qx=_at$hQ6Ai8 zde1^Ap!{6SFB&G+31^%zt_Su<>cliU<4wmr?L z!@wmR%#SI5?GKwU5qhNhC^$2MXW{n4{==~8FXEpbylmvw6}p@mTRYYMw{i+a5-Q(is!+aDQxJcwYif}}Um%!Zm) z;>fQGQ?!E>^FOeqS*pDg{+A*#W1NCY<_r$6XLc@zB$nKN5fiO6m8mGH(TWo`0XRs;j)>w#o$|bU-GZ6c2W(pZ(zxOL8$T9f{htsJ-{9xP!1_%LbxI#y zl#eFvuzY8Fn8g)oeS+JAC&aQ1Ugw^7$Ds0(=r@g?$e?x2Pgv9Fsu>c)P8kPMWA(z_ zPrrRKpf8Ib*ys^jxHwRL`z(9mdpyr4|#iID$h|G9;ez$|?=-L%?nt>$-`9h5B6`^O!ztV;PxGM4F~EP+DA-3Fwpfq)M>kp$1B)m$Vg-Ze_7K1Bl`7jUTk*x(!Aic z@u+RJGn(~XlSGnx!5N*3`~JRy{u*VW?{_vg?=nOMa0$+fj7OUKCjbb1E_vbJrFVDe zJ9Mk-RKJD}yq&s=9&R_OK5($@$7K^4QJq5@?hHsIBuuCS}|t-ib5V$Qze&L2QcoAu9_1(JBfU4GCMQeVXH%Z|2RaN1J zziD@$xP~occI;VnOY0i}L~+DG5T0i@Z|Z6KUH<#X?=3Ua(YCzNhzaYs$3eN7ny3q$ zL$n8lj0aTVeECUjh($8#^OH|P0X3`o_tue8W*Z40ml^*y2J7k|loz$?TFix@t6}ja zX~I9?d2{XiVV4wclxn^1%2^y$Bu9KB9O<0gRO!>m>bjHvWokshBCYr5Uki!t?kpMf zGG4$>bNm|1h>9RgnsqT^o(&OQC%#xiJ(m@s)v6W1XADP%&cUw2)nu>(k%eP^=|bYL zkkX>h3+^f0tvUi=)uN%1tG5cr2$xhX?{A-lVC7uW54L|vzwGKw;2&+JnI%z+mJMVK zV~H+kSNEcAJoOQxLE3so^}6DMPort(pa_Sm?sTrzOIGx$Y#i*Gztrm1&DdUYMw3^D zJ<6-0;n?}Es$r~hI^Je*Y5velFj^oFOk+PNYfg9th7 zfa(3Z%Qfgq0dPS=X<_ov;SB@NP2BCn4W!;EMmVu<`)c{%595$3y4^;#OED>n^1yJ3CUhTtzQT zby$3#|7~_O)@?~EH%V(NXk#iXvsudt!|1gYn9jC zyx#JnI->9KpjYJ2tOa7@nK`2qEp|fZ0uv#BzLNHK#AuJ74`+5XD(e)z@>0U2AUWn_ zw{k2V;1zF;?j7_PZFvi^zhjozz@z(=W!#+Jyt7R*AU7%}fz- zVB2CYpqN4N{&ZqXVe@oa@8wS3>g1(aPmhfaE}a~!`RXF%?ho5&@NIB9aFna8)s=D9 z`$k@E?bW;Y7G=spJg^iCm~N(|kJ!FsM=vV{xtyj0suUQ^EqNuu94!_z)$$YhO1YI! z&n!CwF2COT^^7>(OQ#$y4JVzi1l*0!aE%$5085IEFnAPlWpLk>e6lbZ;Va`m+#MD5 zRP>nGk2=o?L9C_4-Xon+Fzcw;_x#=>sv4hBcR_<&%h=G%^Wtxys;GfN#$?-ft2=uI z?COukzCADYHJHbt^9;u!P+@0)O9Yz!di_AvF@b8nZiXLiS_@SLFLMJ`77#e=RIXW< zgn}ZJa5aVNyqGEG01lpp(b9_j6&hPlv1}Got4}m0j1$79_`NOxX`K+*gHt)9XbiiU z;-F*de_E7YWGdEO6{;@W5E1KM;FvV0t`K?Y6dUhi01V>CdSUF7*aq?FVAIgHN{_~P zc^T~jHX=cAVzBIc$3!p480}ky^tNfydw8Jr?t)5z$GS;0kpE4>se;2=F~ilVL}!5< z<-@hEI`Auh*o;WVv&4#vv)?|Y*d*r@kM z?@85+yQQM`+>?LUCua{CA{)DBn>MBtmtfFu@UzOR|z9c!(`Nla3H$ zd3RRt#vdvyX9)S_?h*NR1s=s5t8(BMYyB70{l9&fRag6`NaD{;yLls$cw%Jbk6B{M zQ*PLSE~SP?A?-|aTS2IY5^9?5cN5dyLXCIVfBhm>J>>zicFG&4%aK-pCvRnK`0+fT zet7CwEZyEfhYU>l1XbU9yn@pORNmBZM_qZ#)Mc^)zfl2!jIdMNpD}oFHr-y3D43Wu z5S<`c#$K7ZC%g3{EtXZ4z}HOJx5G1|?D3Dk_#!S2W6lE%@B4&UU2o7YStxfI%&Sl{WIWk;#&Y}G72MO=j{1Rge4-)pV% z2TBG*%>n$^ry)11W-KVyf%)hJ>WGorQThy;kCb7)?>y&Oq785=jRViv-gqS5t@NBs z&Juwsxl<(og;kMgaUQ_W46W_fxKAq_WmE@goP8=8saGe7W~dwPll^d`$ATg5b2a># zX;tRnpBSR0%ScdlDkq`ZbeypHel^reVC~4Cb30f>%p%|2l{>4#t1CU*&OL={Te7mJ z?6bL}fgay2YSXr#`iu#2cT&mN%PK4g;JZ~V!y<*sH5AQ=YTALoZ@Q?ydC_9D#wDl! zu-##-w(fUGy&>QL-xnk2+j*0XpUY*dA$w-xV?SI7BpwT8W@$Bl{5CFxjj(|%gvmSL z7V%tP1ej4aa2`OzPRMCwI2g+2KFg!0=Py+nO}Zc+ei%94OZ(I~TF_B)qTfAn&>nF=1)xipxi&SH6wGsE|ooT+*35Y4X<{%fc5h&J08V-f5nkDBJcd*{}u zQ$&`F-(Hs+QU79~sh409d%@1zLtK12g_Yb6y&L{FZtXnT)U(jD@yBiucE`%h_zh=9NYy{PDAmbldwPF5V6F)@Li#{4z zPk4d0$pT6~?8w|zb_Z51p{0f915X*HN;>mAADb-e#utjua)>cwO3hpZ-xTRDD{PnR zch`4n`O0dw%C2iRxEKCN?>tLU!t4I6W3RQu+br9>u~B$7{D}A1A{2!!a4UbO0ojJ5fF%bJQ!kd~gVp8?$0fEmeG}In|QxlcOw1 z&#R0C9LLIF6KbWc)XZ~*6qTmNxL@Bl*wp@JFlpxIb*Onpsk_Ae{ogU23ymHfn(03O PzL6UPb=o=|x48cSAJC(Z literal 0 HcmV?d00001 diff --git a/assets/design-2/broken-clouds.png b/assets/design-2/broken-clouds.png new file mode 100644 index 0000000000000000000000000000000000000000..5b207ffca6e5d798f9f7eed89bb5e56066faecc2 GIT binary patch literal 8571 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

-

Temp

-

location

-

condition

-

sunrise

-

sunset

+
+ sun + clouds-img + broken-clouds-img + rain-img +

Temp

+

location

+

condition

+
+
+

sunrise

+

sunset

+
+
+
-

forecast for the following 4 days

-
    forecast
+
    forecast
diff --git a/kladd b/kladd deleted file mode 100644 index e69de29bb..000000000 diff --git a/script.js b/script.js index 2a4a35985..652b2cca9 100644 --- a/script.js +++ b/script.js @@ -21,6 +21,12 @@ const temperature = document.getElementById("temp"); const weatherCondition = document.getElementById("condition"); const sunriseDisplay = document.getElementById("sunriseID"); const sunsetDisplay = document.getElementById("sunsetID"); +const forecast = document.getElementById("forecastID") +//DOM Selectors - Images +const sunImg = document.getElementById("sun"); +const cloudsImg = document.getElementById("cloudsImg"); +const rainImg = document.getElementById("rainImg"); +const brokenCloudsImg = document.getElementById("brokenCloudsImg"); //FUNCTIONS // Function to convert UNIX timestamp to readable time format @@ -35,6 +41,23 @@ const makeElementSunny = (element) => { element.classList.remove("weather-card") element.classList.add("weather-card-sunny") } + +// Function to format timestamp to date string (YYYY-MM-DD) +const formatDate = (timestamp) => { + const date = new Date(timestamp * 1000); + return date.toISOString().split('T')[0]; // Get only the date part +}; + +// Function to get day of the week from date string +const getDayOfWeek = (dateString) => { + const date = new Date(dateString); + const daysOfWeek = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; + return daysOfWeek[date.getDay()]; // Returns the day of the week +}; + +// Initialize an object to hold daily min and max temps +const dailyTemps = {}; + //Fetching data from the IPA for current weather fetch(URL) .then(response => response.json()) @@ -44,7 +67,7 @@ fetch(URL) const stockholm = data.name; const stockholmTemp = data.main.temp; const roundedTemp = Math.round(stockholmTemp); - const displayCondition = data.weather[0].description;; + const displayCondition = data.weather[0].description; //changing the innerHTML for city, temp and condition. weatherLocation.innerText = `${stockholm}`; @@ -56,42 +79,48 @@ fetch(URL) const sunriseTime = convertUnixToTime(data.sys.sunrise); const sunsetTime = convertUnixToTime(data.sys.sunset); - // Display sunrise and sunset times + // Display sunrise and sunset times in innerText sunriseDisplay.innerText = `Sunrise ${sunriseTime}`; - sunsetDisplay.innerText = `Sunset ${sunsetTime}`; - - // switch(displayCondition) { - // case "Clear": - // makeElementSunny(document.getElementById("--")) - // break - // case "Cloudy": - // ... - // break - // } - - // if (displayCondition == "Clear") { - // makeElementSunny(document.getElementById("--")) - // } else if() + sunsetDisplay.innerText = `Sunset ${sunsetTime}`; + + // Hide all images + sunImg.classList.add("hidden"); + cloudsImg.classList.add("hidden"); + rainImg.classList.add("hidden"); + brokenCloudsImg.classList.add("hidden"); + + //Change image if weahtercondition is sunny/cloudy etc + switch (true) { + case displayCondition.includes("clear"): + sunImg.classList.remove("hidden"); + sunImg.classList.add("visible"); + break; + case displayCondition.includes("cloudy"): + cloudsImg.classList.remove("hidden"); + cloudsImg.classList.add("visible"); + break; + case displayCondition.includes("rain"): + rainImg.classList.remove("hidden"); + rainImg.classList.add("visible"); + break; + case displayCondition.includes("broken clouds"): + brokenCloudsImg.classList.remove("hidden"); + brokenCloudsImg.classList.add("visible"); + break; + } }) - .catch(error => console.error('Error fetching data:', error)); + .catch(error => { + console.error('Error fetching weather data:', error); + forecast.innerHTML = "Unable to retrieve weather data."; + }); -//Fetching data from the forecastURL +// Fetching data from the forecastURL fetch(forecastURL) .then(response => response.json()) .then(data => { - console.log(data) - - - // Helper function to format timestamp to date string (YYYY-MM-DD) - const formatDate = (timestamp) => { - const date = new Date(timestamp * 1000); - return date.toISOString().split('T')[0]; // Get only the date part - }; - - // Initialize an object to hold daily min and max temps - const dailyTemps = {}; + console.log(data); // Iterate through the weather forecast data.list.forEach((forecast) => { @@ -109,19 +138,41 @@ fetch(forecastURL) } }); - // Extract the next four days' temperatures - const nextFourDays = Object.entries(dailyTemps).slice(0, 4).map(([date, temps]) => ({ - date, - min: temps.min, - max: temps.max, - })); - - console.log(nextFourDays); // Output the result + // Extract the next four days' temperatures and convert date to day name + const nextFourDays = Object.entries(dailyTemps) + .slice(0, 5) // Get the first four days + .map(([date, temps]) => ({ + date: getDayOfWeek(date), // Convert date to day name + min: temps.min, + max: temps.max, + })); + + // Render the forecast data in the browser + renderForecast(nextFourDays); }) .catch(error => { - console.error('Error fetching weather data:', error); // Handle errors + console.error('Error fetching forecast data:', error); + forecast.innerHTML = "Unable to retrieve forecast data."; }); +// Function to render forecast data in the browser +const renderForecast = (forecastData) => { + // Clear the existing forecast content + forecast.innerHTML = ""; + let forecastContent = ""; + + forecastData.forEach(day => { + forecastContent += + `
  • + ${day.date} + ${Math.round(day.min)}° / ${Math.round(day.max)}°C +
  • `; + }); + + // Set the forecast data to the innerHTML of the forecast container + forecast.innerHTML = forecastContent; +}; + diff --git a/style.css b/style.css index 783dbe091..f4b638c24 100644 --- a/style.css +++ b/style.css @@ -1,66 +1,141 @@ -body { - background-color: lightgray; - margin: 30px; - text-align: center; - font-family: "Roboto", sans-serif; - font-weight: 300; - font-style: normal; -} - -.weather-card { - width: 414px; - height: 896px; - margin: 0 auto; - box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.3); - display: flex; - flex-direction: column; - background-color: white; -} - -.weather-card-sunny { - width: 414px; - height: 896px; - margin: 0 auto; - box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.3); - display: flex; - flex-direction: column; - background-color: yellow; -} - -.location-card { - background: linear-gradient(90deg, #8589FF 0%, #E8E9FF 100%); - ; - width: 100%; - height: 50%; - color: white; -} - -.temp { - font-size: 120px; - display: inline-block; - position: relative; - line-height: 140.63px; - margin-top: 30px; - margin-bottom: 0; -} - -/* making the unit be positioned at the top of the temp-number */ -.temp-unit { - font-size: 40px; - display: inline-block; - bottom: 100%; - left: 0; - transform: translateY(-50px); - margin-left: 1px; -} - -/* Display sunrise and sunset on the same line */ -.sunrise-sunset { - display: inline; -} - -.forecast-card { - background-color: white; - width: 100%; - height: 50%; -} \ No newline at end of file + body { + margin: 30px; + font-family: "Roboto", sans-serif; + font-weight: 300; + font-style: normal; + } + + .weather-card { + width: 414px; + height: 896px; + margin: 0 auto; + box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.3); + display: flex; + flex-direction: column; + background-color: white; + } + + .location-card { + background: linear-gradient(90deg, #8589FF 0%, #E8E9FF 100%); + width: 100%; + height: 50%; + margin: 0; + color: white; + position: relative; + } + + /* background for rainy */ + .location-card-rainy { + background: linear-gradient(90deg, #7d7ea1 0%, #6264A2 100%); + } + + /* background for night */ + .location-card-night { + background: linear-gradient(270deg, #6264A2 50.98%, #222350 51.14%); + width: 100%; + height: 50%; + margin: 0; + color: white; + position: relative; + } + + .temp-container { + position: relative; + } + + /* Hides images if they are not called */ + .hidden { + display: none; + } + + /*Shows images when they are called */ + .visible { + position: absolute; + top: 65px; + right: 45px; + width: 40%; + } + + .temp { + font-size: 120px; + display: inline-block; + position: relative; + margin-top: 140px; + margin-bottom: 0; + margin-left: 35px; + margin-bottom: 0; + padding: 0; + } + + .temp-unit { + font-size: 40px; + display: inline-block; + bottom: 100%; + left: 0; + transform: translateY(-50px); + } + + .location { + position: absolute; + top: 235px; + margin-left: 40px; + font-size: 34px; + margin-bottom: 0; + } + + .condition { + position: absolute; + top: 290px; + margin-left: 40px; + font-size: 22px; + margin-bottom: 0; + } + + .suntime-container { + display: flex; + flex-direction: row; + align-items: center; + margin-top: 30px; + padding-right: 40px; + position: relative; + } + + .sunrise, + .sunset { + margin-top: 40px; + margin-left: 40px; + font-size: 22px; + } + + + .forecast-card { + background-color: white; + width: 100%; + height: 50%; + display: grid; + } + + .forecast { + display: grid; + grid-template-columns: repeat(1, 1fr); + padding: 10px; + margin-top: 10px; + list-style-type: none; + } + + #forecastID li { + background-color: #ededed; + height: 24px; + padding: 20px; + border-radius: 30px; + text-align: center; + font-size: 20px; + line-height: 23.44px; + } + + .forecast-item { + display: flex; + justify-content: space-around; + padding: 10px 0; + border-bottom: 1px solid #ccc; + } \ No newline at end of file From 1d9faba7da88cdfa21dd74c1065f20b34e6975d7 Mon Sep 17 00:00:00 2001 From: iamfannyhenriques Date: Mon, 30 Sep 2024 03:12:33 +0200 Subject: [PATCH 4/7] added switchfunction for nighttime and daytime --- README.md | 20 ++++++--- index.html | 9 ++-- script.js | 130 ++++++++++++++++++++++++++++++++++++++--------------- style.css | 71 +++++++++++++++++++++++++++-- 4 files changed, 183 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index f8b15f4cb..dd77ab172 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,22 @@ -# Weather App +Project: WeatherTheWeatherApp -Replace this readme with your own information about your project. - -Start by briefly describing the assignment in a sentence or two. Keep it short and to the point. +This project is a weahterApp that fetches data from an API and displays the current location, temp, weather condition, sunrise and sunset time. It also shows a forecast of today and the following 4 days. The app changes images and background depending on if the condition is clear, cloudy, rainy and if it is night or day. ## The problem -Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next? +The first challange was to fetch the data from the url. I used the console.log to solve this as it helped me se where the specific data was in the api. +The second challange was to convert the sunset and sunriseTime into "real numbers", i used convertUnixToTime, unixTimestamp, + +changing background and images to adapt to the weathercondition and daytime/nighttime. +This was very challenging, i used a "fetch"-condition to first initialise the different weatherconditions and hid or add the elements from html. To see if it worked i changed the weatherCondition = to "rain" "cloud" or "broken". +I then tried to get the current hour from the ipa, i was not successful unfortionatly but the time i got was pretty close to the current time so i used that. I then added if & else if statements to the "fetch" to make it check if it is daytime or nighttime. To see if i was successful i changed the "currentHour" to "14" and. + + +If i had more time i would: +- Create a helper-function that would include all the images and cards to make the fetch-function be shorter, as it is now a lot of redundant and repetetive code which makes it hard to follow and read. I believe this would fix that problem. +- Fetch and add symbols for each day of the forecast, depending on if the weather condition is cloudy, rainy or clear. +- I would adjust the styling so that it matches the figma-layout better. +- Make the app more responsive to both smaller and wider screens. ## View it live diff --git a/index.html b/index.html index ef5a586e6..5007b8c16 100644 --- a/index.html +++ b/index.html @@ -17,12 +17,13 @@
    -
    +
    sun - clouds-img - broken-clouds-img - rain-img + clouds-img + broken-clouds-img + rain-img + moon-img

    Temp

    location

    condition

    diff --git a/script.js b/script.js index 652b2cca9..2c6f9423a 100644 --- a/script.js +++ b/script.js @@ -5,16 +5,11 @@ const API_KEY = '1bd3fe8b6571a9e92c6d24232e62bdc8' const URL = `${BASE_URL}${API_KEY}` -console.log(URL) - //STEP 2: URL for Weather Forecast const FORECAST_URL = 'https://api.openweathermap.org/data/2.5/forecast?q=Stockholm,Sweden&units=metric&appid=' const forecastURL = `${FORECAST_URL}${API_KEY}` -console.log(forecastURL) - - // DOM Selectors const weatherLocation = document.getElementById("location"); const temperature = document.getElementById("temp"); @@ -22,13 +17,21 @@ const weatherCondition = document.getElementById("condition"); const sunriseDisplay = document.getElementById("sunriseID"); const sunsetDisplay = document.getElementById("sunsetID"); const forecast = document.getElementById("forecastID") +const locationCard = document.getElementById("locationCard") //DOM Selectors - Images const sunImg = document.getElementById("sun"); const cloudsImg = document.getElementById("cloudsImg"); const rainImg = document.getElementById("rainImg"); const brokenCloudsImg = document.getElementById("brokenCloudsImg"); +const moonImg = document.getElementById("moonImg") //FUNCTIONS +//Function to handle errors +const handleError = (errorMessage) => { + console.error('Error fetching data:', errorMessage); + forecast.innerHTML = "Unable to retrieve weather data."; +}; + // Function to convert UNIX timestamp to readable time format const convertUnixToTime = (unixTimestamp) => { const date = new Date(unixTimestamp * 1000); @@ -36,12 +39,6 @@ const convertUnixToTime = (unixTimestamp) => { return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); }; -//Function to make the background adapt to the weathercondition -const makeElementSunny = (element) => { - element.classList.remove("weather-card") - element.classList.add("weather-card-sunny") -} - // Function to format timestamp to date string (YYYY-MM-DD) const formatDate = (timestamp) => { const date = new Date(timestamp * 1000); @@ -52,7 +49,7 @@ const formatDate = (timestamp) => { const getDayOfWeek = (dateString) => { const date = new Date(dateString); const daysOfWeek = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; - return daysOfWeek[date.getDay()]; // Returns the day of the week + return daysOfWeek[date.getDay()]; }; // Initialize an object to hold daily min and max temps @@ -83,37 +80,103 @@ fetch(URL) sunriseDisplay.innerText = `Sunrise ${sunriseTime}`; sunsetDisplay.innerText = `Sunset ${sunsetTime}`; + //find the current time from the IPA + const timezoneOffset = 3600; + const apiTimestamp = 1727642907; + const localDate = new Date(apiTimestamp * 1000); + const localTimeInMilliseconds = localDate.getTime() + (timezoneOffset * 1000); + const localTime = new Date(localTimeInMilliseconds); + const formattedLocalTime = localTime.toLocaleTimeString('en-GB', { + hour: '2-digit', + minute: '2-digit', + hour12: false + }); + const currentHour = localTime.getHours(); + // Hide all images sunImg.classList.add("hidden"); cloudsImg.classList.add("hidden"); rainImg.classList.add("hidden"); brokenCloudsImg.classList.add("hidden"); + moonImg.classList.add("hidden"); - //Change image if weahtercondition is sunny/cloudy etc + // Change image & background if condition is sunny/cloudy and if the time is night/day switch (true) { case displayCondition.includes("clear"): - sunImg.classList.remove("hidden"); - sunImg.classList.add("visible"); + if (currentHour >= 6 && currentHour < 21) { + // Daytime clear weather + sunImg.classList.remove("hidden"); + sunImg.classList.add("visible"); + moonImg.classList.add("hidden"); + locationCard.classList.remove("location-card-night"); + locationCard.classList.add("location-card"); + } else { + // Nighttime clear weather + moonImg.classList.remove("hidden"); + moonImg.classList.add("visible"); + sunImg.classList.add("hidden"); + locationCard.classList.add("location-card-night"); + } break; - case displayCondition.includes("cloudy"): - cloudsImg.classList.remove("hidden"); - cloudsImg.classList.add("visible"); + + case displayCondition.includes("cloud"): + if (currentHour >= 6 && currentHour < 21) { + // Daytime cloudy weather + cloudsImg.classList.remove("hidden"); + cloudsImg.classList.add("visible"); + moonImg.classList.add("hidden"); + locationCard.classList.remove("location-card-night"); + locationCard.classList.add("location-card"); + } else { + // Nighttime cloudy weather + moonImg.classList.remove("hidden"); + moonImg.classList.add("visible"); + cloudsImg.classList.add("hidden"); + locationCard.classList.add("location-card-night"); + } break; + case displayCondition.includes("rain"): - rainImg.classList.remove("hidden"); - rainImg.classList.add("visible"); + if (currentHour >= 6 && currentHour < 21) { + // Daytime rainy weather + rainImg.classList.remove("hidden"); + rainImg.classList.add("visible"); + moonImg.classList.add("hidden"); + locationCard.classList.remove("location-card-night"); + locationCard.classList.add("location-card-rainy"); + } else { + // Nighttime rainy weather + moonImg.classList.remove("hidden"); + moonImg.classList.add("visible"); + rainImg.classList.add("hidden"); + locationCard.classList.add("location-card-night"); + } break; - case displayCondition.includes("broken clouds"): - brokenCloudsImg.classList.remove("hidden"); - brokenCloudsImg.classList.add("visible"); + + case displayCondition.includes("broken"): + if (currentHour >= 6 && currentHour < 21) { + // Daytime broken clouds + brokenCloudsImg.classList.remove("hidden"); + brokenCloudsImg.classList.add("visible"); + moonImg.classList.add("hidden"); + locationCard.classList.remove("location-card-night"); + locationCard.classList.add("location-card"); + } else { + // Nighttime broken clouds + moonImg.classList.remove("hidden"); + moonImg.classList.add("visible"); + brokenCloudsImg.classList.add("hidden"); + locationCard.classList.add("location-card-night"); + } break; + + default: + locationCard.classList.add("location-card"); + moonImg.classList.add("hidden"); } }) - .catch(error => { - console.error('Error fetching weather data:', error); - forecast.innerHTML = "Unable to retrieve weather data."; - }); + .catch(error => handleError(error)); // Fetching data from the forecastURL @@ -140,9 +203,10 @@ fetch(forecastURL) // Extract the next four days' temperatures and convert date to day name const nextFourDays = Object.entries(dailyTemps) - .slice(0, 5) // Get the first four days + //Getting the current day + the following 4 days + .slice(0, 5) .map(([date, temps]) => ({ - date: getDayOfWeek(date), // Convert date to day name + date: getDayOfWeek(date), min: temps.min, max: temps.max, })); @@ -150,14 +214,11 @@ fetch(forecastURL) // Render the forecast data in the browser renderForecast(nextFourDays); }) - .catch(error => { - console.error('Error fetching forecast data:', error); - forecast.innerHTML = "Unable to retrieve forecast data."; - }); + .catch(error => handleError(error)); + // Function to render forecast data in the browser const renderForecast = (forecastData) => { - // Clear the existing forecast content forecast.innerHTML = ""; let forecastContent = ""; @@ -169,7 +230,6 @@ const renderForecast = (forecastData) => { `; }); - // Set the forecast data to the innerHTML of the forecast container forecast.innerHTML = forecastContent; }; diff --git a/style.css b/style.css index f4b638c24..dbd8aebb7 100644 --- a/style.css +++ b/style.css @@ -26,12 +26,17 @@ /* background for rainy */ .location-card-rainy { - background: linear-gradient(90deg, #7d7ea1 0%, #6264A2 100%); + background: linear-gradient(90deg, #6264A2 0%, #9b9cc2 100%); + width: 100%; + height: 50%; + margin: 0; + color: white; + position: relative; } /* background for night */ .location-card-night { - background: linear-gradient(270deg, #6264A2 50.98%, #222350 51.14%); + background: linear-gradient(90deg, #222350 0%, #5a5c9b 100%); width: 100%; height: 50%; margin: 0; @@ -53,7 +58,7 @@ position: absolute; top: 65px; right: 45px; - width: 40%; + width: 35%; } .temp { @@ -138,4 +143,64 @@ justify-content: space-around; padding: 10px 0; border-bottom: 1px solid #ccc; + } + + /* Responsiveness */ + @media(max-width: 414px) { + body { + margin: 10px; + } + + .weather-card { + width: 95%; + height: 600px; + } + + .temp { + font-size: 80px; + margin-top: 70px; + } + + .temp-unit { + font-size: 30px; + transform: translateY(-35px); + } + + .visible { + top: 50px; + right: 30px; + width: 25%; + } + + .location { + top: 140px; + font-size: 22px; + } + + .condition { + top: 180px; + font-size: 17px; + } + + .suntime-container { + margin-top: 45px; + margin-left: 5px; + } + + .sunrise, + .sunset { + margin-top: 25px; + margin-left: 35px; + font-size: 13px; + } + + .forecast { + gap: 7px; + } + + #forecastID li { + height: 20px; + padding: 12px; + font-size: 15px; + } } \ No newline at end of file From 3883dd05572404ea1abefae83042815ba1e8fa6a Mon Sep 17 00:00:00 2001 From: iamfannyhenriques Date: Mon, 30 Sep 2024 03:28:48 +0200 Subject: [PATCH 5/7] updated readme --- README.md | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index dd77ab172..9baa71f2e 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,19 @@ -Project: WeatherTheWeatherApp +Project: WeatherTheWeatherApp -This project is a weahterApp that fetches data from an API and displays the current location, temp, weather condition, sunrise and sunset time. It also shows a forecast of today and the following 4 days. The app changes images and background depending on if the condition is clear, cloudy, rainy and if it is night or day. +WeatherTheWeatherApp is a weather application that retrieves and displays real-time data for Stockholm. It fetches and displays the current location, temperature, weather condition, sunrise, and sunset times. It shows the weather forecast for today and the next four days, including daily min and max temperatures. The app visually changes images and background styles based on whether it’s clear, cloudy, or rainy, and whether it’s day or night. -## The problem +Challenges Encountered +- The initial challenge involved successfully retrieving data from the OpenWeatherMap API. Utilizing console.log helped me identifying the structure of the API response. +- Converting UNIX timestamps for sunrise and sunset times into a readable format was a challenge, but resolved this using a the function, convertUnixToTime. +- I found implementing some sort of logic to change the background and images based on weather conditions and the time of day very complex. For this, I use a switch statement and various condition checks to ensure the app responded accurately to different weather scenarios/time of day. -The first challange was to fetch the data from the url. I used the console.log to solve this as it helped me se where the specific data was in the api. -The second challange was to convert the sunset and sunriseTime into "real numbers", i used convertUnixToTime, unixTimestamp, +If given more time, I would: -changing background and images to adapt to the weathercondition and daytime/nighttime. -This was very challenging, i used a "fetch"-condition to first initialise the different weatherconditions and hid or add the elements from html. To see if it worked i changed the weatherCondition = to "rain" "cloud" or "broken". -I then tried to get the current hour from the ipa, i was not successful unfortionatly but the time i got was pretty close to the current time so i used that. I then added if & else if statements to the "fetch" to make it check if it is daytime or nighttime. To see if i was successful i changed the "currentHour" to "14" and. - - -If i had more time i would: -- Create a helper-function that would include all the images and cards to make the fetch-function be shorter, as it is now a lot of redundant and repetetive code which makes it hard to follow and read. I believe this would fix that problem. -- Fetch and add symbols for each day of the forecast, depending on if the weather condition is cloudy, rainy or clear. -- I would adjust the styling so that it matches the figma-layout better. -- Make the app more responsive to both smaller and wider screens. +- Create a helper function to streamline the code that handles image and background changes, as it now includes a lot of redundancy and repetetive code. +- Implement weather condition icons for each day in the forecast. +- Refine the styling to better align with the Figma design layout. +- Enhance responsiveness for a wider range of screen sizes. ## View it live -Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about. +https://master--weathertheweatherapp.netlify.app \ No newline at end of file From 84b7c0737dce5e7d2d42e8b40efd8cdced494d5d Mon Sep 17 00:00:00 2001 From: iamfannyhenriques Date: Mon, 30 Sep 2024 14:29:07 +0200 Subject: [PATCH 6/7] changed currentHour logic --- script.js | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/script.js b/script.js index 2c6f9423a..9dedabdfe 100644 --- a/script.js +++ b/script.js @@ -80,18 +80,16 @@ fetch(URL) sunriseDisplay.innerText = `Sunrise ${sunriseTime}`; sunsetDisplay.innerText = `Sunset ${sunsetTime}`; - //find the current time from the IPA - const timezoneOffset = 3600; - const apiTimestamp = 1727642907; - const localDate = new Date(apiTimestamp * 1000); - const localTimeInMilliseconds = localDate.getTime() + (timezoneOffset * 1000); - const localTime = new Date(localTimeInMilliseconds); - const formattedLocalTime = localTime.toLocaleTimeString('en-GB', { - hour: '2-digit', - minute: '2-digit', - hour12: false - }); - const currentHour = localTime.getHours(); + // Create a new Date object + const date = new Date(); + + // Get the time offset for Stockholm (CET/CEST: Central European Time/ Central European Summer Time) + const options = { + timeZone: "Europe/Stockholm", + hour: "2-digit", + }; + + const stockholmTime = date.toLocaleTimeString("sv-SE", options); // Hide all images sunImg.classList.add("hidden"); @@ -103,7 +101,7 @@ fetch(URL) // Change image & background if condition is sunny/cloudy and if the time is night/day switch (true) { case displayCondition.includes("clear"): - if (currentHour >= 6 && currentHour < 21) { + if (stockholmTime >= 6 && stockholmTime < 21) { // Daytime clear weather sunImg.classList.remove("hidden"); sunImg.classList.add("visible"); @@ -120,7 +118,7 @@ fetch(URL) break; case displayCondition.includes("cloud"): - if (currentHour >= 6 && currentHour < 21) { + if (stockholmTime >= 6 && stockholmTime < 21) { // Daytime cloudy weather cloudsImg.classList.remove("hidden"); cloudsImg.classList.add("visible"); @@ -137,7 +135,7 @@ fetch(URL) break; case displayCondition.includes("rain"): - if (currentHour >= 6 && currentHour < 21) { + if (stockholmTime >= 6 && stockholmTime < 21) { // Daytime rainy weather rainImg.classList.remove("hidden"); rainImg.classList.add("visible"); @@ -154,7 +152,7 @@ fetch(URL) break; case displayCondition.includes("broken"): - if (currentHour >= 6 && currentHour < 21) { + if (stockholmTime >= 6 && stockholmTime < 21) { // Daytime broken clouds brokenCloudsImg.classList.remove("hidden"); brokenCloudsImg.classList.add("visible"); From d7e73d854562435936110bc1f5875c7303da1865 Mon Sep 17 00:00:00 2001 From: iamfannyhenriques Date: Wed, 9 Oct 2024 20:01:12 +0200 Subject: [PATCH 7/7] changed height --- .DS_Store | Bin 6148 -> 6148 bytes assets/.DS_Store | Bin 6148 -> 6148 bytes style.css | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.DS_Store b/.DS_Store index ee653b59c599f22dc852bd0968cf1cdb6c39732b..0b5ad9507441e40fd0cc949641a1180989f3efe3 100644 GIT binary patch delta 46 zcmZoMXffCj%)+>1atKQymqc~7v5~Qkf{F3ub1X89U6Wt4$TN0t=4SoPw3(gbFFycP CWe%?Z delta 45 zcmZoMXffCj%)+>RatKQyr+9U>k)e))iOJ;iEHaFpli#q&Gj?s}Vg1dtnT_KgKLAOM B4tW3o diff --git a/assets/.DS_Store b/assets/.DS_Store index 4ad1f9ce1e4d569f8a95be9498882537db0be8fd..e7457303cc09536bcd8051947f8d935c91e8a087 100644 GIT binary patch delta 65 zcmZoMXfc=|#>CJ*u~2NHo+2aD!~pBb1|lqz`56;7Z(|H(n|y%r_-1wveh#3T%^MlN VGf(ChF=S+zY{MhHIYwj!GXQrN64n3! delta 116 zcmZoMXfc=|#>B`mu~2NHo+2aj!~p9_j154#C)repA(J7QA)g_Sp_svfK^I7t0@=C@ zh71NksK-zMTPvOFbFU(Fv@Oxkj%E3or9kPXz0d|-