├── .eslintrc.json ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── azure-pipelines.yml ├── gatsby-config.js ├── gatsby-node.js ├── lessons ├── ajax.md ├── calculator-setup.md ├── calculator.md ├── css.md ├── dogs.md ├── dom.md ├── final-project.txt ├── forms.md ├── functions-and-scope.md ├── github.md ├── html.md ├── images │ ├── FrontendMastersLogo.png │ ├── GitHub-1.png │ ├── GitHub-2.png │ ├── GitHub-3.png │ ├── GitHub-4.png │ ├── GitHub-5.png │ ├── GitHub-6.png │ ├── borderbox2.png │ ├── brian.jpg │ ├── contentbox1.png │ ├── css-boxmodel.png │ ├── css-shorthand.png │ ├── jen.jpg │ ├── logo.svg │ ├── vscode-enabled.jpg │ ├── vscode-icon.jpg │ ├── vscode-open-in-browser.jpg │ └── vscode-reload.jpg ├── interactive.md ├── intro-to-programming.md ├── intro.md ├── layout.md ├── mole.md ├── objects-and-arrays.md ├── quiz.md ├── setup.md └── tests.md ├── package-lock.json ├── package.json ├── src ├── components │ ├── TOCCard.css │ └── TOCCard.js ├── layouts │ ├── index.css │ └── index.js ├── pages │ ├── 404.js │ ├── index.css │ └── index.js └── templates │ └── lessonTemplate.js ├── static ├── calculator.css ├── calculator.html ├── calculator.js ├── dog-viewer │ ├── dog.css │ ├── dog.html │ └── dog.js ├── doggos │ ├── doggos.html │ └── doggos.js ├── exercises │ ├── 1-html │ │ ├── book excerpt.txt │ │ ├── book.html │ │ ├── hobbies.html │ │ ├── images │ │ │ └── blog1.jpg │ │ └── index.html │ ├── 2-css │ │ ├── begin │ │ │ └── learningcss.html │ │ ├── images │ │ │ ├── Logo.png │ │ │ ├── blog1.jpg │ │ │ ├── blog2.jpg │ │ │ └── blog3.jpg │ │ └── in-class │ │ │ ├── css │ │ │ └── style.css │ │ │ └── learningcss.html │ ├── 3-layout.zip │ ├── 3-layout │ │ ├── blog-begin │ │ │ ├── blog.html │ │ │ ├── css │ │ │ │ └── styles.css │ │ │ └── img │ │ │ │ ├── blog1.png │ │ │ │ ├── blog2.png │ │ │ │ ├── blog3.png │ │ │ │ ├── icon1.png │ │ │ │ ├── icon2.png │ │ │ │ ├── icon3.png │ │ │ │ ├── icon4.png │ │ │ │ ├── icon5.png │ │ │ │ ├── icon6.png │ │ │ │ ├── icon7.png │ │ │ │ └── logo.png │ │ ├── blog-end │ │ │ ├── blog.html │ │ │ ├── css │ │ │ │ └── styles.css │ │ │ └── img │ │ │ │ ├── blog1.png │ │ │ │ ├── blog2.png │ │ │ │ ├── blog3.png │ │ │ │ ├── icon1.png │ │ │ │ ├── icon2.png │ │ │ │ ├── icon3.png │ │ │ │ ├── icon4.png │ │ │ │ ├── icon5.png │ │ │ │ ├── icon6.png │ │ │ │ ├── icon7.png │ │ │ │ └── logo.png │ │ ├── blog.png │ │ └── boxmodel │ │ │ ├── Box Model Worksheet answers.docx │ │ │ ├── Box Model Worksheet answers.pdf │ │ │ ├── Box Model Worksheet.docx │ │ │ └── Box Model Worksheet.pdf │ ├── 4-forms.zip │ ├── 4-forms │ │ ├── begin │ │ │ ├── css │ │ │ │ └── forms.css │ │ │ ├── forms.html │ │ │ ├── img │ │ │ │ ├── galaxy.jpg │ │ │ │ └── image credit.rtf │ │ │ └── js │ │ │ │ └── forms.js │ │ └── end │ │ │ ├── css │ │ │ └── forms-end.css │ │ │ ├── forms-end.html │ │ │ ├── img │ │ │ ├── galaxy.jpg │ │ │ └── image credit.rtf │ │ │ └── js │ │ │ └── forms.js │ ├── 5-github.zip │ └── 5-github │ │ ├── begin │ │ ├── calculator.html │ │ └── css │ │ │ └── calculator.css │ │ ├── calculator instructions.txt │ │ ├── calculator-spec.png │ │ └── end │ │ ├── calculator.html │ │ └── css │ │ ├── calculator-jen.css │ │ └── calculator.css ├── favicon.ico ├── fox-pet │ ├── bg │ │ ├── BG Lightening 1.png │ │ ├── BG Lightening 2.png │ │ ├── BUTTONS │ │ │ ├── Hover.png │ │ │ ├── NotSelected.png │ │ │ └── Selected.png │ │ ├── Canvas.png │ │ ├── DAY.png │ │ ├── DEAD.png │ │ ├── FG lightening 1.png │ │ ├── FG lightening 2.png │ │ ├── FRAME.png │ │ ├── ICONS │ │ │ ├── Hover.png │ │ │ ├── NotSelected.png │ │ │ └── Selected.png │ │ ├── NIGHT.png │ │ ├── RAINY.png │ │ └── rain.png │ ├── fox.css │ ├── fox.html │ ├── fox.js │ ├── pet │ │ ├── AtRest.png │ │ ├── Eating.png │ │ ├── Egg.png │ │ ├── FoxBase.png │ │ ├── Hungry.png │ │ ├── PoopBag.png │ │ ├── Pooping.png │ │ ├── Rain.png │ │ ├── Sleeping.png │ │ ├── TombStone.png │ │ ├── Walking.png │ │ └── Yay.png │ └── sprites.css ├── gallery │ ├── gallery.js │ ├── images │ │ ├── 1.jpg │ │ ├── 10.jpg │ │ ├── 11.jpg │ │ ├── 12.jpg │ │ ├── 2.jpg │ │ ├── 3.jpg │ │ ├── 4.jpg │ │ ├── 5.jpg │ │ ├── 6.jpg │ │ ├── 7.jpg │ │ ├── 8.jpg │ │ ├── 9.jpg │ │ └── bh.png │ ├── index.html │ ├── styles.css │ ├── with-libraries.html │ └── with-libraries.js ├── layout │ ├── 37DE85_0_0.eot │ ├── 37DE85_0_0.ttf │ ├── 37DE85_0_0.woff │ ├── 37DE85_0_0.woff2 │ ├── Scratch_texture.png │ ├── TreeBG.png │ ├── fm-vector-optimized.svg │ ├── logoBurst.png │ └── postIT_bg.png └── mole-game │ ├── background.png │ ├── cursor-worm.png │ ├── cursor.png │ ├── king-mole-fed.png │ ├── king-mole-hungry.png │ ├── king-mole-leaving.png │ ├── king-mole-sad.png │ ├── mole-fed.png │ ├── mole-hungry.png │ ├── mole-leaving.png │ ├── mole-sad.png │ ├── mole.css │ ├── mole.html │ ├── mole.js │ ├── win.png │ └── worm.png └── yarn.lock /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint:recommended", 4 | "plugin:import/errors", 5 | "plugin:react/recommended", 6 | "plugin:jsx-a11y/recommended", 7 | "prettier", 8 | "prettier/react" 9 | ], 10 | "rules": { 11 | "react/prop-types": 0, 12 | "jsx-a11y/label-has-for": 0, 13 | "no-console": 1 14 | }, 15 | "plugins": ["react", "import", "jsx-a11y"], 16 | "parser": "babel-eslint", 17 | "parserOptions": { 18 | "ecmaVersion": 2018, 19 | "sourceType": "module", 20 | "ecmaFeatures": { 21 | "jsx": true 22 | } 23 | }, 24 | "env": { 25 | "es6": true, 26 | "browser": true, 27 | "node": true 28 | }, 29 | "settings": { 30 | "react": { 31 | "version": "16.5.2" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Project dependencies 2 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 3 | node_modules 4 | .cache/ 5 | # Build directory 6 | public/ 7 | .DS_Store 8 | yarn-error.log 9 | mole.zip 10 | fox.zip 11 | luna.zip 12 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Frontend Masters Bootcamp 🏕 2 | 3 | ### More information about the bootcamp: https://frontendmasters.com/bootcamp/ 4 | ### Course website: https://frontendmasters.github.io/bootcamp/ 5 | 6 |   7 | 8 | [![Build Status](https://dev.azure.com/btholt/bootcamp/_apis/build/status/btholt.bootcamp)](https://dev.azure.com/btholt/bootcamp/_build/latest?definitionId=2) 9 | [![GitHub Deployment Badge](https://vsrm.dev.azure.com/btholt/_apis/public/Release/badge/55cc037f-434a-43f1-bfa9-7ed68aa22f42/1/1)](https://dev.azure.com/btholt/bootcamp/_releases2) 10 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Node.js 2 | # Build a general Node.js application with npm. 3 | # Add steps that analyze code, save build artifacts, deploy, and more: 4 | # https://docs.microsoft.com/vsts/pipelines/languages/javascript 5 | 6 | name: Frontend Masters Boot Camp 7 | 8 | pool: 9 | vmImage: "Ubuntu 16.04" 10 | 11 | trigger: 12 | - master 13 | 14 | steps: 15 | - task: NodeTool@0 16 | inputs: 17 | versionSpec: "8.x" 18 | displayName: "Installing Node.js" 19 | 20 | - script: | 21 | npm install 22 | npm run build 23 | displayName: "Running npm install and build" 24 | 25 | - task: CopyFiles@2 26 | inputs: 27 | sourceFolder: "$(System.DefaultWorkingDirectory)/public" 28 | contents: | 29 | **/* 30 | targetFolder: "$(Build.ArtifactStagingDirectory)" 31 | overWrite: true 32 | displayName: "Copying built static files" 33 | 34 | - task: PublishBuildArtifacts@1 35 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | siteMetadata: { 3 | title: "Frontend Masters Bootcamp", 4 | subtitle: "JavaScript", 5 | description: "Learn JavaScript by building projects with Frontend Masters", 6 | keywords: ["javascript", "coding", "intro", "web development", "front end"] 7 | }, 8 | pathPrefix: "/bootcamp", 9 | plugins: [ 10 | `gatsby-plugin-remove-trailing-slashes`, 11 | `gatsby-plugin-layout`, 12 | { 13 | resolve: `gatsby-source-filesystem`, 14 | options: { 15 | path: `${__dirname}/lessons`, 16 | name: "markdown-pages" 17 | } 18 | }, 19 | `gatsby-plugin-react-helmet`, 20 | { 21 | resolve: `gatsby-transformer-remark`, 22 | options: { 23 | plugins: [ 24 | `gatsby-remark-autolink-headers`, 25 | `gatsby-remark-copy-linked-files`, 26 | `gatsby-remark-prismjs`, 27 | { 28 | resolve: `gatsby-remark-images`, 29 | options: { 30 | maxWidth: 800, 31 | linkImagesToOriginal: true, 32 | sizeByPixelDensity: false 33 | } 34 | } 35 | ] 36 | } 37 | }, 38 | { 39 | resolve: "gatsby-plugin-klipse", 40 | options: { 41 | klipseSettings: { 42 | selector_eval_js: ".language-javascript", 43 | selector_eval_html: ".language-html", 44 | codemirror_options_in: { 45 | lineWrapping: true, 46 | lineNumbers: true 47 | }, 48 | codemirror_options_out: { 49 | lineWrapping: true, 50 | lineNumbers: true 51 | } 52 | } 53 | } 54 | } 55 | ] 56 | }; 57 | -------------------------------------------------------------------------------- /gatsby-node.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | exports.createPages = ({ actions, graphql }) => { 4 | const { createPage } = actions; 5 | 6 | const lessonTemplate = path.resolve(`src/templates/lessonTemplate.js`); 7 | 8 | return graphql(` 9 | { 10 | allMarkdownRemark( 11 | sort: { order: DESC, fields: [frontmatter___order] } 12 | limit: 1000 13 | ) { 14 | edges { 15 | node { 16 | excerpt(pruneLength: 250) 17 | html 18 | id 19 | frontmatter { 20 | order 21 | path 22 | title 23 | } 24 | } 25 | } 26 | } 27 | } 28 | `).then(result => { 29 | if (result.errors) { 30 | return Promise.reject(result.errors); 31 | } 32 | 33 | result.data.allMarkdownRemark.edges.forEach(({ node }) => { 34 | createPage({ 35 | path: node.frontmatter.path, 36 | component: lessonTemplate 37 | }); 38 | }); 39 | }); 40 | }; 41 | -------------------------------------------------------------------------------- /lessons/ajax.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "AJAX" 3 | path: "/ajax" 4 | order: 16 5 | --- 6 | 7 | Web development is full of stupid acronyms. AJAX is one of the worst offenders of this because it actually means something different than what it does. It stands for "asynchronous JavaScript and XML" which is not what it does. However it morphed and evolved and now it's the term that we use to represent what you do when a website requests more information from a server after the page has loaded. 8 | 9 | We're going to use AJAX to request data from an API (lol acronyms.) An API is application programming interface, but what we mean we say API in this context is it's a public server that will allow us to make AJAX calls and it will respond. Most big websites will have some sort of public API, like Twitter for example. There are many [public APIs][api]. 10 | 11 | The API we're going to use is [dog.ceo][dog]. It's a simple, silly API that will give you back random pictures of dogs. Awesome. Make a new project in your favorite editor, add an index.html with the following: 12 | 13 | ```htm 14 | 15 | 16 | 17 | 18 | Dogs 19 | 20 | 21 | 22 |

Doggos

