From 6ae5f46165fa7871f24e848ca71de0c2a41e5b57 Mon Sep 17 00:00:00 2001 From: Grecia Osorio Date: Thu, 28 Aug 2025 13:35:27 -0500 Subject: [PATCH 1/4] Challenges 0-4 have been completed --- index.js | 65 ++++++++++++++++++++++++++++++++++++++++++------------- style.css | 5 +++++ 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/index.js b/index.js index 86fe7d438..8435234a6 100644 --- a/index.js +++ b/index.js @@ -10,6 +10,7 @@ import GAMES_DATA from './games.js'; // create a list of objects to store the data about the games using JSON.parse const GAMES_JSON = JSON.parse(GAMES_DATA) + // remove all child elements from a parent element in the DOM function deleteChildElements(parent) { while (parent.firstChild) { @@ -27,27 +28,40 @@ const gamesContainer = document.getElementById("games-container"); // create a function that adds all data from the games array to the page function addGamesToPage(games) { - // loop over each item in the data - - + //forEach goes over each value in the list of ojbects games + // game = one value in games + games.forEach(game => { // create a new div element, which will become the game card - - + // document.createElement - creates a new element in the document + const gameCard = document.createElement('div'); // add the class game-card to the list - - + gameCard.classList.add('game-card'); // set the inner HTML using a template literal to display some info // about each game - // TIP: if your images are not displaying, make sure there is space - // between the end of the src attribute and the end of the tag ("/>") - - + //call upon each key in the game value (game.key) to get their value + //back ticks so it reads the ${} + gameCard.innerHTML = ` + Game Image +
+

Name: ${game.name}

+

Description: ${game.description}

+

Pledged: ${game.pledged}

+

Goal: ${game.goal}

+

Backers: ${game.backers}

