├── 4geeks.ico ├── preview.gif ├── public └── assets │ └── img │ ├── 4geeks.ico │ └── rigo-baby.jpg ├── .learn └── config.json ├── .gitignore ├── .gitpod.yml ├── .github └── workflows │ └── validate-integrity.yml ├── .gitpod.Dockerfile ├── .eslintrc ├── .devcontainer └── devcontainer.json ├── _utils ├── clean-stack.js └── prettier.js ├── learn.json ├── deploy-to-github.js ├── package.json ├── webpack.config.js ├── src ├── style │ └── index.css ├── index.html └── js │ └── app.js ├── README.md └── README.es.md /4geeks.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breatheco-de/exercise-conditional-profile-card/HEAD/4geeks.ico -------------------------------------------------------------------------------- /preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breatheco-de/exercise-conditional-profile-card/HEAD/preview.gif -------------------------------------------------------------------------------- /public/assets/img/4geeks.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breatheco-de/exercise-conditional-profile-card/HEAD/public/assets/img/4geeks.ico -------------------------------------------------------------------------------- /public/assets/img/rigo-baby.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breatheco-de/exercise-conditional-profile-card/HEAD/public/assets/img/rigo-baby.jpg -------------------------------------------------------------------------------- /.learn/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "editor": { 4 | "agent": "vscode" 5 | }, 6 | "autoPlay": false 7 | }, 8 | "currentExercise": null 9 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #ignore the git local files and the c9 project files 2 | .git 3 | .c9 4 | 5 | # ignore the repositories where webpack puts the bundles 6 | dist/ 7 | public/bundle/* 8 | node_modules/ 9 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | # List the ports you want to expose and what to do when they are served. See https://www.gitpod.io/docs/config-ports/ 2 | ports: 3 | - port: 3000 4 | onOpen: open-browser 5 | visibility: public 6 | 7 | tasks: 8 | - before: nvm install 16 9 | command: npm install 10 | -------------------------------------------------------------------------------- /.github/workflows/validate-integrity.yml: -------------------------------------------------------------------------------- 1 | name: Validate Integrity 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v3 11 | - uses: actions/setup-node@v3 12 | with: 13 | node-version: '14.x' 14 | - run: npm install @learnpack/learnpack -g 15 | - run: learnpack audit -------------------------------------------------------------------------------- /.gitpod.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gitpod/workspace-full 2 | 3 | USER gitpod 4 | 5 | # Install custom tools, runtime, etc. using apt-get 6 | # For example, the command below would install "bastet" - a command line tetris clone: 7 | # 8 | # RUN sudo apt-get -q update && \ 9 | # sudo apt-get install -yq bastet && \ 10 | # sudo rm -rf /var/lib/apt/lists/* 11 | # 12 | # More information: https://www.gitpod.io/docs/config-docker/ 13 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "env": { 4 | "browser": true, 5 | }, 6 | "rules": { 7 | "strict":0, 8 | "no-unused-vars": 0, 9 | "no-console": 0, 10 | "semi": ["error", "always"], 11 | "allowImportExportEverywhere": false, 12 | "comma-dangle": [1, { //when to use the last comma 13 | "arrays": "never", 14 | "objects": "never", 15 | "imports": "never", 16 | "exports": "never", 17 | "functions": "ignore", 18 | }], 19 | }, 20 | "extends": ["eslint:recommended"] 21 | } 22 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node 3 | { 4 | "name": "Node.js", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "mcr.microsoft.com/devcontainers/javascript-node:0-16", 7 | 8 | // Features to add to the dev container. More info: https://containers.dev/features. 9 | // "features": {}, 10 | 11 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 12 | // "forwardPorts": [], 13 | 14 | // Use 'postCreateCommand' to run commands after the container is created. 15 | "postCreateCommand": "npm install", 16 | 17 | // Configure tool-specific properties. 18 | // "customizations": {}, 19 | 20 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 21 | // "remoteUser": "root" 22 | } 23 | -------------------------------------------------------------------------------- /_utils/clean-stack.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | const StackUtils = require('stack-utils'); 5 | const stack = new StackUtils({cwd: process.cwd(), internals: StackUtils.nodeInternals()}); 6 | const chalk = require('chalk'); 7 | 8 | function displayError(severity, error) { 9 | return "error!!"; 10 | const baseError = formatTitle(severity, severity); 11 | console.log("baseError", baseError) 12 | return concat( 13 | `${baseError} ${removeLoaders(error.file)}`, 14 | '', 15 | error.message, 16 | (error.origin ? error.origin : undefined), 17 | '', 18 | error.infos 19 | ); 20 | } 21 | 22 | function removeLoaders(file) { 23 | if (!file) { 24 | return ""; 25 | } 26 | const split = file.split('!'); 27 | const filePath = split[split.length - 1]; 28 | return `in ${filePath}`; 29 | } 30 | 31 | function format(errors, type) { 32 | return errors 33 | // .filter(isDefaultError) 34 | .reduce((accum, error) => ( 35 | accum.concat(displayError(type, error)) 36 | ), []); 37 | } 38 | 39 | module.exports = format; -------------------------------------------------------------------------------- /learn.json: -------------------------------------------------------------------------------- 1 | { 2 | "gitpod": true, 3 | "title" : { 4 | "us": "Conditional Profile Card Generator", 5 | "es": "Generador de un perfil condicional" 6 | }, 7 | "slug" : "conditional-profile-card", 8 | "status": "published", 9 | "difficulty": "beginner", 10 | "translations": ["es", "us"], 11 | "technologies": ["conditionals", "conditional-rendering", "javascript", "condicionales"], 12 | "preview": "https://github.com/breatheco-de/conditional-profile-card/blob/master/preview.gif?raw=true", 13 | "syntax": "javascript", 14 | "solution" : "https://github.com/breatheco-de/exercise-conditional-profile-card/tree/solution", 15 | "duration" : 4, 16 | "template_url": "self", 17 | "description" : { 18 | "us": "Practice Dynamic Conditions with JavaScript: Build a profile card that updates dynamically based on runtime variables like username, avatar, background, and more. Strengthen your coding skills by mastering condition-based rendering in this hands-on project. Perfect for improving dynamic HTML generation.", 19 | "es": "Practica condiciones dinámicas con JavaScript: Crea una tarjeta de perfil que se actualice dinámicamente según variables en tiempo de ejecución como nombre de usuario, avatar, fondo y más. Fortalece tus habilidades de programación dominando el renderizado basado en condiciones en este proyecto práctico. Ideal para mejorar la generación de HTML dinámico." 20 | }, 21 | "talents": [ 22 | { "badge": "identator", "points": 6 }, 23 | { "badge": "tag-master", "points": 3 }, 24 | { "badge": "window-lover", "points": 3 }, 25 | { "badge": "abc", "points": 5 }, 26 | { "badge": "functional-developer", "points": 5 } 27 | ], 28 | "autoPlay": false, 29 | "projectType": "project", 30 | "telemetry": { 31 | "batch": "https://breathecode.herokuapp.com/v1/assignment/me/telemetry?asset_id=181" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /deploy-to-github.js: -------------------------------------------------------------------------------- 1 | var ghpages = require('gh-pages'); 2 | var Console = require('bc-console'); 3 | var webpack = require('webpack'); 4 | var path = require('path'); 5 | var fs = require('fs'); 6 | 7 | var remoteOriginUrl = require('remote-origin-url'); 8 | var gh = require('parse-github-url'); 9 | 10 | if (!fs.existsSync(path.resolve(__dirname,'.git'))){ 11 | Console.error("No repository found on this project"); 12 | Console.help("Follow this steps to create a new repository for your project: http://kbroman.org/github_tutorial/pages/init.html"); 13 | return; 14 | } 15 | 16 | const origin = remoteOriginUrl.sync(); 17 | if(!origin || origin==''){ 18 | Console.error("No remote origin has been found on this repository"); 19 | Console.help(`Check your remote by doing: 20 | $ git remote get-url origin 21 | 22 | Add your remote by doing: 23 | $ git remote add origin 24 | `); 25 | return; 26 | } 27 | Console.info("The remote was found successfully, starting the deploy from here: "+origin); 28 | 29 | const repository = gh(origin); 30 | const compiler = webpack(require(path.resolve(__dirname, 'webpack.config.js'))); 31 | compiler.run((err, stats) => { 32 | if (err || stats.hasErrors()) { 33 | console.log(stats.toString({ 34 | colors: true 35 | })); 36 | Console.error("There was an error compiling, review above"); 37 | return; 38 | } 39 | Console.success("Your code compiled successfully, proceding to deploy..."); 40 | ghpages.publish('public', function(err) { 41 | if(err){ 42 | console.error(err); 43 | Console.error("There was an error publishing your website"); 44 | return; 45 | } 46 | //https://.github.io/ 47 | Console.success(`Your website has been deployed successfully here: https://${repository["owner"]}.github.io/${repository["name"]}`); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vanillajs-hello", 3 | "version": "1.0.0", 4 | "description": "Professional Boilerplate for Vanilla.js Web Apps", 5 | "private": true, 6 | "scripts": { 7 | "start": "webpack-dev-server --mode development --port 3000", 8 | "build": "webpack --mode development --verbose --colors --display-error-details", 9 | "deploy": "node deploy-to-github.js" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/4GeeksAcademy/vanillajs-hello.git" 14 | }, 15 | "keywords": [ 16 | "Vanilla.js", 17 | "Boilerplate", 18 | "WebPack", 19 | "Boilerplate", 20 | "BreatheCode" 21 | ], 22 | "babel": { 23 | "presets": [ 24 | "@babel/preset-env" 25 | ] 26 | }, 27 | "author": "Alejandro Sanchez", 28 | "license": "ISC", 29 | "bugs": { 30 | "url": "https://github.com/4GeeksAcademy/vanillajs-hello/issues" 31 | }, 32 | "homepage": "https://github.com/4GeeksAcademy/vanillajs-hello#readme", 33 | "dependencies": { 34 | "@popperjs/core": "^2.10.1", 35 | "bootstrap": "^5.1.1" 36 | }, 37 | "devDependencies": { 38 | "@babel/cli": "^7.4.3", 39 | "@babel/core": "^7.4.3", 40 | "@babel/preset-env": "^7.4.3", 41 | "babel-eslint": "^10.0.1", 42 | "babel-loader": "^8.0.5", 43 | "bc-console": "0.0.2", 44 | "bc-webpack-error-reporting-plugin": "0.0.2", 45 | "clean-stack": "^3.0.1", 46 | "css-loader": "^3.5.1", 47 | "error-overlay-webpack-plugin": "^0.2.0", 48 | "escape-string-regexp": "^1.0.5", 49 | "eslint": "^4.19.1", 50 | "eslint-loader": "^2.0.0", 51 | "file-loader": "^6.0.0", 52 | "friendly-errors-webpack-plugin": "^1.7.0", 53 | "gh-pages": "^1.2.0", 54 | "html-loader": "^1.1.0", 55 | "html-webpack-plugin": "^4.3.0", 56 | "parse-github-url": "^1.0.2", 57 | "prettier": "^1.19.1", 58 | "prettier-webpack-plugin": "^1.1.0", 59 | "remote-origin-url": "^1.0.0", 60 | "stack-utils": "^2.0.3", 61 | "style-loader": "^1.1.3", 62 | "webpack": "^4.44.2", 63 | "webpack-cli": "^3.3.11", 64 | "webpack-dev-server": "^3.11.0" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const PrettierPlugin = require("./_utils/prettier.js"); 4 | const cleanStack = require("./_utils/clean-stack.js"); 5 | const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin'); 6 | const ErrorOverlayPlugin = require('error-overlay-webpack-plugin'); 7 | const WebpackErrorReporting = require('bc-webpack-error-reporting-plugin'); 8 | const HtmlWebpackPlugin = require('html-webpack-plugin') 9 | 10 | const port = 3000; 11 | let publicUrl = `http://localhost:${port}`; 12 | if(process.env.GITPOD_WORKSPACE_URL){ 13 | const [schema, host] = process.env.GITPOD_WORKSPACE_URL.split('://'); 14 | publicUrl = `${port}-${host}`; 15 | } 16 | 17 | module.exports = { 18 | mode: 'development', 19 | entry: ['./src/js/app.js'], 20 | output: { 21 | path: path.resolve(__dirname, 'public'), 22 | filename: 'main.bundle.js', 23 | sourceMapFilename: '[name].js.map' 24 | }, 25 | devtool: "source-map", 26 | devServer: { 27 | historyApiFallback: true, 28 | public: publicUrl, 29 | stats: 'errors-warnings', 30 | }, 31 | module: { 32 | rules: [ 33 | { 34 | test: /\.js$/, 35 | exclude: /node_modules/, 36 | use: ['babel-loader', 'eslint-loader'] 37 | }, 38 | { 39 | test: /\.css$/, 40 | use: ['style-loader', 'css-loader'] 41 | }, 42 | { 43 | test: /\.(png|svg|jpg|gif|ico)$/, 44 | use: { 45 | loader: 'file-loader', 46 | options: { name: '[name].[ext]' } 47 | } 48 | }, 49 | { 50 | test: /\.html$/i, 51 | use: { 52 | loader: 'html-loader', 53 | options: { 54 | attributes: false 55 | } 56 | } 57 | } 58 | ] 59 | }, 60 | plugins: [ 61 | new FriendlyErrorsWebpackPlugin({ 62 | // additionalFormatters: [cleanStack] 63 | }), 64 | new ErrorOverlayPlugin(), 65 | new HtmlWebpackPlugin({ 66 | filename: "index.html", 67 | template: "src/index.html", 68 | favicon: "4geeks.ico" 69 | }), 70 | new PrettierPlugin({ 71 | failSilently: true 72 | }), 73 | ] 74 | }; 75 | -------------------------------------------------------------------------------- /src/style/index.css: -------------------------------------------------------------------------------- 1 | .filters { 2 | background: white; 3 | width: 100%; 4 | } 5 | .filters li { 6 | display: inline-block; 7 | max-width: 80px; 8 | padding: 3px; 9 | } 10 | .filters li label { 11 | display: block; 12 | font-size: 12px; 13 | font-weight: 900; 14 | } 15 | .filters li input { 16 | width: 100%; 17 | } 18 | .filters li select { 19 | width: 100%; 20 | } 21 | .widget { 22 | position: relative; 23 | width: 300px; 24 | height: 350px; 25 | margin: 50px auto; 26 | background: #fff; 27 | border-radius: 5px; 28 | box-shadow: 0 5px 25px rgba(0, 0, 0, 0.1); 29 | } 30 | .widget .cover { 31 | height: 160px; 32 | overflow: hidden; 33 | } 34 | .widget .cover img { 35 | width: 100%; 36 | height: auto; 37 | min-height: 160px; 38 | border-radius: 4px 4px 0 0; 39 | } 40 | .widget .photo { 41 | position: absolute; 42 | top: 85px; 43 | left: 50%; 44 | width: 100px; 45 | height: 100px; 46 | margin: 0 0 0 -55px; 47 | border: 5px solid #fff; 48 | border-radius: 50%; 49 | } 50 | .widget h1, 51 | .widget h2, 52 | .widget h3 { 53 | display: block; 54 | margin: 10px 0; 55 | text-align: center; 56 | font-family: "Open Sans", sans-serif; 57 | font-size: 16px; 58 | font-weight: 300; 59 | color: #999; 60 | } 61 | .widget h1 { 62 | margin: 60px 0 20px; 63 | font-size: 26px; 64 | color: #000; 65 | } 66 | .widget h3 { 67 | font-size: 12px; 68 | } 69 | .widget ul { 70 | position: absolute; 71 | top: 20px; 72 | padding: 0; 73 | background: #2cdfd3; 74 | } 75 | .widget ul.position-left { 76 | left: -26px; 77 | } 78 | .widget ul.position-right { 79 | right: -27px; 80 | } 81 | .widget ul li { 82 | list-style: none; 83 | } 84 | .widget ul li a { 85 | display: block; 86 | padding: 5px 6px; 87 | color: #fff; 88 | cursor: pointer; 89 | text-align: center; 90 | border-bottom: 1px solid #2cd5ca; 91 | transition: background-color 0.3s; 92 | } 93 | .widget ul li:hover > a { 94 | background-color: #2cd5ca; 95 | } 96 | .widget ul li:first-child > a { 97 | border-radius: 0 3px 0 0; 98 | } 99 | .widget ul li:last-child > a { 100 | border: none; 101 | border-radius: 0 0 3px 0; 102 | } 103 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Hello Rigo with Vanilla.js 7 | 8 | 12 | 13 | 14 | 15 |
    16 |
  • 17 | 18 | 23 |
  • 24 |
  • 25 | 26 | 27 |
  • 28 |
  • 29 | 30 | 31 |
  • 32 |
  • 33 | 34 | 38 |
  • 39 |
  • 40 | 41 | 42 |
  • 43 |
  • 44 | 45 | 46 |
  • 47 |
  • 48 | 49 | 50 |
  • 51 |
  • 52 | 53 | 54 |
  • 55 |
  • 56 | 57 | 63 |
  • 64 |
  • 65 | 66 | 73 |
  • 74 |
  • 75 | 76 | 83 |
  • 84 |
