master c92b0bc3a87f cached
159 files
176.5 KB
56.2k tokens
85 symbols
1 requests
Download .txt
Showing preview only (206K chars total). Download the full file or copy to clipboard to get everything.
Repository: bradtraversy/50projects50days
Branch: master
Commit: c92b0bc3a87f
Files: 159
Total size: 176.5 KB

Directory structure:
gitextract_82g65fro/

├── .gitignore
├── 3d-boxes-background/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── LICENSE
├── README.md
├── _project_starter_/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── animated-countdown/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── animated-navigation/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── auto-text-effect/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── background-slider/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── blurry-loading/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── button-ripple-effect/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── content-placeholder/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── custom-range-slider/
│   ├── .vscode/
│   │   └── settings.json
│   ├── index.html
│   ├── script.js
│   └── style.css
├── dad-jokes/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── double-click-heart/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── double-vertical-slider/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── drag-n-drop/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── drawing-app/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── drink-water/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── event-keycodes/
│   ├── dark-style.css
│   ├── index.html
│   └── script.js
├── expanding-cards/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── faq-collapse/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── feedback-ui-design/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── form-input-wave/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── github-profiles/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── good-cheap-fast/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── hidden-search/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── hoverboard/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── image-carousel/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── incrementing-counter/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── insect-catch-game/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── kinetic-loader/
│   ├── index.html
│   └── style.css
├── live-user-filter/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── mobile-tab-navigation/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── movie-app/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── netflix-mobile-navigation/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── notes-app/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── password-generator/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── password-strength-background/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── pokedex/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── progress-steps/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── quiz-app/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── random-choice-picker/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── random-image-generator/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── rotating-nav-animation/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── scroll-animation/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── simple-timer/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── sound-board/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── split-landing-page/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── sticky-navigation/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── testimonial-box-switcher/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── theme-clock/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── toast-notification/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── todo-list/
│   ├── index.html
│   ├── script.js
│   └── style.css
└── verify-account-ui/
    ├── index.html
    ├── script.js
    └── style.css

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.DS_Store

================================================
FILE: 3d-boxes-background/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css"
      integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog=="
      crossorigin="anonymous"
    />
    <link rel="stylesheet" href="style.css" />
    <title>3D Boxes Background</title>
  </head>
  <body>
    <button id="btn" class="magic">Magic 🎩</button>
    <div id="boxes" class="boxes big"></div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: 3d-boxes-background/script.js
================================================
const boxesContainer = document.getElementById('boxes')
const btn = document.getElementById('btn')

btn.addEventListener('click', () => boxesContainer.classList.toggle('big'))

function createBoxes() {
  for (let i = 0; i < 4; i++) {
    for (let j = 0; j < 4; j++) {
      const box = document.createElement('div')
      box.classList.add('box')
      box.style.backgroundPosition = `${-j * 125}px ${-i * 125}px`
      boxesContainer.appendChild(box)
    }
  }
}

createBoxes()


================================================
FILE: 3d-boxes-background/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: #fafafa;
  font-family: 'Roboto', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
}

.magic {
  background-color: #f9ca24;
  color: #fff;
  font-family: 'Poppins', sans-serif;
  border: 0;
  border-radius: 3px;
  font-size: 16px;
  padding: 12px 20px;
  cursor: pointer;
  position: fixed;
  top: 20px;
  letter-spacing: 1px;
  box-shadow: 0 3px rgba(249, 202, 36, 0.5);
  z-index: 100;
}

.magic:focus {
  outline: none;
}

.magic:active {
  box-shadow: none;
  transform: translateY(2px);
}

.boxes {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-around;
  height: 500px;
  width: 500px;
  position: relative;
  transition: 0.4s ease;
}

.boxes.big {
  width: 600px;
  height: 600px;
}

.boxes.big .box {
  transform: rotateZ(360deg);
}

.box {
  background-image: url('https://media.giphy.com/media/EZqwsBSPlvSda/giphy.gif');
  background-repeat: no-repeat;
  background-size: 500px 500px;
  position: relative;
  height: 125px;
  width: 125px;
  transition: 0.4s ease;
}

.box::after {
  content: '';
  background-color: #f6e58d;
  position: absolute;
  top: 8px;
  right: -15px;
  height: 100%;
  width: 15px;
  transform: skewY(45deg);
}

.box::before {
  content: '';
  background-color: #f9ca24;
  position: absolute;
  bottom: -15px;
  left: 8px;
  height: 15px;
  width: 100%;
  transform: skewX(45deg);
}


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2022 Brad Traversy

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# 50 Projects in 50 Days - HTML/CSS and JavaScript

This is the main repository for all of the projects in the course.

