├── .github └── FUNDING.yml ├── Google Script for twitter └── google script.js ├── README.md ├── dynamic_table_of_content ├── index.html ├── script.js └── style.css ├── html_login_form ├── icon.png ├── index.html └── main.css ├── javascript_carousel ├── images │ ├── testimonial1.jpg │ ├── testimonial2.jpg │ └── testimonial3.jpg ├── index.html ├── script.js └── style.css ├── pomodoro-clock ├── index.html ├── progressBar.js ├── script.js └── style.css ├── random_quote_machine ├── index.html ├── index.js └── style.css ├── screenshots ├── html_login_form.png ├── javascript_carousel.gif ├── javascript_pomodoro_clock.gif ├── javascript_random_quote_machine.gif ├── javascript_smooth_scroll_navigation.gif ├── javascript_todo_list.png └── sticky_table_of_content_inspiredwebdev.gif └── smooth_scroll ├── index.html ├── script.js └── style.css /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: https://ko-fi.com/albertomontalesi 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /Google Script for twitter/google script.js: -------------------------------------------------------------------------------- 1 | function sendDailyTweet() { 2 | var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); 3 | var startRowNumber = 1; 4 | var endRowNumber = sheet.getLastRow(); 5 | var twitterKeys = { 6 | TWITTER_CONSUMER_KEY: "[your_key_here]", 7 | TWITTER_CONSUMER_SECRET: "[your_key_here]", 8 | TWITTER_ACCESS_TOKEN: "[your_key_here]", 9 | TWITTER_ACCESS_SECRET: "[your_key_here]", 10 | } 11 | var props = PropertiesService.getScriptProperties(); 12 | props.setProperties(twitterKeys); 13 | var params = new Array(0); 14 | var service = new Twitter.OAuth(props); 15 | 16 | var vietnameseWord; 17 | var englishWord; 18 | var sentenceExample; 19 | var identifier; 20 | 21 | for (var currentRowNumber = startRowNumber; currentRowNumber <= endRowNumber; currentRowNumber++) { 22 | var row = sheet.getRange(currentRowNumber + ":" + currentRowNumber) 23 | .getValues(); 24 | // check that the fourth column (Date) is equal to today 25 | if (isToday(row[0][3])) { 26 | vietnameseWord = row[0][0]; 27 | englishWord = row[0][1]; 28 | sentenceExample = row[0][2]; 29 | identifier = currentRowNumber - 1; 30 | // also add a number to the tweet: Word of the day #60: 31 | console.log("the word of the day is " + vietnameseWord + ", the sentence of the day is " + sentenceExample); 32 | break; 33 | } 34 | } 35 | 36 | if (!service.hasAccess()) { 37 | console.log("Authentication Failed"); 38 | } else { 39 | console.log("Authentication Successful"); 40 | var status = "Vietnamese Word #" + identifier + "\n\n" + vietnameseWord + " - " + englishWord + "\n\n" + "E.g: " + sentenceExample + "\n\n" + 41 | "Comment with your sentence. Learn more @ elingos.com" + "\n\n" + "#wordoftheday #languagelearning #learnvietnamese #vietnameselanguage #elingosvietnamese"; 42 | try { 43 | console.log(status); 44 | var response = service.sendTweet(status, params); 45 | console.log(response); 46 | } catch (e) { 47 | console.log(e) 48 | } 49 | } 50 | 51 | 52 | 53 | } 54 | 55 | function isToday(date) { 56 | var today = new Date(); 57 | var dateFromRow = new Date(date); 58 | return dateFromRow.getDate() == today.getDate() && 59 | dateFromRow.getMonth() == today.getMonth() && 60 | dateFromRow.getFullYear() == today.getFullYear() 61 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [InspiredWebDev Tutorials](https://inspiredwebdev.com) 2 | 3 | [![](https://img.shields.io/badge/Donate-PayPal-blue.svg)](https://www.paypal.me/albertomontalesi) 4 | [![](https://img.shields.io/badge/Follow-Medium-green.svg)](https://medium.com/@labby92) 5 | [![Twitter](https://img.shields.io/twitter/url/https/github.com/AlbertoMontalesi/JavaScript-es6-and-beyond-ebook.svg?style=social)](https://twitter.com/intent/tweet?text=Wow:&url=https%3A%2F%2Fgithub.com%2FAlbertoMontalesi%2FJavaScript-es6-and-beyond-ebook) 6 | 7 | [![GitHub forks](https://img.shields.io/github/forks/AlbertoMontalesi/InspiredWebDev-Tutorials.svg)](https://github.com/AlbertoMontalesi/InspiredWebDev-Tutorials/network) 8 | [![GitHub stars](https://img.shields.io/github/stars/AlbertoMontalesi/InspiredWebDev-Tutorials.svg)](https://github.com/AlbertoMontalesi/InspiredWebDev-Tutorials/stargazers) 9 | 10 | [![Github All Releases](https://img.shields.io/github/downloads/AlbertoMontalesi/JavaScript-es6-and-beyond-ebook/total.svg)](https://github.com/AlbertoMontalesi/InspiredWebDev-Tutorials) 11 | 12 | [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/AlbertoMontalesi/InspiredWebDev-Tutorials/pulls) 13 | [![HitCount](http://hits.dwyl.io/albertomontalesi/InspiredWebDev-Tutorials.svg)](http://hits.dwyl.io/albertomontalesi/InspiredWebDev-Tutorials) 14 | 15 | This repo hosts the code for all my tutorials 16 | 17 | Follow me on my [Blog](https://inspiredwebdev.com) for more tutorials and articles. 18 | 19 | If you are interested in learning JavaScript, don't forget to [check out my e-book](https://github.com/AlbertoMontalesi/The-complete-guide-to-modern-JavaScript) 20 | 21 | --- 22 | 23 | --- 24 | 25 | ## [6 Pomodoro Clock](https://inspiredwebdev.com/tutorial/create-pomodoro-clock) 26 | 27 | ![pomodoro clock](/screenshots/javascript_pomodoro_clock.gif) 28 | 29 | --- 30 | 31 | ## [5 Random Quote Machine](https://inspiredwebdev.com/tutorial/create-random-quote-machine) 32 | 33 | ![random quote machine](/screenshots/javascript_random_quote_machine.gif) 34 | 35 | --- 36 | 37 | ## [4 Smooth Scroll Navigation](https://inspiredwebdev.com/tutorial/smooth-scrolling-navigation) 38 | 39 | ![smooth scroll navigation](/screenshots/javascript_smooth_scroll_navigation.gif) 40 | 41 | --- 42 | 43 | ## [3 JavaScript Carousel](https://www.inspiredwebdev.com/tutorial/javascript-carousel) 44 | 45 | ![project 2 - javascript carousel](/screenshots/javascript_carousel.gif) 46 | 47 | --- 48 | 49 | ## [2 Simple HTML Form](https://www.inspiredwebdev.com/tutorial/create-responsive-html-login-form) 50 | 51 | ![project 1 - simple html form](/screenshots/html_login_form.png) 52 | 53 | --- 54 | 55 | ## [1 To Do List](https://www.inspiredwebdev.com/tutorial/how-to-create-a-to-do-list-with-javascript) 56 | 57 | ![project 1 - to do list](/screenshots/javascript_todo_list.png) 58 | -------------------------------------------------------------------------------- /dynamic_table_of_content/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | InspiredWebDev dynamic table of content 11 | 12 | 13 | 14 | 15 |
16 | 17 |
18 |
19 |

