DEV Community

Aishwarya Mali
Aishwarya Mali

Posted on

#JavaScriptmas 2023 Day 19 to 24

Welcome back! If you've been following along, we've already solved challenges of Days 1 to 18 in our journey. Now, buckle up as we dive into the last leg of this adventure of Days 19 to 24.

Day 19: Debug Jingle Words

Task

  • There are loads of problems in JS. Find them, and fix them!
function handleGuess(e) {
    e.preventDefault()
    let currentState = []
    let input = document.getElementById('user-input')
    let guess = input.value
    const guessArr = guess.split('')
    for (let i = 0; i < wordArr.length; i++) {
        if (guessArr[i] === wordArr[i]) {
            currentState.push(guessArr[i])
        } else {
            currentState.push("-")
        }
    }
    renderGuess(currentState)
    checkWin(guess)
    input.value = ''
}
Enter fullscreen mode Exit fullscreen mode

The problems causing the errors were:

  • The id of the input was incorrect.
  • Instead of using guess.split(' '), it was necessary to use guess.split('') to split the string into individual letters.
  • Implemented a for loop to iterate through each letter of both the guess and wordArr.
  • Finally, when a letter is matched, it is pushed; otherwise, ('-') is pushed.
function renderGuess(arr) {
    const wordHtml = arr.map((letter) => {
        let html = ""
        if (letter === "-") {
            html += `<span class="letter wrong">-</span>`
        } else {
            html += `<span class="letter correct">${letter}</span>`
        }
        return html
    })
    wordDisplay.innerHTML = wordHtml.join('')
}
Enter fullscreen mode Exit fullscreen mode

Visual clue indicating whether entered letter is correct

I have also updated the renderGuess function to provide users with a visual clue indicating whether the letter is correct or not.

Check my scrim here.

Day 20: Save Santa!

Task

  • Save Santa by removing the lions, tigers, bears, and other nefarious creatures from the deeply-nested array. Following is the input.
const dangerArray = [
    ["๐ŸŽ…", "๐Ÿ‘บ"],
    [
        ["๐ŸŽ…", "๐Ÿฆ"],
        ["๐Ÿ‘น", "๐ŸŽ…"]
    ],
    [
        [
            ["๐ŸŽ…", "๐Ÿป"],
            ["๐ŸงŒ", "๐ŸŽ…"]
        ],
        [
            ["๐Ÿฏ", "๐ŸŽ…"],
            ["๐ŸŽ…", "๐Ÿ˜ˆ"]
        ]
    ]
];
Enter fullscreen mode Exit fullscreen mode
function saveSanta(arr) {
    for(let i=0; i<arr.length; i++ ){
        if(Array.isArray(arr[i])){
            saveSanta(arr[i])
        }
        else{
            if(arr[i]!=="๐ŸŽ…"){
                arr.splice(i, 1)
            }
        }
    }
    return arr
}

console.log(saveSanta(dangerArray))
Enter fullscreen mode Exit fullscreen mode
  • First we iterate over the array and check if each item is an array.
  • If it is, a recursive call to the current function is made.
  • Otherwise, we check if the item is not Santa.
  • If it isn't, the item is sliced from the array.

Check my scrim here.

Day 21: Expanding Search Bar

Task

  • ๏ปฟSearch input: Takes upto 1/3 of the width of its container

  • When the user clicks into the search bar:

    • Input grows to entire width of its parent container with smooth transition
    • Shrinks back to original size when user clicks away
    • Blue border
    • Bonus: placeholder text is not visible when user clicks inside the search bar
<div class="container">
  <label for="search-field" class="visually-hidden">Search</label>
  <input type="search" 
    class="search-bar" 
    id="search-field"
    placeholder="Search..."/>
</div>
Enter fullscreen mode Exit fullscreen mode
html, body {
    margin: 0;
    padding: 0;
}

:root {
    --search-border: #bbb;
    --search-focus-border: #3a71ca;
}

.visually-hidden {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0,0,0,0) !important;
    white-space: nowrap !important;
    border: 0 !important;
}

.container{
    width: 80%;
    margin: 30px auto 0;
}

.search-bar{
    border: 1px solid var(--search-border);
    border-radius: 4px;
    padding: 8px;
    width: 30%;
    transition: width .2s linear;
}

.search-bar:focus{
    width: 100%;
    border-color: var(--search-focus-border);
}

.search-bar:focus::-webkit-input-placeholder {
    opacity: 0;
}

.search-bar:focus::-moz-placeholder {
   opacity: 0;
}

.search-bar:focus:-ms-input-placeholder {
    opacity: 0;
}

.search-bar:focus:-moz-placeholder {
   opacity: 0;
}
Enter fullscreen mode Exit fullscreen mode

