├── .eslintrc.json ├── .github └── workflows │ └── linters.yml ├── .gitignore ├── .hintrc ├── .stylelintrc.json ├── README.md ├── dist ├── index.html └── main.js ├── package-lock.json ├── package.json ├── src ├── index.html ├── index.js ├── modules │ └── scoreUI.js └── style.css └── webpack.config.js /.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": [ 1, { 18 | "js": "always", "json": "always" 19 | }] 20 | }, 21 | "ignorePatterns": [ 22 | "dist/", 23 | "build/", 24 | "src/" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /.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-18.04 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions/setup-node@v1 15 | with: 16 | node-version: "12.x" 17 | - name: Setup Lighthouse 18 | run: npm install -g @lhci/cli@0.7.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-18.04 24 | steps: 25 | - uses: actions/checkout@v2 26 | - uses: actions/setup-node@v1 27 | with: 28 | node-version: "12.x" 29 | - name: Setup Webhint 30 | run: | 31 | npm install --save-dev hint@6.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 --telemetry=off . 35 | stylelint: 36 | name: Stylelint 37 | runs-on: ubuntu-18.04 38 | steps: 39 | - uses: actions/checkout@v2 40 | - uses: actions/setup-node@v1 41 | with: 42 | node-version: "12.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-18.04 52 | steps: 53 | - uses: actions/checkout@v2 54 | - uses: actions/setup-node@v1 55 | with: 56 | node-version: "12.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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # .gitignore 2 | node_modules/ -------------------------------------------------------------------------------- /.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 | } -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["stylelint-config-standard"], 3 | "plugins": ["stylelint-scss", "stylelint-csstree-validator"], 4 | "rules": { 5 | "at-rule-no-unknown": null, 6 | "scss/at-rule-no-unknown": true, 7 | "csstree/validator": true 8 | }, 9 | "ignoreFiles": ["build/**", "dist/**", "**/reset*.css", "**/bootstrap*.css", "**/*.js", "**/*.jsx"] 10 | } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Leaderboard 2 | 3 | > 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](https://www.notion.so/microverse/Leaderboard-API-service-24c0c3c116974ac49488d4eb0267ade3). 4 | 5 | ## How it looks like : 6 | 7 | ![style](https://user-images.githubusercontent.com/94958024/163553708-34076e8b-427d-4d9b-899c-079bf2acef4b.png) 8 | 9 | 10 | 11 | ## Built With 12 | 13 | - Major languages: Javascript, HTML & CSS 14 | - Frameworks: none 15 | - Technologies used: Webpack, Leaderboard API service 16 | 17 | ## Live Demo is avaible here 18 | 19 | [Live Demo Link](https://anicetfantomas.github.io/Leaderboard/) 20 | 21 | 22 | ## Getting Started 23 | 24 | ``` 25 | To get a local copy up and running follow these simple example steps. 26 | 27 | git clone 28 | 29 | https://github.com/AnicetFantomas/Leaderboard.git 30 | 31 | ``` 32 | ### To run this project locacally 33 | ``` 34 | - mpm install 35 | - npm start 36 | ``` 37 | 38 | ## Prerequisites 39 | 40 | The basic requirements for building the javascript are: 41 | ``` 42 | - A working browser application (Google chrome, Mozilla Firefox, Microsoft edge ...) 43 | - VSCode or any other equivalent code editor 44 | - Node Package Manager (For installing packages like Lighthous, webhint & stylelint used for checking and or debugging bad codes before deployment) 45 | ``` 46 | 47 | ### Deployment 48 | 49 | https://anicetfantomas.github.io/Leaderboard/ 50 | 51 | ## Authors 52 | 53 | 👤 **Anicet Murhula** 54 | 55 | - GitHub: [@AnicetFantomas](https://github.com/AnicetFantomas) 56 | 57 | - LinkedIn: [Anicet Murhula](https://www.linkedin.com/in/anicet-murhula-13a1b0220/) 58 | 59 | 60 | ## 🤝 Contributing 61 | 62 | Contributions, issues, and feature requests are welcome! 63 | 64 | Feel free to check the [issues page](../../issues/). 65 | 66 | ## Show your support 67 | 68 | Give a ⭐️ if you like this project! 69 | 70 | ## Acknowledgments 71 | 72 | - Hat tip to anyone whose code was used 73 | - Inspiration 74 | - etc 75 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | Wbpack Exercise

Hello webpack!

