#JavaScriptmas 2023 Day 7 to 12
Tags: webdev, scrimba, javascript, javascriptmas
Published: 2023-12-13 12:50:31

Welcome back! If you've been following along, we've already solved challenges of [Days 1 to 6](https://dev.to/aishwaryamali24/javascriptmas-2023-day-1-6-3m15) in our journey. Now, buckle up as we dive headfirst into the next leg of this adventure Days 7 to 12. Let's start.

## Day 7: Xmas Present wishlist
### Task

- Add items to wishlist array.
- Iterate over the wishlist array.
- Display your wishlist on the page.
- Style the wishlist with CSS.

### Stretch Goals

- Provide a way to add / remove wishlist items.
- Make each array an object with item's name, description, and a link to where it can be purchased

```
const wishlist = [
  {
      name: "Books",
      description: "I love to read so need more books!",
      link: "https://www.amazon.in/"
  },
  {
      name: "Headphone",
      description: "Nirvanaa 751 ANC Wireless Headphone",
      link: "https://www.boat-lifestyle.com/products/nirvana-751-anc-headphone"
  }
];

function renderList(list){
    let listEl = ""
    list.map((list, index) =>{
        listEl += `
        <div class='wishlist-box'>
            <div>
                <h2><a href='${list.link}' target='_blank'>${list.name}</a></h2>
                <p>${list.description}</p>
            </div>
            <div class="delete" onclick="deleteWish(${index})">❌</div>
        </div>
        `
    })
    wishlistEl.innerHTML = listEl
}

renderList(wishlist)

addWishBtn.addEventListener('click', function(){
    if(!wishNameInput.value || !wishDescriptionInput.value || !wishLinkInput.value) return
    const newWish = {
        name: wishNameInput.value,
        description: wishDescriptionInput.value,
        link: wishLinkInput.value
    }
    wishlist.push(newWish)
    renderList(wishlist)
    wishNameInput.value = wishDescriptionInput.value = wishLinkInput.value = ""
})

function deleteWish(index){
    wishlist.splice(index, 1)
    renderList(wishlist)
}
```

- First, created an array of objects called `wishlist` and rendered this object using the [`map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) method on the UI.
- For the `Add Wish` button, first checked if there is a value in the inputs. If not, the process is terminated. If there is a value, added all the values to a new object and pushed this object to the `wishlist` array. Finally, cleared all the inputs.
- Lastly, for `deleteWish`, get the index of the item we wished to delete. Based on that index, use the splice method to remove that item from the array and update the UI.

Check my scrim [here](https://scrimba.com/scrim/cod2a468aa65a80482fb066c7).

## Day 8: Animated Progress Bar
#### HTML

```
<div class="progress-bar">
  <div class="progress-status"></div>
</div>
```
#### CSS

```
.progress-bar,
.progress-status {
  height: 30px;
  background: var(--progressbar-bg);
  border-radius: 50px;
  width: 100%;
}

.progress-bar {
  position: relative;
}

.progress-status {
  position: absolute;
  top: 0;
  animation: progress 5s infinite;
  animation-timing-function: linear;
  animation-fill-mode: forwards;
}

@keyframes progress {
  0% {
    width: 0%;
    background-color: var(--start);
  }
  50% {
    width: 50%;
    background-color: var(--middle);
  }
  100% {
    width: 100%;
    background-color: var(--finish);
  }
}
```

- First, positioned the `progress-status` div on the `progress-bar` using `position:absolute`.
- For the `progress-status`, applied animation: progress 5s infinite; to call the keyframe "progress" infinitely.
- In the keyframe, defined animations starting at 0%, reaching 50%, and finishing at 100%.
- To ensure smooth operation, used `animation-timing-function: linear`. Without this, the progress bar starts correctly but then slows down at 50% and restarts again after that.

Check my scrim [here](https://scrimba.com/scrim/coa414b5ebf7a881548916750).

## Day 9: AI Christmas E-card
### Task

- When a user hits submit, dialogModal should be hidden.
- Use the inputted text to generate an image for the e-card using an AI model. 
- Render the image to imageContainer.

```
formSubmit.addEventListener('submit', function(e){
    e.preventDefault()
    dialogModal.close();
    image.style.display = "none"
    loadingText.style.display = "block"
    if(!userInput.value) return
    
    query({"inputs": userInput.value}).then(async(response) => {
        const src = await blobToBase64(response)
        loadingText.style.display = "none"
        image.src = src
        image.style.display = "block"
    });
    
})

async function query(data) {
	const response = await fetch(
		"https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0",
		{
			headers: { Authorization: `Bearer ${process.env.HUGGING_FACE_API_KEY}` },
			method: "POST",
			body: JSON.stringify(data),
		}
	);
	const result = await response.blob();
	return result;
}


function blobToBase64(blob) {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = function () {
            const base64String = reader.result;
            resolve(base64String);
        };
        reader.onerror = function (error) {
            reject(error);
        };
        reader.readAsDataURL(blob);
    });
}
```

- I used [huggingface](https://huggingface.co/) for this challenge. You can find the documentation [here](https://huggingface.co/docs/huggingface.js/inference/README).
- When the form is submitted we use the given description as input to call the function that will return a blob of image. This blob is then converted to Base64 using the `blobToBase64` function.
- The function uses the `FileReader` object, which is part of the web platform's File API, to read the contents of the Blob.
- It sets up an onload event handler, which will be triggered when the reading operation is successfully completed.
- Inside the onload handler, it converts the read content to a Base64-encoded string and resolves the Promise with that string.
- If there is an error during the reading operation, the onerror event handler is triggered, and the Promise is rejected with the error.
- Finally, we append this image to UI.

Check my scrim [here](https://scrimba.com/scrim/co86a468cbb3a7184411c7859).

## Day 10: Rockin' Around
### Task

- Add code to make the youtube player play the new YouTube song

```
const player = document.getElementById("player")