The trick here is that we initially set the width of .search-bar to 30% of its parent container. When clicked, we utilize the :focus selector to dynamically adjust the width to 100%, employing a transition effect for a smooth visual transition. To hide the placeholder text, browser-specific placeholder selectors are used, and a style of opacity: 0; is applied.

Check my scrim here.

Day 22: Gift App

Task

  • Make it so that the data doesn't disappear on reload. Use localStorage.
let people = JSON.parse(localStorage.getItem("people")) || []

if(people) renderList(people)

addButtonEl.addEventListener("click", function() {
    let inputValue = inputFieldEl.value

    if (inputValue) {
        people.push(inputValue)
        localStorage.setItem("people", JSON.stringify(people))
        clearInputFieldEl()

        renderList(people)
    }
})

function appendPersonToPeopleListEl(person) {

    let newEl = document.createElement("li")

    newEl.textContent = person

    newEl.addEventListener("dblclick", function() {
        let index = people.indexOf(person)

        people.splice(index, 1)
        localStorage.setItem("people", JSON.stringify(people))
        img.src = "./images/gifts.webp"
        renderList(people)
    })

    peopleListEl.append(newEl)
}
Enter fullscreen mode Exit fullscreen mode
  • When a new person is added to our Gift App list, we use localStorage.setItem("people", JSON.stringify(people)) to store the people array with the key named "people" in localStorage. The stringify function is used to convert a JavaScript object (in this case, the people array) into a JSON-formatted string.
  • The object is similarly updated when a person is removed from the list.
  • Lastly, to retrieve the data, we use JSON.parse(localStorage.getItem("people")). The parse function is used to convert a JSON-formatted string back into a JavaScript object.

Check my scrim here.

Day 23: Toggle Switch

Task

  • On click, toggle switch moves from one side to another
  • Cursor becomes pointer
  • Match styles
  • No JavaScript
<div class="toggle-wrap">
  <label for="toggle">
    <input type="checkbox" id="toggle" class="toggle-input"></input>
    <div class="toggle-switch"></div>
  </label>
</div>
Enter fullscreen mode Exit fullscreen mode
#toggle{
    display: none;
}

.toggle-wrap{
    width: 80px;
    height: 40px;
    border: 2px solid var(--toggle-border);
    border-radius: 100px;
    background: var(--toggle-bg);
    display: flex;
    align-items: center;
}

label{
    width: 100%;
    cursor: pointer;
}

.toggle-switch{
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: var(--toggle-switch-bg);
    transition: transform 0.2s linear;
    backface-visibility: hidden;
}

.toggle-input:checked + .toggle-switch{
    transform: translateX(45px);
}

.toggle-input:not(:checked) + .toggle-switch{
    transform: translateX(5px); 
}
Enter fullscreen mode Exit fullscreen mode
  • Here, we hide the actual checkbox, but since we use the id and for attributes in both the label and input, we can determine whether it is checked or not.
  • We utilize the :checked selector and a combination selector to shift the slide to the right side.
  • To check if it is unchecked, we use :not() selector in combination with :checked and translate the position to its initial state.
  • The transition property is used to ensure a smooth animation.

Check my scrim here.

Day 24: Christmas Lights

Task

  • Make Christmas tree lights flash on and off every 800 milliseconds on a permanent loop.
  • Make the blue and red lights toggle on and off alternatively. So first the red lights come on, and then as they go off, the blue lights come on.
const blues = document.querySelectorAll('.blue');
const reds = document.querySelectorAll('.red');
let isRed = true;

function toggleLights() {
    if (isRed) {
        reds.forEach(redLight => {
            redLight.classList.add("lights-on");
        });
        blues.forEach(blueLight => {
            blueLight.classList.remove("lights-on");
        });
    } else {
        blues.forEach(blueLight => {
            blueLight.classList.add("lights-on");
        });
        reds.forEach(redLight => {
            redLight.classList.remove("lights-on");
        });
    }
    isRed = !isRed;
}

setInterval(toggleLights, 800);
Enter fullscreen mode Exit fullscreen mode
  • We use setInterval(toggleLights, 800); to call the toggleLights function every 800 milliseconds.
  • In the function, we check if isRed is true. If it is, we add the lights-on class to the red lights and remove it from the blue lights.
  • Otherwise, we add the lights-on class to the blue lights and remove it from the red lights.

Check my scrim here.

As we finish up the 24-day coding adventure of #JavaScriptmas, I can't help but smile thinking about how much fun it brought to my daily routine. Solving a new challenge each day became something I looked forward to, keeping me consistent and excited.

I want to say a big thank you to everyone who followed along and joined me in this coding journey. Your support and enthusiasm made it even better!

Thanks for being a part of it. Until next time, happy coding!

Top comments (0)