-------------------------------------------------------------------------------- /dist/main.js: -------------------------------------------------------------------------------- 1 | (()=>{"use strict";var e,t,r,n,o,a,i,c,s,u,p,l,d,f,v={426:(e,t,r)=>{r.d(t,{Z:()=>c});var n=r(81),o=r.n(n),a=r(645),i=r.n(a)()(o());i.push([e.id,"",""]);const c=i},645:e=>{e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var r="",n=void 0!==t[5];return t[4]&&(r+="@supports (".concat(t[4],") {")),t[2]&&(r+="@media ".concat(t[2]," {")),n&&(r+="@layer".concat(t[5].length>0?" ".concat(t[5]):""," {")),r+=e(t),n&&(r+="}"),t[2]&&(r+="}"),t[4]&&(r+="}"),r})).join("")},t.i=function(e,r,n,o,a){"string"==typeof e&&(e=[[null,e,void 0]]);var i={};if(n)for(var c=0;c0?" ".concat(p[5]):""," {").concat(p[1],"}")),p[5]=a),r&&(p[2]?(p[1]="@media ".concat(p[2]," {").concat(p[1],"}"),p[2]=r):p[2]=r),o&&(p[4]?(p[1]="@supports (".concat(p[4],") {").concat(p[1],"}"),p[4]=o):p[4]="".concat(o)),t.push(p))}},t}},81:e=>{e.exports=function(e){return e[1]}},379:e=>{var t=[];function r(e){for(var r=-1,n=0;n{var t={};e.exports=function(e,r){var n=function(e){if(void 0===t[e]){var r=document.querySelector(e);if(window.HTMLIFrameElement&&r instanceof window.HTMLIFrameElement)try{r=r.contentDocument.head}catch(e){r=null}t[e]=r}return t[e]}(e);if(!n)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");n.appendChild(r)}},216:e=>{e.exports=function(e){var t=document.createElement("style");return e.setAttributes(t,e.attributes),e.insert(t,e.options),t}},565:(e,t,r)=>{e.exports=function(e){var t=r.nc;t&&e.setAttribute("nonce",t)}},795:e=>{e.exports=function(e){var t=e.insertStyleElement(e);return{update:function(r){!function(e,t,r){var n="";r.supports&&(n+="@supports (".concat(r.supports,") {")),r.media&&(n+="@media ".concat(r.media," {"));var o=void 0!==r.layer;o&&(n+="@layer".concat(r.layer.length>0?" ".concat(r.layer):""," {")),n+=r.css,o&&(n+="}"),r.media&&(n+="}"),r.supports&&(n+="}");var a=r.sourceMap;a&&"undefined"!=typeof btoa&&(n+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(a))))," */")),t.styleTagTransform(n,e,t.options)}(t,e,r)},remove:function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(t)}}}},589:e=>{e.exports=function(e,t){if(t.styleSheet)t.styleSheet.cssText=e;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(e))}}}},m={};function h(e){var t=m[e];if(void 0!==t)return t.exports;var r=m[e]={id:e,exports:{}};return v[e](r,r.exports,h),r.exports}h.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return h.d(t,{a:t}),t},h.d=(e,t)=>{for(var r in t)h.o(t,r)&&!h.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},h.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),e=h(379),t=h.n(e),r=h(795),n=h.n(r),o=h(569),a=h.n(o),i=h(565),c=h.n(i),s=h(216),u=h.n(s),p=h(589),l=h.n(p),d=h(426),(f={}).styleTagTransform=l(),f.setAttributes=c(),f.insert=a().bind(null,"head"),f.domAPI=n(),f.insertStyleElement=u(),t()(d.Z,f),d.Z&&d.Z.locals&&d.Z.locals})(); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leaderboard", 3 | "version": "1.0.0", 4 | "description": "", 5 | "private": true, 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "webpack serve --open", 9 | "build": "webpack" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/AnicetFantomas/Leaderboard.git" 14 | }, 15 | "keywords": [], 16 | "author": "", 17 | "license": "ISC", 18 | "bugs": { 19 | "url": "https://github.com/AnicetFantomas/Leaderboard/issues" 20 | }, 21 | "homepage": "https://github.com/AnicetFantomas/Leaderboard#readme", 22 | "devDependencies": { 23 | "babel-eslint": "^10.1.0", 24 | "css-loader": "^6.7.1", 25 | "eslint": "^7.32.0", 26 | "eslint-config-airbnb-base": "^14.2.1", 27 | "eslint-plugin-import": "^2.26.0", 28 | "hint": "^6.1.11", 29 | "html-webpack-plugin": "^5.5.0", 30 | "style-loader": "^3.3.1", 31 | "stylelint": "^13.13.1", 32 | "stylelint-config-standard": "^21.0.0", 33 | "stylelint-csstree-validator": "^1.9.0", 34 | "stylelint-scss": "^3.21.0", 35 | "webpack": "^5.72.0", 36 | "webpack-cli": "^4.9.2", 37 | "webpack-dev-server": "^4.8.1" 38 | }, 39 | "dependencies": { 40 | "axios": "^0.26.1", 41 | "lodash": "^4.17.21" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Anicet's Leaderboard 7 | 8 | 9 |

Leaderboard

10 |
11 |
12 |
13 |

Recent scores

14 |
    15 | 16 |
17 |
18 |
19 |

Add your score

20 |
21 | 22 | 23 | 24 |
25 |
26 |
27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import './style.css'; 2 | import { loadData, loadScores, getScores } from './modules/scoreUI'; 3 | 4 | const url = 'https://us-central1-js-capstone-backend.cloudfunctions.net/api/games/AkKe5vSRElL4hhJr8Kvj/scores'; 5 | const refreshBtn = document.getElementById('refresh-btn'); 6 | const getForm = document.querySelector('.myForm'); 7 | 8 | window.addEventListener('load', () => loadScores(url)) 9 | refreshBtn.addEventListener('click',() => loadScores(url)); 10 | getForm.addEventListener('submit', async (e) => { 11 | e.preventDefault(); 12 | await getScores(url, loadData()); 13 | loadScores(url); 14 | getForm.reset(); 15 | }) 16 | -------------------------------------------------------------------------------- /src/modules/scoreUI.js: -------------------------------------------------------------------------------- 1 | const userInput = document.getElementById('name'); 2 | const scoreInput = document.getElementById('score'); 3 | const listBoard = document.getElementById('my-list'); 4 | 5 | const getAll = async (url) => (await fetch(url)).json(); 6 | const getScores = async(url, score) => (await fetch(url, score)).json(); 7 | 8 | const loadData = () => { 9 | const scoresData = { 10 | method : 'POST', 11 | headers: { 'Content-Type': 'application/json' }, 12 | body : JSON.stringify({ 13 | user: userInput.value.trim(), 14 | score: scoreInput.value.trim() 15 | }) 16 | }; 17 | return scoresData; 18 | }; 19 | 20 | loadData(); 21 | 22 | const loadScores = async (url) => { 23 | const {result} = await getAll(url); 24 | listBoard.innerHTML = result.sort((a,b) => b.score - a.score).map((score) => `
  • ${score.user}: ${score.score}
  • `).join('') 25 | } 26 | export {loadData, loadScores, getScores}; -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | padding: 0; 3 | margin: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | background-color: rgb(235, 242, 245); 9 | width: 100%; 10 | display: flex; 11 | justify-content: center; 12 | flex-direction: column; 13 | padding-bottom: 17%; 14 | padding-top: 30px; 15 | } 16 | 17 | h1 { 18 | text-align: center; 19 | color: red; 20 | font-size: 50px; 21 | margin-bottom: 30px; 22 | } 23 | 24 | .wrapper { 25 | background-color: #fff; 26 | width: 90%; 27 | border: 2px solid #000; 28 | padding: 8px; 29 | align-self: center; 30 | border-radius: 10px; 31 | } 32 | 33 | .scores-container { 34 | width: 90%; 35 | display: flex; 36 | margin: 30px; 37 | } 38 | 39 | .scores { 40 | width: 50%; 41 | } 42 | 43 | .scores-header { 44 | display: flex; 45 | margin-bottom: 10px; 46 | } 47 | 48 | .scores-header h2 { 49 | color: red; 50 | flex-grow: 1; 51 | font-size: 30px; 52 | } 53 | 54 | form button { 55 | padding: 5px; 56 | width: 30%; 57 | margin-left: 68%; 58 | font-weight: bold; 59 | font-size: 18px; 60 | } 61 | 62 | .scores-header button { 63 | padding: 5px; 64 | width: 30%; 65 | font-weight: bold; 66 | font-size: 18px; 67 | } 68 | 69 | .scores-form { 70 | width: 50%; 71 | margin-left: 20px; 72 | } 73 | 74 | .scores-form h2 { 75 | color: red; 76 | margin-bottom: 10px; 77 | font-size: 30px; 78 | } 79 | 80 | form { 81 | background-color: #fff; 82 | border: 2px solid #000; 83 | padding: 6px; 84 | } 85 | 86 | .scores-form form { 87 | display: flex; 88 | flex-direction: column; 89 | } 90 | 91 | form input { 92 | margin: 10px; 93 | padding: 5px; 94 | border: 2px solid black; 95 | } 96 | 97 | button:focus { 98 | transform: scale(0.7); 99 | } 100 | 101 | button:hover { 102 | background-color: rgb(145, 115, 115); 103 | } 104 | 105 | ul { 106 | background-color: #fff; 107 | border: 2px solid black; 108 | list-style: none; 109 | padding: 8px; 110 | font-size: 20px; 111 | font-weight: bold; 112 | } 113 | 114 | li:hover { 115 | transform: scaleY(0.9); 116 | font-size: 20px; 117 | } 118 | 119 | li:nth-child(odd) { 120 | background-color: rgb(207, 202, 202); 121 | } 122 | 123 | input::placeholder { 124 | color: rgb(37, 36, 36); 125 | font-size: 18px; 126 | } 127 | -------------------------------------------------------------------------------- /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 | devServer: { 8 | static: './dist', 9 | }, 10 | plugins: [ 11 | new HtmlWebpackPlugin({ 12 | template: './src/index.html', 13 | }), 14 | ], 15 | output: { 16 | filename: 'main.js', 17 | path: path.resolve(__dirname, 'dist'), 18 | }, 19 | module: { 20 | rules: [ 21 | { 22 | test: /\.css$/i, 23 | use: ['style-loader', 'css-loader'], 24 | }, 25 | ], 26 | }, 27 | }; --------------------------------------------------------------------------------