-   [Course Link](https://www.traversymedia.com/50-Projects-In-50-Days)


|  #  | Project                                                                                                                     | Live Demo                                                                         |
| :-: | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| 01  | [Expanding Cards](https://github.com/bradtraversy/50projects50days/tree/master/expanding-cards)                             | [Live Demo](https://50projects50days.com/projects/expanding-cards/)               |
| 02  | [Progress Steps](https://github.com/bradtraversy/50projects50days/tree/master/progress-steps)                               | [Live Demo](https://50projects50days.com/projects/progress-steps/)                |
| 03  | [Rotating Navigation Animation](https://github.com/bradtraversy/50projects50days/tree/master/rotating-nav-animation)                       | [Live Demo](https://50projects50days.com/projects/rotating-navigation-animation/) |
| 04  | [Hidden Search Widget](https://github.com/bradtraversy/50projects50days/tree/master/hidden-search)                          | [Live Demo](https://50projects50days.com/projects/hidden-search-widget/)          |
| 05  | [Blurry Loading](https://github.com/bradtraversy/50projects50days/tree/master/blurry-loading)                               | [Live Demo](https://50projects50days.com/projects/blurry-loading/)                |
| 06  | [Scroll Animation](https://github.com/bradtraversy/50projects50days/tree/master/scroll-animation)                           | [Live Demo](https://50projects50days.com/projects/scroll-animation/)              |
| 07  | [Split Landing Page](https://github.com/bradtraversy/50projects50days/tree/master/split-landing-page)                       | [Live Demo](https://50projects50days.com/projects/split-landing-page/)            |
| 08  | [Form Wave](https://github.com/bradtraversy/50projects50days/tree/master/form-input-wave)                                         | [Live Demo](https://50projects50days.com/projects/form-wave/)                     |
| 09  | [Sound Board](https://github.com/bradtraversy/50projects50days/tree/master/sound-board)                                     | [Live Demo](https://50projects50days.com/projects/sound-board/)                   |
| 10  | [Dad Jokes](https://github.com/bradtraversy/50projects50days/tree/master/dad-jokes)                                         | [Live Demo](https://50projects50days.com/projects/dad-jokes/)                     |
| 11  | [Event Keycodes](https://github.com/bradtraversy/50projects50days/tree/master/event-keycodes)                               | [Live Demo](https://50projects50days.com/projects/event-keycodes/)                |
| 12  | [Faq Collapse](https://github.com/bradtraversy/50projects50days/tree/master/faq-collapse)                                   | [Live Demo](https://50projects50days.com/projects/faq-collapse/)                  |
| 13  | [Random Choice Picker](https://github.com/bradtraversy/50projects50days/tree/master/random-choice-picker)                   | [Live Demo](https://50projects50days.com/projects/random-choice-picker/)          |
| 14  | [Animated Navigation](https://github.com/bradtraversy/50projects50days/tree/master/animated-navigation)                     | [Live Demo](https://50projects50days.com/projects/animated-navigation/)           |
| 15  | [Incrementing Counter](https://github.com/bradtraversy/50projects50days/tree/master/incrementing-counter)                   | [Live Demo](https://50projects50days.com/projects/incrementing-counter/)          |
| 16  | [Drink Water](https://github.com/bradtraversy/50projects50days/tree/master/drink-water)                                     | [Live Demo](https://50projects50days.com/projects/drink-water/)                   |
| 17  | [Movie App](https://github.com/bradtraversy/50projects50days/tree/master/movie-app)                                         | [Live Demo](https://50projects50days.com/projects/movie-app/)                     |
| 18  | [Background Slider](https://github.com/bradtraversy/50projects50days/tree/master/background-slider)                         | [Live Demo](https://50projects50days.com/projects/background-slider/)             |
| 19  | [Theme Clock](https://github.com/bradtraversy/50projects50days/tree/master/theme-clock)                                     | [Live Demo](https://50projects50days.com/projects/theme-clock/)                   |
| 20  | [Button Ripple Effect](https://github.com/bradtraversy/50projects50days/tree/master/button-ripple-effect)                   | [Live Demo](https://50projects50days.com/projects/button-ripple-effect/)          |
| 21  | [Drag N Drop](https://github.com/bradtraversy/50projects50days/tree/master/drag-n-drop)                                     | [Live Demo](https://50projects50days.com/projects/drag-n-drop/)                   |
| 22  | [Drawing App](https://github.com/bradtraversy/50projects50days/tree/master/drawing-app)                                     | [Live Demo](https://50projects50days.com/projects/drawing-app/)                   |
| 23  | [Kinetic Loader](https://github.com/bradtraversy/50projects50days/tree/master/kinetic-loader)                               | [Live Demo](https://50projects50days.com/projects/kinetic-loader/)                |
| 24  | [Content Placeholder](https://github.com/bradtraversy/50projects50days/tree/master/content-placeholder)                     | [Live Demo](https://50projects50days.com/projects/content-placeholder/)           |
| 25  | [Sticky Navbar](https://github.com/bradtraversy/50projects50days/tree/master/sticky-navigation)                                 | [Live Demo](https://50projects50days.com/projects/sticky-navbar/)                 |
| 26  | [Double Vertical Slider](https://github.com/bradtraversy/50projects50days/tree/master/double-vertical-slider)               | [Live Demo](https://50projects50days.com/projects/double-vertical-slider/)        |
| 27  | [Toast Notification](https://github.com/bradtraversy/50projects50days/tree/master/toast-notification)                       | [Live Demo](https://50projects50days.com/projects/toast-notification/)            |
| 28  | [Github Profiles](https://github.com/bradtraversy/50projects50days/tree/master/github-profiles)                             | [Live Demo](https://50projects50days.com/projects/github-profiles/)               |
| 29  | [Double Click Heart](https://github.com/bradtraversy/50projects50days/tree/master/double-click-heart)                       | [Live Demo](https://50projects50days.com/projects/double-click-heart/)            |
| 30  | [Auto Text Effect](https://github.com/bradtraversy/50projects50days/tree/master/auto-text-effect)                           | [Live Demo](https://50projects50days.com/projects/auto-text-effect/)              |
| 31  | [Password Generator](https://github.com/bradtraversy/50projects50days/tree/master/password-generator)                       | [Live Demo](https://50projects50days.com/projects/password-generator/)            |
| 32  | [Good Cheap Fast](https://github.com/bradtraversy/50projects50days/tree/master/good-cheap-fast)                             | [Live Demo](https://50projects50days.com/projects/good-cheap-fast/)               |
| 33  | [Notes App](https://github.com/bradtraversy/50projects50days/tree/master/notes-app)                                         | [Live Demo](https://50projects50days.com/projects/notes-app/)                     |
| 34  | [Animated Countdown](https://github.com/bradtraversy/50projects50days/tree/master/animated-countdown)                       | [Live Demo](https://50projects50days.com/projects/animated-countdown/)            |
| 35  | [Image Carousel](https://github.com/bradtraversy/50projects50days/tree/master/image-carousel)                               | [Live Demo](https://50projects50days.com/projects/image-carousel/)                |
| 36  | [Hoverboard](https://github.com/bradtraversy/50projects50days/tree/master/hoverboard)                                       | [Live Demo](https://50projects50days.com/projects/hoverboard/)                    |
| 37  | [Pokedex](https://github.com/bradtraversy/50projects50days/tree/master/pokedex)                                             | [Live Demo](https://50projects50days.com/projects/pokedex/)                       |
| 38  | [Mobile Tab Navigation](https://github.com/bradtraversy/50projects50days/tree/master/mobile-tab-navigation)                 | [Live Demo](https://50projects50days.com/projects/mobile-tab-navigation/)         |
| 39  | [Password Strength Background](https://github.com/bradtraversy/50projects50days/tree/master/password-strength-background)   | [Live Demo](https://50projects50days.com/projects/password-strength-background/)  |
| 40  | [3d Background Boxes](https://github.com/bradtraversy/50projects50days/tree/master/3d-boxes-background)                     | [Live Demo](https://50projects50days.com/projects/3d-background-boxes/)           |
| 41  | [Verify Account Ui](https://github.com/bradtraversy/50projects50days/tree/master/verify-account-ui)                         | [Live Demo](https://50projects50days.com/projects/verify-account-ui/)             |
| 42  | [Live User Filter](https://github.com/bradtraversy/50projects50days/tree/master/live-user-filter)                           | [Live Demo](https://50projects50days.com/projects/live-user-filter/)              |
| 43  | [Feedback Ui Design](https://github.com/bradtraversy/50projects50days/tree/master/feedback-ui-design)                       | [Live Demo](https://50projects50days.com/projects/feedback-ui-design/)            |
| 44  | [Custom Range Slider](https://github.com/bradtraversy/50projects50days/tree/master/custom-range-slider)                     | [Live Demo](https://50projects50days.com/projects/custom-range-slider/)           |
| 45  | [Netflix Mobile Navigation](https://github.com/bradtraversy/50projects50days/tree/master/netflix-mobile-navigation)         | [Live Demo](https://50projects50days.com/projects/netflix-mobile-navigation/)     |
| 46  | [Quiz App](https://github.com/bradtraversy/50projects50days/tree/master/quiz-app)                                           | [Live Demo](https://50projects50days.com/projects/quiz-app/)                      |
| 47  | [Testimonial Box Switcher](https://github.com/bradtraversy/50projects50days/tree/master/testimonial-box-switcher)           | [Live Demo](https://50projects50days.com/projects/testimonial-box-switcher/)      |
| 48  | [Random Image Feed](https://github.com/bradtraversy/50projects50days/tree/master/random-image-generator)                         | [Live Demo](https://50projects50days.com/projects/random-image-feed/)             |
| 49  | [Todo List](https://github.com/bradtraversy/50projects50days/tree/master/todo-list)                                         | [Live Demo](https://50projects50days.com/projects/todo-list/)                     |
| 50  | [Insect Catch Game](https://github.com/bradtraversy/50projects50days/tree/master/insect-catch-game)                         | [Live Demo](https://50projects50days.com/projects/insect-catch-game/)             |
| 51  | [Simple Timer](https://github.com/bradtraversy/50projects50days/tree/master/simple-timer)                                   | [Live Demo](https://50projects50days.com/projects/simple-timer/)             |

**NOTE ON PULL REQUESTS**: All of these projects are part of the course. While I do appreciate people trying to make some things prettier or adding new features, we are only accepting pull requests and looking at issues for bug fixes so that the code stays inline with the course

## License

The MIT License

Copyright (c) 2020-2021 Traversy Media https://traversymedia.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

🔹 Software Disclaimer 🔹

🛠️ Provided "As Is" – No guarantees, use at your own risk.
📜 No Warranty – No promises on performance or fitness for any purpose.
⚖️ No Liability – Authors aren't responsible for any damages or claims.
🔄 Use Freely – But at your own discretion and responsibility.

🚀 In short: Use it, but don’t blame us! 😃


================================================
FILE: _project_starter_/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>My Project</title>
  </head>
  <body>
    <h1>Project Starter</h1>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: _project_starter_/script.js
================================================



================================================
FILE: _project_starter_/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

* {
  box-sizing: border-box;
}

body {
  font-family: 'Roboto', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}


================================================
FILE: animated-countdown/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Animated Countdown</title>
  </head>
  <body>
    <div class="counter">
      <div class="nums">
        <span class="in">3</span>
        <span>2</span>
        <span>1</span>
        <span>0</span>
      </div>
      <h4>Get Ready</h4>
    </div>

    <div class="final">
      <h1>GO</h1>
      <button id="replay">
        <span>Replay</span>
      </button>
    </div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: animated-countdown/script.js
================================================
const nums = document.querySelectorAll('.nums span')
const counter = document.querySelector('.counter')
const finalMessage = document.querySelector('.final')
const replay = document.querySelector('#replay')

runAnimation()

function resetDOM() {
  counter.classList.remove('hide')
  finalMessage.classList.remove('show')

  nums.forEach((num) => {
    num.classList.value = ''
  })

  nums[0].classList.add('in')
}

function runAnimation() {
  nums.forEach((num, idx) => {
    const nextToLast = nums.length - 1

    num.addEventListener('animationend', (e) => {
      if (e.animationName === 'goIn' && idx !== nextToLast) {
        num.classList.remove('in')
        num.classList.add('out')
      } else if (e.animationName === 'goOut' && num.nextElementSibling) {
        num.nextElementSibling.classList.add('in')
      } else {
        counter.classList.add('hide')
        finalMessage.classList.add('show')
      }
    })
  })
}

replay.addEventListener('click', () => {
  resetDOM()
  runAnimation()
})


================================================
FILE: animated-countdown/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

* {
  box-sizing: border-box;
}

body {
  font-family: 'Roboto', sans-serif;
  margin: 0;
  height: 100vh;
  overflow: hidden;
}

h4 {
  font-size: 20px;
  margin: 5px;
  text-transform: uppercase;
}

.counter {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
}

.counter.hide {
  transform: translate(-50%, -50%) scale(0);
  animation: hide 0.2s ease-out;
}

@keyframes hide {
  0% {
    transform: translate(-50%, -50%) scale(1);
  }

  100% {
    transform: translate(-50%, -50%) scale(0);
  }
}

.final {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) scale(0);
  text-align: center;
}

.final.show {
  transform: translate(-50%, -50%) scale(1);
  animation: show 0.2s ease-out;
}

@keyframes show {
  0% {
    transform: translate(-50%, -50%) scale(0);
  }

  30% {
    transform: translate(-50%, -50%) scale(1.4);
  }

  100% {
    transform: translate(-50%, -50%) scale(1);
  }
}

.nums {
  color: #3498db;
  font-size: 50px;
  position: relative;
  overflow: hidden;
  width: 250px;
  height: 50px;
}

.nums span {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) rotate(120deg);
  transform-origin: bottom center;
}

.nums span.in {
  transform: translate(-50%, -50%) rotate(0deg);
  animation: goIn 0.5s ease-in-out;
}

.nums span.out {
  animation: goOut 0.5s ease-in-out;
}

@keyframes goIn {
  0% {
    transform: translate(-50%, -50%) rotate(120deg);
  }

  30% {
    transform: translate(-50%, -50%) rotate(-20deg);
  }

  60% {
    transform: translate(-50%, -50%) rotate(10deg);
  }

  100% {
    transform: translate(-50%, -50%) rotate(0deg);
  }
}

@keyframes goOut {
  0% {
    transform: translate(-50%, -50%) rotate(0deg);
  }

  60% {
    transform: translate(-50%, -50%) rotate(20deg);
  }

  100% {
    transform: translate(-50%, -50%) rotate(-120deg);
  }
}

#replay{
  background-color: #3498db;
  border-radius: 3px;
  border: none;
  color: aliceblue;
  padding: 5px;
  text-align: center;
  display: inline-block;
  cursor: pointer;
  transition: all 0.3s;
}

#replay span{
  cursor: pointer;
  display: inline-block;
  position: relative;
  transition: 0.3s;
}

#replay span:after{
  content: '\00bb';
  position: absolute;
  opacity: 0;
  top: 0;
  right: -20px;
  transition: 0.5s;
}

#replay:hover span{
  padding-right: 25px;
}

#replay:hover span:after{
  opacity: 1;
  right: 0;
}


================================================
FILE: animated-navigation/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Animated Navigation</title>
  </head>
  <body>
    <nav class="active" id="nav">
      <ul>
        <li><a href="#">Home</a></li>
        <li><a href="#">Works</a></li>
        <li><a href="#">About</a></li>
        <li><a href="#">Contact</a></li>
      </ul>
      <button class="icon" id="toggle">
        <div class="line line1"></div>
        <div class="line line2"></div>
      </button>
    </nav>
    <script src="script.js"></script>

    <!-- Dribbble link: https://dribbble.com/shots/2427219-Header-Navigation-Day-053-dailyui -->
  </body>
</html>


================================================
FILE: animated-navigation/script.js
================================================
const toggle = document.getElementById('toggle')
const nav = document.getElementById('nav')

toggle.addEventListener('click', () => nav.classList.toggle('active'))


================================================
FILE: animated-navigation/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: #eafbff;
  background-image: linear-gradient(
    to bottom,
    #eafbff 0%,
    #eafbff 50%,
    #5290f9 50%,
    #5290f9 100%
  );
  font-family: 'Muli', sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  margin: 0;
}

nav {
  background-color: #fff;
  padding: 20px;
  width: 80px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 3px;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
  transition: width 0.6s linear;
  overflow-x: hidden;
}

nav.active {
  width: 350px;
}

nav ul {
  display: flex;
  list-style-type: none;
  padding: 0;
  margin: 0;
  width: 0;
  transition: width 0.6s linear;
}

nav.active ul {
  width: 100%;
}

nav ul li {
  transform: rotateY(0deg);
  opacity: 0;
  transition: transform 0.6s linear, opacity 0.6s linear;
}

nav.active ul li {
  opacity: 1;
  transform: rotateY(360deg);
}

nav ul a {
  position: relative;
  color: #000;
  text-decoration: none;
  margin: 0 10px;
}

.icon {
  background-color: #fff;
  border: 0;
  cursor: pointer;
  padding: 0;
  position: relative;
  height: 30px;
  width: 30px;
}

.icon:focus {
  outline: 0;
}

.icon .line {
  background-color: #5290f9;
  height: 2px;
  width: 20px;
  position: absolute;
  top: 10px;
  left: 5px;
  transition: transform 0.6s linear;
}

.icon .line2 {
  top: auto;
  bottom: 10px;
}

nav.active .icon .line1 {
  transform: rotate(-765deg) translateY(5.5px);
}

nav.active .icon .line2 {
  transform: rotate(765deg) translateY(-5.5px);
}


================================================
FILE: auto-text-effect/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Auto Text Effect</title>
  </head>
  <body>
    <h1 id="text">Starting...</h1>

    <div>
      <label for="speed">Speed:</label>
      <input type="number" name="speed" id="speed" value="1" min="1" max="10" step="1">
    </div>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: auto-text-effect/script.js
================================================
const textEl = document.getElementById('text')
const speedEl = document.getElementById('speed')
const text = 'We Love Programming!'
let idx = 1
let speed = 300 / speedEl.value

writeText()

function writeText() {
    textEl.innerText = text.slice(0, idx)

    idx++

    if(idx > text.length) {
        idx = 1
    }

    setTimeout(writeText, speed)
}


speedEl.addEventListener('input', (e) => speed = 300 / e.target.value)

================================================
FILE: auto-text-effect/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: darksalmon;
  font-family: 'Roboto', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

div {
  position: absolute;
  bottom: 20px;
  background: rgba(0, 0, 0, 0.1);
  padding: 10px 20px;
  font-size: 18px;
}

input {
  width: 50px;
  padding: 5px;
  font-size: 18px;
  background-color: darksalmon;
  border: none;
  text-align: center;
}

input:focus {
  outline: none;
}


================================================
FILE: background-slider/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css"
      integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog=="
      crossorigin="anonymous"
    />
    <link rel="stylesheet" href="style.css" />
    <title>Background Slider</title>
  </head>
  <body>
    <div class="slider-container">
      <div
        class="slide active"
        style="
          background-image: url('https://images.unsplash.com/photo-1549880338-65ddcdfd017b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2100&q=80');
        "
      ></div>
      <div
        class="slide"
        style="
          background-image: url('https://images.unsplash.com/photo-1511593358241-7eea1f3c84e5?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1934&q=80');
        "
      ></div>

      <div
        class="slide"
        style="
          background-image: url('https://images.unsplash.com/photo-1495467033336-2effd8753d51?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2100&q=80');
        "
      ></div>

      <div
        class="slide"
        style="
          background-image: url('https://images.unsplash.com/photo-1522735338363-cc7313be0ae0?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2689&q=80');
        "
      ></div>

      <div
        class="slide"
        style="
          background-image: url('https://images.unsplash.com/photo-1559087867-ce4c91325525?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2100&q=80');
        "
      ></div>

      <button class="arrow left-arrow" id="left">
        <i class="fas fa-arrow-left"></i>
      </button>

      <button class="arrow right-arrow" id="right">
        <i class="fas fa-arrow-right"></i>
      </button>
    </div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: background-slider/script.js
================================================
const body = document.body
const slides = document.querySelectorAll('.slide')
const leftBtn = document.getElementById('left')
const rightBtn = document.getElementById('right')

let activeSlide = 0

rightBtn.addEventListener('click', () => {
  activeSlide++

  if (activeSlide > slides.length - 1) {
    activeSlide = 0
  }

  setBgToBody()
  setActiveSlide()
})

leftBtn.addEventListener('click', () => {
  activeSlide--

  if (activeSlide < 0) {
    activeSlide = slides.length - 1
  }

  setBgToBody()
  setActiveSlide()
})

setBgToBody()

function setBgToBody() {
  body.style.backgroundImage = slides[activeSlide].style.backgroundImage
}

function setActiveSlide() {
  slides.forEach((slide) => slide.classList.remove('active'))

  slides[activeSlide].classList.add('active')
}


================================================
FILE: background-slider/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

* {
  box-sizing: border-box;
}

body {
  font-family: 'Roboto', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
  background-position: center center;
  background-size: cover;
  transition: 0.4s;
}

body::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
  background-color: rgba(0, 0, 0, 0.7);
  z-index: -1;
}

.slider-container {
  box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
  height: 70vh;
  width: 70vw;
  position: relative;
  overflow: hidden;
}

.slide {
  opacity: 0;
  height: 100vh;
  width: 100vw;
  background-position: center center;
  background-size: cover;
  position: absolute;
  top: -15vh;
  left: -15vw;
  transition: 0.4s ease;
  z-index: 1;
}

.slide.active {
  opacity: 1;
}

.arrow {
  position: fixed;
  background-color: transparent;
  color: #fff;
  padding: 20px;
  font-size: 30px;
  border: 2px solid orange;
  top: 50%;
  transform: translateY(-50%);
  cursor: pointer;
}

.arrow:focus {
  outline: 0;
}

.left-arrow {
  left: calc(15vw - 65px);
}

.right-arrow {
  right: calc(15vw - 65px);
}


================================================
FILE: blurry-loading/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Blurry Loading</title>
  </head>
  <body>
    <section class="bg"></section>
    <div class="loading-text">0%</div>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: blurry-loading/script.js
================================================
const loadText = document.querySelector('.loading-text')
const bg = document.querySelector('.bg')

let load = 0

let int = setInterval(blurring, 30)

function blurring() {
  load++

  if (load > 99) {
    clearInterval(int)
  }

  loadText.innerText = `${load}%`
  loadText.style.opacity = scale(load, 0, 100, 1, 0)
  bg.style.filter = `blur(${scale(load, 0, 100, 30, 0)}px)`
}

// https://stackoverflow.com/questions/10756313/javascript-jquery-map-a-range-of-numbers-to-another-range-of-numbers
const scale = (num, in_min, in_max, out_min, out_max) => {
  return ((num - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min
}


================================================
FILE: blurry-loading/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Ubuntu');

* {
  box-sizing: border-box;
}

body {
  font-family: 'Ubuntu', sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.bg {
  background: url('https://images.unsplash.com/photo-1576161787924-01bb08dad4a4?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2104&q=80')
    no-repeat center center/cover;
  position: absolute;
  top: -30px;
  left: -30px;
  width: calc(100vw + 60px);
  height: calc(100vh + 60px);
  z-index: -1;
  filter: blur(0px);
}

.loading-text {
  font-size: 50px;
  color: #fff;
}


================================================
FILE: button-ripple-effect/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Button Ripple Effect</title>
  </head>
  <body>
    <button class="ripple">Click Me</button>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: button-ripple-effect/script.js
================================================
const buttons = document.querySelectorAll('.ripple')

buttons.forEach(button => {
    button.addEventListener('click', function (e) {
        const x = e.pageX
        const y = e.pageY

        const buttonTop = e.target.offsetTop
        const buttonLeft = e.target.offsetLeft

        const xInside = x - buttonLeft
        const yInside = y - buttonTop

        const circle = document.createElement('span')
        circle.classList.add('circle')
        circle.style.top = yInside + 'px'
        circle.style.left = xInside + 'px'

        this.appendChild(circle)

        setTimeout(() => circle.remove(), 500)
    })
})

================================================
FILE: button-ripple-effect/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: #000;
  font-family: 'Roboto', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

button {
  background-color: purple;
  color: #fff;
  border: 1px purple solid;
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: 2px;
  padding: 20px 30px;
  overflow: hidden;
  margin: 10px 0;
  position: relative;
}

button:focus {
  outline: none;
}

button .circle {
  position: absolute;
  background-color: #fff;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  transform: translate(-50%, -50%) scale(0);
  animation: scale 0.5s ease-out;
}

@keyframes scale {
  to {
    transform: translate(-50%, -50%) scale(3);
    opacity: 0;
  }
}


================================================
FILE: content-placeholder/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Content Placeholder</title>
  </head>
  <body>
    <div class="card">
      <div class="card-header animated-bg" id="header">&nbsp;</div>

      <div class="card-content">
        <h3 class="card-title animated-bg animated-bg-text" id="title">
          &nbsp;
        </h3>
        <p class="card-excerpt" id="excerpt">
          &nbsp;
          <span class="animated-bg animated-bg-text">&nbsp;</span>
          <span class="animated-bg animated-bg-text">&nbsp;</span>
          <span class="animated-bg animated-bg-text">&nbsp;</span>
        </p>
        <div class="author">
          <div class="profile-img animated-bg" id="profile_img">&nbsp;</div>
          <div class="author-info">
            <strong class="animated-bg animated-bg-text" id="name"
              >&nbsp;</strong
            >
            <small class="animated-bg animated-bg-text" id="date">&nbsp;</small>
          </div>
        </div>
      </div>
    </div>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: content-placeholder/script.js
================================================
const header = document.getElementById('header')
const title = document.getElementById('title')
const excerpt = document.getElementById('excerpt')
const profile_img = document.getElementById('profile_img')
const name = document.getElementById('name')
const date = document.getElementById('date')

const animated_bgs = document.querySelectorAll('.animated-bg')
const animated_bg_texts = document.querySelectorAll('.animated-bg-text')

setTimeout(getData, 2500)

function getData() {
  header.innerHTML =
    '<img src="https://images.unsplash.com/photo-1496181133206-80ce9b88a853?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2102&q=80" alt="" />'
  title.innerHTML = 'Lorem ipsum dolor sit amet'
  excerpt.innerHTML =
    'Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolore perferendis'
  profile_img.innerHTML =
    '<img src="https://randomuser.me/api/portraits/men/45.jpg" alt="" />'
  name.innerHTML = 'John Doe'
  date.innerHTML = 'Oct 08, 2020'

  animated_bgs.forEach((bg) => bg.classList.remove('animated-bg'))
  animated_bg_texts.forEach((bg) => bg.classList.remove('animated-bg-text'))
}


================================================
FILE: content-placeholder/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: #ecf0f1;
  font-family: 'Roboto', sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

img {
  max-width: 100%;
}

.card {
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  border-radius: 10px;
  overflow: hidden;
  width: 350px;
}

.card-header {
  height: 200px;
}

.card-header img {
  object-fit: cover;
  height: 100%;
  width: 100%;
}

.card-content {
  background-color: #fff;
  padding: 30px;
}

.card-title {
  height: 20px;
  margin: 0;
}

.card-excerpt {
  color: #777;
  margin: 10px 0 20px;
}

.author {
  display: flex;
}

.profile-img {
  border-radius: 50%;
  overflow: hidden;
  height: 40px;
  width: 40px;
}

.author-info {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  margin-left: 10px;
  width: 100px;
}

.author-info small {
  color: #aaa;
  margin-top: 5px;
}

.animated-bg {
  background-image: linear-gradient(
    to right,
    #f6f7f8 0%,
    #edeef1 10%,
    #f6f7f8 20%,
    #f6f7f8 100%
  );
  background-size: 200% 100%;
  animation: bgPos 1s linear infinite;
}

.animated-bg-text {
  border-radius: 50px;
  display: inline-block;
  margin: 0;
  height: 10px;
  width: 100%;
}

@keyframes bgPos {
  0% {
    background-position: 50% 0;
  }

  100% {
    background-position: -150% 0;
  }
}


================================================
FILE: custom-range-slider/.vscode/settings.json
================================================
{
    "liveServer.settings.port": 5501
}

================================================
FILE: custom-range-slider/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Custom Range Slider</title>
  </head>
  <body>
    <h2>Custom Range Slider</h2>
    <div class="range-container">
      <input type="range" id="range" min="0" max="100">
      <label for="range">50</label>
    </div>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: custom-range-slider/script.js
================================================
const range = document.getElementById('range')

range.addEventListener('input', (e) => {
    const value = +e.target.value
    const label = e.target.nextElementSibling

    const range_width = getComputedStyle(e.target).getPropertyValue('width')
    const label_width = getComputedStyle(label).getPropertyValue('width')

    const num_width = +range_width.substring(0, range_width.length - 2)
    const num_label_width = +label_width.substring(0, label_width.length - 2)

    const max = +e.target.max
    const min = +e.target.min

    const left = value * (num_width / max) - num_label_width / 2 + scale(value, min, max, 10, -10)

    label.style.left = `${left}px`


    label.innerHTML = value
})

// https://stackoverflow.com/questions/10756313/javascript-jquery-map-a-range-of-numbers-to-another-range-of-numbers
const scale = (num, in_min, in_max, out_min, out_max) => {
    return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
  }

================================================
FILE: custom-range-slider/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Lato&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-image: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
  font-family: 'Lato', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

h2 {
  position: absolute;
  top: 10px;
}

.range-container {
  position: relative;
}

input[type='range'] {
  width: 300px;
  margin: 18px 0;
  -webkit-appearance: none;
}

input[type='range']:focus {
  outline: none;
}

input[type='range'] + label {
  background-color: #fff;
  position: absolute;
  top: -25px;
  left: 110px;
  width: 80px;
  padding: 5px 0;
  text-align: center;
  border-radius: 4px;
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
}

/* Chrome & Safari */
input[type='range']::-webkit-slider-runnable-track {
  background: purple;
  border-radius: 4px;
  width: 100%;
  height: 10px;
  cursor: pointer;
}

input[type='range']::-webkit-slider-thumb {
  -webkit-appearance: none;
  height: 24px;
  width: 24px;
  background: #fff;
  border-radius: 50%;
  border: 1px solid purple;
  margin-top: -7px;
  cursor: pointer;
}

/* Firefox */
input[type='range']::-moz-range-track {
  background: purple;
  border-radius: 4px;
  width: 100%;
  height: 13px;
  cursor: pointer;
}

input[type='range']::-moz-range-thumb {
  -webkit-appearance: none;
  height: 24px;
  width: 24px;
  background: #fff;
  border-radius: 50%;
  border: 1px solid purple;
  margin-top: -7px;
  cursor: pointer;
}

/* IE */
input[type='range']::-ms-track {
  background: purple;
  border-radius: 4px;
  width: 100%;
  height: 13px;
  cursor: pointer;
}

input[type='range']::-ms-thumb {
  -webkit-appearance: none;
  height: 24px;
  width: 24px;
  background: #fff;
  border-radius: 50%;
  border: 1px solid purple;
  margin-top: -7px;
  cursor: pointer;
}


================================================
FILE: dad-jokes/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Dad Jokes</title>
  </head>
  <body>
    <div class="container">
      <h3>Don't Laugh Challenge</h3>
      <div id="joke" class="joke">// Joke goes here</div>
      <button id="jokeBtn" class="btn">Get Another Joke</button>
    </div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: dad-jokes/script.js
================================================
const jokeEl = document.getElementById('joke')
const jokeBtn = document.getElementById('jokeBtn')

jokeBtn.addEventListener('click', generateJoke)

generateJoke()

// USING ASYNC/AWAIT
async function generateJoke() {
  const config = {
    headers: {
      Accept: 'application/json',
    },
  }

  const res = await fetch('https://icanhazdadjoke.com', config)

  const data = await res.json()

  jokeEl.innerHTML = data.joke
}

// USING .then()
// function generateJoke() {
//   const config = {
//     headers: {
//       Accept: 'application/json',
//     },
//   }

//   fetch('https://icanhazdadjoke.com', config)
//     .then((res) => res.json())
//     .then((data) => {
//       jokeEl.innerHTML = data.joke
//     })
// }


================================================
FILE: dad-jokes/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: #686de0;
  font-family: 'Roboto', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
  padding: 20px;
}

.container {
  background-color: #fff;
  border-radius: 10px;
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1), 0 6px 6px rgba(0, 0, 0, 0.1);
  padding: 50px 20px;
  text-align: center;
  max-width: 100%;
  width: 800px;
}

h3 {
  margin: 0;
  opacity: 0.5;
  letter-spacing: 2px;
}

.joke {
  font-size: 30px;
  letter-spacing: 1px;
  line-height: 40px;
  margin: 50px auto;
  max-width: 600px;
}

.btn {
  background-color: #9f68e0;
  color: #fff;
  border: 0;
  border-radius: 10px;
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1), 0 6px 6px rgba(0, 0, 0, 0.1);
  padding: 14px 40px;
  font-size: 16px;
  cursor: pointer;
}

.btn:active {
  transform: scale(0.98);
}

.btn:focus {
  outline: 0;
}


================================================
FILE: double-click-heart/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog==" crossorigin="anonymous" />
    <link rel="stylesheet" href="style.css" />
    <title>Double Click Heart</title>
  </head>
  <body>
    <h3>Double click on the image to <i class="fas fa-heart"></i> it</h3>
    <small>You liked it <span id="times">0</span> times</small>

    <div class="loveMe"></div>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: double-click-heart/script.js
================================================
const loveMe = document.querySelector('.loveMe')
const times = document.querySelector('#times')

let clickTime = 0
let timesClicked = 0

loveMe.addEventListener('click', (e) => {
    if(clickTime === 0) {
        clickTime = new Date().getTime()
    } else {
        if((new Date().getTime() - clickTime) < 800) {
            createHeart(e)
            clickTime = 0
        } else {
            clickTime = new Date().getTime()
        }
    }
})

const createHeart = (e) => {
    const heart = document.createElement('i')
    heart.classList.add('fas')
    heart.classList.add('fa-heart')

    const x = e.clientX
    const y = e.clientY

    const leftOffset = e.target.offsetLeft
    const topOffset = e.target.offsetTop

    const xInside = x - leftOffset
    const yInside = y - topOffset

    heart.style.top = `${yInside}px`
    heart.style.left = `${xInside}px`

    loveMe.appendChild(heart)

    times.innerHTML = ++timesClicked

    setTimeout(() => heart.remove(), 1000)
}

================================================
FILE: double-click-heart/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Oswald');

* {
  box-sizing: border-box;
}

body {
  font-family: 'Oswald', sans-serif;
  text-align: center;
  overflow: hidden;
  margin: 0;
}

h3 {
  margin-bottom: 0;
  text-align: center;
}

small {
  display: block;
  margin-bottom: 20px;
  text-align: center;
}

.fa-heart {
  color: red;
}

.loveMe {
  height: 440px;
  width: 300px;
  background: url('https://images.unsplash.com/photo-1504215680853-026ed2a45def?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=334&q=80')
    no-repeat center center/cover;
  margin: auto;
  cursor: pointer;
  max-width: 100%;
  position: relative;
  box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);
  overflow: hidden;
}

.loveMe .fa-heart {
  position: absolute;
  animation: grow 0.6s linear;
  transform: translate(-50%, -50%) scale(0);
}

@keyframes grow {
  to {
    transform: translate(-50%, -50%) scale(10);
    opacity: 0;
  }
}


================================================
FILE: double-vertical-slider/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css" />
    <link rel="stylesheet" href="style.css" />
    <title>Vertical Slider</title>
  </head>
  <body>
    <div class="slider-container">
      <div class="left-slide">
        <div style="background-color: #FD3555">
          <h1>Nature flower</h1>
          <p>all in pink</p>
        </div>
        <div style="background-color: #2A86BA">
          <h1>Bluuue Sky</h1>
          <p>with it's mountains</p>
        </div>
        <div style="background-color: #252E33">
          <h1>Lonely castle</h1>
          <p>in the wilderness</p>
        </div>
        <div style="background-color: #FFB866">
          <h1>Flying eagle</h1>
          <p>in the sunset</p>
        </div>
      </div>
      <div class="right-slide">
        <div style="background-image: url('https://images.unsplash.com/photo-1508768787810-6adc1f613514?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=e27f6661df21ed17ab5355b28af8df4e&auto=format&fit=crop&w=1350&q=80')"></div>
        <div style="background-image: url('https://images.unsplash.com/photo-1519981593452-666cf05569a9?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=90ed8055f06493290dad8da9584a13f7&auto=format&fit=crop&w=715&q=80')"></div>
        <div style="background-image: url('https://images.unsplash.com/photo-1486899430790-61dbf6f6d98b?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=8ecdee5d1b3ed78ff16053b0227874a2&auto=format&fit=crop&w=1002&q=80')"></div>
        <div style="background-image: url('https://images.unsplash.com/photo-1510942201312-84e7962f6dbb?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=da4ca7a78004349f1b63f257e50e4360&auto=format&fit=crop&w=1050&q=80')"></div>
      </div>
      <div class="action-buttons">
        <button class="down-button">
          <i class="fas fa-arrow-down"></i>
        </button>
        <button class="up-button">
          <i class="fas fa-arrow-up"></i>
        </button>
      </div>
    </div>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: double-vertical-slider/script.js
================================================
const sliderContainer = document.querySelector('.slider-container')
const slideRight = document.querySelector('.right-slide')
const slideLeft = document.querySelector('.left-slide')
const upButton = document.querySelector('.up-button')
const downButton = document.querySelector('.down-button')
const slidesLength = slideRight.querySelectorAll('div').length

let activeSlideIndex = 0

slideLeft.style.top = `-${(slidesLength - 1) * 100}vh`

upButton.addEventListener('click', () => changeSlide('up'))
downButton.addEventListener('click', () => changeSlide('down'))

const changeSlide = (direction) => {
    const sliderHeight = sliderContainer.clientHeight
    if(direction === 'up') {
        activeSlideIndex++
        if(activeSlideIndex > slidesLength - 1) {
            activeSlideIndex = 0
        }
    } else if(direction === 'down') {
        activeSlideIndex--
        if(activeSlideIndex < 0) {
            activeSlideIndex = slidesLength - 1
        }
    }

    slideRight.style.transform = `translateY(-${activeSlideIndex * sliderHeight}px)`
    slideLeft.style.transform = `translateY(${activeSlideIndex * sliderHeight}px)`
}

================================================
FILE: double-vertical-slider/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Open+Sans');

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: 'Open Sans', sans-serif;
  height: 100vh;
}

.slider-container {
  position: relative;
  overflow: hidden;
  width: 100vw;
  height: 100vh;
}

.left-slide {
  height: 100%;
  width: 35%;
  position: absolute;
  top: 0;
  left: 0;
  transition: transform 0.5s ease-in-out;
}

.left-slide > div {
  height: 100%;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #fff;
}

.left-slide h1 {
  font-size: 40px;
  margin-bottom: 10px;
  margin-top: -30px;
}

.right-slide {
  height: 100%;
  position: absolute;
  top: 0;
  left: 35%;
  width: 65%;
  transition: transform 0.5s ease-in-out;
}

.right-slide > div {
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center center;
  height: 100%;
  width: 100%;
}

button {
  background-color: #fff;
  border: none;
  color: #aaa;
  cursor: pointer;
  font-size: 16px;
  padding: 15px;
}

button:hover {
  color: #222;
}

button:focus {
  outline: none;
}

.slider-container .action-buttons button {
  position: absolute;
  left: 35%;
  top: 50%;
  z-index: 100;
}

.slider-container .action-buttons .down-button {
  transform: translateX(-100%);
  border-top-left-radius: 5px;
  border-bottom-left-radius: 5px;
}

.slider-container .action-buttons .up-button {
  transform: translateY(-100%);
  border-top-right-radius: 5px;
  border-bottom-right-radius: 5px;
}


================================================
FILE: drag-n-drop/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Drag N Drop</title>
  </head>
  <body>
    <div class="empty">
      <div class="fill" draggable="true"></div>
    </div>
    <div class="empty"></div>
    <div class="empty"></div>
    <div class="empty"></div>
    <div class="empty"></div>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: drag-n-drop/script.js
================================================
const fill = document.querySelector('.fill')
const empties = document.querySelectorAll('.empty')
const body = document.body

body.addEventListener('dragstart', dragStart)
body.addEventListener('dragend', dragEnd)

for(const empty of empties) {
    empty.addEventListener('dragover', dragOver)
    empty.addEventListener('dragenter', dragEnter)
    empty.addEventListener('dragleave', dragLeave)
    empty.addEventListener('drop', dragDrop)
}

function dragStart(e) {
    if(!e.target.classList.contains("fill")) {
        e.preventDefault()
        return
    }
    fill.className += ' hold' 
    setTimeout(() => fill.className = 'invisible', 0)
}

function dragEnd() {
    fill.className = 'fill'
}

function dragOver(e) {
    e.preventDefault()
}

function dragEnter(e) {
    e.preventDefault()
    this.className += ' hovered'
}

function dragLeave() {
    this.className = 'empty'
}

function dragDrop() {
    this.className = 'empty'
    this.append(fill)
}

================================================
FILE: drag-n-drop/style.css
================================================
* {
  box-sizing: border-box;
}

body {
  background-color: steelblue;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.empty {
  height: 150px;
  width: 150px;
  margin: 10px;
  border: solid 3px black;
  background: white;
}

.fill {
  background-image: url('https://source.unsplash.com/random/150x150');
  height: 145px;
  width: 145px;
  cursor: pointer;
}

.hold {
  border: solid 5px #ccc;
}

.hovered {
  background-color: #333;
  border-color: white;
  border-style: dashed;
}

@media (max-width: 800px) {
  body {
    flex-direction: column;
  }
}


================================================
FILE: drawing-app/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Drawing App</title>
  </head>
  <body>
    <canvas id="canvas" width="800" height="700"></canvas>
    <div class="toolbox">
      <button id="decrease">-</button>
      <span id="size">10</span>
      <button id="increase">+</button>
      <input type="color" id="color">
      <button id="clear">X</button>
    </div>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: drawing-app/script.js
================================================
const canvas = document.getElementById('canvas');
const increaseBtn = document.getElementById('increase');
const decreaseBtn = document.getElementById('decrease');
const sizeEL = document.getElementById('size');
const colorEl = document.getElementById('color');
const clearEl = document.getElementById('clear');

const ctx = canvas.getContext('2d');

let size = 10
let isPressed = false
colorEl.value = 'black'
let color = colorEl.value
let x
let y

canvas.addEventListener('mousedown', (e) => {
    isPressed = true

    x = e.offsetX
    y = e.offsetY
})

document.addEventListener('mouseup', (e) => {
    isPressed = false

    x = undefined
    y = undefined
})

canvas.addEventListener('mousemove', (e) => {
    if(isPressed) {
        const x2 = e.offsetX
        const y2 = e.offsetY

        drawCircle(x2, y2)
        drawLine(x, y, x2, y2)

        x = x2
        y = y2
    }
})

function drawCircle(x, y) {
    ctx.beginPath();
    ctx.arc(x, y, size, 0, Math.PI * 2)
    ctx.fillStyle = color
    ctx.fill()
}

function drawLine(x1, y1, x2, y2) {
    ctx.beginPath()
    ctx.moveTo(x1, y1)
    ctx.lineTo(x2, y2)
    ctx.strokeStyle = color
    ctx.lineWidth = size * 2
    ctx.stroke()
}

function updateSizeOnScreen() {
    sizeEL.innerText = size
}

increaseBtn.addEventListener('click', () => {
    size += 5

    if(size > 50) {
        size = 50
    }

    updateSizeOnScreen()
})

decreaseBtn.addEventListener('click', () => {
    size -= 5

    if(size < 5) {
        size = 5
    }

    updateSizeOnScreen()
})

colorEl.addEventListener('change', (e) => color = e.target.value)

clearEl.addEventListener('click', () => ctx.clearRect(0,0, canvas.width, canvas.height))


================================================
FILE: drawing-app/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: #f5f5f5;
  font-family: 'Roboto', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  margin: 0;
}

canvas {
  border: 2px solid steelblue;
}

.toolbox {
  background-color: steelblue;
  border: 1px solid slateblue;
  display: flex;
  width: 804px;
  padding: 1rem;
}

.toolbox > * {
  background-color: #fff;
  border: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 2rem;
  height: 50px;
  width: 50px;
  margin: 0.25rem;
  padding: 0.25rem;
  cursor: pointer;
}

.toolbox > *:last-child {
  margin-left: auto;
}


================================================
FILE: drink-water/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Drink Water</title>
  </head>
  <body>
    <h1>Drink Water</h1>
    <h3>Goal: 2 Liters</h3>

    <div class="cup">
      <div class="remained" id="remained">
        <span id="liters"></span>
        <small>Remained</small>
      </div>

      <div class="percentage" id="percentage"></div>
    </div>

    <p class="text">Select how many glasses of water that you have drank</p>

    <div class="cups">
      <div class="cup cup-small">250 ml</div>
      <div class="cup cup-small">250 ml</div>
      <div class="cup cup-small">250 ml</div>
      <div class="cup cup-small">250 ml</div>
      <div class="cup cup-small">250 ml</div>
      <div class="cup cup-small">250 ml</div>
      <div class="cup cup-small">250 ml</div>
      <div class="cup cup-small">250 ml</div>
    </div>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: drink-water/script.js
================================================
const smallCups = document.querySelectorAll('.cup-small')
const liters = document.getElementById('liters')
const percentage = document.getElementById('percentage')
const remained = document.getElementById('remained')

updateBigCup()

smallCups.forEach((cup, idx) => {
    cup.addEventListener('click', () => highlightCups(idx))
})

function highlightCups(idx) {
    if (idx===7 && smallCups[idx].classList.contains("full")) idx--;
    else if(smallCups[idx].classList.contains('full') && !smallCups[idx].nextElementSibling.classList.contains('full')) {
        idx--
    }

    smallCups.forEach((cup, idx2) => {
        if(idx2 <= idx) {
            cup.classList.add('full')
        } else {
            cup.classList.remove('full')
        }
    })

    updateBigCup()
}

function updateBigCup() {
    const fullCups = document.querySelectorAll('.cup-small.full').length
    const totalCups = smallCups.length

    if(fullCups === 0) {
        percentage.style.visibility = 'hidden'
        percentage.style.height = 0
    } else {
        percentage.style.visibility = 'visible'
        percentage.style.height = `${fullCups / totalCups * 330}px`
        percentage.innerText = `${fullCups / totalCups * 100}%`
    }

    if(fullCups === totalCups) {
        remained.style.visibility = 'hidden'
        remained.style.height = 0
    } else {
        remained.style.visibility = 'visible'
        liters.innerText = `${2 - (250 * fullCups / 1000)}L`
    }
}


================================================
FILE: drink-water/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Montserrat:400,600&display=swap');

:root {
  --border-color: #144fc6;
  --fill-color: #6ab3f8;
}

* {
  box-sizing: border-box;
}

body {
  background-color: #3494e4;
  color: #fff;
  font-family: 'Montserrat', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-bottom: 40px;
}

h1 {
  margin: 10px 0 0;
}

h3 {
  font-weight: 400;
  margin: 10px 0;
}

.cup {
  background-color: #fff;
  border: 4px solid var(--border-color);
  color: var(--border-color);
  border-radius: 0 0 40px 40px;
  height: 330px;
  width: 150px;
  margin: 30px 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.cup.cup-small {
  height: 95px;
  width: 50px;
  border-radius: 0 0 15px 15px;
  background-color: rgba(255, 255, 255, 0.9);
  cursor: pointer;
  font-size: 14px;
  align-items: center;
  justify-content: center;
  text-align: center;
  margin: 5px;
  transition: 0.3s ease;
}

.cup.cup-small.full {
  background-color: var(--fill-color);
  color: #fff;
}

.cups {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  width: 280px;
}

.remained {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  flex: 1;
  transition: 0.3s ease;
}

.remained span {
  font-size: 20px;
  font-weight: bold;
}

.remained small {
  font-size: 12px;
}

.percentage {
  background-color: var(--fill-color);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  font-size: 30px;
  height: 0;
  transition: 0.3s ease;
}

.text {
  text-align: center;
  margin: 0 0 5px;
}


================================================
FILE: event-keycodes/dark-style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');

* {
  box-sizing: border-box;
 
}

body {
  background-color: #383838;
  font-family: 'Muli', sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.key {
  border: 1px solid #999999;
  background-color: #2B2B2B;
  box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
  display: inline-flex;
  align-items: center;
  font-size: 20px;
  font-weight: bold;
  padding: 20px;
  flex-direction: column;
  margin: 10px;
  min-width: 150px;
  color: white;
  position: relative;
}

.key small {
  position: absolute;
  top: -24px;
  left: 0;
  text-align: center;
  width: 100%;
  color: #c4c4c4;
  font-size: 14px;
}


================================================
FILE: event-keycodes/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Event KeyCodes</title>
  </head>
  <body>
    <div id="insert">
      <div class="key">
        Press any key to get the keyCode
      </div>
    </div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: event-keycodes/script.js
================================================
const insert = document.getElementById('insert')

window.addEventListener('keydown', (event) => {
  insert.innerHTML = `
  <div class="key">
  ${event.key === ' ' ? 'Space' : event.key} 
  <small>event.key</small>
</div>

<div class="key">
  ${event.keyCode}
  <small>event.keyCode</small>
</div>

<div class="key">
  ${event.code}
  <small>event.code</small>
</div>
  `
})

================================================
FILE: expanding-cards/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Expanding Cards</title>
  </head>
  <body>
    <div class="container">
      <div class="panel active" style="background-image: url('https://images.unsplash.com/photo-1558979158-65a1eaa08691?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80')">
        <h3>Explore The World</h3>
      </div>
      <div class="panel" style="background-image: url('https://images.unsplash.com/photo-1572276596237-5db2c3e16c5d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80')">
        <h3>Wild Forest</h3>
      </div>
      <div class="panel" style="background-image: url('https://images.unsplash.com/photo-1507525428034-b723cf961d3e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1353&q=80')">
        <h3>Sunny Beach</h3>
      </div>
      <div class="panel" style="background-image: url('https://images.unsplash.com/photo-1551009175-8a68da93d5f9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1351&q=80')">
        <h3>City on Winter</h3>
      </div>
      <div class="panel" style="background-image: url('https://images.unsplash.com/photo-1549880338-65ddcdfd017b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80')">
        <h3>Mountains - Clouds</h3>
      </div>

    </div>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: expanding-cards/script.js
================================================
const panels = document.querySelectorAll('.panel')

panels.forEach(panel => {
    panel.addEventListener('click', () => {
        removeActiveClasses()
        panel.classList.add('active')
    })
})

function removeActiveClasses() {
    panels.forEach(panel => {
        panel.classList.remove('active')
    })
}

================================================
FILE: expanding-cards/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');

* {
  box-sizing: border-box;
}

body {
  font-family: 'Muli', sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.container {
  display: flex;
  width: 90vw;
}

.panel {
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  height: 80vh;
  border-radius: 50px;
  color: #fff;
  cursor: pointer;
  flex: 0.5;
  margin: 10px;
  position: relative;
  -webkit-transition: all 700ms ease-in;
}

.panel h3 {
  font-size: 24px;
  position: absolute;
  bottom: 20px;
  left: 20px;
  margin: 0;
  opacity: 0;
}

.panel.active {
  flex: 5;
}

.panel.active h3 {
  opacity: 1;
  transition: opacity 0.3s ease-in 0.4s;
}

@media (max-width: 480px) {
  .container {
    width: 100vw;
  }

  .panel:nth-of-type(4),
  .panel:nth-of-type(5) {
    display: none;
  }
}


================================================
FILE: faq-collapse/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog==" crossorigin="anonymous" />
    <link rel="stylesheet" href="style.css" />
    <title>FAQ</title>
  </head>
  <body>
    <h1>Frequently Asked Questions</h1>
    <div class="faq-container">
      <div class="faq active">
        <h3 class="faq-title">
          Why shouldn't we trust atoms?
        </h3>

        <p class="faq-text">
          They make up everything
        </p>

        <button class="faq-toggle">
          <i class="fas fa-chevron-down"></i>
          <i class="fas fa-times"></i>
        </button>
      </div>

      <div class="faq">
        <h3 class="faq-title">
          What do you call someone with no body and no nose?
        </h3>
        <p class="faq-text">
          Nobody knows.
        </p>
        <button class="faq-toggle">
          <i class="fas fa-chevron-down"></i>
          <i class="fas fa-times"></i>
        </button>
      </div>
      
      <div class="faq">
        <h3 class="faq-title">
          What's the object-oriented way to become wealthy?
        </h3>
        <p class="faq-text">
          Inheritance.
        </p>
        <button class="faq-toggle">
          <i class="fas fa-chevron-down"></i>
          <i class="fas fa-times"></i>
        </button>
      </div>
      
      <div class="faq">
        <h3 class="faq-title">
          How many tickles does it take to tickle an octopus?
        </h3>
        <p class="faq-text">
          Ten-tickles!
        </p>
        <button class="faq-toggle">
          <i class="fas fa-chevron-down"></i>
          <i class="fas fa-times"></i>
        </button>
      </div>
      
      <div class="faq">
        <h3 class="faq-title">
          What is: 1 + 1?
        </h3>
        <p class="faq-text">
          Depends on who are you asking.
        </p>
        <button class="faq-toggle">
          <i class="fas fa-chevron-down"></i>
          <i class="fas fa-times"></i>
        </button>
      </div>
    </div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: faq-collapse/script.js
================================================
const toggles = document.querySelectorAll('.faq-toggle')

toggles.forEach(toggle => {
    toggle.addEventListener('click', () => {
        toggle.parentNode.classList.toggle('active')
    })
})

================================================
FILE: faq-collapse/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');

* {
  box-sizing: border-box;
}

body {
  font-family: 'Muli', sans-serif;
  background-color: #f0f0f0;
}

h1 {
  margin: 50px 0 30px;
  text-align: center;
}

.faq-container {
  max-width: 600px;
  margin: 0 auto;
}

.faq {
  background-color: transparent;
  border: 1px solid #9fa4a8;
  border-radius: 10px;
  margin: 20px 0;
  padding: 30px;
  position: relative;
  overflow: hidden;
  transition: 0.3s ease;
}

.faq.active {
  background-color: #fff;
  box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1), 0 3px 6px rgba(0, 0, 0, 0.1);
}

.faq.active::before,
.faq.active::after {
  content: '\f075';
  font-family: 'Font Awesome 5 Free';
  color: #2ecc71;
  font-size: 7rem;
  position: absolute;
  opacity: 0.2;
  top: 20px;
  left: 20px;
  z-index: 0;
}

.faq.active::before {
  color: #3498db;
  top: -10px;
  left: -30px;
  transform: rotateY(180deg);
}

.faq-title {
  margin: 0 35px 0 0;
}

.faq-text {
  display: none;
  margin: 30px 0 0;
}

.faq.active .faq-text {
  display: block;
}

.faq-toggle {
  background-color: transparent;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  padding: 0;
  position: absolute;
  top: 30px;
  right: 30px;
  height: 30px;
  width: 30px;
}

.faq-toggle:focus {
  outline: 0;
}

.faq-toggle .fa-times {
  display: none;
}

.faq.active .faq-toggle .fa-times {
  color: #fff;
  display: block;
}

.faq.active .faq-toggle .fa-chevron-down {
  display: none;
}

.faq.active .faq-toggle {
  background-color: #9fa4a8;
}


================================================
FILE: feedback-ui-design/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog==" crossorigin="anonymous" />
    <link rel="stylesheet" href="style.css" />
    <title>Let Us Know Your Feedback</title>
  </head>
  <body>
    <div id="panel" class="panel-container">
      <strong>How satisfied are you with our <br /> customer support performance?</strong>
      <div class="ratings-container">
        <div class="rating">
          <img src="https://img.icons8.com/external-neu-royyan-wijaya/64/000000/external-emoji-neumojis-smiley-neu-royyan-wijaya-17.png" alt="">
          <small>Unhappy</small>
        </div>

        <div class="rating">
          <img src="https://img.icons8.com/external-neu-royyan-wijaya/64/000000/external-emoji-neumojis-smiley-neu-royyan-wijaya-3.png" alt=""/>
          <small>Neutral</small>
        </div>

        <div class="rating active">
          <img src="https://img.icons8.com/external-neu-royyan-wijaya/64/000000/external-emoji-neumojis-smiley-neu-royyan-wijaya-30.png" alt=""/>
          <small>Satisfied</small>
        </div>
      </div>
      <button class="btn" id="send">Send Review</button>
    </div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: feedback-ui-design/script.js
================================================
const ratings = document.querySelectorAll('.rating')
const ratingsContainer = document.querySelector('.ratings-container')
const sendBtn = document.querySelector('#send')
const panel = document.querySelector('#panel')
let selectedRating = 'Satisfied'

ratingsContainer.addEventListener('click', (e) => {
    if(e.target.parentNode.classList.contains('rating') && e.target.nextElementSibling) {
        removeActive()
        e.target.parentNode.classList.add('active')
        selectedRating = e.target.nextElementSibling.innerHTML
    } else if(
        e.target.parentNode.classList.contains('rating') &&
        e.target.previousSibling &&
        e.target.previousElementSibling.nodeName === 'IMG'
    ) {
        removeActive()
        e.target.parentNode.classList.add('active')
        selectedRating = e.target.innerHTML
    }

})

sendBtn.addEventListener('click', (e) => {
    panel.innerHTML = `
        <i class="fas fa-heart"></i>
        <strong>Thank You!</strong>
        <br>
        <strong>Feedback: ${selectedRating}</strong>
        <p>We'll use your feedback to improve our customer support</p>
    `
})

function removeActive() {
    for(let i = 0; i < ratings.length; i++) {
        ratings[i].classList.remove('active')
    }
}


================================================
FILE: feedback-ui-design/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Montserrat&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: #fef9f2;
  font-family: 'Montserrat', sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.panel-container {
  background-color: #fff;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
  border-radius: 4px;
  font-size: 90%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  padding: 30px;
  max-width: 400px;
}

.panel-container strong {
  line-height: 20px;
}

.ratings-container {
  display: flex;
  margin: 20px 0;
}

.rating {
  flex: 1;
  cursor: pointer;
  padding: 20px;
  margin: 10px 5px;
}

.rating:hover,
.rating.active {
  border-radius: 4px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

.rating img {
  width: 40px;
}

.rating small {
  color: #555;
  display: inline-block;
  margin: 10px 0 0;
}

.rating:hover small,
.rating.active small {
  color: #111;
}

.btn {
  background-color: #302d2b;
  color: #fff;
  border: 0;
  border-radius: 4px;
  padding: 12px 30px;
  cursor: pointer;
}

.btn:focus {
  outline: 0;
}

.btn:active {
  transform: scale(0.98);
}

.fa-heart {
  color: red;
  font-size: 30px;
  margin-bottom: 10px;
}


================================================
FILE: form-input-wave/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Form Input Wave</title>
  </head>
  <body>
    <div class="container">
      <h1>Please Login</h1>
      <form>
        <div class="form-control">
          <input type="text" required>
          <label>Email</label>
          <!-- <label>
            <span style="transition-delay: 0ms">E</span>
              <span style="transition-delay: 50ms">m</span>
              <span style="transition-delay: 100ms">a</span>
              <span style="transition-delay: 150ms">i</span>
              <span style="transition-delay: 200ms">l</span>
        </label> -->
        </div>

        <div class="form-control">
          <input type="password" required>
          <label>Password</label>
        </div>

        <button class="btn">Login</button>

        <p class="text">Don't have an account? <a href="#">Register</a> </p>
      </form>
    </div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: form-input-wave/script.js
================================================
const labels = document.querySelectorAll('.form-control label')

labels.forEach(label => {
    label.innerHTML = label.innerText
        .split('')
        .map((letter, idx) => `<span style="transition-delay:${idx * 50}ms">${letter}</span>`)
        .join('')
})

================================================
FILE: form-input-wave/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: steelblue;
  color: #fff;
  font-family: 'Muli', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.container {
  background-color: rgba(0, 0, 0, 0.4);
  padding: 20px 40px;
  border-radius: 5px;
}

.container h1 {
  text-align: center;
  margin-bottom: 30px;
}

.container a {
  text-decoration: none;
  color: lightblue;
}

.btn {
  cursor: pointer;
  display: inline-block;
  width: 100%;
  background: lightblue;
  padding: 15px;
  font-family: inherit;
  font-size: 16px;
  border: 0;
  border-radius: 5px;
}

.btn:focus {
  outline: 0;
}

.btn:active {
  transform: scale(0.98);
}

.text {
  margin-top: 30px;
}

.form-control {
  position: relative;
  margin: 20px 0 40px;
  width: 300px;
}

.form-control input {
  background-color: transparent;
  border: 0;
  border-bottom: 2px #fff solid;
  display: block;
  width: 100%;
  padding: 15px 0;
  font-size: 18px;
  color: #fff;
  position: relative;
  z-index: 100;
}

.form-control input:focus,
.form-control input:valid {
  outline: 0;
  border-bottom-color: lightblue;
}

.form-control label {
  position: absolute;
  top: 15px;
  left: 0;
  pointer-events: none;
}

.form-control label span {
  display: inline-block;
  font-size: 18px;
  min-width: 5px;
  transition: 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}

.form-control input:focus ~ label span,
.form-control input:valid ~ label span {
  color: lightblue;
  transform: translateY(-30px);
}


================================================
FILE: github-profiles/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Github Profiles</title>
  </head>
  <body>
    <form class="user-form" id="form">
      <input type="text" id="search" placeholder="Search a Github User">
    </form>

    <main id="main"></main>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.0/axios.min.js" integrity="sha512-DZqqY3PiOvTP9HkjIWgjO6ouCbq+dxqWoJZ/Q+zPYNHmlnI2dQnbJ5bxAHpAMw+LXRm4D72EIRXzvcHQtE8/VQ==" crossorigin="anonymous"></script>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: github-profiles/script.js
================================================
const APIURL = 'https://api.github.com/users/'

const main = document.getElementById('main')
const form = document.getElementById('form')
const search = document.getElementById('search')

async function getUser(username) {
    try {
        const { data } = await axios(APIURL + username)

        createUserCard(data)
        getRepos(username)
    } catch(err) {
        if(err.response.status == 404) {
            createErrorCard('No profile with this username')
        }
    }
}

async function getRepos(username) {
    try {
        const { data } = await axios(APIURL + username + '/repos?sort=created')

        addReposToCard(data)
    } catch(err) {
        createErrorCard('Problem fetching repos')
    }
}

function createUserCard(user) {
    const userID = user.name || user.login
    const userBio = user.bio ? `<p>${user.bio}</p>` : ''
    const cardHTML = `
    <div class="card">
    <div>
      <img src="${user.avatar_url}" alt="${user.name}" class="avatar">
    </div>
    <div class="user-info">
      <h2>${userID}</h2>
      ${userBio}
      <ul>
        <li>${user.followers} <strong>Followers</strong></li>
        <li>${user.following} <strong>Following</strong></li>
        <li>${user.public_repos} <strong>Repos</strong></li>
      </ul>

      <div id="repos"></div>
    </div>
  </div>
    `
    main.innerHTML = cardHTML
    
}

function createErrorCard(msg) {
    const cardHTML = `
        <div class="card">
            <h1>${msg}</h1>
        </div>
    `

    main.innerHTML = cardHTML
}

function addReposToCard(repos) {
    const reposEl = document.getElementById('repos')

    repos
        .slice(0, 5)
        .forEach(repo => {
            const repoEl = document.createElement('a')
            repoEl.classList.add('repo')
            repoEl.href = repo.html_url
            repoEl.target = '_blank'
            repoEl.innerText = repo.name

            reposEl.appendChild(repoEl)
        })
}

form.addEventListener('submit', (e) => {
    e.preventDefault()

    const user = search.value

    if(user) {
        getUser(user)

        search.value = ''
    }
})



================================================
FILE: github-profiles/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: #2a2a72;
  color: #fff;
  font-family: 'Poppins', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.user-form {
  width: 100%;
  max-width: 700px;
}

.user-form input {
  width: 100%;
  display: block;
  background-color: #4c2885;
  border: none;
  border-radius: 10px;
  color: #fff;
  padding: 1rem;
  margin-bottom: 2rem;
  font-family: inherit;
  font-size: 1rem;
  box-shadow: 0 5px 10px rgba(154, 160, 185, 0.05),
    0 15px 40px rgba(0, 0, 0, 0.1);
}

.user-form input::placeholder {
  color: #bbb;
}

.user-form input:focus {
  outline: none;
}

.card {
  max-width: 800px;
  background-color: #4c2885;
  border-radius: 20px;
  box-shadow: 0 5px 10px rgba(154, 160, 185, 0.05),
    0 15px 40px rgba(0, 0, 0, 0.1);
  display: flex;
  padding: 3rem;
  margin: 0 1.5rem;
}

.avatar {
  border-radius: 50%;
  border: 10px solid #2a2a72;
  height: 150px;
  width: 150px;
}

.user-info {
  color: #eee;
  margin-left: 2rem;
}

.user-info h2 {
  margin-top: 0;
}

.user-info ul {
  list-style-type: none;
  display: flex;
  justify-content: space-between;
  padding: 0;
  max-width: 400px;
}

.user-info ul li {
  display: flex;
  align-items: center;
}

.user-info ul li strong {
  font-size: 0.9rem;
  margin-left: 0.5rem;
}

.repo {
  text-decoration: none;
  color: #fff;
  background-color: #212a72;
  font-size: 0.7rem;
  padding: 0.25rem 0.5rem;
  margin-right: 0.5rem;
  margin-bottom: 0.5rem;
  display: inline-block;
}

@media (max-width: 500px) {
  .card {
    flex-direction: column;
    align-items: center;
  }

  .user-form {
    max-width: 400px;
  }
}


================================================
FILE: good-cheap-fast/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Good, Cheap, Fast</title>
  </head>
  <body>
    <h2>How do you want your project to be?</h2>
    <div class="toggle-container">
      <input type="checkbox" id="good" class="toggle">
      <label for="good" class="label">
        <div class="ball"></div>
      </label>
      <span>Good</span>
    </div>

    <div class="toggle-container">
      <input type="checkbox" id="cheap" class="toggle">
      <label for="cheap" class="label">
        <div class="ball"></div>
      </label>
      <span>Cheap</span>
    </div>

    <div class="toggle-container">
      <input type="checkbox" id="fast" class="toggle">
      <label for="fast" class="label">
        <div class="ball"></div>
      </label>
      <span>Fast</span>
    </div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: good-cheap-fast/script.js
================================================
const toggles = document.querySelectorAll('.toggle')
const good = document.querySelector('#good')
const cheap = document.querySelector('#cheap')
const fast = document.querySelector('#fast')

toggles.forEach(toggle => toggle.addEventListener('change', (e) => doTheTrick(e.target)))

function doTheTrick(theClickedOne) {
    if(good.checked && cheap.checked && fast.checked) {
        if(good === theClickedOne) {
            fast.checked = false
        }

        if(cheap === theClickedOne) {
            good.checked = false
        }

        if(fast === theClickedOne) {
            cheap.checked = false
        }
    }
}

================================================
FILE: good-cheap-fast/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

* {
  box-sizing: border-box;
}

body {
  font-family: 'Roboto', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.toggle-container {
  display: flex;
  align-items: center;
  margin: 10px 0;
  width: 200px;
}

.toggle {
  visibility: hidden;
}

.label {
  position: relative;
  background-color: #d0d0d0;
  border-radius: 50px;
  cursor: pointer;
  display: inline-block;
  margin: 0 15px 0;
  width: 80px;
  height: 40px;
}

.toggle:checked + .label {
  background-color: #8e44ad;
}

.ball {
  background: #fff;
  height: 34px;
  width: 34px;
  border-radius: 50%;
  position: absolute;
  top: 3px;
  left: 3px;
  align-items: center;
  justify-content: center;
  animation: slideOff 0.3s linear forwards;
}

.toggle:checked + .label .ball {
  animation: slideOn 0.3s linear forwards;
}

@keyframes slideOn {
  0% {
    transform: translateX(0) scale(1);
  }
  50% {
    transform: translateX(20px) scale(1.2);
  }
  100% {
    transform: translateX(40px) scale(1);
  }
}

@keyframes slideOff {
  0% {
    transform: translateX(40px) scale(1);
  }
  50% {
    transform: translateX(20px) scale(1.2);
  }
  100% {
    transform: translateX(0) scale(1);
  }
}


================================================
FILE: hidden-search/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog==" crossorigin="anonymous" />
    <link rel="stylesheet" href="style.css" />
    <title>Hidden Search</title>
  </head>
  <body>
    <div class="search">
      <input type="text" class="input" placeholder="Search...">
      <button class="btn">
        <i class="fas fa-search"></i>
      </button>
    </div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: hidden-search/script.js
================================================
const search = document.querySelector('.search')
const btn = document.querySelector('.btn')
const input = document.querySelector('.input')

btn.addEventListener('click', () => {
    search.classList.toggle('active')
    input.focus()
})

================================================
FILE: hidden-search/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-image: linear-gradient(90deg, #7d5fff, #7158e2);
  font-family: 'Roboto', sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.search {
  position: relative;
  height: 50px;
}

.search .input {
  background-color: #fff;
  border: 0;
  font-size: 18px;
  padding: 15px;
  height: 50px;
  width: 50px;
  transition: width 0.3s ease;
}

.btn {
  background-color: #fff;
  border: 0;
  cursor: pointer;
  font-size: 24px;
  position: absolute;
  top: 0;
  left: 0;
  height: 50px;
  width: 50px;
  transition: transform 0.3s ease;
}

.btn:focus,
.input:focus {
  outline: none;
}

.search.active .input {
  width: 200px;
}

.search.active .btn {
  transform: translateX(198px);
}


================================================
FILE: hoverboard/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Hoverboard</title>
  </head>
  <body>
    <div class="container" id="container"></div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: hoverboard/script.js
================================================
const container = document.getElementById('container')
const colors = ['#e74c3c', '#8e44ad', '#3498db', '#e67e22', '#2ecc71']
const SQUARES = 500

for(let i = 0; i < SQUARES; i++) {
    const square = document.createElement('div')
    square.classList.add('square')

    square.addEventListener('mouseover', () => setColor(square))

    square.addEventListener('mouseout', () => removeColor(square))

    container.appendChild(square)
}

function setColor(element) {
   const color = getRandomColor()
   element.style.background = color
   element.style.boxShadow = `0 0 2px ${color}, 0 0 10px ${color}`
}

function removeColor(element) {
   element.style.background = '#1d1d1d'
   element.style.boxShadow = '0 0 2px #000'
}

function getRandomColor() {
    return colors[Math.floor(Math.random() * colors.length)]
}

================================================
FILE: hoverboard/style.css
================================================
* {
  box-sizing: border-box;
}

body {
  background-color: #111;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.container {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  max-width: 400px;
}

.square {
  background-color: #1d1d1d;
  box-shadow: 0 0 2px #000;
  height: 16px;
  width: 16px;
  margin: 2px;
  transition: 2s ease;
}

.square:hover {
  transition-duration: 0s;
}


================================================
FILE: image-carousel/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Image Carousel</title>
  </head>
  <body>
    <div class="carousel">
      <div class="image-container" id="imgs">
        <img src="https://images.unsplash.com/photo-1599394022918-6c2776530abb?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1458&q=80"
       alt="first-image"
       />
    <img
       src="https://images.unsplash.com/photo-1593642632559-0c6d3fc62b89?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1500&q=80"
       alt="second-image"
       />
    <img
       src="https://images.unsplash.com/photo-1599423300746-b62533397364?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1500&q=80"
       alt="third-image"
       />
    <img
       src="https://images.unsplash.com/photo-1599561046251-bfb9465b4c44?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1492&q=80"
       alt="fourth-image"
       />
      </div>

      <div class="buttons-container">
        <button id="left" class="btn">Prev</button>
        <button id="right" class="btn">Next</button>
      </div>
    </div>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: image-carousel/script.js
================================================
const imgs = document.getElementById('imgs')
const leftBtn = document.getElementById('left')
const rightBtn = document.getElementById('right')

const img = document.querySelectorAll('#imgs img')

let idx = 0

let interval = setInterval(run, 2000)

function run() {
    idx++
    changeImage()
}

function changeImage() {
    if(idx > img.length - 1) {
        idx = 0
    } else if(idx < 0) {
        idx = img.length - 1
    }

    imgs.style.transform = `translateX(${-idx * 500}px)`
}

function resetInterval() {
    clearInterval(interval)
    interval = setInterval(run, 2000)
}

rightBtn.addEventListener('click', () => {
    idx++
    changeImage()
    resetInterval()
})

leftBtn.addEventListener('click', () => {
    idx--
    changeImage()
    resetInterval()
})


================================================
FILE: image-carousel/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

* {
  box-sizing: border-box;
}

body {
  font-family: 'Roboto', sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  margin: 0;
}

img {
  width: 500px;
  height: 500px;
  object-fit: cover;
}

.carousel {
  box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
  height: 530px;
  width: 500px;
  overflow: hidden;
}

.image-container {
  display: flex;
  transform: translateX(0);
  transition: transform 0.5s ease-in-out;
}

.buttons-container {
  display: flex;
  justify-content: space-between;
}

.btn {
  background-color: rebeccapurple;
  color: #fff;
  border: none;
  padding: 0.5rem;
  cursor: pointer;
  width: 49.5%;
}

.btn:hover {
  opacity: 0.9;
}

.btn:focus {
  outline: none;
}


================================================
FILE: incrementing-counter/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog==" crossorigin="anonymous" />
    <link rel="stylesheet" href="style.css" />
    <title>Increment Counter</title>
  </head>
  <body>
    <div class="counter-container">
      <i class="fab fa-twitter fa-3x"></i>
      <div class="counter" data-target="12000"></div>
      <span>Twitter Followers</span>
    </div>

    <div class="counter-container">
      <i class="fab fa-youtube fa-3x"></i>
      <div class="counter" data-target="5000"></div>
      <span>YouTube Subscribers</span>
    </div>

    <div class="counter-container">
      <i class="fab fa-facebook fa-3x"></i>
      <div class="counter" data-target="7500"></div>
      <span>Facebook Fans</span>
    </div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: incrementing-counter/script.js
================================================
const counters = document.querySelectorAll('.counter')

counters.forEach(counter => {
    counter.innerText = '0'

    const updateCounter = () => {
        const target = +counter.getAttribute('data-target')
        const c = +counter.innerText

        const increment = target / 200

        if(c < target) {
            counter.innerText = `${Math.ceil(c + increment)}`
            setTimeout(updateCounter, 1)
        } else {
            counter.innerText = target
        }
    }

    updateCounter()
})

================================================
FILE: incrementing-counter/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Roboto+Mono&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: #8e44ad;
  color: #fff;
  font-family: 'Roboto Mono', sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.counter-container {
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  margin: 30px 50px;
}

.counter {
  font-size: 60px;
  margin-top: 10px;
}

@media (max-width: 580px) {
  body {
    flex-direction: column;
  }
}


================================================
FILE: insect-catch-game/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Catch The Insect</title>
  </head>
  <body>
    <div class="screen">
      <h1>Catch The Insect</h1>
      <button class="btn" id="start-btn">Play Game</button>
    </div>

    <div class="screen">
      <h1>What is your "favorite" insect?</h1>
      <ul class="insects-list">
        <li>
          <button class="choose-insect-btn">
            <p>Fly</p>
            <img src="http://pngimg.com/uploads/fly/fly_PNG3946.png" alt="fly">
          </button>
        </li>
        <li>
          <button class="choose-insect-btn">
            <p>Mosquito</p>
            <img
               src="http://pngimg.com/uploads/mosquito/mosquito_PNG18175.png"
               alt="mosquito"
               />
          </button>
        </li>
        <li>
          <button class="choose-insect-btn">
            <p>Spider</p>
            <img
               src="http://pngimg.com/uploads/spider/spider_PNG12.png"
               alt="spider"
               />
          </button>
        </li>
        <li>
          <button class="choose-insect-btn">
            <p>Roach</p>
            <img
               src="http://pngimg.com/uploads/roach/roach_PNG12163.png"
               alt="roach"
               />
          </button>
        </li>
      </ul>
    </div>

    <div class="screen game-container" id="game-container">
      <h3 id="time" class="time">Time: 00:00</h3>
      <h3 id="score" class="score">Score: 0</h3>
      <h5 id="message" class="message">
        Are you annoyed yet? <br>
        You are playing an impossible game!!
      </h5>
    </div>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: insect-catch-game/script.js
================================================
const screens = document.querySelectorAll('.screen');
const choose_insect_btns = document.querySelectorAll('.choose-insect-btn');
const start_btn = document.getElementById('start-btn')
const game_container = document.getElementById('game-container')
const timeEl = document.getElementById('time')
const scoreEl = document.getElementById('score')
const message = document.getElementById('message')
let seconds = 0
let score = 0
let selected_insect = {}

start_btn.addEventListener('click', () => screens[0].classList.add('up'))

choose_insect_btns.forEach(btn => {
    btn.addEventListener('click', () => {
        const img = btn.querySelector('img')
        const src = img.getAttribute('src')
        const alt = img.getAttribute('alt')
        selected_insect = { src, alt }
        screens[1].classList.add('up')
        setTimeout(createInsect, 1000)
        startGame()
    })
})

function startGame() {
    setInterval(increaseTime, 1000)
}

function increaseTime() {
    let m = Math.floor(seconds / 60)
    let s = seconds % 60
    m = m < 10 ? `0${m}` : m
    s = s < 10 ? `0${s}` : s
    timeEl.innerHTML = `Time: ${m}:${s}`
    seconds++
}

function createInsect() {
    const insect = document.createElement('div')
    insect.classList.add('insect')
    const { x, y } = getRandomLocation()
    insect.style.top = `${y}px`
    insect.style.left = `${x}px`
    insect.innerHTML = `<img src="${selected_insect.src}" alt="${selected_insect.alt}" style="transform: rotate(${Math.random() * 360}deg)" />`

    insect.addEventListener('click', catchInsect)

    game_container.appendChild(insect)
}

function getRandomLocation() {
    const width = window.innerWidth
    const height = window.innerHeight
    const x = Math.random() * (width - 200) + 100
    const y = Math.random() * (height - 200) + 100
    return { x, y }
}

function catchInsect() {
    increaseScore()
    this.classList.add('caught')
    setTimeout(() => this.remove(), 2000)
    addInsects()
}

function addInsects() {
    setTimeout(createInsect, 1000)
    setTimeout(createInsect, 1500)
}

function increaseScore() {
    score++
    if(score > 19) {
        message.classList.add('visible')
    }
    scoreEl.innerHTML = `Score: ${score}`
}

================================================
FILE: insect-catch-game/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Press+Start+2P&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: #516dff;
  color: #fff;
  font-family: 'Press Start 2P', sans-serif;
  height: 100vh;
  overflow: hidden;
  margin: 0;
  text-align: center;
}

a {
  color: #fff;
}

h1 {
  line-height: 1.4;
}

.btn {
  border: 0;
  background-color: #fff;
  color: #516dff;
  padding: 15px 20px;
  font-family: inherit;
  cursor: pointer;
}

.btn:hover {
  opacity: 0.9;
}

.btn:focus {
  outline: 0;
}

.screen {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  width: 100vw;
  transition: margin 0.5s ease-out;
}

.screen.up {
  margin-top: -100vh;
}

.insects-list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  list-style-type: none;
  padding: 0;
}

.insects-list li {
  margin: 10px;
}

.choose-insect-btn {
  background-color: transparent;
  border: 2px solid #fff;
  color: #fff;
  cursor: pointer;
  font-family: inherit;
  width: 150px;
  height: 150px;
}

.choose-insect-btn:hover {
  background-color: #fff;
  color: #516dff;
}

.choose-insect-btn:active {
  background-color: rgba(255, 255, 255, 0.7);
}

.choose-insect-btn img {
  width: 100px;
  height: 100px;
  object-fit: contain;
}

.game-container {
  position: relative;
}

.time,
.score {
  position: absolute;
  top: 20px;
}

.time {
  left: 20px;
}

.score {
  right: 20px;
}

.message {
  line-height: 1.7;
  background-color: rgba(0, 0, 0, 0.5);
  width: 100%;
  padding: 20px;
  z-index: 100;
  text-align: center;
  opacity: 0;
  position: absolute;
  top: 0;
  left: 50%;
  transform: translate(-50%, -150%);
  transition: transform 0.4s ease-in;
}

.message.visible {
  transform: translate(-50%, 150%);
  opacity: 1;
}

.insect {
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100px;
  height: 100px;
  position: absolute;
  transform: translate(-50%, -50%) scale(1);
  transition: transform 0.3s ease-in-out;
}

.insect.caught {
  transform: translate(-50%, -50%) scale(0);
}

.insect img {
  width: 100px;
  height: 100px;
}


================================================
FILE: kinetic-loader/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Kinetic Loader</title>
  </head>
  <body>
    <div class="kinetic"></div>
    
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: kinetic-loader/style.css
================================================
* {
  box-sizing: border-box;
}

body {
  background-color: #2c3e50;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.kinetic {
  position: relative;
  height: 80px;
  width: 80px;
}

.kinetic::after,
.kinetic::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  border: 50px solid transparent;
  border-bottom-color: #fff;
  animation: rotateA 2s linear infinite 0.5s;
}

.kinetic::before {
  transform: rotate(90deg);
  animation: rotateB 2s linear infinite;
}

@keyframes rotateA {
  0%,
  25% {
    transform: rotate(0deg);
  }

  50%,
  75% {
    transform: rotate(180deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

@keyframes rotateB {
  0%,
  25% {
    transform: rotate(90deg);
  }

  50%,
  75% {
    transform: rotate(270deg);
  }

  100% {
    transform: rotate(450deg);
  }
}


================================================
FILE: live-user-filter/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Live User Filter</title>
  </head>
  <body>
    <div class="container">
      <header class="header">
        <h4 class="title">Live User Filter</h4>
        <small class="subtitle">Search by name and/or location</small>
        <input type="text" id="filter" placeholder="Search">
      </header>

      <ul id="result" class="user-list">
        <li>
          <h3>Loading...</h3>
        </li>
      </ul>
    </div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: live-user-filter/script.js
================================================
const result = document.getElementById('result')
const filter = document.getElementById('filter')
const listItems = []

getData()

filter.addEventListener('input', (e) => filterData(e.target.value))

async function getData() {
    const res = await fetch('https://randomuser.me/api?results=50')

    const { results } = await res.json()

    // Clear result
    result.innerHTML = ''

    results.forEach(user => {
        const li = document.createElement('li')

        listItems.push(li)

        li.innerHTML = `
            <img src="${user.picture.large}" alt="${user.name.first}">
            <div class="user-info">
                <h4>${user.name.first} ${user.name.last}</h4>
                <p>${user.location.city}, ${user.location.country}</p>
            </div>
        `

        result.appendChild(li)
    })
}

function filterData(searchTerm) {
    listItems.forEach(item => {
        if(item.innerText.toLowerCase().includes(searchTerm.toLowerCase())) {
            item.classList.remove('hide')
        } else {
            item.classList.add('hide')
        }
    })
}

================================================
FILE: live-user-filter/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: #f8f9fd;
  font-family: 'Roboto', sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.container {
  border-radius: 5px;
  box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.2);
  overflow: hidden;
  width: 300px;
}

.title {
  margin: 0;
}

.subtitle {
  display: inline-block;
  margin: 5px 0 20px;
  opacity: 0.8;
}

.header {
  background-color: #3e57db;
  color: #fff;
  padding: 30px 20px;
}

.header input {
  background-color: rgba(0, 0, 0, 0.3);
  border: 0;
  border-radius: 50px;
  color: #fff;
  font-size: 14px;
  padding: 10px 15px;
  width: 100%;
}

.header input:focus {
  outline: none;
}

.user-list {
  background-color: #fff;
  list-style-type: none;
  margin: 0;
  padding: 0;
  max-height: 400px;
  overflow-y: auto;
}

.user-list li {
  display: flex;
  padding: 20px;
}

.user-list img {
  border-radius: 50%;
  object-fit: cover;
  height: 50px;
  width: 50px;
}

.user-list .user-info {
  margin-left: 10px;
}

.user-list .user-info h4 {
  margin: 0 0 10px;
}

.user-list .user-info p {
  font-size: 12px;
}

.user-list li:not(:last-of-type) {
  border-bottom: 1px solid #eee;
}

.user-list li.hide {
  display: none;
}


================================================
FILE: mobile-tab-navigation/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog==" crossorigin="anonymous" />
    <link rel="stylesheet" href="style.css" />
    <title>Mobile Tab Navigation</title>
  </head>
  <body>
    <div class="phone">
      <img src="https://images.unsplash.com/photo-1480074568708-e7b720bb3f09?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1053&q=80" alt="home" class="content show">
      <img src="https://images.unsplash.com/photo-1454165804606-c3d57bc86b40?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1050&q=80" alt="work" class="content">
      <img src="https://images.unsplash.com/photo-1471107340929-a87cd0f5b5f3?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1266&q=80" alt="blog" class="content">
      <img src="https://images.unsplash.com/photo-1522202176988-66273c2fd55f?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1351&q=80" alt="about" class="content">
      <nav>
        <ul>
          <li class="active">
            <i class="fas fa-home"></i>
            <p>Home</p>
          </li>
          <li>
            <i class="fas fa-box"></i>
            <p>Work</p>
          </li>
          <li>
            <i class="fas fa-book-open"></i>
            <p>Blog</p>
          </li>
          <li>
            <i class="fas fa-users"></i>
            <p>About Us</p>
          </li>
        </ul>
      </nav>
    </div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: mobile-tab-navigation/script.js
================================================
const contents = document.querySelectorAll('.content')
const listItems = document.querySelectorAll('nav ul li')

listItems.forEach((item, idx) => {
    item.addEventListener('click', () => {
        hideAllContents()
        hideAllItems()

        item.classList.add('active')
        contents[idx].classList.add('show')
    })
})

function hideAllContents() {
    contents.forEach(content => content.classList.remove('show'))
}


function hideAllItems() {
    listItems.forEach(item => item.classList.remove('active'))
}

================================================
FILE: mobile-tab-navigation/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Open+Sans&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: rgba(155, 89, 182, 0.7);
  font-family: 'Open Sans', sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  margin: 0;
}

.phone {
  position: relative;
  overflow: hidden;
  border: 3px solid #eee;
  border-radius: 15px;
  height: 600px;
  width: 340px;
}

.phone .content {
  opacity: 0;
  object-fit: cover;
  position: absolute;
  top: 0;
  left: 0;
  height: calc(100% - 60px);
  width: 100%;
  transition: opacity 0.4s ease;
}

.phone .content.show {
  opacity: 1;
}

nav {
  position: absolute;
  bottom: 0;
  left: 0;
  margin-top: -5px;
  width: 100%;
}

nav ul {
  background-color: #fff;
  display: flex;
  list-style-type: none;
  padding: 0;
  margin: 0;
  height: 60px;
}

nav li {
  color: #777;
  cursor: pointer;
  flex: 1;
  padding: 10px;
  text-align: center;
}

nav ul li p {
  font-size: 12px;
  margin: 2px 0;
}

nav ul li:hover,
nav ul li.active {
  color: #8e44ad;
}


================================================
FILE: movie-app/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Movie App</title>
  </head>
  <body>
    <header>
      <form id="form">
        <input type="text" id="search" class="search" placeholder="Search">
      </form>
    </header>

    <main id="main"></main>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: movie-app/script.js
================================================
const API_URL = 'https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=3fd2be6f0c70a2a598f084ddfb75487c&page=1'
const IMG_PATH = 'https://image.tmdb.org/t/p/w1280'
const SEARCH_API = 'https://api.themoviedb.org/3/search/movie?api_key=3fd2be6f0c70a2a598f084ddfb75487c&query="'

const main = document.getElementById('main')
const form = document.getElementById('form')
const search = document.getElementById('search')

// Get initial movies
getMovies(API_URL)

async function getMovies(url) {
    const res = await fetch(url)
    const data = await res.json()

    showMovies(data.results)
}

function showMovies(movies) {
    main.innerHTML = ''

    movies.forEach((movie) => {
        const { title, poster_path, vote_average, overview } = movie

        const movieEl = document.createElement('div')
        movieEl.classList.add('movie')

        movieEl.innerHTML = `
            <img src="${IMG_PATH + poster_path}" alt="${title}">
            <div class="movie-info">
          <h3>${title}</h3>
          <span class="${getClassByRate(vote_average)}">${vote_average}</span>
            </div>
            <div class="overview">
          <h3>Overview</h3>
          ${overview}
        </div>
        `
        main.appendChild(movieEl)
    })
}

function getClassByRate(vote) {
    if(vote >= 8) {
        return 'green'
    } else if(vote >= 5) {
        return 'orange'
    } else {
        return 'red'
    }
}

form.addEventListener('submit', (e) => {
    e.preventDefault()

    const searchTerm = search.value

    if(searchTerm && searchTerm !== '') {
        getMovies(SEARCH_API + searchTerm)

        search.value = ''
    } else {
        window.location.reload()
    }
})

================================================
FILE: movie-app/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');

:root {
  --primary-color: #22254b;
  --secondary-color: #373b69;
}

* {
  box-sizing: border-box;
}

body {
  background-color: var(--primary-color);
  font-family: 'Poppins', sans-serif;
  margin: 0;
}

header {
  padding: 1rem;
  display: flex;
  justify-content: flex-end;
  background-color: var(--secondary-color);
}

.search {
  background-color: transparent;
  border: 2px solid var(--primary-color);
  border-radius: 50px;
  font-family: inherit;
  font-size: 1rem;
  padding: 0.5rem 1rem;
  color: #fff;
}

.search::placeholder {
  color: #7378c5;
}

.search:focus {
  outline: none;
  background-color: var(--primary-color);
}

main {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}

.movie {
  width: 300px;
  margin: 1rem;
  background-color: var(--secondary-color);
  box-shadow: 0 4px 5px rgba(0, 0, 0, 0.2);
  position: relative;
  overflow: hidden;
  border-radius: 3px;
}

.movie img {
  width: 100%;
}

.movie-info {
  color: #eee;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap:0.2rem;
  padding: 0.5rem 1rem 1rem;
  letter-spacing: 0.5px;
}

.movie-info h3 {
  margin-top: 0;
}

.movie-info span {
  background-color: var(--primary-color);
  padding: 0.25rem 0.5rem;
  border-radius: 3px;
  font-weight: bold;
}

.movie-info span.green {
  color: lightgreen;
}

.movie-info span.orange {
  color: orange;
}

.movie-info span.red {
  color: red;
}

.overview {
  background-color: #fff;
  padding: 2rem;
  position: absolute;
  left: 0;
  bottom: 0;
  right: 0;
  max-height: 100%;
  transform: translateY(101%);
  overflow-y: auto;
  transition: transform 0.3s ease-in;
}

.movie:hover .overview {
  transform: translateY(0);
}


================================================
FILE: netflix-mobile-navigation/index.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css"
    integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog=="
    crossorigin="anonymous" />
  <link rel="stylesheet" href="style.css" />
  <title>Netflix Mobile Navigation</title>
</head>

<body>
  <button class="nav-btn open-btn">
    <i class="fas fa-bars"></i>
  </button>

  <img
    src="https://images.ctfassets.net/4cd45et68cgf/7LrExJ6PAj6MSIPkDyCO86/542b1dfabbf3959908f69be546879952/Netflix-Brand-Logo.png?w=684&h=456"
    alt="Logo" class="logo">

  <p class="text">Mobile Navigation</p>

  <div class="nav nav-black">
    <div class="nav nav-red">
      <div class="nav nav-white">
        <button class="nav-btn close-btn">
          <i class="fas fa-times"></i>
        </button>

        <img
          src="https://images.ctfassets.net/4cd45et68cgf/7LrExJ6PAj6MSIPkDyCO86/542b1dfabbf3959908f69be546879952/Netflix-Brand-Logo.png?w=684&h=456"
          alt="Logo" class="logo">

        <ul class="list">
          <li><a href="#">Teams</a></li>
          <li><a href="#">Locations</a></li>
          <li><a href="#">Life at Netflix</a></li>
          <li>
            <ul>
              <li><a href="#">Netflix culture memo</a></li>
              <li><a href="#">Work life balance</a></li>
              <li><a href="#">Inclusion & diversity</a></li>
              <li><a href="#">Blog</a></li>
            </ul>
          </li>
        </ul>
      </div>
    </div>
  </div>

  <script src="script.js"></script>
</body>

</html>

================================================
FILE: netflix-mobile-navigation/script.js
================================================
const open_btn = document.querySelector('.open-btn')
const close_btn = document.querySelector('.close-btn')
const nav = document.querySelectorAll('.nav')

open_btn.addEventListener('click', () => {
    nav.forEach(nav_el => nav_el.classList.add('visible'))
})

close_btn.addEventListener('click', () => {
    nav.forEach(nav_el => nav_el.classList.remove('visible'))
})

================================================
FILE: netflix-mobile-navigation/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');

* {
  box-sizing: border-box;
}

body {
  font-family: 'Muli', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
}

.text {
  text-transform: uppercase;
}

.logo {
  width: 200px;
}

.nav-btn {
  border: none;
  background-color: transparent;
  cursor: pointer;
  font-size: 20px;
}

.open-btn {
  position: fixed;
  top: 10px;
  left: 10px;
}

.nav {
  position: fixed;
  top: 0;
  left: 0;
  height: 100vh;
  transform: translateX(-100%);
  transition: transform 0.3s ease-in-out;
}

.nav.visible {
  transform: translateX(0);
}

.nav-black {
  background-color: rgb(34, 31, 31);
  width: 60%;
  max-width: 480px;
  min-width: 320px;
  transition-delay: 0.4s;
}

.nav-black.visible {
  transition-delay: 0s;
}

.nav-red {
  background-color: rgb(229, 9, 20);
  width: 95%;
  transition-delay: 0.2s;
}

.nav-red.visible {
  transition-delay: 0.2s;
}

.nav-white {
  background-color: #fff;
  width: 95%;
  padding: 40px;
  position: relative;
  transition-delay: 0s;
}

.nav-white.visible {
  transition-delay: 0.4s;
}

.close-btn {
  opacity: 0.3;
  position: absolute;
  top: 40px;
  right: 30px;
}

.list {
  list-style-type: none;
  padding: 0;
}

.list li {
  margin: 20px 0;
}

.list li a {
  color: rgb(34, 31, 31);
  font-size: 14px;
  text-decoration: none;
  text-transform: uppercase;
}

.list ul {
  list-style-type: none;
  padding-left: 20px;
}


================================================
FILE: notes-app/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog==" crossorigin="anonymous" />
    <link rel="stylesheet" href="style.css" />
    <title>Notes App</title>
  </head>
  <body>
    <button class="add" id="add">
      <i class="fas fa-plus"></i> Add note
    </button>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/1.2.2/marked.min.js"></script>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: notes-app/script.js
================================================
const addBtn = document.getElementById('add')

const notes = JSON.parse(localStorage.getItem('notes'))

if(notes) {
    notes.forEach(note => addNewNote(note))
}

addBtn.addEventListener('click', () => addNewNote())

function addNewNote(text = '') {
    const note = document.createElement('div')
    note.classList.add('note')

    note.innerHTML = `
    <div class="tools">
        <button class="edit"><i class="fas fa-edit"></i></button>
        <button class="delete"><i class="fas fa-trash-alt"></i></button>
    </div>

    <div class="main ${text ? "" : "hidden"}"></div>
    <textarea class="${text ? "hidden" : ""}"></textarea>
    `

    const editBtn = note.querySelector('.edit')
    const deleteBtn = note.querySelector('.delete')
    const main = note.querySelector('.main')
    const textArea = note.querySelector('textarea')

    textArea.value = text
    main.innerHTML = marked(text)

    deleteBtn.addEventListener('click', () => {
        note.remove()

        updateLS()
    })

    editBtn.addEventListener('click', () => {
        main.classList.toggle('hidden')
        textArea.classList.toggle('hidden')
    })

    textArea.addEventListener('input', (e) => {
        const { value } = e.target

        main.innerHTML = marked(value)

        updateLS()
    })

    document.body.appendChild(note)
}

function updateLS() {
    const notesText = document.querySelectorAll('textarea')

    const notes = []

    notesText.forEach(note => notes.push(note.value))

    localStorage.setItem('notes', JSON.stringify(notes))
}

================================================
FILE: notes-app/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');

* {
  box-sizing: border-box;
  outline: none;
}

body {
  background-color: #7bdaf3;
  font-family: 'Poppins', sans-serif;
  display: flex;
  flex-wrap: wrap;
  margin: 0;
  padding-top: 3rem;
}

.add {
  position: fixed;
  top: 1rem;
  right: 1rem;
  background-color: #9ec862;
  color: #fff;
  border: none;
  border-radius: 3px;
  padding: 0.5rem 1rem;
  cursor: pointer;
}

.add:active {
  transform: scale(0.98);
}

.note {
  background-color: #fff;
  box-shadow: 0 0 10px 4px rgba(0, 0, 0, 0.1);
  margin: 30px 20px;
  height: 400px;
  width: 400px;
  overflow-y: scroll;
}

.note .tools {
  background-color: #9ec862;
  display: flex;
  justify-content: flex-end;
  padding: 0.5rem;
}

.note .tools button {
  background-color: transparent;
  border: none;
  color: #fff;
  cursor: pointer;
  font-size: 1rem;
  margin-left: 0.5rem;
}

.note textarea {
  outline: none;
  font-family: inherit;
  font-size: 1.2rem;
  border: none;
  height: 400px;
  width: 100%;
  padding: 20px;
}

.main {
  padding: 20px;
}

.hidden {
  display: none;
}


================================================
FILE: password-generator/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog==" crossorigin="anonymous" />
    <link rel="stylesheet" href="style.css" />
    <title>Password Generator</title>
  </head>
  <body>
    <div class="container">
      <h2>Password Generator</h2>
      <div class="result-container">
        <span id="result"></span>
        <button class="btn" id="clipboard">
          <i class="far fa-clipboard"></i>
        </button>
      </div>
      <div class="settings">
        <div class="setting">
          <label>Password Length</label>
          <input type="number" id="length" min="4" max="20" value="20">
        </div>
        <div class="setting">
          <label>Include uppercase letters</label>
          <input type="checkbox" id="uppercase" checked>
        </div>
        <div class="setting">
          <label>Include lowercase letters</label>
          <input type="checkbox" id="lowercase" checked>
        </div>
        <div class="setting">
          <label>Include numbers</label>
          <input type="checkbox" id="numbers" checked>
        </div>
        <div class="setting">
          <label>Include symbols</label>
          <input type="checkbox" id="symbols" checked>
        </div>
      </div>

      <button class="btn btn-large" id="generate">
        Generate Password
      </button>
    </div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: password-generator/script.js
================================================
const resultEl = document.getElementById('result')
const lengthEl = document.getElementById('length')
const uppercaseEl = document.getElementById('uppercase')
const lowercaseEl = document.getElementById('lowercase')
const numbersEl = document.getElementById('numbers')
const symbolsEl = document.getElementById('symbols')
const generateEl = document.getElementById('generate')
const clipboardEl = document.getElementById('clipboard')

const randomFunc = {
    lower: getRandomLower,
    upper: getRandomUpper,
    number: getRandomNumber,
    symbol: getRandomSymbol
}

clipboardEl.addEventListener('click', () => {
    const password = resultEl.innerText;
  if (!password) {
    return;
  }
  navigator.clipboard.writeText(password);
    alert('Password copied to clipboard!')
})

generateEl.addEventListener('click', () => {
    const length = +lengthEl.value
    const hasLower = lowercaseEl.checked
    const hasUpper = uppercaseEl.checked
    const hasNumber = numbersEl.checked
    const hasSymbol = symbolsEl.checked

    resultEl.innerText = generatePassword(hasLower, hasUpper, hasNumber, hasSymbol, length)
})

function generatePassword(lower, upper, number, symbol, length) {
    let generatedPassword = ''
    const typesCount = lower + upper + number + symbol
    const typesArr = [{lower}, {upper}, {number}, {symbol}].filter(item => Object.values(item)[0])
    
    if(typesCount === 0) {
        return ''
    }

    for(let i = 0; i < length; i += typesCount) {
        typesArr.forEach(type => {
            const funcName = Object.keys(type)[0]
            generatedPassword += randomFunc[funcName]()
        })
    }

    const finalPassword = generatedPassword.slice(0, length)

    return finalPassword
}

function getRandomLower() {
    return String.fromCharCode(Math.floor(Math.random() * 26) + 97)
}

function getRandomUpper() {
    return String.fromCharCode(Math.floor(Math.random() * 26) + 65)
}

function getRandomNumber() {
    return String.fromCharCode(Math.floor(Math.random() * 10) + 48)
}

function getRandomSymbol() {
    const symbols = '!@#$%^&*(){}[]=<>/,.'
    return symbols[Math.floor(Math.random() * symbols.length)]
}


================================================
FILE: password-generator/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: #3b3b98;
  color: #fff;
  font-family: 'Muli', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  padding: 10px;
  margin: 0;
}

h2 {
  margin: 10px 0 20px;
  text-align: center;
}

.container {
  background-color: #23235b;
  box-shadow: 0px 2px 10px rgba(255, 255, 255, 0.2);
  padding: 20px;
  width: 350px;
  max-width: 100%;
}

.result-container {
  background-color: rgba(0, 0, 0, 0.4);
  display: flex;
  justify-content: flex-start;
  align-items: center;
  position: relative;
  font-size: 18px;
  letter-spacing: 1px;
  padding: 12px 10px;
  height: 50px;
  width: 100%;
}

.result-container #result {
  word-wrap: break-word;
  max-width: calc(100% - 40px);
  overflow-y: scroll;
  height: 100%;
}

#result::-webkit-scrollbar {
  width: 1rem;
}

.result-container .btn {
  position: absolute;
  top: 5px;
  right: 5px;
  width: 40px;
  height: 40px;
  font-size: 20px;
}

.btn {
  border: none;
  background-color: #3b3b98;
  color: #fff;
  font-size: 16px;
  padding: 8px 12px;
  cursor: pointer;
}

.btn-large {
  display: block;
  width: 100%;
}

.setting {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 15px 0;
}


================================================
FILE: password-strength-background/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/1.8.11/tailwind.min.css"
      integrity="sha512-KO1h5ynYuqsFuEicc7DmOQc+S9m2xiCKYlC3zcZCSEw0RGDsxcMnppRaMZnb0DdzTDPaW22ID/gAGCZ9i+RT/w=="
      crossorigin="anonymous"
    />
    <link rel="stylesheet" href="style.css" />
    <title>Password Strength Backround</title>
  </head>
  <body>
    <div class="background" id="background"></div>
    <div class="bg-white rounded p-10 text-center shadow-md">
      <h1 class="text-3xl">Image Password Strength</h1>
      <p class="text-sm text-gray-700">Change the password to see the effect</p>
      <div class="my-4 text-left">
        <label for="email" class="text-gray-900">Email:</label>
        <input
          type="text"
          class="border block w-full p-2 mt-2 rounded"
          id="email"
          placeholder="Enter Email"
        />
      </div>

      <div class="my-4 text-left">
        <label for="email" class="text-gray-900">Password:</label>
        <input
          type="password"
          class="border block w-full p-2 mt-2 rounded"
          id="password"
          placeholder="Enter Password"
        />
      </div>

      <button
        class="bg-black text-white py-2 mt-4 inline-block w-full rounded"
        type="submit"
      >
        Submit
      </button>
    </div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: password-strength-background/script.js
================================================
const password = document.getElementById('password')
const background = document.getElementById('background')

password.addEventListener('input', (e) => {
  const input = e.target.value
  const length = input.length
  const blurValue = 20 - length * 2
  background.style.filter = `blur(${blurValue}px)`
})


================================================
FILE: password-strength-background/style.css
================================================
* {
  box-sizing: border-box;
}

body {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.background {
  background: url('https://images.unsplash.com/photo-1556745757-8d76bdb6984b')
    no-repeat center center/cover;
  position: absolute;
  top: -20px;
  bottom: -20px;
  left: -20px;
  right: -20px;
  z-index: -1;
  filter: blur(20px);
}


================================================
FILE: pokedex/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Pokedex</title>
  </head>
  <body>
    <h1>Pokedex</h1>
    <div class="poke-container" id="poke-container"></div>

    <!-- Design inspired by this Dribbble shot: https://dribbble.com/shots/5611109--Pokemon -->
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: pokedex/script.js
================================================
const poke_container = document.getElementById('poke-container')
const pokemon_count = 150
const colors = {
    fire: '#FDDFDF',
    grass: '#DEFDE0',
	electric: '#FCF7DE',
	water: '#DEF3FD',
	ground: '#f4e7da',
	rock: '#d5d5d4',
	fairy: '#fceaff',
	poison: '#98d7a5',
	bug: '#f8d5a3',
	dragon: '#97b3e6',
	psychic: '#eaeda1',
	flying: '#F5F5F5',
	fighting: '#E6E0D4',
	normal: '#F5F5F5'
}

const main_types = Object.keys(colors)

const fetchPokemons = async () => {
    for(let i = 1; i <= pokemon_count; i++) {
        await getPokemon(i)
    }
}

const getPokemon = async (id) => {
    const url = `https://pokeapi.co/api/v2/pokemon/${id}`
    const res = await fetch(url)
    const data = await res.json()
    createPokemonCard(data)
}

const createPokemonCard = (pokemon) => {
    const pokemonEl = document.createElement('div')
    pokemonEl.classList.add('pokemon')

    const name = pokemon.name[0].toUpperCase() + pokemon.name.slice(1)
    const id = pokemon.id.toString().padStart(3, '0')

    const poke_types = pokemon.types.map(type => type.type.name)
    const type = main_types.find(type => poke_types.indexOf(type) > -1)
    const color = colors[type]

    pokemonEl.style.backgroundColor = color

    const pokemonInnerHTML = `
    <div class="img-container">
        <img src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png"" alt="${name}">
    </div>
    <div class="info">
        <span class="number">#${id}</span>
        <h3 class="name">${name}</h3>
        <small class="type">Type: <span>${type}</span> </small>
    </div>
    `

    pokemonEl.innerHTML = pokemonInnerHTML

    poke_container.appendChild(pokemonEl)
}

fetchPokemons()


================================================
FILE: pokedex/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Lato:300,400&display=swap');

* {
  box-sizing: border-box;
}

body {
  background: #efefbb;
  background: linear-gradient(to right, #d4d3dd, #efefbb);
  font-family: 'Lato', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin: 0;
}

h1 {
  letter-spacing: 3px;
}

.poke-container {
  display: flex;
  flex-wrap: wrap;
  align-items: space-between;
  justify-content: center;
  margin: 0 auto;
  max-width: 1200px;
}

.pokemon {
  background-color: #eee;
  border-radius: 10px;
  box-shadow: 0 3px 15px rgba(100, 100, 100, 0.5);
  margin: 10px;
  padding: 20px;
  text-align: center;
}

.pokemon .img-container {
  background-color: rgba(255, 255, 255, 0.6);
  border-radius: 50%;
  width: 120px;
  height: 120px;
  text-align: center;
}

.pokemon .img-container img {
  max-width: 90%;
  margin-top: 20px;
}

.pokemon .info {
  margin-top: 20px;
}

.pokemon .info .number {
  background-color: rgba(0, 0, 0, 0.1);
  padding: 5px 10px;
  border-radius: 10px;
  font-size: 0.8em;
}

.pokemon .info .name {
  margin: 15px 0 7px;
  letter-spacing: 1px;
}


================================================
FILE: progress-steps/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Progress Steps</title>
  </head>
  <body>
    <div class="container">
      <div class="progress-container">
        <div class="progress" id="progress"></div>
        <div class="circle active">1</div>
        <div class="circle">2</div>
        <div class="circle">3</div>
        <div class="circle">4</div>
      </div>

      <button class="btn" id="prev" disabled>Prev</button>
      <button class="btn" id="next">Next</button>
    </div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: progress-steps/script.js
================================================
const progress = document.getElementById('progress')
const prev = document.getElementById('prev')
const next = document.getElementById('next')
const circles = document.querySelectorAll('.circle')

let currentActive = 1

next.addEventListener('click', () => {
    currentActive++

    if(currentActive > circles.length) {
        currentActive = circles.length
    }

    update()
})

prev.addEventListener('click', () => {
    currentActive--

    if(currentActive < 1) {
        currentActive = 1
    }

    update()
})

function update() {
    circles.forEach((circle, idx) => {
        if(idx < currentActive) {
            circle.classList.add('active')
        } else {
            circle.classList.remove('active')
        }
    })

    const actives = document.querySelectorAll('.active')

    progress.style.width = (actives.length - 1) / (circles.length - 1) * 100 + '%'

    if(currentActive === 1) {
        prev.disabled = true
    } else if(currentActive === circles.length) {
        next.disabled = true
    } else {
        prev.disabled = false
        next.disabled = false
    }
}

================================================
FILE: progress-steps/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');

:root {
  --line-border-fill: #3498db;
  --line-border-empty: #383838;

}

* {
  box-sizing: border-box;
}

body {
  background-color: #f1f1f1;
  font-family: 'Muli', sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.container {
  text-align: center;
}

.progress-container {
  display: flex;
  justify-content: space-between;
  position: relative;
  margin-bottom: 30px;
  max-width: 100%;
  width: 350px;
}

.progress-container::before {
  content: '';
  background-color: var(--line-border-empty);
  position: absolute;
  top: 50%;
  left: 0;
  transform: translateY(-50%);
  height: 4px;
  width: 100%;
  z-index: -1;
}

.progress {
  background-color: var(--line-border-fill);
  position: absolute;
  top: 50%;
  left: 0;
  transform: translateY(-50%);
  height: 4px;
  width: 0%;
  z-index: -1;
  transition: 0.4s ease;
}

.circle {
  background-color: #f1f1f1;
  color:#e2e2e2;
  border-radius: 50%;
  height: 30px;
  width: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 3px solid var(--line-border-empty);
  transition: 0.4s ease;
}

.circle.active {
  border-color: var(--line-border-fill);
}

.btn {
  background-color: var(--line-border-fill);
  color: #fff;
  border: 0;
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
  padding: 8px 30px;
  margin: 5px;
  font-size: 14px;
}

.btn:active {
  transform: scale(0.98);
}

.btn:focus {
  outline: 0;
}

.btn:disabled {
  background-color: var(--line-border-empty);
  cursor: not-allowed;
}


================================================
FILE: quiz-app/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Quiz App</title>
  </head>
  <body>
    <div class="quiz-container" id="quiz">
      <div class="quiz-header">
        <h2 id="question">Question text</h2>
        <ul>
          <li>
            <input type="radio" name="answer" id="a" class="answer">
            <label for="a" id="a_text">Question</label>
          </li>

          <li>
            <input type="radio" name="answer" id="b" class="answer">
            <label for="b" id="b_text">Question</label>
          </li>

          <li>
            <input type="radio" name="answer" id="c" class="answer">
            <label for="c" id="c_text">Question</label>
          </li>

          <li>
            <input type="radio" name="answer" id="d" class="answer">
            <label for="d" id="d_text">Question</label>
          </li>
        </ul>
      </div>
      <button id="submit">Submit</button>
    </div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: quiz-app/script.js
================================================
const quizData = [
    {
        question: "Which language runs in a web browser?",
        a: "Java",
        b: "C",
        c: "Python",
        d: "JavaScript",
        correct: "d",
    },
    {
        question: "What does CSS stand for?",
        a: "Central Style Sheets",
        b: "Cascading Style Sheets",
        c: "Cascading Simple Sheets",
        d: "Cars SUVs Sailboats",
        correct: "b",
    },
    {
        question: "What does HTML stand for?",
        a: "Hypertext Markup Language",
        b: "Hypertext Markdown Language",
        c: "Hyperloop Machine Language",
        d: "Helicopters Terminals Motorboats Lamborginis",
        correct: "a",
    },
    {
        question: "What year was JavaScript launched?",
        a: "1996",
        b: "1995",
        c: "1994",
        d: "none of the above",
        correct: "b",
    },
];

const quiz = document.getElementById('quiz')
const answerEls = document.querySelectorAll('.answer')
const questionEl = document.getElementById('question')
const a_text = document.getElementById('a_text')
const b_text = document.getElementById('b_text')
const c_text = document.getElementById('c_text')
const d_text = document.getElementById('d_text')
const submitBtn = document.getElementById('submit')

let currentQuiz = 0
let score = 0

loadQuiz()

function loadQuiz() {
    deselectAnswers()

    const currentQuizData = quizData[currentQuiz]

    questionEl.innerText = currentQuizData.question
    a_text.innerText = currentQuizData.a
    b_text.innerText = currentQuizData.b
    c_text.innerText = currentQuizData.c
    d_text.innerText = currentQuizData.d
}

function deselectAnswers() {
    answerEls.forEach(answerEl => answerEl.checked = false)
}

function getSelected() {
    let answer

    answerEls.forEach(answerEl => {
        if(answerEl.checked) {
            answer = answerEl.id
        }
    })

    return answer
}

submitBtn.addEventListener('click', () => {
    const answer = getSelected()
    
    if(answer) {
        if(answer === quizData[currentQuiz].correct) {
            score++
        }

        currentQuiz++

        if(currentQuiz < quizData.length) {
            loadQuiz()
        } else {
            quiz.innerHTML = `
                <h2>You answered ${score}/${quizData.length} questions correctly</h2>

                <button onclick="location.reload()">Reload</button>
            `
        }
    }
})

================================================
FILE: quiz-app/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: #b8c6db;
  background-image: linear-gradient(315deg, #b8c6db 0%, #f5f7fa 100%);
  font-family: 'Poppins', sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.quiz-container {
  background-color: #fff;
  border-radius: 10px;
  box-shadow: 0 0 10px 2px rgba(100, 100, 100, 0.1);
  width: 600px;
  overflow: hidden;
}

.quiz-header {
  padding: 4rem;
}

h2 {
  padding: 1rem;
  text-align: center;
  margin: 0;
}

ul {
  list-style-type: none;
  padding: 0;
}

ul li {
  font-size: 1.2rem;
  margin: 1rem 0;
}

ul li label {
  cursor: pointer;
}

button {
  background-color: #8e44ad;
  color: #fff;
  border: none;
  display: block;
  width: 100%;
  cursor: pointer;
  font-size: 1.1rem;
  font-family: inherit;
  padding: 1.3rem;
}

button:hover {
  background-color: #732d91;
}

button:focus {
  outline: none;
  background-color: #5e3370;
}


================================================
FILE: random-choice-picker/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Random Choice Picker</title>
  </head>
  <body>
    <div class="container">
      <h3>Enter all of the choices divided by a comma (','). <br> Press enter when you're done</h3>
      <textarea placeholder="Enter choices here..." id="textarea"></textarea>

      <div id="tags"></div>
    </div>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: random-choice-picker/script.js
================================================
const tagsEl = document.getElementById('tags')
const textarea = document.getElementById('textarea')

textarea.focus()

textarea.addEventListener('keyup', (e) => {
    createTags(e.target.value)

    if(e.key === 'Enter') {
        setTimeout(() => {
            e.target.value = ''
        }, 10)

        randomSelect()
    }
})

function createTags(input) {
    const tags = input.split(',').filter(tag => tag.trim() !== '').map(tag => tag.trim())
    
    tagsEl.innerHTML = ''

    tags.forEach(tag => {
        const tagEl = document.createElement('span')
        tagEl.classList.add('tag')
        tagEl.innerText = tag
        tagsEl.appendChild(tagEl)
    })
}

function randomSelect() {
    const times = 30

    const interval = setInterval(() => {
        const randomTag = pickRandomTag()
	
	if (randomTag !== undefined) {
        highlightTag(randomTag)

        setTimeout(() => {
            unHighlightTag(randomTag)
        }, 100)
	}
    }, 100);

    setTimeout(() => {
        clearInterval(interval)

        setTimeout(() => {
            const randomTag = pickRandomTag()

            highlightTag(randomTag)
        }, 100)

    }, times * 100)
}

function pickRandomTag() {
    const tags = document.querySelectorAll('.tag')
    return tags[Math.floor(Math.random() * tags.length)]
}

function highlightTag(tag) {
    tag.classList.add('highlight')
}

function unHighlightTag(tag) {
    tag.classList.remove('highlight')
}


================================================
FILE: random-choice-picker/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: #2b88f0;
  font-family: 'Muli', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

h3 {
  color: #fff;
  margin: 10px 0 20px;
  text-align: center;
}

.container {
  width: 500px;
}

textarea {
  border: none;
  display: block;
  width: 100%;
  height: 100px;
  font-family: inherit;
  padding: 10px;
  margin: 0 0 20px;
  font-size: 16px;
}

textarea:focus {
  outline: none;
}

.tag {
  background-color: #f0932b;
  color: #fff;
  border-radius: 50px;
  padding: 10px 20px;
  margin: 0 5px 10px 0;
  font-size: 14px;
  display: inline-block;
}

.tag.highlight {
  background-color: #273c75;
}


================================================
FILE: random-image-generator/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Random Image Feed</title>
  </head>
  <body>
    <h1 class="title">Random Image Feed</h1>
    <div class="container"></div>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: random-image-generator/script.js
================================================
const container = document.querySelector('.container')
const unsplashURL = 'https://source.unsplash.com/random/'
const rows = 5

for(let i = 0; i < rows * 3; i++) {
    const img = document.createElement('img')
    img.src = `${unsplashURL}${getRandomSize()}`
    container.appendChild(img)
}

function getRandomSize() {
    return `${getRandomNr()}x${getRandomNr()}`
}

function getRandomNr() {
    return Math.floor(Math.random() * 10) + 300
}

================================================
FILE: random-image-generator/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

* {
  box-sizing: border-box;
}

body {
  font-family: 'Roboto', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  margin: 0;
}

.title {
  margin: 10px 0 0;
  text-align: center;
}

.container {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  max-width: 1000px;
}

.container img {
  object-fit: cover;
  margin: 10px;
  height: 300px;
  width: 300px;
  max-width: 100%;
}


================================================
FILE: rotating-nav-animation/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog==" crossorigin="anonymous" />
    <link rel="stylesheet" href="style.css" />
    <title>Rotating Navigation</title>
  </head>
  <body>
    <div class="container">
      <div class="circle-container">
        <div class="circle">
          <button id="close">
            <i class="fas fa-times"></i>
          </button>
          <button id="open">
            <i class="fas fa-bars"></i>
          </button>
        </div>
      </div>

      <div class="content">
        <h1>Amazing Article</h1>
        <small>Florin Pop</small>
        <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusantium quia in ratione dolores cupiditate, maxime aliquid impedit dolorem nam dolor omnis atque fuga labore modi veritatis porro laborum minus, illo, maiores recusandae cumque ipsa quos. Tenetur, consequuntur mollitia labore pariatur sunt quia harum aut. Eum maxime dolorem provident natus veritatis molestiae cumque quod voluptates ab non, tempore cupiditate? Voluptatem, molestias culpa. Corrupti, laudantium iure aliquam rerum sint nam quas dolor dignissimos in error placeat quae temporibus minus optio eum soluta cupiditate! Cupiditate saepe voluptates laudantium. Ducimus consequuntur perferendis consequatur nobis exercitationem molestias fugiat commodi omnis. Asperiores quia tenetur nemo ipsa.</p>

        <h3>My Dog</h3>
        <img src="https://images.unsplash.com/photo-1507146426996-ef05306b995a?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2100&q=80" alt="doggy" />
        <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Sit libero deleniti rerum quo, incidunt vel consequatur culpa ullam. Magnam facere earum unde harum. Ea culpa veritatis magnam at aliquid. Perferendis totam placeat molestias illo laudantium? Minus id minima doloribus dolorum fugit deserunt qui vero voluptas, ut quia cum amet temporibus veniam ad ea ab perspiciatis, enim accusamus asperiores explicabo provident. Voluptates sint, neque fuga cum illum, tempore autem maxime similique laborum odio, magnam esse. Aperiam?</p>
      </div>
    </div>

    <nav>
      <ul>
        <li><i class="fas fa-home"></i><a href="#"> Home</a></li>
        <li><i class="fas fa-user-alt"></i><a href="#"> About</a></li>
        <li><i class="fas fa-envelope"></i><a href="#"> Contact</a></li>
      </ul>
    </nav>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: rotating-nav-animation/script.js
================================================
const open = document.getElementById('open')
const close = document.getElementById('close')
const container = document.querySelector('.container')

open.addEventListener('click', () => container.classList.add('show-nav'))

close.addEventListener('click', () => container.classList.remove('show-nav'))

================================================
FILE: rotating-nav-animation/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Lato&display=swap');

* {
  box-sizing: border-box;
}

body {
  font-family: 'Lato', sans-serif;
  background-color: #333;
  color: #222;
  overflow-x: hidden;
  margin: 0;
}

.container {
  background-color: #fafafa;
  transform-origin: top left;
  transition: transform 0.5s linear;
  width: 100vw;
  min-height: 100vh;
  padding: 50px;
}

.container.show-nav {
  transform: rotate(-20deg);
}

.circle-container {
  position: fixed;
  top: -100px;
  left: -100px;
}

.circle {
  background-color: #ff7979;
  height: 200px;
  width: 200px;
  border-radius: 50%;
  position: relative;
  transition: transform 0.5s linear;
}

.container.show-nav .circle {
  transform: rotate(-70deg);
}

.circle button {
  cursor: pointer;
  position: absolute;
  top: 50%;
  left: 50%;
  height: 100px;
  background: transparent;
  border: 0;
  font-size: 26px;
  color: #fff;
}

.circle button:focus {
  outline: none;
}

.circle button#open {
  left: 60%;
}

.circle button#close {
  top: 60%;
  transform: rotate(90deg);
  transform-origin: top left;
}

.container.show-nav + nav li {
  transform: translateX(0);
  transition-delay: 0.3s;
}

nav {
  position: fixed;
  bottom: 40px;
  left: 0;
  z-index: 100;
}

nav ul {
  list-style-type: none;
  padding-left: 30px;
}

nav ul li {
  text-transform: uppercase;
  color: #fff;
  margin: 40px 0;
  transform: translateX(-100%);
  transition: transform 0.4s ease-in;
}

nav ul li i {
  font-size: 20px;
  margin-right: 10px;
}

nav ul li + li {
  margin-left: 15px;
  transform: translateX(-150%);
}

nav ul li + li + li {
  margin-left: 30px;
  transform: translateX(-200%);
}

nav a{
  color: #fafafa;
  text-decoration: none;
  transition: all 0.5s;
}

nav a:hover {
  color: #FF7979;
  font-weight: bold;
}

.content img {
  max-width: 100%;
}

.content {
  max-width: 1000px;
  margin: 50px auto;
}

.content h1 {
  margin: 0;
}

.content small {
  color: #555;
  font-style: italic;
}

.content p {
  color: #333;
  line-height: 1.5;
}


================================================
FILE: scroll-animation/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Scroll Animation</title>
  </head>
  <body>
    <h1>Scroll to see the animation</h1>
    <div class="box"><h2>Content</h2></div>
    <div class="box"><h2>Content</h2></div>
    <div class="box"><h2>Content</h2></div>
    <div class="box"><h2>Content</h2></div>
    <div class="box"><h2>Content</h2></div>
    <div class="box"><h2>Content</h2></div>
    <div class="box"><h2>Content</h2></div>
    <div class="box"><h2>Content</h2></div>
    <div class="box"><h2>Content</h2></div>
    <div class="box"><h2>Content</h2></div>
    <div class="box"><h2>Content</h2></div>
    <div class="box"><h2>Content</h2></div>
    <div class="box"><h2>Content</h2></div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: scroll-animation/script.js
================================================
const boxes = document.querySelectorAll('.box')

window.addEventListener('scroll', checkBoxes)

checkBoxes()

function checkBoxes() {
    const triggerBottom = window.innerHeight / 5 * 4

    boxes.forEach(box => {
        const boxTop = box.getBoundingClientRect().top

        if(boxTop < triggerBottom) {
            box.classList.add('show')
        } else {
            box.classList.remove('show')
        }
    })
}

================================================
FILE: scroll-animation/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: #efedd6;
  font-family: 'Roboto', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin: 0;
  overflow-x: hidden;
}

h1 {
  margin: 10px;
}

.box {
  background-color: steelblue;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 400px;
  height: 200px;
  margin: 10px;
  border-radius: 10px;
  box-shadow: 2px 4px 5px rgba(0, 0, 0, 0.3);
  transform: translateX(400%);
  transition: transform 0.4s ease;
}

.box:nth-of-type(even) {
  transform: translateX(-400%);
}

.box.show {
  transform: translateX(0);
}

.box h2 {
  font-size: 45px;
}


================================================
FILE: simple-timer/index.html
================================================
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <script src="https://cdn.tailwindcss.com"></script>
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
      integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA=="
      crossorigin="anonymous"
      referrerpolicy="no-referrer"
    />
    <link rel="stylesheet" href="style.css" />
    <title>Simple Timer</title>
  </head>

  <body class="bg-gray-700 flex justify-center items-center min-h-screen">
    <div class="bg-gray-900 p-16 rounded-2xl shadow w-full max-w-sm">
      <h1 class="text-4xl text-center text-white">Timer</h1>

      <!-- Create the circle -->
      <div
        id="conic"
        class="bg-conic flex items-center justify-center w-60 h-60 mx-auto my-10 rounded-full relative"
      >
        <p id="timer" class="text-blue-200 relative text-5xl z-10">00:00</p>

        <!-- Create the inner cirlce and line -->
        <div
          class="w-[calc(100%-4px)] aspect-square bg-gray-800 rounded-full absolute inset-[2px]"
        ></div>
        <!-- Create the hand/marker -->
        <div class="hand h-1/2 absolute top-0">
          <span
            class="w-2 h-2 bg-white rounded-full absolute -top-1 -left-1"
          ></span>
        </div>
      </div>

      <div class="flex justify-center gap-6">
        <button
          id="reset"
          class="flex justify-center items-center w-10 h-10 bg-blue-300 rounded-full"
        >
          <i class="fas fa-refresh"></i>
        </button>

        <button
          id="play"
          class="flex justify-center items-center w-10 h-10 bg-blue-300 rounded-full group"
        >
          <i class="fas fa-play"></i>
        </button>
      </div>
    </div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: simple-timer/script.js
================================================
const resetBtn = document.querySelector('#reset');
const playBtn = document.querySelector('#play');
const timerEl = document.querySelector('#timer');
const root = document.querySelector(':root');

// Initial setup
const totalSeconds = 60;
let playing = false;
let currentSeconds = totalSeconds;
timerEl.innerText = formatTime(totalSeconds);

const timerInterval = setInterval(run, 1000);

playBtn.addEventListener('click', () => {
  playing = !playing;
  playBtn.classList.toggle('play');
  playBtn.classList.toggle('bg-green-500'); // Toggle the color class
  const playIcon = playBtn.querySelector('i');
  playIcon.classList.toggle('fa-play'); // Toggle the play icon
  playIcon.classList.toggle('fa-pause'); // Toggle the pause icon
});
resetBtn.addEventListener('click', resetAll);

// Run the timer
function run() {
  if (playing) {
    currentSeconds -= 1;
    if (currentSeconds <= 0) {
      clearInterval(timerInterval);
      resetAll();
    }

    timerEl.innerText = formatTime(currentSeconds);
    root.style.setProperty('--degrees', calcDeg());
  }
}

// Format the time
function formatTime(seconds) {
  const minutes = Math.floor(seconds / 60);
  const newSeconds = seconds % 60;

  return `${minutes.toString().padStart(2, '0')}:${newSeconds
    .toString()
    .padStart(2, '0')}`;
}

// Calculate the degrees
function calcDeg() {
  return `${360 - (currentSeconds / totalSeconds) * 360}deg`;
}

// Reset all the values
function resetAll() {
  playing = false;
  playBtn.classList.remove('play');
  playBtn.classList.remove('bg-green-500'); // Remove the color class
  const playIcon = playBtn.querySelector('i');
  playIcon.classList.remove('fa-pause'); // Remove the pause icon
  playIcon.classList.add('fa-play'); // Add the play icon
  currentSeconds = totalSeconds;
  timerEl.innerText = formatTime(totalSeconds);
  root.style.setProperty('--degrees', '0deg');
}


================================================
FILE: simple-timer/style.css
================================================
:root {
  --degrees: 0deg;
}

.bg-conic {
  background: conic-gradient(
    transparent 0deg,
    transparent var(--degrees),
    white var(--degrees),
    white 360deg
  );
}

.hand {
  transform-origin: bottom center;
  transform: rotate(var(--degrees));
}


================================================
FILE: sound-board/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Sound Board</title>
  </head>
  <body>
    <audio id="applause" src="sounds/applause.mp3"></audio>
    <audio id="boo" src="sounds/boo.mp3"></audio>
    <audio id="gasp" src="sounds/gasp.mp3"></audio>
    <audio id="tada" src="sounds/tada.mp3"></audio>
    <audio id="victory" src="sounds/victory.mp3"></audio>
    <audio id="wrong" src="sounds/wrong.mp3"></audio>

    <div id="buttons"></div>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: sound-board/script.js
================================================
const sounds = ['applause', 'boo', 'gasp', 'tada', 'victory', 'wrong']

sounds.forEach(sound => {
    const btn = document.createElement('button')
    btn.classList.add('btn')

    btn.innerText = sound

    btn.addEventListener('click', () => {
        stopSongs()

        document.getElementById(sound).play()
    })

    document.getElementById('buttons').appendChild(btn)
})

function stopSongs() {
    sounds.forEach(sound => {
        const song = document.getElementById(sound)

        song.pause()
        song.currentTime = 0;
    })
}

================================================
FILE: sound-board/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: rgb(161, 100, 223);
  font-family: 'Poppins', sans-serif;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  text-align: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.btn {
  background-color: rebeccapurple;
  border-radius: 5px;
  border: none;
  color: #fff;
  margin: 1rem;
  padding: 1.5rem 3rem;
  font-size: 1.2rem;
  font-family: inherit;
  cursor: pointer;
}

.btn:hover {
  opacity: 0.9;
}

.btn:focus {
  outline: none;
}


================================================
FILE: split-landing-page/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Split Landing Page
    </title>
  </head>
  <body>
    <div class="container">
      <div class="split left">
        <h1>Playstation 5</h1>
        <a href="#" class="btn">Buy Now</a>
      </div>
      <div class="split right">
        <h1>XBox Series X</h1>
        <a href="#" class="btn">Buy Now</a>
      </div>
    </div>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: split-landing-page/script.js
================================================
const left = document.querySelector('.left')
const right = document.querySelector('.right')
const container = document.querySelector('.container')

left.addEventListener('mouseenter', () => container.classList.add('hover-left'))
left.addEventListener('mouseleave', () => container.classList.remove('hover-left'))

right.addEventListener('mouseenter', () => container.classList.add('hover-right'))
right.addEventListener('mouseleave', () => container.classList.remove('hover-right'))

================================================
FILE: split-landing-page/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

:root {
  --left-bg-color: rgba(87, 84, 236, 0.7);
  --right-bg-color: rgba(43, 43, 43, 0.8);
  --left-btn-hover-color: rgba(87, 84, 236, 1);
  --right-btn-hover-color: rgba(28, 122, 28, 1);
  --hover-width: 75%;
  --other-width: 25%;
  --speed: 1000ms;
}

* {
  box-sizing: border-box;
}

body {
  font-family: 'Roboto', sans-serif;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

h1 {
  font-size: 4rem;
  color: #fff;
  position: absolute;
  left: 50%;
  top: 20%;
  transform: translateX(-50%);
  white-space: nowrap;
}

.btn {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  left: 50%;
  top: 40%;
  transform: translateX(-50%);
  text-decoration: none;
  color: #fff;
  border: #fff solid 0.2rem;
  font-size: 1rem;
  font-weight: bold;
  text-transform: uppercase;
  width: 15rem;
  padding: 1.5rem;
}

.split.left .btn:hover {
  background-color: var(--left-btn-hover-color);
  border-color: var(--left-btn-hover-color);
}

.split.right .btn:hover {
  background-color: var(--right-btn-hover-color);
  border-color: var(--right-btn-hover-color);
}

.container {
  position: relative;
  width: 100%;
  height: 100%;
  background: #333;
}

.split {
  position: absolute;
  width: 50%;
  height: 100%;
  overflow: hidden;
}

.split.left {
  left: 0;
  background: url('ps.jpg');
  background-repeat: no-repeat;
  background-size: cover;
}

.split.left::before {
  content: '';
  position: absolute;
  width: 100%;
  height: 100%;
  background-color: var(--left-bg-color);
}

.split.right {
  right: 0;
  background: url('xbox.jpg');
  background-repeat: no-repeat;
  background-size: cover;
}

.split.right::before {
  content: '';
  position: absolute;
  width: 100%;
  height: 100%;
  background-color: var(--right-bg-color);
}

.split.right,
.split.left,
.split.right::before,
.split.left::before {
  transition: all var(--speed) ease-in-out;
}

.hover-left .left {
  width: var(--hover-width);
}

.hover-left .right {
  width: var(--other-width);
}

.hover-right .right {
  width: var(--hover-width);
}

.hover-right .left {
  width: var(--other-width);
}

@media (max-width: 800px) {
  h1 {
    font-size: 2rem;
    top: 30%;
  }

  .btn {
    padding: 1.2rem;
    width: 12rem;
  }
}


================================================
FILE: sticky-navigation/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Sticky Navigation</title>
  </head>
  <body>
    <nav class="nav">
      <div class="container">
        <h1 class="logo"><a href="/index.html">My Website</a></h1>
        <ul>
          <li><a href="#" class="current">Home</a></li>
          <li><a href="#">About</a></li>
          <li><a href="#">Services</a></li>
          <li><a href="#">Contact</a></li>
        </ul>
      </div>
    </nav>

    <div class="hero">
      <div class="container">
        <h1>Welcome To My Website</h1>
        <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Maiores, consequuntur?</p>
      </div>
    </div>

    <section class="container content">
      <h2>Content One</h2>
      <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Ratione dolorem voluptates eveniet tempora ut cupiditate magnam, sapiente, hic quo in ipsum iste soluta eaque perferendis nihil recusandae dolore officia aperiam corporis similique. Facilis quos tempore labore totam! Consectetur molestiae iusto ducimus error reiciendis aspernatur dolor, modi dolorem sit architecto, voluptate magni sunt unde est quas? Voluptates a dolorum voluptatum quo perferendis aut sit. Aspernatur libero laboriosam ab eligendi omnis delectus earum labore, placeat officiis sint illum rem voluptas ipsum repellendus iste eius recusandae quae excepturi facere, iure rerum sequi? Illum velit delectus dicta et iste dolorum obcaecati minus odio eligendi!</p>

      <h3>Content Two</h3>
      <p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Pariatur provident nostrum possimus inventore nisi laboriosam consequatur modi nulla eos, commodi, omnis distinctio! Maxime distinctio impedit provident, voluptates illo odio nostrum minima beatae similique a sint sapiente voluptatum atque optio illum est! Tenetur tempora doloremque quae iste aperiam hic cumque repellat?</p>
    </section>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: sticky-navigation/script.js
================================================
const nav = document.querySelector('.nav')
window.addEventListener('scroll', fixNav)

function fixNav() {
    if(window.scrollY > nav.offsetHeight + 150) {
        nav.classList.add('active')
    } else {
        nav.classList.remove('active')
    }
}

================================================
FILE: sticky-navigation/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Open+Sans');

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: 'Open Sans', sans-serif;
  color: #222;
  padding-bottom: 50px;
}

.container {
  max-width: 1200px;
  margin: 0 auto;
}

.nav {
  position: fixed;
  background-color: #222;
  top: 0;
  left: 0;
  right: 0;
  transition: all 0.3s ease-in-out;
}

.nav .container {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 20px 0;
  transition: all 0.3s ease-in-out;
}

.nav ul {
  display: flex;
  list-style-type: none;
  align-items: center;
  justify-content: center;
}

.nav a {
  color: #fff;
  text-decoration: none;
  padding: 7px 15px;
  transition: all 0.3s ease-in-out;
}

.nav.active {
  background-color: #fff;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}

.nav.active a {
  color: #000;
}

.nav.active .container {
  padding: 10px 0;
}

.nav a.current,
.nav a:hover {
  color: #c0392b;
  font-weight: bold;
}

.hero {
  background-image: url('https://images.pexels.com/photos/450035/pexels-photo-450035.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260');
  background-repeat: no-repeat;
  background-size: cover;
  background-position: bottom center;
  height: 100vh;
  color: #fff;
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
  position: relative;
  margin-bottom: 20px;
  z-index: -2;
}

.hero::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  z-index: -1;
}

.hero h1 {
  font-size: 46px;
  margin: -20px 0 20px;
}

.hero p {
  font-size: 20px;
  letter-spacing: 1px;
}

.content h2,
.content h3 {
  font-size: 150%;
  margin: 20px 0;
}

.content p {
  color: #555;
  line-height: 30px;
  letter-spacing: 1.2px;
}


================================================
FILE: testimonial-box-switcher/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css"
      integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog=="
      crossorigin="anonymous"
    />
    <link rel="stylesheet" href="style.css" />
    <title>Testimonial Box</title>
  </head>
  <body>
    <div class="testimonial-container">
      <div class="progress-bar"></div>
      <div class="fas fa-quote-right fa-quote"></div>
      <div class="fas fa-quote-left fa-quote"></div>
      <p class="testimonial">
        I've worked with literally hundreds of HTML/CSS developers and I have to
        say the top spot goes to this guy. This guy is an amazing developer. He
        stresses on good, clean code and pays heed to the details. I love
        developers who respect each and every aspect of a throughly thought out
        design and do their best to put it in code. He goes over and beyond and
        transforms ART into PIXELS - without a glitch, every time.
      </p>
      <div class="user">
        <img
          src="https://randomuser.me/api/portraits/women/46.jpg"
          alt="user"
          class="user-image"
        />
        <div class="user-details">
          <h4 class="username">Miyah Myles</h4>
          <p class="role">Marketing</p>
        </div>
      </div>
    </div>
    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: testimonial-box-switcher/script.js
================================================
const testimonialsContainer = document.querySelector('.testimonials-container')
const testimonial = document.querySelector('.testimonial')
const userImage = document.querySelector('.user-image')
const username = document.querySelector('.username')
const role = document.querySelector('.role')

const testimonials = [
  {
    name: 'Miyah Myles',
    position: 'Marketing',
    photo:
      'https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&s=707b9c33066bf8808c934c8ab394dff6',
    text:
      "I've worked with literally hundreds of HTML/CSS developers and I have to say the top spot goes to this guy. This guy is an amazing developer. He stresses on good, clean code and pays heed to the details. I love developers who respect each and every aspect of a throughly thought out design and do their best to put it in code. He goes over and beyond and transforms ART into PIXELS - without a glitch, every time.",
  },
  {
    name: 'June Cha',
    position: 'Software Engineer',
    photo: 'https://randomuser.me/api/portraits/women/44.jpg',
    text:
      'This guy is an amazing frontend developer that delivered the task exactly how we need it, do your self a favor and hire him, you will not be disappointed by the work delivered. He will go the extra mile to make sure that you are happy with your project. I will surely work again with him!',
  },
  {
    name: 'Iida Niskanen',
    position: 'Data Entry',
    photo: 'https://randomuser.me/api/portraits/women/68.jpg',
    text:
      "This guy is a hard worker. Communication was also very good with him and he was very responsive all the time, something not easy to find in many freelancers. We'll definitely repeat with him.",
  },
  {
    name: 'Renee Sims',
    position: 'Receptionist',
    photo: 'https://randomuser.me/api/portraits/women/65.jpg',
    text:
      "This guy does everything he can to get the job done and done right. This is the second time I've hired him, and I'll hire him again in the future.",
  },
  {
    name: 'Jonathan Nunfiez',
    position: 'Graphic Designer',
    photo: 'https://randomuser.me/api/portraits/men/43.jpg',
    text:
      "I had my concerns that due to a tight deadline this project can't be done. But this guy proved me wrong not only he delivered an outstanding work but he managed to deliver 1 day prior to the deadline. And when I asked for some revisions he made them in MINUTES. I'm looking forward to work with him again and I totally recommend him. Thanks again!",
  },
  {
    name: 'Sasha Ho',
    position: 'Accountant',
    photo:
      'https://images.pexels.com/photos/415829/pexels-photo-415829.jpeg?h=350&auto=compress&cs=tinysrgb',
    text:
      'This guy is a top notch designer and front end developer. He communicates well, works fast and produces quality work. We have been lucky to work with him!',
  },
  {
    name: 'Veeti Seppanen',
    position: 'Director',
    photo: 'https://randomuser.me/api/portraits/men/97.jpg',
    text:
      'This guy is a young and talented IT professional, proactive and responsible, with a strong work ethic. He is very strong in PSD2HTML conversions and HTML/CSS technology. He is a quick learner, eager to learn new technologies. He is focused and has the good dynamics to achieve due dates and outstanding results.',
  },
]

let idx = 1

function updateTestimonial() {
  const { name, position, photo, text } = testimonials[idx]

  testimonial.innerHTML = text
  userImage.src = photo
  username.innerHTML = name
  role.innerHTML = position

  idx++

  if (idx > testimonials.length - 1) {
    idx = 0
  }
}

setInterval(updateTestimonial, 10000)


================================================
FILE: testimonial-box-switcher/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Montserrat');

* {
  box-sizing: border-box;
}

body {
  background-color: #f4f4f4;
  font-family: 'Montserrat', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
  padding: 10px;
}

.testimonial-container {
  background-color: #476ce4;
  color: #fff;
  border-radius: 15px;
  margin: 20px auto;
  padding: 50px 80px;
  max-width: 768px;
  position: relative;
}

.fa-quote {
  color: rgba(255, 255, 255, 0.3);
  font-size: 28px;
  position: absolute;
  top: 70px;
}

.fa-quote-right {
  left: 40px;
}

.fa-quote-left {
  right: 40px;
}

.testimonial {
  line-height: 28px;
  text-align: justify;
}

.user {
  display: flex;
  align-items: center;
  justify-content: center;
}

.user .user-image {
  border-radius: 50%;
  height: 75px;
  width: 75px;
  object-fit: cover;
}

.user .user-details {
  margin-left: 10px;
}

.user .username {
  margin: 0;
}

.user .role {
  font-weight: normal;
  margin: 10px 0;
}

.progress-bar {
  background-color: #fff;
  height: 4px;
  width: 100%;
  animation: grow 10s linear infinite;
  transform-origin: left;
}

@keyframes grow {
  0% {
    transform: scaleX(0);
  }
}

@media (max-width: 768px) {
  .testimonial-container {
    padding: 20px 30px;
  }

  .fa-quote {
    display: none;
  }
}


================================================
FILE: theme-clock/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Theme Clock</title>
  </head>
  <body>
    <!-- Inspired by this dribbble shot https://dribbble.com/shots/5958443-Alarm-clock -->

    <button class="toggle">Dark mode</button>

    <div class="clock-container">
      <div class="clock">
        <div class="needle hour"></div>
        <div class="needle minute"></div>
        <div class="needle second"></div>
        <div class="center-point"></div>
      </div>

      <div class="time"></div>
      <div class="date"></div>
    </div>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: theme-clock/script.js
================================================
const hourEl = document.querySelector('.hour')
const minuteEl = document.querySelector('.minute')
const secondEl = document.querySelector('.second')
const timeEl = document.querySelector('.time')
const dateEl = document.querySelector('.date')
const toggle = document.querySelector('.toggle')

const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

toggle.addEventListener('click', (e) => {
    const html = document.querySelector('html')
    if (html.classList.contains('dark')) {
        html.classList.remove('dark')
        e.target.innerHTML = 'Dark mode'
    } else {
        html.classList.add('dark')
        e.target.innerHTML = 'Light mode'
    }
})

function setTime() {
    const time = new Date();
    const month = time.getMonth()
    const day = time.getDay()
    const date = time.getDate()
    const hours = time.getHours()
    const hoursForClock = hours >= 13 ? hours % 12 : hours;
    const minutes = time.getMinutes()
    const seconds = time.getSeconds()
    const ampm = hours >= 12 ? 'PM' : 'AM'

    hourEl.style.transform = `translate(-50%, -100%) rotate(${scale(hoursForClock, 0, 12, 0, 360)}deg)`
    minuteEl.style.transform = `translate(-50%, -100%) rotate(${scale(minutes, 0, 60, 0, 360)}deg)`
    secondEl.style.transform = `translate(-50%, -100%) rotate(${scale(seconds, 0, 60, 0, 360)}deg)`

    timeEl.innerHTML = `${hoursForClock}:${minutes < 10 ? `0${minutes}` : minutes} ${ampm}`
    dateEl.innerHTML = `${days[day]}, ${months[month]} <span class="circle">${date}</span>`
}

// StackOverflow https://stackoverflow.com/questions/10756313/javascript-jquery-map-a-range-of-numbers-to-another-range-of-numbers
const scale = (num, in_min, in_max, out_min, out_max) => {
    return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

setTime()

setInterval(setTime, 1000)


================================================
FILE: theme-clock/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Heebo:300&display=swap');

* {
  box-sizing: border-box;
}

:root {
  --primary-color: #000;
  --secondary-color: #fff;
}

html {
  transition: all 0.5s ease-in;
}

html.dark {
  --primary-color: #fff;
  --secondary-color: #333;
}

html.dark {
  background-color: #111;
  color: var(--primary-color);
}

body {
  font-family: 'Heebo', sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.toggle {
  cursor: pointer;
  background-color: var(--primary-color);
  color: var(--secondary-color);
  border: 0;
  border-radius: 4px;
  padding: 8px 12px;
  position: absolute;
  top: 100px;
}

.toggle:focus {
  outline: none;
}

.clock-container {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
}

.clock {
  position: relative;
  width: 200px;
  height: 200px;
}

.needle {
  background-color: var(--primary-color);
  position: absolute;
  top: 50%;
  left: 50%;
  height: 65px;
  width: 3px;
  transform-origin: bottom center;
  transition: all 0.5s ease-in linear;
}

.needle.hour {
  transform: translate(-50%, -100%) rotate(0deg);
}

.needle.minute {
  transform: translate(-50%, -100%) rotate(0deg);
  height: 100px;
}

.needle.second {
  transform: translate(-50%, -100%) rotate(0deg);
  height: 100px;
  background-color: #e74c3c;
}

.center-point {
  background-color: #e74c3c;
  width: 10px;
  height: 10px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
}

.center-point::after {
  content: '';
  background-color: var(--primary-color);
  width: 5px;
  height: 5px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
}

.time {
  font-size: 60px;
}

.date {
  color: #aaa;
  font-size: 14px;
  letter-spacing: 0.3px;
  text-transform: uppercase;
}

.date .circle {
  background-color: var(--primary-color);
  color: var(--secondary-color);
  border-radius: 50%;
  height: 18px;
  width: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 18px;
  transition: all 0.5s ease-in;
  font-size: 12px;
}

================================================
FILE: toast-notification/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Toast Notification</title>
  </head>
  <body>
    <div id="toasts"></div>

    <button class="btn" id="button">Show Notification</button>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: toast-notification/script.js
================================================
const button = document.getElementById('button')
const toasts = document.getElementById('toasts')

const messages = [
    'Message One',
    'Message Two',
    'Message Three',
    'Message Four',
]

const types = ['info', 'success', 'error']

button.addEventListener('click', () => createNotification())

function createNotification(message = null, type = null) {
    const notif = document.createElement('div')
    notif.classList.add('toast')
    notif.classList.add(type ? type : getRandomType())

    notif.innerText = message ? message : getRandomMessage()

    toasts.appendChild(notif)

    setTimeout(() => {
        notif.remove()
    }, 3000)
}

function getRandomMessage() {
    return messages[Math.floor(Math.random() * messages.length)]
}

function getRandomType() {
    return types[Math.floor(Math.random() * types.length)]
}

================================================
FILE: toast-notification/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: rebeccapurple;
  font-family: 'Poppins', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

.btn {
  background-color: #ffffff;
  color: rebeccapurple;
  font-family: inherit;
  font-weight: bold;
  padding: 1rem;
  border-radius: 5px;
  border: none;
  cursor: pointer;
}

.btn:focus {
  outline: none;
}

.btn:active {
  transform: scale(0.98);
}

#toasts {
  position: fixed;
  bottom: 10px;
  right: 10px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}

.toast {
  background-color: #fff;
  border-radius: 5px;
  padding: 1rem 2rem;
  margin: 0.5rem;
}

.toast.info {
  color: rebeccapurple;
}

.toast.success {
  color: green;
}

.toast.error {
  color: red;
}


================================================
FILE: todo-list/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Todo List</title>
  </head>
  <body>
    <h1>todos</h1>
    <form id="form">
      <input type="text" class="input" id="input" placeholder="Enter your todo" autocomplete="off">

      <ul class="todos" id="todos"></ul>
    </form>
    <small>Left click to toggle completed. <br> Right click to delete todo</small>

    <script src="script.js"></script>
  </body>
</html>


================================================
FILE: todo-list/script.js
================================================
const form = document.getElementById('form')
const input = document.getElementById('input')
const todosUL = document.getElementById('todos')

const todos = JSON.parse(localStorage.getItem('todos'))

if(todos) {
    todos.forEach(todo => addTodo(todo))
}

form.addEventListener('submit', (e) => {
    e.preventDefault()

    addTodo()
})

function addTodo(todo) {
    let todoText = input.value

    if(todo) {
        todoText = todo.text
    }

    if(todoText) {
        const todoEl = document.createElement('li')
        if(todo && todo.completed) {
            todoEl.classList.add('completed')
        }

        todoEl.innerText = todoText

        todoEl.addEventListener('click', () => {
            todoEl.classList.toggle('completed')
            updateLS()
        }) 

        todoEl.addEventListener('contextmenu', (e) => {
            e.preventDefault()

            todoEl.remove()
            updateLS()
        }) 

        todosUL.appendChild(todoEl)

        input.value = ''

        updateLS()
    }
}

function updateLS() {
    todosEl = document.querySelectorAll('li')

    const todos = []

    todosEl.forEach(todoEl => {
        todos.push({
            text: todoEl.innerText,
            completed: todoEl.classList.contains('completed')
        })
    })

    localStorage.setItem('todos', JSON.stringify(todos))
}

================================================
FILE: todo-list/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: #f5f5f5;
  color: #444;
  font-family: 'Poppins', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  margin: 0;
}

h1 {
  color: rgb(179, 131, 226);
  font-size: 10rem;
  text-align: center;
  opacity: 0.4;
}

form {
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
  max-width: 100%;
  width: 400px;
}

.input {
  border: none;
  color: #444;
  font-size: 2rem;
  padding: 1rem 2rem;
  display: block;
  width: 100%;
}

.input::placeholder {
  color: #d5d5d5;
}

.input:focus {
  outline-color: rgb(179, 131, 226);
}

.todos {
  background-color: #fff;
  padding: 0;
  margin: 0;
  list-style-type: none;
}

.todos li {
  border-top: 1px solid #e5e5e5;
  cursor: pointer;
  font-size: 1.5rem;
  padding: 1rem 2rem;
}

.todos li.completed {
  color: #b6b6b6;
  text-decoration: line-through;
}

small {
  color: #b5b5b5;
  margin-top: 3rem;
  text-align: center;
}


================================================
FILE: verify-account-ui/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Verify Account</title>
  </head>
  <body>
    <div class="container">
      <h2>Verify Your Account</h2>
      <p>We emailed you the six digit code to cool_guy@email.com <br/> Enter the code below to confirm your email address.</p>
      <div class="code-container">
        <input type="number" class="code" placeholder="0" min="0" max="9" required>
        <input type="number" class="code" placeholder="0" min="0" max="9" required>
        <input type="number" class="code" placeholder="0" min="0" max="9" required>
        <input type="number" class="code" placeholder="0" min="0" max="9" required>
        <input type="number" class="code" placeholder="0" min="0" max="9" required>
        <input type="number" class="code" placeholder="0" min="0" max="9" required>
      </div>
      <small class="info">
        This is design only. We didn't actually send you an email as we don't have your email, right?
      </small>
    </div>
    <script src="script.js"></script>
  </body>
</html>


=====================================
Download .txt
gitextract_82g65fro/

├── .gitignore
├── 3d-boxes-background/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── LICENSE
├── README.md
├── _project_starter_/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── animated-countdown/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── animated-navigation/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── auto-text-effect/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── background-slider/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── blurry-loading/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── button-ripple-effect/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── content-placeholder/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── custom-range-slider/
│   ├── .vscode/
│   │   └── settings.json
│   ├── index.html
│   ├── script.js
│   └── style.css
├── dad-jokes/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── double-click-heart/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── double-vertical-slider/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── drag-n-drop/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── drawing-app/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── drink-water/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── event-keycodes/
│   ├── dark-style.css
│   ├── index.html
│   └── script.js
├── expanding-cards/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── faq-collapse/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── feedback-ui-design/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── form-input-wave/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── github-profiles/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── good-cheap-fast/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── hidden-search/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── hoverboard/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── image-carousel/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── incrementing-counter/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── insect-catch-game/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── kinetic-loader/
│   ├── index.html
│   └── style.css
├── live-user-filter/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── mobile-tab-navigation/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── movie-app/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── netflix-mobile-navigation/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── notes-app/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── password-generator/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── password-strength-background/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── pokedex/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── progress-steps/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── quiz-app/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── random-choice-picker/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── random-image-generator/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── rotating-nav-animation/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── scroll-animation/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── simple-timer/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── sound-board/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── split-landing-page/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── sticky-navigation/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── testimonial-box-switcher/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── theme-clock/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── toast-notification/
│   ├── index.html
│   ├── script.js
│   └── style.css
├── todo-list/
│   ├── index.html
│   ├── script.js
│   └── style.css
└── verify-account-ui/
    ├── index.html
    ├── script.js
    └── style.css
Download .txt
SYMBOL INDEX (85 symbols across 34 files)

FILE: 3d-boxes-background/script.js
  function createBoxes (line 6) | function createBoxes() {

FILE: animated-countdown/script.js
  function resetDOM (line 8) | function resetDOM() {
  function runAnimation (line 19) | function runAnimation() {

FILE: auto-text-effect/script.js
  function writeText (line 9) | function writeText() {

FILE: background-slider/script.js
  function setBgToBody (line 32) | function setBgToBody() {
  function setActiveSlide (line 36) | function setActiveSlide() {

FILE: blurry-loading/script.js
  function blurring (line 8) | function blurring() {

FILE: content-placeholder/script.js
  function getData (line 13) | function getData() {

FILE: dad-jokes/script.js
  function generateJoke (line 9) | async function generateJoke() {

FILE: drag-n-drop/script.js
  function dragStart (line 15) | function dragStart(e) {
  function dragEnd (line 24) | function dragEnd() {
  function dragOver (line 28) | function dragOver(e) {
  function dragEnter (line 32) | function dragEnter(e) {
  function dragLeave (line 37) | function dragLeave() {
  function dragDrop (line 41) | function dragDrop() {

FILE: drawing-app/script.js
  function drawCircle (line 44) | function drawCircle(x, y) {
  function drawLine (line 51) | function drawLine(x1, y1, x2, y2) {
  function updateSizeOnScreen (line 60) | function updateSizeOnScreen() {

FILE: drink-water/script.js
  function highlightCups (line 12) | function highlightCups(idx) {
  function updateBigCup (line 29) | function updateBigCup() {

FILE: expanding-cards/script.js
  function removeActiveClasses (line 10) | function removeActiveClasses() {

FILE: feedback-ui-design/script.js
  function removeActive (line 34) | function removeActive() {

FILE: github-profiles/script.js
  constant APIURL (line 1) | const APIURL = 'https://api.github.com/users/'
  function getUser (line 7) | async function getUser(username) {
  function getRepos (line 20) | async function getRepos(username) {
  function createUserCard (line 30) | function createUserCard(user) {
  function createErrorCard (line 55) | function createErrorCard(msg) {
  function addReposToCard (line 65) | function addReposToCard(repos) {

FILE: good-cheap-fast/script.js
  function doTheTrick (line 8) | function doTheTrick(theClickedOne) {

FILE: hoverboard/script.js
  constant SQUARES (line 3) | const SQUARES = 500
  function setColor (line 16) | function setColor(element) {
  function removeColor (line 22) | function removeColor(element) {
  function getRandomColor (line 27) | function getRandomColor() {

FILE: image-carousel/script.js
  function run (line 11) | function run() {
  function changeImage (line 16) | function changeImage() {
  function resetInterval (line 26) | function resetInterval() {

FILE: insect-catch-game/script.js
  function startGame (line 26) | function startGame() {
  function increaseTime (line 30) | function increaseTime() {
  function createInsect (line 39) | function createInsect() {
  function getRandomLocation (line 52) | function getRandomLocation() {
  function catchInsect (line 60) | function catchInsect() {
  function addInsects (line 67) | function addInsects() {
  function increaseScore (line 72) | function increaseScore() {

FILE: live-user-filter/script.js
  function getData (line 9) | async function getData() {
  function filterData (line 34) | function filterData(searchTerm) {

FILE: mobile-tab-navigation/script.js
  function hideAllContents (line 14) | function hideAllContents() {
  function hideAllItems (line 19) | function hideAllItems() {

FILE: movie-app/script.js
  constant API_URL (line 1) | const API_URL = 'https://api.themoviedb.org/3/discover/movie?sort_by=pop...
  constant IMG_PATH (line 2) | const IMG_PATH = 'https://image.tmdb.org/t/p/w1280'
  constant SEARCH_API (line 3) | const SEARCH_API = 'https://api.themoviedb.org/3/search/movie?api_key=3f...
  function getMovies (line 12) | async function getMovies(url) {
  function showMovies (line 19) | function showMovies(movies) {
  function getClassByRate (line 43) | function getClassByRate(vote) {

FILE: notes-app/script.js
  function addNewNote (line 11) | function addNewNote(text = '') {
  function updateLS (line 55) | function updateLS() {

FILE: password-generator/script.js
  function generatePassword (line 36) | function generatePassword(lower, upper, number, symbol, length) {
  function getRandomLower (line 57) | function getRandomLower() {
  function getRandomUpper (line 61) | function getRandomUpper() {
  function getRandomNumber (line 65) | function getRandomNumber() {
  function getRandomSymbol (line 69) | function getRandomSymbol() {

FILE: progress-steps/script.js
  function update (line 28) | function update() {

FILE: quiz-app/script.js
  function loadQuiz (line 50) | function loadQuiz() {
  function deselectAnswers (line 62) | function deselectAnswers() {
  function getSelected (line 66) | function getSelected() {

FILE: random-choice-picker/script.js
  function createTags (line 18) | function createTags(input) {
  function randomSelect (line 31) | function randomSelect() {
  function pickRandomTag (line 58) | function pickRandomTag() {
  function highlightTag (line 63) | function highlightTag(tag) {
  function unHighlightTag (line 67) | function unHighlightTag(tag) {

FILE: random-image-generator/script.js
  function getRandomSize (line 11) | function getRandomSize() {
  function getRandomNr (line 15) | function getRandomNr() {

FILE: scroll-animation/script.js
  function checkBoxes (line 7) | function checkBoxes() {

FILE: simple-timer/script.js
  function run (line 25) | function run() {
  function formatTime (line 39) | function formatTime(seconds) {
  function calcDeg (line 49) | function calcDeg() {
  function resetAll (line 54) | function resetAll() {

FILE: sound-board/script.js
  function stopSongs (line 18) | function stopSongs() {

FILE: sticky-navigation/script.js
  function fixNav (line 4) | function fixNav() {

FILE: testimonial-box-switcher/script.js
  function updateTestimonial (line 63) | function updateTestimonial() {

FILE: theme-clock/script.js
  function setTime (line 22) | function setTime() {

FILE: toast-notification/script.js
  function createNotification (line 15) | function createNotification(message = null, type = null) {
  function getRandomMessage (line 29) | function getRandomMessage() {
  function getRandomType (line 33) | function getRandomType() {

FILE: todo-list/script.js
  function addTodo (line 17) | function addTodo(todo) {
  function updateLS (line 52) | function updateLS() {
Condensed preview — 159 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (199K chars).
[
  {
    "path": ".gitignore",
    "chars": 9,
    "preview": ".DS_Store"
  },
  {
    "path": "3d-boxes-background/index.html",
    "chars": 678,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "3d-boxes-background/script.js",
    "chars": 479,
    "preview": "const boxesContainer = document.getElementById('boxes')\nconst btn = document.getElementById('btn')\n\nbtn.addEventListener"
  },
  {
    "path": "3d-boxes-background/style.css",
    "chars": 1654,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');\n@import url('https://fonts.goo"
  },
  {
    "path": "LICENSE",
    "chars": 1070,
    "preview": "MIT License\n\nCopyright (c) 2022 Brad Traversy\n\nPermission is hereby granted, free of charge, to any person obtaining a c"
  },
  {
    "path": "README.md",
    "chars": 13044,
    "preview": "# 50 Projects in 50 Days - HTML/CSS and JavaScript\n\nThis is the main repository for all of the projects in the course.\n\n"
  },
  {
    "path": "_project_starter_/index.html",
    "chars": 329,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "_project_starter_/script.js",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "_project_starter_/style.css",
    "chars": 313,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');\n\n* {\n  box-sizing: border-box;"
  },
  {
    "path": "animated-countdown/index.html",
    "chars": 636,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "animated-countdown/script.js",
    "chars": 1011,
    "preview": "const nums = document.querySelectorAll('.nums span')\nconst counter = document.querySelector('.counter')\nconst finalMessa"
  },
  {
    "path": "animated-countdown/style.css",
    "chars": 2528,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');\n\n* {\n  box-sizing: border-box;"
  },
  {
    "path": "animated-navigation/index.html",
    "chars": 766,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "animated-navigation/script.js",
    "chars": 164,
    "preview": "const toggle = document.getElementById('toggle')\nconst nav = document.getElementById('nav')\n\ntoggle.addEventListener('cl"
  },
  {
    "path": "animated-navigation/style.css",
    "chars": 1653,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');\n\n* {\n  box-sizing: border-box;\n}\n\nbody {\n  bac"
  },
  {
    "path": "auto-text-effect/index.html",
    "chars": 492,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "auto-text-effect/script.js",
    "chars": 425,
    "preview": "const textEl = document.getElementById('text')\nconst speedEl = document.getElementById('speed')\nconst text = 'We Love Pr"
  },
  {
    "path": "auto-text-effect/style.css",
    "chars": 632,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');\n\n* {\n  box-sizing: border-box;"
  },
  {
    "path": "background-slider/index.html",
    "chars": 2070,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "background-slider/script.js",
    "chars": 782,
    "preview": "const body = document.body\nconst slides = document.querySelectorAll('.slide')\nconst leftBtn = document.getElementById('l"
  },
  {
    "path": "background-slider/style.css",
    "chars": 1305,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');\n\n* {\n  box-sizing: border-box;"
  },
  {
    "path": "blurry-loading/index.html",
    "chars": 379,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "blurry-loading/script.js",
    "chars": 635,
    "preview": "const loadText = document.querySelector('.loading-text')\nconst bg = document.querySelector('.bg')\n\nlet load = 0\n\nlet int"
  },
  {
    "path": "blurry-loading/style.css",
    "chars": 659,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Ubuntu');\n\n* {\n  box-sizing: border-box;\n}\n\nbody {\n  font-family: '"
  },
  {
    "path": "button-ripple-effect/index.html",
    "chars": 355,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "button-ripple-effect/script.js",
    "chars": 627,
    "preview": "const buttons = document.querySelectorAll('.ripple')\n\nbuttons.forEach(button => {\n    button.addEventListener('click', f"
  },
  {
    "path": "button-ripple-effect/style.css",
    "chars": 908,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');\n\n* {\n  box-sizing: border-box;"
  },
  {
    "path": "content-placeholder/index.html",
    "chars": 1205,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "content-placeholder/script.js",
    "chars": 1129,
    "preview": "const header = document.getElementById('header')\nconst title = document.getElementById('title')\nconst excerpt = document"
  },
  {
    "path": "content-placeholder/style.css",
    "chars": 1481,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');\n\n* {\n  box-sizing: border-box;"
  },
  {
    "path": "custom-range-slider/.vscode/settings.json",
    "chars": 40,
    "preview": "{\n    \"liveServer.settings.port\": 5501\n}"
  },
  {
    "path": "custom-range-slider/index.html",
    "chars": 480,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "custom-range-slider/script.js",
    "chars": 961,
    "preview": "const range = document.getElementById('range')\n\nrange.addEventListener('input', (e) => {\n    const value = +e.target.val"
  },
  {
    "path": "custom-range-slider/style.css",
    "chars": 1909,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Lato&display=swap');\n\n* {\n  box-sizing: border-box;\n}\n\nbody {\n  bac"
  },
  {
    "path": "dad-jokes/index.html",
    "chars": 498,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "dad-jokes/script.js",
    "chars": 731,
    "preview": "const jokeEl = document.getElementById('joke')\nconst jokeBtn = document.getElementById('jokeBtn')\n\njokeBtn.addEventListe"
  },
  {
    "path": "dad-jokes/style.css",
    "chars": 1052,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');\n\n* {\n  box-sizing: border-box;"
  },
  {
    "path": "double-click-heart/index.html",
    "chars": 723,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "double-click-heart/script.js",
    "chars": 985,
    "preview": "const loveMe = document.querySelector('.loveMe')\nconst times = document.querySelector('#times')\n\nlet clickTime = 0\nlet t"
  },
  {
    "path": "double-click-heart/style.css",
    "chars": 980,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Oswald');\n\n* {\n  box-sizing: border-box;\n}\n\nbody {\n  font-family: '"
  },
  {
    "path": "double-vertical-slider/index.html",
    "chars": 2198,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "double-vertical-slider/script.js",
    "chars": 1139,
    "preview": "const sliderContainer = document.querySelector('.slider-container')\nconst slideRight = document.querySelector('.right-sl"
  },
  {
    "path": "double-vertical-slider/style.css",
    "chars": 1553,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Open+Sans');\n\n* {\n  box-sizing: border-box;\n  margin: 0;\n  padding:"
  },
  {
    "path": "drag-n-drop/index.html",
    "chars": 505,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "drag-n-drop/script.js",
    "chars": 963,
    "preview": "const fill = document.querySelector('.fill')\nconst empties = document.querySelectorAll('.empty')\nconst body = document.b"
  },
  {
    "path": "drag-n-drop/style.css",
    "chars": 629,
    "preview": "* {\n  box-sizing: border-box;\n}\n\nbody {\n  background-color: steelblue;\n  display: flex;\n  align-items: center;\n  justify"
  },
  {
    "path": "drawing-app/index.html",
    "chars": 582,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "drawing-app/script.js",
    "chars": 1690,
    "preview": "const canvas = document.getElementById('canvas');\nconst increaseBtn = document.getElementById('increase');\nconst decreas"
  },
  {
    "path": "drawing-app/style.css",
    "chars": 783,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');\n\n* {\n  box-sizing: border-box;"
  },
  {
    "path": "drink-water/index.html",
    "chars": 1046,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "drink-water/script.js",
    "chars": 1462,
    "preview": "const smallCups = document.querySelectorAll('.cup-small')\nconst liters = document.getElementById('liters')\nconst percent"
  },
  {
    "path": "drink-water/style.css",
    "chars": 1685,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Montserrat:400,600&display=swap');\n\n:root {\n  --border-color: #144f"
  },
  {
    "path": "event-keycodes/dark-style.css",
    "chars": 777,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');\n\n* {\n  box-sizing: border-box;\n \n}\n\nbody {\n  b"
  },
  {
    "path": "event-keycodes/index.html",
    "chars": 415,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "event-keycodes/script.js",
    "chars": 373,
    "preview": "const insert = document.getElementById('insert')\n\nwindow.addEventListener('keydown', (event) => {\n  insert.innerHTML = `"
  },
  {
    "path": "expanding-cards/index.html",
    "chars": 1540,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "expanding-cards/script.js",
    "chars": 313,
    "preview": "const panels = document.querySelectorAll('.panel')\n\npanels.forEach(panel => {\n    panel.addEventListener('click', () => "
  },
  {
    "path": "expanding-cards/style.css",
    "chars": 946,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');\n\n* {\n  box-sizing: border-box;\n}\n\nbody {\n  fon"
  },
  {
    "path": "faq-collapse/index.html",
    "chars": 2360,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "faq-collapse/script.js",
    "chars": 193,
    "preview": "const toggles = document.querySelectorAll('.faq-toggle')\n\ntoggles.forEach(toggle => {\n    toggle.addEventListener('click"
  },
  {
    "path": "faq-collapse/style.css",
    "chars": 1621,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');\n\n* {\n  box-sizing: border-box;\n}\n\nbody {\n  fon"
  },
  {
    "path": "feedback-ui-design/index.html",
    "chars": 1492,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "feedback-ui-design/script.js",
    "chars": 1253,
    "preview": "const ratings = document.querySelectorAll('.rating')\nconst ratingsContainer = document.querySelector('.ratings-container"
  },
  {
    "path": "feedback-ui-design/style.css",
    "chars": 1329,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Montserrat&display=swap');\n\n* {\n  box-sizing: border-box;\n}\n\nbody {"
  },
  {
    "path": "form-input-wave/index.html",
    "chars": 1113,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "form-input-wave/script.js",
    "chars": 263,
    "preview": "const labels = document.querySelectorAll('.form-control label')\n\nlabels.forEach(label => {\n    label.innerHTML = label.i"
  },
  {
    "path": "form-input-wave/style.css",
    "chars": 1657,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');\n\n* {\n  box-sizing: border-box;\n}\n\nbody {\n  bac"
  },
  {
    "path": "github-profiles/index.html",
    "chars": 684,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "github-profiles/script.js",
    "chars": 2111,
    "preview": "const APIURL = 'https://api.github.com/users/'\n\nconst main = document.getElementById('main')\nconst form = document.getEl"
  },
  {
    "path": "github-profiles/style.css",
    "chars": 1831,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');\n\n* {\n  box-sizing: border-box"
  },
  {
    "path": "good-cheap-fast/index.html",
    "chars": 997,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "good-cheap-fast/script.js",
    "chars": 626,
    "preview": "const toggles = document.querySelectorAll('.toggle')\nconst good = document.querySelector('#good')\nconst cheap = document"
  },
  {
    "path": "good-cheap-fast/style.css",
    "chars": 1360,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');\n\n* {\n  box-sizing: border-box;"
  },
  {
    "path": "hidden-search/index.html",
    "chars": 728,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "hidden-search/script.js",
    "chars": 236,
    "preview": "const search = document.querySelector('.search')\nconst btn = document.querySelector('.btn')\nconst input = document.query"
  },
  {
    "path": "hidden-search/style.css",
    "chars": 900,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');\n\n* {\n  box-sizing: border-box;"
  },
  {
    "path": "hoverboard/index.html",
    "chars": 349,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "hoverboard/script.js",
    "chars": 816,
    "preview": "const container = document.getElementById('container')\nconst colors = ['#e74c3c', '#8e44ad', '#3498db', '#e67e22', '#2ec"
  },
  {
    "path": "hoverboard/style.css",
    "chars": 492,
    "preview": "* {\n  box-sizing: border-box;\n}\n\nbody {\n  background-color: #111;\n  display: flex;\n  align-items: center;\n  justify-cont"
  },
  {
    "path": "image-carousel/index.html",
    "chars": 1326,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "image-carousel/script.js",
    "chars": 773,
    "preview": "const imgs = document.getElementById('imgs')\nconst leftBtn = document.getElementById('left')\nconst rightBtn = document.g"
  },
  {
    "path": "image-carousel/style.css",
    "chars": 823,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');\n\n* {\n  box-sizing: border-box;"
  },
  {
    "path": "incrementing-counter/index.html",
    "chars": 1093,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "incrementing-counter/script.js",
    "chars": 510,
    "preview": "const counters = document.querySelectorAll('.counter')\n\ncounters.forEach(counter => {\n    counter.innerText = '0'\n\n    c"
  },
  {
    "path": "incrementing-counter/style.css",
    "chars": 589,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Roboto+Mono&display=swap');\n\n* {\n  box-sizing: border-box;\n}\n\nbody "
  },
  {
    "path": "insect-catch-game/index.html",
    "chars": 1826,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "insect-catch-game/script.js",
    "chars": 2223,
    "preview": "const screens = document.querySelectorAll('.screen');\nconst choose_insect_btns = document.querySelectorAll('.choose-inse"
  },
  {
    "path": "insect-catch-game/style.css",
    "chars": 2168,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Press+Start+2P&display=swap');\n\n* {\n  box-sizing: border-box;\n}\n\nbo"
  },
  {
    "path": "kinetic-loader/index.html",
    "chars": 341,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "kinetic-loader/style.css",
    "chars": 912,
    "preview": "* {\n  box-sizing: border-box;\n}\n\nbody {\n  background-color: #2c3e50;\n  display: flex;\n  align-items: center;\n  justify-c"
  },
  {
    "path": "live-user-filter/index.html",
    "chars": 682,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "live-user-filter/script.js",
    "chars": 1088,
    "preview": "const result = document.getElementById('result')\nconst filter = document.getElementById('filter')\nconst listItems = []\n\n"
  },
  {
    "path": "live-user-filter/style.css",
    "chars": 1367,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');\n\n* {\n  box-sizing: border-box;"
  },
  {
    "path": "mobile-tab-navigation/index.html",
    "chars": 1772,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "mobile-tab-navigation/script.js",
    "chars": 522,
    "preview": "const contents = document.querySelectorAll('.content')\nconst listItems = document.querySelectorAll('nav ul li')\n\nlistIte"
  },
  {
    "path": "mobile-tab-navigation/style.css",
    "chars": 1075,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Open+Sans&display=swap');\n\n* {\n  box-sizing: border-box;\n}\n\nbody {\n"
  },
  {
    "path": "movie-app/index.html",
    "chars": 469,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "movie-app/script.js",
    "chars": 1713,
    "preview": "const API_URL = 'https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=3fd2be6f0c70a2a598f084ddfb7"
  },
  {
    "path": "movie-app/style.css",
    "chars": 1791,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');\n\n:root {\n  --primary-color: #"
  },
  {
    "path": "netflix-mobile-navigation/index.html",
    "chars": 1743,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"UTF-8\" />\n  <meta name=\"viewport\" content=\"width=device-width,"
  },
  {
    "path": "netflix-mobile-navigation/script.js",
    "chars": 369,
    "preview": "const open_btn = document.querySelector('.open-btn')\nconst close_btn = document.querySelector('.close-btn')\nconst nav = "
  },
  {
    "path": "netflix-mobile-navigation/style.css",
    "chars": 1507,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');\n\n* {\n  box-sizing: border-box;\n}\n\nbody {\n  fon"
  },
  {
    "path": "notes-app/index.html",
    "chars": 729,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "notes-app/script.js",
    "chars": 1548,
    "preview": "const addBtn = document.getElementById('add')\n\nconst notes = JSON.parse(localStorage.getItem('notes'))\n\nif(notes) {\n    "
  },
  {
    "path": "notes-app/style.css",
    "chars": 1140,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');\n\n* {\n  box-sizing: border-box"
  },
  {
    "path": "password-generator/index.html",
    "chars": 1696,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "password-generator/script.js",
    "chars": 2163,
    "preview": "const resultEl = document.getElementById('result')\nconst lengthEl = document.getElementById('length')\nconst uppercaseEl "
  },
  {
    "path": "password-generator/style.css",
    "chars": 1393,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');\n\n* {\n  box-sizing: border-box;\n}\n\nbody {\n  bac"
  },
  {
    "path": "password-strength-background/index.html",
    "chars": 1558,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "password-strength-background/script.js",
    "chars": 306,
    "preview": "const password = document.getElementById('password')\nconst background = document.getElementById('background')\n\npassword."
  },
  {
    "path": "password-strength-background/style.css",
    "chars": 437,
    "preview": "* {\n  box-sizing: border-box;\n}\n\nbody {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-cont"
  },
  {
    "path": "pokedex/index.html",
    "chars": 474,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "pokedex/script.js",
    "chars": 1705,
    "preview": "const poke_container = document.getElementById('poke-container')\nconst pokemon_count = 150\nconst colors = {\n    fire: '#"
  },
  {
    "path": "pokedex/style.css",
    "chars": 1167,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Lato:300,400&display=swap');\n\n* {\n  box-sizing: border-box;\n}\n\nbody"
  },
  {
    "path": "progress-steps/index.html",
    "chars": 707,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "progress-steps/script.js",
    "chars": 1099,
    "preview": "const progress = document.getElementById('progress')\nconst prev = document.getElementById('prev')\nconst next = document."
  },
  {
    "path": "progress-steps/style.css",
    "chars": 1661,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');\n\n:root {\n  --line-border-fill: #3498db;\n  --li"
  },
  {
    "path": "quiz-app/index.html",
    "chars": 1138,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "quiz-app/script.js",
    "chars": 2415,
    "preview": "const quizData = [\n    {\n        question: \"Which language runs in a web browser?\",\n        a: \"Java\",\n        b: \"C\",\n "
  },
  {
    "path": "quiz-app/style.css",
    "chars": 1075,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');\n\n* {\n  box-sizing: border-box"
  },
  {
    "path": "random-choice-picker/index.html",
    "chars": 557,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "random-choice-picker/script.js",
    "chars": 1448,
    "preview": "const tagsEl = document.getElementById('tags')\nconst textarea = document.getElementById('textarea')\n\ntextarea.focus()\n\nt"
  },
  {
    "path": "random-choice-picker/style.css",
    "chars": 837,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');\n\n* {\n  box-sizing: border-box;\n}\n\nbody {\n  bac"
  },
  {
    "path": "random-image-generator/index.html",
    "chars": 387,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "random-image-generator/script.js",
    "chars": 445,
    "preview": "const container = document.querySelector('.container')\nconst unsplashURL = 'https://source.unsplash.com/random/'\nconst r"
  },
  {
    "path": "random-image-generator/style.css",
    "chars": 583,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');\n\n* {\n  box-sizing: border-box;"
  },
  {
    "path": "rotating-nav-animation/index.html",
    "chars": 2748,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "rotating-nav-animation/script.js",
    "chars": 300,
    "preview": "const open = document.getElementById('open')\nconst close = document.getElementById('close')\nconst container = document.q"
  },
  {
    "path": "rotating-nav-animation/style.css",
    "chars": 2031,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Lato&display=swap');\n\n* {\n  box-sizing: border-box;\n}\n\nbody {\n  fon"
  },
  {
    "path": "scroll-animation/index.html",
    "chars": 919,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "scroll-animation/script.js",
    "chars": 422,
    "preview": "const boxes = document.querySelectorAll('.box')\n\nwindow.addEventListener('scroll', checkBoxes)\n\ncheckBoxes()\n\nfunction c"
  },
  {
    "path": "scroll-animation/style.css",
    "chars": 793,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');\n\n* {\n  box-sizing: border-box;"
  },
  {
    "path": "simple-timer/index.html",
    "chars": 2009,
    "preview": "<html>\r\n  <head>\r\n    <meta charset=\"UTF-8\" />\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0"
  },
  {
    "path": "simple-timer/script.js",
    "chars": 1949,
    "preview": "const resetBtn = document.querySelector('#reset');\r\nconst playBtn = document.querySelector('#play');\r\nconst timerEl = do"
  },
  {
    "path": "simple-timer/style.css",
    "chars": 276,
    "preview": ":root {\r\n  --degrees: 0deg;\r\n}\r\n\r\n.bg-conic {\r\n  background: conic-gradient(\r\n    transparent 0deg,\r\n    transparent var"
  },
  {
    "path": "sound-board/index.html",
    "chars": 658,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "sound-board/script.js",
    "chars": 546,
    "preview": "const sounds = ['applause', 'boo', 'gasp', 'tada', 'victory', 'wrong']\n\nsounds.forEach(sound => {\n    const btn = docume"
  },
  {
    "path": "sound-board/style.css",
    "chars": 637,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');\n\n* {\n  box-sizing: border-box"
  },
  {
    "path": "split-landing-page/index.html",
    "chars": 592,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "split-landing-page/script.js",
    "chars": 482,
    "preview": "const left = document.querySelector('.left')\nconst right = document.querySelector('.right')\nconst container = document.q"
  },
  {
    "path": "split-landing-page/style.css",
    "chars": 2334,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');\n\n:root {\n  --left-bg-color: rg"
  },
  {
    "path": "sticky-navigation/index.html",
    "chars": 2126,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "sticky-navigation/script.js",
    "chars": 251,
    "preview": "const nav = document.querySelector('.nav')\nwindow.addEventListener('scroll', fixNav)\n\nfunction fixNav() {\n    if(window."
  },
  {
    "path": "sticky-navigation/style.css",
    "chars": 1845,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Open+Sans');\n\n* {\n  box-sizing: border-box;\n  margin: 0;\n  padding:"
  },
  {
    "path": "testimonial-box-switcher/index.html",
    "chars": 1592,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "testimonial-box-switcher/script.js",
    "chars": 3691,
    "preview": "const testimonialsContainer = document.querySelector('.testimonials-container')\nconst testimonial = document.querySelect"
  },
  {
    "path": "testimonial-box-switcher/style.css",
    "chars": 1391,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Montserrat');\n\n* {\n  box-sizing: border-box;\n}\n\nbody {\n  background"
  },
  {
    "path": "theme-clock/index.html",
    "chars": 753,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "theme-clock/script.js",
    "chars": 1962,
    "preview": "const hourEl = document.querySelector('.hour')\nconst minuteEl = document.querySelector('.minute')\nconst secondEl = docum"
  },
  {
    "path": "theme-clock/style.css",
    "chars": 2242,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Heebo:300&display=swap');\n\n* {\n  box-sizing: border-box;\n}\n\n:root {"
  },
  {
    "path": "toast-notification/index.html",
    "chars": 401,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "toast-notification/script.js",
    "chars": 842,
    "preview": "const button = document.getElementById('button')\nconst toasts = document.getElementById('toasts')\n\nconst messages = [\n  "
  },
  {
    "path": "toast-notification/style.css",
    "chars": 948,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');\n\n* {\n  box-sizing: border-box"
  },
  {
    "path": "todo-list/index.html",
    "chars": 577,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "todo-list/script.js",
    "chars": 1344,
    "preview": "const form = document.getElementById('form')\nconst input = document.getElementById('input')\nconst todosUL = document.get"
  },
  {
    "path": "todo-list/style.css",
    "chars": 1086,
    "preview": "@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');\n\n* {\n  box-sizing: border-box"
  },
  {
    "path": "verify-account-ui/index.html",
    "chars": 1201,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "verify-account-ui/script.js",
    "chars": 393,
    "preview": "const codes = document.querySelectorAll('.code')\n\ncodes[0].focus()\n\ncodes.forEach((code, idx) => {\n    code.addEventList"
  },
  {
    "path": "verify-account-ui/style.css",
    "chars": 1306,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Muli:300,700&display=swap');\n\n* {\n  box-sizing: border-box;\n}\n\nbody"
  }
]

About this extraction

This page contains the full source code of the bradtraversy/50projects50days GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 159 files (176.5 KB), approximately 56.2k tokens, and a symbol index with 85 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!