23 |
24 |
25 | 26 | 27 | 28 | 29 | 30 | ``` 31 | 32 | Make a new file called `doggos.js` and put the following: 33 | 34 | ```js 35 | const BREEDS_URL = "https://dog.ceo/api/breeds/image/random"; 36 | 37 | const promise = fetch(DOG_URL); 38 | 39 | promise 40 | .then(function(response) { 41 | const processingPromise = response.json(); 42 | return processingPromise; 43 | }) 44 | .then(function(processedResponse) { 45 | console.log(breeds); 46 | }); 47 | 48 | console.log("this will log first"); 49 | ``` 50 | 51 | We're using a browser function here called `fetch`. `fetch` is the new way of doing AJAX and it is so much easier than the old one. Never use the old one. What `fetch` returns is called a **promise** and it's similar to a callback that we used before. A promise, like callbacks, allows you to deal with things that don't happen immediately, things that are asynchronous. In this case, we're waiting for the API to respond with the information we asked for. It takes to request more information over the Internet and we don't want to hold up the rest of our code. 52 | 53 | With a promise, it's an object that represents the future answer to whatever you asked. That's sort of weird, but it ends up being convenient. So, we have this promise, and with it we call the `then` method on it and give it a function to run once that asynchronous action (the API request) finishes. 54 | 55 | The response will look something like: 56 | 57 | ```json 58 | { 59 | "status": "success", 60 | "message": "https://images.dog.ceo/breeds/affenpinscher/n02110627_11783.jpg" 61 | } 62 | ``` 63 | 64 | If that looks like JavaScript it's because it's technically valid JavaScript! It makes it really easy to use with JavaScript. Once it finishes, it gives you back an unuseful blob of stuff though. We know this blob is actually given to us in a special format called **JSON** (lol more acronyms.) JSON stands for JavaScript Object Notation, and it's a very common way to exchange data over the Internet because it's machine readable but also pretty readable to humans. Because we know this response will be in JSON (we know that because the [documentation][docs] say so) we can say process this blob into a JavaScript object we can use. 65 | 66 | However processing this into JSON is not always trivial. If you have a lot stuff to process, it can take a lot of time and computer processing to do so. As such, this made asynchronous as well and it returns a promise. That's why we do the `return processingPromise;` line. This is called **promise chaining**. The next `then` will be called once this processing is finished. 67 | 68 | Once finished, it's a normal JavaScript we can access normally. So try (inside of the function with `processedResponse`): `console.log(processedResponse.status)`. It should log out `"success"`. Cool, right? 69 | 70 | So now what I want to do make an image on the page of a random doggo. This API happens to do just that! So, let's make it happen. Make you file say: 71 | 72 | ```js 73 | const DOG_URL = "https://dog.ceo/api/breeds/image/random"; 74 | 75 | const promise = fetch(DOG_URL); 76 | const doggos = document.querySelector(".doggos"); 77 | 78 | promise 79 | .then(function(response) { 80 | const processingPromise = response.json(); 81 | return processingPromise; 82 | }) 83 | .then(function(processedResponse) { 84 | const img = document.createElement("img"); 85 | img.src = processedResponse.message; 86 | img.alt = "Cute doggo"; 87 | doggos.appendChild(img); 88 | }); 89 | ``` 90 | 91 | Here we create an `` tag and append it into the DOM via `appendChild`. Wouldn't it be cool if we could do it multiple times? Let's do it!! 92 | 93 | ```js 94 | const DOG_URL = "https://dog.ceo/api/breeds/image/random"; 95 | 96 | const doggos = document.querySelector(".doggos"); 97 | 98 | function addNewDoggo() { 99 | const promise = fetch(DOG_URL); 100 | promise 101 | .then(function(response) { 102 | const processingPromise = response.json(); 103 | return processingPromise; 104 | }) 105 | .then(function(processedResponse) { 106 | const img = document.createElement("img"); 107 | img.src = processedResponse.message; 108 | img.alt = "Cute doggo"; 109 | doggos.appendChild(img); 110 | }); 111 | } 112 | 113 | document.querySelector(".add-doggo").addEventListener("click", addNewDoggo); 114 | ``` 115 | 116 | Now you can add as many doggos as you want! Here's my example: 117 | 118 | 119 | 120 | 121 | 122 | For your extra-credit project, here are some cool ways to expand this project: 123 | 124 | 1. Add this to your GitHub in its own repo (we'll learn how to do that later) 125 | 1. Style it nice using CSS. 126 | 1. Show a loading gif (just use an ``) that shows when you're loading a new doggo and then hide it when you're done. 127 | 1. The dog.ceo API allows you to [request a list of breeds][breeds]. Use this list to populate a ``. Then when a user select a dog breed, show a picture of that dog using the the [random image by breed][pic] API. 128 | 129 | [dog]: https://dog.ceo/dog-api/ 130 | [api]: https://github.com/toddmotto/public-apis 131 | [breeds]: https://dog.ceo/dog-api/documentation/ 132 | [docs]: https://dog.ceo/dog-api/documentation/random 133 | [pic]: https://dog.ceo/dog-api/documentation/breed 134 | -------------------------------------------------------------------------------- /lessons/calculator-setup.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 7 3 | title: "Calculator HTML & CSS Exercise" 4 | path: "/calculator-html" 5 | --- 6 | 7 | Our goal is to create a calculator that looks exactly like this image: 8 | 9 | ![](https://frontendmasters.github.io/bootcamp/exercises/5-github/calculator-spec.png) 10 | 11 | ## Exercise Files 12 | 13 | Download the calculator exercise files, including the beginning state, ending state, instructions, and specification for how the calculator should look: 14 | 15 | https://github.com/FrontendMasters/bootcamp/tree/master/static/exercises/5-github.zip 16 | 17 | We are focusing this lesson on creating the HTML and CSS for the caclulator. In a future lesson we will make it interactive with JavaScript. 18 | 19 | ## A few Things To Know About This Calculator: 20 | 21 | ### To Get Symbols for Math, You'll Need to Look Up Their HTML Codes 22 | 23 | One place to do that is here: 24 | 25 | [HTML Math Characters](https://www.toptal.com/designers/htmlarrows/math/) 26 | 27 | [HTML Arrow Characters](https://www.toptal.com/designers/htmlarrows/arrows/) 28 | 29 | ### The Calculator Buttons Should Be Clickable 30 | 31 | You'll program them later in the course with JavaScript. But for right now, somehow we need to code clickable buttons. 32 | 33 | ### Colors used in this design include: 34 | 35 | - black: #000000 36 | - white: #ffffff 37 | - light grey: #d8d9db 38 | - buttons on hover: #ebebeb 39 | - button active state: #bbbcbe 40 | - function buttons: #df974c 41 | - function buttons on hover: #dfb07e 42 | - function button active state: #dd8d37 43 | 44 | - The overall width of this calculator is 400px. 45 | 46 | ## Suggested approach: 47 | 48 | - Create a wrapper with a width of 400px to set up the calculator. 49 | - Determine how many rows and columns we need. 50 | - Identify elements that occupy more than one column. 51 | - Determine the HTML tags required to code rows and cells. 52 | - Code a single row of 4 elements to start with and see if you can get that working. 53 | - Now add the other rows of 4 elements. 54 | - Finally, add the rows where there are fewer than 4 elements. What do you need to adjust to get these to work? 55 | - Once your layout is mostly working, add the colors and make it pretty. 56 | 57 | ## HTML and CSS Tips and Hints 58 | 59 | - Programming is all about taking large problems and breaking them into smaller problems. If you're trying to tackle too much at once, break it into two smaller problems and try to solve one of those. 60 | - Personally, I wrote the HTML and CSS first. Once that's all taken care of, then I do the JavaScript. 61 | - For the font of the "result screen" I'd just use `monospace`. 62 | - There are so many ways to write this. There is no one right way. My solution is not the only nor is it the best solution. Experiment. Try. Fail. Succeed. It's all about learning here. 63 | - Good idea to use `` for the buttons. You have to deal with some extra styling stuff but it will make your code work pretty much automatically for disabled people. In general when writing HTML, if something serves the function of a button, make it a ``. 64 | - I used multiple rows of flex layed out divs for the button. You could do it all in one div using the `flex-wrap` property. 65 | - The secret to getting equal gutters (which is what you call the black space between buttons): you can set width to be `24.5%` (so four of them fit on a line) and then use `justify-cotent: space-between` to evenly space them. That'll give them a gutter of roughly `.5%` of the whole width. The problem with using percentages in conjuections with heights: your heights and widths are different. 5% of height is not the same of 5% of width, and that'll make the gutters look weird. You want the bottom gutters to be the same size as the side gutters. `margin-bottom` to the resuce! If you give the row a `margin-bottom` of `.5%` (if you're using my same numbers) then that'll work since margin is always measured as a function of width (just one of those things you have to know!) Hopefully that helps. 66 | - Sometimes I do the math to get things right. Sometimes I just guess-and-check to see if it looks okay. 67 | - You can add a class to get the orange buttons. Or you could try `:last-child` (assuming you have row div.) 68 | 69 | Good luck! 70 | -------------------------------------------------------------------------------- /lessons/calculator.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 14 3 | title: "Exercise: Making the Calculator Work with JavaScript" 4 | path: "/calculator" 5 | --- 6 | 7 | 13 | 14 | We are going to rebuild the calculator on iOS! Here it is: 15 | 16 | 17 | 18 | 19 | 20 | My implementation of it is embedded here on the page so feel free to play with it. 21 | 22 | ## Let's go over the requirements: 23 | 24 | - The calculator should work like it does above 25 | - The calculator should function like a normal calculator 26 | - **Do not** implement `%` or `.`. You can assume everything will be an integer. 27 | - `C` means clear. When a user clicks it, it should clear everything and go back to the first state it was in when the page loaded. 28 | - Doing the back arrow is extra credit. It's like pressing backspace; it'll delete the last character typed. If it's clicked when there's only one digit, it sets the current number to be `0`. 29 | - Don't worry about if the number is too long for the screen. 30 | - Calculators tend to have some special behavior when you hit equals: if you type another number it erases the results and starts over. Feel free to do that but also free free (like me) to just treat it normally and make the user hit `C` if they want to clear it. Let's keep it simple. 31 | 32 | Okay, now that you have requirements, let's go over some tips and hints. 33 | 34 | ## JavaScript Tips and Hints 35 | 36 | - Again, no wrong way to do this. I wrote about 80 lines of JavaScript to finish the project (not including empty lines.) I say that so you have an idea of how much code you should be writing. If you're writing 200+ lines of code, you may want to rethink some of your solutions. Don't feel like you're going for the smallest possible answer. You're just going for correct. 37 | - I use `console.log` everywhere while I'm writing code. Just remember to take them out at the end. 38 | - Many small functions is _very_ preferable to one large function. Have each function do one thing well as opposed to having giant functions that do everything. If you find a function doing too, break it into smaller pieces. I solved it with eight different functions. 39 | - You'll need to keep track of several variables. Make sure these variables are stored in a place where they stay in scope. 40 | - You can add an event listener to each button individually, or you can use one listener at the root of the button. I did the latter but it's up to you. 41 | 42 | ## Types 43 | 44 | A brief note on what called **types** in JavaScript. We've danced the idea already and I want to make it a little more concrete for you. Strings, booleans, objects, arrays, numbers, these are different types of types (lol). JavaScript is a language where you don't have to concern yourself _a lot_ with types since it doesn't strictly enforce them (other languages do) but in this problem you are definitely going to have to deal with it. 45 | 46 | Whatever you put into the DOM and whatever you get out it are going to strings, every time. If I do: 47 | 48 |
49 | 50 | ```javascript 51 | const num = 10; 52 | const div = document.querySelector(".number-target"); // the div right above this block 53 | console.log(num, typeof num); // this is a number here 54 | div.innerText = num; 55 | console.log(div.innerText, typeof div.innerText); // it's a string here 56 | ``` 57 | 58 | Since you're doing math here, you'll need the numbers to actually be of the number type. Otherwise you'll get `"5" + "5" = "55"`. There's a function called `parseInt(string)` that will turn a string of a number (`"5"`) to a number (`5`). 59 | 60 | You'll also see that we used the `typeof` operator. `typeof` tells whatever the type of the thing that comes right after it is. This is useful to quickly see what's happening in your code. Be careful because `typeof` is not always useful, but it is useful for telling numbers and strings apart. 61 | 62 | ## Starting HTML & CSS 63 | 64 | You can copy and paste the HTML & CSS to start with locally, or use our [calculcator starter CodePen][calcstarter] to focus on writing the JavaScript. 65 | 66 | - [The HTML][html] (you can view source on it) 67 | - [The CSS][css] 68 | 69 | **Now go code the JavaScript to make the calculator work!** 70 | 71 | ### Answer: [The JavaScript][js] 72 | 73 | [html]: https://github.com/FrontendMasters/bootcamp/blob/master/static/calculator.html 74 | [css]: https://github.com/FrontendMasters/bootcamp/blob/master/static/calculator.css 75 | [js]: https://github.com/FrontendMasters/bootcamp/blob/master/static/calculator.js 76 | [calcstarter]: https://codepen.io/frontendmasters/pen/wQMgWR 77 | -------------------------------------------------------------------------------- /lessons/dogs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Exercise: Dog App" 3 | path: "/dogs" 4 | order: 17 5 | --- 6 | 7 | We're going to build a dog picture viewer using the [dog.ceo API][dogceo]. This project is going to allow users to select a breed from a drop down list and then display a random picture of that breed. 8 | 9 | [Here's my version of it.][dog-viewer] 10 | 11 | Requirements: 12 | 13 | - Here are the API docs. 14 | - The list of breeds can be obtained by `List all breeds` API (see the docs linked above.) Request the list of breeds and then use those to create all the `option`s for the `select`. 15 | - When the page first loads, show a loading spinner until the image has loaded. I used an emoji with CSS animations to do so. Feel free to [look at what other people have done][loading], write your own (short tutorial will be below), or use an animated GIF. When the image loads, hide the spinner and show the image. 16 | - You already know how to change the `src` of an `img`, but if you immediately hide the loading spinner and show the `img`, you'll have a flash of time where nothing on the page since the image hasn't loaded yet. You can side step this by using `addEventListener` on the `img` tag and listen for the `"load"` event. Once the `"load"` event happens, it means the image is loaded and ready to be shown. 17 | - You can do AJAX request using fetch and promises like I showed you in the previous chapter. I'm now going to show you a brand new feature called async / await and it makes this a lot easier. 18 | 19 | Let's chat about CSS animations a second here: 20 | 21 | ```html 22 | 50 | 51 | 52 | ``` 53 | 54 | 56 | 57 | - These `@keyframes` animations are re-usable animations that we define once and can use as many times as we want. 58 | - The second word (in our case `spin` and `psychadelic`) are what we called the animations, similar to a variable name. It's what we can refer to it as later. 59 | - Inside the `@keyframes` we have a `to` property. You can define very fine grain steps in the animation but here we want it to infer the steps. We _could_ add `from { transform: rotateZ(0deg); }` but the browser already knows that it's at `0deg` rotation. In this case, it just infers that you want it to start from where it is and animate to the `to` point. 60 | - You can also use percentages. Instead of `to` you'd use `100%` and instead of `from` you'd use `0%`. You can put as many steps as you want in there too e.g. `1%`, `10%`, `50%`, `92%`, etc. 61 | - Where you want to _use_ animation, put something like `animation: spin 1s infinite linear;`. This will use the `spin` animation we defined above, will take 1 second to do one iteration of the animation, will do it with linear easing, and will continue to do it infitiely. The order is not important here. 62 | - Easing allows you to make it seem elastic when it starts and stops, like a ball bouncing. It's faster at the bottom of the bounce and slower at the top. 63 | 64 | Let's talk about async / await for a second. So far we've been using promises and `.then`. There's an easier way to do it and it's called async / await. 65 | 66 | ```html 67 | 68 | 69 | 79 | ``` 80 | 81 | Notice the function getDoggo has the `async` keyword there. This means inside of this function we can use `await`. `await` takes a promise and then _pauses_ the function until that promise resolves and gives you the answer back. It makes the code a lot simpler to understand. If you need to deal with errors, you can just try / catch. Feel free to write code this way for this exercise or continue using promises. Do note that I can't say `await` in the top level; it has to be inside of an async function. 82 | 83 | Your page does not have to look like mine. Feel free to design it however you want. Feel free to copy me too! 84 | 85 | Good luck! 86 | 87 | If you want to see my answers, [here is the JavaScript][js], [here is the CSS][css], and [here is the HTML][html]. 88 | 89 | [dogceo]: https://dog.ceo/dog-api/documentation/ 90 | [dog-viewer]: https://frontendmasters.github.io/bootcamp/dog-viewer/dog.html 91 | [loading]: https://codepen.io/tag/spinner/# 92 | [js]: https://github.com/btholt/bootcamp/blob/master/static/dog-viewer/dog.js 93 | [css]: https://github.com/btholt/bootcamp/blob/master/static/dog-viewer/dog.css 94 | [html]: https://github.com/btholt/bootcamp/blob/master/static/dog-viewer/dog.html 95 | -------------------------------------------------------------------------------- /lessons/functions-and-scope.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 9 3 | title: "Functions and Scope" 4 | path: "/functions-and-scope" 5 | --- 6 | 7 | A function is a bit of re-usable code. Just how we like to re-use CSS classes, we love to re-use code. Let's start with an example: 8 | 9 | ```javascript 10 | function addTwo(number) { 11 | return number + 2; 12 | } 13 | 14 | const finalAnswer = addTwo(5); 15 | console.log(finalAnswer); 16 | ``` 17 | 18 | This isn't super useful but hopefully it shows you the mechanics of how a function works. We created a function called `addTwo`. This function takes in one parameter, `number` and it returns that number with 2 added to it. We can now use that `addTwo` function as much as we want! Let's make a something a bit more useful. 19 | 20 | ```javascript 21 | function greet(firstName, lastName, honorific, greeting) { 22 | return `${greeting} ${honorific} ${lastName}! I’m extremely pleased you could join us, ${firstName}! I hope you enjoy your stay, ${honorific} ${lastName}.`; 23 | } 24 | 25 | console.log(greet("Brian", "Holt", "Lord", "Salutations")); 26 | console.log(greet("Jack", "Sparrow", "Captain", "A-hoy")); 27 | ``` 28 | 29 | Now we rather than have to repeate ourselves over-and-over again with that long string, we can just call greet with the appropriate parameters. Here we use four parameters. The order is important that we send in the parameters because this will be the order function receives these parameters. You can have as many or as few parameters as you like. 30 | 31 | The way **call** a function is you add parens to the end of it, like this: `someFunctionName()`. If you see parens after a variable name, you instantly know that that's a function. Inside of the parens go the parameters. These variables will be passed to the function that is being called in the order that you put them there. Example: 32 | 33 | ```javascript 34 | const myHomeCity = "Salt Lake City"; 35 | const myHomeState = "Utah"; 36 | const myHomeCountry = "USA"; 37 | 38 | function logOutYourHome(city, state, country) { 39 | console.log(`You are from ${city}, ${state} ${country}.`); 40 | } 41 | 42 | logOutYourHome(myHomeCity, myHomeState, myHomeCountry); 43 | ``` 44 | 45 | ## Scope 46 | 47 | We'll talk about scope multiple times but we'll start off here with it. Every time you call a function, it has its own scope. Other things can't peek into it; it just has its own little workspace for it work with. Once its done, any variable that you haven't explicitly held on to or returned at the end is discarded. For example: 48 | 49 | ```javascript 50 | function addFive(number) { 51 | const someVariable = "you can't see me outside this function"; 52 | return number + 5; 53 | } 54 | 55 | addFive(10); 56 | console.log(someVariable); 57 | ``` 58 | 59 | This is not going to work. `someVariable` is inside of the `addFive` scope and once `addFive` completes, it throws `someVariable` away since it's now out-of-scope. 60 | 61 | ```javascript 62 | let friendsAtYourParty = 0; 63 | for (let i = 0; i <= 10; i++) { 64 | friendsAtYourParty++; 65 | } 66 | console.log(i); 67 | ``` 68 | 69 | Even this doesn't work since `i` is only in scope for the loop and then after that it's thrown away. This can be a difficult one to deal with as someone new to coding because you'll go to log something or use a variable and it's out of scope so it's not there. Just know if that happens, this is probably the problem. 70 | 71 | Scope is hard. And scope is particularly strange in JavaScript (it varies by programming language.) If it feels hard it's because it is. A general, imperfect way for you to think about it right now is that a variable is "alive" (in scope) in between whatever the closest `{` is until that `{` closes its corresponding `}`. A few examples below, see if you can get it right. Keep in mind that the variable will stay in scope as long as any scope it exists in still exists. If I declare a variable in an outter scope and modify a variable in an inner scope, that variable will survive as long as the outter scope does. **It matters where the variable is declared.** 72 | 73 | ```js 74 | const A = "A"; 75 | let F; 76 | 77 | function doStuff(B) { 78 | console.log(B); 79 | const C = "C"; 80 | let H = "H"; 81 | if (1 + 1 === 2) { 82 | const D = "D"; 83 | H = "something else"; 84 | } 85 | console.log(D); 86 | console.log(H); 87 | F = "F"; 88 | } 89 | 90 | let E = 0; 91 | while (E < 3) { 92 | E++; 93 | console.log(A); 94 | const G = "G"; 95 | } 96 | console.log(E); 97 | console.log(G); 98 | 99 | doStuff("B"); 100 | console.log(B); 101 | console.log(C); 102 | console.log(F); 103 | ``` 104 | 105 | This is pretty convulated example but see what you think. Once your ready, the next block will be the answers. 106 | 107 | ```javascript 108 | const A = "A"; 109 | let F; 110 | 111 | function doStuff(B) { 112 | console.log(B); // works, B parameter is still in scope 113 | const C = "C"; 114 | let H = "H"; 115 | if (1 + 1 === 2) { 116 | const D = "D"; 117 | H = "something else"; 118 | } 119 | console.log(D); // does not work, D was declared in that if statement block 120 | console.log(H); // works, H was declared outside the if statement 121 | F = "F"; 122 | } 123 | 124 | let E = 0; 125 | while (E < 3) { 126 | E++; 127 | console.log(A); // works, the outter block (called the global scope) is still in scope 128 | const G = "G"; 129 | } 130 | console.log(E); // works, E was declared outside the whie loop 131 | console.log(G); // does not work, declared inside the while loop and it's over 132 | 133 | doStuff("B"); 134 | console.log(B); // does not work, the B parameter expires after the function call 135 | console.log(C); // does not work, C was declared inside the function and the function is over 136 | console.log(F); // works, F was declared in the global scope 137 | ``` 138 | 139 | ## Builtins 140 | 141 | Lots of functions already exist for you! Smart people have created this commonly-used functions for things we often need. For example, say you have a string and you want to make everything lowercase, you can do this: 142 | 143 | ```javascript 144 | const sentence = "ThIs HaS wEiRd CaSiNg On It"; 145 | console.log(sentence.toLowerCase()); 146 | ``` 147 | 148 | Always be looking for the parens. And the best place to look all this stuff up is from our friends at Mozilla (makers of Firefox): [the MDN][mdn]. MDN used to stand for "Mozilla Developer Network" I think but now it's just synonmous with the documentation for the web. I literally look at this website several times a day. As I said before, you are not expected to remember everything. Looking things up on the MDN is **not** cheating. 149 | 150 | You can call `Math.round(5.1)` and it'll return that number rounded (in this, `5`). You can use `string.substr(indexToStart, howManyCharactersToInclude)` to return part of a string. For example `const name = "Brian Holt"; console.log(name.substr(6, 3))` logs out `"Hol"` (remember numbering starts at 0). We'll introduce them as we go but know there are a _lot_ of them. You'll learn by doing. 151 | 152 | ```javascript 153 | console.log(Math.round(5.1)); 154 | 155 | const name = "Brian Holt"; 156 | console.log(name.substr(6, 3)); 157 | ``` 158 | 159 | [mdn]: https://developer.mozilla.org/en-US/ 160 | -------------------------------------------------------------------------------- /lessons/github.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 6 3 | title: "GitHub" 4 | path: "/github" 5 | --- 6 | 7 | ## GitHub Pages 8 | 9 | ### Getting Web Pages Online 10 | 11 | Files are found at https://github.com/FrontendMasters/bootcamp/tree/master/static/exercises/5-github 12 | 13 | [Download ZIP of Files](https://github.com/FrontendMasters/bootcamp/blob/master/static/exercises/5-github.zip) 14 | 15 | ### Getting web pages online 16 | 17 | So far, the websites we've built have worked on the computer in front of us only. That's not much of a site if no one else can see it! 18 | 19 | You will need a way to display your web pages online so the world can see them. There are many ways to accomplish this. One of the oldest ways that still works great is the following: 20 | 21 | - **Sign up for web hosting** with a web hosting provider. (For the simple sites we're building, any web hosting provider will work!) This is also called a **server**. 22 | - As part of the hosting signup, **purchase a domain name** for your website. (Alternatively, if you already have a domain name, **point the domain name** to your new web hosting.) 23 | - Download a FTP program like **FileZilla** ([https://filezilla-project.org/download.php?type=client](https://filezilla-project.org/download.php?type=client)), and t**ransfer your website** from your computer to the web hosting provider's server. 24 | - **Look at your website!** 25 | 26 | Unfortunately, web hosting and domain names costs money, and we are just starting out, wanting to keep everything free. 27 | 28 | Fortunately, there is another solution to getting a simple website like ours online: GitHub Pages! 29 | 30 | You will need to follow the below instructions very carefully to get this working. I've included links to additional reading if you get lost along the way. 31 | 32 | ## 1. Sign up for GitHub 33 | 34 | First, sign up for GitHub. 35 | 36 | Go to [https://www.github.com](https://www.github.com) and sign up for the service. 37 | 38 | If you already have a GitHub account, make sure you are signed in. 39 | 40 | ## 2. Download GitHub Desktop 41 | 42 | Go to [https://desktop.github.com](https://desktop.github.com) and download the GitHub Desktop version for your computer, Mac or Windows. 43 | 44 | Install the application on your computer. 45 | 46 | ## 3. Create a repository 47 | 48 | A repository is a place where your files will be stored, similar to a folder or a directory. 49 | 50 | 1. Make sure you are signed into GitHub. 51 | 2. Go here: [https://github.com/new](https://github.com/new) 52 | 3. In the Repository Name field, enter your username.github.io. For example, I am `jen4web` on GitHub, so my repository name is `jen4web.github.io`. Add a description. The other settings should look like the ones below. Click the "create repository" button. 53 | 54 | ![Create a repository](./images/GitHub-1.png) 55 | 56 | ## 4. Set up the repository in GitHub Desktop 57 | 58 | **Click the "Set up in Desktop" button in the next screen:** 59 | 60 | ![Set up the repository in GitHub Desktop](./images/GitHub-2.png) 61 | 62 | Allow GitHub Desktop to open. There is an opening configuration screen. Click on "Sign into GitHub.com". 63 | 64 | ![Sign into GitHub.com](./images/GitHub-3.png) 65 | 66 | Enter your username (or email address) and password. 67 | 68 | ![Log into GitHub](./images/GitHub-4.png) 69 | 70 | Configure your name and email as you wish, and click Continue. Click the finish button on the next screen, and you are good to go! 71 | 72 | Now you are in GitHub Desktop, and the screen should be filled out for you on the URL tab. Choose the desktop for your local path. It will create a new folder for you on the desktop: 73 | 74 | ![Setting up local repos](./images/GitHub-5.png) 75 | 76 | Click the "Clone" button to finish setting up GitHub Desktop. 77 | 78 | ## 5. Make sure your GitHub folder has all of the files you want to post online 79 | 80 | Review the folder. Does it have all of your HTML, images, and CSS ready to post? If not, copy these files into the folder. 81 | 82 | **Make sure one file — probably your home page — is called index.html.** Make sure the links to that file are correct. 83 | 84 | Refer back to GitHub Desktop — once you've copied in your files and folders, you should see all of them listed here. 85 | 86 | ![Posting files to GitHub](./images/GitHub-6.png) 87 | 88 | ## 6. Make a commit note for each file in the lower left corner 89 | 90 | A "commit" is the moment you upload these files and folders to GitHub. You are "committing" your changes to the repository. 91 | 92 | Make a note for each item by clicking on the file name and writing a note in the lower left corner of the screen. 93 | 94 | ## 7. Click the "Commit to master" button and "Publish Branch" button 95 | 96 | With notes in place, select all of your files and folders and click the blue "commit to master" button in the lower left. Then click the "publish branch" button in the black area in the upper right. 97 | 98 | ## 8. Look in your browser window 99 | 100 | Open a new tab in your browser and go to `https://.github.io` -- in my case, [https://jen4web.github.io](https://jen4web.github.io). 101 | 102 | You should see your web page, images, and CSS styles show up on your home page 103 | 104 | ## 9. Waaaa, it didn't work!!! 105 | 106 | What exactly "didn't work?" 107 | 108 | - Did you keep the exact same file and folder structure that you had on your computer previously? If not, you broke the paths between files, and you'll need to fix that. 109 | - Did all of your images and css upload? (Go to `www.github.com/`, click on Repositories, and click on the repository for this exercise. Are all of the files there and in the proper places? 110 | - Did you have a file called index.html? If not, you'll need to type in the name of that file as part of the URL. For example: [http://jen4web.github.io/about.html](http://jen4web.github.io/about.html) 111 | - Did you follow the above instructions exactly? If you named your repository something other than `.github.io`, it "won't work." 112 | 113 | ## 10. Updating files in your repository 114 | 115 | You may want to keep making changes to your website, and you want to keep publishing those changes to your repo. To do this: 116 | 117 | - Make all of your edits and changes in VSCode, just as you've been doing. Save your changes in the `.github.io` folder. 118 | - When you're ready to post your changes, open up GitHub Desktop, and go into the `.github.io repo`. 119 | - Make sure the "changes" tab is selected. It should show you all changed files since the last time you posted. 120 | - Select each file individually, make a note about what changed, and click "commit to master" 121 | - Click the button on the top right, which might now read "fetch origin" -- but it still does the same thing. 122 | - Check to see your changes in the browser. 123 | 124 | ## References 125 | 126 | - GitHub [http://www.github.com](http://www.github.com) 127 | - GitHub Pages [https://pages.github.com/](https://pages.github.com/) 128 | - How to Craft a Stand-Out Web Developer Portfolio 129 | [https://skillcrush.com/2016/10/31/web-developer-portfolio/](https://skillcrush.com/2016/10/31/web-developer-portfolio/) 130 | - How to Build an Impressive Portfolio When You're New to Tech 131 | [https://skillcrush.com/2015/03/12/impressive-tech-portfolio/](https://skillcrush.com/2015/03/12/impressive-tech-portfolio/) 132 | 133 | ## Your Portfolio Project 134 | 135 | When thinking about your portfolio, consider these business questions: 136 | 137 | - Who will see it? 138 | - What will they want to know about you? 139 | - What questions do you need to answer? 140 | - What value can you provide? 141 | 142 | Then consider these technical questions: 143 | 144 | - What is your color scheme? Branding? 145 | - Have you made the pages look consistent across your site? 146 | - Do all of your links work correctly? 147 | - Does your site look good in Chrome and Firefox? 148 | 149 | ### Waaaa, it "doesn't work"!!! 150 | 151 | Remember to use the HTML and CSS validators if things are looking odd in the browser, or if the colors in the editor seem off. That's an indicator that you've made some errors along the way. The HTML validator is great for catching errors pertaining to syntax, tag spelling, tag nesting, and applying the right attributes to a given tag. The CSS validator will find unclosed curly brackets, properties and values that don't exist, and more. 152 | 153 | HTML validator: http://validator.w3.org/ 154 | 155 | CSS validator: http://jigsaw.w3.org/css-validator 156 | -------------------------------------------------------------------------------- /lessons/images/FrontendMastersLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/lessons/images/FrontendMastersLogo.png -------------------------------------------------------------------------------- /lessons/images/GitHub-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/lessons/images/GitHub-1.png -------------------------------------------------------------------------------- /lessons/images/GitHub-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/lessons/images/GitHub-2.png -------------------------------------------------------------------------------- /lessons/images/GitHub-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/lessons/images/GitHub-3.png -------------------------------------------------------------------------------- /lessons/images/GitHub-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/lessons/images/GitHub-4.png -------------------------------------------------------------------------------- /lessons/images/GitHub-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/lessons/images/GitHub-5.png -------------------------------------------------------------------------------- /lessons/images/GitHub-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/lessons/images/GitHub-6.png -------------------------------------------------------------------------------- /lessons/images/borderbox2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/lessons/images/borderbox2.png -------------------------------------------------------------------------------- /lessons/images/brian.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/lessons/images/brian.jpg -------------------------------------------------------------------------------- /lessons/images/contentbox1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/lessons/images/contentbox1.png -------------------------------------------------------------------------------- /lessons/images/css-boxmodel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/lessons/images/css-boxmodel.png -------------------------------------------------------------------------------- /lessons/images/css-shorthand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/lessons/images/css-shorthand.png -------------------------------------------------------------------------------- /lessons/images/jen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/lessons/images/jen.jpg -------------------------------------------------------------------------------- /lessons/images/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lessons/images/vscode-enabled.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/lessons/images/vscode-enabled.jpg -------------------------------------------------------------------------------- /lessons/images/vscode-icon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/lessons/images/vscode-icon.jpg -------------------------------------------------------------------------------- /lessons/images/vscode-open-in-browser.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/lessons/images/vscode-open-in-browser.jpg -------------------------------------------------------------------------------- /lessons/images/vscode-reload.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/lessons/images/vscode-reload.jpg -------------------------------------------------------------------------------- /lessons/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: "Introduction to the Course" 4 | path: "/intro" 5 | --- 6 | 7 | From Jen Kramer and Brian Holt, your instructors: 8 | 9 | We are excited to teach you the basics of web development, including HTML, CSS, and some JavaScript. In this course we assume you know absolutely nothing about writing code. 10 | 11 | Because this is a short course, we are not able to cover everything about HTML, CSS, JavaScript, and web development exhaustively. Our goal is to teach you just enough to determine whether this kind of work for you. Do you enjoy it? Is it interesting? 12 | 13 | If so, you'll be ready to dig into all of the resources the Internet offers, learning more on your own. **Completing this course will not fully prepare you to be a professional web developer.** You will need more practice with these concepts and more education. However, this course is an excellent start towards that goal. 14 | 15 | ## Prerequisites 16 | 17 | We do assume that you have a basic grasp of how to operate your computer: how to browse the Internet, how to operate your operating system, how to use a keyboard and mouse, etc. 18 | 19 | We also assume you have completed the Internet Fundamentals course, a free introduction to important concepts like file management, the client and the server, and how the web works. http://www.internetfundamentals.com 20 | 21 | ## Tips to Succeed In This Course 22 | 23 | Contrary to what many people believe, you do not have to be a wizard with math to write code. The two subjects share some overlap but also are quite different. Many artists, lawyers, historians, linguists, and others have great success learning how to code. Don't let those preconceived notions hold you back at all. 24 | 25 | Also keep in mind that this is _hard_. Learning how to code is hard. It's similar to learning a foreign language where you have to learn a lot of small pieces of information to be able to make sense of the larger picture. It's easy to feel discouraged, especially when you feel like you _should_ get something but don't. Keep your head up and keep trying. Walk away from the problem and come back later. Try explaining your problem to someone / your dog / a [rubber ducky][rubber-duck] Seriously, it works. Say it out loud. 26 | 27 | Never feel afraid to Google _anything_. Every programmer you know, from the top person in the field to the newest student is Googling things _constantly_. This isn't cheating; it's a skill. It's a requirement. There is so much information coming at you that cannot possibly remember it all. Copy and paste code. Look at StackOverflow. Ask dumb questions. You get better by repeatedly exposing yourself to information. Each time a bit more will sink in. 28 | 29 | Don't try to understand every piece all at once. There are times where it's okay to just trust that something works and come back later to understand how. It's a tough balance because you do want to try to understand what's going on. We will tell you what's worth diving into and what's worth leaving for another day. You don't have to understand it all at once. 30 | 31 | Lastly, this isn't a get-rich-quick scheme. Learning to code is hard and requires a lot of hard work. While entry-level jobs are out there, and you can get them with months of work, we guarantee you you'll have to work hard for them. 32 | 33 | ## Who Are We? 34 | 35 | ### Jen Kramer, Lecturer at Harvard University Extension School 36 | 37 | ![Jen Kramer](./images/jen.jpg) 38 | 39 | I'm Jen Kramer. I teach the web! 40 | 41 | For most of my 18 year career, I've been a freelancer. I lived in the backwoods of Vermont and built websites for interesting people. I ran a small web design firm in New Hampshire and built websites for interesting companies. Now I live in the Boston suburbs, and while I build fewer sites than I used to do, I do still occasionally put together sites for a good cause. 42 | 43 | Throughout, I've also been a teacher. I taught academically: community college, undergraduates, and graduate students. I taught commercially: LinkedIn Learning/Lynda.com, Frontend Masters, osTraining, and O'Reilly, creating over 35 video training courses. I taught dozens of workshops for corporations and at conferences. I've presented at a conference every six weeks, on average, for the last ten years. And I've written 3 books -- currently working on #4. 44 | 45 | Most of my teaching focuses on the continuum from concept for a website through coding the front end. That includes topics like user experience (UX), user interface design (UI), HTML, CSS, responsive design, content management systems like Joomla and WordPress, project management, web marketing and branding, web semantics, web analytics, and accessibility. 46 | 47 | In all my years of teaching, my favorite audience is the beginning beginners -- in other words, people just like you. You are the most difficult audience, because concepts professionals have long taken for granted are brand new and fresh for you. Everything needs to be explained exactly. In explaining, I learn what I didn't know in enough detail before. It is here that the habits of an entire career are formed. It is here, I believe, that I can most influence the web and where it's going. 48 | 49 | [frontend-masters]: https://frontendmasters.com/teachers/jen-kramer/ 50 | [twitter]: https://twitter.com/jen4web 51 | [facebook]: https://www.facebook.com/webdesignjen/ 52 | [github]: https://github.com/jen4web 53 | [linkedin]: https://www.linkedin.com/in/jen4web/ 54 | [slideshare]: https://www.slideshare.net/jen4web 55 | 56 | ### Brian Holt, Cloud Developer Advocate at Microsoft 57 | 58 | ![Brian drinking a beer](./images/brian.jpg) 59 | 60 | My name is Brian Holt. I'm presently (as of writing) a cloud developer advocate at Microsoft. That means I talk to people why I think Azure is a pretty cool place to deploy your code. I write a lot of code demos and help with some open source libraries. I've taught a lot of lessons on [Frontend Masters][frontend-masters] and used to be on the frontend development podcast [Front End Happy Hour][fehh]. Previous to that, I was a senior or staff JavaScript and Node engineer at LinkedIn, Netflix, Reddit, Needle, KSL.com, and NuSkin. 61 | 62 | My biggest passions in life are people and experiences. I hope by going through this course that it can improve your life in some meaningful way and that you in turn can improve someone else's life. My beautiful wife and I live in Seattle, Washington in the United States of America with our cute little Havanese dog Luna. I'd almost always rather be traveling and have been fortunate to see over thirty countries in the past five years. 63 | 64 | Please catch up with me on social media, would love to chat: 65 | 66 | - [Twitter][twitter] 67 | - [Instagram][instagram] 68 | - [GitHub][github] 69 | - [LinkedIn][linkedin] 70 | 71 | I love to teach. It's a challenging task that forces you to peel back all the knowledge you've gain so you can approach someone who lacks the same experience and terminology you have. It forces you to take amorphous concepts floating in your brain and crystalize them into solid concepts that you can describe. It forces you to acknowledge your gaps in knowledge because you'll begin to question things you know others will question. For me to ever master a concept, I have to teach it to someone else. 72 | 73 | Unfortunately life gets in the way. These courses take dozens of hours to prepare and to get right. While I'd love to just create content all day, I have a (awesome) day job at Microsoft that demands and deserves my full attention. However I'm grateful to the team at [Frontend Masters][fem] for giving me deadlines and incentive to create these courses and then allowing and encouraging me to open source the materials. Not everyone has the money to pay for these courses which is why these materials are and will be forever open source for you to reference and share. I think the video content is pretty good too and so I'd encourage you to take a look at that on Frontend Masters too if that's in the cards for you. 74 | 75 | [rubber-duck]: https://en.wikipedia.org/wiki/Rubber_duck_debugging 76 | [frontend-masters]: https://frontendmasters.com/teachers/brian-holt/ 77 | [fehh]: http://frontendhappyhour.com/ 78 | [fem]: https://frontendmasters.com/ 79 | [twitter]: https://twitter.com/holtbt 80 | [instagram]: https://www.instagram.com/briantholt/ 81 | [github]: https://github.com/btholt 82 | [linkedin]: https://www.linkedin.com/in/btholt/ 83 | 84 | ## Why was this course created? 85 | 86 | ![Frontend Masters Logo](./images/FrontendMastersLogo.png) 87 | 88 | Frontend Masters sponsored this bootcamp as a service to their community. They have long been the leader in advanced front-end web development courses, well-respected by the professional community. However, increasingly, they were contacted by beginners, attracted to the high quality of the courses, but without the background to adequately take advantage of the material. 89 | -------------------------------------------------------------------------------- /lessons/mole.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 18 3 | title: "Exercise: Feed-A-Star-Mole" 4 | path: "/mole" 5 | --- 6 | 7 | Here's your next project, a fun variant on the game Whack-A-Mole. If you're not familiar with the premise, the idea is that little moles will pop out of holes and the game is to tap them before they go back in their holes. In our variant, they're hungry little star moles and we're going to feed them worms! After a user gets 10 points, they win the game! There are also more-rare royal star moles that are worth double. If a user doesn't click on a mole in time, the mole frowns and heads back in its hole. If you manage to feed it in time, it smiles happily and disappers back into its hole. 8 | 9 | We even have beautiful artwork for you to use, drawn by the talented [Alice Brereton][alice]. 10 | 11 | [Here's my version of the game.][mole] 12 | 13 | This is a hard project but you can do it! I'd recommend taking it in steps rather than trying to do everything at once. Some sort of progression. I'd recommend something like: 14 | 15 | - Get all the CSS and HTML on the page. Have ten holes with a hungry mole in each. No JS done yet. 16 | - Make the moles show up and disappear (don't worry about the sad face / butt yet.) Don't make them clickable yet, just have them disappear and reappear after a random interval. 17 | - Make the hungry moles clickable. If you click on one, add 1 point to your score. 18 | - After 10 clicks, show the win screen. 19 | - Show the worm meter. As a player clicks on moles, show more and more of the worm. 20 | - Make one in ten of the moles that show up a royal mole. If a user clicks a royal mole, add 2 points to their score. 21 | - If a user doesn't click a mole in time, show a sad mole. 22 | - If a user does click a mole in time, show a fed mole. 23 | - After both sad and fed moles, show a mole butt. 24 | - You're done! 25 | 26 | Feel free to play with the timing. In my version I used the following timings: 27 | 28 | - Hungry moles show up for two seconds 29 | - Sad, fed, and mole butts show for a half second. 30 | - Moles wait at least two seconds before showing up in the same hole and no more than twenty seconds. 31 | 32 | Some concepts you'll need to know. 33 | 34 | - `Date.now()` is going to be a useful function for you. It gives you back how many milliseconds have transpired since January 1, 1970 (often to referred as UNIX time or UNIX Epoch time, [see here if you want to know more][epoch]). 35 | 36 | ```javascript 37 | console.log(Date.now()); 38 | ``` 39 | 40 | - You can handle the timing one of two ways: `setInterval` or `requestAnimationFrame` 41 | - `setInterval` allows you to run a function every X milliseconds. So if I wrote `setInterval(function() { console.log('hi') }, 1000);` would log `hi` every second. 42 | - `requestAnimationFrame` is preferred. It asks the browser once it's finished doing the previous render to call you function. This happens quite frequently (on the order of milliseconds) so be aware of that. The nice thing is that requestAnimationFrame doesn't run while the browser tab isn't in focus. 43 | 44 | ```html 45 |
setInterval 0
46 |
requestAnimationFrame 0
47 | 69 | ``` 70 | 71 | - The latter is a bit more complicated with `requestAnimationFrame` but it allows the browser to yield back to you when its idle. The former will run no matter after the allotted amount of milliseconds. 72 | - Notice with `requestAnimationFrame`, I'm checking after `Date.now() + 1000` milliseconds have gone by. This is how you make it run only every second. 73 | - You'll probably want to represent each mole as an object. You'll need to keep track of what state each mole is in ("fed", "hungry", "leaving", "sad", "gone"), if it's a royal or not, and the time to update its status again. 74 | - Statuses flow predictably. "gone" goes to "hungry" next, "hungry" goes to "sad", "sad" goes to "leaving", and "leaving" to "gone", always. "hungry" can go to "fed" if they're clicked in time. They go from "fed" to "leaving" and then back into the normal cycle. 75 | - You can modify the `src` of an image and it updates the image. 76 | 77 | ```html 78 | 79 | 98 | ``` 99 | 100 | You'll need all the static assets (images.) [Grab them here.][assets] 101 | 102 | Good luck! 103 | 104 | If you want to see my answers, [here is the JavaScript][js], [here is the CSS][css], and [here is the HTML][html]. 105 | 106 | [alice]: https://www.pickledalice.com/ 107 | [mole]: ./mole-game/mole.html 108 | [epoch]: https://en.wikipedia.org/wiki/Unix_time 109 | [assets]: https://frontendmasters.github.io/bootcamp/mole.zip 110 | [js]: https://github.com/btholt/bootcamp/blob/master/static/mole-game/mole.js 111 | [css]: https://github.com/btholt/bootcamp/blob/master/static/mole-game/mole.css 112 | [html]: https://github.com/btholt/bootcamp/blob/master/static/mole-game/mole.html 113 | -------------------------------------------------------------------------------- /lessons/quiz.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 10 3 | title: "Exercise: Quiz" 4 | path: "/quiz" 5 | --- 6 | 7 | For your first exercise you are going to build a quiz game! We are going to use a tool called [CodePen][codepen]. CodePen is basically a little miniature development environment contained in your browser. Instead of having your separate HTML, CSS, and JavaScript files, CodePen combines them nicely into one web page for you. It's nice for making simple, shareable pieces of code. And you it makes it easy to do exercises. 8 | 9 | Some words of advice for as you use CodePen: 10 | 11 | - I recommend signing up for an account. But you do not have to. This will allow you to save your work. 12 | - The way you'll be able to save your work is click the **Fork** button. It means to fork (as in how a river forks) from the original author's version to your own version. You can modify it without worrying about changing mine. It's making your own copy. 13 | - It is possible to crash the browser. Normally CodePen can recover well on its own but in the case that you make it crash so bad it can't even start, see this [blog post][no-js] to see how to start with JavaScript turned off. 14 | - In this exercise you do not need to modify the CSS or HTML at all. However you can see it and play around it if you want to. 15 | - The first one is complete for you as an example. You don't need to change anything about it. 16 | - If you see see a icon like this: ! in the bottom right of the JavaScript pane, it means you have syntax errors in your JS (code that doesn't work / make sense.) If you click on it, it will show you what's wrong. If you're writing code and nothing is happening differently, check to see if that exclamation point is there. 17 | - If you're stuck, Google it. That's not cheating. That's what you're supposed to do. 18 | - Don't be afraid of looking at the answers. This is about learning, not grades. That said, don't cheat yourself. Try. Struggle. Learn. 19 | 20 | Good luck! 21 | 22 | - [Exercise][ex] 23 | - [Answer][ans] 24 | 25 | [codepen]: https://codepen.io 26 | [no-js]: https://blog.codepen.io/documentation/features/turn-off-javascript-in-previews/ 27 | [ex]: https://codepen.io/btholt/pen/VELvwP 28 | [ans]: https://codepen.io/btholt/pen/aRZWGV 29 | -------------------------------------------------------------------------------- /lessons/setup.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | title: "Setup & Prerequisites" 4 | path: "/setup" 5 | --- 6 | 7 | ## 1. Go Through Internet Fundamentals 8 | 9 | In order to make sure you have the skills you’ll need to follow along with the Bootcamp, you'll need to take the FREE [Internet Fundamentals course](https://internetfundamentals.com). 10 | 11 | ## 2. Install Visual Studio Code (VSCode) 12 | 13 | You should install [VSCode](https://code.visualstudio.com) (Visual Studio Code) on your computer, as 14 | this was part of the Internet Fundamentals course: 15 | www.internetfundamentals.com 16 | 17 | To this, we will add an extension. 18 | 19 | 1\. Open VSCode. On the left side of the window, click on the very last 20 | icon: 21 | 22 | 23 | 24 | 2\. In the Search box, type in **Open in Browser** and hit return. You 25 | should see a list of a bunch of extensions called Open in Browser. 26 | 27 | 3\. The very first one, or one near the top of the list, should be the 28 | version from TechER. Click the green Install button. 29 | 30 | ![](./images/vscode-open-in-browser.jpg) 31 | 32 | Once installed, this will change to a blue Reload button. Click that, 33 | and the extension will be installed. 34 | 35 | ![](./images/vscode-reload.jpg) 36 | 37 | The extension is installed when your screen looks like this: 38 | 39 | ![](./images/vscode-enabled.jpg) 40 | -------------------------------------------------------------------------------- /lessons/tests.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 12 3 | title: "Exercise: Make the Tests Pass" 4 | path: "/tests" 5 | --- 6 | 7 | As a way of making sure your code doesn't break over time, we write testing code to test our code. That would like something like this: `expect(addTwo(5)).toEqual(7)`. As long as your tests pass, you can deploy new code with confidence that you didn't break old things in the process of launching new code. It's a failsafe of sorts. 8 | 9 | In this exercise, I wrote a bunch of tests that you need to make pass. You will not need to write any HTML or CSS. In the preview window, you'll see a summary of how many tests you have made pass and how many are still failing. The best approach here is to tackle each test one-at-a-time and ignore the others. You can even make other tests not run by changing the test-calling functions to be `xdescribe` or `xit` or you can only one test/suite run by changing them to `fdescribe` or `fit`, just remember to change them all back to `it` and `describe`. 10 | 11 | These tests are hard. Be prepared for that. You're finished when you make all your tests pass. 12 | 13 | The sorting one is particularly tough. If you need help, check out [my other course here][cs] and scroll down to the bubble sort part. 14 | 15 | - [Exercise][exercise] 16 | - [Answer][answer] 17 | 18 | [exercise]: https://codepen.io/btholt/pen/QZKxRw?editors=0010 19 | [answer]: https://codepen.io/btholt/pen/xyEajx?editors=0010 20 | [cs]: https://btholt.github.io/four-semesters-of-cs/ 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootcamp", 3 | "description": "Frontend Masters Boot Camp", 4 | "version": "1.0.0", 5 | "author": "Brian Holt ", 6 | "dependencies": { 7 | "bootstrap": "^4.3.1", 8 | "code-mirror-themes": "^1.0.0", 9 | "gatsby": "^2.0.9", 10 | "gatsby-cli": "^2.4.1", 11 | "gatsby-link": "^2.0.1", 12 | "gatsby-plugin-klipse": "^2.1.0", 13 | "gatsby-plugin-layout": "^1.0.2", 14 | "gatsby-plugin-react-helmet": "^3.0.0", 15 | "gatsby-plugin-remove-trailing-slashes": "^2.0.4", 16 | "gatsby-plugin-sharp": "^2.0.5", 17 | "gatsby-remark-autolink-headers": "^2.0.6", 18 | "gatsby-remark-copy-linked-files": "^2.0.5", 19 | "gatsby-remark-images": "^2.0.1", 20 | "gatsby-remark-prismjs": "^3.0.0", 21 | "gatsby-source-filesystem": "^2.0.1", 22 | "gatsby-transformer-remark": "^2.1.3", 23 | "prismjs": "^1.15.0", 24 | "react": "^16.5.2", 25 | "react-dom": "^16.5.2", 26 | "react-helmet": "^5.2.0" 27 | }, 28 | "keywords": [], 29 | "license": "(CC-BY-NC-4.0 OR Apache-2.0)", 30 | "main": "n/a", 31 | "scripts": { 32 | "build:static": "gatsby build --prefix-paths", 33 | "build:zip:fox": "bestzip static/fox.zip static/fox-pet/", 34 | "build:zip:mole": "bestzip static/mole.zip static/mole-game/", 35 | "build:zip:luna": "bestzip static/luna.zip static/gallery/images/", 36 | "build:zip": "run-p build:zip:mole build:zip:fox build:zip:luna", 37 | "build": "run-s build:zip build:static", 38 | "dev": "gatsby develop", 39 | "format": "prettier --write \"src/**/*.{js,jsx,md,css}\"", 40 | "lint": "eslint \"src/**/*.{js,jsx}\"" 41 | }, 42 | "devDependencies": { 43 | "@babel/polyfill": "^7.0.0", 44 | "babel-eslint": "^10.0.1", 45 | "bestzip": "^2.1.1", 46 | "core-js": "^2.5.7", 47 | "eslint": "^5.6.0", 48 | "eslint-config-prettier": "^3.1.0", 49 | "eslint-plugin-import": "^2.14.0", 50 | "eslint-plugin-jsx-a11y": "^6.1.1", 51 | "eslint-plugin-react": "^7.11.1", 52 | "npm-run-all": "^4.1.5", 53 | "prettier": "^1.14.3" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/components/TOCCard.css: -------------------------------------------------------------------------------- 1 | .main-card { 2 | width: 100%; 3 | margin: 0; 4 | overflow: hidden; 5 | background-color: white; 6 | background-image: url(https://frontendmasters.github.io/bootcamp/layout/postIT_bg.png); 7 | background-size: 60px; 8 | box-shadow: 0px 10px rgba(36, 40, 39, 0.5); 9 | padding: 20px; 10 | } 11 | 12 | .lesson-title { 13 | font-size: 32px; 14 | padding: 25px 30px 2px 30px; 15 | font-family: "PosterizerKGRough", "Courier New", Courier, monospace; 16 | color: #2c2825; 17 | text-align: center; 18 | } 19 | 20 | .lesson-content { 21 | padding: 0 0 15px 0; 22 | color: #2c2825; 23 | overflow: hidden; 24 | } 25 | 26 | @media (min-width: 680px) { 27 | .lesson-content { 28 | padding-right: 15px; 29 | } 30 | } 31 | 32 | .lesson-content a { 33 | color: #923a21; 34 | padding-left: 0; 35 | } 36 | -------------------------------------------------------------------------------- /src/components/TOCCard.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Link from "gatsby-link"; 3 | 4 | import "./TOCCard.css"; 5 | 6 | const LessonCard = ({ content, title }) => ( 7 |
8 |

{title}

9 |
10 |
    11 | {content.map(lesson => ( 12 |
  1. 13 | 14 | {lesson.node.frontmatter.title} 15 | 16 |
  2. 17 | ))} 18 |
19 |
20 |
21 | ); 22 | 23 | export default LessonCard; 24 | -------------------------------------------------------------------------------- /src/layouts/index.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "PosterizerKGRough"; 3 | src: url("https://frontendmasters.github.io/bootcamp/layout/37DE85_0_0.eot"); 4 | src: url("https://frontendmasters.github.io/bootcamp/layout/37DE85_0_0.eot?#iefix") 5 | format("embedded-opentype"), 6 | url("https://frontendmasters.github.io/bootcamp/layout/37DE85_0_0.woff2") 7 | format("woff2"), 8 | url("https://frontendmasters.github.io/bootcamp/layout/37DE85_0_0.woff") 9 | format("woff"), 10 | url("https://frontendmasters.github.io/bootcamp/layout/37DE85_0_0.ttf") 11 | format("truetype"); 12 | } 13 | 14 | .transparent { 15 | background-color: rgba(0, 0, 0, 0.8); 16 | } 17 | 18 | .navbar { 19 | border-bottom: 1px solid #ccc; 20 | width: 100%; 21 | top: 0; 22 | z-index: 10; 23 | } 24 | 25 | .navbar .logo { 26 | line-height: 100%; 27 | padding: 5px 0; 28 | margin: 0 15px; 29 | } 30 | 31 | .navbar .logo img { 32 | width: 224px; 33 | } 34 | 35 | .navbar h2 { 36 | color: #979898; 37 | text-transform: none; 38 | font-family: "PosterizerKGRough", "Courier New", Courier, monospace; 39 | padding: 0; 40 | padding-top: 10px; 41 | margin: 0; 42 | padding-left: 15px; 43 | } 44 | 45 | @media (min-width: 500px) { 46 | .navbar-brand { 47 | display: flex; 48 | align-items: flex-end; 49 | } 50 | .navbar h2 { 51 | padding-left: 0; 52 | justify-content: flex-end; 53 | display: inline-block; 54 | } 55 | .navbar .logo { 56 | display: inline-block; 57 | } 58 | } 59 | 60 | .jumbotron.gradient { 61 | color: white; 62 | text-transform: uppercase; 63 | font-weight: bold; 64 | } 65 | 66 | .navbar-brand.navbar-brand { 67 | text-transform: uppercase; 68 | color: white; 69 | font-weight: bold; 70 | } 71 | 72 | .navbar-brand.navbar-brand:hover { 73 | color: #777; 74 | } 75 | 76 | .navbar-brand.navbar-brand:focus { 77 | color: white; 78 | } 79 | 80 | .lesson { 81 | margin: auto; 82 | margin-top: 80px; 83 | margin-bottom: 40px; 84 | padding: 20px 20px 25px; 85 | background-color: #fff; 86 | overflow: scroll; 87 | width: 92%; 88 | max-width: 1200px; 89 | box-shadow: 0px 10px rgba(36, 40, 39, 0.5); 90 | } 91 | 92 | @media (min-width: 680px) { 93 | .lesson { 94 | width: 80%; 95 | padding: 20px 40px 25px; 96 | } 97 | } 98 | 99 | .lesson h1 { 100 | color: #923a21; 101 | font-size: 52px; 102 | font-family: "PosterizerKGRough", "Courier New", Courier, monospace; 103 | padding: 20px 12px 6px 0; 104 | } 105 | 106 | .lesson h2 { 107 | color: #42352c; 108 | font-family: "PosterizerKGRough", "Courier New", Courier, monospace; 109 | padding: 10px 0px 0px 0px; 110 | } 111 | 112 | .lesson p { 113 | clear: both; 114 | } 115 | 116 | .lesson-links { 117 | font-size: 18px; 118 | padding: 15px 0; 119 | } 120 | 121 | .next { 122 | color: #d74f25; 123 | float: right; 124 | } 125 | 126 | .prev { 127 | float: left; 128 | color: #d74f25; 129 | } 130 | 131 | .lesson-title { 132 | color: white; 133 | text-transform: uppercase; 134 | font-weight: bold; 135 | } 136 | 137 | .klipse-result { 138 | border: 1px solid #90b4fe; 139 | padding-top: 10px; 140 | padding-left: 10px; 141 | position: relative; 142 | width: 100%; 143 | margin-bottom: 10px; 144 | } 145 | 146 | .klipse-result .CodeMirror-wrap { 147 | width: 100%; 148 | border-color: transparent; 149 | } 150 | 151 | .klipse-result::before { 152 | content: "Result"; 153 | font-weight: bold; 154 | background-color: white; 155 | position: absolute; 156 | top: -13px; 157 | height: 13px; 158 | } 159 | 160 | .language-htm, 161 | .language-css, 162 | .language-js, 163 | .language-json { 164 | width: 100%; 165 | } 166 | 167 | .gatsby-highlight { 168 | /* border: 1px solid black; */ 169 | padding: 4px; 170 | border-radius: 4px; 171 | display: flex; 172 | justify-content: space-between; 173 | flex-direction: column; 174 | align-items: stretch; 175 | } 176 | 177 | .CodeMirror-wrap { 178 | width: 100%; 179 | font-size: 12px; 180 | height: inherit; 181 | margin-bottom: 12px; 182 | } 183 | 184 | .CodeMirror-gutters { 185 | height: inherit !important; 186 | } 187 | 188 | .klipse-snippet > .CodeMirror { 189 | border: none; 190 | width: 100%; 191 | } 192 | 193 | .gatsby-highlight > .klipse-snippet { 194 | border: 1px solid #90b4fe; 195 | width: 100%; 196 | border-right: none; 197 | position: relative; 198 | margin-bottom: 15px; 199 | } 200 | 201 | .doggos { 202 | width: 100%; 203 | border: 1px solid #666; 204 | border-radius: 5px; 205 | } 206 | -------------------------------------------------------------------------------- /src/layouts/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Link from "gatsby-link"; 3 | import Helmet from "react-helmet"; 4 | import { graphql, StaticQuery } from "gatsby"; 5 | 6 | import "bootstrap/dist/css/bootstrap.css"; 7 | import "prismjs/themes/prism-solarizedlight.css"; 8 | import "code-mirror-themes/themes/monokai.css"; 9 | import "./index.css"; 10 | 11 | const TemplateWrapper = props => ( 12 | ( 14 |
15 | 28 |
29 | 30 | 31 | Frontend Masters logo 35 | 36 |

BootCamp

37 | 38 |
39 |
{props.children}
40 |
41 |
42 | )} 43 | query={graphql` 44 | { 45 | site { 46 | siteMetadata { 47 | title 48 | subtitle 49 | description 50 | keywords 51 | } 52 | } 53 | } 54 | `} 55 | /> 56 | ); 57 | 58 | export default TemplateWrapper; 59 | -------------------------------------------------------------------------------- /src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const NotFoundPage = () => ( 4 |
5 |

NOT FOUND

6 |

You just hit a route that doesn't exist... the sadness.

7 |
8 | ); 9 | 10 | export default NotFoundPage; 11 | -------------------------------------------------------------------------------- /src/pages/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | /* background-image: url(/layout/TreeBG.png); */ 3 | background-image: url(https://frontendmasters.github.io/bootcamp/layout/Scratch_texture.png), 4 | linear-gradient(#59726a, #b2c4be); 5 | background-repeat: repeat, no-repeat; 6 | background-size: 300px 200px, 100% 100%; 7 | background-color: #b2c4be; 8 | position: relative; 9 | min-height: 100%; 10 | } 11 | 12 | .main-card { 13 | margin-bottom: 100px; 14 | } 15 | 16 | #pageBGFooter { 17 | background-image: url(https://frontendmasters.github.io/bootcamp/layout/TreeBG.png); 18 | background-position: top; 19 | bottom: 0; 20 | left: 0; 21 | background-size: cover; 22 | position: fixed; 23 | width: 100%; 24 | height: 40%; 25 | z-index: -1; 26 | } 27 | 28 | .BootcampHero { 29 | background-image: url(https://frontendmasters.github.io/bootcamp/layout/logoBurst.png); 30 | background-repeat: no-repeat; 31 | background-size: 100%; 32 | min-height: 300px; 33 | padding-top: 80%; 34 | width: 100%; 35 | height: auto; 36 | } 37 | 38 | .index { 39 | width: 97%; 40 | max-width: 750px; 41 | margin: 0 auto; 42 | margin-top: 20px; 43 | } 44 | 45 | .lesson h3 { 46 | padding: 20px 0 10px; 47 | } 48 | 49 | .example-table { 50 | border-collapse: separate; 51 | } 52 | 53 | .example-table td { 54 | border: 1px solid black; 55 | width: 20px; 56 | height: 20px; 57 | } 58 | 59 | .example-table .current { 60 | background-color: #fcc; 61 | } 62 | 63 | .example-table .n { 64 | border-top-color: transparent; 65 | } 66 | 67 | .example-table .s { 68 | border-bottom-color: transparent; 69 | } 70 | 71 | .example-table .e { 72 | border-right-color: transparent; 73 | } 74 | 75 | .example-table .w { 76 | border-left-color: transparent; 77 | } 78 | 79 | .lesson-content td { 80 | border: 1px solid black; 81 | padding: 8px; 82 | } 83 | 84 | .lesson-content td input { 85 | min-width: 300px; 86 | } 87 | 88 | .lesson-flex { 89 | display: flex; 90 | flex-direction: column; 91 | justify-content: center; 92 | align-items: center; 93 | } 94 | 95 | .random-tweet { 96 | width: 100%; 97 | margin-top: 100px; 98 | } 99 | 100 | .fem-link { 101 | text-align: center; 102 | } 103 | -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StaticQuery, graphql } from "gatsby"; 3 | import Card from "../components/TOCCard"; 4 | 5 | import "./index.css"; 6 | 7 | const IndexPage = () => ( 8 | ( 34 |
35 |
36 | 37 | 41 |
42 | )} 43 | /> 44 | ); 45 | 46 | export default IndexPage; 47 | -------------------------------------------------------------------------------- /src/templates/lessonTemplate.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Link from "gatsby-link"; 3 | import { graphql } from "gatsby"; 4 | 5 | export default function Template(props) { 6 | let { markdownRemark, allMarkdownRemark } = props.data; // data.markdownRemark holds our post data 7 | 8 | const { frontmatter, html } = markdownRemark; 9 | const prevLink = 10 | frontmatter.order > 0 ? ( 11 | 17 | {"← " + 18 | allMarkdownRemark.edges[frontmatter.order - 1].node.frontmatter.title} 19 | 20 | ) : null; 21 | const nextLink = 22 | frontmatter.order + 1 < allMarkdownRemark.edges.length ? ( 23 | 29 | {allMarkdownRemark.edges[frontmatter.order + 1].node.frontmatter.title + 30 | " →"} 31 | 32 | ) : null; 33 | return ( 34 |
35 |
36 |

{frontmatter.title}

37 |
41 |
42 | {prevLink} 43 | {nextLink} 44 |
45 |
46 |
47 | ); 48 | } 49 | 50 | export const pageQuery = graphql` 51 | query LessonByPath($path: String!) { 52 | markdownRemark(frontmatter: { path: { eq: $path } }) { 53 | html 54 | frontmatter { 55 | path 56 | title 57 | order 58 | } 59 | } 60 | allMarkdownRemark( 61 | sort: { order: ASC, fields: [frontmatter___order] } 62 | limit: 1000 63 | ) { 64 | edges { 65 | node { 66 | frontmatter { 67 | order 68 | path 69 | title 70 | } 71 | } 72 | } 73 | } 74 | } 75 | `; 76 | -------------------------------------------------------------------------------- /static/calculator.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | padding: 0; 7 | margin: 0; 8 | } 9 | 10 | .calc { 11 | width: 400px; 12 | background-color: black; 13 | color: white; 14 | } 15 | 16 | .screen { 17 | color: white; 18 | font-size: 40px; 19 | font-family: "Courier New", Courier, monospace; 20 | text-align: right; 21 | padding: 20px 5px; 22 | } 23 | 24 | .calc-button { 25 | background-color: #d8d9db; 26 | color: black; 27 | height: 100px; 28 | width: 24.5%; 29 | border: none; 30 | border-radius: 0; 31 | font-size: 40px; 32 | cursor: pointer; 33 | } 34 | 35 | .calc-button:hover { 36 | background-color: #ebebeb; 37 | } 38 | 39 | .calc-button:active { 40 | background-color: #bbbcbe; 41 | } 42 | 43 | .double { 44 | width: 49.7%; 45 | } 46 | 47 | .triple { 48 | width: 74.8%; 49 | } 50 | 51 | .calc-button:last-child { 52 | background-color: #df974c; 53 | color: white; 54 | } 55 | 56 | .calc-button:last-child:hover { 57 | background-color: #dfb07e; 58 | } 59 | 60 | .calc-button:last-child:active { 61 | background-color: #dd8d37; 62 | } 63 | 64 | .calc-button-row { 65 | display: flex; 66 | align-content: stretch; 67 | justify-content: space-between; 68 | margin-bottom: 0.5%; 69 | } 70 | 71 | .calc-button-row:last-child { 72 | padding-bottom: 0; 73 | } 74 | -------------------------------------------------------------------------------- /static/calculator.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Calculator 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 | 0 16 |
17 | 18 |
19 |
20 | 21 | 22 | 23 |
24 |
25 | 26 | 27 | 28 | 29 |
30 |
31 | 32 | 33 | 34 | 35 |
36 |
37 | 38 | 39 | 40 | 41 |
42 |
43 | 44 | 45 |
46 |
47 |
48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /static/calculator.js: -------------------------------------------------------------------------------- 1 | let runningTotal = 0; 2 | let buffer = "0"; 3 | let previousOperator; 4 | const screen = document.querySelector(".screen"); 5 | 6 | function buttonClick(value) { 7 | if (isNaN(parseInt(value))) { 8 | handleSymbol(value); 9 | } else { 10 | handleNumber(value); 11 | } 12 | rerender(); 13 | } 14 | 15 | function handleNumber(value) { 16 | if (buffer === "0") { 17 | buffer = value; 18 | } else { 19 | buffer += value; 20 | } 21 | } 22 | 23 | function handleMath(value) { 24 | if (buffer === "0") { 25 | // do nothing 26 | return; 27 | } 28 | 29 | const intBuffer = parseInt(buffer); 30 | if (runningTotal === 0) { 31 | runningTotal = intBuffer; 32 | } else { 33 | flushOperation(intBuffer); 34 | } 35 | 36 | previousOperator = value; 37 | 38 | buffer = "0"; 39 | } 40 | 41 | function flushOperation(intBuffer) { 42 | if (previousOperator === "+") { 43 | runningTotal += intBuffer; 44 | } else if (previousOperator === "-") { 45 | runningTotal -= intBuffer; 46 | } else if (previousOperator === "×") { 47 | runningTotal *= intBuffer; 48 | } else { 49 | runningTotal /= intBuffer; 50 | } 51 | } 52 | 53 | function handleSymbol(value) { 54 | switch (value) { 55 | case "C": 56 | buffer = "0"; 57 | runningTotal = 0; 58 | break; 59 | case "=": 60 | if (previousOperator === null) { 61 | // need two numbers to do math 62 | return; 63 | } 64 | flushOperation(parseInt(buffer)); 65 | previousOperator = null; 66 | buffer = +runningTotal; 67 | runningTotal = 0; 68 | break; 69 | case "←": 70 | if (buffer.length === 1) { 71 | buffer = "0"; 72 | } else { 73 | buffer = buffer.substring(0, buffer.length - 1); 74 | } 75 | break; 76 | case "+": 77 | case "-": 78 | case "×": 79 | case "÷": 80 | handleMath(value); 81 | break; 82 | } 83 | } 84 | 85 | function rerender() { 86 | screen.innerText = buffer; 87 | } 88 | 89 | function init() { 90 | document 91 | .querySelector(".calc-buttons") 92 | .addEventListener("click", function(event) { 93 | buttonClick(event.target.innerText); 94 | }); 95 | } 96 | 97 | init(); 98 | -------------------------------------------------------------------------------- /static/dog-viewer/dog.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, 7 | Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; 8 | padding: 0; 9 | margin: 0; 10 | } 11 | 12 | nav { 13 | background-color: #ff4136; 14 | color: white; 15 | } 16 | 17 | .nav-list { 18 | display: flex; 19 | justify-content: space-between; 20 | align-items: center; 21 | padding: 30px; 22 | margin: 0; 23 | list-style: none; 24 | } 25 | 26 | .main-image { 27 | display: none; 28 | } 29 | 30 | .loading-dog { 31 | animation: spin 1s infinite linear; 32 | font-size: 50px; 33 | display: none; 34 | } 35 | 36 | .container { 37 | display: flex; 38 | align-items: center; 39 | justify-content: center; 40 | height: 80vh; 41 | overflow: hidden; 42 | } 43 | 44 | .main-image { 45 | max-width: 100%; 46 | max-height: 80vh; 47 | } 48 | 49 | @keyframes spin { 50 | to { 51 | transform: rotateZ(360deg); 52 | } 53 | } 54 | 55 | .show { 56 | display: block; 57 | } 58 | -------------------------------------------------------------------------------- /static/dog-viewer/dog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Dog Viewer 9 | 10 | 11 | 12 | 13 | 24 | 25 |
26 | main viewer 27 | 🐶 28 |
29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /static/dog-viewer/dog.js: -------------------------------------------------------------------------------- 1 | const main = document.getElementById("main"); 2 | const loader = document.getElementById("loader"); 3 | const breedSelect = document.getElementById("breed"); 4 | 5 | async function init() { 6 | // populate breed list 7 | const res = await fetch("https://dog.ceo/api/breeds/list/all"); 8 | const resJson = await res.json(); 9 | 10 | let breedOptions = ""; 11 | 12 | let breedList = Object.keys(resJson.message); 13 | 14 | for (let i = 0; i < breedList.length; i++) { 15 | breedOptions += ``; 16 | } 17 | 18 | breedSelect.innerHTML = breedOptions; 19 | 20 | // get first image 21 | const randomRes = await fetch("https://dog.ceo/api/breeds/image/random"); 22 | const randomResJson = await randomRes.json(); 23 | 24 | main.src = randomResJson.message; 25 | 26 | // add event listeners 27 | breedSelect.addEventListener("change", handleBreedChange); 28 | 29 | main.addEventListener("load", function() { 30 | main.classList.add("show"); 31 | loader.classList.remove("show"); 32 | }); 33 | } 34 | 35 | async function handleBreedChange(event) { 36 | const breed = event.target.value; 37 | 38 | main.classList.remove("show"); 39 | loader.classList.add("show"); 40 | 41 | const res = await fetch(` https://dog.ceo/api/breed/${breed}/images/random`); 42 | const resJson = await res.json(); 43 | 44 | main.src = resJson.message; 45 | } 46 | 47 | init(); 48 | -------------------------------------------------------------------------------- /static/doggos/doggos.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dogs 5 | 6 | 7 | 8 |