85 |
86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /_utils/prettier.js: -------------------------------------------------------------------------------- 1 | const prettier = require("prettier"); 2 | const fs = require("fs"); 3 | const path = require("path"); 4 | 5 | const DEFAULT_EXTENSIONS = prettier.getSupportInfo 6 | ? prettier 7 | .getSupportInfo() 8 | .languages.map(l => l.extensions) 9 | .reduce((accumulator, currentValue) => accumulator.concat(currentValue)) 10 | : [ 11 | ".css", 12 | ".graphql", 13 | ".js", 14 | ".json", 15 | ".jsx", 16 | ".less", 17 | ".sass", 18 | ".scss", 19 | ".ts", 20 | ".tsx", 21 | ".vue", 22 | ".yaml", 23 | ]; 24 | 25 | const DEFAULT_ENCODING = "utf-8"; 26 | 27 | const DEFAULT_CONFIG_FILE = `${process.cwd()}/.prettierrc`; 28 | 29 | module.exports = class PrettierPlugin { 30 | constructor(options) { 31 | options = options || {}; 32 | 33 | // Encoding to use when reading / writing files 34 | this.encoding = options.encoding || DEFAULT_ENCODING; 35 | delete options.encoding; 36 | 37 | // Only process these files 38 | this.extensions = options.extensions || DEFAULT_EXTENSIONS; 39 | delete options.extensions; 40 | 41 | // Utilize this config file for options 42 | this.configFile = options.configFile || DEFAULT_CONFIG_FILE; 43 | delete options.configFile; 44 | 45 | // Resolve the config options from file to an object 46 | const configOptions = prettier.resolveConfig.sync(this.configFile) || {}; 47 | 48 | // Override Prettier options from config if any are specified 49 | this.prettierOptions = Object.assign(configOptions, options); 50 | 51 | // Fail silently 52 | this.failSilently = options.failSilently || false; 53 | delete options.failSilently; 54 | } 55 | 56 | apply(compiler) { 57 | compiler.hooks.emit.tapAsync('Prettier', (compilation, callback) => { 58 | const promises = []; 59 | compilation.fileDependencies.forEach(filepath => { 60 | if (this.extensions.indexOf(path.extname(filepath)) === -1) { 61 | return; 62 | } 63 | 64 | if (/node_modules/.exec(filepath)) { 65 | return; 66 | } 67 | promises.push(new Promise((resolve, reject) => { 68 | fs.readFile(filepath, this.encoding, (err, source) => { 69 | if (err) { 70 | return reject(err); 71 | } 72 | 73 | try{ 74 | const prettierSource = prettier.format(source, Object.assign({}, this.prettierOptions, { filepath })); 75 | if (prettierSource !== source) { 76 | fs.writeFile(filepath, prettierSource, this.encoding, err => { 77 | if (err) { 78 | return reject(err); 79 | } 80 | resolve(); 81 | }); 82 | } else { 83 | resolve(); 84 | } 85 | } 86 | catch(err){ 87 | if(this.failSilently) resolve(); 88 | else return reject(err); 89 | } 90 | }); 91 | })); 92 | }); 93 | 94 | Promise.all(promises).then(() => { 95 | callback(); 96 | }).catch(err => { 97 | callback(err); 98 | }); 99 | }); 100 | } 101 | }; 102 | -------------------------------------------------------------------------------- /src/js/app.js: -------------------------------------------------------------------------------- 1 | import "../style/index.css"; 2 | 3 | /** 4 | * EDIT ONLY INSIDE THIS RENDER FUNCTION 5 | * This function is called every time the user changes types or changes any input 6 | * 7 | { 8 | includeCover: true, // if includeCover is true the algorithm should show the cover image 9 | background: "https://images.unsplash.com/photo-1511974035430-5de47d3b95da", // this is the image's url that will be used as a background for the profile cover 10 | avatarURL: "https://randomuser.me/api/portraits/women/42.jpg", // this is the url for the profile avatar 11 | socialMediaPosition: "position-right", // social media bar position (position-left or position-right) 12 | //for social media links, only update usernames 13 | twitter: null, // social media usernames 14 | github: null, 15 | linkedin: null, 16 | instagram: null, 17 | 18 | name: null, 19 | lastName: null, 20 | role: null, 21 | country: null, 22 | city: null 23 | } 24 | */ 25 | function render(variables = {}) { 26 | console.log("These are the current variables: ", variables); // print on the console 27 | // here we ask the logical questions to make decisions on how to build the html 28 | // if includeCover==false then we reset the cover code without the tag to make the cover transparent. 29 | let cover = `
`; 30 | if (variables.includeCover == false) cover = "
"; 31 | 32 | // reset the website body with the new html output 33 | document.querySelector("#widget_content").innerHTML = `
34 | ${cover} 35 | 36 |

Lucy Boilett

37 |

Web Developer

38 |

Miami, USA

39 |
    40 |
  • 41 |
  • 42 |
  • 43 |
  • 44 |
45 |
46 | `; 47 | } 48 | 49 | /** 50 | * Don't change any of the lines below, here is where we do the logic for the dropdowns 51 | */ 52 | window.onload = function() { 53 | window.variables = { 54 | // if includeCover is true the algorithm should show the cover image 55 | includeCover: true, 56 | // this is the image's url that will be used as a background for the profile cover 57 | background: "https://images.unsplash.com/photo-1511974035430-5de47d3b95da", 58 | // this is the url for the profile avatar 59 | avatarURL: "https://randomuser.me/api/portraits/women/42.jpg", 60 | // social media bar position (position-left or position-right) 61 | socialMediaPosition: "position-right", 62 | // social media usernames 63 | twitter: null, 64 | github: null, 65 | linkedin: null, 66 | instagram: null, 67 | name: null, 68 | lastName: null, 69 | role: null, 70 | country: null, 71 | city: null 72 | }; 73 | render(window.variables); // render the card for the first time 74 | 75 | document.querySelectorAll(".picker").forEach(function(elm) { 76 | elm.addEventListener("change", function(e) { 77 | // <- add a listener to every input 78 | const attribute = e.target.getAttribute("for"); // when any input changes, collect the value 79 | let values = {}; 80 | values[attribute] = 81 | this.value == "" || this.value == "null" 82 | ? null 83 | : this.value == "true" 84 | ? true 85 | : this.value == "false" 86 | ? false 87 | : this.value; 88 | render(Object.assign(window.variables, values)); // render again the card with new values 89 | }); 90 | }); 91 | }; 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Conditional Profile Card 3 | 4 | 5 | **Note:** If you are working locally, make sure that you have node.js installed in your computer by typing in your terminal: 6 | 7 | ```bash 8 | $ node -v 9 | ``` 10 | 11 | 12 | 13 | ## 🌱 How to start this project 14 | 15 | This project comes with the necessary files to start working immediately. 16 | 17 | We recommend opening this very same repository using a provisioning tool like [Codespaces](https://4geeks.com/lesson/what-is-github-codespaces) (recommended) or [Gitpod](https://4geeks.com/lesson/how-to-use-gitpod). Alternatively, you can clone it on your local computer using the `git clone` command. 18 | 19 | This is the repository you need to open: 20 | 21 | ```text 22 | https://github.com/breatheco-de/exercise-conditional-profile-card.git 23 | ``` 24 | 25 | **👉 Please follow these steps on** [how to start a coding project](https://4geeks.com/lesson/how-to-start-a-project). 26 | 27 | To see the result in the browser, you will need to start the project by running the following command in your terminal: 28 | ```bash 29 | $ npm run start 30 | ``` 31 | 32 | > 💡 Important: Remember to save and upload your code to GitHub by creating a new repository, updating the remote (`git remote set-url origin `), and uploading the code to your new repository using the `add`, `commit` and `push` commands from the git terminal. 33 | 34 | 35 | 36 | ## Some context 37 | 38 | As a web developer, you will be creating lots and lots of dynamic HTML using JavaScript based algorithms. 39 | 40 | In this exercise, you have to create the HTML code needed to render a profile card based on a series of variables that could change in value during runtime. Here is an example of the profile card: 41 | 42 | ![Conditional Profile Card](https://github.com/breatheco-de/exercise-conditional-profile-card/blob/master/preview.gif?raw=true) 43 | 44 | Inside the `src/app.js` file there is a `render` function that receives variables and contains the logic to create most of the website HTML code. 45 | 46 | ```js 47 | function render(variables = {}) { 48 | document.querySelector("#widget_content").innerHTML = `
Website code
`; 49 | } 50 | ``` 51 | 52 | You can see the `variables` that are being generated by typing on the developer console: 53 | 54 | ```js 55 | console.log(window.variables); 56 | /* 57 | { 58 | includeCover: true, // if includeCover is true the algorithm should show the cover image 59 | background: "https://images.unsplash.com/photo-1511974035430-5de47d3b95da", // this is the image's url that will be used as a background for the profile cover 60 | avatarURL: "https://randomuser.me/api/portraits/women/42.jpg", // this is the url for the profile avatar 61 | socialMediaPosition: "left", // social media bar position (left or right) 62 | 63 | twitter: null, // social media usernames 64 | github: "alesanchezr", 65 | linkedin: null, 66 | instagram: null, 67 | 68 | name: null, 69 | lastName: null, 70 | role: null, 71 | country: null, 72 | city: null 73 | } 74 | */ 75 | ``` 76 | 77 | ## 📝 Instructions 78 | 79 | These instructions come with a video for better understanding: https://youtu.be/gaVm8eyCqlM 80 | 81 | 1. Read and understand the `render` function and the value of the `variables` variable that it receives. 82 | 83 | 2. Change the content of the `render` function to make it render the variables on the card. 84 | 85 | ## 💡 Attention! 86 | 87 | You **do not** need to add any event listeners to the elements that are already built in the project. This is already being done by this part of the code: 88 | 89 | ```javascript 90 | document.querySelectorAll(".picker").forEach(function(elm) { 91 | elm.addEventListener("change", function(e) { 92 | // <- add a listener to every input 93 | const attribute = e.target.getAttribute("for"); // when any input changes, collect the value 94 | let values = {}; 95 | values[attribute] = 96 | this.value == "" || this.value == "null" 97 | ? null 98 | : this.value == "true" 99 | ? true 100 | : this.value == "false" 101 | ? false 102 | : this.value; 103 | render(Object.assign(window.variables, values)); // render again the card with new values 104 | }); 105 | }); 106 | ``` 107 | 108 | So when the elements contents "change" they will already update the variable values for each element. All you need to do is to update the HTML content inside `render` function, as mentioned on instruction 1. 109 | 110 | ## Initial Variable Values 111 | 112 | | Name | Type | Default Value | Description | 113 | | --- | --- | --- | --- | 114 | | includeCover | boolean | true | it determines if the cover shoud be visible with an image or not | 115 | | background | string | null | the image's url that will be used as a background for the profile cover | 116 | | avatarURL | string | null | the url for the profile avatar | 117 | | socialMediaPosition | string | "right" | it can be `left` or `right` and it determines where to place the social media bar | 118 | | twitter | string | null | the twitter username to be displayed on the profile | 119 | | github | string | null | the github username to be displayed on the profile | 120 | | linkedin | string | null | the linkedin username to be displayed on the profile | 121 | | instagram | string | null | the instagram username to be displayed on the profile | 122 | | name | string | null | The name of the user to be displayed on the profile | 123 | | lastName | string | null | The name of the user to be displayed on the profile | 124 | | role | string | null | The name of the user to be displayed on the profile | 125 | | country | string | null | The name of the user to be displayed on the profile | 126 | | city | string | null | the city of the user to be displayed on the profile | 127 | 128 | ## Hard-Coded HTML 129 | 130 | This is an example of a possible HTML output, you will have to replace the name, last name, etc. With the values that these variables may have. 131 | 132 | ```html 133 |
134 |
135 | 136 |

Ryan Boylett

137 |

Web Developer

138 |

Miami, USA

139 |
    140 |
  • 141 |
  • 142 |
  • 143 |
  • 144 |
145 |
146 | ``` 147 | 148 | This and many other projects are built by students as part of the 4Geeks Academy [Coding Bootcamp](https://4geeksacademy.com/us/coding-bootcamp) by [Alejandro Sanchez](https://twitter.com/alesanchezr) and many other contributors. Find out more about our [Full Stack Developer Course](https://4geeksacademy.com/us/coding-bootcamps/part-time-full-stack-developer), and [Data Science Bootcamp](https://4geeksacademy.com/us/coding-bootcamps/datascience-machine-learning). 149 | -------------------------------------------------------------------------------- /README.es.md: -------------------------------------------------------------------------------- 1 | 2 | # Tarjeta de Perfil Condicional 3 | 4 | 5 | **Nota:** Si trabajas localmente, asegúrate de que tienes node.js instalado en tu computadora escribiendo en tu terminal: 6 | 7 | ```bash 8 | $ node -v 9 | ``` 10 | 11 | 12 | 13 | ## 🌱 Cómo comenzar este proyecto 14 | 15 | Este proyecto viene con los archivos necesarios para comenzar a trabajar de inmediato. 16 | 17 | Recomendamos abrir este mismo repositorio usando un entorno de desarrollo como [Codespaces](https://4geeks.com/es/lesson/tutorial-de-github-codespaces) (recomendado) o [Gitpod](https://4geeks.com/es/lesson/como-utilizar-gitpod). Alternativamente, puedes clonarlo en tu computadora local usando el comando `git clone`. 18 | 19 | Este es el repositorio que necesitas abrir: 20 | 21 | ```text 22 | https://github.com/breatheco-de/exercise-conditional-profile-card.git 23 | ``` 24 | 25 | **👉 Por favor sigue estos pasos sobre** [cómo comenzar un proyecto de programación](https://4geeks.com/es/lesson/como-comenzar-un-proyecto-de-codificacion). 26 | 27 | Para ver el resultado en el navegador, deberás iniciar el proyecto ejecutando el siguiente comando en tu terminal: 28 | ```bash 29 | $ npm run start 30 | ``` 31 | 32 | > 💡 Importante: Recuerda guardar y cargar tu código en GitHub creando un nuevo repositorio, actualizando el remoto (`git remote set-url origin `) y cargando el código en su nuevo repositorio usando los comandos `add`, `commit` y `push` desde el terminal git. 33 | 34 | 35 | 36 | ## Un poco de Contexto 37 | 38 | Como desarrollador web, estarás creando muchos HTML dinámicos y CSS usando algoritmos de JavaScript. 39 | 40 | En este ejercicio, debes crear el código HTML necesario para renderizar una tarjeta de perfil en función de una serie de variables que pueden cambiar. Aquí hay un ejemplo: 41 | 42 | ![Tarjeta de perfil condicional](https://github.com/breatheco-de/exercise-conditional-profile-card/raw/master/preview.gif?raw=true) 43 | 44 | Dentro de `src/app.js` hay una función llamada `render` que recibe un objeto `variables` y contiene la lógica para crear la mayoría del código HTML de nuestro sitio web. 45 | 46 | ```js 47 | function render(variables = {}) { 48 | document.querySelector("#widget_content").innerHTML = `
Website code
`; 49 | } 50 | ``` 51 | 52 | Puedes ver las `variables` que están siendo generadas escribiendo en la consola: 53 | 54 | ```js 55 | console.log(window.variables); 56 | /* 57 | { 58 | includeCover: true, // if includeCover is true the algorithm should show the cover image 59 | background: "https://images.unsplash.com/photo-1511974035430-5de47d3b95da", // this is the image's url that will be used as a background for the profile cover 60 | avatarURL: "https://randomuser.me/api/portraits/women/42.jpg", // this is the url for the profile avatar 61 | socialMediaPosition: "left", // social media bar position (left or right) 62 | 63 | twitter: null, // social media usernames 64 | github: "alesanchezr", 65 | linkedin: null, 66 | instagram: null, 67 | 68 | name: null, 69 | lastName: null, 70 | role: null, 71 | country: null, 72 | city: null 73 | } 74 | */ 75 | ``` 76 | 77 | ## 📝 Instrucciones 78 | 79 | Revisa este video con las instrucciones para que entiendas mejor el ejercicio: https://youtu.be/gaVm8eyCqlM 80 | 81 | 1. Lee y comprende la función `render` y el valor de la variable `variables` que recibe. 82 | 83 | 2. Cambia el contenido de la función `render` para que renderice todos los valores que llegan a través de `variables` en la tarjeta de perfil. 84 | 85 | ## 💡 Atención! 86 | 87 | **No** necesitas añadir ningún *event listener* a los elementos que ya están construidos en el proyecto. Esto ya está siendo realizado por esta parte del código: 88 | 89 | ```javascript 90 | document.querySelectorAll(".picker").forEach(function(elm) { 91 | elm.addEventListener("change", function(e) { 92 | // <- add a listener to every input 93 | const attribute = e.target.getAttribute("for"); // when any input changes, collect the value 94 | let values = {}; 95 | values[attribute] = 96 | this.value == "" || this.value == "null" 97 | ? null 98 | : this.value == "true" 99 | ? true 100 | : this.value == "false" 101 | ? false 102 | : this.value; 103 | render(Object.assign(window.variables, values)); // render again the card with new values 104 | }); 105 | }); 106 | ``` 107 | 108 | Entonces cuando el contenido de los elementos "cambia" se va a actualizar de una vez la variable para cada elemento. Todo lo que necesitas hacer es actualizar el contenido HTML dentro de la función `render`, como se mencionó en la instrucción 1. 109 | 110 | ## Valores de variables iniciales 111 | 112 | | Nombre | Tipo | Valor por Defecto | Descripción | 113 | | --- | --- | --- | --- | 114 | | background | string | null | La url de la imagen que se utilizará como fondo para la portada del perfil | 115 | | includeCover | boolean | true | Determina si debe mostrarse la portada o no | 116 | | avatarURL | string | null | La url para el avatar del perfil | 117 | | socialMediaPosition | string | "right" | puede ser `left` o` right` y determina dónde colocar la barra de redes sociales | 118 | | twitter | string | null | El nombre de usuario de Twitter que se mostrará en el perfil | 119 | | github | string | null | El nombre de usuario de Github que se mostrará en el perfil | 120 | | linkedin | string | null | El nombre de usuario de Linkedin que se mostrará en el perfil | 121 | | instagram | string | null | El nombre de usuario de Instagram para ser mostrado en el perfil | 122 | | name | string | null | El nombre del usuario que se mostrará en el perfil | 123 | | lastName | string | null | El nombre del usuario que se mostrará en el perfil | 124 | | role | string | null | El nombre del título del trabajo que se mostrará en el perfil | 125 | | country | string | null | El país de residencia del usuario que se mostrará en el perfil | 126 | | city | string | null | La ciudad de residencia del usuario que se mostrará en el perfil | 127 | 128 | ## HTML programado manualmente 129 | 130 | Este es un ejemplo de una posible salida HTML, vas a tener que remplazar el nombre, apellido, etc. Con los valores que puedan tener estas variables. 131 | 132 | ```html 133 |
134 |
135 | 136 |

Ryan Boylett

137 |

Web Developer

138 |

Miami, USA

139 |
    140 |
  • 141 |
  • 142 |
  • 143 |
  • 144 |
145 |
146 | ``` 147 | 148 | Este y otros proyectos son usados para [aprender a programar](https://4geeksacademy.com/es/aprender-a-programar/aprender-a-programar-desde-cero) por parte de los alumnos de 4Geeks Academy [Coding Bootcamp](https://4geeksacademy.com/us/coding-bootcamp) realizado por [Alejandro Sánchez](https://twitter.com/alesanchezr) y muchos otros contribuyentes. Conoce más sobre nuestros [Cursos de Programación](https://4geeksacademy.com/es/curso-de-programacion-desde-cero?lang=es) para convertirte en [Full Stack Developer](https://4geeksacademy.com/es/coding-bootcamps/desarrollador-full-stack/?lang=es), o nuestro [Data Science Bootcamp](https://4geeksacademy.com/es/coding-bootcamps/curso-datascience-machine-learning). 149 | --------------------------------------------------------------------------------