function playSong(id) {
  const youtubeSrc = `https://www.youtube.com/embed/${id}?autoplay=1`
  player.src = youtubeSrc
}
```

- The code creates a URL for a YouTube video using a template literal. It takes a video ID and constructs a YouTube video URL with the format.
- At the end, assigned this URL to the player's src.

Check my scrim [here](https://scrimba.com/scrim/co3dc4558bb56f2ead0d5b196).

## Day 11: Flag Challenge
### Task

- Create Switzerland Flag in CSS

#### HTML

```
<div class="flag flag-swiss">
 <div class="cross cross1"></div>
 <div class="cross cross2"></div>
</div>
```
#### CSS

```
.flag{
    width: 300px;
    height: 300px;
    background: var(--red);
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    grid-template-rows: repeat(5, 1fr);
}

.cross{
    background: var(--white);
}

.cross1{
    grid-row: 2/5;
    grid-column: 3/4;
}

.cross2{
    grid-row: 3/4;
    grid-column: 2/5;
}
```
- I used [`grid`](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout)` for this challenge, defining the height and width of the div and setting its display property to grid.

![CSS Grid structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ahm7w6tozxlgz9tb9ika.png)
- The grid is defined with 5 rows and 5 columns, each set to  `1fr`
- Based on the image above, I have positioned `.cross1`, `.cross2` accordingly using `grid-row` and `grid-column`.

Check my scrim [here](https://scrimba.com/scrim/co5ed47048aef825733374126).

## Day 12: Santa's Gift Sorter
### Task

- Help santa by sorting the gifts array into alphabetical order and reverse alphabetical order.

~~~
const xmasGifts = ['guitar 🎸', 'skates ⛸️', 'bear 🧸', 'magnet 🧲', 'laptop 💻', 'games console 🎮', 'jewellery 💍', 'kite 🪁'];

const sortedAZ = [...xmasGifts].sort();
console.log('A-Z: ', sortedAZ);

const sortedZA = [...xmasGifts].sort().reverse();
console.log('Z-A: ', sortedZA);
~~~

- For sorting into alphabetical order, we have used [`sort()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) method
- For sorting in reverse alphabetical order, we have first used sort() and then used [`reverse()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse).

Check my scrim [here](https://scrimba.com/scrim/cof374ab4ae40ac0b01451586).

Would love to hear your thoughts. Stay tuned for the next iteration of this series.