├── .gitignore
├── 3d-boxes-background
├── index.html
├── script.js
└── style.css
├── 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
├── index.html
├── script.js
└── style.css
├── 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
├── sound-board
├── index.html
├── script.js
├── sounds
│ ├── applause.mp3
│ ├── boo.mp3
│ ├── gasp.mp3
│ ├── tada.mp3
│ ├── victory.mp3
│ └── wrong.mp3
└── style.css
├── split-landing-page
├── index.html
├── ps.jpg
├── script.js
├── style.css
└── xbox.jpg
├── 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
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
--------------------------------------------------------------------------------
/3d-boxes-background/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
12 |
13 | 3D Boxes Background
14 |
15 |
16 | Magic 🎩
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/3d-boxes-background/script.js:
--------------------------------------------------------------------------------
1 | const boxesContainer = document.getElementById('boxes')
2 | const btn = document.getElementById('btn')
3 |
4 | btn.addEventListener('click', () => boxesContainer.classList.toggle('big'))
5 |
6 | function createBoxes() {
7 | for (let i = 0; i < 4; i++) {
8 | for (let j = 0; j < 4; j++) {
9 | const box = document.createElement('div')
10 | box.classList.add('box')
11 | box.style.backgroundPosition = `${-j * 125}px ${-i * 125}px`
12 | boxesContainer.appendChild(box)
13 | }
14 | }
15 | }
16 |
17 | createBoxes()
18 |
--------------------------------------------------------------------------------
/3d-boxes-background/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
2 | @import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap');
3 |
4 | * {
5 | box-sizing: border-box;
6 | }
7 |
8 | body {
9 | background-color: #fafafa;
10 | font-family: 'Roboto', sans-serif;
11 | display: flex;
12 | flex-direction: column;
13 | align-items: center;
14 | justify-content: center;
15 | height: 100vh;
16 | overflow: hidden;
17 | }
18 |
19 | .magic {
20 | background-color: #f9ca24;
21 | color: #fff;
22 | font-family: 'Poppins', sans-serif;
23 | border: 0;
24 | border-radius: 3px;
25 | font-size: 16px;
26 | padding: 12px 20px;
27 | cursor: pointer;
28 | position: fixed;
29 | top: 20px;
30 | letter-spacing: 1px;
31 | box-shadow: 0 3px rgba(249, 202, 36, 0.5);
32 | z-index: 100;
33 | }
34 |
35 | .magic:focus {
36 | outline: none;
37 | }
38 |
39 | .magic:active {
40 | box-shadow: none;
41 | transform: translateY(2px);
42 | }
43 |
44 | .boxes {
45 | display: flex;
46 | flex-wrap: wrap;
47 | justify-content: space-around;
48 | height: 500px;
49 | width: 500px;
50 | position: relative;
51 | transition: 0.4s ease;
52 | }
53 |
54 | .boxes.big {
55 | width: 600px;
56 | height: 600px;
57 | }
58 |
59 | .boxes.big .box {
60 | transform: rotateZ(360deg);
61 | }
62 |
63 | .box {
64 | background-image: url('https://media.giphy.com/media/EZqwsBSPlvSda/giphy.gif');
65 | background-repeat: no-repeat;
66 | background-size: 500px 500px;
67 | position: relative;
68 | height: 125px;
69 | width: 125px;
70 | transition: 0.4s ease;
71 | }
72 |
73 | .box::after {
74 | content: '';
75 | background-color: #f6e58d;
76 | position: absolute;
77 | top: 8px;
78 | right: -15px;
79 | height: 100%;
80 | width: 15px;
81 | transform: skewY(45deg);
82 | }
83 |
84 | .box::before {
85 | content: '';
86 | background-color: #f9ca24;
87 | position: absolute;
88 | bottom: -15px;
89 | left: 8px;
90 | height: 15px;
91 | width: 100%;
92 | transform: skewX(45deg);
93 | }
94 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 50 Projects in 50 Days - HTML/CSS and JavaScript
2 |
3 | **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
4 |
--------------------------------------------------------------------------------
/_project_starter_/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | My Project
8 |
9 |
10 | Project Starter
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/_project_starter_/script.js:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/_project_starter_/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | font-family: 'Roboto', sans-serif;
9 | display: flex;
10 | flex-direction: column;
11 | align-items: center;
12 | justify-content: center;
13 | height: 100vh;
14 | overflow: hidden;
15 | margin: 0;
16 | }
17 |
--------------------------------------------------------------------------------
/animated-countdown/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Animated Countdown
8 |
9 |
10 |
11 |
12 | 3
13 | 2
14 | 1
15 | 0
16 |
17 |
Get Ready
18 |
19 |
20 |
21 |
GO
22 |
23 | Replay
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/animated-countdown/script.js:
--------------------------------------------------------------------------------
1 | const nums = document.querySelectorAll('.nums span')
2 | const counter = document.querySelector('.counter')
3 | const finalMessage = document.querySelector('.final')
4 | const replay = document.querySelector('#replay')
5 |
6 | runAnimation()
7 |
8 | function resetDOM() {
9 | counter.classList.remove('hide')
10 | finalMessage.classList.remove('show')
11 |
12 | nums.forEach((num) => {
13 | num.classList.value = ''
14 | })
15 |
16 | nums[0].classList.add('in')
17 | }
18 |
19 | function runAnimation() {
20 | nums.forEach((num, idx) => {
21 | const nextToLast = nums.length - 1
22 |
23 | num.addEventListener('animationend', (e) => {
24 | if (e.animationName === 'goIn' && idx !== nextToLast) {
25 | num.classList.remove('in')
26 | num.classList.add('out')
27 | } else if (e.animationName === 'goOut' && num.nextElementSibling) {
28 | num.nextElementSibling.classList.add('in')
29 | } else {
30 | counter.classList.add('hide')
31 | finalMessage.classList.add('show')
32 | }
33 | })
34 | })
35 | }
36 |
37 | replay.addEventListener('click', () => {
38 | resetDOM()
39 | runAnimation()
40 | })
41 |
--------------------------------------------------------------------------------
/animated-countdown/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | font-family: 'Roboto', sans-serif;
9 | margin: 0;
10 | height: 100vh;
11 | overflow: hidden;
12 | }
13 |
14 | h4 {
15 | font-size: 20px;
16 | margin: 5px;
17 | text-transform: uppercase;
18 | }
19 |
20 | .counter {
21 | position: fixed;
22 | top: 50%;
23 | left: 50%;
24 | transform: translate(-50%, -50%);
25 | text-align: center;
26 | }
27 |
28 | .counter.hide {
29 | transform: translate(-50%, -50%) scale(0);
30 | animation: hide 0.2s ease-out;
31 | }
32 |
33 | @keyframes hide {
34 | 0% {
35 | transform: translate(-50%, -50%) scale(1);
36 | }
37 |
38 | 100% {
39 | transform: translate(-50%, -50%) scale(0);
40 | }
41 | }
42 |
43 | .final {
44 | position: fixed;
45 | top: 50%;
46 | left: 50%;
47 | transform: translate(-50%, -50%) scale(0);
48 | text-align: center;
49 | }
50 |
51 | .final.show {
52 | transform: translate(-50%, -50%) scale(1);
53 | animation: show 0.2s ease-out;
54 | }
55 |
56 | @keyframes show {
57 | 0% {
58 | transform: translate(-50%, -50%) scale(0);
59 | }
60 |
61 | 30% {
62 | transform: translate(-50%, -50%) scale(1.4);
63 | }
64 |
65 | 100% {
66 | transform: translate(-50%, -50%) scale(1);
67 | }
68 | }
69 |
70 | .nums {
71 | color: #3498db;
72 | font-size: 50px;
73 | position: relative;
74 | overflow: hidden;
75 | width: 250px;
76 | height: 50px;
77 | }
78 |
79 | .nums span {
80 | position: absolute;
81 | top: 50%;
82 | left: 50%;
83 | transform: translate(-50%, -50%) rotate(120deg);
84 | transform-origin: bottom center;
85 | }
86 |
87 | .nums span.in {
88 | transform: translate(-50%, -50%) rotate(0deg);
89 | animation: goIn 0.5s ease-in-out;
90 | }
91 |
92 | .nums span.out {
93 | animation: goOut 0.5s ease-in-out;
94 | }
95 |
96 | @keyframes goIn {
97 | 0% {
98 | transform: translate(-50%, -50%) rotate(120deg);
99 | }
100 |
101 | 30% {
102 | transform: translate(-50%, -50%) rotate(-20deg);
103 | }
104 |
105 | 60% {
106 | transform: translate(-50%, -50%) rotate(10deg);
107 | }
108 |
109 | 100% {
110 | transform: translate(-50%, -50%) rotate(0deg);
111 | }
112 | }
113 |
114 | @keyframes goOut {
115 | 0% {
116 | transform: translate(-50%, -50%) rotate(0deg);
117 | }
118 |
119 | 60% {
120 | transform: translate(-50%, -50%) rotate(20deg);
121 | }
122 |
123 | 100% {
124 | transform: translate(-50%, -50%) rotate(-120deg);
125 | }
126 | }
127 |
128 | #replay{
129 | background-color: #3498db;
130 | border-radius: 3px;
131 | border: none;
132 | color: aliceblue;
133 | padding: 5px;
134 | text-align: center;
135 | display: inline-block;
136 | cursor: pointer;
137 | transition: all 0.3s;
138 | }
139 |
140 | #replay span{
141 | cursor: pointer;
142 | display: inline-block;
143 | position: relative;
144 | transition: 0.3s;
145 | }
146 |
147 | #replay span:after{
148 | content: '\00bb';
149 | position: absolute;
150 | opacity: 0;
151 | top: 0;
152 | right: -20px;
153 | transition: 0.5s;
154 | }
155 |
156 | #replay:hover span{
157 | padding-right: 25px;
158 | }
159 |
160 | #replay:hover span:after{
161 | opacity: 1;
162 | right: 0;
163 | }
164 |
--------------------------------------------------------------------------------
/animated-navigation/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Animated Navigation
8 |
9 |
10 |
11 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/animated-navigation/script.js:
--------------------------------------------------------------------------------
1 | const toggle = document.getElementById('toggle')
2 | const nav = document.getElementById('nav')
3 |
4 | toggle.addEventListener('click', () => nav.classList.toggle('active'))
5 |
--------------------------------------------------------------------------------
/animated-navigation/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #eafbff;
9 | background-image: linear-gradient(
10 | to bottom,
11 | #eafbff 0%,
12 | #eafbff 50%,
13 | #5290f9 50%,
14 | #5290f9 100%
15 | );
16 | font-family: 'Muli', sans-serif;
17 | display: flex;
18 | align-items: center;
19 | justify-content: center;
20 | height: 100vh;
21 | margin: 0;
22 | }
23 |
24 | nav {
25 | background-color: #fff;
26 | padding: 20px;
27 | width: 80px;
28 | display: flex;
29 | align-items: center;
30 | justify-content: center;
31 | border-radius: 3px;
32 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
33 | transition: width 0.6s linear;
34 | overflow-x: hidden;
35 | }
36 |
37 | nav.active {
38 | width: 350px;
39 | }
40 |
41 | nav ul {
42 | display: flex;
43 | list-style-type: none;
44 | padding: 0;
45 | margin: 0;
46 | width: 0;
47 | transition: width 0.6s linear;
48 | }
49 |
50 | nav.active ul {
51 | width: 100%;
52 | }
53 |
54 | nav ul li {
55 | transform: rotateY(0deg);
56 | opacity: 0;
57 | transition: transform 0.6s linear, opacity 0.6s linear;
58 | }
59 |
60 | nav.active ul li {
61 | opacity: 1;
62 | transform: rotateY(360deg);
63 | }
64 |
65 | nav ul a {
66 | position: relative;
67 | color: #000;
68 | text-decoration: none;
69 | margin: 0 10px;
70 | }
71 |
72 | .icon {
73 | background-color: #fff;
74 | border: 0;
75 | cursor: pointer;
76 | padding: 0;
77 | position: relative;
78 | height: 30px;
79 | width: 30px;
80 | }
81 |
82 | .icon:focus {
83 | outline: 0;
84 | }
85 |
86 | .icon .line {
87 | background-color: #5290f9;
88 | height: 2px;
89 | width: 20px;
90 | position: absolute;
91 | top: 10px;
92 | left: 5px;
93 | transition: transform 0.6s linear;
94 | }
95 |
96 | .icon .line2 {
97 | top: auto;
98 | bottom: 10px;
99 | }
100 |
101 | nav.active .icon .line1 {
102 | transform: rotate(-765deg) translateY(5.5px);
103 | }
104 |
105 | nav.active .icon .line2 {
106 | transform: rotate(765deg) translateY(-5.5px);
107 | }
108 |
--------------------------------------------------------------------------------
/auto-text-effect/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Auto Text Effect
8 |
9 |
10 | Starting...
11 |
12 |
13 | Speed:
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/auto-text-effect/script.js:
--------------------------------------------------------------------------------
1 | const textEl = document.getElementById('text')
2 | const speedEl = document.getElementById('speed')
3 | const text = 'We Love Programming!'
4 | let idx = 1
5 | let speed = 300 / speedEl.value
6 |
7 | writeText()
8 |
9 | function writeText() {
10 | textEl.innerText = text.slice(0, idx)
11 |
12 | idx++
13 |
14 | if(idx > text.length) {
15 | idx = 1
16 | }
17 |
18 | setTimeout(writeText, speed)
19 | }
20 |
21 |
22 | speedEl.addEventListener('input', (e) => speed = 300 / e.target.value)
--------------------------------------------------------------------------------
/auto-text-effect/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: darksalmon;
9 | font-family: 'Roboto', sans-serif;
10 | display: flex;
11 | flex-direction: column;
12 | align-items: center;
13 | justify-content: center;
14 | height: 100vh;
15 | overflow: hidden;
16 | margin: 0;
17 | }
18 |
19 | div {
20 | position: absolute;
21 | bottom: 20px;
22 | background: rgba(0, 0, 0, 0.1);
23 | padding: 10px 20px;
24 | font-size: 18px;
25 | }
26 |
27 | input {
28 | width: 50px;
29 | padding: 5px;
30 | font-size: 18px;
31 | background-color: darksalmon;
32 | border: none;
33 | text-align: center;
34 | }
35 |
36 | input:focus {
37 | outline: none;
38 | }
39 |
--------------------------------------------------------------------------------
/background-slider/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
12 |
13 | Background Slider
14 |
15 |
16 |
17 |
23 |
29 |
30 |
36 |
37 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/background-slider/script.js:
--------------------------------------------------------------------------------
1 | const body = document.body
2 | const slides = document.querySelectorAll('.slide')
3 | const leftBtn = document.getElementById('left')
4 | const rightBtn = document.getElementById('right')
5 |
6 | let activeSlide = 0
7 |
8 | rightBtn.addEventListener('click', () => {
9 | activeSlide++
10 |
11 | if (activeSlide > slides.length - 1) {
12 | activeSlide = 0
13 | }
14 |
15 | setBgToBody()
16 | setActiveSlide()
17 | })
18 |
19 | leftBtn.addEventListener('click', () => {
20 | activeSlide--
21 |
22 | if (activeSlide < 0) {
23 | activeSlide = slides.length - 1
24 | }
25 |
26 | setBgToBody()
27 | setActiveSlide()
28 | })
29 |
30 | setBgToBody()
31 |
32 | function setBgToBody() {
33 | body.style.backgroundImage = slides[activeSlide].style.backgroundImage
34 | }
35 |
36 | function setActiveSlide() {
37 | slides.forEach((slide) => slide.classList.remove('active'))
38 |
39 | slides[activeSlide].classList.add('active')
40 | }
41 |
--------------------------------------------------------------------------------
/background-slider/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | font-family: 'Roboto', sans-serif;
9 | display: flex;
10 | flex-direction: column;
11 | align-items: center;
12 | justify-content: center;
13 | height: 100vh;
14 | overflow: hidden;
15 | margin: 0;
16 | background-position: center center;
17 | background-size: cover;
18 | transition: 0.4s;
19 | }
20 |
21 | body::before {
22 | content: '';
23 | position: absolute;
24 | top: 0;
25 | left: 0;
26 | width: 100%;
27 | height: 100vh;
28 | background-color: rgba(0, 0, 0, 0.7);
29 | z-index: -1;
30 | }
31 |
32 | .slider-container {
33 | box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
34 | height: 70vh;
35 | width: 70vw;
36 | position: relative;
37 | overflow: hidden;
38 | }
39 |
40 | .slide {
41 | opacity: 0;
42 | height: 100vh;
43 | width: 100vw;
44 | background-position: center center;
45 | background-size: cover;
46 | position: absolute;
47 | top: -15vh;
48 | left: -15vw;
49 | transition: 0.4s ease;
50 | z-index: 1;
51 | }
52 |
53 | .slide.active {
54 | opacity: 1;
55 | }
56 |
57 | .arrow {
58 | position: fixed;
59 | background-color: transparent;
60 | color: #fff;
61 | padding: 20px;
62 | font-size: 30px;
63 | border: 2px solid orange;
64 | top: 50%;
65 | transform: translateY(-50%);
66 | cursor: pointer;
67 | }
68 |
69 | .arrow:focus {
70 | outline: 0;
71 | }
72 |
73 | .left-arrow {
74 | left: calc(15vw - 65px);
75 | }
76 |
77 | .right-arrow {
78 | right: calc(15vw - 65px);
79 | }
80 |
--------------------------------------------------------------------------------
/blurry-loading/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Blurry Loading
8 |
9 |
10 |
11 | 0%
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/blurry-loading/script.js:
--------------------------------------------------------------------------------
1 | const loadText = document.querySelector('.loading-text')
2 | const bg = document.querySelector('.bg')
3 |
4 | let load = 0
5 |
6 | let int = setInterval(blurring, 30)
7 |
8 | function blurring() {
9 | load++
10 |
11 | if (load > 99) {
12 | clearInterval(int)
13 | }
14 |
15 | loadText.innerText = `${load}%`
16 | loadText.style.opacity = scale(load, 0, 100, 1, 0)
17 | bg.style.filter = `blur(${scale(load, 0, 100, 30, 0)}px)`
18 | }
19 |
20 | // https://stackoverflow.com/questions/10756313/javascript-jquery-map-a-range-of-numbers-to-another-range-of-numbers
21 | const scale = (num, in_min, in_max, out_min, out_max) => {
22 | return ((num - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min
23 | }
24 |
--------------------------------------------------------------------------------
/blurry-loading/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Ubuntu');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | font-family: 'Ubuntu', sans-serif;
9 | display: flex;
10 | align-items: center;
11 | justify-content: center;
12 | height: 100vh;
13 | overflow: hidden;
14 | margin: 0;
15 | }
16 |
17 | .bg {
18 | background: url('https://images.unsplash.com/photo-1576161787924-01bb08dad4a4?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2104&q=80')
19 | no-repeat center center/cover;
20 | position: absolute;
21 | top: -30px;
22 | left: -30px;
23 | width: calc(100vw + 60px);
24 | height: calc(100vh + 60px);
25 | z-index: -1;
26 | filter: blur(0px);
27 | }
28 |
29 | .loading-text {
30 | font-size: 50px;
31 | color: #fff;
32 | }
33 |
--------------------------------------------------------------------------------
/button-ripple-effect/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Button Ripple Effect
8 |
9 |
10 | Click Me
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/button-ripple-effect/script.js:
--------------------------------------------------------------------------------
1 | const buttons = document.querySelectorAll('.ripple')
2 |
3 | buttons.forEach(button => {
4 | button.addEventListener('click', function (e) {
5 | const x = e.clientX
6 | const y = e.clientY
7 |
8 | const buttonTop = e.target.offsetTop
9 | const buttonLeft = e.target.offsetLeft
10 |
11 | const xInside = x - buttonLeft
12 | const yInside = y - buttonTop
13 |
14 | const circle = document.createElement('span')
15 | circle.classList.add('circle')
16 | circle.style.top = yInside + 'px'
17 | circle.style.left = xInside + 'px'
18 |
19 | this.appendChild(circle)
20 |
21 | setTimeout(() => circle.remove(), 500)
22 | })
23 | })
--------------------------------------------------------------------------------
/button-ripple-effect/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #000;
9 | font-family: 'Roboto', sans-serif;
10 | display: flex;
11 | flex-direction: column;
12 | align-items: center;
13 | justify-content: center;
14 | height: 100vh;
15 | overflow: hidden;
16 | margin: 0;
17 | }
18 |
19 | button {
20 | background-color: purple;
21 | color: #fff;
22 | border: 1px purple solid;
23 | font-size: 14px;
24 | text-transform: uppercase;
25 | letter-spacing: 2px;
26 | padding: 20px 30px;
27 | overflow: hidden;
28 | margin: 10px 0;
29 | position: relative;
30 | }
31 |
32 | button:focus {
33 | outline: none;
34 | }
35 |
36 | button .circle {
37 | position: absolute;
38 | background-color: #fff;
39 | width: 100px;
40 | height: 100px;
41 | border-radius: 50%;
42 | transform: translate(-50%, -50%) scale(0);
43 | animation: scale 0.5s ease-out;
44 | }
45 |
46 | @keyframes scale {
47 | to {
48 | transform: translate(-50%, -50%) scale(3);
49 | opacity: 0;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/content-placeholder/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Content Placeholder
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/content-placeholder/script.js:
--------------------------------------------------------------------------------
1 | const header = document.getElementById('header')
2 | const title = document.getElementById('title')
3 | const excerpt = document.getElementById('excerpt')
4 | const profile_img = document.getElementById('profile_img')
5 | const name = document.getElementById('name')
6 | const date = document.getElementById('date')
7 |
8 | const animated_bgs = document.querySelectorAll('.animated-bg')
9 | const animated_bg_texts = document.querySelectorAll('.animated-bg-text')
10 |
11 | setTimeout(getData, 2500)
12 |
13 | function getData() {
14 | header.innerHTML =
15 | ' '
16 | title.innerHTML = 'Lorem ipsum dolor sit amet'
17 | excerpt.innerHTML =
18 | 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolore perferendis'
19 | profile_img.innerHTML =
20 | ' '
21 | name.innerHTML = 'John Doe'
22 | date.innerHTML = 'Oct 08, 2020'
23 |
24 | animated_bgs.forEach((bg) => bg.classList.remove('animated-bg'))
25 | animated_bg_texts.forEach((bg) => bg.classList.remove('animated-bg-text'))
26 | }
27 |
--------------------------------------------------------------------------------
/content-placeholder/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #ecf0f1;
9 | font-family: 'Roboto', sans-serif;
10 | display: flex;
11 | align-items: center;
12 | justify-content: center;
13 | height: 100vh;
14 | overflow: hidden;
15 | margin: 0;
16 | }
17 |
18 | img {
19 | max-width: 100%;
20 | }
21 |
22 | .card {
23 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
24 | border-radius: 10px;
25 | overflow: hidden;
26 | width: 350px;
27 | }
28 |
29 | .card-header {
30 | height: 200px;
31 | }
32 |
33 | .card-header img {
34 | object-fit: cover;
35 | height: 100%;
36 | width: 100%;
37 | }
38 |
39 | .card-content {
40 | background-color: #fff;
41 | padding: 30px;
42 | }
43 |
44 | .card-title {
45 | height: 20px;
46 | margin: 0;
47 | }
48 |
49 | .card-excerpt {
50 | color: #777;
51 | margin: 10px 0 20px;
52 | }
53 |
54 | .author {
55 | display: flex;
56 | }
57 |
58 | .profile-img {
59 | border-radius: 50%;
60 | overflow: hidden;
61 | height: 40px;
62 | width: 40px;
63 | }
64 |
65 | .author-info {
66 | display: flex;
67 | flex-direction: column;
68 | justify-content: space-around;
69 | margin-left: 10px;
70 | width: 100px;
71 | }
72 |
73 | .author-info small {
74 | color: #aaa;
75 | margin-top: 5px;
76 | }
77 |
78 | .animated-bg {
79 | background-image: linear-gradient(
80 | to right,
81 | #f6f7f8 0%,
82 | #edeef1 10%,
83 | #f6f7f8 20%,
84 | #f6f7f8 100%
85 | );
86 | background-size: 200% 100%;
87 | animation: bgPos 1s linear infinite;
88 | }
89 |
90 | .animated-bg-text {
91 | border-radius: 50px;
92 | display: inline-block;
93 | margin: 0;
94 | height: 10px;
95 | width: 100%;
96 | }
97 |
98 | @keyframes bgPos {
99 | 0% {
100 | background-position: 50% 0;
101 | }
102 |
103 | 100% {
104 | background-position: -150% 0;
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/custom-range-slider/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "liveServer.settings.port": 5501
3 | }
--------------------------------------------------------------------------------
/custom-range-slider/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Custom Range Slider
8 |
9 |
10 | Custom Range Slider
11 |
12 |
13 | 50
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/custom-range-slider/script.js:
--------------------------------------------------------------------------------
1 | const range = document.getElementById('range')
2 |
3 | range.addEventListener('input', (e) => {
4 | const value = +e.target.value
5 | const label = e.target.nextElementSibling
6 |
7 | const range_width = getComputedStyle(e.target).getPropertyValue('width')
8 | const label_width = getComputedStyle(label).getPropertyValue('width')
9 |
10 | const num_width = +range_width.substring(0, range_width.length - 2)
11 | const num_label_width = +label_width.substring(0, label_width.length - 2)
12 |
13 | const max = +e.target.max
14 | const min = +e.target.min
15 |
16 | const left = value * (num_width / max) - num_label_width / 2 + scale(value, min, max, 10, -10)
17 |
18 | label.style.left = `${left}px`
19 |
20 |
21 | label.innerHTML = value
22 | })
23 |
24 | // https://stackoverflow.com/questions/10756313/javascript-jquery-map-a-range-of-numbers-to-another-range-of-numbers
25 | const scale = (num, in_min, in_max, out_min, out_max) => {
26 | return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
27 | }
--------------------------------------------------------------------------------
/custom-range-slider/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Lato&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-image: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
9 | font-family: 'Lato', sans-serif;
10 | display: flex;
11 | flex-direction: column;
12 | align-items: center;
13 | justify-content: center;
14 | height: 100vh;
15 | overflow: hidden;
16 | margin: 0;
17 | }
18 |
19 | h2 {
20 | position: absolute;
21 | top: 10px;
22 | }
23 |
24 | .range-container {
25 | position: relative;
26 | }
27 |
28 | input[type='range'] {
29 | width: 300px;
30 | margin: 18px 0;
31 | -webkit-appearance: none;
32 | }
33 |
34 | input[type='range']:focus {
35 | outline: none;
36 | }
37 |
38 | input[type='range'] + label {
39 | background-color: #fff;
40 | position: absolute;
41 | top: -25px;
42 | left: 110px;
43 | width: 80px;
44 | padding: 5px 0;
45 | text-align: center;
46 | border-radius: 4px;
47 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
48 | }
49 |
50 | /* Chrome & Safari */
51 | input[type='range']::-webkit-slider-runnable-track {
52 | background: purple;
53 | border-radius: 4px;
54 | width: 100%;
55 | height: 10px;
56 | cursor: pointer;
57 | }
58 |
59 | input[type='range']::-webkit-slider-thumb {
60 | -webkit-appearance: none;
61 | height: 24px;
62 | width: 24px;
63 | background: #fff;
64 | border-radius: 50%;
65 | border: 1px solid purple;
66 | margin-top: -7px;
67 | cursor: pointer;
68 | }
69 |
70 | /* Firefox */
71 | input[type='range']::-moz-range-track {
72 | background: purple;
73 | border-radius: 4px;
74 | width: 100%;
75 | height: 13px;
76 | cursor: pointer;
77 | }
78 |
79 | input[type='range']::-moz-range-thumb {
80 | -webkit-appearance: none;
81 | height: 24px;
82 | width: 24px;
83 | background: #fff;
84 | border-radius: 50%;
85 | border: 1px solid purple;
86 | margin-top: -7px;
87 | cursor: pointer;
88 | }
89 |
90 | /* IE */
91 | input[type='range']::-ms-track {
92 | background: purple;
93 | border-radius: 4px;
94 | width: 100%;
95 | height: 13px;
96 | cursor: pointer;
97 | }
98 |
99 | input[type='range']::-ms-thumb {
100 | -webkit-appearance: none;
101 | height: 24px;
102 | width: 24px;
103 | background: #fff;
104 | border-radius: 50%;
105 | border: 1px solid purple;
106 | margin-top: -7px;
107 | cursor: pointer;
108 | }
109 |
--------------------------------------------------------------------------------
/dad-jokes/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Dad Jokes
8 |
9 |
10 |
11 |
Don't Laugh Challenge
12 |
// Joke goes here
13 |
Get Another Joke
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/dad-jokes/script.js:
--------------------------------------------------------------------------------
1 | const jokeEl = document.getElementById('joke')
2 | const jokeBtn = document.getElementById('jokeBtn')
3 |
4 | jokeBtn.addEventListener('click', generateJoke)
5 |
6 | generateJoke()
7 |
8 | // USING ASYNC/AWAIT
9 | async function generateJoke() {
10 | const config = {
11 | headers: {
12 | Accept: 'application/json',
13 | },
14 | }
15 |
16 | const res = await fetch('https://icanhazdadjoke.com', config)
17 |
18 | const data = await res.json()
19 |
20 | jokeEl.innerHTML = data.joke
21 | }
22 |
23 | // USING .then()
24 | // function generateJoke() {
25 | // const config = {
26 | // headers: {
27 | // Accept: 'application/json',
28 | // },
29 | // }
30 |
31 | // fetch('https://icanhazdadjoke.com', config)
32 | // .then((res) => res.json())
33 | // .then((data) => {
34 | // jokeEl.innerHTML = data.joke
35 | // })
36 | // }
37 |
--------------------------------------------------------------------------------
/dad-jokes/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #686de0;
9 | font-family: 'Roboto', sans-serif;
10 | display: flex;
11 | flex-direction: column;
12 | align-items: center;
13 | justify-content: center;
14 | height: 100vh;
15 | overflow: hidden;
16 | margin: 0;
17 | padding: 20px;
18 | }
19 |
20 | .container {
21 | background-color: #fff;
22 | border-radius: 10px;
23 | box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1), 0 6px 6px rgba(0, 0, 0, 0.1);
24 | padding: 50px 20px;
25 | text-align: center;
26 | max-width: 100%;
27 | width: 800px;
28 | }
29 |
30 | h3 {
31 | margin: 0;
32 | opacity: 0.5;
33 | letter-spacing: 2px;
34 | }
35 |
36 | .joke {
37 | font-size: 30px;
38 | letter-spacing: 1px;
39 | line-height: 40px;
40 | margin: 50px auto;
41 | max-width: 600px;
42 | }
43 |
44 | .btn {
45 | background-color: #9f68e0;
46 | color: #fff;
47 | border: 0;
48 | border-radius: 10px;
49 | box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1), 0 6px 6px rgba(0, 0, 0, 0.1);
50 | padding: 14px 40px;
51 | font-size: 16px;
52 | cursor: pointer;
53 | }
54 |
55 | .btn:active {
56 | transform: scale(0.98);
57 | }
58 |
59 | .btn:focus {
60 | outline: 0;
61 | }
62 |
--------------------------------------------------------------------------------
/double-click-heart/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Double Click Heart
9 |
10 |
11 | Double click on the image to it
12 | You liked it 0 times
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/double-click-heart/script.js:
--------------------------------------------------------------------------------
1 | const loveMe = document.querySelector('.loveMe')
2 | const times = document.querySelector('#times')
3 |
4 | let clickTime = 0
5 | let timesClicked = 0
6 |
7 | loveMe.addEventListener('click', (e) => {
8 | if(clickTime === 0) {
9 | clickTime = new Date().getTime()
10 | } else {
11 | if((new Date().getTime() - clickTime) < 800) {
12 | createHeart(e)
13 | clickTime = 0
14 | } else {
15 | clickTime = new Date().getTime()
16 | }
17 | }
18 | })
19 |
20 | const createHeart = (e) => {
21 | const heart = document.createElement('i')
22 | heart.classList.add('fas')
23 | heart.classList.add('fa-heart')
24 |
25 | const x = e.clientX
26 | const y = e.clientY
27 |
28 | const leftOffset = e.target.offsetLeft
29 | const topOffset = e.target.offsetTop
30 |
31 | const xInside = x - leftOffset
32 | const yInside = y - topOffset
33 |
34 | heart.style.top = `${yInside}px`
35 | heart.style.left = `${xInside}px`
36 |
37 | loveMe.appendChild(heart)
38 |
39 | times.innerHTML = ++timesClicked
40 |
41 | setTimeout(() => heart.remove(), 1000)
42 | }
--------------------------------------------------------------------------------
/double-click-heart/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Oswald');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | font-family: 'Oswald', sans-serif;
9 | text-align: center;
10 | overflow: hidden;
11 | margin: 0;
12 | }
13 |
14 | h3 {
15 | margin-bottom: 0;
16 | text-align: center;
17 | }
18 |
19 | small {
20 | display: block;
21 | margin-bottom: 20px;
22 | text-align: center;
23 | }
24 |
25 | .fa-heart {
26 | color: red;
27 | }
28 |
29 | .loveMe {
30 | height: 440px;
31 | width: 300px;
32 | background: url('https://images.unsplash.com/photo-1504215680853-026ed2a45def?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=334&q=80')
33 | no-repeat center center/cover;
34 | margin: auto;
35 | cursor: pointer;
36 | max-width: 100%;
37 | position: relative;
38 | box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);
39 | overflow: hidden;
40 | }
41 |
42 | .loveMe .fa-heart {
43 | position: absolute;
44 | animation: grow 0.6s linear;
45 | transform: translate(-50%, -50%) scale(0);
46 | }
47 |
48 | @keyframes grow {
49 | to {
50 | transform: translate(-50%, -50%) scale(10);
51 | opacity: 0;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/double-vertical-slider/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Vertical Slider
9 |
10 |
11 |
12 |
13 |
14 |
Nature flower
15 |
all in pink
16 |
17 |
18 |
Bluuue Sky
19 |
with it's mountains
20 |
21 |
22 |
Lonely castle
23 |
in the wilderness
24 |
25 |
26 |
Flying eagle
27 |
in the sunset
28 |
29 |
30 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/double-vertical-slider/script.js:
--------------------------------------------------------------------------------
1 | const sliderContainer = document.querySelector('.slider-container')
2 | const slideRight = document.querySelector('.right-slide')
3 | const slideLeft = document.querySelector('.left-slide')
4 | const upButton = document.querySelector('.up-button')
5 | const downButton = document.querySelector('.down-button')
6 | const slidesLength = slideRight.querySelectorAll('div').length
7 |
8 | let activeSlideIndex = 0
9 |
10 | slideLeft.style.top = `-${(slidesLength - 1) * 100}vh`
11 |
12 | upButton.addEventListener('click', () => changeSlide('up'))
13 | downButton.addEventListener('click', () => changeSlide('down'))
14 |
15 | const changeSlide = (direction) => {
16 | const sliderHeight = sliderContainer.clientHeight
17 | if(direction === 'up') {
18 | activeSlideIndex++
19 | if(activeSlideIndex > slidesLength - 1) {
20 | activeSlideIndex = 0
21 | }
22 | } else if(direction === 'down') {
23 | activeSlideIndex--
24 | if(activeSlideIndex < 0) {
25 | activeSlideIndex = slidesLength - 1
26 | }
27 | }
28 |
29 | slideRight.style.transform = `translateY(-${activeSlideIndex * sliderHeight}px)`
30 | slideLeft.style.transform = `translateY(${activeSlideIndex * sliderHeight}px)`
31 | }
--------------------------------------------------------------------------------
/double-vertical-slider/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Open+Sans');
2 |
3 | * {
4 | box-sizing: border-box;
5 | margin: 0;
6 | padding: 0;
7 | }
8 |
9 | body {
10 | font-family: 'Open Sans', sans-serif;
11 | height: 100vh;
12 | }
13 |
14 | .slider-container {
15 | position: relative;
16 | overflow: hidden;
17 | width: 100vw;
18 | height: 100vh;
19 | }
20 |
21 | .left-slide {
22 | height: 100%;
23 | width: 35%;
24 | position: absolute;
25 | top: 0;
26 | left: 0;
27 | transition: transform 0.5s ease-in-out;
28 | }
29 |
30 | .left-slide > div {
31 | height: 100%;
32 | width: 100%;
33 | display: flex;
34 | flex-direction: column;
35 | align-items: center;
36 | justify-content: center;
37 | color: #fff;
38 | }
39 |
40 | .left-slide h1 {
41 | font-size: 40px;
42 | margin-bottom: 10px;
43 | margin-top: -30px;
44 | }
45 |
46 | .right-slide {
47 | height: 100%;
48 | position: absolute;
49 | top: 0;
50 | left: 35%;
51 | width: 65%;
52 | transition: transform 0.5s ease-in-out;
53 | }
54 |
55 | .right-slide > div {
56 | background-repeat: no-repeat;
57 | background-size: cover;
58 | background-position: center center;
59 | height: 100%;
60 | width: 100%;
61 | }
62 |
63 | button {
64 | background-color: #fff;
65 | border: none;
66 | color: #aaa;
67 | cursor: pointer;
68 | font-size: 16px;
69 | padding: 15px;
70 | }
71 |
72 | button:hover {
73 | color: #222;
74 | }
75 |
76 | button:focus {
77 | outline: none;
78 | }
79 |
80 | .slider-container .action-buttons button {
81 | position: absolute;
82 | left: 35%;
83 | top: 50%;
84 | z-index: 100;
85 | }
86 |
87 | .slider-container .action-buttons .down-button {
88 | transform: translateX(-100%);
89 | border-top-left-radius: 5px;
90 | border-bottom-left-radius: 5px;
91 | }
92 |
93 | .slider-container .action-buttons .up-button {
94 | transform: translateY(-100%);
95 | border-top-right-radius: 5px;
96 | border-bottom-right-radius: 5px;
97 | }
98 |
--------------------------------------------------------------------------------
/drag-n-drop/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Drag N Drop
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/drag-n-drop/script.js:
--------------------------------------------------------------------------------
1 | const fill = document.querySelector('.fill')
2 | const empties = document.querySelectorAll('.empty')
3 |
4 | fill.addEventListener('dragstart', dragStart)
5 | fill.addEventListener('dragend', dragEnd)
6 |
7 | for(const empty of empties) {
8 | empty.addEventListener('dragover', dragOver)
9 | empty.addEventListener('dragenter', dragEnter)
10 | empty.addEventListener('dragleave', dragLeave)
11 | empty.addEventListener('drop', dragDrop)
12 | }
13 |
14 | function dragStart() {
15 | this.className += ' hold'
16 | setTimeout(() => this.className = 'invisible', 0)
17 | }
18 |
19 | function dragEnd() {
20 | this.className = 'fill'
21 | }
22 |
23 | function dragOver(e) {
24 | e.preventDefault()
25 | }
26 |
27 | function dragEnter(e) {
28 | e.preventDefault()
29 | this.className += ' hovered'
30 | }
31 |
32 | function dragLeave() {
33 | this.className = 'empty'
34 | }
35 |
36 | function dragDrop() {
37 | this.className = 'empty'
38 | this.append(fill)
39 | }
--------------------------------------------------------------------------------
/drag-n-drop/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | }
4 |
5 | body {
6 | background-color: steelblue;
7 | display: flex;
8 | align-items: center;
9 | justify-content: center;
10 | height: 100vh;
11 | overflow: hidden;
12 | margin: 0;
13 | }
14 |
15 | .empty {
16 | height: 150px;
17 | width: 150px;
18 | margin: 10px;
19 | border: solid 3px black;
20 | background: white;
21 | }
22 |
23 | .fill {
24 | background-image: url('https://source.unsplash.com/random/150x150');
25 | height: 145px;
26 | width: 145px;
27 | cursor: pointer;
28 | }
29 |
30 | .hold {
31 | border: solid 5px #ccc;
32 | }
33 |
34 | .hovered {
35 | background-color: #333;
36 | border-color: white;
37 | border-style: dashed;
38 | }
39 |
40 | @media (max-width: 800px) {
41 | body {
42 | flex-direction: column;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/drawing-app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Drawing App
8 |
9 |
10 |
11 |
12 | -
13 | 10
14 | +
15 |
16 | X
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/drawing-app/script.js:
--------------------------------------------------------------------------------
1 | const canvas = document.getElementById('canvas');
2 | const increaseBtn = document.getElementById('increase');
3 | const decreaseBtn = document.getElementById('decrease');
4 | const sizeEL = document.getElementById('size');
5 | const colorEl = document.getElementById('color');
6 | const clearEl = document.getElementById('clear');
7 |
8 | const ctx = canvas.getContext('2d');
9 |
10 | let size = 10
11 | let isPressed = false
12 | colorEl.value = 'black'
13 | let color = colorEl.value
14 | let x
15 | let y
16 |
17 | canvas.addEventListener('mousedown', (e) => {
18 | isPressed = true
19 |
20 | x = e.offsetX
21 | y = e.offsetY
22 | })
23 |
24 | document.addEventListener('mouseup', (e) => {
25 | isPressed = false
26 |
27 | x = undefined
28 | y = undefined
29 | })
30 |
31 | canvas.addEventListener('mousemove', (e) => {
32 | if(isPressed) {
33 | const x2 = e.offsetX
34 | const y2 = e.offsetY
35 |
36 | drawCircle(x2, y2)
37 | drawLine(x, y, x2, y2)
38 |
39 | x = x2
40 | y = y2
41 | }
42 | })
43 |
44 | function drawCircle(x, y) {
45 | ctx.beginPath();
46 | ctx.arc(x, y, size, 0, Math.PI * 2)
47 | ctx.fillStyle = color
48 | ctx.fill()
49 | }
50 |
51 | function drawLine(x1, y1, x2, y2) {
52 | ctx.beginPath()
53 | ctx.moveTo(x1, y1)
54 | ctx.lineTo(x2, y2)
55 | ctx.strokeStyle = color
56 | ctx.lineWidth = size * 2
57 | ctx.stroke()
58 | }
59 |
60 | function updateSizeOnScreen() {
61 | sizeEL.innerText = size
62 | }
63 |
64 | increaseBtn.addEventListener('click', () => {
65 | size += 5
66 |
67 | if(size > 50) {
68 | size = 50
69 | }
70 |
71 | updateSizeOnScreen()
72 | })
73 |
74 | decreaseBtn.addEventListener('click', () => {
75 | size -= 5
76 |
77 | if(size < 5) {
78 | size = 5
79 | }
80 |
81 | updateSizeOnScreen()
82 | })
83 |
84 | colorEl.addEventListener('change', (e) => color = e.target.value)
85 |
86 | clearEl.addEventListener('click', () => ctx.clearRect(0,0, canvas.width, canvas.height))
87 |
--------------------------------------------------------------------------------
/drawing-app/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #f5f5f5;
9 | font-family: 'Roboto', sans-serif;
10 | display: flex;
11 | flex-direction: column;
12 | align-items: center;
13 | justify-content: center;
14 | height: 100vh;
15 | margin: 0;
16 | }
17 |
18 | canvas {
19 | border: 2px solid steelblue;
20 | }
21 |
22 | .toolbox {
23 | background-color: steelblue;
24 | border: 1px solid slateblue;
25 | display: flex;
26 | width: 804px;
27 | padding: 1rem;
28 | }
29 |
30 | .toolbox > * {
31 | background-color: #fff;
32 | border: none;
33 | display: inline-flex;
34 | align-items: center;
35 | justify-content: center;
36 | font-size: 2rem;
37 | height: 50px;
38 | width: 50px;
39 | margin: 0.25rem;
40 | padding: 0.25rem;
41 | cursor: pointer;
42 | }
43 |
44 | .toolbox > *:last-child {
45 | margin-left: auto;
46 | }
47 |
--------------------------------------------------------------------------------
/drink-water/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Drink Water
8 |
9 |
10 | Drink Water
11 | Goal: 2 Liters
12 |
13 |
14 |
15 |
16 | Remained
17 |
18 |
19 |
20 |
21 |
22 | Select how many glasses of water that you have drank
23 |
24 |
25 |
250 ml
26 |
250 ml
27 |
250 ml
28 |
250 ml
29 |
250 ml
30 |
250 ml
31 |
250 ml
32 |
250 ml
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/drink-water/script.js:
--------------------------------------------------------------------------------
1 | const smallCups = document.querySelectorAll('.cup-small')
2 | const liters = document.getElementById('liters')
3 | const percentage = document.getElementById('percentage')
4 | const remained = document.getElementById('remained')
5 |
6 | updateBigCup()
7 |
8 | smallCups.forEach((cup, idx) => {
9 | cup.addEventListener('click', () => highlightCups(idx))
10 | })
11 |
12 | function highlightCups(idx) {
13 | if (idx===7 && smallCups[idx].classList.contains("full")) idx--;
14 | else if(smallCups[idx].classList.contains('full') && !smallCups[idx].nextElementSibling.classList.contains('full')) {
15 | idx--
16 | }
17 |
18 | smallCups.forEach((cup, idx2) => {
19 | if(idx2 <= idx) {
20 | cup.classList.add('full')
21 | } else {
22 | cup.classList.remove('full')
23 | }
24 | })
25 |
26 | updateBigCup()
27 | }
28 |
29 | function updateBigCup() {
30 | const fullCups = document.querySelectorAll('.cup-small.full').length
31 | const totalCups = smallCups.length
32 |
33 | if(fullCups === 0) {
34 | percentage.style.visibility = 'hidden'
35 | percentage.style.height = 0
36 | } else {
37 | percentage.style.visibility = 'visible'
38 | percentage.style.height = `${fullCups / totalCups * 330}px`
39 | percentage.innerText = `${fullCups / totalCups * 100}%`
40 | }
41 |
42 | if(fullCups === totalCups) {
43 | remained.style.visibility = 'hidden'
44 | remained.style.height = 0
45 | } else {
46 | remained.style.visibility = 'visible'
47 | liters.innerText = `${2 - (250 * fullCups / 1000)}L`
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/drink-water/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Montserrat:400,600&display=swap');
2 |
3 | :root {
4 | --border-color: #144fc6;
5 | --fill-color: #6ab3f8;
6 | }
7 |
8 | * {
9 | box-sizing: border-box;
10 | }
11 |
12 | body {
13 | background-color: #3494e4;
14 | color: #fff;
15 | font-family: 'Montserrat', sans-serif;
16 | display: flex;
17 | flex-direction: column;
18 | align-items: center;
19 | margin-bottom: 40px;
20 | }
21 |
22 | h1 {
23 | margin: 10px 0 0;
24 | }
25 |
26 | h3 {
27 | font-weight: 400;
28 | margin: 10px 0;
29 | }
30 |
31 | .cup {
32 | background-color: #fff;
33 | border: 4px solid var(--border-color);
34 | color: var(--border-color);
35 | border-radius: 0 0 40px 40px;
36 | height: 330px;
37 | width: 150px;
38 | margin: 30px 0;
39 | display: flex;
40 | flex-direction: column;
41 | overflow: hidden;
42 | }
43 |
44 | .cup.cup-small {
45 | height: 95px;
46 | width: 50px;
47 | border-radius: 0 0 15px 15px;
48 | background-color: rgba(255, 255, 255, 0.9);
49 | cursor: pointer;
50 | font-size: 14px;
51 | align-items: center;
52 | justify-content: center;
53 | text-align: center;
54 | margin: 5px;
55 | transition: 0.3s ease;
56 | }
57 |
58 | .cup.cup-small.full {
59 | background-color: var(--fill-color);
60 | color: #fff;
61 | }
62 |
63 | .cups {
64 | display: flex;
65 | flex-wrap: wrap;
66 | align-items: center;
67 | justify-content: center;
68 | width: 280px;
69 | }
70 |
71 | .remained {
72 | display: flex;
73 | flex-direction: column;
74 | align-items: center;
75 | justify-content: center;
76 | text-align: center;
77 | flex: 1;
78 | transition: 0.3s ease;
79 | }
80 |
81 | .remained span {
82 | font-size: 20px;
83 | font-weight: bold;
84 | }
85 |
86 | .remained small {
87 | font-size: 12px;
88 | }
89 |
90 | .percentage {
91 | background-color: var(--fill-color);
92 | display: flex;
93 | align-items: center;
94 | justify-content: center;
95 | font-weight: bold;
96 | font-size: 30px;
97 | height: 0;
98 | transition: 0.3s ease;
99 | }
100 |
101 | .text {
102 | text-align: center;
103 | margin: 0 0 5px;
104 | }
105 |
--------------------------------------------------------------------------------
/event-keycodes/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Event KeyCodes
8 |
9 |
10 |
11 |
12 | Press any key to get the keyCode
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/event-keycodes/script.js:
--------------------------------------------------------------------------------
1 | const insert = document.getElementById('insert')
2 |
3 | window.addEventListener('keydown', (event) => {
4 | insert.innerHTML = `
5 |
6 | ${event.key === ' ' ? 'Space' : event.key}
7 | event.key
8 |
9 |
10 |
11 | ${event.keyCode}
12 | event.keyCode
13 |
14 |
15 |
16 | ${event.code}
17 | event.code
18 |
19 | `
20 | })
--------------------------------------------------------------------------------
/event-keycodes/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #e1e1e1;
9 | font-family: 'Muli', sans-serif;
10 | display: flex;
11 | align-items: center;
12 | justify-content: center;
13 | text-align: center;
14 | height: 100vh;
15 | overflow: hidden;
16 | margin: 0;
17 | }
18 |
19 | .key {
20 | border: 1px solid #999;
21 | background-color: #eee;
22 | box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
23 | display: inline-flex;
24 | align-items: center;
25 | font-size: 20px;
26 | font-weight: bold;
27 | padding: 20px;
28 | flex-direction: column;
29 | margin: 10px;
30 | min-width: 150px;
31 | position: relative;
32 | }
33 |
34 | .key small {
35 | position: absolute;
36 | top: -24px;
37 | left: 0;
38 | text-align: center;
39 | width: 100%;
40 | color: #555;
41 | font-size: 14px;
42 | }
43 |
44 | @media(max-width:768px){
45 | .key{
46 | margin: 10px 0px;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/expanding-cards/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Expanding Cards
8 |
9 |
10 |
11 |
12 |
Explore The World
13 |
14 |
15 |
Wild Forest
16 |
17 |
18 |
Sunny Beach
19 |
20 |
21 |
City on Winter
22 |
23 |
24 |
Mountains - Clouds
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/expanding-cards/script.js:
--------------------------------------------------------------------------------
1 | const panels = document.querySelectorAll('.panel')
2 |
3 | panels.forEach(panel => {
4 | panel.addEventListener('click', () => {
5 | removeActiveClasses()
6 | panel.classList.add('active')
7 | })
8 | })
9 |
10 | function removeActiveClasses() {
11 | panels.forEach(panel => {
12 | panel.classList.remove('active')
13 | })
14 | }
--------------------------------------------------------------------------------
/expanding-cards/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | font-family: 'Muli', sans-serif;
9 | display: flex;
10 | align-items: center;
11 | justify-content: center;
12 | height: 100vh;
13 | overflow: hidden;
14 | margin: 0;
15 | }
16 |
17 | .container {
18 | display: flex;
19 | width: 90vw;
20 | }
21 |
22 | .panel {
23 | background-size: cover;
24 | background-position: center;
25 | background-repeat: no-repeat;
26 | height: 80vh;
27 | border-radius: 50px;
28 | color: #fff;
29 | cursor: pointer;
30 | flex: 0.5;
31 | margin: 10px;
32 | position: relative;
33 | -webkit-transition: all 700ms ease-in;
34 | }
35 |
36 | .panel h3 {
37 | font-size: 24px;
38 | position: absolute;
39 | bottom: 20px;
40 | left: 20px;
41 | margin: 0;
42 | opacity: 0;
43 | }
44 |
45 | .panel.active {
46 | flex: 5;
47 | }
48 |
49 | .panel.active h3 {
50 | opacity: 1;
51 | transition: opacity 0.3s ease-in 0.4s;
52 | }
53 |
54 | @media (max-width: 480px) {
55 | .container {
56 | width: 100vw;
57 | }
58 |
59 | .panel:nth-of-type(4),
60 | .panel:nth-of-type(5) {
61 | display: none;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/faq-collapse/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | FAQ
9 |
10 |
11 | Frequently Asked Questions
12 |
13 |
14 |
15 | Why shouldn't we trust atoms?
16 |
17 |
18 |
19 | They make up everything
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | What do you call someone with no body and no nose?
31 |
32 |
33 | Nobody knows.
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | What's the object-oriented way to become wealthy?
44 |
45 |
46 | Inheritance.
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | How many tickles does it take to tickle an octopus?
57 |
58 |
59 | Ten-tickles!
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | What is: 1 + 1?
70 |
71 |
72 | Depends on who are you asking.
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/faq-collapse/script.js:
--------------------------------------------------------------------------------
1 | const toggles = document.querySelectorAll('.faq-toggle')
2 |
3 | toggles.forEach(toggle => {
4 | toggle.addEventListener('click', () => {
5 | toggle.parentNode.classList.toggle('active')
6 | })
7 | })
--------------------------------------------------------------------------------
/faq-collapse/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | font-family: 'Muli', sans-serif;
9 | background-color: #f0f0f0;
10 | }
11 |
12 | h1 {
13 | margin: 50px 0 30px;
14 | text-align: center;
15 | }
16 |
17 | .faq-container {
18 | max-width: 600px;
19 | margin: 0 auto;
20 | }
21 |
22 | .faq {
23 | background-color: transparent;
24 | border: 1px solid #9fa4a8;
25 | border-radius: 10px;
26 | margin: 20px 0;
27 | padding: 30px;
28 | position: relative;
29 | overflow: hidden;
30 | transition: 0.3s ease;
31 | }
32 |
33 | .faq.active {
34 | background-color: #fff;
35 | box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1), 0 3px 6px rgba(0, 0, 0, 0.1);
36 | }
37 |
38 | .faq.active::before,
39 | .faq.active::after {
40 | content: '\f075';
41 | font-family: 'Font Awesome 5 Free';
42 | color: #2ecc71;
43 | font-size: 7rem;
44 | position: absolute;
45 | opacity: 0.2;
46 | top: 20px;
47 | left: 20px;
48 | z-index: 0;
49 | }
50 |
51 | .faq.active::before {
52 | color: #3498db;
53 | top: -10px;
54 | left: -30px;
55 | transform: rotateY(180deg);
56 | }
57 |
58 | .faq-title {
59 | margin: 0 35px 0 0;
60 | }
61 |
62 | .faq-text {
63 | display: none;
64 | margin: 30px 0 0;
65 | }
66 |
67 | .faq.active .faq-text {
68 | display: block;
69 | }
70 |
71 | .faq-toggle {
72 | background-color: transparent;
73 | border: 0;
74 | border-radius: 50%;
75 | cursor: pointer;
76 | display: flex;
77 | align-items: center;
78 | justify-content: center;
79 | font-size: 16px;
80 | padding: 0;
81 | position: absolute;
82 | top: 30px;
83 | right: 30px;
84 | height: 30px;
85 | width: 30px;
86 | }
87 |
88 | .faq-toggle:focus {
89 | outline: 0;
90 | }
91 |
92 | .faq-toggle .fa-times {
93 | display: none;
94 | }
95 |
96 | .faq.active .faq-toggle .fa-times {
97 | color: #fff;
98 | display: block;
99 | }
100 |
101 | .faq.active .faq-toggle .fa-chevron-down {
102 | display: none;
103 | }
104 |
105 | .faq.active .faq-toggle {
106 | background-color: #9fa4a8;
107 | }
108 |
--------------------------------------------------------------------------------
/feedback-ui-design/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Let Us Know Your Feedback
9 |
10 |
11 |
12 |
How satisfied are you with our customer support performance?
13 |
14 |
15 |
16 |
Unhappy
17 |
18 |
19 |
20 |
21 |
Neutral
22 |
23 |
24 |
25 |
26 |
Satisfied
27 |
28 |
29 |
Send Review
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/feedback-ui-design/script.js:
--------------------------------------------------------------------------------
1 | const ratings = document.querySelectorAll('.rating')
2 | const ratingsContainer = document.querySelector('.ratings-container')
3 | const sendBtn = document.querySelector('#send')
4 | const panel = document.querySelector('#panel')
5 | let selectedRating = 'Satisfied'
6 |
7 | ratingsContainer.addEventListener('click', (e) => {
8 | if(e.target.parentNode.classList.contains('rating') && e.target.nextElementSibling) {
9 | removeActive()
10 | e.target.parentNode.classList.add('active')
11 | selectedRating = e.target.nextElementSibling.innerHTML
12 | } else if(
13 | e.target.parentNode.classList.contains('rating') &&
14 | e.target.previousSibling &&
15 | e.target.previousElementSibling.nodeName === 'IMG'
16 | ) {
17 | removeActive()
18 | e.target.parentNode.classList.add('active')
19 | selectedRating = e.target.innerHTML
20 | }
21 |
22 | })
23 |
24 | sendBtn.addEventListener('click', (e) => {
25 | panel.innerHTML = `
26 |
27 | Thank You!
28 |
29 | Feedback: ${selectedRating}
30 | We'll use your feedback to improve our customer support
31 | `
32 | })
33 |
34 | function removeActive() {
35 | for(let i = 0; i < ratings.length; i++) {
36 | ratings[i].classList.remove('active')
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/feedback-ui-design/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Montserrat&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #fef9f2;
9 | font-family: 'Montserrat', sans-serif;
10 | display: flex;
11 | align-items: center;
12 | justify-content: center;
13 | height: 100vh;
14 | overflow: hidden;
15 | margin: 0;
16 | }
17 |
18 | .panel-container {
19 | background-color: #fff;
20 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
21 | border-radius: 4px;
22 | font-size: 90%;
23 | display: flex;
24 | flex-direction: column;
25 | justify-content: center;
26 | align-items: center;
27 | text-align: center;
28 | padding: 30px;
29 | max-width: 400px;
30 | }
31 |
32 | .panel-container strong {
33 | line-height: 20px;
34 | }
35 |
36 | .ratings-container {
37 | display: flex;
38 | margin: 20px 0;
39 | }
40 |
41 | .rating {
42 | flex: 1;
43 | cursor: pointer;
44 | padding: 20px;
45 | margin: 10px 5px;
46 | }
47 |
48 | .rating:hover,
49 | .rating.active {
50 | border-radius: 4px;
51 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
52 | }
53 |
54 | .rating img {
55 | width: 40px;
56 | }
57 |
58 | .rating small {
59 | color: #555;
60 | display: inline-block;
61 | margin: 10px 0 0;
62 | }
63 |
64 | .rating:hover small,
65 | .rating.active small {
66 | color: #111;
67 | }
68 |
69 | .btn {
70 | background-color: #302d2b;
71 | color: #fff;
72 | border: 0;
73 | border-radius: 4px;
74 | padding: 12px 30px;
75 | cursor: pointer;
76 | }
77 |
78 | .btn:focus {
79 | outline: 0;
80 | }
81 |
82 | .btn:active {
83 | transform: scale(0.98);
84 | }
85 |
86 | .fa-heart {
87 | color: red;
88 | font-size: 30px;
89 | margin-bottom: 10px;
90 | }
91 |
--------------------------------------------------------------------------------
/form-input-wave/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Form Input Wave
8 |
9 |
10 |
11 |
Please Login
12 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/form-input-wave/script.js:
--------------------------------------------------------------------------------
1 | const labels = document.querySelectorAll('.form-control label')
2 |
3 | labels.forEach(label => {
4 | label.innerHTML = label.innerText
5 | .split('')
6 | .map((letter, idx) => `${letter} `)
7 | .join('')
8 | })
--------------------------------------------------------------------------------
/form-input-wave/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: steelblue;
9 | color: #fff;
10 | font-family: 'Muli', sans-serif;
11 | display: flex;
12 | flex-direction: column;
13 | align-items: center;
14 | justify-content: center;
15 | height: 100vh;
16 | overflow: hidden;
17 | margin: 0;
18 | }
19 |
20 | .container {
21 | background-color: rgba(0, 0, 0, 0.4);
22 | padding: 20px 40px;
23 | border-radius: 5px;
24 | }
25 |
26 | .container h1 {
27 | text-align: center;
28 | margin-bottom: 30px;
29 | }
30 |
31 | .container a {
32 | text-decoration: none;
33 | color: lightblue;
34 | }
35 |
36 | .btn {
37 | cursor: pointer;
38 | display: inline-block;
39 | width: 100%;
40 | background: lightblue;
41 | padding: 15px;
42 | font-family: inherit;
43 | font-size: 16px;
44 | border: 0;
45 | border-radius: 5px;
46 | }
47 |
48 | .btn:focus {
49 | outline: 0;
50 | }
51 |
52 | .btn:active {
53 | transform: scale(0.98);
54 | }
55 |
56 | .text {
57 | margin-top: 30px;
58 | }
59 |
60 | .form-control {
61 | position: relative;
62 | margin: 20px 0 40px;
63 | width: 300px;
64 | }
65 |
66 | .form-control input {
67 | background-color: transparent;
68 | border: 0;
69 | border-bottom: 2px #fff solid;
70 | display: block;
71 | width: 100%;
72 | padding: 15px 0;
73 | font-size: 18px;
74 | color: #fff;
75 | }
76 |
77 | .form-control input:focus,
78 | .form-control input:valid {
79 | outline: 0;
80 | border-bottom-color: lightblue;
81 | }
82 |
83 | .form-control label {
84 | position: absolute;
85 | top: 15px;
86 | left: 0;
87 | pointer-events: none;
88 | }
89 |
90 | .form-control label span {
91 | display: inline-block;
92 | font-size: 18px;
93 | min-width: 5px;
94 | transition: 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
95 | }
96 |
97 | .form-control input:focus + label span,
98 | .form-control input:valid + label span {
99 | color: lightblue;
100 | transform: translateY(-30px);
101 | }
102 |
--------------------------------------------------------------------------------
/github-profiles/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Github Profiles
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/github-profiles/script.js:
--------------------------------------------------------------------------------
1 | const APIURL = 'https://api.github.com/users/'
2 |
3 | const main = document.getElementById('main')
4 | const form = document.getElementById('form')
5 | const search = document.getElementById('search')
6 |
7 | async function getUser(username) {
8 | try {
9 | const { data } = await axios(APIURL + username)
10 |
11 | createUserCard(data)
12 | getRepos(username)
13 | } catch(err) {
14 | if(err.response.status == 404) {
15 | createErrorCard('No profile with this username')
16 | }
17 | }
18 | }
19 |
20 | async function getRepos(username) {
21 | try {
22 | const { data } = await axios(APIURL + username + '/repos?sort=created')
23 |
24 | addReposToCard(data)
25 | } catch(err) {
26 | createErrorCard('Problem fetching repos')
27 | }
28 | }
29 |
30 | function createUserCard(user) {
31 | const userID = user.name || user.login
32 | const userBio = user.bio ? `${user.bio}
` : ''
33 | const cardHTML = `
34 |
35 |
36 |
37 |
38 |
39 |
${userID}
40 | ${userBio}
41 |
42 | ${user.followers} Followers
43 | ${user.following} Following
44 | ${user.public_repos} Repos
45 |
46 |
47 |
48 |
49 |
50 | `
51 | main.innerHTML = cardHTML
52 |
53 | }
54 |
55 | function createErrorCard(msg) {
56 | const cardHTML = `
57 |
58 |
${msg}
59 |
60 | `
61 |
62 | main.innerHTML = cardHTML
63 | }
64 |
65 | function addReposToCard(repos) {
66 | const reposEl = document.getElementById('repos')
67 |
68 | repos
69 | .slice(0, 5)
70 | .forEach(repo => {
71 | const repoEl = document.createElement('a')
72 | repoEl.classList.add('repo')
73 | repoEl.href = repo.html_url
74 | repoEl.target = '_blank'
75 | repoEl.innerText = repo.name
76 |
77 | reposEl.appendChild(repoEl)
78 | })
79 | }
80 |
81 | form.addEventListener('submit', (e) => {
82 | e.preventDefault()
83 |
84 | const user = search.value
85 |
86 | if(user) {
87 | getUser(user)
88 |
89 | search.value = ''
90 | }
91 | })
92 |
93 |
--------------------------------------------------------------------------------
/github-profiles/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #2a2a72;
9 | color: #fff;
10 | font-family: 'Poppins', sans-serif;
11 | display: flex;
12 | flex-direction: column;
13 | align-items: center;
14 | justify-content: center;
15 | height: 100vh;
16 | overflow: hidden;
17 | margin: 0;
18 | }
19 |
20 | .user-form {
21 | width: 100%;
22 | max-width: 700px;
23 | }
24 |
25 | .user-form input {
26 | width: 100%;
27 | display: block;
28 | background-color: #4c2885;
29 | border: none;
30 | border-radius: 10px;
31 | color: #fff;
32 | padding: 1rem;
33 | margin-bottom: 2rem;
34 | font-family: inherit;
35 | font-size: 1rem;
36 | box-shadow: 0 5px 10px rgba(154, 160, 185, 0.05),
37 | 0 15px 40px rgba(0, 0, 0, 0.1);
38 | }
39 |
40 | .user-form input::placeholder {
41 | color: #bbb;
42 | }
43 |
44 | .user-form input:focus {
45 | outline: none;
46 | }
47 |
48 | .card {
49 | max-width: 800px;
50 | background-color: #4c2885;
51 | border-radius: 20px;
52 | box-shadow: 0 5px 10px rgba(154, 160, 185, 0.05),
53 | 0 15px 40px rgba(0, 0, 0, 0.1);
54 | display: flex;
55 | padding: 3rem;
56 | margin: 0 1.5rem;
57 | }
58 |
59 | .avatar {
60 | border-radius: 50%;
61 | border: 10px solid #2a2a72;
62 | height: 150px;
63 | width: 150px;
64 | }
65 |
66 | .user-info {
67 | color: #eee;
68 | margin-left: 2rem;
69 | }
70 |
71 | .user-info h2 {
72 | margin-top: 0;
73 | }
74 |
75 | .user-info ul {
76 | list-style-type: none;
77 | display: flex;
78 | justify-content: space-between;
79 | padding: 0;
80 | max-width: 400px;
81 | }
82 |
83 | .user-info ul li {
84 | display: flex;
85 | align-items: center;
86 | }
87 |
88 | .user-info ul li strong {
89 | font-size: 0.9rem;
90 | margin-left: 0.5rem;
91 | }
92 |
93 | .repo {
94 | text-decoration: none;
95 | color: #fff;
96 | background-color: #212a72;
97 | font-size: 0.7rem;
98 | padding: 0.25rem 0.5rem;
99 | margin-right: 0.5rem;
100 | margin-bottom: 0.5rem;
101 | display: inline-block;
102 | }
103 |
104 | @media (max-width: 500px) {
105 | .card {
106 | flex-direction: column;
107 | align-items: center;
108 | }
109 |
110 | .user-form {
111 | max-width: 400px;
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/good-cheap-fast/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Good, Cheap, Fast
8 |
9 |
10 | How do you want your project to be?
11 |
12 |
13 |
14 |
15 |
16 |
Good
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
Cheap
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
Fast
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/good-cheap-fast/script.js:
--------------------------------------------------------------------------------
1 | const toggles = document.querySelectorAll('.toggle')
2 | const good = document.querySelector('#good')
3 | const cheap = document.querySelector('#cheap')
4 | const fast = document.querySelector('#fast')
5 |
6 | toggles.forEach(toggle => toggle.addEventListener('change', (e) => doTheTrick(e.target)))
7 |
8 | function doTheTrick(theClickedOne) {
9 | if(good.checked && cheap.checked && fast.checked) {
10 | if(good === theClickedOne) {
11 | fast.checked = false
12 | }
13 |
14 | if(cheap === theClickedOne) {
15 | good.checked = false
16 | }
17 |
18 | if(fast === theClickedOne) {
19 | cheap.checked = false
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/good-cheap-fast/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | font-family: 'Roboto', sans-serif;
9 | display: flex;
10 | flex-direction: column;
11 | align-items: center;
12 | justify-content: center;
13 | height: 100vh;
14 | overflow: hidden;
15 | margin: 0;
16 | }
17 |
18 | .toggle-container {
19 | display: flex;
20 | align-items: center;
21 | margin: 10px 0;
22 | width: 200px;
23 | }
24 |
25 | .toggle {
26 | visibility: hidden;
27 | }
28 |
29 | .label {
30 | position: relative;
31 | background-color: #d0d0d0;
32 | border-radius: 50px;
33 | cursor: pointer;
34 | display: inline-block;
35 | margin: 0 15px 0;
36 | width: 80px;
37 | height: 40px;
38 | }
39 |
40 | .toggle:checked + .label {
41 | background-color: #8e44ad;
42 | }
43 |
44 | .ball {
45 | background: #fff;
46 | height: 34px;
47 | width: 34px;
48 | border-radius: 50%;
49 | position: absolute;
50 | top: 3px;
51 | left: 3px;
52 | align-items: center;
53 | justify-content: center;
54 | animation: slideOff 0.3s linear forwards;
55 | }
56 |
57 | .toggle:checked + .label .ball {
58 | animation: slideOn 0.3s linear forwards;
59 | }
60 |
61 | @keyframes slideOn {
62 | 0% {
63 | transform: translateX(0) scale(1);
64 | }
65 | 50% {
66 | transform: translateX(20px) scale(1.2);
67 | }
68 | 100% {
69 | transform: translateX(40px) scale(1);
70 | }
71 | }
72 |
73 | @keyframes slideOff {
74 | 0% {
75 | transform: translateX(40px) scale(1);
76 | }
77 | 50% {
78 | transform: translateX(20px) scale(1.2);
79 | }
80 | 100% {
81 | transform: translateX(0) scale(1);
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/hidden-search/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Hidden Search
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/hidden-search/script.js:
--------------------------------------------------------------------------------
1 | const search = document.querySelector('.search')
2 | const btn = document.querySelector('.btn')
3 | const input = document.querySelector('.input')
4 |
5 | btn.addEventListener('click', () => {
6 | search.classList.toggle('active')
7 | input.focus()
8 | })
--------------------------------------------------------------------------------
/hidden-search/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-image: linear-gradient(90deg, #7d5fff, #7158e2);
9 | font-family: 'Roboto', sans-serif;
10 | display: flex;
11 | align-items: center;
12 | justify-content: center;
13 | height: 100vh;
14 | overflow: hidden;
15 | margin: 0;
16 | }
17 |
18 | .search {
19 | position: relative;
20 | height: 50px;
21 | }
22 |
23 | .search .input {
24 | background-color: #fff;
25 | border: 0;
26 | font-size: 18px;
27 | padding: 15px;
28 | height: 50px;
29 | width: 50px;
30 | transition: width 0.3s ease;
31 | }
32 |
33 | .btn {
34 | background-color: #fff;
35 | border: 0;
36 | cursor: pointer;
37 | font-size: 24px;
38 | position: absolute;
39 | top: 0;
40 | left: 0;
41 | height: 50px;
42 | width: 50px;
43 | transition: transform 0.3s ease;
44 | }
45 |
46 | .btn:focus,
47 | .input:focus {
48 | outline: none;
49 | }
50 |
51 | .search.active .input {
52 | width: 200px;
53 | }
54 |
55 | .search.active .btn {
56 | transform: translateX(198px);
57 | }
58 |
--------------------------------------------------------------------------------
/hoverboard/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Hoverboard
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/hoverboard/script.js:
--------------------------------------------------------------------------------
1 | const container = document.getElementById('container')
2 | const colors = ['#e74c3c', '#8e44ad', '#3498db', '#e67e22', '#2ecc71']
3 | const SQUARES = 500
4 |
5 | for(let i = 0; i < SQUARES; i++) {
6 | const square = document.createElement('div')
7 | square.classList.add('square')
8 |
9 | square.addEventListener('mouseover', () => setColor(square))
10 |
11 | square.addEventListener('mouseout', () => removeColor(square))
12 |
13 | container.appendChild(square)
14 | }
15 |
16 | function setColor(element) {
17 | const color = getRandomColor()
18 | element.style.background = color
19 | element.style.boxShadow = `0 0 2px ${color}, 0 0 10px ${color}`
20 | }
21 |
22 | function removeColor(element) {
23 | element.style.background = '#1d1d1d'
24 | element.style.boxShadow = '0 0 2px #000'
25 | }
26 |
27 | function getRandomColor() {
28 | return colors[Math.floor(Math.random() * colors.length)]
29 | }
--------------------------------------------------------------------------------
/hoverboard/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | }
4 |
5 | body {
6 | background-color: #111;
7 | display: flex;
8 | align-items: center;
9 | justify-content: center;
10 | height: 100vh;
11 | overflow: hidden;
12 | margin: 0;
13 | }
14 |
15 | .container {
16 | display: flex;
17 | align-items: center;
18 | justify-content: center;
19 | flex-wrap: wrap;
20 | max-width: 400px;
21 | }
22 |
23 | .square {
24 | background-color: #1d1d1d;
25 | box-shadow: 0 0 2px #000;
26 | height: 16px;
27 | width: 16px;
28 | margin: 2px;
29 | transition: 2s ease;
30 | }
31 |
32 | .square:hover {
33 | transition-duration: 0s;
34 | }
35 |
--------------------------------------------------------------------------------
/image-carousel/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Image Carousel
8 |
9 |
10 |
11 |
28 |
29 |
30 | Prev
31 | Next
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/image-carousel/script.js:
--------------------------------------------------------------------------------
1 | const imgs = document.getElementById('imgs')
2 | const leftBtn = document.getElementById('left')
3 | const rightBtn = document.getElementById('right')
4 |
5 | const img = document.querySelectorAll('#imgs img')
6 |
7 | let idx = 0
8 |
9 | let interval = setInterval(run, 2000)
10 |
11 | function run() {
12 | idx++
13 | changeImage()
14 | }
15 |
16 | function changeImage() {
17 | if(idx > img.length - 1) {
18 | idx = 0
19 | } else if(idx < 0) {
20 | idx = img.length - 1
21 | }
22 |
23 | imgs.style.transform = `translateX(${-idx * 500}px)`
24 | }
25 |
26 | function resetInterval() {
27 | clearInterval(interval)
28 | interval = setInterval(run, 2000)
29 | }
30 |
31 | rightBtn.addEventListener('click', () => {
32 | idx++
33 | changeImage()
34 | resetInterval()
35 | })
36 |
37 | leftBtn.addEventListener('click', () => {
38 | idx--
39 | changeImage()
40 | resetInterval()
41 | })
42 |
--------------------------------------------------------------------------------
/image-carousel/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | font-family: 'Roboto', sans-serif;
9 | display: flex;
10 | align-items: center;
11 | justify-content: center;
12 | height: 100vh;
13 | margin: 0;
14 | }
15 |
16 | img {
17 | width: 500px;
18 | height: 500px;
19 | object-fit: cover;
20 | }
21 |
22 | .carousel {
23 | box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
24 | height: 530px;
25 | width: 500px;
26 | overflow: hidden;
27 | }
28 |
29 | .image-container {
30 | display: flex;
31 | transform: translateX(0);
32 | transition: transform 0.5s ease-in-out;
33 | }
34 |
35 | .buttons-container {
36 | display: flex;
37 | justify-content: space-between;
38 | }
39 |
40 | .btn {
41 | background-color: rebeccapurple;
42 | color: #fff;
43 | border: none;
44 | padding: 0.5rem;
45 | cursor: pointer;
46 | width: 49.5%;
47 | }
48 |
49 | .btn:hover {
50 | opacity: 0.9;
51 | }
52 |
53 | .btn:focus {
54 | outline: none;
55 | }
56 |
--------------------------------------------------------------------------------
/incrementing-counter/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Increment Counter
9 |
10 |
11 |
12 |
13 |
14 |
Twitter Followers
15 |
16 |
17 |
18 |
19 |
20 |
YouTube Subscribers
21 |
22 |
23 |
24 |
25 |
26 |
Facebook Fans
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/incrementing-counter/script.js:
--------------------------------------------------------------------------------
1 | const counters = document.querySelectorAll('.counter')
2 |
3 | counters.forEach(counter => {
4 | counter.innerText = '0'
5 |
6 | const updateCounter = () => {
7 | const target = +counter.getAttribute('data-target')
8 | const c = +counter.innerText
9 |
10 | const increment = target / 200
11 |
12 | if(c < target) {
13 | counter.innerText = `${Math.ceil(c + increment)}`
14 | setTimeout(updateCounter, 1)
15 | } else {
16 | counter.innerText = target
17 | }
18 | }
19 |
20 | updateCounter()
21 | })
--------------------------------------------------------------------------------
/incrementing-counter/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Roboto+Mono&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #8e44ad;
9 | color: #fff;
10 | font-family: 'Roboto Mono', sans-serif;
11 | display: flex;
12 | align-items: center;
13 | justify-content: center;
14 | height: 100vh;
15 | overflow: hidden;
16 | margin: 0;
17 | }
18 |
19 | .counter-container {
20 | display: flex;
21 | flex-direction: column;
22 | justify-content: center;
23 | text-align: center;
24 | margin: 30px 50px;
25 | }
26 |
27 | .counter {
28 | font-size: 60px;
29 | margin-top: 10px;
30 | }
31 |
32 | @media (max-width: 580px) {
33 | body {
34 | flex-direction: column;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/insect-catch-game/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Catch The Insect
8 |
9 |
10 |
11 |
Catch The Insect
12 | Play Game
13 |
14 |
15 |
16 |
What is your "favorite" insect?
17 |
18 |
19 |
20 | Fly
21 |
22 |
23 |
24 |
25 |
26 | Mosquito
27 |
31 |
32 |
33 |
34 |
35 | Spider
36 |
40 |
41 |
42 |
43 |
44 | Roach
45 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
Time: 00:00
56 | Score: 0
57 |
58 | Are you annnoyed yet?
59 | You are playing an impossible game!!
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/insect-catch-game/script.js:
--------------------------------------------------------------------------------
1 | const screens = document.querySelectorAll('.screen');
2 | const choose_insect_btns = document.querySelectorAll('.choose-insect-btn');
3 | const start_btn = document.getElementById('start-btn')
4 | const game_container = document.getElementById('game-container')
5 | const timeEl = document.getElementById('time')
6 | const scoreEl = document.getElementById('score')
7 | const message = document.getElementById('message')
8 | let seconds = 0
9 | let score = 0
10 | let selected_insect = {}
11 |
12 | start_btn.addEventListener('click', () => screens[0].classList.add('up'))
13 |
14 | choose_insect_btns.forEach(btn => {
15 | btn.addEventListener('click', () => {
16 | const img = btn.querySelector('img')
17 | const src = img.getAttribute('src')
18 | const alt = img.getAttribute('alt')
19 | selected_insect = { src, alt }
20 | screens[1].classList.add('up')
21 | setTimeout(createInsect, 1000)
22 | startGame()
23 | })
24 | })
25 |
26 | function startGame() {
27 | setInterval(increaseTime, 1000)
28 | }
29 |
30 | function increaseTime() {
31 | let m = Math.floor(seconds / 60)
32 | let s = seconds % 60
33 | m = m < 10 ? `0${m}` : m
34 | s = s < 10 ? `0${s}` : s
35 | timeEl.innerHTML = `Time: ${m}:${s}`
36 | seconds++
37 | }
38 |
39 | function createInsect() {
40 | const insect = document.createElement('div')
41 | insect.classList.add('insect')
42 | const { x, y } = getRandomLocation()
43 | insect.style.top = `${y}px`
44 | insect.style.left = `${x}px`
45 | insect.innerHTML = ` `
46 |
47 | insect.addEventListener('click', catchInsect)
48 |
49 | game_container.appendChild(insect)
50 | }
51 |
52 | function getRandomLocation() {
53 | const width = window.innerWidth
54 | const height = window.innerHeight
55 | const x = Math.random() * (width - 200) + 100
56 | const y = Math.random() * (height - 200) + 100
57 | return { x, y }
58 | }
59 |
60 | function catchInsect() {
61 | increaseScore()
62 | this.classList.add('caught')
63 | setTimeout(() => this.remove(), 2000)
64 | addInsects()
65 | }
66 |
67 | function addInsects() {
68 | setTimeout(createInsect, 1000)
69 | setTimeout(createInsect, 1500)
70 | }
71 |
72 | function increaseScore() {
73 | score++
74 | if(score > 19) {
75 | message.classList.add('visible')
76 | }
77 | scoreEl.innerHTML = `Score: ${score}`
78 | }
--------------------------------------------------------------------------------
/insect-catch-game/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Press+Start+2P&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #516dff;
9 | color: #fff;
10 | font-family: 'Press Start 2P', sans-serif;
11 | height: 100vh;
12 | overflow: hidden;
13 | margin: 0;
14 | text-align: center;
15 | }
16 |
17 | a {
18 | color: #fff;
19 | }
20 |
21 | h1 {
22 | line-height: 1.4;
23 | }
24 |
25 | .btn {
26 | border: 0;
27 | background-color: #fff;
28 | color: #516dff;
29 | padding: 15px 20px;
30 | font-family: inherit;
31 | cursor: pointer;
32 | }
33 |
34 | .btn:hover {
35 | opacity: 0.9;
36 | }
37 |
38 | .btn:focus {
39 | outline: 0;
40 | }
41 |
42 | .screen {
43 | display: flex;
44 | flex-direction: column;
45 | align-items: center;
46 | justify-content: center;
47 | height: 100vh;
48 | width: 100vw;
49 | transition: margin 0.5s ease-out;
50 | }
51 |
52 | .screen.up {
53 | margin-top: -100vh;
54 | }
55 |
56 | .insects-list {
57 | display: flex;
58 | flex-wrap: wrap;
59 | justify-content: center;
60 | list-style-type: none;
61 | padding: 0;
62 | }
63 |
64 | .insects-list li {
65 | margin: 10px;
66 | }
67 |
68 | .choose-insect-btn {
69 | background-color: transparent;
70 | border: 2px solid #fff;
71 | color: #fff;
72 | cursor: pointer;
73 | font-family: inherit;
74 | width: 150px;
75 | height: 150px;
76 | }
77 |
78 | .choose-insect-btn:hover {
79 | background-color: #fff;
80 | color: #516dff;
81 | }
82 |
83 | .choose-insect-btn:active {
84 | background-color: rgba(255, 255, 255, 0.7);
85 | }
86 |
87 | .choose-insect-btn img {
88 | width: 100px;
89 | height: 100px;
90 | object-fit: contain;
91 | }
92 |
93 | .game-container {
94 | position: relative;
95 | }
96 |
97 | .time,
98 | .score {
99 | position: absolute;
100 | top: 20px;
101 | }
102 |
103 | .time {
104 | left: 20px;
105 | }
106 |
107 | .score {
108 | right: 20px;
109 | }
110 |
111 | .message {
112 | line-height: 1.7;
113 | background-color: rgba(0, 0, 0, 0.5);
114 | width: 100%;
115 | padding: 20px;
116 | z-index: 100;
117 | text-align: center;
118 | opacity: 0;
119 | position: absolute;
120 | top: 0;
121 | left: 50%;
122 | transform: translate(-50%, -150%);
123 | transition: transform 0.4s ease-in;
124 | }
125 |
126 | .message.visible {
127 | transform: translate(-50%, 150%);
128 | opacity: 1;
129 | }
130 |
131 | .insect {
132 | cursor: pointer;
133 | display: flex;
134 | align-items: center;
135 | justify-content: center;
136 | width: 100px;
137 | height: 100px;
138 | position: absolute;
139 | transform: translate(-50%, -50%) scale(1);
140 | transition: transform 0.3s ease-in-out;
141 | }
142 |
143 | .insect.caught {
144 | transform: translate(-50%, -50%) scale(0);
145 | }
146 |
147 | .insect img {
148 | width: 100px;
149 | height: 100px;
150 | }
151 |
--------------------------------------------------------------------------------
/kinetic-loader/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Kinetic Loader
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/kinetic-loader/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | }
4 |
5 | body {
6 | background-color: #2c3e50;
7 | display: flex;
8 | align-items: center;
9 | justify-content: center;
10 | height: 100vh;
11 | overflow: hidden;
12 | margin: 0;
13 | }
14 |
15 | .kinetic {
16 | position: relative;
17 | height: 80px;
18 | width: 80px;
19 | }
20 |
21 | .kinetic::after,
22 | .kinetic::before {
23 | content: '';
24 | position: absolute;
25 | top: 0;
26 | left: 0;
27 | width: 0;
28 | height: 0;
29 | border: 50px solid transparent;
30 | border-bottom-color: #fff;
31 | animation: rotateA 2s linear infinite 0.5s;
32 | }
33 |
34 | .kinetic::before {
35 | transform: rotate(90deg);
36 | animation: rotateB 2s linear infinite;
37 | }
38 |
39 | @keyframes rotateA {
40 | 0%,
41 | 25% {
42 | transform: rotate(0deg);
43 | }
44 |
45 | 50%,
46 | 75% {
47 | transform: rotate(180deg);
48 | }
49 |
50 | 100% {
51 | transform: rotate(360deg);
52 | }
53 | }
54 |
55 | @keyframes rotateB {
56 | 0%,
57 | 25% {
58 | transform: rotate(90deg);
59 | }
60 |
61 | 50%,
62 | 75% {
63 | transform: rotate(270deg);
64 | }
65 |
66 | 100% {
67 | transform: rotate(450deg);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/live-user-filter/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Live User Filter
8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 | Loading...
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/live-user-filter/script.js:
--------------------------------------------------------------------------------
1 | const result = document.getElementById('result')
2 | const filter = document.getElementById('filter')
3 | const listItems = []
4 |
5 | getData()
6 |
7 | filter.addEventListener('input', (e) => filterData(e.target.value))
8 |
9 | async function getData() {
10 | const res = await fetch('https://randomuser.me/api?results=50')
11 |
12 | const { results } = await res.json()
13 |
14 | // Clear result
15 | result.innerHTML = ''
16 |
17 | results.forEach(user => {
18 | const li = document.createElement('li')
19 |
20 | listItems.push(li)
21 |
22 | li.innerHTML = `
23 |
24 |
25 |
${user.name.first} ${user.name.last}
26 |
${user.location.city}, ${user.location.country}
27 |
28 | `
29 |
30 | result.appendChild(li)
31 | })
32 | }
33 |
34 | function filterData(searchTerm) {
35 | listItems.forEach(item => {
36 | if(item.innerText.toLowerCase().includes(searchTerm.toLowerCase())) {
37 | item.classList.remove('hide')
38 | } else {
39 | item.classList.add('hide')
40 | }
41 | })
42 | }
--------------------------------------------------------------------------------
/live-user-filter/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #f8f9fd;
9 | font-family: 'Roboto', sans-serif;
10 | display: flex;
11 | align-items: center;
12 | justify-content: center;
13 | height: 100vh;
14 | overflow: hidden;
15 | margin: 0;
16 | }
17 |
18 | .container {
19 | border-radius: 5px;
20 | box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.2);
21 | overflow: hidden;
22 | width: 300px;
23 | }
24 |
25 | .title {
26 | margin: 0;
27 | }
28 |
29 | .subtitle {
30 | display: inline-block;
31 | margin: 5px 0 20px;
32 | opacity: 0.8;
33 | }
34 |
35 | .header {
36 | background-color: #3e57db;
37 | color: #fff;
38 | padding: 30px 20px;
39 | }
40 |
41 | .header input {
42 | background-color: rgba(0, 0, 0, 0.3);
43 | border: 0;
44 | border-radius: 50px;
45 | color: #fff;
46 | font-size: 14px;
47 | padding: 10px 15px;
48 | width: 100%;
49 | }
50 |
51 | .header input:focus {
52 | outline: none;
53 | }
54 |
55 | .user-list {
56 | background-color: #fff;
57 | list-style-type: none;
58 | margin: 0;
59 | padding: 0;
60 | max-height: 400px;
61 | overflow-y: auto;
62 | }
63 |
64 | .user-list li {
65 | display: flex;
66 | padding: 20px;
67 | }
68 |
69 | .user-list img {
70 | border-radius: 50%;
71 | object-fit: cover;
72 | height: 50px;
73 | width: 50px;
74 | }
75 |
76 | .user-list .user-info {
77 | margin-left: 10px;
78 | }
79 |
80 | .user-list .user-info h4 {
81 | margin: 0 0 10px;
82 | }
83 |
84 | .user-list .user-info p {
85 | font-size: 12px;
86 | }
87 |
88 | .user-list li:not(:last-of-type) {
89 | border-bottom: 1px solid #eee;
90 | }
91 |
92 | .user-list li.hide {
93 | display: none;
94 | }
95 |
--------------------------------------------------------------------------------
/mobile-tab-navigation/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Mobile Tab Navigation
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | Home
21 |
22 |
23 |
24 | Work
25 |
26 |
27 |
28 | Blog
29 |
30 |
31 |
32 | About Us
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/mobile-tab-navigation/script.js:
--------------------------------------------------------------------------------
1 | const contents = document.querySelectorAll('.content')
2 | const listItems = document.querySelectorAll('nav ul li')
3 |
4 | listItems.forEach((item, idx) => {
5 | item.addEventListener('click', () => {
6 | hideAllContents()
7 | hideAllItems()
8 |
9 | item.classList.add('active')
10 | contents[idx].classList.add('show')
11 | })
12 | })
13 |
14 | function hideAllContents() {
15 | contents.forEach(content => content.classList.remove('show'))
16 | }
17 |
18 |
19 | function hideAllItems() {
20 | listItems.forEach(item => item.classList.remove('active'))
21 | }
--------------------------------------------------------------------------------
/mobile-tab-navigation/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Open+Sans&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: rgba(155, 89, 182, 0.7);
9 | font-family: 'Open Sans', sans-serif;
10 | display: flex;
11 | align-items: center;
12 | justify-content: center;
13 | height: 100vh;
14 | margin: 0;
15 | }
16 |
17 | .phone {
18 | position: relative;
19 | overflow: hidden;
20 | border: 3px solid #eee;
21 | border-radius: 15px;
22 | height: 600px;
23 | width: 340px;
24 | }
25 |
26 | .phone .content {
27 | opacity: 0;
28 | object-fit: cover;
29 | position: absolute;
30 | top: 0;
31 | left: 0;
32 | height: calc(100% - 60px);
33 | width: 100%;
34 | transition: opacity 0.4s ease;
35 | }
36 |
37 | .phone .content.show {
38 | opacity: 1;
39 | }
40 |
41 | nav {
42 | position: absolute;
43 | bottom: 0;
44 | left: 0;
45 | margin-top: -5px;
46 | width: 100%;
47 | }
48 |
49 | nav ul {
50 | background-color: #fff;
51 | display: flex;
52 | list-style-type: none;
53 | padding: 0;
54 | margin: 0;
55 | height: 60px;
56 | }
57 |
58 | nav li {
59 | color: #777;
60 | cursor: pointer;
61 | flex: 1;
62 | padding: 10px;
63 | text-align: center;
64 | }
65 |
66 | nav ul li p {
67 | font-size: 12px;
68 | margin: 2px 0;
69 | }
70 |
71 | nav ul li:hover,
72 | nav ul li.active {
73 | color: #8e44ad;
74 | }
75 |
--------------------------------------------------------------------------------
/movie-app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Movie App
8 |
9 |
10 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/movie-app/script.js:
--------------------------------------------------------------------------------
1 | const API_URL = 'https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=3fd2be6f0c70a2a598f084ddfb75487c&page=1'
2 | const IMG_PATH = 'https://image.tmdb.org/t/p/w1280'
3 | const SEARCH_API = 'https://api.themoviedb.org/3/search/movie?api_key=3fd2be6f0c70a2a598f084ddfb75487c&query="'
4 |
5 | const main = document.getElementById('main')
6 | const form = document.getElementById('form')
7 | const search = document.getElementById('search')
8 |
9 | // Get initial movies
10 | getMovies(API_URL)
11 |
12 | async function getMovies(url) {
13 | const res = await fetch(url)
14 | const data = await res.json()
15 |
16 | showMovies(data.results)
17 | }
18 |
19 | function showMovies(movies) {
20 | main.innerHTML = ''
21 |
22 | movies.forEach((movie) => {
23 | const { title, poster_path, vote_average, overview } = movie
24 |
25 | const movieEl = document.createElement('div')
26 | movieEl.classList.add('movie')
27 |
28 | movieEl.innerHTML = `
29 |
30 |
31 |
${title}
32 | ${vote_average}
33 |
34 |
35 |
Overview
36 | ${overview}
37 |
38 | `
39 | main.appendChild(movieEl)
40 | })
41 | }
42 |
43 | function getClassByRate(vote) {
44 | if(vote >= 8) {
45 | return 'green'
46 | } else if(vote >= 5) {
47 | return 'orange'
48 | } else {
49 | return 'red'
50 | }
51 | }
52 |
53 | form.addEventListener('submit', (e) => {
54 | e.preventDefault()
55 |
56 | const searchTerm = search.value
57 |
58 | if(searchTerm && searchTerm !== '') {
59 | getMovies(SEARCH_API + searchTerm)
60 |
61 | search.value = ''
62 | } else {
63 | window.location.reload()
64 | }
65 | })
--------------------------------------------------------------------------------
/movie-app/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');
2 |
3 | :root {
4 | --primary-color: #22254b;
5 | --secondary-color: #373b69;
6 | }
7 |
8 | * {
9 | box-sizing: border-box;
10 | }
11 |
12 | body {
13 | background-color: var(--primary-color);
14 | font-family: 'Poppins', sans-serif;
15 | margin: 0;
16 | }
17 |
18 | header {
19 | padding: 1rem;
20 | display: flex;
21 | justify-content: flex-end;
22 | background-color: var(--secondary-color);
23 | }
24 |
25 | .search {
26 | background-color: transparent;
27 | border: 2px solid var(--primary-color);
28 | border-radius: 50px;
29 | font-family: inherit;
30 | font-size: 1rem;
31 | padding: 0.5rem 1rem;
32 | color: #fff;
33 | }
34 |
35 | .search::placeholder {
36 | color: #7378c5;
37 | }
38 |
39 | .search:focus {
40 | outline: none;
41 | background-color: var(--primary-color);
42 | }
43 |
44 | main {
45 | display: flex;
46 | flex-wrap: wrap;
47 | justify-content: center;
48 | }
49 |
50 | .movie {
51 | width: 300px;
52 | margin: 1rem;
53 | background-color: var(--secondary-color);
54 | box-shadow: 0 4px 5px rgba(0, 0, 0, 0.2);
55 | position: relative;
56 | overflow: hidden;
57 | border-radius: 3px;
58 | }
59 |
60 | .movie img {
61 | width: 100%;
62 | }
63 |
64 | .movie-info {
65 | color: #eee;
66 | display: flex;
67 | align-items: center;
68 | justify-content: space-between;
69 | gap:0.2rem;
70 | padding: 0.5rem 1rem 1rem;
71 | letter-spacing: 0.5px;
72 | }
73 |
74 | .movie-info h3 {
75 | margin-top: 0;
76 | }
77 |
78 | .movie-info span {
79 | background-color: var(--primary-color);
80 | padding: 0.25rem 0.5rem;
81 | border-radius: 3px;
82 | font-weight: bold;
83 | }
84 |
85 | .movie-info span.green {
86 | color: lightgreen;
87 | }
88 |
89 | .movie-info span.orange {
90 | color: orange;
91 | }
92 |
93 | .movie-info span.red {
94 | color: red;
95 | }
96 |
97 | .overview {
98 | background-color: #fff;
99 | padding: 2rem;
100 | position: absolute;
101 | left: 0;
102 | bottom: 0;
103 | right: 0;
104 | max-height: 100%;
105 | transform: translateY(101%);
106 | overflow-y: auto;
107 | transition: transform 0.3s ease-in;
108 | }
109 |
110 | .movie:hover .overview {
111 | transform: translateY(0);
112 | }
113 |
--------------------------------------------------------------------------------
/netflix-mobile-navigation/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Netflix Mobile Navigation
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Mobile Navigation
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/netflix-mobile-navigation/script.js:
--------------------------------------------------------------------------------
1 | const open_btn = document.querySelector('.open-btn')
2 | const close_btn = document.querySelector('.close-btn')
3 | const nav = document.querySelectorAll('.nav')
4 |
5 | open_btn.addEventListener('click', () => {
6 | nav.forEach(nav_el => nav_el.classList.add('visible'))
7 | })
8 |
9 | close_btn.addEventListener('click', () => {
10 | nav.forEach(nav_el => nav_el.classList.remove('visible'))
11 | })
--------------------------------------------------------------------------------
/netflix-mobile-navigation/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | font-family: 'Muli', sans-serif;
9 | display: flex;
10 | flex-direction: column;
11 | align-items: center;
12 | justify-content: center;
13 | height: 100vh;
14 | }
15 |
16 | .text {
17 | text-transform: uppercase;
18 | }
19 |
20 | .logo {
21 | width: 150px;
22 | }
23 |
24 | .nav-btn {
25 | border: none;
26 | background-color: transparent;
27 | cursor: pointer;
28 | font-size: 20px;
29 | }
30 |
31 | .open-btn {
32 | position: fixed;
33 | top: 10px;
34 | left: 10px;
35 | }
36 |
37 | .nav {
38 | position: fixed;
39 | top: 0;
40 | left: 0;
41 | height: 100vh;
42 | transform: translateX(-100%);
43 | transition: transform 0.3s ease-in-out;
44 | }
45 |
46 | .nav.visible {
47 | transform: translateX(0);
48 | }
49 |
50 | .nav-black {
51 | background-color: rgb(34, 31, 31);
52 | width: 60%;
53 | max-width: 480px;
54 | min-width: 320px;
55 | transition-delay: 0.4s;
56 | }
57 |
58 | .nav-black.visible {
59 | transition-delay: 0s;
60 | }
61 |
62 | .nav-red {
63 | background-color: rgb(229, 9, 20);
64 | width: 95%;
65 | transition-delay: 0.2s;
66 | }
67 |
68 | .nav-red.visible {
69 | transition-delay: 0.2s;
70 | }
71 |
72 | .nav-white {
73 | background-color: #fff;
74 | width: 95%;
75 | padding: 40px;
76 | position: relative;
77 | transition-delay: 0s;
78 | }
79 |
80 | .nav-white.visible {
81 | transition-delay: 0.4s;
82 | }
83 |
84 | .close-btn {
85 | opacity: 0.3;
86 | position: absolute;
87 | top: 40px;
88 | right: 30px;
89 | }
90 |
91 | .list {
92 | list-style-type: none;
93 | padding: 0;
94 | }
95 |
96 | .list li {
97 | margin: 20px 0;
98 | }
99 |
100 | .list li a {
101 | color: rgb(34, 31, 31);
102 | font-size: 14px;
103 | text-decoration: none;
104 | text-transform: uppercase;
105 | }
106 |
107 | .list ul {
108 | list-style-type: none;
109 | padding-left: 20px;
110 | }
111 |
--------------------------------------------------------------------------------
/notes-app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Notes App
9 |
10 |
11 |
12 | Add note
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/notes-app/script.js:
--------------------------------------------------------------------------------
1 | const addBtn = document.getElementById('add')
2 |
3 | const notes = JSON.parse(localStorage.getItem('notes'))
4 |
5 | if(notes) {
6 | notes.forEach(note => addNewNote(note))
7 | }
8 |
9 | addBtn.addEventListener('click', () => addNewNote())
10 |
11 | function addNewNote(text = '') {
12 | const note = document.createElement('div')
13 | note.classList.add('note')
14 |
15 | note.innerHTML = `
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | `
24 |
25 | const editBtn = note.querySelector('.edit')
26 | const deleteBtn = note.querySelector('.delete')
27 | const main = note.querySelector('.main')
28 | const textArea = note.querySelector('textarea')
29 |
30 | textArea.value = text
31 | main.innerHTML = marked(text)
32 |
33 | deleteBtn.addEventListener('click', () => {
34 | note.remove()
35 |
36 | updateLS()
37 | })
38 |
39 | editBtn.addEventListener('click', () => {
40 | main.classList.toggle('hidden')
41 | textArea.classList.toggle('hidden')
42 | })
43 |
44 | textArea.addEventListener('input', (e) => {
45 | const { value } = e.target
46 |
47 | main.innerHTML = marked(value)
48 |
49 | updateLS()
50 | })
51 |
52 | document.body.appendChild(note)
53 | }
54 |
55 | function updateLS() {
56 | const notesText = document.querySelectorAll('textarea')
57 |
58 | const notes = []
59 |
60 | notesText.forEach(note => notes.push(note.value))
61 |
62 | localStorage.setItem('notes', JSON.stringify(notes))
63 | }
--------------------------------------------------------------------------------
/notes-app/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | outline: none;
6 | }
7 |
8 | body {
9 | background-color: #7bdaf3;
10 | font-family: 'Poppins', sans-serif;
11 | display: flex;
12 | flex-wrap: wrap;
13 | margin: 0;
14 | padding-top: 3rem;
15 | }
16 |
17 | .add {
18 | position: fixed;
19 | top: 1rem;
20 | right: 1rem;
21 | background-color: #9ec862;
22 | color: #fff;
23 | border: none;
24 | border-radius: 3px;
25 | padding: 0.5rem 1rem;
26 | cursor: pointer;
27 | }
28 |
29 | .add:active {
30 | transform: scale(0.98);
31 | }
32 |
33 | .note {
34 | background-color: #fff;
35 | box-shadow: 0 0 10px 4px rgba(0, 0, 0, 0.1);
36 | margin: 30px 20px;
37 | height: 400px;
38 | width: 400px;
39 | overflow-y: scroll;
40 | }
41 |
42 | .note .tools {
43 | background-color: #9ec862;
44 | display: flex;
45 | justify-content: flex-end;
46 | padding: 0.5rem;
47 | }
48 |
49 | .note .tools button {
50 | background-color: transparent;
51 | border: none;
52 | color: #fff;
53 | cursor: pointer;
54 | font-size: 1rem;
55 | margin-left: 0.5rem;
56 | }
57 |
58 | .note textarea {
59 | outline: none;
60 | font-family: inherit;
61 | font-size: 1.2rem;
62 | border: none;
63 | height: 400px;
64 | width: 100%;
65 | padding: 20px;
66 | }
67 |
68 | .main {
69 | padding: 20px;
70 | }
71 |
72 | .hidden {
73 | display: none;
74 | }
75 |
--------------------------------------------------------------------------------
/password-generator/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Password Generator
9 |
10 |
11 |
12 |
Password Generator
13 |
14 |
15 |
16 |
17 |
18 |
19 |
41 |
42 |
43 | Generate Password
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/password-generator/script.js:
--------------------------------------------------------------------------------
1 | const resultEl = document.getElementById('result')
2 | const lengthEl = document.getElementById('length')
3 | const uppercaseEl = document.getElementById('uppercase')
4 | const lowercaseEl = document.getElementById('lowercase')
5 | const numbersEl = document.getElementById('numbers')
6 | const symbolsEl = document.getElementById('symbols')
7 | const generateEl = document.getElementById('generate')
8 | const clipboardEl = document.getElementById('clipboard')
9 |
10 | const randomFunc = {
11 | lower: getRandomLower,
12 | upper: getRandomUpper,
13 | number: getRandomNumber,
14 | symbol: getRandomSymbol
15 | }
16 |
17 | clipboardEl.addEventListener('click', () => {
18 | const textarea = document.createElement('textarea')
19 | const password = resultEl.innerText
20 |
21 | if(!password) { return }
22 |
23 | textarea.value = password
24 | document.body.appendChild(textarea)
25 | textarea.select()
26 | document.execCommand('copy')
27 | textarea.remove()
28 | alert('Password copied to clipboard!')
29 | })
30 |
31 | generateEl.addEventListener('click', () => {
32 | const length = +lengthEl.value
33 | const hasLower = lowercaseEl.checked
34 | const hasUpper = uppercaseEl.checked
35 | const hasNumber = numbersEl.checked
36 | const hasSymbol = symbolsEl.checked
37 |
38 | resultEl.innerText = generatePassword(hasLower, hasUpper, hasNumber, hasSymbol, length)
39 | })
40 |
41 | function generatePassword(lower, upper, number, symbol, length) {
42 | let generatedPassword = ''
43 | const typesCount = lower + upper + number + symbol
44 | const typesArr = [{lower}, {upper}, {number}, {symbol}].filter(item => Object.values(item)[0])
45 |
46 | if(typesCount === 0) {
47 | return ''
48 | }
49 |
50 | for(let i = 0; i < length; i += typesCount) {
51 | typesArr.forEach(type => {
52 | const funcName = Object.keys(type)[0]
53 | generatedPassword += randomFunc[funcName]()
54 | })
55 | }
56 |
57 | const finalPassword = generatedPassword.slice(0, length)
58 |
59 | return finalPassword
60 | }
61 |
62 | function getRandomLower() {
63 | return String.fromCharCode(Math.floor(Math.random() * 26) + 97)
64 | }
65 |
66 | function getRandomUpper() {
67 | return String.fromCharCode(Math.floor(Math.random() * 26) + 65)
68 | }
69 |
70 | function getRandomNumber() {
71 | return String.fromCharCode(Math.floor(Math.random() * 10) + 48)
72 | }
73 |
74 | function getRandomSymbol() {
75 | const symbols = '!@#$%^&*(){}[]=<>/,.'
76 | return symbols[Math.floor(Math.random() * symbols.length)]
77 | }
--------------------------------------------------------------------------------
/password-generator/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #3b3b98;
9 | color: #fff;
10 | font-family: 'Muli', sans-serif;
11 | display: flex;
12 | flex-direction: column;
13 | align-items: center;
14 | justify-content: center;
15 | height: 100vh;
16 | overflow: hidden;
17 | padding: 10px;
18 | margin: 0;
19 | }
20 |
21 | h2 {
22 | margin: 10px 0 20px;
23 | text-align: center;
24 | }
25 |
26 | .container {
27 | background-color: #23235b;
28 | box-shadow: 0px 2px 10px rgba(255, 255, 255, 0.2);
29 | padding: 20px;
30 | width: 350px;
31 | max-width: 100%;
32 | }
33 |
34 | .result-container {
35 | background-color: rgba(0, 0, 0, 0.4);
36 | display: flex;
37 | justify-content: flex-start;
38 | align-items: center;
39 | position: relative;
40 | font-size: 18px;
41 | letter-spacing: 1px;
42 | padding: 12px 10px;
43 | height: 50px;
44 | width: 100%;
45 | }
46 |
47 | .result-container #result {
48 | word-wrap: break-word;
49 | max-width: calc(100% - 40px);
50 | overflow-y: scroll;
51 | height: 100%;
52 | }
53 |
54 | #result::-webkit-scrollbar {
55 | width: 1rem;
56 | }
57 |
58 | .result-container .btn {
59 | position: absolute;
60 | top: 5px;
61 | right: 5px;
62 | width: 40px;
63 | height: 40px;
64 | font-size: 20px;
65 | }
66 |
67 | .btn {
68 | border: none;
69 | background-color: #3b3b98;
70 | color: #fff;
71 | font-size: 16px;
72 | padding: 8px 12px;
73 | cursor: pointer;
74 | }
75 |
76 | .btn-large {
77 | display: block;
78 | width: 100%;
79 | }
80 |
81 | .setting {
82 | display: flex;
83 | justify-content: space-between;
84 | align-items: center;
85 | margin: 15px 0;
86 | }
87 |
--------------------------------------------------------------------------------
/password-strength-background/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
12 |
13 | Password Strength Backround
14 |
15 |
16 |
17 |
18 |
Image Password Strength
19 |
Change the password to see the effect
20 |
21 | Email:
22 |
28 |
29 |
30 |
31 | Password:
32 |
38 |
39 |
40 |
44 | Submit
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/password-strength-background/script.js:
--------------------------------------------------------------------------------
1 | const password = document.getElementById('password')
2 | const background = document.getElementById('background')
3 |
4 | password.addEventListener('input', (e) => {
5 | const input = e.target.value
6 | const length = input.length
7 | const blurValue = 20 - length * 2
8 | background.style.filter = `blur(${blurValue}px)`
9 | })
10 |
--------------------------------------------------------------------------------
/password-strength-background/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | }
4 |
5 | body {
6 | display: flex;
7 | flex-direction: column;
8 | align-items: center;
9 | justify-content: center;
10 | height: 100vh;
11 | overflow: hidden;
12 | margin: 0;
13 | }
14 |
15 | .background {
16 | background: url('https://images.unsplash.com/photo-1556745757-8d76bdb6984b')
17 | no-repeat center center/cover;
18 | position: absolute;
19 | top: -20px;
20 | bottom: -20px;
21 | left: -20px;
22 | right: -20px;
23 | z-index: -1;
24 | filter: blur(20px);
25 | }
26 |
--------------------------------------------------------------------------------
/pokedex/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Pokedex
8 |
9 |
10 | Pokedex
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/pokedex/script.js:
--------------------------------------------------------------------------------
1 | const poke_container = document.getElementById('poke-container')
2 | const pokemon_count = 150
3 | const colors = {
4 | fire: '#FDDFDF',
5 | grass: '#DEFDE0',
6 | electric: '#FCF7DE',
7 | water: '#DEF3FD',
8 | ground: '#f4e7da',
9 | rock: '#d5d5d4',
10 | fairy: '#fceaff',
11 | poison: '#98d7a5',
12 | bug: '#f8d5a3',
13 | dragon: '#97b3e6',
14 | psychic: '#eaeda1',
15 | flying: '#F5F5F5',
16 | fighting: '#E6E0D4',
17 | normal: '#F5F5F5'
18 | }
19 |
20 | const main_types = Object.keys(colors)
21 |
22 | const fetchPokemons = async () => {
23 | for(let i = 1; i <= pokemon_count; i++) {
24 | await getPokemon(i)
25 | }
26 | }
27 |
28 | const getPokemon = async (id) => {
29 | const url = `https://pokeapi.co/api/v2/pokemon/${id}`
30 | const res = await fetch(url)
31 | const data = await res.json()
32 | createPokemonCard(data)
33 | }
34 |
35 | const createPokemonCard = (pokemon) => {
36 | const pokemonEl = document.createElement('div')
37 | pokemonEl.classList.add('pokemon')
38 |
39 | const name = pokemon.name[0].toUpperCase() + pokemon.name.slice(1)
40 | const id = pokemon.id.toString().padStart(3, '0')
41 |
42 | const poke_types = pokemon.types.map(type => type.type.name)
43 | const type = main_types.find(type => poke_types.indexOf(type) > -1)
44 | const color = colors[type]
45 |
46 | pokemonEl.style.backgroundColor = color
47 |
48 | const pokemonInnerHTML = `
49 |
50 |
51 |
52 |
53 | #${id}
54 |
${name}
55 | Type: ${type}
56 |
57 | `
58 |
59 | pokemonEl.innerHTML = pokemonInnerHTML
60 |
61 | poke_container.appendChild(pokemonEl)
62 | }
63 |
64 | fetchPokemons()
65 |
--------------------------------------------------------------------------------
/pokedex/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Lato:300,400&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background: #efefbb;
9 | background: linear-gradient(to right, #d4d3dd, #efefbb);
10 | font-family: 'Lato', sans-serif;
11 | display: flex;
12 | flex-direction: column;
13 | align-items: center;
14 | justify-content: center;
15 | margin: 0;
16 | }
17 |
18 | h1 {
19 | letter-spacing: 3px;
20 | }
21 |
22 | .poke-container {
23 | display: flex;
24 | flex-wrap: wrap;
25 | align-items: space-between;
26 | justify-content: center;
27 | margin: 0 auto;
28 | max-width: 1200px;
29 | }
30 |
31 | .pokemon {
32 | background-color: #eee;
33 | border-radius: 10px;
34 | box-shadow: 0 3px 15px rgba(100, 100, 100, 0.5);
35 | margin: 10px;
36 | padding: 20px;
37 | text-align: center;
38 | }
39 |
40 | .pokemon .img-container {
41 | background-color: rgba(255, 255, 255, 0.6);
42 | border-radius: 50%;
43 | width: 120px;
44 | height: 120px;
45 | text-align: center;
46 | }
47 |
48 | .pokemon .img-container img {
49 | max-width: 90%;
50 | margin-top: 20px;
51 | }
52 |
53 | .pokemon .info {
54 | margin-top: 20px;
55 | }
56 |
57 | .pokemon .info .number {
58 | background-color: rgba(0, 0, 0, 0.1);
59 | padding: 5px 10px;
60 | border-radius: 10px;
61 | font-size: 0.8em;
62 | }
63 |
64 | .pokemon .info .name {
65 | margin: 15px 0 7px;
66 | letter-spacing: 1px;
67 | }
68 |
--------------------------------------------------------------------------------
/progress-steps/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Progress Steps
8 |
9 |
10 |
11 |
12 |
13 |
1
14 |
2
15 |
3
16 |
4
17 |
18 |
19 |
Prev
20 |
Next
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/progress-steps/script.js:
--------------------------------------------------------------------------------
1 | const progress = document.getElementById('progress')
2 | const prev = document.getElementById('prev')
3 | const next = document.getElementById('next')
4 | const circles = document.querySelectorAll('.circle')
5 |
6 | let currentActive = 1
7 |
8 | next.addEventListener('click', () => {
9 | currentActive++
10 |
11 | if(currentActive > circles.length) {
12 | currentActive = circles.length
13 | }
14 |
15 | update()
16 | })
17 |
18 | prev.addEventListener('click', () => {
19 | currentActive--
20 |
21 | if(currentActive < 1) {
22 | currentActive = 1
23 | }
24 |
25 | update()
26 | })
27 |
28 | function update() {
29 | circles.forEach((circle, idx) => {
30 | if(idx < currentActive) {
31 | circle.classList.add('active')
32 | } else {
33 | circle.classList.remove('active')
34 | }
35 | })
36 |
37 | const actives = document.querySelectorAll('.active')
38 |
39 | progress.style.width = (actives.length - 1) / (circles.length - 1) * 100 + '%'
40 |
41 | if(currentActive === 1) {
42 | prev.disabled = true
43 | } else if(currentActive === circles.length) {
44 | next.disabled = true
45 | } else {
46 | prev.disabled = false
47 | next.disabled = false
48 | }
49 | }
--------------------------------------------------------------------------------
/progress-steps/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
2 |
3 | :root {
4 | --line-border-fill: #3498db;
5 | --line-border-empty: #e0e0e0;
6 | }
7 |
8 | * {
9 | box-sizing: border-box;
10 | }
11 |
12 | body {
13 | background-color: #f6f7fb;
14 | font-family: 'Muli', sans-serif;
15 | display: flex;
16 | align-items: center;
17 | justify-content: center;
18 | height: 100vh;
19 | overflow: hidden;
20 | margin: 0;
21 | }
22 |
23 | .container {
24 | text-align: center;
25 | }
26 |
27 | .progress-container {
28 | display: flex;
29 | justify-content: space-between;
30 | position: relative;
31 | margin-bottom: 30px;
32 | max-width: 100%;
33 | width: 350px;
34 | }
35 |
36 | .progress-container::before {
37 | content: '';
38 | background-color: var(--line-border-empty);
39 | position: absolute;
40 | top: 50%;
41 | left: 0;
42 | transform: translateY(-50%);
43 | height: 4px;
44 | width: 100%;
45 | z-index: -1;
46 | }
47 |
48 | .progress {
49 | background-color: var(--line-border-fill);
50 | position: absolute;
51 | top: 50%;
52 | left: 0;
53 | transform: translateY(-50%);
54 | height: 4px;
55 | width: 0%;
56 | z-index: -1;
57 | transition: 0.4s ease;
58 | }
59 |
60 | .circle {
61 | background-color: #fff;
62 | color: #999;
63 | border-radius: 50%;
64 | height: 30px;
65 | width: 30px;
66 | display: flex;
67 | align-items: center;
68 | justify-content: center;
69 | border: 3px solid var(--line-border-empty);
70 | transition: 0.4s ease;
71 | }
72 |
73 | .circle.active {
74 | border-color: var(--line-border-fill);
75 | }
76 |
77 | .btn {
78 | background-color: var(--line-border-fill);
79 | color: #fff;
80 | border: 0;
81 | border-radius: 6px;
82 | cursor: pointer;
83 | font-family: inherit;
84 | padding: 8px 30px;
85 | margin: 5px;
86 | font-size: 14px;
87 | }
88 |
89 | .btn:active {
90 | transform: scale(0.98);
91 | }
92 |
93 | .btn:focus {
94 | outline: 0;
95 | }
96 |
97 | .btn:disabled {
98 | background-color: var(--line-border-empty);
99 | cursor: not-allowed;
100 | }
101 |
--------------------------------------------------------------------------------
/quiz-app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Quiz App
8 |
9 |
10 |
11 |
35 | Submit
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/quiz-app/script.js:
--------------------------------------------------------------------------------
1 | const quizData = [
2 | {
3 | question: "Which language runs in a web browser?",
4 | a: "Java",
5 | b: "C",
6 | c: "Python",
7 | d: "JavaScript",
8 | correct: "d",
9 | },
10 | {
11 | question: "What does CSS stand for?",
12 | a: "Central Style Sheets",
13 | b: "Cascading Style Sheets",
14 | c: "Cascading Simple Sheets",
15 | d: "Cars SUVs Sailboats",
16 | correct: "b",
17 | },
18 | {
19 | question: "What does HTML stand for?",
20 | a: "Hypertext Markup Language",
21 | b: "Hypertext Markdown Language",
22 | c: "Hyperloop Machine Language",
23 | d: "Helicopters Terminals Motorboats Lamborginis",
24 | correct: "a",
25 | },
26 | {
27 | question: "What year was JavaScript launched?",
28 | a: "1996",
29 | b: "1995",
30 | c: "1994",
31 | d: "none of the above",
32 | correct: "b",
33 | },
34 | ];
35 |
36 | const quiz = document.getElementById('quiz')
37 | const answerEls = document.querySelectorAll('.answer')
38 | const questionEl = document.getElementById('question')
39 | const a_text = document.getElementById('a_text')
40 | const b_text = document.getElementById('b_text')
41 | const c_text = document.getElementById('c_text')
42 | const d_text = document.getElementById('d_text')
43 | const submitBtn = document.getElementById('submit')
44 |
45 | let currentQuiz = 0
46 | let score = 0
47 |
48 | loadQuiz()
49 |
50 | function loadQuiz() {
51 | deselectAnswers()
52 |
53 | const currentQuizData = quizData[currentQuiz]
54 |
55 | questionEl.innerText = currentQuizData.question
56 | a_text.innerText = currentQuizData.a
57 | b_text.innerText = currentQuizData.b
58 | c_text.innerText = currentQuizData.c
59 | d_text.innerText = currentQuizData.d
60 | }
61 |
62 | function deselectAnswers() {
63 | answerEls.forEach(answerEl => answerEl.checked = false)
64 | }
65 |
66 | function getSelected() {
67 | let answer
68 |
69 | answerEls.forEach(answerEl => {
70 | if(answerEl.checked) {
71 | answer = answerEl.id
72 | }
73 | })
74 |
75 | return answer
76 | }
77 |
78 | submitBtn.addEventListener('click', () => {
79 | const answer = getSelected()
80 |
81 | if(answer) {
82 | if(answer === quizData[currentQuiz].correct) {
83 | score++
84 | }
85 |
86 | currentQuiz++
87 |
88 | if(currentQuiz < quizData.length) {
89 | loadQuiz()
90 | } else {
91 | quiz.innerHTML = `
92 | You answered ${score}/${quizData.length} questions correctly
93 |
94 | Reload
95 | `
96 | }
97 | }
98 | })
--------------------------------------------------------------------------------
/quiz-app/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #b8c6db;
9 | background-image: linear-gradient(315deg, #b8c6db 0%, #f5f7fa 100%);
10 | font-family: 'Poppins', sans-serif;
11 | display: flex;
12 | align-items: center;
13 | justify-content: center;
14 | height: 100vh;
15 | overflow: hidden;
16 | margin: 0;
17 | }
18 |
19 | .quiz-container {
20 | background-color: #fff;
21 | border-radius: 10px;
22 | box-shadow: 0 0 10px 2px rgba(100, 100, 100, 0.1);
23 | width: 600px;
24 | overflow: hidden;
25 | }
26 |
27 | .quiz-header {
28 | padding: 4rem;
29 | }
30 |
31 | h2 {
32 | padding: 1rem;
33 | text-align: center;
34 | margin: 0;
35 | }
36 |
37 | ul {
38 | list-style-type: none;
39 | padding: 0;
40 | }
41 |
42 | ul li {
43 | font-size: 1.2rem;
44 | margin: 1rem 0;
45 | }
46 |
47 | ul li label {
48 | cursor: pointer;
49 | }
50 |
51 | button {
52 | background-color: #8e44ad;
53 | color: #fff;
54 | border: none;
55 | display: block;
56 | width: 100%;
57 | cursor: pointer;
58 | font-size: 1.1rem;
59 | font-family: inherit;
60 | padding: 1.3rem;
61 | }
62 |
63 | button:hover {
64 | background-color: #732d91;
65 | }
66 |
67 | button:focus {
68 | outline: none;
69 | background-color: #5e3370;
70 | }
71 |
--------------------------------------------------------------------------------
/random-choice-picker/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Random Choice Picker
8 |
9 |
10 |
11 |
Enter all of the choices divided by a comma (','). Press enter when you're done
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/random-choice-picker/script.js:
--------------------------------------------------------------------------------
1 | const tagsEl = document.getElementById('tags')
2 | const textarea = document.getElementById('textarea')
3 |
4 | textarea.focus()
5 |
6 | textarea.addEventListener('keyup', (e) => {
7 | createTags(e.target.value)
8 |
9 | if(e.key === 'Enter') {
10 | setTimeout(() => {
11 | e.target.value = ''
12 | }, 10)
13 |
14 | randomSelect()
15 | }
16 | })
17 |
18 | function createTags(input) {
19 | const tags = input.split(',').filter(tag => tag.trim() !== '').map(tag => tag.trim())
20 |
21 | tagsEl.innerHTML = ''
22 |
23 | tags.forEach(tag => {
24 | const tagEl = document.createElement('span')
25 | tagEl.classList.add('tag')
26 | tagEl.innerText = tag
27 | tagsEl.appendChild(tagEl)
28 | })
29 | }
30 |
31 | function randomSelect() {
32 | const times = 30
33 |
34 | const interval = setInterval(() => {
35 | const randomTag = pickRandomTag()
36 |
37 | if (randomTag !== undefined) {
38 | highlightTag(randomTag)
39 |
40 | setTimeout(() => {
41 | unHighlightTag(randomTag)
42 | }, 100)
43 | }
44 | }, 100);
45 |
46 | setTimeout(() => {
47 | clearInterval(interval)
48 |
49 | setTimeout(() => {
50 | const randomTag = pickRandomTag()
51 |
52 | highlightTag(randomTag)
53 | }, 100)
54 |
55 | }, times * 100)
56 | }
57 |
58 | function pickRandomTag() {
59 | const tags = document.querySelectorAll('.tag')
60 | return tags[Math.floor(Math.random() * tags.length)]
61 | }
62 |
63 | function highlightTag(tag) {
64 | tag.classList.add('highlight')
65 | }
66 |
67 | function unHighlightTag(tag) {
68 | tag.classList.remove('highlight')
69 | }
70 |
--------------------------------------------------------------------------------
/random-choice-picker/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #2b88f0;
9 | font-family: 'Muli', sans-serif;
10 | display: flex;
11 | flex-direction: column;
12 | align-items: center;
13 | justify-content: center;
14 | height: 100vh;
15 | overflow: hidden;
16 | margin: 0;
17 | }
18 |
19 | h3 {
20 | color: #fff;
21 | margin: 10px 0 20px;
22 | text-align: center;
23 | }
24 |
25 | .container {
26 | width: 500px;
27 | }
28 |
29 | textarea {
30 | border: none;
31 | display: block;
32 | width: 100%;
33 | height: 100px;
34 | font-family: inherit;
35 | padding: 10px;
36 | margin: 0 0 20px;
37 | font-size: 16px;
38 | }
39 |
40 | textarea:focus {
41 | outline: none;
42 | }
43 |
44 | .tag {
45 | background-color: #f0932b;
46 | color: #fff;
47 | border-radius: 50px;
48 | padding: 10px 20px;
49 | margin: 0 5px 10px 0;
50 | font-size: 14px;
51 | display: inline-block;
52 | }
53 |
54 | .tag.highlight {
55 | background-color: #273c75;
56 | }
57 |
--------------------------------------------------------------------------------
/random-image-generator/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Random Image Feed
8 |
9 |
10 | Random Image Feed
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/random-image-generator/script.js:
--------------------------------------------------------------------------------
1 | const container = document.querySelector('.container')
2 | const unsplashURL = 'https://source.unsplash.com/random/'
3 | const rows = 5
4 |
5 | for(let i = 0; i < rows * 3; i++) {
6 | const img = document.createElement('img')
7 | img.src = `${unsplashURL}${getRandomSize()}`
8 | container.appendChild(img)
9 | }
10 |
11 | function getRandomSize() {
12 | return `${getRandomNr()}x${getRandomNr()}`
13 | }
14 |
15 | function getRandomNr() {
16 | return Math.floor(Math.random() * 10) + 300
17 | }
--------------------------------------------------------------------------------
/random-image-generator/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | font-family: 'Roboto', sans-serif;
9 | display: flex;
10 | flex-direction: column;
11 | align-items: center;
12 | justify-content: center;
13 | min-height: 100vh;
14 | margin: 0;
15 | }
16 |
17 | .title {
18 | margin: 10px 0 0;
19 | text-align: center;
20 | }
21 |
22 | .container {
23 | display: flex;
24 | align-items: center;
25 | justify-content: center;
26 | flex-wrap: wrap;
27 | max-width: 1000px;
28 | }
29 |
30 | .container img {
31 | object-fit: cover;
32 | margin: 10px;
33 | height: 300px;
34 | width: 300px;
35 | max-width: 100%;
36 | }
37 |
--------------------------------------------------------------------------------
/rotating-nav-animation/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Rotating Navigation
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
Amazing Article
25 |
Florin Pop
26 |
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.
27 |
28 |
My Dog
29 |
30 |
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?
31 |
32 |
33 |
34 |
35 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/rotating-nav-animation/script.js:
--------------------------------------------------------------------------------
1 | const open = document.getElementById('open')
2 | const close = document.getElementById('close')
3 | const container = document.querySelector('.container')
4 |
5 | open.addEventListener('click', () => container.classList.add('show-nav'))
6 |
7 | close.addEventListener('click', () => container.classList.remove('show-nav'))
--------------------------------------------------------------------------------
/rotating-nav-animation/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Lato&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | font-family: 'Lato', sans-serif;
9 | background-color: #333;
10 | color: #222;
11 | overflow-x: hidden;
12 | margin: 0;
13 | }
14 |
15 | .container {
16 | background-color: #fafafa;
17 | transform-origin: top left;
18 | transition: transform 0.5s linear;
19 | width: 100vw;
20 | min-height: 100vh;
21 | padding: 50px;
22 | }
23 |
24 | .container.show-nav {
25 | transform: rotate(-20deg);
26 | }
27 |
28 | .circle-container {
29 | position: fixed;
30 | top: -100px;
31 | left: -100px;
32 | }
33 |
34 | .circle {
35 | background-color: #ff7979;
36 | height: 200px;
37 | width: 200px;
38 | border-radius: 50%;
39 | position: relative;
40 | transition: transform 0.5s linear;
41 | }
42 |
43 | .container.show-nav .circle {
44 | transform: rotate(-70deg);
45 | }
46 |
47 | .circle button {
48 | cursor: pointer;
49 | position: absolute;
50 | top: 50%;
51 | left: 50%;
52 | height: 100px;
53 | background: transparent;
54 | border: 0;
55 | font-size: 26px;
56 | color: #fff;
57 | }
58 |
59 | .circle button:focus {
60 | outline: none;
61 | }
62 |
63 | .circle button#open {
64 | left: 60%;
65 | }
66 |
67 | .circle button#close {
68 | top: 60%;
69 | transform: rotate(90deg);
70 | transform-origin: top left;
71 | }
72 |
73 | .container.show-nav + nav li {
74 | transform: translateX(0);
75 | transition-delay: 0.3s;
76 | }
77 |
78 | nav {
79 | position: fixed;
80 | bottom: 40px;
81 | left: 0;
82 | z-index: 100;
83 | }
84 |
85 | nav ul {
86 | list-style-type: none;
87 | padding-left: 30px;
88 | }
89 |
90 | nav ul li {
91 | text-transform: uppercase;
92 | color: #fff;
93 | margin: 40px 0;
94 | transform: translateX(-100%);
95 | transition: transform 0.4s ease-in;
96 | }
97 |
98 | nav ul li i {
99 | font-size: 20px;
100 | margin-right: 10px;
101 | }
102 |
103 | nav ul li + li {
104 | margin-left: 15px;
105 | transform: translateX(-150%);
106 | }
107 |
108 | nav ul li + li + li {
109 | margin-left: 30px;
110 | transform: translateX(-200%);
111 | }
112 |
113 | nav a{
114 | color: #fafafa;
115 | text-decoration: none;
116 | transition: all 0.5s;
117 | }
118 |
119 | nav a:hover {
120 | color: #FF7979;
121 | font-weight: bold;
122 | }
123 |
124 | .content img {
125 | max-width: 100%;
126 | }
127 |
128 | .content {
129 | max-width: 1000px;
130 | margin: 50px auto;
131 | }
132 |
133 | .content h1 {
134 | margin: 0;
135 | }
136 |
137 | .content small {
138 | color: #555;
139 | font-style: italic;
140 | }
141 |
142 | .content p {
143 | color: #333;
144 | line-height: 1.5;
145 | }
146 |
--------------------------------------------------------------------------------
/scroll-animation/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Scroll Animation
8 |
9 |
10 | Scroll to see the animation
11 |
Content
12 |
Content
13 |
Content
14 |
Content
15 |
Content
16 |
Content
17 |
Content
18 |
Content
19 |
Content
20 |
Content
21 |
Content
22 |
Content
23 |
Content
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/scroll-animation/script.js:
--------------------------------------------------------------------------------
1 | const boxes = document.querySelectorAll('.box')
2 |
3 | window.addEventListener('scroll', checkBoxes)
4 |
5 | checkBoxes()
6 |
7 | function checkBoxes() {
8 | const triggerBottom = window.innerHeight / 5 * 4
9 |
10 | boxes.forEach(box => {
11 | const boxTop = box.getBoundingClientRect().top
12 |
13 | if(boxTop < triggerBottom) {
14 | box.classList.add('show')
15 | } else {
16 | box.classList.remove('show')
17 | }
18 | })
19 | }
--------------------------------------------------------------------------------
/scroll-animation/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #efedd6;
9 | font-family: 'Roboto', sans-serif;
10 | display: flex;
11 | flex-direction: column;
12 | align-items: center;
13 | justify-content: center;
14 | margin: 0;
15 | overflow-x: hidden;
16 | }
17 |
18 | h1 {
19 | margin: 10px;
20 | }
21 |
22 | .box {
23 | background-color: steelblue;
24 | color: #fff;
25 | display: flex;
26 | align-items: center;
27 | justify-content: center;
28 | width: 400px;
29 | height: 200px;
30 | margin: 10px;
31 | border-radius: 10px;
32 | box-shadow: 2px 4px 5px rgba(0, 0, 0, 0.3);
33 | transform: translateX(400%);
34 | transition: transform 0.4s ease;
35 | }
36 |
37 | .box:nth-of-type(even) {
38 | transform: translateX(-400%);
39 | }
40 |
41 | .box.show {
42 | transform: translateX(0);
43 | }
44 |
45 | .box h2 {
46 | font-size: 45px;
47 | }
48 |
--------------------------------------------------------------------------------
/sound-board/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Sound Board
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/sound-board/script.js:
--------------------------------------------------------------------------------
1 | const sounds = ['applause', 'boo', 'gasp', 'tada', 'victory', 'wrong']
2 |
3 | sounds.forEach(sound => {
4 | const btn = document.createElement('button')
5 | btn.classList.add('btn')
6 |
7 | btn.innerText = sound
8 |
9 | btn.addEventListener('click', () => {
10 | stopSongs()
11 |
12 | document.getElementById(sound).play()
13 | })
14 |
15 | document.getElementById('buttons').appendChild(btn)
16 | })
17 |
18 | function stopSongs() {
19 | sounds.forEach(sound => {
20 | const song = document.getElementById(sound)
21 |
22 | song.pause()
23 | song.currentTime = 0;
24 | })
25 | }
--------------------------------------------------------------------------------
/sound-board/sounds/applause.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xprincedev/HTML-CSS-Training/e3bdf61cd13d7d07e11f816be8acb32df2134490/sound-board/sounds/applause.mp3
--------------------------------------------------------------------------------
/sound-board/sounds/boo.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xprincedev/HTML-CSS-Training/e3bdf61cd13d7d07e11f816be8acb32df2134490/sound-board/sounds/boo.mp3
--------------------------------------------------------------------------------
/sound-board/sounds/gasp.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xprincedev/HTML-CSS-Training/e3bdf61cd13d7d07e11f816be8acb32df2134490/sound-board/sounds/gasp.mp3
--------------------------------------------------------------------------------
/sound-board/sounds/tada.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xprincedev/HTML-CSS-Training/e3bdf61cd13d7d07e11f816be8acb32df2134490/sound-board/sounds/tada.mp3
--------------------------------------------------------------------------------
/sound-board/sounds/victory.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xprincedev/HTML-CSS-Training/e3bdf61cd13d7d07e11f816be8acb32df2134490/sound-board/sounds/victory.mp3
--------------------------------------------------------------------------------
/sound-board/sounds/wrong.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xprincedev/HTML-CSS-Training/e3bdf61cd13d7d07e11f816be8acb32df2134490/sound-board/sounds/wrong.mp3
--------------------------------------------------------------------------------
/sound-board/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: rgb(161, 100, 223);
9 | font-family: 'Poppins', sans-serif;
10 | display: flex;
11 | flex-wrap: wrap;
12 | align-items: center;
13 | justify-content: center;
14 | text-align: center;
15 | height: 100vh;
16 | overflow: hidden;
17 | margin: 0;
18 | }
19 |
20 | .btn {
21 | background-color: rebeccapurple;
22 | border-radius: 5px;
23 | border: none;
24 | color: #fff;
25 | margin: 1rem;
26 | padding: 1.5rem 3rem;
27 | font-size: 1.2rem;
28 | font-family: inherit;
29 | cursor: pointer;
30 | }
31 |
32 | .btn:hover {
33 | opacity: 0.9;
34 | }
35 |
36 | .btn:focus {
37 | outline: none;
38 | }
39 |
--------------------------------------------------------------------------------
/split-landing-page/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Split Landing Page
8 |
9 |
10 |
11 |
12 |
13 |
Playstation 5
14 |
Buy Now
15 |
16 |
17 |
XBox Series X
18 |
Buy Now
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/split-landing-page/ps.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xprincedev/HTML-CSS-Training/e3bdf61cd13d7d07e11f816be8acb32df2134490/split-landing-page/ps.jpg
--------------------------------------------------------------------------------
/split-landing-page/script.js:
--------------------------------------------------------------------------------
1 | const left = document.querySelector('.left')
2 | const right = document.querySelector('.right')
3 | const container = document.querySelector('.container')
4 |
5 | left.addEventListener('mouseenter', () => container.classList.add('hover-left'))
6 | left.addEventListener('mouseleave', () => container.classList.remove('hover-left'))
7 |
8 | right.addEventListener('mouseenter', () => container.classList.add('hover-right'))
9 | right.addEventListener('mouseleave', () => container.classList.remove('hover-right'))
--------------------------------------------------------------------------------
/split-landing-page/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
2 |
3 | :root {
4 | --left-bg-color: rgba(87, 84, 236, 0.7);
5 | --right-bg-color: rgba(43, 43, 43, 0.8);
6 | --left-btn-hover-color: rgba(87, 84, 236, 1);
7 | --right-btn-hover-color: rgba(28, 122, 28, 1);
8 | --hover-width: 75%;
9 | --other-width: 25%;
10 | --speed: 1000ms;
11 | }
12 |
13 | * {
14 | box-sizing: border-box;
15 | }
16 |
17 | body {
18 | font-family: 'Roboto', sans-serif;
19 | height: 100vh;
20 | overflow: hidden;
21 | margin: 0;
22 | }
23 |
24 | h1 {
25 | font-size: 4rem;
26 | color: #fff;
27 | position: absolute;
28 | left: 50%;
29 | top: 20%;
30 | transform: translateX(-50%);
31 | white-space: nowrap;
32 | }
33 |
34 | .btn {
35 | position: absolute;
36 | display: flex;
37 | align-items: center;
38 | justify-content: center;
39 | left: 50%;
40 | top: 40%;
41 | transform: translateX(-50%);
42 | text-decoration: none;
43 | color: #fff;
44 | border: #fff solid 0.2rem;
45 | font-size: 1rem;
46 | font-weight: bold;
47 | text-transform: uppercase;
48 | width: 15rem;
49 | padding: 1.5rem;
50 | }
51 |
52 | .split.left .btn:hover {
53 | background-color: var(--left-btn-hover-color);
54 | border-color: var(--left-btn-hover-color);
55 | }
56 |
57 | .split.right .btn:hover {
58 | background-color: var(--right-btn-hover-color);
59 | border-color: var(--right-btn-hover-color);
60 | }
61 |
62 | .container {
63 | position: relative;
64 | width: 100%;
65 | height: 100%;
66 | background: #333;
67 | }
68 |
69 | .split {
70 | position: absolute;
71 | width: 50%;
72 | height: 100%;
73 | overflow: hidden;
74 | }
75 |
76 | .split.left {
77 | left: 0;
78 | background: url('ps.jpg');
79 | background-repeat: no-repeat;
80 | background-size: cover;
81 | }
82 |
83 | .split.left::before {
84 | content: '';
85 | position: absolute;
86 | width: 100%;
87 | height: 100%;
88 | background-color: var(--left-bg-color);
89 | }
90 |
91 | .split.right {
92 | right: 0;
93 | background: url('xbox.jpg');
94 | background-repeat: no-repeat;
95 | background-size: cover;
96 | }
97 |
98 | .split.right::before {
99 | content: '';
100 | position: absolute;
101 | width: 100%;
102 | height: 100%;
103 | background-color: var(--right-bg-color);
104 | }
105 |
106 | .split.right,
107 | .split.left,
108 | .split.right::before,
109 | .split.left::before {
110 | transition: all var(--speed) ease-in-out;
111 | }
112 |
113 | .hover-left .left {
114 | width: var(--hover-width);
115 | }
116 |
117 | .hover-left .right {
118 | width: var(--other-width);
119 | }
120 |
121 | .hover-right .right {
122 | width: var(--hover-width);
123 | }
124 |
125 | .hover-right .left {
126 | width: var(--other-width);
127 | }
128 |
129 | @media (max-width: 800px) {
130 | h1 {
131 | font-size: 2rem;
132 | top: 30%;
133 | }
134 |
135 | .btn {
136 | padding: 1.2rem;
137 | width: 12rem;
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/split-landing-page/xbox.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xprincedev/HTML-CSS-Training/e3bdf61cd13d7d07e11f816be8acb32df2134490/split-landing-page/xbox.jpg
--------------------------------------------------------------------------------
/sticky-navigation/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Sticky Navigation
8 |
9 |
10 |
11 |
20 |
21 |
22 |
23 |
24 |
Welcome To My Website
25 |
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Maiores, consequuntur?
26 |
27 |
28 |
29 |
30 | Content One
31 | 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!
32 |
33 | Content Two
34 | 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?
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/sticky-navigation/script.js:
--------------------------------------------------------------------------------
1 | const nav = document.querySelector('.nav')
2 | window.addEventListener('scroll', fixNav)
3 |
4 | function fixNav() {
5 | if(window.scrollY > nav.offsetHeight + 150) {
6 | nav.classList.add('active')
7 | } else {
8 | nav.classList.remove('active')
9 | }
10 | }
--------------------------------------------------------------------------------
/sticky-navigation/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Open+Sans');
2 |
3 | * {
4 | box-sizing: border-box;
5 | margin: 0;
6 | padding: 0;
7 | }
8 |
9 | body {
10 | font-family: 'Open Sans', sans-serif;
11 | color: #222;
12 | padding-bottom: 50px;
13 | }
14 |
15 | .container {
16 | max-width: 1200px;
17 | margin: 0 auto;
18 | }
19 |
20 | .nav {
21 | position: fixed;
22 | background-color: #222;
23 | top: 0;
24 | left: 0;
25 | right: 0;
26 | transition: all 0.3s ease-in-out;
27 | }
28 |
29 | .nav .container {
30 | display: flex;
31 | justify-content: space-between;
32 | align-items: center;
33 | padding: 20px 0;
34 | transition: all 0.3s ease-in-out;
35 | }
36 |
37 | .nav ul {
38 | display: flex;
39 | list-style-type: none;
40 | align-items: center;
41 | justify-content: center;
42 | }
43 |
44 | .nav a {
45 | color: #fff;
46 | text-decoration: none;
47 | padding: 7px 15px;
48 | transition: all 0.3s ease-in-out;
49 | }
50 |
51 | .nav.active {
52 | background-color: #fff;
53 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
54 | }
55 |
56 | .nav.active a {
57 | color: #000;
58 | }
59 |
60 | .nav.active .container {
61 | padding: 10px 0;
62 | }
63 |
64 | .nav a.current,
65 | .nav a:hover {
66 | color: #c0392b;
67 | font-weight: bold;
68 | }
69 |
70 | .hero {
71 | background-image: url('https://images.pexels.com/photos/450035/pexels-photo-450035.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260');
72 | background-repeat: no-repeat;
73 | background-size: cover;
74 | background-position: bottom center;
75 | height: 100vh;
76 | color: #fff;
77 | display: flex;
78 | justify-content: center;
79 | align-items: center;
80 | text-align: center;
81 | position: relative;
82 | margin-bottom: 20px;
83 | z-index: -2;
84 | }
85 |
86 | .hero::before {
87 | content: '';
88 | position: absolute;
89 | top: 0;
90 | left: 0;
91 | width: 100%;
92 | height: 100%;
93 | background-color: rgba(0, 0, 0, 0.5);
94 | z-index: -1;
95 | }
96 |
97 | .hero h1 {
98 | font-size: 46px;
99 | margin: -20px 0 20px;
100 | }
101 |
102 | .hero p {
103 | font-size: 20px;
104 | letter-spacing: 1px;
105 | }
106 |
107 | .content h2,
108 | .content h3 {
109 | font-size: 150%;
110 | margin: 20px 0;
111 | }
112 |
113 | .content p {
114 | color: #555;
115 | line-height: 30px;
116 | letter-spacing: 1.2px;
117 | }
118 |
--------------------------------------------------------------------------------
/testimonial-box-switcher/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
12 |
13 | Testimonial Box
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | I've worked with literally hundreds of HTML/CSS developers and I have to
22 | say the top spot goes to this guy. This guy is an amazing developer. He
23 | stresses on good, clean code and pays heed to the details. I love
24 | developers who respect each and every aspect of a throughly thought out
25 | design and do their best to put it in code. He goes over and beyond and
26 | transforms ART into PIXELS - without a glitch, every time.
27 |
28 |
29 |
34 |
35 |
Miyah Myles
36 |
Marketing
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/testimonial-box-switcher/script.js:
--------------------------------------------------------------------------------
1 | const testimonialsContainer = document.querySelector('.testimonials-container')
2 | const testimonial = document.querySelector('.testimonial')
3 | const userImage = document.querySelector('.user-image')
4 | const username = document.querySelector('.username')
5 | const role = document.querySelector('.role')
6 |
7 | const testimonials = [
8 | {
9 | name: 'Miyah Myles',
10 | position: 'Marketing',
11 | photo:
12 | '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',
13 | text:
14 | "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.",
15 | },
16 | {
17 | name: 'June Cha',
18 | position: 'Software Engineer',
19 | photo: 'https://randomuser.me/api/portraits/women/44.jpg',
20 | text:
21 | '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!',
22 | },
23 | {
24 | name: 'Iida Niskanen',
25 | position: 'Data Entry',
26 | photo: 'https://randomuser.me/api/portraits/women/68.jpg',
27 | text:
28 | "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.",
29 | },
30 | {
31 | name: 'Renee Sims',
32 | position: 'Receptionist',
33 | photo: 'https://randomuser.me/api/portraits/women/65.jpg',
34 | text:
35 | "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.",
36 | },
37 | {
38 | name: 'Jonathan Nunfiez',
39 | position: 'Graphic Designer',
40 | photo: 'https://randomuser.me/api/portraits/men/43.jpg',
41 | text:
42 | "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!",
43 | },
44 | {
45 | name: 'Sasha Ho',
46 | position: 'Accountant',
47 | photo:
48 | 'https://images.pexels.com/photos/415829/pexels-photo-415829.jpeg?h=350&auto=compress&cs=tinysrgb',
49 | text:
50 | '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!',
51 | },
52 | {
53 | name: 'Veeti Seppanen',
54 | position: 'Director',
55 | photo: 'https://randomuser.me/api/portraits/men/97.jpg',
56 | text:
57 | '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.',
58 | },
59 | ]
60 |
61 | let idx = 1
62 |
63 | function updateTestimonial() {
64 | const { name, position, photo, text } = testimonials[idx]
65 |
66 | testimonial.innerHTML = text
67 | userImage.src = photo
68 | username.innerHTML = name
69 | role.innerHTML = position
70 |
71 | idx++
72 |
73 | if (idx > testimonials.length - 1) {
74 | idx = 0
75 | }
76 | }
77 |
78 | setInterval(updateTestimonial, 10000)
79 |
--------------------------------------------------------------------------------
/testimonial-box-switcher/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Montserrat');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #f4f4f4;
9 | font-family: 'Montserrat', sans-serif;
10 | display: flex;
11 | flex-direction: column;
12 | align-items: center;
13 | justify-content: center;
14 | height: 100vh;
15 | overflow: hidden;
16 | margin: 0;
17 | padding: 10px;
18 | }
19 |
20 | .testimonial-container {
21 | background-color: #476ce4;
22 | color: #fff;
23 | border-radius: 15px;
24 | margin: 20px auto;
25 | padding: 50px 80px;
26 | max-width: 768px;
27 | position: relative;
28 | }
29 |
30 | .fa-quote {
31 | color: rgba(255, 255, 255, 0.3);
32 | font-size: 28px;
33 | position: absolute;
34 | top: 70px;
35 | }
36 |
37 | .fa-quote-right {
38 | left: 40px;
39 | }
40 |
41 | .fa-quote-left {
42 | right: 40px;
43 | }
44 |
45 | .testimonial {
46 | line-height: 28px;
47 | text-align: justify;
48 | }
49 |
50 | .user {
51 | display: flex;
52 | align-items: center;
53 | justify-content: center;
54 | }
55 |
56 | .user .user-image {
57 | border-radius: 50%;
58 | height: 75px;
59 | width: 75px;
60 | object-fit: cover;
61 | }
62 |
63 | .user .user-details {
64 | margin-left: 10px;
65 | }
66 |
67 | .user .username {
68 | margin: 0;
69 | }
70 |
71 | .user .role {
72 | font-weight: normal;
73 | margin: 10px 0;
74 | }
75 |
76 | .progress-bar {
77 | background-color: #fff;
78 | height: 4px;
79 | width: 100%;
80 | animation: grow 10s linear infinite;
81 | transform-origin: left;
82 | }
83 |
84 | @keyframes grow {
85 | 0% {
86 | transform: scaleX(0);
87 | }
88 | }
89 |
90 | @media (max-width: 768px) {
91 | .testimonial-container {
92 | padding: 20px 30px;
93 | }
94 |
95 | .fa-quote {
96 | display: none;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/theme-clock/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Theme Clock
8 |
9 |
10 |
11 |
12 | Dark mode
13 |
14 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/theme-clock/script.js:
--------------------------------------------------------------------------------
1 | const hourEl = document.querySelector('.hour')
2 | const minuteEl = document.querySelector('.minute')
3 | const secondEl = document.querySelector('.second')
4 | const timeEl = document.querySelector('.time')
5 | const dateEl = document.querySelector('.date')
6 | const toggle = document.querySelector('.toggle')
7 |
8 | const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
9 | const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
10 |
11 | toggle.addEventListener('click', (e) => {
12 | const html = document.querySelector('html')
13 | if (html.classList.contains('dark')) {
14 | html.classList.remove('dark')
15 | e.target.innerHTML = 'Dark mode'
16 | } else {
17 | html.classList.add('dark')
18 | e.target.innerHTML = 'Light mode'
19 | }
20 | })
21 |
22 | function setTime() {
23 | const time = new Date();
24 | const month = time.getMonth()
25 | const day = time.getDay()
26 | const date = time.getDate()
27 | const hours = time.getHours()
28 | const hoursForClock = hours >= 13 ? hours % 12 : hours;
29 | const minutes = time.getMinutes()
30 | const seconds = time.getSeconds()
31 | const ampm = hours >= 12 ? 'PM' : 'AM'
32 |
33 | hourEl.style.transform = `translate(-50%, -100%) rotate(${scale(hoursForClock, 0, 12, 0, 360)}deg)`
34 | minuteEl.style.transform = `translate(-50%, -100%) rotate(${scale(minutes, 0, 60, 0, 360)}deg)`
35 | secondEl.style.transform = `translate(-50%, -100%) rotate(${scale(seconds, 0, 60, 0, 360)}deg)`
36 |
37 | timeEl.innerHTML = `${hoursForClock}:${minutes < 10 ? `0${minutes}` : minutes} ${ampm}`
38 | dateEl.innerHTML = `${days[day]}, ${months[month]} ${date} `
39 | }
40 |
41 | // StackOverflow https://stackoverflow.com/questions/10756313/javascript-jquery-map-a-range-of-numbers-to-another-range-of-numbers
42 | const scale = (num, in_min, in_max, out_min, out_max) => {
43 | return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
44 | }
45 |
46 | setTime()
47 |
48 | setInterval(setTime, 1000)
49 |
--------------------------------------------------------------------------------
/theme-clock/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Heebo:300&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | :root {
8 | --primary-color: #000;
9 | --secondary-color: #fff;
10 | }
11 |
12 | html {
13 | transition: all 0.5s ease-in;
14 | }
15 |
16 | html.dark {
17 | --primary-color: #fff;
18 | --secondary-color: #333;
19 | }
20 |
21 | html.dark {
22 | background-color: #111;
23 | color: var(--primary-color);
24 | }
25 |
26 | body {
27 | font-family: 'Heebo', sans-serif;
28 | display: flex;
29 | align-items: center;
30 | justify-content: center;
31 | height: 100vh;
32 | overflow: hidden;
33 | margin: 0;
34 | }
35 |
36 | .toggle {
37 | cursor: pointer;
38 | background-color: var(--primary-color);
39 | color: var(--secondary-color);
40 | border: 0;
41 | border-radius: 4px;
42 | padding: 8px 12px;
43 | position: absolute;
44 | top: 100px;
45 | }
46 |
47 | .toggle:focus {
48 | outline: none;
49 | }
50 |
51 | .clock-container {
52 | display: flex;
53 | flex-direction: column;
54 | justify-content: space-between;
55 | align-items: center;
56 | }
57 |
58 | .clock {
59 | position: relative;
60 | width: 200px;
61 | height: 200px;
62 | }
63 |
64 | .needle {
65 | background-color: var(--primary-color);
66 | position: absolute;
67 | top: 50%;
68 | left: 50%;
69 | height: 65px;
70 | width: 3px;
71 | transform-origin: bottom center;
72 | transition: all 0.5s ease-in;
73 | }
74 |
75 | .needle.hour {
76 | transform: translate(-50%, -100%) rotate(0deg);
77 | }
78 |
79 | .needle.minute {
80 | transform: translate(-50%, -100%) rotate(0deg);
81 | height: 100px;
82 | }
83 |
84 | .needle.second {
85 | transform: translate(-50%, -100%) rotate(0deg);
86 | height: 100px;
87 | background-color: #e74c3c;
88 | }
89 |
90 | .center-point {
91 | background-color: #e74c3c;
92 | width: 10px;
93 | height: 10px;
94 | position: absolute;
95 | top: 50%;
96 | left: 50%;
97 | transform: translate(-50%, -50%);
98 | border-radius: 50%;
99 | }
100 |
101 | .center-point::after {
102 | content: '';
103 | background-color: var(--primary-color);
104 | width: 5px;
105 | height: 5px;
106 | position: absolute;
107 | top: 50%;
108 | left: 50%;
109 | transform: translate(-50%, -50%);
110 | border-radius: 50%;
111 | }
112 |
113 | .time {
114 | font-size: 60px;
115 | }
116 |
117 | .date {
118 | color: #aaa;
119 | font-size: 14px;
120 | letter-spacing: 0.3px;
121 | text-transform: uppercase;
122 | }
123 |
124 | .date .circle {
125 | background-color: var(--primary-color);
126 | color: var(--secondary-color);
127 | border-radius: 50%;
128 | height: 18px;
129 | width: 18px;
130 | display: inline-flex;
131 | align-items: center;
132 | justify-content: center;
133 | line-height: 18px;
134 | transition: all 0.5s ease-in;
135 | font-size: 12px;
136 | }
137 |
--------------------------------------------------------------------------------
/toast-notification/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Toast Notification
8 |
9 |
10 |
11 |
12 | Show Notification
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/toast-notification/script.js:
--------------------------------------------------------------------------------
1 | const button = document.getElementById('button')
2 | const toasts = document.getElementById('toasts')
3 |
4 | const messages = [
5 | 'Message One',
6 | 'Message Two',
7 | 'Message Three',
8 | 'Message Four',
9 | ]
10 |
11 | const types = ['info', 'success', 'error']
12 |
13 | button.addEventListener('click', () => createNotification())
14 |
15 | function createNotification(message = null, type = null) {
16 | const notif = document.createElement('div')
17 | notif.classList.add('toast')
18 | notif.classList.add(type ? type : getRandomType())
19 |
20 | notif.innerText = message ? message : getRandomMessage()
21 |
22 | toasts.appendChild(notif)
23 |
24 | setTimeout(() => {
25 | notif.remove()
26 | }, 3000)
27 | }
28 |
29 | function getRandomMessage() {
30 | return messages[Math.floor(Math.random() * messages.length)]
31 | }
32 |
33 | function getRandomType() {
34 | return types[Math.floor(Math.random() * types.length)]
35 | }
--------------------------------------------------------------------------------
/toast-notification/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: rebeccapurple;
9 | font-family: 'Poppins', sans-serif;
10 | display: flex;
11 | flex-direction: column;
12 | align-items: center;
13 | justify-content: center;
14 | height: 100vh;
15 | overflow: hidden;
16 | margin: 0;
17 | }
18 |
19 | .btn {
20 | background-color: #ffffff;
21 | color: rebeccapurple;
22 | font-family: inherit;
23 | font-weight: bold;
24 | padding: 1rem;
25 | border-radius: 5px;
26 | border: none;
27 | cursor: pointer;
28 | }
29 |
30 | .btn:focus {
31 | outline: none;
32 | }
33 |
34 | .btn:active {
35 | transform: scale(0.98);
36 | }
37 |
38 | #toasts {
39 | position: fixed;
40 | bottom: 10px;
41 | right: 10px;
42 | display: flex;
43 | flex-direction: column;
44 | align-items: flex-end;
45 | }
46 |
47 | .toast {
48 | background-color: #fff;
49 | border-radius: 5px;
50 | padding: 1rem 2rem;
51 | margin: 0.5rem;
52 | }
53 |
54 | .toast.info {
55 | color: rebeccapurple;
56 | }
57 |
58 | .toast.success {
59 | color: green;
60 | }
61 |
62 | .toast.error {
63 | color: red;
64 | }
65 |
--------------------------------------------------------------------------------
/todo-list/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Todo List
8 |
9 |
10 | todos
11 |
16 | Left click to toggle completed. Right click to delete todo
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/todo-list/script.js:
--------------------------------------------------------------------------------
1 | const form = document.getElementById('form')
2 | const input = document.getElementById('input')
3 | const todosUL = document.getElementById('todos')
4 |
5 | const todos = JSON.parse(localStorage.getItem('todos'))
6 |
7 | if(todos) {
8 | todos.forEach(todo => addTodo(todo))
9 | }
10 |
11 | form.addEventListener('submit', (e) => {
12 | e.preventDefault()
13 |
14 | addTodo()
15 | })
16 |
17 | function addTodo(todo) {
18 | let todoText = input.value
19 |
20 | if(todo) {
21 | todoText = todo.text
22 | }
23 |
24 | if(todoText) {
25 | const todoEl = document.createElement('li')
26 | if(todo && todo.completed) {
27 | todoEl.classList.add('completed')
28 | }
29 |
30 | todoEl.innerText = todoText
31 |
32 | todoEl.addEventListener('click', () => {
33 | todoEl.classList.toggle('completed')
34 | updateLS()
35 | })
36 |
37 | todoEl.addEventListener('contextmenu', (e) => {
38 | e.preventDefault()
39 |
40 | todoEl.remove()
41 | updateLS()
42 | })
43 |
44 | todosUL.appendChild(todoEl)
45 |
46 | input.value = ''
47 |
48 | updateLS()
49 | }
50 | }
51 |
52 | function updateLS() {
53 | todosEl = document.querySelectorAll('li')
54 |
55 | const todos = []
56 |
57 | todosEl.forEach(todoEl => {
58 | todos.push({
59 | text: todoEl.innerText,
60 | completed: todoEl.classList.contains('completed')
61 | })
62 | })
63 |
64 | localStorage.setItem('todos', JSON.stringify(todos))
65 | }
--------------------------------------------------------------------------------
/todo-list/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #f5f5f5;
9 | color: #444;
10 | font-family: 'Poppins', sans-serif;
11 | display: flex;
12 | flex-direction: column;
13 | align-items: center;
14 | justify-content: center;
15 | height: 100vh;
16 | margin: 0;
17 | }
18 |
19 | h1 {
20 | color: rgb(179, 131, 226);
21 | font-size: 10rem;
22 | text-align: center;
23 | opacity: 0.4;
24 | }
25 |
26 | form {
27 | box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
28 | max-width: 100%;
29 | width: 400px;
30 | }
31 |
32 | .input {
33 | border: none;
34 | color: #444;
35 | font-size: 2rem;
36 | padding: 1rem 2rem;
37 | display: block;
38 | width: 100%;
39 | }
40 |
41 | .input::placeholder {
42 | color: #d5d5d5;
43 | }
44 |
45 | .input:focus {
46 | outline-color: rgb(179, 131, 226);
47 | }
48 |
49 | .todos {
50 | background-color: #fff;
51 | padding: 0;
52 | margin: 0;
53 | list-style-type: none;
54 | }
55 |
56 | .todos li {
57 | border-top: 1px solid #e5e5e5;
58 | cursor: pointer;
59 | font-size: 1.5rem;
60 | padding: 1rem 2rem;
61 | }
62 |
63 | .todos li.completed {
64 | color: #b6b6b6;
65 | text-decoration: line-through;
66 | }
67 |
68 | small {
69 | color: #b5b5b5;
70 | margin-top: 3rem;
71 | text-align: center;
72 | }
73 |
--------------------------------------------------------------------------------
/verify-account-ui/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Verify Account
8 |
9 |
10 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/verify-account-ui/script.js:
--------------------------------------------------------------------------------
1 | const codes = document.querySelectorAll('.code')
2 |
3 | codes[0].focus()
4 |
5 | codes.forEach((code, idx) => {
6 | code.addEventListener('keydown', (e) => {
7 | if(e.key >= 0 && e.key <=9) {
8 | codes[idx].value = ''
9 | setTimeout(() => codes[idx + 1].focus(), 10)
10 | } else if(e.key === 'Backspace') {
11 | setTimeout(() => codes[idx - 1].focus(), 10)
12 | }
13 | })
14 | })
--------------------------------------------------------------------------------
/verify-account-ui/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Muli:300,700&display=swap');
2 | * {
3 | box-sizing: border-box;
4 | }
5 |
6 | body {
7 | background-color: #fbfcfe;
8 | font-family: 'Muli', sans-serif;
9 | display: flex;
10 | align-items: center;
11 | justify-content: center;
12 | height: 100vh;
13 | overflow: hidden;
14 | margin: 0;
15 | }
16 |
17 | .container {
18 | background-color: #fff;
19 | border: 3px #000 solid;
20 | border-radius: 10px;
21 | padding: 30px;
22 | max-width: 1000px;
23 | text-align: center;
24 | }
25 |
26 | .code-container {
27 | display: flex;
28 | align-items: center;
29 | justify-content: center;
30 | margin: 40px 0;
31 | }
32 |
33 | .code {
34 | caret-color: transparent;
35 | border-radius: 5px;
36 | font-size: 75px;
37 | height: 120px;
38 | width: 100px;
39 | border: 1px solid #eee;
40 | margin: 1%;
41 | text-align: center;
42 | font-weight: 300;
43 | -moz-appearance: textfield;
44 | }
45 |
46 | .code::-webkit-outer-spin-button,
47 | .code::-webkit-inner-spin-button {
48 | -webkit-appearance: none;
49 | margin: 0;
50 | }
51 |
52 | .code:valid {
53 | border-color: #3498db;
54 | box-shadow: 0 10px 10px -5px rgba(0, 0, 0, 0.25);
55 | }
56 |
57 | .info {
58 | background-color: #eaeaea;
59 | display: inline-block;
60 | padding: 10px;
61 | line-height: 20px;
62 | max-width: 400px;
63 | color: #777;
64 | border-radius: 5px;
65 | }
66 |
67 | @media (max-width: 600px) {
68 | .code-container {
69 | flex-wrap: wrap;
70 | }
71 |
72 | .code {
73 | font-size: 60px;
74 | height: 80px;
75 | max-width: 70px;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------