├── .gitignore ├── .babelrc ├── .hintrc ├── src ├── index.js ├── modules │ ├── createScore.js │ ├── displayScores.js │ └── fetching.js ├── index.html └── style.css ├── .eslintrc.json ├── webpack.config.js ├── .stylelintrc.json ├── MIT.md ├── package.json ├── .github └── workflows │ └── linters.yml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "test": { 4 | "plugins": ["@babel/plugin-transform-modules-commonjs"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.hintrc: -------------------------------------------------------------------------------- 1 | { 2 | "connector": { 3 | "name": "local", 4 | "options": { 5 | "pattern": ["**", "!.git/**", "!node_modules/**"] 6 | } 7 | }, 8 | "extends": ["development"], 9 | "formatters": ["stylish"], 10 | "hints": [ 11 | "button-type", 12 | "disown-opener", 13 | "html-checker", 14 | "meta-charset-utf-8", 15 | "meta-viewport", 16 | "no-inline-styles:error" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import './style.css'; 2 | import { getScores } from './modules/fetching.js'; 3 | import createScoreHandler from './modules/createScore.js'; 4 | 5 | const addScoreForm = document.querySelector('#form'); 6 | const refreshButton = document.querySelector('#refresh-btn'); 7 | 8 | getScores(); 9 | 10 | addScoreForm.addEventListener('submit', createScoreHandler); 11 | refreshButton.addEventListener('click', getScores); 12 | -------------------------------------------------------------------------------- /src/modules/createScore.js: -------------------------------------------------------------------------------- 1 | import { postScore } from './fetching.js'; 2 | 3 | const createScoreHandler = (event) => { 4 | event.preventDefault(); 5 | const user = document.querySelector('#user'); 6 | const score = document.querySelector('#score'); 7 | 8 | postScore({ user: user.value, score: score.value }); 9 | 10 | document.querySelector('.success').classList.remove('hidden'); 11 | user.value = ''; 12 | score.value = ''; 13 | }; 14 | 15 | export default createScoreHandler; 16 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "jest": true 6 | }, 7 | "parser": "babel-eslint", 8 | "parserOptions": { 9 | "ecmaVersion": 2018, 10 | "sourceType": "module" 11 | }, 12 | "extends": ["airbnb-base"], 13 | "rules": { 14 | "no-shadow": "off", 15 | "no-param-reassign": "off", 16 | "eol-last": "off", 17 | "import/extensions": [ 18 | 1, 19 | { 20 | "js": "always", 21 | "json": "always" 22 | } 23 | ] 24 | }, 25 | "ignorePatterns": ["dist/", "build/"] 26 | } 27 | -------------------------------------------------------------------------------- /src/modules/displayScores.js: -------------------------------------------------------------------------------- 1 | const display = (scores) => { 2 | const scoreListContainer = document.querySelector('.score-list-container'); 3 | let scoresListHtml = ''; 4 | 5 | // sort scores based on the score before displaying 6 | scores.sort((a, b) => b.score - a.score); 7 | 8 | // iterate over scores and added them to DOM 9 | scores.forEach((score) => { 10 | scoresListHtml += ` 11 |
  • ${score.user}: ${score.score}
  • 12 | `; 13 | }); 14 | scoreListContainer.innerHTML = scoresListHtml; 15 | }; 16 | 17 | export default display; 18 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | 4 | module.exports = { 5 | mode: 'development', 6 | entry: './src/index.js', 7 | output: { 8 | filename: 'main.js', 9 | path: path.resolve(__dirname, 'dist'), 10 | }, 11 | plugins: [ 12 | new HtmlWebpackPlugin({ 13 | title: 'Output Management', 14 | template: './src/index.html', 15 | }), 16 | ], 17 | module: { 18 | rules: [ 19 | { 20 | test: /\.css$/, 21 | use: ['style-loader', 'css-loader'], 22 | }, 23 | { 24 | test: /\.html$/, 25 | use: ['html-loader'], 26 | }, 27 | { 28 | test: /\.(png|svg|jpg|jpeg|gif)$/i, 29 | type: 'asset/resource', 30 | }, 31 | ], 32 | }, 33 | }; 34 | -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["stylelint-config-standard"], 3 | "plugins": ["stylelint-scss", "stylelint-csstree-validator"], 4 | "rules": { 5 | "at-rule-no-unknown": [ 6 | true, 7 | { 8 | "ignoreAtRules": [ 9 | "tailwind", 10 | "apply", 11 | "variants", 12 | "responsive", 13 | "screen" 14 | ] 15 | } 16 | ], 17 | "scss/at-rule-no-unknown": [ 18 | true, 19 | { 20 | "ignoreAtRules": [ 21 | "tailwind", 22 | "apply", 23 | "variants", 24 | "responsive", 25 | "screen" 26 | ] 27 | } 28 | ], 29 | "csstree/validator": true 30 | }, 31 | "ignoreFiles": [ 32 | "build/**", 33 | "dist/**", 34 | "**/reset*.css", 35 | "**/bootstrap*.css", 36 | "**/*.js", 37 | "**/*.jsx" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /src/modules/fetching.js: -------------------------------------------------------------------------------- 1 | import display from './displayScores.js'; 2 | 3 | const postScore = async (body) => { 4 | try { 5 | await fetch( 6 | 'https://us-central1-js-capstone-backend.cloudfunctions.net/api/games/I8nlr5WBZ1UYAevVbaLR/scores', 7 | { 8 | method: 'POST', 9 | body: JSON.stringify(body), 10 | headers: { 11 | 'Content-type': 'application/json; charset=UTF-8', 12 | }, 13 | }, 14 | ); 15 | } catch (error) { 16 | document.querySelector('.error').classList.remove('hidden'); 17 | } 18 | }; 19 | 20 | const getScores = async () => { 21 | try { 22 | const response = await fetch( 23 | 'https://us-central1-js-capstone-backend.cloudfunctions.net/api/games/I8nlr5WBZ1UYAevVbaLR/scores', 24 | ); 25 | const scores = await response.json(); 26 | display(scores.result); 27 | } catch (error) { 28 | document.querySelector('.error').classList.remove('hidden'); 29 | } 30 | }; 31 | 32 | export { getScores, postScore }; 33 | -------------------------------------------------------------------------------- /MIT.md: -------------------------------------------------------------------------------- 1 | ## Copyright 2023, Ahmed Eid 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this webpage and associated documentation files, to deal in the webpage without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the webpage, and to permit persons to whom the webpage is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the webpage. 6 | 7 | THE webpage IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE webpage OR THE USE OR OTHER DEALINGS IN THE webpage. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leaderboard", 3 | "version": "1.0.0", 4 | "description": "The leaderboard website displays scores submitted by different players. It also allows you to submit your score. All data is preserved thanks to the external Leaderboard API service.", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "webpack-dev-server --config webpack.config.js --open", 8 | "build": "webpack --config webpack.config.js" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "@babel/plugin-transform-modules-commonjs": "^7.22.5", 15 | "babel-eslint": "^10.1.0", 16 | "eslint": "^7.32.0", 17 | "eslint-config-airbnb-base": "^14.2.1", 18 | "eslint-plugin-import": "^2.27.5", 19 | "hint": "^7.1.9", 20 | "html-loader": "^4.2.0", 21 | "html-webpack-plugin": "^5.5.3", 22 | "style-loader": "^3.3.3", 23 | "stylelint": "^13.13.1", 24 | "stylelint-config-standard": "^21.0.0", 25 | "stylelint-csstree-validator": "^1.9.0", 26 | "stylelint-scss": "^3.21.0", 27 | "webpack": "^5.87.0", 28 | "webpack-cli": "^5.1.4", 29 | "webpack-dev-server": "^4.15.1", 30 | "webpack-merge": "^5.9.0" 31 | }, 32 | "dependencies": { 33 | "css-loader": "^6.8.1", 34 | "file-loader": "^6.2.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 |
    10 |

    Leaderboard

    11 |
    12 |
    13 | 14 |
    15 |
    16 |

    Recent scores

    17 | 20 |
    21 | 22 |
    23 | 24 |
    25 |

    Add you score

    26 |
    27 | 28 | 29 | 30 |
    31 |
    32 | 35 | 38 |
    39 |
    40 |
    41 | 42 | 43 | -------------------------------------------------------------------------------- /.github/workflows/linters.yml: -------------------------------------------------------------------------------- 1 | name: Linters 2 | 3 | on: pull_request 4 | 5 | env: 6 | FORCE_COLOR: 1 7 | 8 | jobs: 9 | lighthouse: 10 | name: Lighthouse 11 | runs-on: ubuntu-22.04 12 | steps: 13 | - uses: actions/checkout@v3 14 | - uses: actions/setup-node@v3 15 | with: 16 | node-version: "18.x" 17 | - name: Setup Lighthouse 18 | run: npm install -g @lhci/cli@0.11.x 19 | - name: Lighthouse Report 20 | run: lhci autorun --upload.target=temporary-public-storage --collect.staticDistDir=. 21 | webhint: 22 | name: Webhint 23 | runs-on: ubuntu-22.04 24 | steps: 25 | - uses: actions/checkout@v3 26 | - uses: actions/setup-node@v3 27 | with: 28 | node-version: "18.x" 29 | - name: Setup Webhint 30 | run: | 31 | npm install --save-dev hint@7.x 32 | [ -f .hintrc ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/html-css-js/.hintrc 33 | - name: Webhint Report 34 | run: npx hint . 35 | stylelint: 36 | name: Stylelint 37 | runs-on: ubuntu-22.04 38 | steps: 39 | - uses: actions/checkout@v3 40 | - uses: actions/setup-node@v3 41 | with: 42 | node-version: "18.x" 43 | - name: Setup Stylelint 44 | run: | 45 | npm install --save-dev stylelint@13.x stylelint-scss@3.x stylelint-config-standard@21.x stylelint-csstree-validator@1.x 46 | [ -f .stylelintrc.json ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/html-css-js/.stylelintrc.json 47 | - name: Stylelint Report 48 | run: npx stylelint "**/*.{css,scss}" 49 | eslint: 50 | name: ESLint 51 | runs-on: ubuntu-22.04 52 | steps: 53 | - uses: actions/checkout@v3 54 | - uses: actions/setup-node@v3 55 | with: 56 | node-version: "18.x" 57 | - name: Setup ESLint 58 | run: | 59 | npm install --save-dev eslint@7.x eslint-config-airbnb-base@14.x eslint-plugin-import@2.x babel-eslint@10.x 60 | [ -f .eslintrc.json ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/html-css-js/.eslintrc.json 61 | - name: ESLint Report 62 | run: npx eslint . 63 | nodechecker: 64 | name: node_modules checker 65 | runs-on: ubuntu-22.04 66 | steps: 67 | - uses: actions/checkout@v3 68 | - name: Check node_modules existence 69 | run: | 70 | if [ -d "node_modules/" ]; then echo -e "\e[1;31mThe node_modules/ folder was pushed to the repo. Please remove it from the GitHub repository and try again."; echo -e "\e[1;32mYou can set up a .gitignore file with this folder included on it to prevent this from happening in the future." && exit 1; fi -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | *, 2 | ::after, 3 | ::before { 4 | margin: 0; 5 | padding: 0; 6 | box-sizing: border-box; 7 | } 8 | 9 | html { 10 | font-size: 60%; 11 | } 12 | 13 | body { 14 | font-size: 25px; 15 | font-family: Oswald, sans-serif; 16 | } 17 | 18 | .hidden { 19 | display: none; 20 | } 21 | 22 | h2 { 23 | transition: 0.2s; 24 | } 25 | 26 | header { 27 | margin: 5rem; 28 | font-size: 3rem; 29 | } 30 | 31 | main { 32 | width: 100%; 33 | padding: 2rem 3rem; 34 | display: flex; 35 | justify-content: space-between; 36 | } 37 | 38 | .btn { 39 | width: 10rem; 40 | padding: 0.5rem 0; 41 | align-self: flex-end; 42 | font-family: inherit; 43 | cursor: pointer; 44 | font-size: 1.8rem; 45 | background: none; 46 | outline: none; 47 | border: 2px solid #000; 48 | transform: scale(1.1); 49 | transition: 0.4s; 50 | } 51 | 52 | .score-list-section, 53 | .add-score-section { 54 | width: 50%; 55 | padding: 2rem; 56 | display: flex; 57 | flex-direction: column; 58 | align-items: center; 59 | } 60 | 61 | .list-header { 62 | display: flex; 63 | width: 100%; 64 | justify-content: space-around; 65 | } 66 | 67 | .score-list-container { 68 | width: 100%; 69 | margin-top: 3rem; 70 | height: 35rem; 71 | border: 3px solid #222; 72 | overflow-y: scroll; 73 | } 74 | 75 | .score-item { 76 | padding: 1rem 2rem; 77 | } 78 | 79 | .score-item:nth-of-type(even) { 80 | background-color: rgb(128, 128, 128); 81 | } 82 | 83 | .score-item:nth-of-type(odd) { 84 | background-color: rgb(255, 255, 255); 85 | } 86 | 87 | form { 88 | width: 70%; 89 | display: flex; 90 | flex-direction: column; 91 | margin-top: 3rem; 92 | gap: 2rem; 93 | } 94 | 95 | input { 96 | display: block; 97 | height: 5rem; 98 | font-size: 2rem; 99 | border-radius: 7px; 100 | border: 2px solid #333; 101 | padding: 1rem; 102 | } 103 | 104 | .success { 105 | width: fit-content; 106 | margin: 3rem 0; 107 | padding: 1.5rem 3rem; 108 | font-size: 1.6rem; 109 | color: #4bb543; 110 | background-color: #c7e9b4; 111 | } 112 | 113 | .error { 114 | width: fit-content; 115 | margin: 3rem 0; 116 | padding: 1.5rem 3rem; 117 | font-size: 1.6rem; 118 | color: #e74c3c; 119 | background-color: #ffc7b3; 120 | } 121 | 122 | @media screen and (max-width: 768px) { 123 | main { 124 | align-items: center; 125 | flex-direction: column-reverse; 126 | padding: 2rem; 127 | } 128 | 129 | .score-list-section, 130 | .add-score-section { 131 | width: 100%; 132 | } 133 | 134 | form { 135 | width: 100%; 136 | gap: 2rem; 137 | } 138 | 139 | .list-header { 140 | justify-content: space-between; 141 | } 142 | 143 | .add-btn { 144 | align-self: center; 145 | } 146 | 147 | .success, 148 | .error { 149 | font-size: 2rem; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
    6 | 7 |

    Leaderboard

    8 | 9 |
    10 | 11 | 12 | 13 | # 📗 Table of Contents 14 | 15 | - [📖 About the Project](#about-project) 16 | - [🛠 Built With](#built-with) 17 | - [Tech Stack](#tech-stack) 18 | - [Key Features](#key-features) 19 | - [💻 Getting Started](#getting-started) 20 | - [Setup](#setup) 21 | - [Prerequisites](#prerequisites) 22 | - [Install](#install) 23 | - [Usage](#usage) 24 | - [👥 Authors](#authors) 25 | - [🔭 Future Features](#future-features) 26 | - [🤝 Contributing](#contributing) 27 | - [⭐️ Show your support](#support) 28 | - [🙏 Acknowledgements](#acknowledgements) 29 | - [📝 License](#license) 30 | 31 | 32 | 33 | # 📖 Leaderboard 34 | 35 | 36 | **Leaderboard** The leaderboard website displays scores submitted by different players. It also allows you to submit your score. All data is preserved thanks to the external Leaderboard API service. 37 | 38 | ## 🛠 Built With 39 | 40 | ### Tech Stack 41 | 42 | 43 |
    44 | Client 45 | 51 |
    52 | 53 | 54 | 55 | ### Key Features 56 | 57 | - A good HTML and CSS Design. 58 | - Using Webpack 59 | - Check Linters 60 | - Good RADME 61 | 62 |

    (back to top)

    63 | 64 | 65 | 66 | ## 💻 Getting Started 67 | 68 | To get a local copy up and running, follow these steps. 69 | 70 | ### Prerequisites 71 | 72 | In order to run this project you need: 73 | 74 | - Create a repo on your repositores files. 75 | - Clone or make a copy of this repo on your local machine. 76 | - Follow GitHub flow. 77 | - A carefully reading of this README.md is required. 78 | 79 | 80 | ### Setup 81 | 82 | Clone this repository to your desired folder: 83 | 84 | ```bash 85 | cd my-folder 86 | git clone https://github.com/ahmedeid6842/Leaderboard.git 87 | ``` 88 | 89 | ### Install 90 | 91 | Install this project with: 92 | 93 | ```bash 94 | npm install 95 | ``` 96 | 97 | ### Usage 98 | 99 | To run the project: 100 | ```bash 101 | npm start 102 | ``` 103 | 104 | To build the project: 105 | ```bash 106 | npm run build 107 | ``` 108 | 109 | 110 | 111 | ## 👥 Authors 112 | 113 | 👤 **Ahmed Eid** 114 | 115 | - GitHub: [@ahmedeid6842](https://github.com/ahmedeid6842) 116 | - Twitter: [ahmedeid2684](https://twitter.com/ahmedeid2684) 117 | - LinkedIn: [Ahmed Eid](https://www.linkedin.com/in/ahmed-eid-0018571b1/) 118 | 119 |

    (back to top)

    120 | 121 | 122 | 123 | ## 🔭 Future Features 124 | 125 | 126 | - [ ] Apply the Addition and removal functionality 127 | - [ ] Make the project more interactive 128 | 129 |

    (back to top)

    130 | 131 | 132 | 133 | ## 🤝 Contributing 134 | 135 | Contributions, issues, and feature requests are welcome! 136 | 137 | Feel free to check the [issues page](../../issues/). 138 | 139 |

    (back to top)

    140 | 141 | 142 | 143 | ## ⭐️ Show your support 144 | 145 | 146 | If you like this project feel free to leave a start, all contributions are welcome!. 147 | 148 |

    (back to top)

    149 | 150 | 151 | 152 | ## 🙏 Acknowledgments 153 | 154 | We would like to thank Microverse comunity, they do an excellent job. 155 | 156 |

    (back to top)

    157 | 158 | ## 📝 License 159 | 160 | This project is [MIT](./MIT.md) licensed. 161 | 162 | _NOTE: we recommend using the [MIT license] 163 | 164 |

    (back to top)

    165 | --------------------------------------------------------------------------------