Section 1

20 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis 21 | aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

22 |
23 |
24 |

Section 2

25 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis 26 | aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

27 |
28 |
29 |

Section 3

30 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis 31 | aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

32 |
33 |
34 |

Section 4

35 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis 36 | aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

37 |
38 |
39 |
40 |

Table of content

41 |
42 |
43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /dynamic_table_of_content/script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', () => { 2 | const headings = document.querySelectorAll('#content h3'); 3 | if (headings && headings.length) { 4 | 5 | let tableOfContentInner = ''; 6 | headings.forEach((heading, i) => { 7 | // generate an 'li' element that includes a link to the appropriate section 8 | tableOfContentInner += `
  • ${heading.textContent}
  • ` 9 | const originalHeadingContent = heading.innerHTML; 10 | const anchor = `` 11 | // add the anchor to the

    tag 12 | heading.innerHTML = anchor + originalHeadingContent 13 | }) 14 | 15 | const tableOfContent = `
      ${tableOfContentInner}
    ` 16 | // add the generated table of content to the dive 17 | document.querySelector('#table-of-content').innerHTML += tableOfContent 18 | 19 | 20 | // automatically go to the correct section on load 21 | if (location.hash) { 22 | const target = location.hash; 23 | const offsetY = document.querySelector(target).offsetTop; 24 | window.scrollTo(0, offsetY); 25 | } 26 | 27 | } 28 | 29 | }) -------------------------------------------------------------------------------- /dynamic_table_of_content/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | scroll-behavior: smooth; 3 | } 4 | 5 | #container { 6 | display: flex; 7 | justify-content: space-around; 8 | align-items: flex-start; 9 | } 10 | 11 | #content { 12 | width: 70vw; 13 | } 14 | 15 | #content div { 16 | height: 100vh; 17 | } 18 | 19 | #table-of-content { 20 | width: 30vw; 21 | position: sticky; 22 | top: 0; 23 | } -------------------------------------------------------------------------------- /html_login_form/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDev-Tutorials/6631a9df08a73f1cdcd8be111eb27852d30ce84b/html_login_form/icon.png -------------------------------------------------------------------------------- /html_login_form/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | #1 HTML Login Form 8 | 9 | 11 | 12 | 13 | 14 | 15 | 16 |
    17 |
    18 | computer icon 19 |
    20 |
    21 |

    Member Login

    22 |
    23 | 24 | 25 |
    26 |
    27 | 28 | 29 |
    30 | 31 | Forgot Username / Password ? 32 | 33 | Create your account ➡ 34 | 35 |
    36 |
    37 | 38 | 39 | -------------------------------------------------------------------------------- /html_login_form/main.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --body_gradient_left: #7200D0; 3 | --body_gradient_right: #C800C1; 4 | --form_bg: #ffffff; 5 | --input_bg: #E5E5E5; 6 | --input_hover: #eaeaea; 7 | --submit_bg: #1FCC44; 8 | --submit_hover: #40e263; 9 | --icon_color: #6b6b6b; 10 | } 11 | 12 | * { 13 | padding: 0; 14 | margin: 0; 15 | box-sizing: border-box; 16 | } 17 | 18 | body { 19 | /* make the body full height*/ 20 | height: 100vh; 21 | /* set our custom font */ 22 | font-family: 'Roboto', 23 | sans-serif; 24 | /* create a linear gradient*/ 25 | background-image: linear-gradient(to right, var(--body_gradient_left), var(--body_gradient_right)); 26 | display: flex; 27 | } 28 | 29 | #form_wrapper { 30 | width: 1000px; 31 | height: 700px; 32 | /* this will help us center it*/ 33 | margin: auto; 34 | background-color: var(--form_bg); 35 | border-radius: 50px; 36 | /* make it a grid container*/ 37 | display: grid; 38 | /* with two columns of same width*/ 39 | grid-template-columns: 1fr 1fr; 40 | /* with a small gap in between them*/ 41 | grid-gap: 5vw; 42 | /* add some padding around */ 43 | padding: 5vh 15px; 44 | } 45 | 46 | #form_left { 47 | /* center the image */ 48 | display: flex; 49 | justify-content: center; 50 | align-items: center; 51 | } 52 | 53 | #form_left img { 54 | width: 350px; 55 | height: 350px; 56 | } 57 | 58 | #form_right { 59 | display: grid; 60 | /* single column layout */ 61 | grid-template-columns: 1fr; 62 | /* have some gap in between elements*/ 63 | grid-gap: 20px; 64 | padding: 10% 5%; 65 | } 66 | 67 | h1, 68 | span { 69 | text-align: center; 70 | } 71 | 72 | .input_container { 73 | background-color: var(--input_bg); 74 | /* vertically align icon and text inside the div*/ 75 | display: flex; 76 | align-items: center; 77 | padding-left: 20px; 78 | } 79 | 80 | .input_container:hover { 81 | background-color: var(--input_hover); 82 | } 83 | 84 | .input_container, 85 | #input_submit { 86 | height: 60px; 87 | /* make the borders more round */ 88 | border-radius: 30px; 89 | width: 100%; 90 | } 91 | 92 | .input_field { 93 | /* customize the input tag with lighter font and some padding*/ 94 | color: var(--icon_color); 95 | background-color: inherit; 96 | width: 90%; 97 | border: none; 98 | font-size: 1.3rem; 99 | font-weight: 400; 100 | padding-left: 30px; 101 | } 102 | 103 | .input_field:hover, 104 | .input_field:focus { 105 | /* remove the outline */ 106 | outline: none; 107 | } 108 | 109 | #input_submit { 110 | /* submit button has a different color and different padding */ 111 | background-color: var(--submit_bg); 112 | padding-left: 0; 113 | font-weight: bold; 114 | color: white; 115 | text-transform: uppercase; 116 | } 117 | 118 | #input_submit:hover { 119 | background-color: var(--submit_hover); 120 | /* simple color transition on hover */ 121 | transition: background-color, 122 | 1s; 123 | cursor: pointer; 124 | } 125 | 126 | /* shift it a bit lower */ 127 | #create_account { 128 | display: block; 129 | position: relative; 130 | top: 30px; 131 | } 132 | 133 | a { 134 | /* remove default underline */ 135 | text-decoration: none; 136 | color: var(--submit_bg); 137 | font-weight: bold; 138 | } 139 | 140 | a:hover { 141 | color: var(--submit_hover); 142 | } 143 | 144 | i { 145 | color: var(--icon_color); 146 | } 147 | 148 | /* make it responsive */ 149 | @media screen and (max-width:768px) { 150 | 151 | /* make the layout a single column and add some margin to the wrapper */ 152 | #form_wrapper { 153 | grid-template-columns: 1fr; 154 | margin-left: 10px; 155 | margin-right: 10px; 156 | } 157 | /* on small screen we don't display the image */ 158 | #form_left { 159 | display: none; 160 | } 161 | } -------------------------------------------------------------------------------- /javascript_carousel/images/testimonial1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDev-Tutorials/6631a9df08a73f1cdcd8be111eb27852d30ce84b/javascript_carousel/images/testimonial1.jpg -------------------------------------------------------------------------------- /javascript_carousel/images/testimonial2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDev-Tutorials/6631a9df08a73f1cdcd8be111eb27852d30ce84b/javascript_carousel/images/testimonial2.jpg -------------------------------------------------------------------------------- /javascript_carousel/images/testimonial3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDev-Tutorials/6631a9df08a73f1cdcd8be111eb27852d30ce84b/javascript_carousel/images/testimonial3.jpg -------------------------------------------------------------------------------- /javascript_carousel/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | JavaScript Carousel 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
    16 |
    17 |

    Testimonials

    18 |
    19 |
    20 | < 21 |
    22 |
    23 | > 24 |
    25 |
    26 |
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed consectetur 27 | ullamcorper convallis. Suspendisse quis 28 | imperdiet nisi, et accumsan enim. Donec tempus mi ex, ac.
    29 |
    30 |
    31 |
    32 |

    Jane Doe

    33 |

    CEO Company x

    34 |
    35 |
    36 |
    37 |
    38 |
    39 | Cullamcorper convallis. Suspendisse quis 40 | imperdiet nisi, et accumsan enim. Donec tempus mi ex, ac.
    41 |
    42 |
    43 |
    44 |

    Jean Doe

    45 |

    Sales Manager

    46 |
    47 |
    48 |
    49 |
    50 |
    Curabitur sagittis ante ac elementum interdum. Curabitur viverra posuere 51 | lacus viverra ultricies. Phasellus lobortis 52 | consequat vulputate.
    53 |
    54 |
    55 |
    56 |

    John Doe

    57 |

    Business Analyst

    58 |
    59 |
    60 |
    61 |
    62 |
    63 |
    64 | 65 | 66 | -------------------------------------------------------------------------------- /javascript_carousel/script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", () => { 2 | 3 | // grab all the slides 4 | let slides = document.querySelectorAll("#slider .slide"); 5 | // set initial slide 6 | let currentSlide = 0; 7 | //grab both buttons 8 | const nextButton = document.querySelector(".button-right"); 9 | const prevButton = document.querySelector(".button-left"); 10 | 11 | 12 | function nextSlide() { 13 | // current slide becomes hidden 14 | slides[currentSlide].className = 'slide'; 15 | // set the current slide as the next one 16 | currentSlide = (currentSlide + 1) % slides.length; 17 | // add the class showing to the slide to make it visible 18 | slides[currentSlide].className = 'slide showing'; 19 | } 20 | 21 | function prevSlide() { 22 | // current slide becomes hidden 23 | slides[currentSlide].className = 'slide'; 24 | // set the current slide as the previous one 25 | currentSlide = (currentSlide - 1) % slides.length; 26 | 27 | if (currentSlide == -1) { 28 | currentSlide = slides.length - 1; 29 | } 30 | // add the class showing to the slide to make it visible 31 | slides[currentSlide].className = 'slide showing'; 32 | } 33 | 34 | nextButton.addEventListener("click", () => { 35 | // go to next slide on click of the button 36 | nextSlide(); 37 | }); 38 | prevButton.addEventListener("click", () => { 39 | // go to previous slide on click of the button 40 | prevSlide(); 41 | }); 42 | 43 | 44 | /* VERTICALLY ALIGN THE BUTTONS IN THE MIDDLE OF THE SLIDER TEXT 45 | */ 46 | function positionSliderButton() { 47 | // grab the slider 48 | let slider = document.querySelector('.slide-text'); 49 | // grab its height 50 | let sliderHeight = slider.getBoundingClientRect().height; 51 | // grab the button 52 | let buttons = document.querySelectorAll('.slider-button'); 53 | 54 | // for each of the buttons 55 | for (button of buttons) { 56 | // get their height 57 | let buttonHeight = button.getBoundingClientRect().height; 58 | // position them right in the middle of the text, 59 | button.style.top = (((sliderHeight - buttonHeight) / 2).toString()) + "px"; 60 | } 61 | } 62 | positionSliderButton(); 63 | 64 | // whenever the window is resize, reposition the buttons 65 | window.addEventListener('resize', () => { 66 | positionSliderButton(); 67 | }); 68 | 69 | }); -------------------------------------------------------------------------------- /javascript_carousel/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --bg-section: #374057; 3 | --color-headers: #2c3e50; 4 | --color-highlight-green: #00AF4E; 5 | --color-light-gray: #EEEFF2; 6 | } 7 | 8 | * { 9 | font-family: 'Roboto', sans-serif; 10 | padding: 0; 11 | margin: 0; 12 | text-decoration: none; 13 | font-size: 16px; 14 | } 15 | 16 | body { 17 | position: relative; 18 | height: 100vh; 19 | background-color: var(--bg-section); 20 | display: flex; 21 | } 22 | 23 | .container { 24 | width: 900px; 25 | margin: auto; 26 | padding: 20px; 27 | } 28 | 29 | h1 { 30 | font-size: 2rem; 31 | color: white; 32 | text-align: center; 33 | } 34 | 35 | /*create slider */ 36 | #slider { 37 | position: relative; 38 | height: 300px; 39 | padding: 0; 40 | margin: 0; 41 | margin-top: 30px; 42 | margin-bottom: 30px; 43 | } 44 | 45 | .slide { 46 | /* we position the slide absolutely compared to its parent #slider */ 47 | position: absolute; 48 | left: 0px; 49 | top: 0px; 50 | width: 100%; 51 | height: 100%; 52 | opacity: 0; 53 | z-index: 1; 54 | /* change the value for a faster or slower transition between slides */ 55 | -webkit-transition: opacity 0.5s; 56 | -o-transition: opacity 0.5s; 57 | transition: opacity 0.5s; 58 | } 59 | 60 | /* class to show the current slide */ 61 | .showing { 62 | opacity: 1; 63 | z-index: 2; 64 | } 65 | 66 | .slide-text { 67 | background-color: white; 68 | border-radius: 10px; 69 | margin: auto; 70 | padding: 40px; 71 | padding-left: 60px; 72 | position: relative; 73 | } 74 | 75 | /* create the notch */ 76 | .slide-text:after { 77 | content: ''; 78 | display: block; 79 | position: absolute; 80 | bottom: -20px; 81 | left: calc(50%); 82 | -webkit-transform: translateX(-50%); 83 | -ms-transform: translateX(-50%); 84 | transform: translateX(-50%); 85 | width: 0; 86 | height: 0; 87 | border-style: solid; 88 | border-width: 20px 26px 0 0; 89 | border-color: white transparent transparent transparent; 90 | } 91 | 92 | /* align the testimonial in the center */ 93 | .slide-testimonial { 94 | margin-top: 20px; 95 | display: -webkit-box; 96 | display: -ms-flexbox; 97 | display: flex; 98 | -webkit-box-pack: center; 99 | -ms-flex-pack: center; 100 | justify-content: center; 101 | -webkit-box-align: center; 102 | -ms-flex-align: center; 103 | align-items: center; 104 | } 105 | 106 | .slide-img { 107 | margin: 10px; 108 | } 109 | 110 | .slide-img img { 111 | width: 100px; 112 | height: 100px; 113 | border-radius: 50%; 114 | border: 4px solid white; 115 | } 116 | 117 | .slide-person { 118 | margin-left: 20px; 119 | } 120 | 121 | .slide-person p { 122 | padding: 5px; 123 | } 124 | 125 | /* make the name of the person bold */ 126 | .slide-person p:first-of-type { 127 | color: white; 128 | font-weight: bold; 129 | font-size: 1.2rem; 130 | } 131 | 132 | /* make their job title light gray */ 133 | .slide-person p:last-of-type { 134 | color: var(--color-light-gray); 135 | } 136 | 137 | /* position the buttons and make them green */ 138 | .slider-button { 139 | cursor: pointer; 140 | color: white; 141 | font-weight: bold; 142 | width: 40px; 143 | height: 40px; 144 | background-color: var(--color-highlight-green); 145 | z-index: 3; 146 | position: absolute; 147 | text-align: center; 148 | border-radius: 20%; 149 | -webkit-box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); 150 | box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); 151 | display: -webkit-box; 152 | display: -ms-flexbox; 153 | display: flex; 154 | -webkit-box-pack: center; 155 | -ms-flex-pack: center; 156 | justify-content: center; 157 | -webkit-box-align: center; 158 | -ms-flex-align: center; 159 | align-items: center; 160 | } 161 | 162 | /*posion the left an right button horizontally */ 163 | .button-left { 164 | position: absolute; 165 | left: -10px; 166 | } 167 | 168 | .button-right { 169 | position: absolute; 170 | right: -10px; 171 | } -------------------------------------------------------------------------------- /pomodoro-clock/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | FCC_pomodoro_clock 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
    20 |
    21 |
    22 |
    23 | 24 |
    25 |
    26 | 30 | 33 |
    34 |
    35 | 36 | Changes made here will reflect at the start of the next work / 37 | break session 38 | 39 |
    40 |
    41 |
    42 | 43 | 44 |
    45 |
    46 | 47 | 48 |
    49 |
    50 |
    51 |

    Your Sessions

    52 |
      53 |
    54 |
    55 |
    56 |
    57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /pomodoro-clock/progressBar.js: -------------------------------------------------------------------------------- 1 | !function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.ProgressBar=a()}}(function(){var a;return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g=v,y=d-(v-w),a.isPlaying()&&(x?(j(g,a._attachment,y),a.stop(!0)):(a._scheduleId=l(a._timeoutHandler,s),k(a,"beforeTween"),w=0?a:0-a}function m(a,b){var c,d,e,f,h,j;for(e=a,j=0;j<8;j++){if(f=g(e)-a,l(f)d)return d;for(;cf?c=e:d=e,e=.5*(d-c)+c}return e}var n=0,o=0,p=0,q=0,r=0,s=0;return p=3*b,o=3*(d-b)-p,n=1-p-o,s=3*c,r=3*(e-c)-s,q=1-s-r,k(a,j(f))}function b(b,c,d,e){return function(f){return a(f,b,c,d,e,1)}}e.setBezierFunction=function(a,c,d,f,g){var h=b(c,d,f,g);return h.displayName=a,h.x1=c,h.y1=d,h.x2=f,h.y2=g,e.prototype.formula[a]=h},e.unsetBezierFunction=function(a){delete e.prototype.formula[a]}}(),function(){function a(a,b,c,d,f,g){return e.tweenProps(d,b,a,c,1,g,f)}var b=new e;b._filterArgs=[],e.interpolate=function(c,d,f,g,h){var i=e.shallowCopy({},c),j=h||0,k=e.composeEasingObject(c,g||"linear");b.set({});var l=b._filterArgs;l.length=0,l[0]=i,l[1]=c,l[2]=d,l[3]=k,e.applyFilter(b,"tweenCreated"),e.applyFilter(b,"beforeTween");var m=a(c,i,d,f,k,j);return e.applyFilter(b,"afterTween"),m}}(),function(a){function b(a,b){var c,d=[],e=a.length;for(c=0;ca.strokeWidth&&(b=a.trailWidth);var c=50-b/2;return e.render(this._pathTemplate,{radius:c,"2radius":2*c})},f.prototype._trailString=function(a){return this._pathString(a)},b.exports=f},{"./shape":7,"./utils":9}],3:[function(a,b,c){var d=a("./shape"),e=a("./utils"),f=function(a,b){this._pathTemplate="M 0,{center} L 100,{center}",d.apply(this,arguments)};f.prototype=new d,f.prototype.constructor=f,f.prototype._initializeSvg=function(a,b){a.setAttribute("viewBox","0 0 100 "+b.strokeWidth),a.setAttribute("preserveAspectRatio","none")},f.prototype._pathString=function(a){return e.render(this._pathTemplate,{center:a.strokeWidth/2})},f.prototype._trailString=function(a){return this._pathString(a)},b.exports=f},{"./shape":7,"./utils":9}],4:[function(a,b,c){b.exports={Line:a("./line"),Circle:a("./circle"),SemiCircle:a("./semicircle"),Square:a("./square"),Path:a("./path"),Shape:a("./shape"),utils:a("./utils")}},{"./circle":2,"./line":3,"./path":5,"./semicircle":6,"./shape":7,"./square":8,"./utils":9}],5:[function(a,b,c){var d=a("shifty"),e=a("./utils"),f={easeIn:"easeInCubic",easeOut:"easeOutCubic",easeInOut:"easeInOutCubic"},g=function a(b,c){if(!(this instanceof a))throw new Error("Constructor was called without new keyword");c=e.extend({duration:800,easing:"linear",from:{},to:{},step:function(){}},c);var d;d=e.isString(b)?document.querySelector(b):b,this.path=d,this._opts=c,this._tweenable=null;var f=this.path.getTotalLength();this.path.style.strokeDasharray=f+" "+f,this.set(0)};g.prototype.value=function(){var a=this._getComputedDashOffset(),b=this.path.getTotalLength(),c=1-a/b;return parseFloat(c.toFixed(6),10)},g.prototype.set=function(a){this.stop(),this.path.style.strokeDashoffset=this._progressToOffset(a);var b=this._opts.step;if(e.isFunction(b)){var c=this._easing(this._opts.easing),d=this._calculateTo(a,c),f=this._opts.shape||this;b(d,f,this._opts.attachment)}},g.prototype.stop=function(){this._stopTween(),this.path.style.strokeDashoffset=this._getComputedDashOffset()},g.prototype.animate=function(a,b,c){b=b||{},e.isFunction(b)&&(c=b,b={});var f=e.extend({},b),g=e.extend({},this._opts);b=e.extend(g,b);var h=this._easing(b.easing),i=this._resolveFromAndTo(a,h,f);this.stop(),this.path.getBoundingClientRect();var j=this._getComputedDashOffset(),k=this._progressToOffset(a),l=this;this._tweenable=new d,this._tweenable.tween({from:e.extend({offset:j},i.from),to:e.extend({offset:k},i.to),duration:b.duration,easing:h,step:function(a){l.path.style.strokeDashoffset=a.offset;var c=b.shape||l;b.step(a,c,b.attachment)},finish:function(a){e.isFunction(c)&&c()}})},g.prototype._getComputedDashOffset=function(){var a=window.getComputedStyle(this.path,null);return parseFloat(a.getPropertyValue("stroke-dashoffset"),10)},g.prototype._progressToOffset=function(a){var b=this.path.getTotalLength();return b-a*b},g.prototype._resolveFromAndTo=function(a,b,c){return c.from&&c.to?{from:c.from,to:c.to}:{from:this._calculateFrom(b),to:this._calculateTo(a,b)}},g.prototype._calculateFrom=function(a){return d.interpolate(this._opts.from,this._opts.to,this.value(),a)},g.prototype._calculateTo=function(a,b){return d.interpolate(this._opts.from,this._opts.to,a,b)},g.prototype._stopTween=function(){null!==this._tweenable&&(this._tweenable.stop(),this._tweenable=null)},g.prototype._easing=function(a){return f.hasOwnProperty(a)?f[a]:a},b.exports=g},{"./utils":9,shifty:1}],6:[function(a,b,c){var d=a("./shape"),e=a("./circle"),f=a("./utils"),g=function(a,b){this._pathTemplate="M 50,50 m -{radius},0 a {radius},{radius} 0 1 1 {2radius},0",this.containerAspectRatio=2,d.apply(this,arguments)};g.prototype=new d,g.prototype.constructor=g,g.prototype._initializeSvg=function(a,b){a.setAttribute("viewBox","0 0 100 50")},g.prototype._initializeTextContainer=function(a,b,c){a.text.style&&(c.style.top="auto",c.style.bottom="0",a.text.alignToBottom?f.setStyle(c,"transform","translate(-50%, 0)"):f.setStyle(c,"transform","translate(-50%, 50%)"))},g.prototype._pathString=e.prototype._pathString,g.prototype._trailString=e.prototype._trailString,b.exports=g},{"./circle":2,"./shape":7,"./utils":9}],7:[function(a,b,c){var d=a("./path"),e=a("./utils"),f="Object is destroyed",g=function a(b,c){if(!(this instanceof a))throw new Error("Constructor was called without new keyword");if(0!==arguments.length){this._opts=e.extend({color:"#555",strokeWidth:1,trailColor:null,trailWidth:null,fill:null,text:{style:{color:null,position:"absolute",left:"50%",top:"50%",padding:0,margin:0,transform:{prefix:!0,value:"translate(-50%, -50%)"}},autoStyleContainer:!0,alignToBottom:!0,value:null,className:"progressbar-text"},svgStyle:{display:"block",width:"100%"},warnings:!1},c,!0),e.isObject(c)&&void 0!==c.svgStyle&&(this._opts.svgStyle=c.svgStyle),e.isObject(c)&&e.isObject(c.text)&&void 0!==c.text.style&&(this._opts.text.style=c.text.style);var f,g=this._createSvgView(this._opts);if(f=e.isString(b)?document.querySelector(b):b,!f)throw new Error("Container does not exist: "+b);this._container=f,this._container.appendChild(g.svg),this._opts.warnings&&this._warnContainerAspectRatio(this._container),this._opts.svgStyle&&e.setStyles(g.svg,this._opts.svgStyle),this.svg=g.svg,this.path=g.path,this.trail=g.trail,this.text=null;var h=e.extend({attachment:void 0,shape:this},this._opts);this._progressPath=new d(g.path,h),e.isObject(this._opts.text)&&null!==this._opts.text.value&&this.setText(this._opts.text.value)}};g.prototype.animate=function(a,b,c){if(null===this._progressPath)throw new Error(f);this._progressPath.animate(a,b,c)},g.prototype.stop=function(){if(null===this._progressPath)throw new Error(f);void 0!==this._progressPath&&this._progressPath.stop()},g.prototype.destroy=function(){if(null===this._progressPath)throw new Error(f);this.stop(),this.svg.parentNode.removeChild(this.svg),this.svg=null,this.path=null,this.trail=null,this._progressPath=null,null!==this.text&&(this.text.parentNode.removeChild(this.text),this.text=null)},g.prototype.set=function(a){if(null===this._progressPath)throw new Error(f);this._progressPath.set(a)},g.prototype.value=function(){if(null===this._progressPath)throw new Error(f);return void 0===this._progressPath?0:this._progressPath.value()},g.prototype.setText=function(a){if(null===this._progressPath)throw new Error(f);null===this.text&&(this.text=this._createTextContainer(this._opts,this._container),this._container.appendChild(this.text)),e.isObject(a)?(e.removeChildren(this.text),this.text.appendChild(a)):this.text.innerHTML=a},g.prototype._createSvgView=function(a){var b=document.createElementNS("http://www.w3.org/2000/svg","svg");this._initializeSvg(b,a);var c=null;(a.trailColor||a.trailWidth)&&(c=this._createTrail(a),b.appendChild(c));var d=this._createPath(a);return b.appendChild(d),{svg:b,path:d,trail:c}},g.prototype._initializeSvg=function(a,b){a.setAttribute("viewBox","0 0 100 100")},g.prototype._createPath=function(a){var b=this._pathString(a);return this._createPathElement(b,a)},g.prototype._createTrail=function(a){var b=this._trailString(a),c=e.extend({},a);return c.trailColor||(c.trailColor="#eee"),c.trailWidth||(c.trailWidth=c.strokeWidth),c.color=c.trailColor,c.strokeWidth=c.trailWidth,c.fill=null,this._createPathElement(b,c)},g.prototype._createPathElement=function(a,b){var c=document.createElementNS("http://www.w3.org/2000/svg","path");return c.setAttribute("d",a),c.setAttribute("stroke",b.color),c.setAttribute("stroke-width",b.strokeWidth),b.fill?c.setAttribute("fill",b.fill):c.setAttribute("fill-opacity","0"),c},g.prototype._createTextContainer=function(a,b){var c=document.createElement("div");c.className=a.text.className;var d=a.text.style;return d&&(a.text.autoStyleContainer&&(b.style.position="relative"),e.setStyles(c,d),d.color||(c.style.color=a.color)),this._initializeTextContainer(a,b,c),c},g.prototype._initializeTextContainer=function(a,b,c){},g.prototype._pathString=function(a){throw new Error("Override this function for each progress bar")},g.prototype._trailString=function(a){throw new Error("Override this function for each progress bar")},g.prototype._warnContainerAspectRatio=function(a){if(this.containerAspectRatio){var b=window.getComputedStyle(a,null),c=parseFloat(b.getPropertyValue("width"),10),d=parseFloat(b.getPropertyValue("height"),10);e.floatEquals(this.containerAspectRatio,c/d)||(console.warn("Incorrect aspect ratio of container","#"+a.id,"detected:",b.getPropertyValue("width")+"(width)","/",b.getPropertyValue("height")+"(height)","=",c/d),console.warn("Aspect ratio of should be",this.containerAspectRatio))}},b.exports=g},{"./path":5,"./utils":9}],8:[function(a,b,c){var d=a("./shape"),e=a("./utils"),f=function(a,b){this._pathTemplate="M 0,{halfOfStrokeWidth} L {width},{halfOfStrokeWidth} L {width},{width} L {halfOfStrokeWidth},{width} L {halfOfStrokeWidth},{strokeWidth}",this._trailTemplate="M {startMargin},{halfOfStrokeWidth} L {width},{halfOfStrokeWidth} L {width},{width} L {halfOfStrokeWidth},{width} L {halfOfStrokeWidth},{halfOfStrokeWidth}",d.apply(this,arguments)};f.prototype=new d,f.prototype.constructor=f,f.prototype._pathString=function(a){var b=100-a.strokeWidth/2;return e.render(this._pathTemplate,{width:b,strokeWidth:a.strokeWidth,halfOfStrokeWidth:a.strokeWidth/2})},f.prototype._trailString=function(a){var b=100-a.strokeWidth/2;return e.render(this._trailTemplate,{width:b,strokeWidth:a.strokeWidth,halfOfStrokeWidth:a.strokeWidth/2,startMargin:a.strokeWidth/2-a.trailWidth/2})},b.exports=f},{"./shape":7,"./utils":9}],9:[function(a,b,c){function d(a,b,c){a=a||{},b=b||{},c=c||!1;for(var e in b)if(b.hasOwnProperty(e)){var f=a[e],g=b[e];c&&l(f)&&l(g)?a[e]=d(f,g,c):a[e]=g}return a}function e(a,b){var c=a;for(var d in b)if(b.hasOwnProperty(d)){var e=b[d],f="\\{"+d+"\\}",g=new RegExp(f,"g");c=c.replace(g,e)}return c}function f(a,b,c){for(var d=a.style,e=0;e { 2 | 3 | const startButton = document.querySelector("#pomodoro-start"); 4 | const stopButton = document.querySelector("#pomodoro-stop"); 5 | 6 | let isClockRunning = false; 7 | // in seconds = 25 mins 8 | let workSessionDuration = 1500; 9 | let currentTimeLeftInSession = 1500; 10 | 11 | // in seconds = 5 mins; 12 | let breakSessionDuration = 300; 13 | 14 | let timeSpentInCurrentSession = 0; 15 | let type = "Work"; 16 | 17 | let currentTaskLabel = document.querySelector("#pomodoro-clock-task"); 18 | 19 | let updatedWorkSessionDuration; 20 | let updatedBreakSessionDuration; 21 | 22 | let workDurationInput = document.querySelector("#input-work-duration"); 23 | let breakDurationInput = document.querySelector("#input-break-duration"); 24 | 25 | workDurationInput.value = "25"; 26 | breakDurationInput.value = "5"; 27 | 28 | let isClockStopped = true; 29 | 30 | const progressBar = new ProgressBar.Circle("#pomodoro-timer", { 31 | strokeWidth: 2, 32 | text: { 33 | value: "25:00" 34 | }, 35 | trailColor: "#f4f4f4", 36 | }); 37 | 38 | // START 39 | startButton.addEventListener("click", () => { 40 | toggleClock(); 41 | }); 42 | 43 | // STOP 44 | stopButton.addEventListener("click", () => { 45 | toggleClock(true); 46 | }); 47 | 48 | // UPDATE WORK TIME 49 | workDurationInput.addEventListener("input", () => { 50 | updatedWorkSessionDuration = minuteToSeconds(workDurationInput.value); 51 | }); 52 | 53 | // UPDATE PAUSE TIME 54 | breakDurationInput.addEventListener("input", () => { 55 | updatedBreakSessionDuration = minuteToSeconds(breakDurationInput.value); 56 | }); 57 | 58 | const minuteToSeconds = mins => { 59 | return mins * 60; 60 | }; 61 | 62 | const toggleClock = reset => { 63 | togglePlayPauseIcon(reset); 64 | if (reset) { 65 | stopClock(); 66 | } else { 67 | if (isClockStopped) { 68 | setUpdatedTimers(); 69 | isClockStopped = false; 70 | } 71 | 72 | if (isClockRunning === true) { 73 | // pause 74 | clearInterval(clockTimer); 75 | // update icon to the play one 76 | // set the vale of the button to start or pause 77 | isClockRunning = false; 78 | } else { 79 | // start 80 | clockTimer = setInterval(() => { 81 | stepDown(); 82 | displayCurrentTimeLeftInSession(); 83 | progressBar.set(calculateSessionProgress()); 84 | }, 1000); 85 | isClockRunning = true; 86 | } 87 | showStopIcon(); 88 | } 89 | }; 90 | 91 | const displayCurrentTimeLeftInSession = () => { 92 | const secondsLeft = currentTimeLeftInSession; 93 | let result = ""; 94 | const seconds = secondsLeft % 60; 95 | const minutes = parseInt(secondsLeft / 60) % 60; 96 | let hours = parseInt(secondsLeft / 3600); 97 | // add leading zeroes if it's less than 10 98 | function addLeadingZeroes(time) { 99 | return time < 10 ? `0${time}` : time; 100 | } 101 | if (hours > 0) result += `${hours}:`; 102 | result += `${addLeadingZeroes(minutes)}:${addLeadingZeroes(seconds)}`; 103 | progressBar.text.innerText = result.toString(); 104 | }; 105 | 106 | const stopClock = () => { 107 | setUpdatedTimers(); 108 | displaySessionLog(type); 109 | clearInterval(clockTimer); 110 | isClockStopped = true; 111 | isClockRunning = false; 112 | currentTimeLeftInSession = workSessionDuration; 113 | displayCurrentTimeLeftInSession(); 114 | type = "Work"; 115 | timeSpentInCurrentSession = 0; 116 | }; 117 | 118 | const stepDown = () => { 119 | if (currentTimeLeftInSession > 0) { 120 | // decrease time left / increase time spent 121 | currentTimeLeftInSession--; 122 | timeSpentInCurrentSession++; 123 | } else if (currentTimeLeftInSession === 0) { 124 | timeSpentInCurrentSession = 0; 125 | // Timer is over -> if work switch to break, viceversa 126 | if (type === "Work") { 127 | currentTimeLeftInSession = breakSessionDuration; 128 | displaySessionLog("Work"); 129 | type = "Break"; 130 | setUpdatedTimers(); 131 | // new 132 | currentTaskLabel.value = "Break"; 133 | currentTaskLabel.disabled = true; 134 | } else { 135 | currentTimeLeftInSession = workSessionDuration; 136 | type = "Work"; 137 | setUpdatedTimers(); 138 | // new 139 | if (currentTaskLabel.value === "Break") { 140 | currentTaskLabel.value = workSessionLabel; 141 | } 142 | currentTaskLabel.disabled = false; 143 | displaySessionLog("Break"); 144 | } 145 | } 146 | displayCurrentTimeLeftInSession(); 147 | }; 148 | 149 | const displaySessionLog = type => { 150 | const sessionsList = document.querySelector("#pomodoro-sessions"); 151 | // append li to it 152 | const li = document.createElement("li"); 153 | if (type === "Work") { 154 | sessionLabel = currentTaskLabel.value ? currentTaskLabel.value : "Work"; 155 | workSessionLabel = sessionLabel; 156 | } else { 157 | sessionLabel = "Break"; 158 | } 159 | let elapsedTime = parseInt(timeSpentInCurrentSession / 60); 160 | elapsedTime = elapsedTime > 0 ? elapsedTime : "< 1"; 161 | 162 | const text = document.createTextNode( 163 | `${sessionLabel} : ${elapsedTime} min` 164 | ); 165 | li.appendChild(text); 166 | sessionsList.appendChild(li); 167 | }; 168 | 169 | const setUpdatedTimers = () => { 170 | if (type === "Work") { 171 | currentTimeLeftInSession = updatedWorkSessionDuration 172 | ? updatedWorkSessionDuration 173 | : workSessionDuration; 174 | workSessionDuration = currentTimeLeftInSession; 175 | } else { 176 | currentTimeLeftInSession = updatedBreakSessionDuration 177 | ? updatedBreakSessionDuration 178 | : breakSessionDuration; 179 | breakSessionDuration = currentTimeLeftInSession; 180 | } 181 | }; 182 | 183 | const togglePlayPauseIcon = reset => { 184 | const playIcon = document.querySelector("#play-icon"); 185 | const pauseIcon = document.querySelector("#pause-icon"); 186 | if (reset) { 187 | // when resetting -> always revert to play icon 188 | if (playIcon.classList.contains("hidden")) { 189 | playIcon.classList.remove("hidden"); 190 | } 191 | if (!pauseIcon.classList.contains("hidden")) { 192 | pauseIcon.classList.add("hidden"); 193 | } 194 | } else { 195 | playIcon.classList.toggle("hidden"); 196 | pauseIcon.classList.toggle("hidden"); 197 | } 198 | }; 199 | 200 | const showStopIcon = () => { 201 | const stopButton = document.querySelector("#pomodoro-stop"); 202 | stopButton.classList.remove("hidden"); 203 | }; 204 | 205 | const calculateSessionProgress = () => { 206 | // calculate the completion rate of this session 207 | const sessionDuration = 208 | type === "Work" ? workSessionDuration : breakSessionDuration; 209 | return (timeSpentInCurrentSession / sessionDuration) * 10; 210 | }; 211 | 212 | }); 213 | -------------------------------------------------------------------------------- /pomodoro-clock/style.css: -------------------------------------------------------------------------------- 1 | #pomodoro-page { 2 | background-color: red; 3 | } 4 | 5 | #pomodoro-container { 6 | display: flex; 7 | flex-direction: column; 8 | width: 100%; 9 | justify-content: center; 10 | align-items: center; 11 | } 12 | 13 | #pomodoro-clock { 14 | display: flex; 15 | flex-direction: column; 16 | justify-content: center; 17 | align-items: center; 18 | margin-bottom: 40px; 19 | } 20 | 21 | #pomodoro-clock-circle { 22 | display: flex; 23 | flex-direction: column; 24 | justify-content: center; 25 | align-items: center; 26 | border-radius: 50%; 27 | height: 300px; 28 | width: 300px; 29 | border: 5px solid lightgrey; 30 | } 31 | 32 | #pomodoro-clock-timer { 33 | font-size: 3rem; 34 | } 35 | 36 | #pomodoro-clock-circle * { 37 | color: black; 38 | } 39 | 40 | #pomodoro-clock-task { 41 | display: inline-block; 42 | margin-top: 10px; 43 | width: 200px; 44 | padding: 5px 10px; 45 | border: 1px solid lightgrey; 46 | border-radius: 3px 47 | } 48 | 49 | #pomodoro-clock-title { 50 | margin-top: 20px; 51 | width: 200px 52 | } 53 | 54 | #pomodoro-clock-actions { 55 | margin-top: 20px; 56 | display: flex; 57 | flex-direction: row; 58 | justify-content: space-around; 59 | width: 100px; 60 | } 61 | 62 | #pomodoro-clock-actions button { 63 | height: 40px; 64 | width: 40px; 65 | border-radius: 50%; 66 | } 67 | 68 | .hidden { 69 | display: none; 70 | } 71 | 72 | 73 | .pomodoro-input { 74 | display: flex; 75 | flex-direction: column; 76 | width: 100px; 77 | margin-right: 10px; 78 | } 79 | 80 | .pomodoro-input input { 81 | border: 1px solid lightgrey; 82 | border-radius: 3px; 83 | padding: 5px; 84 | } -------------------------------------------------------------------------------- /random_quote_machine/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | FCC_RandomQuoteMachine 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
    21 |
    22 | 23 | 24 |
    25 | 26 |
    27 | 28 |
    29 | 31 | 32 |
    33 | 34 |
    35 | 36 | by Alberto Montalesi 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /random_quote_machine/index.js: -------------------------------------------------------------------------------- 1 | // DOES NOT WORK WITH HTTPS// 2 | // FOR A NON JQUERY VERSION CHECK OUT THE ARTICLE AT: https://inspiredwebdev.com/tutorial/create-random-quote-machine 3 | 4 | $(document).ready(function() { 5 | getQuote(); /*to already have a quote when i load the page*/ 6 | colorRandomizer(); //to create a random color as soon as i load 7 | function getQuote() { 8 | var url = 9 | "https://api.forismatic.com/api/1.0/?method=getQuote&lang=en&format=jsonp&jsonp=?"; 10 | 11 | $.getJSON(url, function(data) { 12 | //store the quote and the author in var 13 | var currentQuote = data.quoteText; 14 | var currentAuthor = data.quoteAuthor; 15 | //add them to my html 16 | $("#quoteText").html(currentQuote); 17 | $("#author").html("- " + currentAuthor); 18 | 19 | //prepopulate my twitter 20 | $("#twitter").attr( 21 | "href", 22 | "https://twitter.com/intent/tweet?hashtags=quotes,Fcc&related=freecodecamp&text=" + 23 | encodeURIComponent('"' + currentQuote + '" ' + currentAuthor) 24 | ); 25 | }); /*end get json*/ 26 | } /*get quote end */ 27 | 28 | $("#new-quote").on("click", function() { 29 | //run my color randomizer and my get quote 30 | colorRandomizer(); 31 | getQuote(); /* to generate a quote */ 32 | }); 33 | 34 | function colorRandomizer() { 35 | var myColors = ["#3498db", "#2ecc71", "#9b59b6", "#e74c3c", "#f1c40f"]; //array of colors 36 | var randomNum = Math.floor(Math.random() * myColors.length); //generate random number 37 | 38 | var randomColor = myColors[randomNum]; //store my random color 39 | //modify bg and txt color with my random color 40 | $(".randomBgColor").css("background-color", randomColor); 41 | $(".randomTxtColor").css("color", randomColor); 42 | } 43 | }); /* end jquery*/ 44 | -------------------------------------------------------------------------------- /random_quote_machine/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Lato:400,700'); 2 | 3 | body { 4 | font-family: 'Lato', sans-serif; 5 | background-color: #3498db; 6 | 7 | } 8 | 9 | * { 10 | margin: 0; 11 | padding: 0; 12 | } 13 | 14 | .randomBgColor { 15 | transition: background-color 1s ease; 16 | 17 | } 18 | 19 | .randomTxtColor { 20 | transition: color 1s ease; 21 | } 22 | 23 | #quote-box { 24 | width: 400px; 25 | min-height: 200px; 26 | height: auto; 27 | margin: 10% auto 0 auto; 28 | background-color: white; 29 | padding: 10px; 30 | border-radius: 5%; 31 | } 32 | 33 | #text { 34 | padding: 25px; 35 | 36 | } 37 | 38 | .fa-quote-left { 39 | font-size: 55px; 40 | padding-right: 15px; 41 | display: inline-block; 42 | width: auto; 43 | } 44 | 45 | #quoteText { 46 | font-size: 25px; 47 | text-align: center; 48 | width: 70%; 49 | 50 | } 51 | 52 | #author { 53 | font-size: 16px; 54 | text-align: right; 55 | display: block; 56 | width: 100%; 57 | } 58 | 59 | #buttonBox { 60 | height: 50px; 61 | padding: 15px; 62 | display: flex; 63 | flex-direction: row; 64 | justify-content: space-between; 65 | align-content: center; 66 | } 67 | 68 | .fa-twitter { 69 | font-size: 40px; 70 | padding: 5px 5px 0 5px; 71 | color: white; 72 | 73 | } 74 | 75 | #new-quote { 76 | padding: 0 10px; 77 | cursor: pointer; 78 | color: white; 79 | font-weight: bold; 80 | 81 | } 82 | 83 | #new-quote:hover { 84 | opacity: 0.5; 85 | } 86 | 87 | .fa-twitter, 88 | #new-quote { 89 | border-radius: 20%; 90 | border: none; 91 | } 92 | 93 | #credit { 94 | display: block; 95 | margin: 0 auto; 96 | width: 150px; 97 | height: 15px; 98 | color: white; 99 | } 100 | 101 | #credit a, 102 | #credit a:hover { 103 | color: inherit; 104 | text-decoration: none; 105 | } 106 | -------------------------------------------------------------------------------- /screenshots/html_login_form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDev-Tutorials/6631a9df08a73f1cdcd8be111eb27852d30ce84b/screenshots/html_login_form.png -------------------------------------------------------------------------------- /screenshots/javascript_carousel.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDev-Tutorials/6631a9df08a73f1cdcd8be111eb27852d30ce84b/screenshots/javascript_carousel.gif -------------------------------------------------------------------------------- /screenshots/javascript_pomodoro_clock.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDev-Tutorials/6631a9df08a73f1cdcd8be111eb27852d30ce84b/screenshots/javascript_pomodoro_clock.gif -------------------------------------------------------------------------------- /screenshots/javascript_random_quote_machine.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDev-Tutorials/6631a9df08a73f1cdcd8be111eb27852d30ce84b/screenshots/javascript_random_quote_machine.gif -------------------------------------------------------------------------------- /screenshots/javascript_smooth_scroll_navigation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDev-Tutorials/6631a9df08a73f1cdcd8be111eb27852d30ce84b/screenshots/javascript_smooth_scroll_navigation.gif -------------------------------------------------------------------------------- /screenshots/javascript_todo_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDev-Tutorials/6631a9df08a73f1cdcd8be111eb27852d30ce84b/screenshots/javascript_todo_list.png -------------------------------------------------------------------------------- /screenshots/sticky_table_of_content_inspiredwebdev.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDev-Tutorials/6631a9df08a73f1cdcd8be111eb27852d30ce84b/screenshots/sticky_table_of_content_inspiredwebdev.gif -------------------------------------------------------------------------------- /smooth_scroll/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Smooth Scroll 9 | 10 | 11 | 12 | 13 | 14 | 15 | 26 | 27 |
    28 |
    Section 1
    29 |
    Section 2
    30 |
    Section 3
    31 |
    32 | 33 | 34 | -------------------------------------------------------------------------------- /smooth_scroll/script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", () => { 2 | // little hack to detect if the user is on ie 11 3 | const isIE11 = !!window.MSInputMethodContext && !!document.documentMode; 4 | // get all the links with an ID that starts with 'sectionLink' 5 | const listOfLinks = document.querySelectorAll("a[href^='#sectionLink"); 6 | // loop over all the links 7 | listOfLinks.forEach(function (link) { 8 | // listen for a click 9 | link.addEventListener('click', () => { 10 | // toggle highlight on and off when we click a link 11 | listOfLinks.forEach( (link) => { 12 | if (link.classList.contains('highlighted')) { 13 | link.classList.remove('highlighted'); 14 | } 15 | }); 16 | link.classList.add('highlighted'); 17 | // get the element where to scroll 18 | let ref = link.href.split('#sectionLink'); 19 | ref = "#section" + ref[1]; 20 | // ie 11 does not support smooth scroll, so we will simply scroll 21 | if (isIE11) { 22 | window.scrollTo(0, document.querySelector(ref).offsetTop); 23 | } else { 24 | window.scroll({ 25 | behavior: 'smooth', 26 | left: 0, 27 | // top gets the distance from the top of the page of our target element 28 | top: document.querySelector(ref).offsetTop 29 | }); 30 | } 31 | }) 32 | }) 33 | }) -------------------------------------------------------------------------------- /smooth_scroll/style.css: -------------------------------------------------------------------------------- 1 | /* basic styling to make the links bigger */ 2 | #navigation { 3 | display: flex; 4 | /* make the navbar alway stay on top */ 5 | position: fixed; 6 | top: 0; 7 | width: 100%; 8 | background-color: white; 9 | } 10 | 11 | #navigation span { 12 | flex-grow: 1; 13 | height: 50px; 14 | border: 1px solid black; 15 | display: flex; 16 | justify-content: center; 17 | align-items: center; 18 | } 19 | 20 | #navigation span a { 21 | display: inline-block; 22 | } 23 | 24 | /* when a link is clicked, it gets highlighted */ 25 | .highlighted { 26 | color: red; 27 | } 28 | 29 | /* make each section taller and give them different colors */ 30 | #content { 31 | margin-top: 50px; 32 | } 33 | 34 | #content div { 35 | height: 100vh; 36 | /* align the text in the middle */ 37 | display: flex; 38 | justify-content: center; 39 | align-items: center; 40 | font-size: 3rem; 41 | font-weight: bold; 42 | } 43 | 44 | #section1 { 45 | background-color: lightcoral; 46 | } 47 | 48 | #section2 { 49 | background-color: lightblue; 50 | } 51 | 52 | #section3 { 53 | background-color: lightgreen; 54 | } --------------------------------------------------------------------------------