diff --git a/button-ripple-effect/script.js b/button-ripple-effect/script.js index b17ecf1..2a7ced9 100644 --- a/button-ripple-effect/script.js +++ b/button-ripple-effect/script.js @@ -2,15 +2,25 @@ const buttons = document.querySelectorAll('.ripple') buttons.forEach(button => { button.addEventListener('click', function (e) { + // e is an event object + // clientx provides the horizontal coordinate within the viewport (currently being shown) + // at which the event occur( as opposed to the coordinate within the page) const x = e.clientX const y = e.clientY + // event.target provides the reference to the object onto which the event was dispatched 触发事件 + // it is different from event.currentTarget when the handler is called during the bubbling or capturing phase of the event + + // five values that position can take : static, absolute, relative, fixed, sticky. + // offsetTop is the distance between the current node and the closest offset parent( whose position is non-static ) + // if there is on offset parent, return body const buttonTop = e.target.offsetTop const buttonLeft = e.target.offsetLeft const xInside = x - buttonLeft const yInside = y - buttonTop - + console.log(e,x,y,'x,y',buttonLeft,buttonTop,'offsetTop,offsetLeft') + console.log(this === e.target,'this') const circle = document.createElement('span') circle.classList.add('circle') circle.style.top = yInside + 'px' diff --git a/toast-notification/style.css b/toast-notification/style.css index 9ae67d4..3782f37 100644 --- a/toast-notification/style.css +++ b/toast-notification/style.css @@ -49,6 +49,17 @@ body { border-radius: 5px; padding: 1rem 2rem; margin: 0.5rem; + animation: toastStart .5s ease-in; +} +@keyframes toastStart{ + from{ + transform: scale(1,0); + opacity: 0.5; + } + to{ + transform: scale(1); + opacity: 1; + } } .toast.info { diff --git a/workout/day1-button-ripple-effect/index.html b/workout/day1-button-ripple-effect/index.html new file mode 100644 index 0000000..9fb3f9d --- /dev/null +++ b/workout/day1-button-ripple-effect/index.html @@ -0,0 +1,14 @@ + + + + + + + Document + + + + + + + \ No newline at end of file diff --git a/workout/day1-button-ripple-effect/script.js b/workout/day1-button-ripple-effect/script.js new file mode 100644 index 0000000..7efab8c --- /dev/null +++ b/workout/day1-button-ripple-effect/script.js @@ -0,0 +1,40 @@ +const rippleButtons = document.querySelectorAll('.ripple'); + +function rippleClick(e){ + + // e is an event object + // clientx provides the horizontal coordinate within the viewport (currently being shown) + // at which the event occur( as opposed to the coordinate within the page) + const clientX = e.clientX + const clientY = e.clientY + + // event.target provides the reference to the object onto which the event was dispatched 触发事件 + // it is different from event.currentTarget when the handler is called during the bubbling or capturing phase of the event + + // five values that position can take : static, absolute, relative, fixed, sticky. + // offsetTop is the distance between the current node and the closest offset parent( whose position is non-static ) + // if there is on offset parent, return body + const target = e.target + const offsetLeft = target.offsetLeft + const offsetTop = target.offsetTop + + const xInside = clientX - offsetLeft; + const yInside = clientY - offsetTop; + + const spanNode = document.createElement('span'); + spanNode.classList.add('rippleCircle'); + // type of value style.left is a string + spanNode.style.left = xInside + 'px' + spanNode.style.top = yInside + 'px' + + target.appendChild(spanNode) + + setTimeout(()=>{ + spanNode.remove() + },500) +} + +console.log(rippleButtons,'rippleButtons') +rippleButtons.forEach((ele) =>{ + ele.addEventListener('click',rippleClick) +}) \ No newline at end of file diff --git a/workout/day1-button-ripple-effect/style.css b/workout/day1-button-ripple-effect/style.css new file mode 100644 index 0000000..5df3c9d --- /dev/null +++ b/workout/day1-button-ripple-effect/style.css @@ -0,0 +1,51 @@ +@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'); + +* { + box-sizing: border-box; +} + +body { + background-color: #000; + font-family: 'Roboto', sans-serif; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100vh; + overflow: hidden; + margin: 0; +} + +button { + background-color: purple; + color: #fff; + border: 1px purple solid; + font-size: 14px; + text-transform: uppercase; + letter-spacing: 2px; + padding: 20px 30px; + overflow: hidden; + margin: 10px 0; + position: relative; +} + +button:focus { + outline: none; +} +/* why set translate(-50%,50%)? */ +/* to set center of the ripple element at the place where the mouse is÷\ */ +.rippleCircle{ + position: absolute; + width: 100px; + height: 100px; + background-color: #fff; + border-radius: 50%; + transform: translate(-50%, -50%) scale(0); + animation: circle .5s ease-out; +} +@keyframes circle{ + to{ + transform: translate(-50%, -50%) scale(3); + opacity: 0; + } +} \ No newline at end of file diff --git a/workout/day2-toast-notification/index.html b/workout/day2-toast-notification/index.html new file mode 100644 index 0000000..e700ba7 --- /dev/null +++ b/workout/day2-toast-notification/index.html @@ -0,0 +1,15 @@ + + + + + + + Document + + + +
+ + + + \ No newline at end of file diff --git a/workout/day2-toast-notification/script.js b/workout/day2-toast-notification/script.js new file mode 100644 index 0000000..a0ef296 --- /dev/null +++ b/workout/day2-toast-notification/script.js @@ -0,0 +1,32 @@ +const btn = document.querySelector('.btn'); +const toastContainer = document.querySelector('#finnui-toast'); + +const randomTextArr = ['message one', 'message two', 'message three', 'message four']; +const randomTypeArr = ['warning', 'success', 'error']; + +function createToast(text,type){ + const toastDom = document.createElement('div'); + const toastText = text || randomText() + const toastType = type || randomType(); + toastDom.classList.add('finn-toast') + toastDom.classList.add(toastType) + toastDom.innerText = toastText + return toastDom +} + +function randomText(){ + return randomTextArr[Math.floor(Math.random()*randomTextArr.length)] +} +function randomType(){ + return randomTypeArr[Math.floor(Math.random()*randomTypeArr.length)] +} + +function showToast(duration = 5){ + const toastNode = createToast(); + toastContainer.appendChild(toastNode) + setTimeout(()=>{ + toastNode.remove() + },duration*1000) +} + +btn.addEventListener('click',()=>showToast()) \ No newline at end of file diff --git a/workout/day2-toast-notification/style.css b/workout/day2-toast-notification/style.css new file mode 100644 index 0000000..d0e08a8 --- /dev/null +++ b/workout/day2-toast-notification/style.css @@ -0,0 +1,79 @@ +@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;400&display=swap'); + +* { + box-sizing: border-box; +} + +body { + background-color: rebeccapurple; + font-family: 'Poppins', sans-serif; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100vh; + overflow: hidden; + margin: 0; +} + +#finnui-toast{ + width: 200px; + position: absolute; + top: 10px; + bottom: 10px; + right: 10px; + display: flex; + flex-direction: column; + justify-content: flex-end; +} + +.btn { + background-color: #ffffff; + color: rebeccapurple; + font-family: inherit; + font-weight: bold; + padding: 1rem; + border-radius: 5px; + border: none; + cursor: pointer; +} + + +@keyframes toast-show{ + from{ + transform: scale(1,0); + } + to{ + transform: scale(1); + } +} + +@keyframes toast-leave{ + from{ + transform: scale(1,0); + } + to{ + transform: scale(1); + } +} + +.finn-toast{ + min-width: 200px; + margin-bottom: 10px; + font-size: 16px; + line-height: 20px; + background-color: #ffffff; + animation: toast-show .5s ease-in; + padding: 5px; + border-radius: 3px; +} + +.warning{ + color: #F2C037; +} +.success{ + color: green; +} +.error{ + color: red; +} \ No newline at end of file diff --git a/workout/day3-hidden-search/index.html b/workout/day3-hidden-search/index.html new file mode 100644 index 0000000..54f45b9 --- /dev/null +++ b/workout/day3-hidden-search/index.html @@ -0,0 +1,19 @@ + + + + + + + + Hidden Search + + + + + + diff --git a/workout/day3-hidden-search/script.js b/workout/day3-hidden-search/script.js new file mode 100644 index 0000000..866ee36 --- /dev/null +++ b/workout/day3-hidden-search/script.js @@ -0,0 +1,9 @@ +const searchNode = document.querySelector('.search'); +const input = document.querySelector('.input') + +searchNode.addEventListener('click',()=> handleClick()); + +function handleClick(){ + searchNode.classList.toggle('active') + input.focus() +} \ No newline at end of file diff --git a/workout/day3-hidden-search/style.css b/workout/day3-hidden-search/style.css new file mode 100644 index 0000000..111c5a6 --- /dev/null +++ b/workout/day3-hidden-search/style.css @@ -0,0 +1,57 @@ +@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'); + +* { + box-sizing: border-box; +} + +body { + background-image: linear-gradient(90deg, #7d5fff, #7158e2); + font-family: 'Roboto', sans-serif; + display: flex; + align-items: center; + justify-content: center; + height: 100vh; + overflow: hidden; + margin: 0; +} + +.search { + position: relative; + height: 50px; +} + +.search .input { + background-color: #fff; + border: 0; + font-size: 18px; + padding: 15px; + height: 50px; + width: 0px; + transition: width 0.3s ease; +} + +.btn { + background-color: #fff; + border: 0; + cursor: pointer; + font-size: 24px; + position: absolute; + top: 0; + left: 0; + height: 50px; + width: 50px; + transition: transform 0.3s ease; +} + +.btn:focus, +.input:focus { + outline: none; +} + +.search.active .input { + width: 200px; +} + +.search.active .btn { + transform: translateX(198px); +} diff --git a/workout/day4-faq-collapse/index.html b/workout/day4-faq-collapse/index.html new file mode 100644 index 0000000..890ec5f --- /dev/null +++ b/workout/day4-faq-collapse/index.html @@ -0,0 +1,77 @@ + + + + + + + + FAQ + + +

Frequently Asked Questions

+
+
+

+ Why shouldn't we trust atoms? +

+ +

+ They make up everything +

+ + +
+ +
+

+ What do you call someone with no body and no nose? +

+

+ Nobody knows. +

+ +
+ +
+

+ What's the object-oriented way to become wealthy? +

+

+ Inheritance. +

+ +
+ +
+

+ How many tickles does it take to tickle an octopus? +

+

+ Ten-tickles! +

+ +
+ +
+

+ What is: 1 + 1? +

+

+ Depends on who are you asking. +

+ +
+
+ + + diff --git a/workout/day4-faq-collapse/script.js b/workout/day4-faq-collapse/script.js new file mode 100644 index 0000000..38505f2 --- /dev/null +++ b/workout/day4-faq-collapse/script.js @@ -0,0 +1,8 @@ +const toggles = document.querySelectorAll('.faq-toggle') + +toggles.forEach(toggle => { + toggle.addEventListener('click', () => { + // use css tricks to implement the requirements first + toggle.parentNode.classList.toggle('active') + }) +}) \ No newline at end of file diff --git a/workout/day4-faq-collapse/style.css b/workout/day4-faq-collapse/style.css new file mode 100644 index 0000000..6300c46 --- /dev/null +++ b/workout/day4-faq-collapse/style.css @@ -0,0 +1,116 @@ +@import url('https://fonts.googleapis.com/css?family=Muli&display=swap'); + +* { + box-sizing: border-box; +} + +body { + font-family: 'Muli', sans-serif; + background-color: #f0f0f0; +} + +h1 { + margin: 50px 0 30px; + text-align: center; +} + +.faq-container { + max-width: 600px; + margin: 0 auto; +} + +.faq { + background-color: transparent; + border: 1px solid #9fa4a8; + border-radius: 10px; + margin: 20px 0; + padding: 30px; + position: relative; + overflow: hidden; +} + +.faq.active { + background-color: #fff; + box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1), 0 3px 6px rgba(0, 0, 0, 0.1); +} + +.faq.active::before, +.faq.active::after { + content: '\f075'; + font-family: 'Font Awesome 5 Free'; + color: #2ecc71; + font-size: 7rem; + position: absolute; + opacity: 0.2; + top: 20px; + left: 20px; + z-index: 0; +} + +.faq.active::before { + color: #3498db; + top: -10px; + left: -30px; + transform: rotateY(180deg); +} + +.faq-title { + margin: 0 35px 0 0; +} + +.faq-text { + height: 0; + margin: 0; + transition-duration: .3s; + overflow: hidden; +} + +.faq.active .faq-text { + height: auto; + margin: 30px 0 0; +} + +.faq-toggle { + background-color: transparent; + border: 0; + border-radius: 50%; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: 16px; + padding: 0; + position: absolute; + top: 30px; + right: 30px; + height: 30px; + width: 30px; +} + +.faq-toggle:focus { + outline: 0; +} + +.faq-toggle .fa-times { + display: none; +} + +.faq.active .faq-toggle .fa-times { + color: #fff; + display: block; +} +@keyframes spin{ + to{ + transform: rotateX(180deg) + } +} +.faq.active .faq-toggle .fa-chevron-down { + /* display: none; */ + /* animation: spin 1s ease; */ + transform: rotateX(180deg); + transition: all .3s; +} + +.faq.active .faq-toggle { + /* background-color: #9fa4a8; */ +} diff --git a/workout/day5-expanding-cards/index.html b/workout/day5-expanding-cards/index.html new file mode 100644 index 0000000..164951d --- /dev/null +++ b/workout/day5-expanding-cards/index.html @@ -0,0 +1,31 @@ + + + + + + + Expanding Cards + + +
+
+

Explore The World

+
+
+

Wild Forest

+
+
+

Sunny Beach

+
+
+

City on Winter

+
+
+

Mountains - Clouds

+
+ +
+ + + + diff --git a/workout/day5-expanding-cards/script.js b/workout/day5-expanding-cards/script.js new file mode 100644 index 0000000..caffe9b --- /dev/null +++ b/workout/day5-expanding-cards/script.js @@ -0,0 +1,19 @@ +const panels = document.querySelectorAll('.panel') +const ACTIVE_NAME = 'active' +panels.forEach(panel => { + panel.addEventListener('click',(e)=>{ + // remove classname of all panels first + // add active classname to e.target + // add or delete classname by calling add or remove method in classList object + removeActiveClasses() + e.target.classList.add(ACTIVE_NAME) + }) +}) + +function removeActiveClasses() { + panels.forEach((panel)=>{ + panel.classList.remove(ACTIVE_NAME) + }) +} + +// in Vue or React, we could set dynamic classname with its reactivity system \ No newline at end of file diff --git a/workout/day5-expanding-cards/style.css b/workout/day5-expanding-cards/style.css new file mode 100644 index 0000000..a6fe024 --- /dev/null +++ b/workout/day5-expanding-cards/style.css @@ -0,0 +1,63 @@ +@import url('https://fonts.googleapis.com/css?family=Muli&display=swap'); + +* { + box-sizing: border-box; +} + +body { + font-family: 'Muli', sans-serif; + display: flex; + align-items: center; + justify-content: center; + height: 100vh; + overflow: hidden; + margin: 0; +} + +.container { + display: flex; + width: 90vw; +} + +.panel { + background-size: cover; + background-position: center; + background-repeat: no-repeat; + height: 80vh; + border-radius: 50px; + color: #fff; + cursor: pointer; + flex: 0.5; + margin: 10px; + position: relative; + -webkit-transition: all 700ms ease-in; +} + +.panel h3 { + font-size: 24px; + position: absolute; + bottom: 20px; + left: 20px; + margin: 0; + opacity: 0; +} + +.panel.active { + flex: 5; +} + +.panel.active h3 { + opacity: 1; + transition: opacity 0.3s ease-in 0.4s; +} + +@media (max-width: 480px) { + .container { + width: 100vw; + } + + .panel:nth-of-type(4), + .panel:nth-of-type(5) { + display: none; + } +} diff --git a/workout/grial-holly-layout/grail-holly-layout-with-flexbox.html b/workout/grial-holly-layout/grail-holly-layout-with-flexbox.html new file mode 100644 index 0000000..e36a79f --- /dev/null +++ b/workout/grial-holly-layout/grail-holly-layout-with-flexbox.html @@ -0,0 +1,37 @@ + + + + + + + Document + + + +
+
left
+
main
+
right
+
+ + \ No newline at end of file diff --git a/workout/grial-holly-layout/index.html b/workout/grial-holly-layout/index.html new file mode 100644 index 0000000..e114470 --- /dev/null +++ b/workout/grial-holly-layout/index.html @@ -0,0 +1,17 @@ + + + + + + + Document + + + +
+
main
+
left
+
right
+
+ + \ No newline at end of file diff --git a/workout/grial-holly-layout/style.css b/workout/grial-holly-layout/style.css new file mode 100644 index 0000000..cad749c --- /dev/null +++ b/workout/grial-holly-layout/style.css @@ -0,0 +1,22 @@ +.container{ + height: 100px; + padding: 0 100px; +} +.colume{ + float: left; + height: 100%; +} +.main{ + background-color: aquamarine; + width: 100%; +} +.left{ + width: 100px; + background-color: antiquewhite; + margin-left: calc( -100% - 100px); +} +.right{ + background-color:cornflowerblue; + width: 100px; + margin-right: -100px; +} \ No newline at end of file