+
+ `; // append the game to the games-container + //this element is grabbed outside the function + gamesContainer.appendChild(gameCard) + }) + // TIP: if your images are not displaying, make sure there is space + // between the end of the src attribute and the end of the tag ("/>") } // call the function we just defined using the correct variable +addGamesToPage(GAMES_JSON) // later, we'll call this function using a different list of games @@ -61,19 +75,40 @@ function addGamesToPage(games) { const contributionsCard = document.getElementById("num-contributions"); // use reduce() to count the number of total contributions by summing the backers - +//call reduce on GAMES_JSON object +//acc = accumulator (fancy word for the total added) +//game = the object from GAMES_JSON (one at a time ladies) +//using dot notation to get the backers for each game and add them all +const contributions = GAMES_JSON.reduce((acc, game) => { + return acc + game.backers; +}, 0) +//check you get an accurate number, should be:19187 (counted them myself) +console.log(contributions) // set the inner HTML using a template literal and toLocaleString to get a number with commas - +const contribFormatted = contributions.toLocaleString('en-US') +contributionsCard.innerHTML = `${contribFormatted}` // grab the amount raised card, then use reduce() to find the total amount raised const raisedCard = document.getElementById("total-raised"); - +const raised = GAMES_JSON.reduce((acc, game) => { + return acc + game.pledged; +}, 0) +console.log(raised) // set inner HTML using template literal - +const raisedFormatted = raised.toLocaleString('en-US') +raisedCard.innerHTML = `$${raisedFormatted}` // grab number of games card and set its inner HTML const gamesCard = document.getElementById("num-games"); +const games = GAMES_JSON.reduce((acc, game) => { + return acc + 1 +}, 0) +console.log(games) + +const gamesFormatted = games.toLocaleString('en-US') +gamesCard.innerHTML = `${gamesFormatted}` + /************************************************************************************* diff --git a/style.css b/style.css index 11303c2a7..46465c406 100644 --- a/style.css +++ b/style.css @@ -21,6 +21,7 @@ body { .stats-container { display: flex; + align-items: center; } .stats-card { @@ -31,6 +32,10 @@ body { width: 100%; text-align: center; } +.stats-card:hover{ + cursor: pointer; + box-shadow: 0 0 30px lightblue; +} #num-contributions, #total-raised, #num-games { font-size: 50px; From 13b52779d452c03b9ad23cd64dbcd115934e4c80 Mon Sep 17 00:00:00 2001 From: Grecia Osorio Date: Thu, 28 Aug 2025 15:11:34 -0500 Subject: [PATCH 2/4] Challenges 5-7 are done!! Will work in bonus customizations now :) --- index.js | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/index.js b/index.js index 8435234a6..fe6545399 100644 --- a/index.js +++ b/index.js @@ -122,10 +122,9 @@ function filterUnfundedOnly() { deleteChildElements(gamesContainer); // use filter() to get a list of games that have not yet met their goal - - + const underFunded = GAMES_JSON.filter((game) => game.pledged < game.goal) // use the function we previously created to add the unfunded games to the DOM - + addGamesToPage(underFunded) } // show only games that are fully funded @@ -133,10 +132,10 @@ function filterFundedOnly() { deleteChildElements(gamesContainer); // use filter() to get a list of games that have met or exceeded their goal - + const funded = GAMES_JSON.filter((game) => game.pledged >= game.goal) // use the function we previously created to add unfunded games to the DOM - + addGamesToPage(funded) } // show all games @@ -144,6 +143,7 @@ function showAllGames() { deleteChildElements(gamesContainer); // add all games from the JSON data to the DOM + addGamesToPage(GAMES_JSON) } @@ -153,6 +153,9 @@ const fundedBtn = document.getElementById("funded-btn"); const allBtn = document.getElementById("all-btn"); // add event listeners with the correct functions to each button +unfundedBtn.addEventListener("click", filterUnfundedOnly) +fundedBtn.addEventListener("click", filterFundedOnly) +allBtn.addEventListener("click", showAllGames) /************************************************************************************* @@ -164,13 +167,18 @@ const allBtn = document.getElementById("all-btn"); const descriptionContainer = document.getElementById("description-container"); // use filter or reduce to count the number of unfunded games - - +const numUnderFunded = GAMES_JSON.filter((game) => game.pledged < game.goal).length +console.log(numUnderFunded) // create a string that explains the number of unfunded games using the ternary operator - +const message = `A total of $${raisedFormatted} has been raised for ${gamesFormatted} games. Currently, +${numUnderFunded != 0 ? + numUnderFunded + " games remain unfunded. We need your help to fund these amazing games!" + : " all games are funded!"}` // create a new DOM element containing the template string and append it to the description container - +const gameMsg = document.createElement('p') +gameMsg.innerHTML = message +descriptionContainer.appendChild(gameMsg) /************************************************************************************ * Challenge 7: Select & display the top 2 games * Skills used: spread operator, destructuring, template literals, sort @@ -184,7 +192,17 @@ const sortedGames = GAMES_JSON.sort( (item1, item2) => { }); // use destructuring and the spread operator to grab the first and second games - +let [game1, game2] = sortedGames +console.log([game1, game2]) // create a new element to hold the name of the top pledge game, then append it to the correct element - -// do the same for the runner up item \ No newline at end of file +const mostFunded = game1.name +console.log(mostFunded) +const mFGame = document.createElement('p') +mFGame.innerHTML = mostFunded +firstGameContainer.appendChild(mFGame) +// do the same for the runner up item +const mostFunded2 = game2.name +console.log(mostFunded2) +const mFGame2 = document.createElement('p') +mFGame2.innerHTML = mostFunded2 +secondGameContainer.appendChild(mFGame2) \ No newline at end of file From 2a060743f95de4832b5be2578963f437c70eeda6 Mon Sep 17 00:00:00 2001 From: Grecia Osorio <146643148+GreciaOsorio@users.noreply.github.com> Date: Thu, 28 Aug 2025 15:22:11 -0500 Subject: [PATCH 3/4] Update README.md --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index a12177342..35eb44660 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,19 @@ -# WEB102 Prework - *Name of App Here* +# WEB102 Prework - *Sea Monster Crowdfunding* -Submitted by: **Your Name Here** +Submitted by: **Grecia Osorio** -**Name of your app** is a website for the company Sea Monster Crowdfunding that displays information about the games they have funded. +**Sea Monster Crowdfunding** is a website for the company Sea Monster Crowdfunding that displays information about the games they have funded. -Time spent: **X** hours spent in total +Time spent: **11** hours spent in total ## Required Features The following **required** functionality is completed: -* [ ] The introduction section explains the background of the company and how many games remain unfunded. -* [ ] The Stats section includes information about the total contributions and dollars raised as well as the top two most funded games. -* [ ] The Our Games section initially displays all games funded by Sea Monster Crowdfunding -* [ ] The Our Games section has three buttons that allow the user to display only unfunded games, only funded games, or all games. +* [x] The introduction section explains the background of the company and how many games remain unfunded. +* [x] The Stats section includes information about the total contributions and dollars raised as well as the top two most funded games. +* [x] The Our Games section initially displays all games funded by Sea Monster Crowdfunding +* [x] The Our Games section has three buttons that allow the user to display only unfunded games, only funded games, or all games. The following **optional** features are implemented: @@ -34,11 +34,11 @@ GIF created with ... ## Notes -Describe any challenges encountered while building the app. +This was a fun and challenging pre-work. I had taken a course for Web Development during college, I found it challenging and fast-paced. Unlike that course, this snipped of work walk me through my tasks in a fun and thoughful way, I retained everything in the challenges. However, one of the biggest setbacks for me was the refreshment of information I needed. I had not use React in many years and forgotten a lot of what you need, that goes for JavaScript as well. Out of everything my biggest struggle was remembering how to properly traverse through data and adding it to the DOM. Once I overcame that obstacle, everything else was a lot of fun! ## License - Copyright [yyyy] [name of copyright owner] + Copyright [2025] [Grecia Osorio] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 5112289f67b4340869124541c7e4d01c37dacbff Mon Sep 17 00:00:00 2001 From: Grecia Osorio Date: Fri, 29 Aug 2025 02:01:45 -0500 Subject: [PATCH 4/4] Functional navbar added to the website --- index.html | 22 +++++++++--- index.js | 84 +++++++++++++++++++++++++++++++++++++++++++- style.css | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 200 insertions(+), 6 deletions(-) diff --git a/index.html b/index.html index ba8123340..9fb6c1923 100644 --- a/index.html +++ b/index.html @@ -3,6 +3,8 @@ + + @@ -13,15 +15,27 @@

Sea Monster Crowdfunding

+ +
+ About Us + Stats + Our Games +
+ + +
+ +
+ -

Welcome to Sea Monster!

+

Welcome to Sea Monster!

The purpose of our company is to fund independent games. We've been in operation for 12 years.

-

Stats

-
+

Stats

+

Individual Contributions

@@ -48,7 +62,7 @@

🥈 Runner Up

-

Our Games

+

Our Games

Check out each of our games below!

diff --git a/index.js b/index.js index fe6545399..4c5768b7b 100644 --- a/index.js +++ b/index.js @@ -205,4 +205,86 @@ const mostFunded2 = game2.name console.log(mostFunded2) const mFGame2 = document.createElement('p') mFGame2.innerHTML = mostFunded2 -secondGameContainer.appendChild(mFGame2) \ No newline at end of file +secondGameContainer.appendChild(mFGame2) + +/************************************************************************************ + * Bonus: Add ons & UX/UI modified + */ +const searchInput = document.getElementById("search"); +const searchBtn = document.getElementById("search-btn"); + +function scrollToGamesSection() { + const gamesSection = document.getElementById('games'); + gamesSection.scrollIntoView({ behavior: 'smooth' }); +} + +function getMatchingGames(searchInput){ + const gameCards = document.querySelectorAll('.game-card'); + let matched = false; + + gameCards.forEach(game => { + const gameNameEl = game.querySelector('h4'); + + if(gameNameEl){ + const gameName = gameNameEl.textContent.toLowerCase(); + + if (gameName.includes(searchInput.toLowerCase())){ + matched = true; + game.classList.add('search-highlight'); + + setTimeout(()=>{ + game.classList.add('fade-out'); + setTimeout(()=>{ + game.classList.remove('search-highlight', 'fade-out'); + }, 300) + }, 3000) + } + } + + }); + return matched; +} + +function noResults(searchVal){ + alert(`We are sorry, we could not find "${searchVal}" among our game library. Make sure to be in the all games filter when searching.`) +} + +function executeSearch(){ + const searchVal = searchInput.value.trim(); + + if(!searchVal){ + alert('Nothing has been search for.'); + return; + } + + let foundInGames = false; + GAMES_JSON.forEach(game => { + if(game.name.toLowerCase().includes(searchVal.toLowerCase())){ + foundInGames = true; + } + }); + + if (foundInGames){ + scrollToGamesSection(); + setTimeout(()=> { + const matched = getMatchingGames(searchVal); + if(!matched){ + noResults(searchVal); + } + }, 500); + } else { + noResults(searchVal); + } + searchInput.value = ''; +} + +searchInput.addEventListener("keypress", (e) => { + if (e.key === "Enter"){ + executeSearch() + } +}); + +searchBtn.addEventListener("click", (e)=>{ + e.preventDefault(); + executeSearch(); +}); diff --git a/style.css b/style.css index 46465c406..39f59324d 100644 --- a/style.css +++ b/style.css @@ -1,8 +1,13 @@ @import url('https://fonts.googleapis.com/css2?family=Cabin:wght@400;500;600;700&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Hanken+Grotesk:ital,wght@0,100..900;1,100..900&display=swap'); + + + body { - font-family: 'Cabin'; + font-family: "Hanken Grotesk", sans-serif; background-color: #758190; + } #tentacles { @@ -10,6 +15,7 @@ body { } .header { + position: sticky; display: flex; background-color: lightblue; padding: 1%; @@ -19,6 +25,98 @@ body { margin-top: -10px; } +.topnav { + position: sticky; + top: 0; + z-index: 999; + display: flex; + align-items: center; + justify-content: space-between; + background-color: rgb(2, 60, 79); + padding: 1%; + margin-left: -10px; + margin-right: -10px; + margin-top: -10px; +} + +.topnav a { + display: block; + color: black; + text-align: center; + padding: 14px 16px; + text-decoration: none; + font-size: 17px; +} + +.topnav a:hover { + background-color: #ddd; + color: black; +} + +.topnav a.active { + background-color: #2196F3; + color: white; +} + +.topnav .search-container { + margin-left: auto; + background:rgba(181, 222, 236, 0.6); + width: 25%; + min-width: 25%; + padding: 5px 5px; + border-radius: 7px; + +} + +.search-container input{ + background: transparent; + flex: 1; + border: 0; + outline: none; + padding: 5px 70px 5px 10px; + font-size: 17px; + font-family: "Hanken Grotesk", sans-serif; +} +::placeholder{ + color:#FFFFFF; +} + +.search-container button { + border: 0; + background: transparent; + color: #FFFFFF; + border-radius: 7px; + padding: 6px 6px; + font-size: 17px; +} +.search-container button:hover{ + cursor: pointer; +} + +.search-highlight{ + background-color: #ffeb3b; + border: 2px solid #ff9800; + box-shadow: 0 4px 20px rgba(255, 152, 0, 0.4); + transform: scale(1.02); + transition: all 0.3s ease-in-out; + animation: pulse 1s ease-in-out 2; +} + +.fade-out{ + background-color: transparent; + border: 2px solid transparent; + box-shadow: none; + transform: scale(1); + transition: all 0.3s ease-in-out; +} + +@keyframes pulse{ + 0% {transform: scale(1.02);} + 50% {transform: scale(1.05);} + 100% {transform: scale(1.02);} +} + + .stats-container { display: flex; align-items: center;