index.html 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>Lee Morgan</title>
  6. <link rel="stylesheet" href="/style">
  7. <link rel="icon" type="img/ico" href="/images/favicon">
  8. <link href='https://api.mapbox.com/mapbox-gl-js/v2.3.1/mapbox-gl.css' rel='stylesheet'>
  9. </head>
  10. <body>
  11. <div id="menu">
  12. <button id="aboutButton" class="active" content="about">
  13. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  14. <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
  15. <circle cx="12" cy="7" r="4"></circle>
  16. </svg>
  17. <p>About Me</p>
  18. </button>
  19. <button id="projectsButton" content="projects">
  20. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  21. <polyline points="16 18 22 12 16 6"></polyline>
  22. <polyline points="8 6 2 12 8 18"></polyline>
  23. </svg>
  24. <p>Projects</p>
  25. </button>
  26. <button id="blogButton" content="blog">
  27. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  28. <path d="M12 19l7-7 3 3-7 7-3-3z"></path>
  29. <path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"></path>
  30. <path d="M2 2l7.586 7.586"></path>
  31. <circle cx="11" cy="11" r="2"></circle>
  32. </svg>
  33. <p>Blog</p>
  34. </button>
  35. <button id="galleryButton" content="gallery">
  36. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  37. <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
  38. <circle cx="8.5" cy="8.5" r="1.5"></circle>
  39. <polyline points="21 15 16 10 5 21"></polyline>
  40. </svg>
  41. <p>Gallery</p>
  42. </button>
  43. <button id="currencyButton" content="currency">
  44. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  45. <line x1="12" y1="1" x2="12" y2="23"></line>
  46. <path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"></path>
  47. </svg>
  48. <p>Currency</p>
  49. </button>
  50. </div>
  51. <div id="mobileMenu">
  52. <svg id="openMobileMenu" stroke-width="1.5" viewBox="0 0 24 24" fill="none" color="#000000">
  53. <path d="M3 5h18M3 12h18M3 19h18" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
  54. </svg>
  55. </div>
  56. <div id="mobileMenuOptions" style="display:none">
  57. <svg id="closeMobileMenu" stroke-width="1.5" viewBox="0 0 24 24" fill="none" color="#000000">
  58. <path d="M6.758 17.243L12.001 12m5.243-5.243L12 12m0 0L6.758 6.757M12.001 12l5.243 5.243" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
  59. </svg>
  60. <a class="mobileChoice" href="/resume">
  61. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  62. <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path>
  63. <polyline points="13 2 13 9 20 9"></polyline>
  64. </svg>
  65. Resume
  66. </a>
  67. <a class="mobileChoice" href="https://github.com/MorganLee909">
  68. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  69. <path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
  70. </svg>
  71. GitHub
  72. </a>
  73. <a class="mobileChoice" href="https://www.linkedin.com/in/leemorganio">
  74. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  75. <path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"></path>
  76. <rect x="2" y="9" width="4" height="12"></rect>
  77. <circle cx="4" cy="4" r="2"></circle>
  78. </svg>
  79. LinkedIn
  80. </a>
  81. <button class="mobileChoice mobileMenuButton" content="about">
  82. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  83. <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
  84. <circle cx="12" cy="7" r="4"></circle>
  85. </svg>
  86. <p>About Me</p>
  87. </button>
  88. <button class="mobileChoice mobileMenuButton" content="projects">
  89. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  90. <polyline points="16 18 22 12 16 6"></polyline>
  91. <polyline points="8 6 2 12 8 18"></polyline>
  92. </svg>
  93. <p>Projects</p>
  94. </button>
  95. <button class="mobileChoice mobileMenuButton" content="blog">
  96. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  97. <path d="M12 19l7-7 3 3-7 7-3-3z"></path>
  98. <path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"></path>
  99. <path d="M2 2l7.586 7.586"></path>
  100. <circle cx="11" cy="11" r="2"></circle>
  101. </svg>
  102. <p>Blog</p>
  103. </button>
  104. <button class="mobileChoice mobileMenuButton" content="gallery">
  105. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  106. <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
  107. <circle cx="8.5" cy="8.5" r="1.5"></circle>
  108. <polyline points="21 15 16 10 5 21"></polyline>
  109. </svg>
  110. <p>Gallery</p>
  111. </button>
  112. <button class="mobileChoice mobileMenuButton" content="currency">
  113. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  114. <line x1="12" y1="1" x2="12" y2="23"></line>
  115. <path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"></path>
  116. </svg>
  117. <p>Currency</p>
  118. </button>
  119. </div>
  120. <div id="main">
  121. <div id="about">
  122. <div class="aboutCenter">
  123. <h1>Who Am I?</h1>
  124. <p>I am web developer based in South Carolina, though I am often traveling. My primary work is involved with creating and maintaining custom websites that require detailed solutions. I enjoy the process of creating custom solutions for websites, whether that be for clients that have a specific need for their websites or working on my own projects for fun.</p>
  125. <p>I also enjoy traveling to different places in the world to experience new places and cultures. One of my favorite hobbies is walking around new cities and photographing all of the beautiful locations that I can find. I try to split my time between resting and enjoying my hometown and going overseas to experience new places.</p>
  126. <p>Another passion of mine is simply learning new things. I greatly enjoy learning new languages, whether that is human or computer languages. Aside from traveling different place, I also try to split my free time between learning new programming tools/paradigms and learning languages. My current interests involve learning Rust as a programming language and Ukrainian as a human language.</p>
  127. </div>
  128. <div class="aboutRight">
  129. <a class="meLink" href="/resume">
  130. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  131. <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path>
  132. <polyline points="13 2 13 9 20 9"></polyline>
  133. </svg>
  134. Resume/CV
  135. </a>
  136. <a class="meLink" href="https://github.com/MorganLee909">
  137. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  138. <path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
  139. </svg>
  140. GitHub
  141. </a>
  142. <a class="meLink" href="https://www.linkedin.com/in/leemorganio">
  143. <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  144. <path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"></path>
  145. <rect x="2" y="9" width="4" height="12"></rect>
  146. <circle cx="4" cy="4" r="2"></circle>
  147. </svg>
  148. LinkedIn
  149. </a>
  150. </div>
  151. </div>
  152. <div id="projects" class="cardContainer" style="display:none">
  153. <a class="card" href="https://thesubline.com">
  154. <h2>The Subline</h2>
  155. <img src="/images/subline" alt="The Subline">
  156. <p>A web application to assist restaurant owners in managing their inventories. Providing insights into usage, waste and other details through the use of data.</p>
  157. </a>
  158. <a class="card" href="https://budgeteer.money">
  159. <h2>Budgeteer</h2>
  160. <img src="/images/budgeteer" alt="Budgeteer">
  161. <p>A simple web application to help people to budget their money in a simple and approachable manner.</p>
  162. </a>
  163. <a class="card" href="/sudoku">
  164. <h2>Sudoku Solver</h2>
  165. <img src="/images/sudoku" alt="Sudoku">
  166. <p>Stuck on a particularly difficult game of sudoku? Enter any sudoku puzzle and have it solved immediately.</p>
  167. </a>
  168. <a class="card" href="/birthdayparadox">
  169. <h2>The Birthday Paradox</h2>
  170. <img src="/images/birthday" alt="Birthday Hat">
  171. <p>A demonstration of the counterintuitive birthday paradox.</p>
  172. </a>
  173. <a class="card" href="https://blacklist.aero">
  174. <h2>Blacklist.aero</h2>
  175. <img src="/images/blacklist" alt="Blacklist.aero logo">
  176. <p>A site to enable airports to blacklist and check on the status of those who use their services.</p>
  177. </a>
  178. <a class="card" href="https://myvillage.market">
  179. <h2>MyVillage.market</h2>
  180. <img src="/images/myvillage-market" alt="Market with various vegetables"/>
  181. <p>A place for local vendors to display their products and users to search for vendors in their region.</p>
  182. </a>
  183. </div>
  184. <div id="blog" style="display:none;">
  185. <div id="blogTags" class="tagContainer"></div>
  186. <div id="blogs" class="cardContainer"></div>
  187. <template id="blogCard">
  188. <a class="card">
  189. <h1></h1>
  190. <img>
  191. </a>
  192. </template>
  193. </div>
  194. <div id="gallery" style="display:none">
  195. <div id="galleryTags" class="tagContainer"></div>
  196. <div id='map' style='width: 400px; height: 300px;'></div>
  197. </div>
  198. <div id="learn" class="cardContainer" style="display:none"></div>
  199. <div id="currency" style="display:none">
  200. <div id="locations"></div>
  201. <div id="currencyContainer"></div>
  202. <template id="currencyTemplate">
  203. <div class="currency">
  204. <h1 class="location"></h1>
  205. <p class="info"></p>
  206. <div class="currencyImages">
  207. <img class="frontImage">
  208. <img class="backImage">
  209. </div>
  210. <p class="comment"></p>
  211. </div>
  212. </template>
  213. </div>
  214. </div>
  215. <script>
  216. //GALLERY MAP
  217. let mapped = false;
  218. let mapPromise = new Promise((resolve, reject)=>{
  219. let script = document.createElement("script");
  220. script.src = "https://api.mapbox.com/mapbox-gl-js/v2.3.1/mapbox-gl.js";
  221. script.onload = resolve;
  222. document.getElementById("gallery").appendChild(script);
  223. });
  224. let mobileMenu = document.getElementById("mobileMenu");
  225. let mobileMenuOptions = document.getElementById("mobileMenuOptions");
  226. document.getElementById("openMobileMenu").onclick = ()=>{
  227. mobileMenu.style.display = "none";
  228. mobileMenuOptions.style.display = "flex";
  229. document.getElementById("closeMobileMenu").onclick = ()=>{
  230. mobileMenu.style.display = "flex";
  231. mobileMenuOptions.style.display = "none";
  232. }
  233. }
  234. let buttons = document.getElementById("menu").children;
  235. let mobileButtons = document.querySelectorAll(".mobileMenuButton");
  236. let content = document.getElementById("main").children;
  237. let navButtonFunctionality = (htmlCollection)=>{
  238. for(let i = 0; i < htmlCollection.length; i++){
  239. htmlCollection[i].onclick = ()=>{
  240. for(let j = 0; j < htmlCollection.length; j++){
  241. htmlCollection[j].classList.remove("active");
  242. }
  243. htmlCollection[i].classList.add("active");
  244. for(let j = 0; j < content.length; j++){
  245. content[j].style.display = "none";
  246. }
  247. if(htmlCollection[i].id === "galleryButton" && mapped === false){
  248. Promise.all([
  249. mapPromise,
  250. fetch("/gallery/retrieve").then(response => response.json())
  251. ])
  252. .then(loadGallery)
  253. .catch((err)=>{});
  254. mapped = true;
  255. }
  256. let string = htmlCollection[i].getAttribute("content");
  257. document.getElementById(string).style.display = "flex";
  258. document.getElementById("mobileMenuOptions").style.display = "none";
  259. document.getElementById("mobileMenu").style.display = "flex";
  260. };
  261. }
  262. }
  263. navButtonFunctionality(buttons);
  264. navButtonFunctionality(mobileButtons);
  265. let searchTags = (content, tag)=>{
  266. let galleryList = [];
  267. for(let i = 0; i < content.length; i++){
  268. for(let j = 0; j < content[i].tags.length; j++){
  269. if(content[i].tags[j].toLowerCase() === tag){
  270. galleryList.push(content[i]);
  271. break;
  272. }
  273. }
  274. }
  275. return galleryList;
  276. }
  277. //Get blog content
  278. let populateBlogs = (blogs)=>{
  279. let container = document.getElementById("blogs");
  280. let template = document.getElementById("blogCard").content.children[0];
  281. while(container.children.length > 0){
  282. container.removeChild(container.firstChild);
  283. }
  284. for(let i = 0; i < blogs.length; i++){
  285. let card = template.cloneNode(true);
  286. card.href = `/blog/${blogs[i]._id}`;
  287. card.children[0].innerText = blogs[i].title;
  288. card.children[1].src = blogs[i].thumbnail;
  289. card.children[1].alt = `${blogs[i].title} thumbnail`;
  290. container.appendChild(card);
  291. }
  292. }
  293. fetch("/blog/retrieve")
  294. .then(response => response.json())
  295. .then((response)=>{
  296. let tagContainer = document.getElementById("blogTags");
  297. let tags = [];
  298. let tag = document.createElement("button");
  299. tag.innerText = "All";
  300. tag.classList.add("tag");
  301. tag.onclick = ()=>{populateBlogs(response)};
  302. tagContainer.appendChild(tag);
  303. for(let i = 0; i < response.length; i++){
  304. for(let j = 0; j < response[i].tags.length; j++){
  305. if(tags.includes(response[i].tags[j].toLowerCase()) === true) continue;
  306. tags.push(response[i].tags[j].toLowerCase());
  307. let tag = document.createElement("button");
  308. tag.innerText = response[i].tags[j];
  309. tag.classList.add("tag");
  310. tag.onclick = ()=>{populateBlogs(searchTags(response, response[i].tags[j].toLowerCase()))};
  311. tagContainer.appendChild(tag);
  312. }
  313. }
  314. populateBlogs(response);
  315. })
  316. .catch((err)=>{});
  317. let loadGallery = (response)=>{
  318. let galleries = response[1].galleries;
  319. //MAP
  320. mapboxgl.accessToken = response[1].mapboxKey;
  321. let map = new mapboxgl.Map({
  322. container: 'map',
  323. style: 'mapbox://styles/mapbox/streets-v11',
  324. center: [-6.2764, 48.3623],
  325. zoom: 3
  326. });
  327. let mapDiv = document.getElementById("map");
  328. mapDiv.style.height = "90%";
  329. mapDiv.style.width = "90%";
  330. map.resize();
  331. //GALLERY DATA
  332. let tagContainer = document.getElementById("galleryTags");
  333. let tags = [];
  334. let tag = document.createElement("button");
  335. tag.innerText = "All";
  336. tag.classList.add("tag");
  337. tagContainer.appendChild(tag);
  338. for(let i = 0; i < galleries.length; i++){
  339. let tags = galleries[i].tags.toString();
  340. tags = tags.replaceAll(",", ", ");
  341. let popup = new mapboxgl.Popup()
  342. .on("open", ()=>{
  343. popup.setHTML(`
  344. <a class="galleryPopup" href="/gallery/${galleries[i]._id}">
  345. <h1>${galleries[i].title}</h1>
  346. <p>${tags}</p>
  347. <img class="popupImage" src="${galleries[i].images[0]}" alt="${galleries[i].title} image">
  348. </a>
  349. `)
  350. });
  351. let marker = new mapboxgl.Marker()
  352. .setLngLat([galleries[i].location.coordinates[1], galleries[i].location.coordinates[0]])
  353. .addTo(map)
  354. .setPopup(popup);
  355. for(let j = 0; j < galleries[i].tags.length; j++){
  356. if(tags.includes(galleries[i].tags[j]) === true) continue;
  357. tags.push(galleries[i].tags[j]);
  358. let tag = document.createElement("button");
  359. tag.innerText = galleries[i].tags[j];
  360. tag.classList.add("tag");
  361. tagContainer.appendChild(tag);
  362. }
  363. }
  364. }
  365. //Get "learn" content
  366. fetch("/learn/courses/json")
  367. .then(response => response.json())
  368. .then((response)=>{
  369. let container = document.getElementById("learn");
  370. for(let i = 0; i < response.length; i++){
  371. let card = document.createElement("a");
  372. card.classList.add("card");
  373. card.href = `/learn/courses/${response[i]._id}`;
  374. container.appendChild(card);
  375. let h2 = document.createElement("h2");
  376. h2.innerText = response[i].title;
  377. card.appendChild(h2);
  378. let img = document.createElement("img");
  379. img.src = response[i].thumbNail;
  380. img.alt = `${response[i].title} thumbnail`;
  381. card.appendChild(img);
  382. }
  383. })
  384. .catch((err)=>{});
  385. //Get currency data
  386. let displayImage = (image, cType)=>{
  387. let div = document.createElement("div");
  388. div.classList.add("fullImageBackground");
  389. div.onclick = ()=>{document.body.removeChild(div)};
  390. document.body.appendChild(div);
  391. image.className = "";
  392. image.style.margin = "auto";
  393. if(cType === "paper"){
  394. image.style.height = "";
  395. image.style.width = "100%";
  396. }else{
  397. image.style.width = "";
  398. image.style.height = "100%";
  399. }
  400. div.appendChild(image);
  401. }
  402. let imageSize = (image)=>{
  403. let width = `${image.clientWidth * 0.35}px`;
  404. image.style.height = `${image.clientHeight * 0.35}px`;
  405. image.style.width = width;
  406. }
  407. let filterLocations = (location, currencies)=>{
  408. let container = document.getElementById("currencyContainer");
  409. let template = document.getElementById("currencyTemplate").content.children[0];
  410. while(container.children.length > 0){
  411. container.removeChild(container.firstChild);
  412. }
  413. for(let i = 0; i < currencies.length; i++){
  414. if(currencies[i].location.toLowerCase() === location){
  415. let currency = template.cloneNode(true);
  416. let frontImage = currency.querySelector(".frontImage");
  417. let backImage = currency.querySelector(".backImage");
  418. let code = currencies[i].currencyCode;
  419. currency.querySelector(".location").innerText = `${currencies[i].location.toUpperCase()} (${currencies[i].name})`;
  420. currency.querySelector(".info").innerText = `${currencies[i].value} ${code ? code : ""}`;
  421. frontImage.src = currencies[i].frontImage;
  422. frontImage.onload = ()=>{imageSize(frontImage)};
  423. frontImage.onclick = ()=>{displayImage(frontImage.cloneNode(true), currencies[i].type)};
  424. backImage.src = currencies[i].backImage;
  425. backImage.onload = ()=>{imageSize(backImage)};
  426. backImage.onclick = ()=>{displayImage(backImage.cloneNode(true), currencies[i].type)};
  427. currency.querySelector(".comment").innerText = currencies[i].comment;
  428. container.appendChild(currency);
  429. }
  430. }
  431. }
  432. fetch("/currency/data")
  433. .then(r=>r.json())
  434. .then((response)=>{
  435. let locationsContainer = document.getElementById("locations");
  436. let locations = [];
  437. for(let i = 0; i < response.length; i++){
  438. if(!locations.includes(response[i].location.toLowerCase())){
  439. locations.push(response[i].location.toLowerCase());
  440. let button = document.createElement("button");
  441. button.classList.add("locationBtn");
  442. button.innerText = response[i].location.toUpperCase();
  443. button.onclick = ()=>{
  444. let btnLocations = document.querySelectorAll(".locationBtn");
  445. for(let j = 0; j < btnLocations.length; j++){
  446. btnLocations[j].classList.remove("curSelected");
  447. }
  448. button.classList.add("curSelected");
  449. filterLocations(response[i].location.toLowerCase(), response);
  450. }
  451. locationsContainer.appendChild(button);
  452. }
  453. }
  454. })
  455. .catch((err)=>{});
  456. </script>
  457. </body>
  458. </html>