Doggos

9 | 10 |
11 |
12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /static/doggos/doggos.js: -------------------------------------------------------------------------------- 1 | const DOG_URL = "https://dog.ceo/api/breeds/image/random"; 2 | 3 | const doggos = document.querySelector(".doggos"); 4 | 5 | function addNewDoggo() { 6 | const promise = fetch(DOG_URL); 7 | promise 8 | .then(function(response) { 9 | const processingPromise = response.json(); 10 | return processingPromise; 11 | }) 12 | .then(function(processedResponse) { 13 | const img = document.createElement("img"); 14 | img.src = processedResponse.message; 15 | img.alt = "Cute doggo"; 16 | doggos.appendChild(img); 17 | }); 18 | } 19 | 20 | document.querySelector(".add-doggo").addEventListener("click", addNewDoggo); 21 | -------------------------------------------------------------------------------- /static/exercises/1-html/book excerpt.txt: -------------------------------------------------------------------------------- 1 | I. What It's All About 2 | 3 | Whence come the thousands of photographs used every month by newspapers and magazines? 4 | 5 | More than that, whence do the photographs come which are used by makers of calendars, postcards, for advertisements, and for illustrating books, stories and articles? 6 | --------------------------------- 7 | This little book is a practical, up-to-the-minute answer to the question: "How can I make my camera-work profitable?" 8 | 9 | A. H. Beardsley, 10 | Publisher, Photo-Era Magazine. 11 | ---------------------------------- 12 | 13 | At first thought, the answer is, "From professional photographers and publisher-photo-services." But professional photographers do not produce one-third of the photographs used, and publisher-photo-services are supplied by that same large number of camerists that supply publications with most of their prints. 14 | 15 | No one can deny that the greatest number of prints published are bought from amateur photographers in towns no larger than the average, and sometimes smaller. 16 | 17 | The camerist does not have to get in an air-ship and fly to Africa in order to produce photographs that will sell. Read what Waldon Fawcett says, himself a success at selling his photographs: 18 | 19 | "The photographer is apt to think that all his ambitions would be realised if only he could journey to foreign shores or to distant corners of our country; or if he could attend the spectacular events that focus the attention of the world now and then. [emphasize] This is a delusion. The real triumph is that of the photographer who utilises the material ready at hand in his own district, be it large or small."[end] 20 | 21 | And more, a person does not have to be an expert photographer in order to succeed at the work. Here is what one prominent writer says about it: 22 | 23 | "The requirements of the field are well within the capabilities of even the beginner in photography, viz.; the ability to make good negatives and good prints, the ability to recognise news-value, and a methodical plan to find the market where the prints will find acceptance. The man or woman who can meet these requirements should be fairly successful from the beginning, and will open up quickly new avenues of special work and profit." 24 | 25 | In short, ability to make metaphors, create lovely heroines or such is not at all necessary to the successful selling of photographs to publications. 26 | 27 | Is the field overcrowded? [emphasis]No.[end] If there were ten times as many persons engaged in the work they could all keep themselves busy. 28 | 29 | The field—how wide is it? Get out your map of the world. The field for [emphasis]making [end] photographs extends from the top margin to the bottom, and from the left to the right. The field for [emphasis]selling [end] photographs—which is more to the point—extends over about five thousand publications which use prints; not to speak of a few score of other markets. 30 | 31 | The markets may be classified briefly: 32 | 33 | (1) Newspapers 34 | (2) Magazines 35 | (3) Postcard-makers 36 | (4) Calendar-makers 37 | (5) Art-study producers 38 | (6) Illustrations for books 39 | (7) Illustrations for articles 40 | (8) Prints for advertising. 41 | 42 | And there are more, of more specialised branches. 43 | 44 | And how does it pay? Please note: "A certain magazine once paid $100 for four prints of sundials. An amateur, who happened to be on the spot with a kodak, made over $200 out of a head-on railroad-collision. A New York professional netted $125 from the newspaper-use of a wedding-party, of considerable local prominence, which was leaving the church after the ceremony." One amateur "realised $300 a year for two or three years from a lucky snapshot of eight pet rabbits in a row." 45 | 46 | A set of South-Pole photographs brought $3,000 from Leslie's and $1,000 more from the International Feature Service. These all, though, are very exceptional instances. The average print sells for about three dollars. But there is absolutely nothing in the world to hinder a wide-awake person with a camera from making from several hundred to over $3,000 a year from his prints. If he becomes a specialist he may earn as high as $5,000 or even more. 47 | 48 | No discrimination is made between press-photographers. The person wins who "delivers the goods." 49 | 50 | However, I do not mean that the instances of $200 or so for prints should be taken as the prices ordinarily paid. I do not maintain that there is a fortune awaiting the man with the camera; but I do say there are unlimited possibilities for salable photographs and almost an unlimited number of markets for them. But there are not "barrels of money" in it, for all. A person may add appreciably to his income for having sold photographs; and having developed the trade to a high degree, he may cash cheques to the amount of $5,000 or more a year. But not every one. Just some. And it isn't like the log and the falling off it. It's work—hard work—[emphasis]hard work.[end] 51 | 52 | Success at selling press-photographs does not depend on the size of the town you live in, the cost or manufacture of your apparatus, or on your literary ability. It depends on you and your worship of the homaged gods of success if you would sell photographs. The gift of these gods is the ability to make good. 53 | 54 | -------------------------------------- 55 | An excerpt from the book, "Making Your Camera Pay," by Frederick C. Davis. Copyright 1922, Robert M. McBride & Company, New York. Full book available online at Project Gutenberg (link to https://www.gutenberg.org/files/35709/35709-h/35709-h.htm) -------------------------------------------------------------------------------- /static/exercises/1-html/book.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |

What It's All About

11 | 12 |

Whence come the thousands of photographs used every month by newspapers and magazines?

13 | 14 |

More than that, whence do the photographs come which are used by makers of calendars, postcards, for advertisements, and for illustrating books, stories and articles?

15 |
16 |

This little book is a practical, up-to-the-minute answer to the question: "How can I make my camera-work profitable?"

17 | 18 | A. H. Beardsley,
19 | Publisher, Photo-Era Magazine.
20 |
21 | 22 |

At first thought, the answer is, "From professional photographers and publisher-photo-services." But professional photographers do not produce one-third of the photographs used, and publisher-photo-services are supplied by that same large number of camerists that supply publications with most of their prints.

23 | 24 |

No one can deny that the greatest number of prints published are bought from amateur photographers in towns no larger than the average, and sometimes smaller.

25 | 26 |

The camerist does not have to get in an air-ship and fly to Africa in order to produce photographs that will sell. Read what Waldon Fawcett says, himself a success at selling his photographs:

27 | 28 |
29 |

"The photographer is apt to think that all his ambitions would be realised if only he could journey to foreign shores or to distant corners of our country; or if he could attend the spectacular events that focus the attention of the world now and then. This is a delusion. The real triumph is that of the photographer who utilises the material ready at hand in his own district, be it large or small."

30 |
31 | 32 |

And more, a person does not have to be an expert photographer in order to succeed at the work. Here is what one prominent writer says about it:

33 | 34 |
35 |

"The requirements of the field are well within the capabilities of even the beginner in photography, viz.; the ability to make good negatives and good prints, the ability to recognise news-value, and a methodical plan to find the market where the prints will find acceptance. The man or woman who can meet these requirements should be fairly successful from the beginning, and will open up quickly new avenues of special work and profit."

36 |
37 | 38 |

In short, ability to make metaphors, create lovely heroines or such is not at all necessary to the successful selling of photographs to publications.

39 | 40 |

Is the field overcrowded? No. If there were ten times as many persons engaged in the work they could all keep themselves busy.

41 | 42 |

The field—how wide is it? Get out your map of the world. The field for making photographs extends from the top margin to the bottom, and from the left to the right. The field for selling photographs—which is more to the point—extends over about five thousand publications which use prints; not to speak of a few score of other markets.

43 | 44 |

The markets may be classified briefly:

45 |
    46 |
  1. Newspapers
  2. 47 |
  3. Magazines
  4. 48 |
  5. Postcard-makers
  6. 49 |
  7. Calendar-makers
  8. 50 |
  9. Art-study producers
  10. 51 |
  11. Illustrations for books
  12. 52 |
  13. Illustrations for articles
  14. 53 |
  15. Prints for advertising.
  16. 54 |
55 | 56 |

And there are more, of more specialised branches.

57 | 58 |

And how does it pay? Please note: "A certain magazine once paid $100 for four prints of sundials. An amateur, who happened to be on the spot with a kodak, made over $200 out of a head-on railroad-collision. A New York professional netted $125 from the newspaper-use of a wedding-party, of considerable local prominence, which was leaving the church after the ceremony." One amateur "realised $300 a year for two or three years from a lucky snapshot of eight pet rabbits in a row."

59 | 60 |

A set of South-Pole photographs brought $3,000 from Leslie's and $1,000 more from the International Feature Service. These all, though, are very exceptional instances. The average print sells for about three dollars. But there is absolutely nothing in the world to hinder a wide-awake person with a camera from making from several hundred to over $3,000 a year from his prints. If he becomes a specialist he may earn as high as $5,000 or even more.

61 | 62 |

No discrimination is made between press-photographers. The person wins who "delivers the goods."

63 | 64 |

However, I do not mean that the instances of $200 or so for prints should be taken as the prices ordinarily paid. I do not maintain that there is a fortune awaiting the man with the camera; but I do say there are unlimited possibilities for salable photographs and almost an unlimited number of markets for them. But there are not "barrels of money" in it, for all. A person may add appreciably to his income for having sold photographs; and having developed the trade to a high degree, he may cash cheques to the amount of $5,000 or more a year. But not every one. Just some. And it isn't like the log and the falling off it. It's work—hard work—hard work.

65 | 66 |

Success at selling press-photographs does not depend on the size of the town you live in, the cost or manufacture of your apparatus, or on your literary ability. It depends on you and your worship of the homaged gods of success if you would sell photographs. The gift of these gods is the ability to make good.

67 | 68 | 69 |
70 |

An excerpt from the book, "Making Your Camera Pay," by Frederick C. Davis. Copyright 1922, Robert M. McBride & Company, New York. Full book available online at Project Gutenberg.

71 |
72 | 73 | -------------------------------------------------------------------------------- /static/exercises/1-html/hobbies.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | My Great Hobbies 8 | 9 | 10 |

My Fine Hobbies

11 | 12 | 13 | 14 | Weird alien eating popcorn. 15 | 16 |
17 |

Some smart person said a really smart thing.

18 | Smart Person 19 |
20 | 21 |

Visit my home page.

22 |

I enjoy doing many things with my spare time. I don't have much spare time, but when I do, you can find me doing one of these things.

23 |
    24 |
  • Playing music
  • 25 |
  • Hiking
  • 26 |
  • Travel
  • 27 |
  • Teaching
  • 28 |
29 | 30 | -------------------------------------------------------------------------------- /static/exercises/1-html/images/blog1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/1-html/images/blog1.jpg -------------------------------------------------------------------------------- /static/exercises/1-html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | My first web page 8 | 9 | 10 |

All About Me

11 | 12 |

Visit my hobbies page.

13 | 14 |

Hello, world! My name is Jen. I live in Boston. Minneapolis is awesome.

15 | 16 |

Here is a picture of a kitten. Because my page is boring without a photo.

17 | 18 | Cute kitty cat. 19 | 20 |

One of my hobbies is playing the flute. I play in an orchestra back in Boston. We have a concert coming up on November 11.

21 | 22 |

Make a Peanut Butter and Jelly Sandwich

23 |
    24 |
  1. Get some peanut butter, jelly, and 2 pieces of bread.
  2. 25 |
  3. Spread peanut butter on one piece of bread and jelly on the other.
  4. 26 |
  5. Put the peanut butter and jelly together, with the bread side facing out.
  6. 27 |
  7. Eat and enjoy!
  8. 28 |
29 |

My Fine Links

30 | 31 |

My favorite website is Google.

32 | 33 |

My favorite music links

34 |

My favorite classical music websites

35 |
My favorite Beethoven music websites
36 |
My favorite website about Beethoven's 9th Symphony
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /static/exercises/2-css/begin/learningcss.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | My first web page 8 | 9 | 10 |

All About Me

11 | 12 |

Hello, world! My name is Jen. I live in Boston. Minneapolis is awesome. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam nostrum, ea consequatur quae impedit sunt cupiditate amet at saepe nulla consequuntur tenetur, repellendus commodi voluptates molestiae deserunt fugit? Consequuntur odit rem magni, veritatis distinctio unde. Tempore ad expedita fugit suscipit.

13 | 14 |
15 |

It's hard to make it easy, but it's easy to make it hard.

16 | Jen Kramer 17 |
18 | 19 |

Here is a picture of a kitten. Because my page is boring without a photo.

20 | 21 | Cute kitty cat. 22 | 23 |

Make a Peanut Butter and Jelly Sandwich

24 |
    25 |
  1. Get some peanut butter, jelly, and 2 pieces of bread.
  2. 26 |
  3. Spread peanut butter on one piece of bread and jelly on the other.
  4. 27 |
  5. Put the peanut butter and jelly together, with the bread side facing out.
  6. 28 |
  7. Eat and enjoy!
  8. 29 |
30 |

My Fine Links

31 |

These are a few links I really enjoy visiting.

32 | 38 |

More Blah Blah

39 | 40 |

Lorem ipsum dolor sit amet consectetur, adipisicing elit. Quasi maiores voluptates cum quis maxime blanditiis asperiores tempore totam ipsam dignissimos? Dolorem dolores illo dignissimos quasi facilis cupiditate, natus obcaecati error quaerat. Corporis ipsa maxime, soluta hic veniam unde ex rem illum ipsam!

41 |

Lorem ipsum dolor sit amet consectetur, adipisicing elit. Quasi maiores voluptates cum quis maxime blanditiis asperiores tempore totam ipsam dignissimos? Dolorem dolores illo dignissimos quasi facilis cupiditate, natus obcaecati error quaerat. Corporis ipsa maxime, soluta hic veniam unde ex rem illum ipsam!

42 | 43 |

More Blah Blah Detail

44 |

Lorem ipsum dolor sit amet consectetur, adipisicing elit. Quasi maiores voluptates cum quis maxime blanditiis asperiores tempore totam ipsam dignissimos? Dolorem dolores illo dignissimos quasi facilis cupiditate, natus obcaecati error quaerat. Corporis ipsa maxime, soluta hic veniam unde ex rem illum ipsam!

45 |

Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo reiciendis ut explicabo sint repudiandae eligendi culpa laboriosam exercitationem! Inventore tenetur doloremque quaerat illo aspernatur sunt aperiam, nam temporibus veritatis cum vel corporis repellendus eveniet optio mollitia ab voluptates consequatur perspiciatis quasi atque? Rerum architecto nobis dicta laudantium neque, accusantium sapiente.

46 | 47 | 48 | -------------------------------------------------------------------------------- /static/exercises/2-css/images/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/2-css/images/Logo.png -------------------------------------------------------------------------------- /static/exercises/2-css/images/blog1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/2-css/images/blog1.jpg -------------------------------------------------------------------------------- /static/exercises/2-css/images/blog2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/2-css/images/blog2.jpg -------------------------------------------------------------------------------- /static/exercises/2-css/images/blog3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/2-css/images/blog3.jpg -------------------------------------------------------------------------------- /static/exercises/2-css/in-class/css/style.css: -------------------------------------------------------------------------------- 1 | /* my first css */ 2 | 3 | body { 4 | font-family: Arial, Helvetica, sans-serif; 5 | background-color: #ffffcc; 6 | } 7 | img { 8 | border: 10px solid green; 9 | } 10 | h1 { 11 | border: 5px dotted red; 12 | color: white; 13 | background-color: black; 14 | text-align: center; 15 | } 16 | blockquote { 17 | font-family: Georgia, 'Times New Roman', Times, serif; 18 | font-size: 3rem; 19 | font-style: italic; 20 | text-align: center; 21 | background-image: url(http://placekitten.com/200/200); 22 | color: white; 23 | } 24 | p { 25 | color: #F25652; 26 | } 27 | #myid { 28 | color: purple; 29 | font-weight: bold; 30 | } 31 | cite { 32 | font-size: 1.5rem; 33 | font-weight: bold; 34 | color: black; 35 | background-color: white; 36 | } 37 | .bigbold { 38 | font-weight: bold; 39 | font-size: 1.3rem; 40 | } 41 | h2, h3, .bigbold, a:link { 42 | color: orange; 43 | } 44 | 45 | ol { 46 | color: green; 47 | } 48 | ul a:link { 49 | font-weight: bold; 50 | text-decoration: none; 51 | color: lightblue; 52 | font-size: 2rem; 53 | 54 | } 55 | a:visited { 56 | color: green; 57 | font-weight: normal; 58 | } 59 | a:hover { 60 | color: orange; 61 | text-decoration: underline; 62 | background-color: black; 63 | } 64 | a.harvard { 65 | color: maroon; 66 | } 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /static/exercises/2-css/in-class/learningcss.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | My first web page 8 | 13 | 14 | 15 | 16 | 17 |

All About Me

18 | 19 |

Hello, world! My name is Jen. I live in Boston. Minneapolis is awesome. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam nostrum, ea consequatur quae impedit sunt cupiditate amet at saepe nulla consequuntur tenetur, repellendus commodi voluptates molestiae deserunt fugit? Consequuntur odit rem magni, veritatis distinctio unde. Tempore ad expedita fugit suscipit.

20 | 21 |
22 |

It's hard to make it easy, but it's easy to make it hard.

23 | Jen Kramer 24 |
25 | 26 |

Here is a picture of a kitten. Because my page is boring without a photo.

27 | 28 | Cute kitty cat. 29 | 30 |

Make a Peanut Butter and Jelly Sandwich

31 |
    32 |
  1. Get some peanut butter, jelly, and 2 pieces of bread.
  2. 33 |
  3. Spread peanut butter on one piece of bread and jelly on the other.
  4. 34 |
  5. Put the peanut butter and jelly together, with the bread side facing out.
  6. 35 |
  7. Eat and enjoy!
  8. 36 |
37 |

My Fine Links

38 |

These are a few links I really enjoy visiting.

39 | 45 |

More Blah Blah

46 | 47 |

Lorem ipsum dolor sit amet consectetur, adipisicing elit. Quasi maiores voluptates cum quis maxime blanditiis asperiores tempore totam ipsam dignissimos? Dolorem dolores illo dignissimos quasi facilis cupiditate, natus obcaecati error quaerat. Corporis ipsa maxime, soluta hic veniam unde ex rem illum ipsam!

48 |

Lorem ipsum dolor sit amet consectetur, adipisicing elit. Quasi maiores voluptates cum quis maxime blanditiis asperiores tempore totam ipsam dignissimos? Dolorem dolores illo dignissimos quasi facilis cupiditate, natus obcaecati error quaerat. Corporis ipsa maxime, soluta hic veniam unde ex rem illum ipsam!

49 | 50 |

More Blah Blah Detail

51 |

Lorem ipsum dolor sit amet consectetur, adipisicing elit. Quasi maiores voluptates cum quis maxime blanditiis asperiores tempore totam ipsam dignissimos? Dolorem dolores illo dignissimos quasi facilis cupiditate, natus obcaecati error quaerat. Corporis ipsa maxime, soluta hic veniam unde ex rem illum ipsam!

52 |

Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo reiciendis ut explicabo sint repudiandae eligendi culpa laboriosam exercitationem! Inventore tenetur doloremque quaerat illo aspernatur sunt aperiam, nam temporibus veritatis cum vel corporis repellendus eveniet optio mollitia ab voluptates consequatur perspiciatis quasi atque? Rerum architecto nobis dicta laudantium neque, accusantium sapiente.

53 | 54 | 55 | -------------------------------------------------------------------------------- /static/exercises/3-layout.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout.zip -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-begin/blog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Alien Blog 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | Zorgblag's Blog. Click for home. 14 |
15 |
16 |

Zorgblag's Blog

17 |

My So-Called Light-Speed Life

18 |
19 |
20 | 29 |
30 |
31 | Earth-Vision Reality TV. 32 |

Why I still Watch Earth-Vision Reality TV

33 |

Posted October 15, 2018

34 |

Lots of my Alien friends have moved on from Earth-Vision Reality TV. I hear the same complaints all the time - its too repetitive, there aren’t enough abductions, our plants in high level governments are too obvious. Blah-blah-blah. You know what I say? They are just setting the stage for the next big chapter, and I can’t wait...

35 |

Read more >>

36 |
37 |
38 | Proper UFO Maintenance. 39 |

Proper UFO Maintenance

40 |

Posted October 5, 2018

41 |

Flying around the galaxy is all well and good, but if you’ve ever found yourself stranded in the middle of an anti-matter cloud for a few millennia, you’ll start wishing you had cared better for your UFO. Here are my top tricks to keep yourself at light speed.

42 |

Read more >>

43 |
44 |
45 |
46 |

Legal disclaimer, copyright, etc.

47 |
    48 |
  • Social Media 1.
  • 49 |
  • Social Media 2.
  • 50 |
  • Social Media 3.
  • 51 |
  • Social Media 4.
  • 52 |
  • Social Media 5.
  • 53 |
  • Social Media 6.
  • 54 |
  • Social Media 7.
  • 55 |
56 |
57 |
58 | 59 | -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-begin/css/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | } 4 | *, *:before, *:after { 5 | box-sizing: inherit; 6 | } 7 | body { 8 | font-family: 'Open Sans', sans-serif; 9 | } 10 | h1, h2, h3, h4, h5, h6 { 11 | font-family: 'Kavivanar', cursive; 12 | font-weight: normal; 13 | } 14 | h2 { 15 | font-size: 2rem; 16 | color: #A51F10; 17 | margin: 0; 18 | } 19 | a { 20 | color: #DA0090; 21 | text-decoration: none; 22 | } 23 | a:hover { 24 | text-decoration: underline; 25 | } 26 | .posted { 27 | font-size: 0.8rem; 28 | color: #89A611; 29 | } 30 | footer { 31 | text-align: center; 32 | font-size: 0.8rem; 33 | } 34 | -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-begin/img/blog1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-begin/img/blog1.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-begin/img/blog2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-begin/img/blog2.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-begin/img/blog3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-begin/img/blog3.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-begin/img/icon1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-begin/img/icon1.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-begin/img/icon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-begin/img/icon2.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-begin/img/icon3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-begin/img/icon3.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-begin/img/icon4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-begin/img/icon4.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-begin/img/icon5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-begin/img/icon5.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-begin/img/icon6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-begin/img/icon6.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-begin/img/icon7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-begin/img/icon7.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-begin/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-begin/img/logo.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-end/blog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Alien Blog 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | Zorgblag's Blog. Click for home. 14 |
15 |
16 |

Zorgblag's Blog

17 |

My So-Called Light-Speed Life

18 |
19 |
20 | 29 |
30 |
31 | Earth-Vision Reality TV. 32 |

Why I still Watch Earth-Vision Reality TV

33 |

Posted October 15, 2018

34 |

Lots of my Alien friends have moved on from Earth-Vision Reality TV. I hear the same complaints all the time - its too repetitive, there aren’t enough abductions, our plants in high level governments are too obvious. Blah-blah-blah. You know what I say? They are just setting the stage for the next big chapter, and I can’t wait...

35 |

Read more >>

36 |
37 |
38 | Proper UFO Maintenance. 39 |

Proper UFO Maintenance

40 |

Posted October 5, 2018

41 |

Flying around the galaxy is all well and good, but if you’ve ever found yourself stranded in the middle of an anti-matter cloud for a few millennia, you’ll start wishing you had cared better for your UFO. Here are my top tricks to keep yourself at light speed.

42 |

Read more >>

43 |
44 |
45 |
46 |

Legal disclaimer, copyright, etc.

47 |
    48 |
  • Social Media 1.
  • 49 |
  • Social Media 2.
  • 50 |
  • Social Media 3.
  • 51 |
  • Social Media 4.
  • 52 |
  • Social Media 5.
  • 53 |
  • Social Media 6.
  • 54 |
  • Social Media 7.
  • 55 |
56 |
57 |
58 | 59 | -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-end/css/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | } 4 | *, *:before, *:after { 5 | box-sizing: inherit; 6 | } 7 | body { 8 | font-family: 'Open Sans', sans-serif; 9 | } 10 | h1, h2, h3, h4, h5, h6 { 11 | font-family: 'Kavivanar', cursive; 12 | font-weight: normal; 13 | } 14 | h2 { 15 | font-size: 2rem; 16 | color: #A51F10; 17 | margin: 0; 18 | } 19 | a { 20 | color: #DA0090; 21 | text-decoration: none; 22 | } 23 | a:hover { 24 | text-decoration: underline; 25 | } 26 | .wrapper { 27 | width: 80%; 28 | margin: 0 auto; 29 | } 30 | header { 31 | display: flex; 32 | flex-flow: row nowrap; 33 | justify-content: space-between; 34 | } 35 | .leftheader { 36 | flex-basis: 40%; 37 | text-align: right; 38 | padding-right: 0.5rem; 39 | } 40 | .rightheader { 41 | flex-basis: 60%; 42 | margin-top: 3.75rem; 43 | padding-left: 0.5rem; 44 | } 45 | .rightheader h1 { 46 | margin: 0; 47 | color: #DA0090; 48 | font-size: 3em; 49 | } 50 | .rightheader p { 51 | margin-top: -0.5rem; 52 | } 53 | nav { 54 | border-bottom: 1px solid #A61F11; 55 | border-top: 1px solid #DA0090; 56 | } 57 | nav ul { 58 | margin: 0; 59 | padding: 0; 60 | list-style-type: none; 61 | text-align: center; 62 | } 63 | nav li { 64 | display: inline-block; 65 | } 66 | nav a { 67 | text-decoration: none; 68 | color: #73352E; 69 | display: block; 70 | padding: 0.5rem 1rem; 71 | } 72 | nav a:hover { 73 | background-color: black; 74 | color: #84DE37 75 | } 76 | section { 77 | border-bottom: 1px solid #DA0090; 78 | margin-bottom: 0.3rem; 79 | display: flex; 80 | flex-flow: column nowrap; 81 | } 82 | article { 83 | margin: 2rem 0; 84 | } 85 | article img { 86 | float: left; 87 | margin: 0 1rem 1rem 0; 88 | border-radius: 1rem; 89 | } 90 | article::after { 91 | content: ""; 92 | display: table; 93 | clear: both; 94 | } 95 | .posted { 96 | font-size: 0.8rem; 97 | color: #89A611; 98 | } 99 | footer { 100 | padding: 1rem 0 3rem 0; 101 | text-align: center; 102 | font-size: 0.8rem; 103 | border-top: 1px solid #A61F11; 104 | } 105 | footer ul { 106 | margin: 0; 107 | padding: 0; 108 | list-style-type: none; 109 | } 110 | footer li { 111 | display: inline-block; 112 | } -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-end/img/blog1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-end/img/blog1.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-end/img/blog2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-end/img/blog2.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-end/img/blog3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-end/img/blog3.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-end/img/icon1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-end/img/icon1.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-end/img/icon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-end/img/icon2.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-end/img/icon3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-end/img/icon3.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-end/img/icon4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-end/img/icon4.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-end/img/icon5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-end/img/icon5.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-end/img/icon6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-end/img/icon6.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-end/img/icon7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-end/img/icon7.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog-end/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog-end/img/logo.png -------------------------------------------------------------------------------- /static/exercises/3-layout/blog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/blog.png -------------------------------------------------------------------------------- /static/exercises/3-layout/boxmodel/Box Model Worksheet answers.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/boxmodel/Box Model Worksheet answers.docx -------------------------------------------------------------------------------- /static/exercises/3-layout/boxmodel/Box Model Worksheet answers.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/boxmodel/Box Model Worksheet answers.pdf -------------------------------------------------------------------------------- /static/exercises/3-layout/boxmodel/Box Model Worksheet.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/boxmodel/Box Model Worksheet.docx -------------------------------------------------------------------------------- /static/exercises/3-layout/boxmodel/Box Model Worksheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/3-layout/boxmodel/Box Model Worksheet.pdf -------------------------------------------------------------------------------- /static/exercises/4-forms.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/4-forms.zip -------------------------------------------------------------------------------- /static/exercises/4-forms/begin/css/forms.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | } 4 | *, *:before, *:after { 5 | box-sizing: inherit; 6 | } 7 | body { 8 | font-family: Arial, Helvetica, sans-serif; 9 | margin: 0; 10 | padding: 0; 11 | } 12 | .wrapper { 13 | width: 80%; 14 | margin: 0 auto; 15 | padding: 1em; 16 | display: flex; 17 | flex-flow: row nowrap; 18 | } 19 | p { 20 | margin-bottom: 0; 21 | margin-top: 2rem; 22 | } 23 | section { 24 | flex-basis: 57%; 25 | margin-right: 10%; 26 | } 27 | aside { 28 | flex-basis: 33%; 29 | } 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /static/exercises/4-forms/begin/forms.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Alien Abduction Order Form 6 | 7 | 8 | 9 |
10 |
11 |

Alien Abduction Order Form

12 |

Fill out the form below to place an order for an alien abduction by one of our fine UFOs.

13 |

Your contact information

14 |

Your name 15 |

Phone number

16 |

Email

17 | 18 |

About your abduction

19 |

Requested date

20 |

How many people would you like abducted?

21 |

What type of UFO do you prefer?

22 |
    23 |
  • Classic oval UFO
  • 24 |
  • Star Wars-style Imperial cruiser
  • 25 |
  • Battlestar Galactica-style Viper
  • 26 |
  • Borg-style cube
  • 27 |
28 |

What type of abduction experience do you want?

29 |
    30 |
  • Tour of the solar system
  • 31 |
  • Alien dinner and discussion
  • 32 |
  • Alien dance lessons
  • 33 |
  • Whale watching
  • 34 |
35 |

Special requests:

36 |

Add me to your email list

37 |
38 | 47 |
48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /static/exercises/4-forms/begin/img/galaxy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/4-forms/begin/img/galaxy.jpg -------------------------------------------------------------------------------- /static/exercises/4-forms/begin/img/image credit.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1561\cocoasubrtf600 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;} 3 | {\colortbl;\red255\green255\blue255;} 4 | {\*\expandedcolortbl;;} 5 | \margl1440\margr1440\vieww10800\viewh8400\viewkind0 6 | \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 7 | 8 | \f0\fs24 \cf0 https://images.nasa.gov/details-GSFC_20171208_Archive_e000056.html\ 9 | \ 10 | Photo caption: Galaxy cluster Abell 370 contains several hundred galaxies tied together by the mutual pull of gravity. Photographed in a combination of visible and near-infrared light, the brightest and largest galaxies are the yellow-white, massive, elliptical galaxies containing many hundreds of billions of stars each. Spiral galaxies have younger populations of stars and are bluish. Mysterious-looking arcs of blue light are distorted images of remote galaxies behind the cluster. The cluster acts as a huge lens in space that magnifies and stretches images of background galaxies like a funhouse mirror. Photo Credit: NASA, ESA, and J. Lotz and the HFF Team (STScI).} -------------------------------------------------------------------------------- /static/exercises/4-forms/begin/js/forms.js: -------------------------------------------------------------------------------- 1 | var form = document.getElementsByTagName("form")[0]; 2 | form.addEventListener("submit", function(e) { 3 | e.preventDefault(); 4 | sendData(); 5 | }); 6 | 7 | // https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript 8 | function sendData() { 9 | var XHR = new XMLHttpRequest(); 10 | var urlEncodedData = ""; 11 | var urlEncodedDataPairs = []; 12 | 13 | urlEncodedDataPairs.push( 14 | encodeURIComponent("name") + 15 | "=" + 16 | encodeURIComponent(form.querySelector("[name='name']").value) 17 | ); 18 | urlEncodedDataPairs.push( 19 | encodeURIComponent("send_to") + 20 | "=" + 21 | encodeURIComponent(form.querySelector("[name='send_to']").value) 22 | ); 23 | urlEncodedDataPairs.push( 24 | encodeURIComponent("email") + 25 | "=" + 26 | encodeURIComponent(form.querySelector("[name='email']").value) 27 | ); 28 | urlEncodedDataPairs.push( 29 | encodeURIComponent("phone") + 30 | "=" + 31 | encodeURIComponent(form.querySelector("[name='phone']").value) 32 | ); 33 | urlEncodedDataPairs.push( 34 | encodeURIComponent("date") + 35 | "=" + 36 | encodeURIComponent(form.querySelector("[name='date']").value) 37 | ); 38 | urlEncodedDataPairs.push( 39 | encodeURIComponent("qty") + 40 | "=" + 41 | encodeURIComponent(form.querySelector("[name='qty']").value) 42 | ); 43 | 44 | // radio buttons 45 | let radio = document.getElementsByName("ufotype"); 46 | for (var i = 0, length = radio.length; i < length; i++) { 47 | if (radio[i].checked) { 48 | urlEncodedDataPairs.push( 49 | encodeURIComponent("ufotype") + "=" + encodeURIComponent(radio[i].value) 50 | ); 51 | } 52 | } 53 | 54 | // dropdown menu 55 | var dropdown = form.querySelector("[name='abtype']"); 56 | urlEncodedDataPairs.push( 57 | encodeURIComponent("abtype") + 58 | "=" + 59 | encodeURIComponent(dropdown.options[dropdown.selectedIndex].text) 60 | ); 61 | urlEncodedDataPairs.push( 62 | encodeURIComponent("comments") + 63 | "=" + 64 | encodeURIComponent(form.querySelector("[name='comments']").value) 65 | ); 66 | urlEncodedDataPairs.push( 67 | encodeURIComponent("subscribe") + 68 | "=" + 69 | encodeURIComponent(form.querySelector("[name='subscribe']").checked) 70 | ); 71 | 72 | // Combine the pairs into a single string and replace all %-encoded spaces to 73 | // the '+' character; matches the behaviour of browser form submissions. 74 | urlEncodedData = urlEncodedDataPairs.join("&").replace(/%20/g, "+"); 75 | 76 | // Define what happens on successful data submission 77 | XHR.addEventListener("load", function(event) { 78 | if (XHR.readyState === XHR.DONE) { 79 | if (XHR.status === 200) { 80 | alert("Your order has been received! Check your email."); 81 | } else { 82 | alert("Oh oh! We have a problem! " + XHR.responseText + "."); 83 | } 84 | } 85 | }); 86 | 87 | // Define what happens in case of error 88 | XHR.addEventListener("error", function(event) { 89 | // This is normally a timeout or connection error. 90 | alert("Oops! Something went wrong."); 91 | }); 92 | 93 | // Set up our request 94 | XHR.open(form.getAttribute("method"), form.getAttribute("action")); 95 | 96 | // Add the required HTTP header for form data POST requests 97 | XHR.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 98 | 99 | // Finally, send our data. 100 | XHR.send(urlEncodedData); 101 | } 102 | -------------------------------------------------------------------------------- /static/exercises/4-forms/end/css/forms-end.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | } 4 | *, *:before, *:after { 5 | box-sizing: inherit; 6 | } 7 | body { 8 | font-family: Arial, Helvetica, sans-serif; 9 | background-image: url(../img/galaxy.jpg); 10 | margin: 0; 11 | padding: 0; 12 | } 13 | .wrapper { 14 | width: 80%; 15 | margin: 0 auto; 16 | padding: 1em; 17 | background-color: #EFB106; 18 | display: flex; 19 | flex-flow: row nowrap; 20 | } 21 | section { 22 | flex-basis: 57%; 23 | margin-right: 10%; 24 | } 25 | aside { 26 | flex-basis: 33%; 27 | } 28 | p, [for="abtype"] { 29 | margin-bottom: 0; 30 | margin-top: 2rem; 31 | } 32 | fieldset, #abtype { 33 | margin-bottom: 2rem; 34 | } 35 | fieldset { 36 | border: 1px solid black; 37 | border-radius: 10px; 38 | } 39 | legend { 40 | font-weight: bold; 41 | font-size: 1.3rem; 42 | margin-top: 1.5rem; 43 | margin-bottom: 1rem; 44 | display: block; 45 | } 46 | label { 47 | display: block; 48 | } 49 | input:not([type="radio"]):not([type="checkbox"]), 50 | textarea { 51 | display: block; 52 | margin-bottom: 2rem; 53 | width: 20rem; 54 | font-family: Arial, Helvetica, sans-serif; 55 | font-size: 1em; 56 | border-radius: 10px; 57 | padding: 0 1rem; 58 | } 59 | textarea { 60 | height: 10rem; 61 | padding: 1rem; 62 | } 63 | select { 64 | font-size: 1rem; 65 | } 66 | button { 67 | margin: 2rem 0; 68 | background-color: #BB342F; 69 | color: white; 70 | border: none; 71 | font-size: 1rem; 72 | padding: 0.5rem 1rem; 73 | border-radius: 10px; 74 | } 75 | button:hover { 76 | background-color: #9A2B27; 77 | } 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /static/exercises/4-forms/end/forms-end.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Alien Abduction Order Form 7 | 8 | 9 | 10 | 11 |
12 |
13 |

Alien Abduction Order Form

14 |

Fill out the form below to place an order for an alien abduction by one of our fine UFOs.

15 |
16 |
17 | Your contact information 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |
27 | About your abduction 28 | 29 | 30 | 31 | 32 | 33 |

What type of UFO do you prefer?

34 | 37 | 40 | 43 | 46 | 49 | 50 | 51 | 58 | 59 | 60 | 61 | 62 | 65 | 66 | 67 |
68 |
69 | 70 |
71 | 82 |
83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /static/exercises/4-forms/end/img/galaxy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/4-forms/end/img/galaxy.jpg -------------------------------------------------------------------------------- /static/exercises/4-forms/end/img/image credit.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1561\cocoasubrtf600 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;} 3 | {\colortbl;\red255\green255\blue255;} 4 | {\*\expandedcolortbl;;} 5 | \margl1440\margr1440\vieww10800\viewh8400\viewkind0 6 | \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 7 | 8 | \f0\fs24 \cf0 https://images.nasa.gov/details-GSFC_20171208_Archive_e000056.html\ 9 | \ 10 | Photo caption: Galaxy cluster Abell 370 contains several hundred galaxies tied together by the mutual pull of gravity. Photographed in a combination of visible and near-infrared light, the brightest and largest galaxies are the yellow-white, massive, elliptical galaxies containing many hundreds of billions of stars each. Spiral galaxies have younger populations of stars and are bluish. Mysterious-looking arcs of blue light are distorted images of remote galaxies behind the cluster. The cluster acts as a huge lens in space that magnifies and stretches images of background galaxies like a funhouse mirror. Photo Credit: NASA, ESA, and J. Lotz and the HFF Team (STScI).} -------------------------------------------------------------------------------- /static/exercises/4-forms/end/js/forms.js: -------------------------------------------------------------------------------- 1 | var form = document.getElementsByTagName("form")[0]; 2 | form.addEventListener("submit", function(e) { 3 | e.preventDefault(); 4 | sendData(); 5 | }); 6 | 7 | // https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript 8 | function sendData() { 9 | var XHR = new XMLHttpRequest(); 10 | var urlEncodedData = ""; 11 | var urlEncodedDataPairs = []; 12 | 13 | urlEncodedDataPairs.push( 14 | encodeURIComponent("name") + 15 | "=" + 16 | encodeURIComponent(form.querySelector("[name='name']").value) 17 | ); 18 | urlEncodedDataPairs.push( 19 | encodeURIComponent("send_to") + 20 | "=" + 21 | encodeURIComponent(form.querySelector("[name='send_to']").value) 22 | ); 23 | urlEncodedDataPairs.push( 24 | encodeURIComponent("email") + 25 | "=" + 26 | encodeURIComponent(form.querySelector("[name='email']").value) 27 | ); 28 | urlEncodedDataPairs.push( 29 | encodeURIComponent("phone") + 30 | "=" + 31 | encodeURIComponent(form.querySelector("[name='phone']").value) 32 | ); 33 | urlEncodedDataPairs.push( 34 | encodeURIComponent("date") + 35 | "=" + 36 | encodeURIComponent(form.querySelector("[name='date']").value) 37 | ); 38 | urlEncodedDataPairs.push( 39 | encodeURIComponent("qty") + 40 | "=" + 41 | encodeURIComponent(form.querySelector("[name='qty']").value) 42 | ); 43 | 44 | // radio buttons 45 | let radio = document.getElementsByName("ufotype"); 46 | for (var i = 0, length = radio.length; i < length; i++) { 47 | if (radio[i].checked) { 48 | urlEncodedDataPairs.push( 49 | encodeURIComponent("ufotype") + "=" + encodeURIComponent(radio[i].value) 50 | ); 51 | } 52 | } 53 | 54 | // dropdown menu 55 | var dropdown = form.querySelector("[name='abtype']"); 56 | urlEncodedDataPairs.push( 57 | encodeURIComponent("abtype") + 58 | "=" + 59 | encodeURIComponent(dropdown.options[dropdown.selectedIndex].text) 60 | ); 61 | urlEncodedDataPairs.push( 62 | encodeURIComponent("comments") + 63 | "=" + 64 | encodeURIComponent(form.querySelector("[name='comments']").value) 65 | ); 66 | urlEncodedDataPairs.push( 67 | encodeURIComponent("subscribe") + 68 | "=" + 69 | encodeURIComponent(form.querySelector("[name='subscribe']").checked) 70 | ); 71 | 72 | // Combine the pairs into a single string and replace all %-encoded spaces to 73 | // the '+' character; matches the behaviour of browser form submissions. 74 | urlEncodedData = urlEncodedDataPairs.join("&").replace(/%20/g, "+"); 75 | 76 | // Define what happens on successful data submission 77 | XHR.addEventListener("load", function(event) { 78 | if (XHR.readyState === XHR.DONE) { 79 | if (XHR.status === 200) { 80 | alert("Your order has been received! Check your email."); 81 | } else { 82 | alert("Oh oh! We have a problem! " + XHR.responseText + "."); 83 | } 84 | } 85 | }); 86 | 87 | // Define what happens in case of error 88 | XHR.addEventListener("error", function(event) { 89 | // This is normally a timeout or connection error. 90 | alert("Oops! Something went wrong."); 91 | }); 92 | 93 | // Set up our request 94 | XHR.open(form.getAttribute("method"), form.getAttribute("action")); 95 | 96 | // Add the required HTTP header for form data POST requests 97 | XHR.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 98 | 99 | // Finally, send our data. 100 | XHR.send(urlEncodedData); 101 | } 102 | -------------------------------------------------------------------------------- /static/exercises/5-github.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/5-github.zip -------------------------------------------------------------------------------- /static/exercises/5-github/begin/calculator.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Calculator 6 | 7 | 8 | 9 |
10 |
11 | 12 |
13 | 14 |
15 | 16 |
17 |
18 | 19 | -------------------------------------------------------------------------------- /static/exercises/5-github/begin/css/calculator.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | } 4 | *, *:before, *:after { 5 | box-sizing: inherit; 6 | } 7 | body { 8 | padding: 0; 9 | margin: 0; 10 | } 11 | .wrapper { 12 | width: 400px; 13 | } 14 | -------------------------------------------------------------------------------- /static/exercises/5-github/calculator instructions.txt: -------------------------------------------------------------------------------- 1 | We will work on creating a calculator for next week's work with JavaScript. 2 | 3 | Our goal is to create a calculator that looks exactly like the image calculator-spec.png, located in your day 5 folder. 4 | 5 | A few things to know about this calculator: 6 | 7 | * To get the symbols for math, you will need to look up their HTML codes. One place to do that is here: 8 | 9 | https://www.toptal.com/designers/htmlarrows/math/ 10 | 11 | https://www.toptal.com/designers/htmlarrows/arrows/ 12 | 13 | * The calculator buttons should be clickable. Next week, you'll program them. But for right now, somehow we need to code clickable buttons. 14 | 15 | * Colors used in this design include: 16 | 17 | - black: #000000 18 | - white: #ffffff 19 | - light grey: #d8d9db 20 | - buttons on hover: #ebebeb 21 | - button active state: #bbbcbe 22 | - function buttons: #df974c 23 | - function buttons on hover: #dfb07e 24 | - function button active state: #dd8d37 25 | 26 | * The overall width of this calculator is 400px. 27 | 28 | 29 | Suggested approach: 30 | * Create a wrapper with a width of 400px to set up the calculator. 31 | * Determine how many rows and columns we need. 32 | * Identify elements that occupy more than one column. 33 | * Determine the HTML tags required to code rows and cells. 34 | * Code a single row of 4 elements to start with and see if you can get that working. 35 | * Now add the other rows of 4 elements. 36 | * Finally, add the rows where there are fewer than 4 elements. What do you need to adjust to get these to work? 37 | * Once your layout is mostly working, add the colors and make it pretty. 38 | -------------------------------------------------------------------------------- /static/exercises/5-github/calculator-spec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/exercises/5-github/calculator-spec.png -------------------------------------------------------------------------------- /static/exercises/5-github/end/calculator.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Calculator 6 | 7 | 8 | 9 |
10 |
11 | 0 12 |
13 | 14 |
15 |
16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | 25 |
26 |
27 | 28 | 29 | 30 | 31 |
32 |
33 | 34 | 35 | 36 | 37 |
38 |
39 | 40 | 41 |
42 |
43 |
44 | 45 | -------------------------------------------------------------------------------- /static/exercises/5-github/end/css/calculator-jen.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | } 4 | *, *:before, *:after { 5 | box-sizing: inherit; 6 | } 7 | body { 8 | padding: 0; 9 | margin: 0; 10 | } 11 | .wrapper { 12 | display: flex; 13 | flex-flow: column nowrap; 14 | background-color: black; 15 | color: white; 16 | } 17 | .screen { 18 | color: white; 19 | font-size: 40px; 20 | font-family: "Courier New", Courier, monospace; 21 | text-align: right; 22 | padding: 20px 5px; 23 | flex-basis: 20%; 24 | } 25 | .calc-buttons { 26 | flex-basis: 80%; 27 | } 28 | .calc-button-row { 29 | display: flex; 30 | align-content: stretch; 31 | justify-content: space-between; 32 | margin-bottom: 0.5%; 33 | } 34 | .calc-button { 35 | background-color: #d8d9db; 36 | color: black; 37 | height: 100px; 38 | flex-basis: 24.5%; 39 | border: none; 40 | border-radius: 0; 41 | font-size: 40px; 42 | cursor: pointer; 43 | } 44 | .calc-button:hover { 45 | background-color: #ebebeb; 46 | } 47 | .calc-button:active { 48 | background-color: #bbbcbe; 49 | } 50 | .double { 51 | flex-basis: 49.7%; 52 | } 53 | .triple { 54 | flex-basis: 74.8%; 55 | } 56 | .calc-button:last-child { 57 | background-color: #df974c; 58 | color: white; 59 | } 60 | .calc-button:last-child:hover { 61 | background-color: #dfb07e; 62 | } 63 | 64 | .calc-button:last-child:active { 65 | background-color: #dd8d37; 66 | } 67 | .calc-button-row:last-child { 68 | padding-bottom: 0; 69 | } -------------------------------------------------------------------------------- /static/exercises/5-github/end/css/calculator.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | } 4 | *, *:before, *:after { 5 | box-sizing: inherit; 6 | } 7 | body { 8 | padding: 0; 9 | margin: 0; 10 | } 11 | .wrapper { 12 | width: 400px; 13 | background-color: black; 14 | color: white; 15 | } 16 | .screen { 17 | color: white; 18 | font-size: 40px; 19 | font-family: "Courier New", Courier, monospace; 20 | text-align: right; 21 | padding: 20px 5px; 22 | } 23 | .calc-button-row { 24 | display: flex; 25 | align-content: stretch; 26 | justify-content: space-between; 27 | margin-bottom: 0.5%; 28 | } 29 | .calc-button { 30 | background-color: #d8d9db; 31 | color: black; 32 | height: 100px; 33 | flex-basis: 24.5%; 34 | border: none; 35 | border-radius: 0; 36 | font-size: 40px; 37 | cursor: pointer; 38 | } 39 | .calc-button:hover { 40 | background-color: #ebebeb; 41 | } 42 | .calc-button:active { 43 | background-color: #bbbcbe; 44 | } 45 | .double { 46 | flex-basis: 49.7%; 47 | } 48 | .triple { 49 | flex-basis: 74.8%; 50 | } 51 | .calc-button:last-child { 52 | background-color: #df974c; 53 | color: white; 54 | } 55 | .calc-button:last-child:hover { 56 | background-color: #dfb07e; 57 | } 58 | 59 | .calc-button:last-child:active { 60 | background-color: #dd8d37; 61 | } 62 | .calc-button-row:last-child { 63 | padding-bottom: 0; 64 | } -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/favicon.ico -------------------------------------------------------------------------------- /static/fox-pet/bg/BG Lightening 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/bg/BG Lightening 1.png -------------------------------------------------------------------------------- /static/fox-pet/bg/BG Lightening 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/bg/BG Lightening 2.png -------------------------------------------------------------------------------- /static/fox-pet/bg/BUTTONS/Hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/bg/BUTTONS/Hover.png -------------------------------------------------------------------------------- /static/fox-pet/bg/BUTTONS/NotSelected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/bg/BUTTONS/NotSelected.png -------------------------------------------------------------------------------- /static/fox-pet/bg/BUTTONS/Selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/bg/BUTTONS/Selected.png -------------------------------------------------------------------------------- /static/fox-pet/bg/Canvas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/bg/Canvas.png -------------------------------------------------------------------------------- /static/fox-pet/bg/DAY.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/bg/DAY.png -------------------------------------------------------------------------------- /static/fox-pet/bg/DEAD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/bg/DEAD.png -------------------------------------------------------------------------------- /static/fox-pet/bg/FG lightening 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/bg/FG lightening 1.png -------------------------------------------------------------------------------- /static/fox-pet/bg/FG lightening 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/bg/FG lightening 2.png -------------------------------------------------------------------------------- /static/fox-pet/bg/FRAME.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/bg/FRAME.png -------------------------------------------------------------------------------- /static/fox-pet/bg/ICONS/Hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/bg/ICONS/Hover.png -------------------------------------------------------------------------------- /static/fox-pet/bg/ICONS/NotSelected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/bg/ICONS/NotSelected.png -------------------------------------------------------------------------------- /static/fox-pet/bg/ICONS/Selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/bg/ICONS/Selected.png -------------------------------------------------------------------------------- /static/fox-pet/bg/NIGHT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/bg/NIGHT.png -------------------------------------------------------------------------------- /static/fox-pet/bg/RAINY.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/bg/RAINY.png -------------------------------------------------------------------------------- /static/fox-pet/bg/rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/bg/rain.png -------------------------------------------------------------------------------- /static/fox-pet/fox.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | margin: 0; 7 | padding: 0; 8 | font-family: Arial, Helvetica, sans-serif; 9 | } 10 | 11 | .container { 12 | display: flex; 13 | align-items: center; 14 | justify-content: center; 15 | position: absolute; 16 | top: 0; 17 | left: 0; 18 | right: 0; 19 | bottom: 0; 20 | } 21 | 22 | .frame { 23 | height: 762px; 24 | width: 762px; 25 | position: relative; 26 | } 27 | 28 | .inner { 29 | position: relative; 30 | } 31 | 32 | .game { 33 | width: 628px; 34 | height: 577px; 35 | position: absolute; 36 | top: 62px; 37 | left: 67px; 38 | } 39 | 40 | .game.night { 41 | width: 716px; 42 | top: 62px; 43 | left: -19px; 44 | } 45 | 46 | .fox { 47 | position: absolute; 48 | top: 336px; 49 | left: 285px; 50 | overflow: hidden; 51 | } 52 | 53 | .fox-pooping { 54 | top: 319px; 55 | left: 159px; 56 | } 57 | 58 | .fox-celebrate { 59 | top: 290px; 60 | left: 290px; 61 | } 62 | 63 | .fox-rain { 64 | top: 362px; 65 | } 66 | 67 | .fox-hungry { 68 | top: 362px; 69 | } 70 | 71 | .fox-eating { 72 | top: 362px; 73 | } 74 | 75 | .fox-egg { 76 | top: 289px; 77 | left: 248px; 78 | } 79 | 80 | .fox-sleep { 81 | top: 351px; 82 | left: 445px; 83 | } 84 | 85 | .fox-dead { 86 | top: 380px; 87 | left: 243px; 88 | } 89 | 90 | .hidden { 91 | display: none; 92 | } 93 | 94 | .buttons { 95 | position: absolute; 96 | top: 674px; 97 | left: 266px; 98 | height: 71px; 99 | width: 228px; 100 | display: flex; 101 | align-items: center; 102 | justify-content: space-between; 103 | } 104 | 105 | .icons { 106 | position: absolute; 107 | top: 572px; 108 | left: 194px; 109 | height: 67px; 110 | width: 374px; 111 | display: flex; 112 | align-items: center; 113 | justify-content: space-between; 114 | } 115 | 116 | .poop-bag { 117 | position: absolute; 118 | top: 300px; 119 | left: 160px; 120 | } 121 | 122 | .modal-inner { 123 | background-color: blueviolet; 124 | color: white; 125 | padding: 20px; 126 | font-size: 20px; 127 | border-radius: 5px; 128 | } 129 | 130 | .modal { 131 | position: absolute; 132 | top: 0; 133 | left: 0; 134 | right: 0; 135 | } 136 | 137 | .modal:empty { 138 | display: none; 139 | } 140 | 141 | .modal-inner:empty { 142 | display: none; 143 | } 144 | -------------------------------------------------------------------------------- /static/fox-pet/fox.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Fox Pet 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 | 19 | 20 |
21 |
22 | 27 |
28 | 29 | 30 | 31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /static/fox-pet/fox.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | clock: 1, 3 | world: 0, 4 | icon: 0, 5 | enum: "INIT", 6 | timeToNextPoop: 0, 7 | timeToNextHungry: 0, 8 | timeToNextSleep: 0, 9 | timeToPoopKill: 0, 10 | timeToHungerKill: 0 11 | }; 12 | 13 | const ICONS = ["fish", "poop", "weather"]; 14 | 15 | const WORLDS = ["day", "rain"]; 16 | 17 | function changeWeather() { 18 | state.world = (1 + state.world) % WORLDS.length; 19 | modScene(WORLDS[state.world]); 20 | determineNextState(); 21 | } 22 | 23 | const writeToModal = text => 24 | (document.querySelector( 25 | ".modal" 26 | ).innerHTML = ``); 27 | 28 | const modFox = state => 29 | (document.querySelector(".fox").className = `fox fox-${state}`); 30 | 31 | const modScene = state => 32 | (document.querySelector(".game").className = `game ${state}`); 33 | 34 | const togglePoopBag = show => 35 | document.querySelector(".poop-bag").classList.toggle("hidden", !show); 36 | 37 | const getNextHungerTime = () => Math.floor(Math.random() + 6) + 3 + state.clock; 38 | const getNextPoopTime = () => Math.floor(Math.random() + 6) + 3 + state.clock; 39 | const getNextSleepTime = () => 40 | Math.floor(Math.random() * 30) + 30 + state.clock; 41 | 42 | function startGame() { 43 | writeToModal(""); 44 | modFox("egg"); 45 | modScene(WORLDS[state.world]); 46 | state.enum = "HATCHING"; 47 | setTimeout(wake, 5000); 48 | } 49 | 50 | function feed() { 51 | state.enum = "FEEDING"; 52 | state.timeToNextHungry = getNextHungerTime(); 53 | state.timeToHungerKill = 0; 54 | modFox("eating"); 55 | setTimeout(celebrate, 11000); 56 | } 57 | 58 | function cleanUpPoop() { 59 | if (state.timeToPoopKill) { 60 | state.timeToNextPoop = getNextPoopTime(); 61 | state.timeToPoopKill = 0; 62 | togglePoopBag(true); 63 | celebrate(); 64 | setTimeout(() => togglePoopBag(false), 4000); 65 | } 66 | } 67 | 68 | function die() { 69 | state.enum = "DEAD"; 70 | modScene("dead"); 71 | modFox("dead"); 72 | writeToModal("It died :(
Press the middle button to start"); 73 | } 74 | 75 | function sleep() { 76 | state.enum = "SLEEP"; 77 | state.timeToNextHungry = 0; 78 | state.timeToNextPoop = 0; 79 | state.timeToNextSleep = 0; 80 | state.timeToPoopKill = 0; 81 | state.timeToHungerKill = 0; 82 | state.timeToWake = getNextSleepTime(); 83 | modFox("sleep"); 84 | modScene("night"); 85 | } 86 | 87 | function wake() { 88 | state.enum = "IDLE"; 89 | state.timeToWake = 0; 90 | state.timeToPoopKill = 0; 91 | state.timeToHungerKill = 0; 92 | state.timeToNextHungry = getNextHungerTime(); 93 | state.timeToNextPoop = getNextPoopTime(); 94 | state.timeToNextSleep = getNextSleepTime(); 95 | modScene(WORLDS[state.world]); 96 | determineNextState(); 97 | } 98 | 99 | function poop() { 100 | state.enum = "POOPING"; 101 | state.timeToNextPoop = 0; 102 | state.timeToPoopKill = getNextPoopTime(); 103 | modFox("pooping"); 104 | setTimeout(function() { 105 | state.enum = "POOPED"; 106 | }, 5000); 107 | } 108 | 109 | function getHungry() { 110 | state.enum = "HUNGRY"; 111 | state.timeToHungerKill = getNextHungerTime(); 112 | state.timeToNextHungry = 0; 113 | modFox("hungry"); 114 | } 115 | 116 | function celebrate() { 117 | state.enum = "CELEBRATING"; 118 | modFox("celebrate"); 119 | setTimeout(function() { 120 | determineNextState(); 121 | }, 4000); 122 | } 123 | 124 | function determineNextState() { 125 | if (state.timeToHungerKill) { 126 | state.enum = "HUNGRY"; 127 | modFox("hungry"); 128 | state.enum = "HUNGRY"; 129 | } else if (state.timeToPoopKill) { 130 | modFox("pooped"); 131 | state.enum = "POOPED"; 132 | } else if (WORLDS[state.world] === "rain") { 133 | state.enum = "IDLE"; 134 | modFox("rain"); 135 | } else { 136 | state.enum = "IDLE"; 137 | modFox("idle"); 138 | } 139 | } 140 | 141 | function buttonClick({ target }) { 142 | if (target.classList.contains("left-btn")) { 143 | document 144 | .querySelector(`.${ICONS[state.icon]}-icon`) 145 | .classList.remove("highlighted"); 146 | state.icon = (2 + state.icon) % ICONS.length; 147 | document 148 | .querySelector(`.${ICONS[state.icon]}-icon`) 149 | .classList.add("highlighted"); 150 | } else if (target.classList.contains("right-btn")) { 151 | document 152 | .querySelector(`.${ICONS[state.icon]}-icon`) 153 | .classList.remove("highlighted"); 154 | state.icon = (1 + state.icon) % ICONS.length; 155 | document 156 | .querySelector(`.${ICONS[state.icon]}-icon`) 157 | .classList.add("highlighted"); 158 | } else { 159 | // can't do actions while in these states 160 | if ( 161 | ["POOPING", "SLEEP", "FEEDING", "CELEBRATING", "HATCHING"].includes( 162 | state.enum 163 | ) 164 | ) { 165 | // do nothing 166 | return; 167 | } 168 | 169 | if (state.enum === "INIT" || state.enum === "DEAD") { 170 | startGame(); 171 | return; 172 | } 173 | 174 | // execute the currently selected action 175 | switch (ICONS[state.icon]) { 176 | case "weather": 177 | changeWeather(); 178 | break; 179 | case "poop": 180 | cleanUpPoop(); 181 | break; 182 | case "fish": 183 | feed(); 184 | break; 185 | } 186 | } 187 | } 188 | 189 | function startTick() { 190 | requestAnimationFrame(tick); 191 | } 192 | 193 | let nextCheck = Date.now(); 194 | const CHECK_INTERVAL = 3000; 195 | async function tick() { 196 | const now = Date.now(); 197 | if (now > nextCheck) { 198 | console.log("check"); 199 | if ( 200 | ![ 201 | "POOPING", 202 | "FEEDING", 203 | "CELEBRATING", 204 | "HATCHING", 205 | "DEAD", 206 | "INIT" 207 | ].includes(state.enum) 208 | ) { 209 | console.log(state.clock); 210 | state.clock++; 211 | if (state.timeToNextHungry && state.timeToNextHungry < state.clock) { 212 | getHungry(); 213 | } else if (state.timeToNextPoop && state.timeToNextPoop < state.clock) { 214 | poop(); 215 | } else if ( 216 | state.timeToHungerKill && 217 | state.timeToHungerKill < state.clock 218 | ) { 219 | die(); 220 | } else if (state.timeToPoopKill && state.timeToPoopKill < state.clock) { 221 | die(); 222 | } else if (state.timeToNextSleep && state.timeToNextSleep < state.clock) { 223 | sleep(); 224 | } else if (state.timeToWake && state.timeToWake < state.clock) { 225 | wake(); 226 | } 227 | } 228 | nextCheck = now + CHECK_INTERVAL; 229 | } 230 | requestAnimationFrame(tick); 231 | } 232 | 233 | async function init() { 234 | document.querySelector(".buttons").addEventListener("click", buttonClick); 235 | startTick(); 236 | } 237 | 238 | init(); 239 | -------------------------------------------------------------------------------- /static/fox-pet/pet/AtRest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/pet/AtRest.png -------------------------------------------------------------------------------- /static/fox-pet/pet/Eating.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/pet/Eating.png -------------------------------------------------------------------------------- /static/fox-pet/pet/Egg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/pet/Egg.png -------------------------------------------------------------------------------- /static/fox-pet/pet/FoxBase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/pet/FoxBase.png -------------------------------------------------------------------------------- /static/fox-pet/pet/Hungry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/pet/Hungry.png -------------------------------------------------------------------------------- /static/fox-pet/pet/PoopBag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/pet/PoopBag.png -------------------------------------------------------------------------------- /static/fox-pet/pet/Pooping.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/pet/Pooping.png -------------------------------------------------------------------------------- /static/fox-pet/pet/Rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/pet/Rain.png -------------------------------------------------------------------------------- /static/fox-pet/pet/Sleeping.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/pet/Sleeping.png -------------------------------------------------------------------------------- /static/fox-pet/pet/TombStone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/pet/TombStone.png -------------------------------------------------------------------------------- /static/fox-pet/pet/Walking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/pet/Walking.png -------------------------------------------------------------------------------- /static/fox-pet/pet/Yay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/fox-pet/pet/Yay.png -------------------------------------------------------------------------------- /static/fox-pet/sprites.css: -------------------------------------------------------------------------------- 1 | .btn { 2 | background-image: url(bg/BUTTONS/NotSelected.png); 3 | background-position: 0px; 4 | width: 62px; 5 | height: 65px; 6 | overflow: hidden; 7 | background-repeat: no-repeat; 8 | background-color: transparent; 9 | border-color: transparent; 10 | cursor: pointer; 11 | } 12 | 13 | .btn.middle-btn { 14 | background-position: -84px 0px; 15 | } 16 | 17 | .btn.right-btn { 18 | background-position: -167px 0px; 19 | } 20 | 21 | .btn:hover, 22 | .btn:focus { 23 | background-image: url(bg/BUTTONS/Hover.png); 24 | } 25 | 26 | .btn:active { 27 | background-image: url(bg/BUTTONS/Selected.png); 28 | } 29 | 30 | .icon { 31 | background-image: url(bg/ICONS/NotSelected.png); 32 | background-position: 0px; 33 | width: 56px; 34 | height: 65px; 35 | overflow: hidden; 36 | background-repeat: no-repeat; 37 | background-color: transparent; 38 | border-color: transparent; 39 | } 40 | 41 | .icon.poop-icon { 42 | background-position: -162px 0px; 43 | } 44 | 45 | .icon.weather-icon { 46 | background-position: -323px 0px; 47 | } 48 | 49 | .icon.highlighted { 50 | background-image: url(bg/ICONS/Hover.png); 51 | } 52 | 53 | .icon.active { 54 | background-image: url(bg/ICONS/Selected.png); 55 | } 56 | 57 | .fox-static { 58 | background-image: url(./pet/FoxBase.png); 59 | width: 117px; 60 | height: 165px; 61 | } 62 | 63 | .fox-idle { 64 | background-image: url(./pet/AtRest.png); 65 | background-repeat: no-repeat; 66 | width: 117px; 67 | height: 165px; 68 | animation: idle 2s steps(3) infinite; 69 | } 70 | 71 | @keyframes idle { 72 | to { 73 | background-position: -372px; 74 | } 75 | } 76 | 77 | .fox.fox-pooping { 78 | background-image: url(./pet/Pooping.png); 79 | background-position: -1836px; 80 | background-repeat: no-repeat; 81 | width: 204px; 82 | height: 202px; 83 | animation: pooping 5s steps(10); 84 | } 85 | 86 | .fox.fox-pooped { 87 | background-image: url(./pet/Pooping.png); 88 | background-position: -1836px; 89 | background-repeat: no-repeat; 90 | width: 204px; 91 | height: 202px; 92 | } 93 | 94 | @keyframes pooping { 95 | from { 96 | background-position: 0; 97 | } 98 | to { 99 | background-position: -2040px; 100 | } 101 | } 102 | 103 | .fox-celebrate.fox { 104 | background-image: url(./pet/Yay.png); 105 | background-repeat: no-repeat; 106 | width: 130.8px; 107 | height: 213px; 108 | animation: celebrate 2s steps(5) infinite; 109 | } 110 | 111 | @keyframes celebrate { 112 | to { 113 | background-position: -654px; 114 | } 115 | } 116 | 117 | .fox-rain.fox { 118 | background-image: url(./pet/Rain.png); 119 | background-repeat: no-repeat; 120 | width: 134px; 121 | height: 153px; 122 | animation: sit-in-the-rain 2s steps(5) infinite alternate; 123 | } 124 | 125 | @keyframes sit-in-the-rain { 126 | to { 127 | background-position: -670px; 128 | } 129 | } 130 | 131 | .fox-hungry.fox { 132 | background-image: url(./pet/Hungry.png); 133 | background-repeat: no-repeat; 134 | width: 130px; 135 | height: 160px; 136 | animation: hungry 1s steps(2) infinite; 137 | } 138 | 139 | @keyframes hungry { 140 | to { 141 | background-position: -260px; 142 | } 143 | } 144 | 145 | .fox-eating.fox { 146 | background-image: url(./pet/Eating.png); 147 | background-position: -1865.7px; 148 | background-repeat: no-repeat; 149 | width: 207.3px; 150 | height: 148px; 151 | animation: eating 10s steps(10); 152 | } 153 | 154 | @keyframes eating { 155 | from { 156 | background-position: 0; 157 | } 158 | to { 159 | background-position: -2073px; 160 | } 161 | } 162 | 163 | .fox-egg.fox { 164 | background-image: url(./pet/Egg.png); 165 | background-repeat: no-repeat; 166 | background-position: -1050px; 167 | width: 175px; 168 | height: 217px; 169 | animation: hatching 4s steps(7); 170 | } 171 | 172 | @keyframes hatching { 173 | from { 174 | background-position: 0; 175 | } 176 | to { 177 | background-position: -1225px; 178 | } 179 | } 180 | 181 | .fox-dead.fox { 182 | background-image: url(./pet/TombStone.png); 183 | background-repeat: no-repeat; 184 | width: 118px; 185 | height: 119px; 186 | animation: being-dead 1s steps(3) infinite; 187 | } 188 | 189 | @keyframes being-dead { 190 | to { 191 | background-position: -354px; 192 | } 193 | } 194 | 195 | .fox-sleep.fox { 196 | background-image: url(./pet/Sleeping.png); 197 | background-repeat: no-repeat; 198 | width: 250px; 199 | height: 155px; 200 | animation: sleeping 4s steps(4) infinite; 201 | } 202 | 203 | @keyframes sleeping { 204 | to { 205 | background-position: -1000px; 206 | } 207 | } 208 | 209 | .foreground-rain { 210 | display: none; 211 | background-image: url(./bg/rain.png); 212 | animation: raining 0.5s steps(3) infinite; 213 | width: 606px; 214 | height: 516px; 215 | overflow: hidden; 216 | position: absolute; 217 | top: 56px; 218 | left: 60px; 219 | } 220 | 221 | .rain ~ .foreground-rain { 222 | display: block; 223 | } 224 | 225 | @keyframes raining { 226 | to { 227 | background-position: -1818px; 228 | } 229 | } 230 | 231 | .poop-bag { 232 | background-image: url(./pet/PoopBag.png); 233 | animation: swing-poop-bag 1s steps(3) infinite alternate; 234 | width: 99px; 235 | height: 104px; 236 | overflow: hidden; 237 | } 238 | 239 | @keyframes swing-poop-bag { 240 | to { 241 | background-position: -297px; 242 | } 243 | } 244 | 245 | .frame { 246 | background-image: url(./bg/FRAME.png); 247 | } 248 | 249 | .game { 250 | background-image: url(./bg/DAY.png); 251 | } 252 | 253 | .game.night { 254 | background-image: url(./bg/NIGHT.png); 255 | } 256 | 257 | .game.dead { 258 | background-image: url(./bg/DEAD.png); 259 | } 260 | 261 | .game.rain { 262 | background-image: url(./bg/RAINY.png); 263 | } 264 | 265 | body { 266 | background-image: url(./bg/Canvas.png); 267 | } 268 | -------------------------------------------------------------------------------- /static/gallery/gallery.js: -------------------------------------------------------------------------------- 1 | let currentlySelected = 0; 2 | const nodes = document.querySelectorAll(".gallery-img"); 3 | const prevBtn = document.querySelector(".prev"); 4 | const nextBtn = document.querySelector(".next"); 5 | 6 | function previous() { 7 | nextBtn.disabled = false; 8 | nodes[currentlySelected].classList.remove("active"); 9 | currentlySelected--; 10 | nodes[currentlySelected].classList.add("active"); 11 | 12 | if (currentlySelected === 0) { 13 | prevBtn.disabled = true; 14 | } 15 | } 16 | 17 | function next() { 18 | prevBtn.disabled = false; 19 | nodes[currentlySelected].classList.remove("active"); 20 | currentlySelected++; 21 | nodes[currentlySelected].classList.add("active"); 22 | 23 | if (currentlySelected + 1 === nodes.length) { 24 | nextBtn.disabled = true; 25 | } 26 | } 27 | 28 | function init() { 29 | prevBtn.addEventListener("click", function() { 30 | previous(); 31 | }); 32 | 33 | nextBtn.addEventListener("click", function(e) { 34 | next(); 35 | }); 36 | } 37 | 38 | init(); 39 | -------------------------------------------------------------------------------- /static/gallery/images/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/gallery/images/1.jpg -------------------------------------------------------------------------------- /static/gallery/images/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/gallery/images/10.jpg -------------------------------------------------------------------------------- /static/gallery/images/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/gallery/images/11.jpg -------------------------------------------------------------------------------- /static/gallery/images/12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/gallery/images/12.jpg -------------------------------------------------------------------------------- /static/gallery/images/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/gallery/images/2.jpg -------------------------------------------------------------------------------- /static/gallery/images/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/gallery/images/3.jpg -------------------------------------------------------------------------------- /static/gallery/images/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/gallery/images/4.jpg -------------------------------------------------------------------------------- /static/gallery/images/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/gallery/images/5.jpg -------------------------------------------------------------------------------- /static/gallery/images/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/gallery/images/6.jpg -------------------------------------------------------------------------------- /static/gallery/images/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/gallery/images/7.jpg -------------------------------------------------------------------------------- /static/gallery/images/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/gallery/images/8.jpg -------------------------------------------------------------------------------- /static/gallery/images/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/gallery/images/9.jpg -------------------------------------------------------------------------------- /static/gallery/images/bh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/gallery/images/bh.png -------------------------------------------------------------------------------- /static/gallery/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Gallery 8 | 9 | 10 | 11 | 25 |
26 | 27 | 28 |
29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /static/gallery/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | .swiper-slide { 6 | text-align: center; 7 | } 8 | 9 | img { 10 | height: 600px; 11 | } 12 | 13 | .gallery-img { 14 | display: none; 15 | } 16 | 17 | .active { 18 | display: block; 19 | } 20 | 21 | .image-gallery { 22 | width: 100%; 23 | display: flex; 24 | justify-content: center; 25 | align-items: center; 26 | } 27 | 28 | .btns { 29 | width: 100%; 30 | display: flex; 31 | justify-content: center; 32 | align-items: center; 33 | } 34 | 35 | .btn { 36 | background-color: #0074d9; 37 | color: white; 38 | font-size: 20px; 39 | padding: 5px 20px; 40 | border-color: transparent; 41 | border-radius: 5px; 42 | cursor: pointer; 43 | } 44 | 45 | .prev { 46 | margin-right: 15px; 47 | } 48 | 49 | .btn:disabled { 50 | background-color: #666; 51 | cursor: not-allowed; 52 | } 53 | 54 | body { 55 | padding: 0; 56 | margin: 0; 57 | } 58 | 59 | .main-nav { 60 | background-color: black; 61 | color: white; 62 | margin: 0; 63 | font-family: Arial, Helvetica, sans-serif; 64 | padding: 15px; 65 | } 66 | 67 | .brand { 68 | margin: 0; 69 | font-size: 50px; 70 | z-index: 10; 71 | cursor: grab; 72 | background-color: white; 73 | border-radius: 50%; 74 | width: 75px; 75 | height: 75px; 76 | border: 1px solid #666; 77 | } 78 | -------------------------------------------------------------------------------- /static/gallery/with-libraries.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Gallery 8 | 12 | 13 | 14 | 15 | 18 |
19 |
20 |
Luna
21 |
Luna
22 |
Luna
23 |
Luna
24 |
Luna
25 |
Luna
26 |
Luna
27 |
Luna
28 |
Luna
29 |
Luna
30 |
Luna
31 |
Luna
32 |
33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /static/gallery/with-libraries.js: -------------------------------------------------------------------------------- 1 | new Swiper(".swiper-container", { 2 | speed: 400, 3 | spaceBetween: 100, 4 | navigation: { 5 | nextEl: ".swiper-button-next", 6 | prevEl: ".swiper-button-prev" 7 | }, 8 | slidesPerView: 1 9 | }); 10 | 11 | // logo 12 | const { styler, spring, listen, pointer, value } = window.popmotion; 13 | 14 | const ball = document.querySelector(".brand"); 15 | const divStyler = styler(ball); 16 | const ballXY = value({ x: 0, y: 0 }, divStyler.set); 17 | 18 | listen(ball, "mousedown touchstart").start(e => { 19 | e.preventDefault(); 20 | pointer(ballXY.get()).start(ballXY); 21 | }); 22 | 23 | listen(document, "mouseup touchend").start(() => { 24 | spring({ 25 | from: ballXY.get(), 26 | velocity: ballXY.getVelocity(), 27 | to: { x: 0, y: 0 }, 28 | stiffness: 200 29 | }).start(ballXY); 30 | }); 31 | -------------------------------------------------------------------------------- /static/layout/37DE85_0_0.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/layout/37DE85_0_0.eot -------------------------------------------------------------------------------- /static/layout/37DE85_0_0.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/layout/37DE85_0_0.ttf -------------------------------------------------------------------------------- /static/layout/37DE85_0_0.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/layout/37DE85_0_0.woff -------------------------------------------------------------------------------- /static/layout/37DE85_0_0.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/layout/37DE85_0_0.woff2 -------------------------------------------------------------------------------- /static/layout/Scratch_texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/layout/Scratch_texture.png -------------------------------------------------------------------------------- /static/layout/TreeBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/layout/TreeBG.png -------------------------------------------------------------------------------- /static/layout/fm-vector-optimized.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/layout/logoBurst.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/layout/logoBurst.png -------------------------------------------------------------------------------- /static/layout/postIT_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/layout/postIT_bg.png -------------------------------------------------------------------------------- /static/mole-game/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/mole-game/background.png -------------------------------------------------------------------------------- /static/mole-game/cursor-worm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/mole-game/cursor-worm.png -------------------------------------------------------------------------------- /static/mole-game/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/mole-game/cursor.png -------------------------------------------------------------------------------- /static/mole-game/king-mole-fed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/mole-game/king-mole-fed.png -------------------------------------------------------------------------------- /static/mole-game/king-mole-hungry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/mole-game/king-mole-hungry.png -------------------------------------------------------------------------------- /static/mole-game/king-mole-leaving.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/mole-game/king-mole-leaving.png -------------------------------------------------------------------------------- /static/mole-game/king-mole-sad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/mole-game/king-mole-sad.png -------------------------------------------------------------------------------- /static/mole-game/mole-fed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/mole-game/mole-fed.png -------------------------------------------------------------------------------- /static/mole-game/mole-hungry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/mole-game/mole-hungry.png -------------------------------------------------------------------------------- /static/mole-game/mole-leaving.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/mole-game/mole-leaving.png -------------------------------------------------------------------------------- /static/mole-game/mole-sad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/mole-game/mole-sad.png -------------------------------------------------------------------------------- /static/mole-game/mole.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | cursor: url(./cursor.png), default; 7 | background-color: #c0c86d; 8 | display: flex; 9 | justify-content: center; 10 | align-items: center; 11 | flex-direction: column; 12 | padding: 0; 13 | margin: 0; 14 | height: 100vh; 15 | width: 100vw; 16 | } 17 | 18 | .bg { 19 | background-image: url(./background.png); 20 | background-repeat: no-repeat; 21 | width: 1920px; 22 | height: 1080px; 23 | display: flex; 24 | flex-wrap: wrap; 25 | justify-content: center; 26 | align-items: center; 27 | } 28 | 29 | .hole { 30 | background: black; 31 | border-radius: 50%; 32 | overflow: visible; 33 | width: 267px; 34 | height: 267px; 35 | } 36 | 37 | .hole-container { 38 | width: 25%; 39 | display: flex; 40 | justify-content: center; 41 | align-items: center; 42 | } 43 | 44 | .mole { 45 | position: relative; 46 | right: 30px; 47 | } 48 | 49 | .hungry { 50 | cursor: url(./cursor-worm.png), pointer; 51 | } 52 | 53 | .gone { 54 | display: none; 55 | } 56 | 57 | .worm { 58 | width: 1660px; 59 | } 60 | 61 | .worm-container { 62 | overflow: hidden; 63 | transition: width 0.5s ease-in-out; 64 | } 65 | 66 | .worm-box { 67 | width: 1660px; 68 | } 69 | 70 | .win { 71 | max-width: 100vw; 72 | max-height: 100vh; 73 | display: none; 74 | } 75 | 76 | .hide { 77 | display: none; 78 | } 79 | 80 | .show { 81 | display: block; 82 | } 83 | -------------------------------------------------------------------------------- /static/mole-game/mole.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Star Moles! 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 | worm meter 17 |
18 |
19 |
20 |
mole
21 |
22 |
23 |
mole
24 |
25 |
26 |
mole
27 |
28 |
29 |
mole
30 |
31 |
32 |
mole
33 |
34 |
35 |
mole
36 |
37 |
38 |
mole
39 |
40 |
41 |
mole
42 |
43 |
44 |
mole
45 |
46 |
47 |
happy mole
48 |
49 |
50 | mole 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /static/mole-game/mole.js: -------------------------------------------------------------------------------- 1 | const MIN_INTERVAL = 2000; 2 | const MAX_INTERVAL = 20000; 3 | const SAD_INTERVAL = 500; 4 | const HUNGRY_INTERVAL = 2000; 5 | const wormContainer = document.querySelector(".worm-container"); 6 | let score = 0; 7 | 8 | const getInterval = () => 9 | Date.now() + MIN_INTERVAL + Math.floor(Math.random() * MAX_INTERVAL); 10 | const getSadInterval = () => Date.now() + SAD_INTERVAL; 11 | const getKingStatus = () => Math.random() > 0.9; 12 | const getHungryInterval = () => Date.now() + HUNGRY_INTERVAL; 13 | 14 | const moles = [ 15 | { 16 | status: "sad", 17 | next: getSadInterval(), 18 | king: true, 19 | node: document.getElementById("hole-0") 20 | }, 21 | { 22 | status: "sad", 23 | next: getSadInterval(), 24 | king: true, 25 | node: document.getElementById("hole-1") 26 | }, 27 | { 28 | status: "sad", 29 | next: getSadInterval(), 30 | king: true, 31 | node: document.getElementById("hole-2") 32 | }, 33 | { 34 | status: "sad", 35 | next: getSadInterval(), 36 | king: true, 37 | node: document.getElementById("hole-3") 38 | }, 39 | { 40 | status: "sad", 41 | next: getSadInterval(), 42 | king: true, 43 | node: document.getElementById("hole-4") 44 | }, 45 | { 46 | status: "sad", 47 | next: getSadInterval(), 48 | king: true, 49 | node: document.getElementById("hole-5") 50 | }, 51 | { 52 | status: "sad", 53 | next: getSadInterval(), 54 | king: true, 55 | node: document.getElementById("hole-6") 56 | }, 57 | { 58 | status: "sad", 59 | next: getSadInterval(), 60 | king: true, 61 | node: document.getElementById("hole-7") 62 | }, 63 | { 64 | status: "sad", 65 | next: getSadInterval(), 66 | king: true, 67 | node: document.getElementById("hole-8") 68 | }, 69 | { 70 | status: "sad", 71 | next: getSadInterval(), 72 | king: true, 73 | node: document.getElementById("hole-9") 74 | } 75 | ]; 76 | 77 | const getNextStatus = mole => { 78 | switch (mole.status) { 79 | case "sad": 80 | case "fed": 81 | mole.next = getSadInterval(); 82 | if (mole.king) { 83 | mole.node.children[0].src = "./king-mole-leaving.png"; 84 | } else { 85 | mole.node.children[0].src = "./mole-leaving.png"; 86 | } 87 | mole.status = "leaving"; 88 | break; 89 | case "leaving": 90 | mole.next = getInterval(); 91 | mole.king = false; 92 | mole.node.children[0].classList.toggle("gone", true); 93 | mole.status = "gone"; 94 | break; 95 | case "hungry": 96 | mole.node.children[0].classList.toggle("hungry", false); 97 | if (mole.king) { 98 | mole.node.children[0].src = "./king-mole-sad.png"; 99 | } else { 100 | mole.node.children[0].src = "./mole-sad.png"; 101 | } 102 | mole.status = "sad"; 103 | mole.next = getSadInterval(); 104 | break; 105 | case "gone": 106 | mole.status = "hungry"; 107 | mole.king = getKingStatus(); 108 | mole.next = getHungryInterval(); 109 | mole.node.children[0].classList.toggle("hungry", true); 110 | mole.node.children[0].classList.toggle("gone", false); 111 | if (mole.king) { 112 | mole.node.children[0].src = "./king-mole-hungry.png"; 113 | } else { 114 | mole.node.children[0].src = "./mole-hungry.png"; 115 | } 116 | break; 117 | } 118 | }; 119 | 120 | const feed = e => { 121 | if (e.target.tagName !== "IMG" || !e.target.classList.contains("hungry")) { 122 | return; 123 | } 124 | 125 | const mole = moles[+e.target.dataset.index]; 126 | 127 | mole.status = "fed"; 128 | mole.next = getSadInterval(); 129 | mole.node.children[0].classList.toggle("hungry", false); 130 | if (mole.king) { 131 | mole.node.children[0].src = "./king-mole-fed.png"; 132 | score += 20; 133 | } else { 134 | mole.node.children[0].src = "./mole-fed.png"; 135 | score += 10; 136 | } 137 | 138 | if (score >= 100) { 139 | win(); 140 | return; 141 | } 142 | 143 | wormContainer.style.width = `${score}%`; 144 | }; 145 | 146 | const win = () => { 147 | document.querySelector(".bg").classList.toggle("hide", true); 148 | document.querySelector(".win").classList.toggle("show", true); 149 | }; 150 | 151 | document.querySelector(".bg").addEventListener("click", feed); 152 | 153 | const nextFrame = () => { 154 | const now = Date.now(); 155 | for (let i = 0; i < moles.length; i++) { 156 | if (moles[i].next < now) { 157 | getNextStatus(moles[i]); 158 | } 159 | } 160 | requestAnimationFrame(nextFrame); 161 | }; 162 | 163 | requestAnimationFrame(nextFrame); 164 | -------------------------------------------------------------------------------- /static/mole-game/win.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/mole-game/win.png -------------------------------------------------------------------------------- /static/mole-game/worm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrontendMasters/bootcamp/998ffbceac4002b11952dcfcd4aa9b9280e7f025/static/mole-game/worm.png --------------------------------------------------------------------------------