├── asset └── background.jpg ├── leaderboard-logo.png ├── dist ├── 8074b963e8861cabb850.jpg ├── index.html └── main.bundle.js ├── .hintrc ├── .eslintrc.json ├── .stylelintrc.json ├── webpack.config.js ├── LICENSE ├── package.json ├── src ├── index.html ├── index.js ├── modules │ └── boardApi.js └── index.css ├── .github └── workflows │ └── linters.yml ├── .gitignore └── README.md /asset/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zuwairanajma/Leaderboard-Project/HEAD/asset/background.jpg -------------------------------------------------------------------------------- /leaderboard-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zuwairanajma/Leaderboard-Project/HEAD/leaderboard-logo.png -------------------------------------------------------------------------------- /dist/8074b963e8861cabb850.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zuwairanajma/Leaderboard-Project/HEAD/dist/8074b963e8861cabb850.jpg -------------------------------------------------------------------------------- /.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 | } -------------------------------------------------------------------------------- /.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 | ] 25 | } -------------------------------------------------------------------------------- /.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": ["tailwind", "apply", "variants", "responsive", "screen"] 9 | } 10 | ], 11 | "scss/at-rule-no-unknown": [ 12 | true, 13 | { 14 | "ignoreAtRules": ["tailwind", "apply", "variants", "responsive", "screen"] 15 | } 16 | ], 17 | "csstree/validator": true 18 | }, 19 | "ignoreFiles": ["build/**", "dist/**", "**/reset*.css", "**/bootstrap*.css", "**/*.js", "**/*.jsx"] 20 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | 4 | module.exports = { 5 | mode: 'development', 6 | entry: { 7 | main: './src/index.js', 8 | }, 9 | output: { 10 | filename: '[name].bundle.js', 11 | path: path.resolve(__dirname, 'dist'), 12 | }, 13 | devServer: { 14 | static: path.resolve(__dirname, 'dist'), 15 | }, 16 | module: { 17 | rules: [ 18 | { 19 | test: /\.css$/, 20 | use: ['style-loader', 'css-loader'], 21 | }, 22 | { 23 | test: /\.(png|svg|jpg|jpeg|gif)$/i, 24 | type: 'asset/resource', 25 | }, 26 | ], 27 | }, 28 | plugins: [ 29 | new HtmlWebpackPlugin({ 30 | template: './src/index.html', 31 | }), 32 | ], 33 | }; 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Zuwaira Enehuwa Sadiq 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-linters-module2", 3 | "version": "1.0.0", 4 | "description": "This is a template repository for setting up a project with Webpack and linters (ESLint and Stylelint) configured. It provides a solid foundation for building JavaScript and CSS projects while ensuring code quality and adherence to coding standards.", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "webpack-dev-server --open", 9 | "build": "webpack" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "babel-eslint": "^10.1.0", 16 | "css-loader": "^6.8.1", 17 | "eslint": "^7.32.0", 18 | "eslint-config-airbnb-base": "^14.2.1", 19 | "eslint-plugin-import": "^2.28.0", 20 | "hint": "^7.1.10", 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.88.2", 28 | "webpack-cli": "^5.1.4", 29 | "webpack-dev-server": "^4.15.1" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | Leaderboard 11 | 12 | 13 |
14 | 19 |
20 |
21 |
22 |
23 |

Recent scores

24 | 25 |
26 |
27 |
    28 |
29 |
30 |
31 | 32 |
33 |
34 |

Add Your Score

35 |
36 | 37 |
38 | 39 |
40 |

Both input fields required.

41 |
42 |
43 | 46 | 47 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | Leaderboard 11 | 12 | 13 |
14 | 19 |
20 |
21 |
22 |
23 |

Recent scores

24 | 25 |
26 |
27 |
    28 |
29 |
30 |
31 | 32 |
33 |
34 |

Add Your Score

35 |
36 | 37 |
38 | 39 |
40 |

Both input fields required.

41 |
42 |
43 | 46 | 47 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import './index.css'; 2 | import { createGame, addYourScore, retrieveScores } from './modules/boardApi.js'; 3 | 4 | // Refresh scores and update the UI 5 | const refreshScores = async () => { 6 | const scoresContainer = document.getElementById('scores-container'); 7 | scoresContainer.innerHTML = ''; 8 | 9 | try { 10 | const scores = await retrieveScores(); 11 | 12 | if (scores.length === 0) { 13 | const noScoresMessage = document.createElement('p'); 14 | noScoresMessage.textContent = 'Lets begin'; 15 | scoresContainer.appendChild(noScoresMessage); 16 | } else { 17 | scores.forEach(({ user, score }) => { 18 | const listItem = document.createElement('li'); 19 | const playerNameSpan = document.createElement('span'); 20 | playerNameSpan.textContent = user; 21 | const scoreSpan = document.createElement('span'); 22 | scoreSpan.textContent = score; 23 | const seperator = document.createElement('span'); 24 | seperator.textContent = ': '; 25 | listItem.appendChild(playerNameSpan); 26 | listItem.appendChild(seperator); 27 | listItem.appendChild(scoreSpan); 28 | scoresContainer.appendChild(listItem); 29 | }); 30 | } 31 | } catch (error) { 32 | // Handle API request error 33 | console.error('Error retrieving scores:', error.message); 34 | } 35 | }; 36 | 37 | // Event listener for the Refresh button 38 | const refreshButton = document.getElementById('refresh-button'); 39 | refreshButton.addEventListener('click', refreshScores); 40 | 41 | // Event listener for the Submit button 42 | const submitForm = document.querySelector('.add-form'); 43 | submitForm.addEventListener('submit', async (e) => { 44 | e.preventDefault(); 45 | const { Player: userName, score } = submitForm.elements; 46 | 47 | addYourScore(userName.value, score.value); 48 | submitForm.reset(); 49 | refreshScores(); 50 | }); 51 | 52 | // Create a new game and initialize the app 53 | document.addEventListener('DOMContentLoaded', async () => { 54 | const gameName = 'My Beauty Game'; 55 | try { 56 | await createGame(gameName); 57 | await refreshScores(); 58 | } catch (error) { 59 | // Handle API request error 60 | console.error('Error creating new game:', error.message); 61 | } 62 | }); 63 | -------------------------------------------------------------------------------- /src/modules/boardApi.js: -------------------------------------------------------------------------------- 1 | // Helper function to handle API errors 2 | const handleApiError = (error) => { 3 | // Handle API request error 4 | console.error('An error occurred:', error); 5 | }; 6 | 7 | // Helper function to make API requests 8 | const makeApiRequest = async (url, method, body) => { 9 | try { 10 | const response = await fetch(url, { 11 | method, 12 | headers: { 13 | 'Content-Type': 'application/json', 14 | }, 15 | body: JSON.stringify(body), 16 | }); 17 | 18 | if (!response.ok) { 19 | throw new Error('API request failed'); 20 | } 21 | 22 | const { result } = await response.json(); 23 | return result; 24 | } catch (error) { 25 | handleApiError(error); 26 | throw error; // Re-throw the error to be handled by the caller 27 | } 28 | }; 29 | 30 | // Create a new game and save the game ID 31 | export const createGame = async (gameName) => { 32 | try { 33 | const response = await makeApiRequest('https://us-central1-js-capstone-backend.cloudfunctions.net/api/games/', 'POST', { 34 | name: gameName, 35 | }); 36 | 37 | const gameId = response.split(' ')[3]; 38 | localStorage.setItem('gameId', gameId); 39 | } catch (error) { 40 | handleApiError(error); 41 | throw error; // Re-throw the error to be handled by the caller 42 | } 43 | }; 44 | 45 | // Retrieve the game ID from local storage 46 | export const getGameId = () => localStorage.getItem('gameId'); 47 | 48 | // Retrieve all scores for the game 49 | export const retrieveScores = async () => { 50 | const gameId = getGameId(); 51 | try { 52 | const response = await makeApiRequest(`https://us-central1-js-capstone-backend.cloudfunctions.net/api/games/${gameId}/scores/`, 'GET'); 53 | return response; 54 | } catch (error) { 55 | handleApiError(error); 56 | return []; // Return an empty array to indicate no scores available 57 | } 58 | }; 59 | 60 | // Save a score for the game 61 | export const addYourScore = async (userName, score) => { 62 | const gameId = getGameId(); 63 | // Validate user input 64 | if (!userName || !score || Number.isNaN(parseInt(score, 10))) { 65 | // Invalid input, handle the error appropriately 66 | return; 67 | } 68 | 69 | try { 70 | await makeApiRequest(`https://us-central1-js-capstone-backend.cloudfunctions.net/api/games/${gameId}/scores/`, 'POST', { 71 | user: userName, 72 | score: parseInt(score, 10), 73 | }); 74 | } catch (error) { 75 | handleApiError(error); 76 | throw error; // Re-throw the error to be handled by the caller 77 | } 78 | }; 79 | -------------------------------------------------------------------------------- /.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 | stylelint: 34 | name: Stylelint 35 | runs-on: ubuntu-22.04 36 | steps: 37 | - uses: actions/checkout@v3 38 | - uses: actions/setup-node@v3 39 | with: 40 | node-version: "18.x" 41 | - name: Setup Stylelint 42 | run: | 43 | npm install --save-dev stylelint@13.x stylelint-scss@3.x stylelint-config-standard@21.x stylelint-csstree-validator@1.x 44 | [ -f .stylelintrc.json ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/html-css-js/.stylelintrc.json 45 | - name: Stylelint Report 46 | run: npx stylelint "**/*.{css,scss}" 47 | eslint: 48 | name: ESLint 49 | runs-on: ubuntu-22.04 50 | steps: 51 | - uses: actions/checkout@v3 52 | - uses: actions/setup-node@v3 53 | with: 54 | node-version: "18.x" 55 | - name: Setup ESLint 56 | run: | 57 | npm install --save-dev eslint@7.x eslint-config-airbnb-base@14.x eslint-plugin-import@2.x babel-eslint@10.x 58 | [ -f .eslintrc.json ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/html-css-js/.eslintrc.json 59 | - name: ESLint Report 60 | run: npx eslint . 61 | nodechecker: 62 | name: node_modules checker 63 | runs-on: ubuntu-22.04 64 | steps: 65 | - uses: actions/checkout@v3 66 | - name: Check node_modules existence 67 | run: | 68 | 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 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | 93 | # Gatsby files 94 | .cache/ 95 | # Comment in the public line in if your project uses Gatsby and not Next.js 96 | # https://nextjs.org/blog/next-9-1#public-directory-support 97 | # public 98 | 99 | # vuepress build output 100 | .vuepress 101 | 102 | # vuepress v2.x temp and cache directory 103 | .temp 104 | .cache 105 | 106 | # Docusaurus cache and generated files 107 | .docusaurus 108 | 109 | # Serverless directories 110 | .serverless/ 111 | 112 | # FuseBox cache 113 | .fusebox/ 114 | 115 | # DynamoDB Local files 116 | .dynamodb/ 117 | 118 | # TernJS port file 119 | .tern-port 120 | 121 | # Stores VSCode versions used for testing VSCode extensions 122 | .vscode-test 123 | 124 | # yarn v2 125 | .yarn/cache 126 | .yarn/unplugged 127 | .yarn/build-state.yml 128 | .yarn/install-state.gz 129 | .pnp.* 130 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Comfortaa:wght@300;400;500;600;700;900&display=swap"); 2 | 3 | :root { 4 | --main-color: #ff0; 5 | --light-white: rgba(255, 255, 255, 0.5); 6 | --light-black: rgba(0, 0, 0, 0.3); 7 | --light-bg: rgba(255, 255, 255, 0.1); 8 | --white: #fff; 9 | --black: #000; 10 | } 11 | 12 | * { 13 | font-family: "Comfortaa", cursive; 14 | margin: 0; 15 | padding: 0; 16 | box-sizing: border-box; 17 | text-decoration: none; 18 | } 19 | 20 | html { 21 | overflow-x: hidden; 22 | } 23 | 24 | #menu-btn { 25 | font-size: 2.5rem; 26 | cursor: pointer; 27 | color: var(--white); 28 | display: none; 29 | } 30 | 31 | body { 32 | background-color: var(--black); 33 | color: #000; 34 | border: 2px solid black; 35 | height: 100%; 36 | } 37 | 38 | .header { 39 | padding: 10px; 40 | } 41 | 42 | .logo { 43 | text-decoration: none; 44 | color: black; 45 | font-weight: 800; 46 | font-size: 32px; 47 | margin-left: 24px; 48 | } 49 | 50 | .header .navbar .logo { 51 | font-size: 2.5rem; 52 | color: var(--main-color); 53 | } 54 | 55 | .score-section { 56 | display: flex; 57 | flex-direction: column; 58 | margin-left: 300px; 59 | margin-top: 60px; 60 | } 61 | 62 | .score-container { 63 | margin-top: 35px; 64 | border: 2px solid black; 65 | margin-bottom: 35px; 66 | background-color: var(--light-white); 67 | } 68 | 69 | .score-header { 70 | display: flex; 71 | gap: 24px; 72 | } 73 | 74 | h2 { 75 | font-size: 24px; 76 | font-weight: 800; 77 | } 78 | 79 | .container-home h2 { 80 | padding-top: 1rem; 81 | font-size: 1.7rem; 82 | color: var(--light-white); 83 | } 84 | 85 | .container-home { 86 | display: flex; 87 | gap: 70px; 88 | background: no-repeat url('../asset/background.jpg') rgba(0, 0, 0, 0.5); 89 | background-position: center; 90 | background-attachment: fixed; 91 | background-size: cover; 92 | background-blend-mode: multiply; 93 | height: 100vh; 94 | } 95 | 96 | .add-score form { 97 | display: flex; 98 | flex-direction: column; 99 | gap: 20px; 100 | margin: 60px 0; 101 | } 102 | 103 | .add-score input { 104 | border: 2px solid black; 105 | height: 40px; 106 | width: 250px; 107 | } 108 | 109 | .input { 110 | margin-top: 25px; 111 | display: flex; 112 | flex-direction: column; 113 | gap: 24px; 114 | } 115 | 116 | li { 117 | list-style: none; 118 | align-items: center; 119 | font-size: 1rem; 120 | padding: 0.5rem 0; 121 | border-bottom: 1px solid grey; 122 | width: 300px; 123 | font-weight: bold; 124 | background-color: lightgray; 125 | } 126 | 127 | li:nth-child(odd) { 128 | background-color: white; 129 | } 130 | 131 | .refresh-btn { 132 | margin-top: 18px; 133 | } 134 | 135 | span { 136 | margin-left: 10px; 137 | } 138 | 139 | .btn { 140 | display: block; 141 | border-radius: 0.5rem; 142 | cursor: pointer; 143 | text-align: center; 144 | font-size: 1rem; 145 | transition: 0.2s linear; 146 | width: 100px; 147 | font-weight: 700; 148 | background-color: white; 149 | height: 34px; 150 | } 151 | 152 | .submit-btn { 153 | margin-left: 150px; 154 | } 155 | 156 | footer { 157 | background-color: grey; 158 | border: 2px solid black; 159 | height: 35px; 160 | width: 100%; 161 | margin-bottom: 0; 162 | } 163 | 164 | .error-msg { 165 | display: none; 166 | } 167 | 168 | @media (max-width: 645px) { 169 | .container-home { 170 | flex-direction: column-reverse; 171 | align-items: center; 172 | width: 100%; 173 | background-color: grey; 174 | margin-top: 20px; 175 | gap: 30px; 176 | } 177 | 178 | .header { 179 | padding: 8px 0 0 0; 180 | } 181 | 182 | .score-section { 183 | margin-top: -50px; 184 | margin-bottom: 30px; 185 | flex-direction: column; 186 | flex-wrap: wrap; 187 | margin-left: 20px; 188 | } 189 | 190 | #menu-btn { 191 | display: block; 192 | margin-right: 10px; 193 | } 194 | 195 | .navbar { 196 | display: flex; 197 | justify-content: space-between; 198 | } 199 | 200 | .refresh-btn { 201 | margin-top: 18px; 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Leaderboard-Project 2 | 3 |
4 | leaderboard logo 5 |
6 | 7 |

Leaderboard Project

8 | 9 |
10 | # 📗 Table of Contents 11 | 12 | - [📖 About the Project](#about-project) 13 | - [🛠 Built With](#built-with) 14 | - [Tech Stack](#tech-stack) 15 | - [Key Features](#key-features) 16 | - [💻 Getting Started](#getting-started) 17 | - [Setup](#setup) 18 | - [Prerequisites](#prerequisites) 19 | - [Usage](#usage) 20 | - [Deployment](#triangular_flag_on_post-deployment) 21 | - [👥 Authors](#authors) 22 | - [🔭 Future Features](#future-features) 23 | - [🤝 Contributing](#contributing) 24 | - [⭐️ Show your support](#support) 25 | - [🙏 Acknowledgements](#acknowledgements) 26 | 27 | 28 | # 📖 "To-do List with webpack Project!" 29 | 30 | 31 | Leaderboard is a simple project built to consume the leaderboard API. A user can add their name and their score which then will be displayed on the list ot the existing scores. This app is also built with module files based on various functionalities, the stacks used to build the project are HTML, CSS and JS. 32 | 33 | ## 🛠 Built With 34 | ### Tech Stack 35 |

HTML

36 |

CSS

37 |

JS

38 |

WebpackDevServer

39 |

HTMLWebpackPlugin

40 | 41 |

42 | Client 43 | 50 |
51 | 52 | ### Key Features 53 | - **Navbar (menu-bar)** 54 | - **localStorage functionality** 55 | - **Add book functionality** 56 | - **Remove book functionality** 57 | - **Footer section** 58 | - **contact information** 59 |

(back to top)

60 | 61 | ## 🚀 Live Demo 62 | You can view this project using this URL "https://zuwairanajma.github.io/Leaderboard-Project/dist/" 63 | 64 |

(back to top)

68 | 69 | To get a local copy up and running, follow these steps. 70 | 71 | ## Setup 72 | 73 | Clone this repository to your desired folder: 74 | 75 | 76 | > Fork this repo 77 | > git clone git@github.com/Zuwairanajma/Leaderboard-Project.git 78 | 79 | ### Prerequisites 80 | 81 | 82 | In order to run this project you need: 83 | 84 | - GitHub account; 85 | - Install Git on your OS. 86 | 87 | ### Install 88 | 89 | Installations required to run this project: 90 | 91 | - Webhint installation. Run the following command: 92 | > npm install --save-dev hint@7.x 93 | 94 | - Stylelint installation. Run the following command: 95 | > npm install --save-dev stylelint@13.x stylelint-scss@3.x stylelint-config-standard@21.x stylelint-csstree-validator@1.x 96 | 97 | - Eslint installation. Run the following command: 98 | > npm install --save-dev eslint@7.x eslint-config-airbnb-base@14.x eslint-plugin-import@2.x babel-eslint@10.x 99 | 100 | - Webpack installation. Run the following command: 101 | > npm install --save-dev style-loader css-loader html-webpack-plugin webpack-dev-server 102 | 103 | 104 | ### Usage 105 | 106 | ### Run tests 107 | 108 | To run tests, run the following commands: 109 | 110 | > npx hint . 111 | > npx stylelint "**/*.{css,scss}" 112 | > npx eslint . 113 | 114 | ### Build 115 | 116 | To build the project, run the following command: 117 | 118 | ```bash 119 | npm run build 120 | ``` 121 | 122 | ### Webpack Development Server 123 | 124 | To run the webpack development server, execute the following command: 125 | 126 | ```bash 127 | npm start 128 | ``` 129 | 130 |

(back to top)

131 | 132 | 133 | ### Deployment 134 | 135 | You can deploy this project using github pages or other hosting sites like netlify.com 136 | 137 |

(back to top)

138 | 139 | ## 👥 Authors 140 | 141 | 👤 **Author1** 142 | 143 | 👤 Zuwaira Sadiq 144 | - GitHub: [@Zuwairanajma](https://github.com/Zuwairanajma) 145 | - Twitter: [@SadiqJuwairiyya](https://twitter.com/SadiqJuwairiyya) 146 | - LinkedIn: [Zuwaira Sadiq](https://www.linkedin.com/in/zuwaira-sadiq-566b891b0?) 147 | 148 |

(back to top)

149 | 150 | 151 | ## 🔭 Future Features 152 | 153 | - [ ] **Functionalities** 154 | - [ ] **Improved UI design** 155 | - [ ] **Enhance Designs for all screen sizes and other media queries such as "print** 156 | 157 | 158 |

(back to top)

159 | 160 | ## 🤝 Contributing 161 | 162 | Contributions, issues, and feature requests are welcome! 163 | 164 |

(back to top)

165 | 166 | ## ⭐️ Show your support 167 | 168 | If you like this project, support and encourage me by staring it and leaving a comment. 169 | 170 |

(back to top)

171 | 172 | ## 🙏 Acknowledgments 173 | 174 | I would like to appreciate and acknowledge the esteem Microverse program for providing me with necessary template files and detailed instructions. 175 | 176 |

(back to top)

177 | 178 | 179 | ## 📝 License 180 | 181 | This project is [MIT](./LICENSE) licensed. 182 | 183 |

(back to top)

184 | -------------------------------------------------------------------------------- /dist/main.bundle.js: -------------------------------------------------------------------------------- 1 | /* 2 | * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). 3 | * This devtool is neither made for production nor for readable output files. 4 | * It uses "eval()" calls to create a separate source file in the browser devtools. 5 | * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) 6 | * or disable the default devtool with "devtool: false". 7 | * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). 8 | */ 9 | /******/ (() => { // webpackBootstrap 10 | /******/ "use strict"; 11 | /******/ var __webpack_modules__ = ({ 12 | 13 | /***/ "./node_modules/css-loader/dist/cjs.js!./src/index.css": 14 | /*!*************************************************************!*\ 15 | !*** ./node_modules/css-loader/dist/cjs.js!./src/index.css ***! 16 | \*************************************************************/ 17 | /***/ ((module, __webpack_exports__, __webpack_require__) => { 18 | 19 | eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_getUrl_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../node_modules/css-loader/dist/runtime/getUrl.js */ \"./node_modules/css-loader/dist/runtime/getUrl.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_getUrl_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_getUrl_js__WEBPACK_IMPORTED_MODULE_2__);\n// Imports\n\n\n\nvar ___CSS_LOADER_URL_IMPORT_0___ = new URL(/* asset import */ __webpack_require__(/*! ../asset/background.jpg */ \"./asset/background.jpg\"), __webpack_require__.b);\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n___CSS_LOADER_EXPORT___.push([module.id, \"@import url(https://fonts.googleapis.com/css2?family=Comfortaa:wght@300;400;500;600;700;900&display=swap);\"]);\nvar ___CSS_LOADER_URL_REPLACEMENT_0___ = _node_modules_css_loader_dist_runtime_getUrl_js__WEBPACK_IMPORTED_MODULE_2___default()(___CSS_LOADER_URL_IMPORT_0___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `:root {\r\n --main-color: #ff0;\r\n --light-white: rgba(255, 255, 255, 0.5);\r\n --light-black: rgba(0, 0, 0, 0.3);\r\n --light-bg: rgba(255, 255, 255, 0.1);\r\n --white: #fff;\r\n --black: #000;\r\n}\r\n\r\n* {\r\n font-family: \"Comfortaa\", cursive;\r\n margin: 0;\r\n padding: 0;\r\n box-sizing: border-box;\r\n text-decoration: none;\r\n}\r\n\r\nhtml {\r\n overflow-x: hidden;\r\n}\r\n\r\n#menu-btn {\r\n font-size: 2.5rem;\r\n cursor: pointer;\r\n color: var(--white);\r\n display: none;\r\n}\r\n\r\nbody {\r\n background-color: var(--black);\r\n\r\n /* background-color: white; */\r\n color: #000;\r\n border: 2px solid black;\r\n height: 100%;\r\n margin-top: 10px;\r\n}\r\n\r\n.header {\r\n margin-top: 40px;\r\n}\r\n\r\n.logo {\r\n text-decoration: none;\r\n color: black;\r\n font-weight: 800;\r\n font-size: 32px;\r\n margin-left: 24px;\r\n margin-bottom: -200px;\r\n}\r\n\r\n.header .navbar .logo {\r\n font-size: 2.5rem;\r\n color: var(--main-color);\r\n}\r\n\r\n.score-section {\r\n display: flex;\r\n flex-direction: column;\r\n margin-left: 75px;\r\n margin-top: 60px;\r\n}\r\n\r\n.score-container {\r\n margin-top: 35px;\r\n border: 2px solid black;\r\n margin-bottom: 35px;\r\n background-color: var(--light-white);\r\n}\r\n\r\n.score-header {\r\n display: flex;\r\n gap: 24px;\r\n}\r\n\r\nh2 {\r\n font-size: 24px;\r\n font-weight: 800;\r\n}\r\n\r\n.container-home h2 {\r\n padding-top: 1rem;\r\n font-size: 1.7rem;\r\n color: var(--light-white);\r\n}\r\n\r\n.container-home {\r\n display: flex;\r\n gap: 70px;\r\n background: no-repeat url(${___CSS_LOADER_URL_REPLACEMENT_0___}) rgba(0, 0, 0, 0.5);\r\n background-position: center;\r\n background-attachment: fixed;\r\n background-size: cover;\r\n background-blend-mode: multiply;\r\n}\r\n\r\n.add-score form {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 20px;\r\n margin: 60px 0;\r\n}\r\n\r\n.add-score input {\r\n border: 2px solid black;\r\n height: 40px;\r\n width: 250px;\r\n}\r\n\r\n.input {\r\n margin-top: 25px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 24px;\r\n}\r\n\r\nli {\r\n list-style: none;\r\n align-items: center;\r\n font-size: 1rem;\r\n padding: 0.5rem 0;\r\n border-bottom: 1px solid grey;\r\n width: 300px;\r\n font-weight: bold;\r\n background-color: lightgray;\r\n}\r\n\r\nli:nth-child(odd) {\r\n background-color: white;\r\n}\r\n\r\n.refresh-btn {\r\n margin-top: 18px;\r\n}\r\n\r\nspan {\r\n margin-left: 10px;\r\n}\r\n\r\n.btn {\r\n display: block;\r\n border-radius: 0.5rem;\r\n cursor: pointer;\r\n text-align: center;\r\n font-size: 1rem;\r\n transition: 0.2s linear;\r\n width: 100px;\r\n font-weight: 700;\r\n background-color: white;\r\n height: 34px;\r\n}\r\n\r\n.submit-btn {\r\n margin-left: 150px;\r\n}\r\n\r\nfooter {\r\n background-color: grey;\r\n border: 2px solid black;\r\n height: 35px;\r\n width: 100%;\r\n}\r\n\r\n.error-msg {\r\n display: none;\r\n}\r\n\r\n@media (max-width: 645px) {\r\n .container-home {\r\n flex-direction: column-reverse;\r\n align-items: center;\r\n width: 100%;\r\n background-color: grey;\r\n }\r\n\r\n .score-section {\r\n margin-top: -50px;\r\n margin-bottom: 30px;\r\n flex-direction: column;\r\n flex-wrap: wrap;\r\n margin-left: 20px;\r\n }\r\n\r\n section .add-form {\r\n width: 100%;\r\n }\r\n\r\n #menu-btn {\r\n display: block;\r\n margin-right: 20px;\r\n }\r\n\r\n .navbar {\r\n display: flex;\r\n justify-content: space-between;\r\n }\r\n\r\n .refresh-btn {\r\n margin-top: 18px;\r\n }\r\n}\r\n`, \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://webpack-linters-module2/./src/index.css?./node_modules/css-loader/dist/cjs.js"); 20 | 21 | /***/ }), 22 | 23 | /***/ "./node_modules/css-loader/dist/runtime/api.js": 24 | /*!*****************************************************!*\ 25 | !*** ./node_modules/css-loader/dist/runtime/api.js ***! 26 | \*****************************************************/ 27 | /***/ ((module) => { 28 | 29 | eval("\n\n/*\n MIT License http://www.opensource.org/licenses/mit-license.php\n Author Tobias Koppers @sokra\n*/\nmodule.exports = function (cssWithMappingToString) {\n var list = [];\n\n // return the list of modules as css string\n list.toString = function toString() {\n return this.map(function (item) {\n var content = \"\";\n var needLayer = typeof item[5] !== \"undefined\";\n if (item[4]) {\n content += \"@supports (\".concat(item[4], \") {\");\n }\n if (item[2]) {\n content += \"@media \".concat(item[2], \" {\");\n }\n if (needLayer) {\n content += \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\");\n }\n content += cssWithMappingToString(item);\n if (needLayer) {\n content += \"}\";\n }\n if (item[2]) {\n content += \"}\";\n }\n if (item[4]) {\n content += \"}\";\n }\n return content;\n }).join(\"\");\n };\n\n // import a list of modules into the list\n list.i = function i(modules, media, dedupe, supports, layer) {\n if (typeof modules === \"string\") {\n modules = [[null, modules, undefined]];\n }\n var alreadyImportedModules = {};\n if (dedupe) {\n for (var k = 0; k < this.length; k++) {\n var id = this[k][0];\n if (id != null) {\n alreadyImportedModules[id] = true;\n }\n }\n }\n for (var _k = 0; _k < modules.length; _k++) {\n var item = [].concat(modules[_k]);\n if (dedupe && alreadyImportedModules[item[0]]) {\n continue;\n }\n if (typeof layer !== \"undefined\") {\n if (typeof item[5] === \"undefined\") {\n item[5] = layer;\n } else {\n item[1] = \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\").concat(item[1], \"}\");\n item[5] = layer;\n }\n }\n if (media) {\n if (!item[2]) {\n item[2] = media;\n } else {\n item[1] = \"@media \".concat(item[2], \" {\").concat(item[1], \"}\");\n item[2] = media;\n }\n }\n if (supports) {\n if (!item[4]) {\n item[4] = \"\".concat(supports);\n } else {\n item[1] = \"@supports (\".concat(item[4], \") {\").concat(item[1], \"}\");\n item[4] = supports;\n }\n }\n list.push(item);\n }\n };\n return list;\n};\n\n//# sourceURL=webpack://webpack-linters-module2/./node_modules/css-loader/dist/runtime/api.js?"); 30 | 31 | /***/ }), 32 | 33 | /***/ "./node_modules/css-loader/dist/runtime/getUrl.js": 34 | /*!********************************************************!*\ 35 | !*** ./node_modules/css-loader/dist/runtime/getUrl.js ***! 36 | \********************************************************/ 37 | /***/ ((module) => { 38 | 39 | eval("\n\nmodule.exports = function (url, options) {\n if (!options) {\n options = {};\n }\n if (!url) {\n return url;\n }\n url = String(url.__esModule ? url.default : url);\n\n // If url is already wrapped in quotes, remove them\n if (/^['\"].*['\"]$/.test(url)) {\n url = url.slice(1, -1);\n }\n if (options.hash) {\n url += options.hash;\n }\n\n // Should url be wrapped?\n // See https://drafts.csswg.org/css-values-3/#urls\n if (/[\"'() \\t\\n]|(%20)/.test(url) || options.needQuotes) {\n return \"\\\"\".concat(url.replace(/\"/g, '\\\\\"').replace(/\\n/g, \"\\\\n\"), \"\\\"\");\n }\n return url;\n};\n\n//# sourceURL=webpack://webpack-linters-module2/./node_modules/css-loader/dist/runtime/getUrl.js?"); 40 | 41 | /***/ }), 42 | 43 | /***/ "./node_modules/css-loader/dist/runtime/noSourceMaps.js": 44 | /*!**************************************************************!*\ 45 | !*** ./node_modules/css-loader/dist/runtime/noSourceMaps.js ***! 46 | \**************************************************************/ 47 | /***/ ((module) => { 48 | 49 | eval("\n\nmodule.exports = function (i) {\n return i[1];\n};\n\n//# sourceURL=webpack://webpack-linters-module2/./node_modules/css-loader/dist/runtime/noSourceMaps.js?"); 50 | 51 | /***/ }), 52 | 53 | /***/ "./src/index.css": 54 | /*!***********************!*\ 55 | !*** ./src/index.css ***! 56 | \***********************/ 57 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { 58 | 59 | eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ \"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !../node_modules/style-loader/dist/runtime/styleDomAPI.js */ \"./node_modules/style-loader/dist/runtime/styleDomAPI.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! !../node_modules/style-loader/dist/runtime/insertBySelector.js */ \"./node_modules/style-loader/dist/runtime/insertBySelector.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! !../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js */ \"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! !../node_modules/style-loader/dist/runtime/insertStyleElement.js */ \"./node_modules/style-loader/dist/runtime/insertStyleElement.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! !../node_modules/style-loader/dist/runtime/styleTagTransform.js */ \"./node_modules/style-loader/dist/runtime/styleTagTransform.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _node_modules_css_loader_dist_cjs_js_index_css__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! !!../node_modules/css-loader/dist/cjs.js!./index.css */ \"./node_modules/css-loader/dist/cjs.js!./src/index.css\");\n\n \n \n \n \n \n \n \n \n \n\nvar options = {};\n\noptions.styleTagTransform = (_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default());\noptions.setAttributes = (_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default());\n\n options.insert = _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, \"head\");\n \noptions.domAPI = (_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default());\noptions.insertStyleElement = (_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default());\n\nvar update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_index_css__WEBPACK_IMPORTED_MODULE_6__[\"default\"], options);\n\n\n\n\n /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_node_modules_css_loader_dist_cjs_js_index_css__WEBPACK_IMPORTED_MODULE_6__[\"default\"] && _node_modules_css_loader_dist_cjs_js_index_css__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals ? _node_modules_css_loader_dist_cjs_js_index_css__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals : undefined);\n\n\n//# sourceURL=webpack://webpack-linters-module2/./src/index.css?"); 60 | 61 | /***/ }), 62 | 63 | /***/ "./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js": 64 | /*!****************************************************************************!*\ 65 | !*** ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js ***! 66 | \****************************************************************************/ 67 | /***/ ((module) => { 68 | 69 | eval("\n\nvar stylesInDOM = [];\nfunction getIndexByIdentifier(identifier) {\n var result = -1;\n for (var i = 0; i < stylesInDOM.length; i++) {\n if (stylesInDOM[i].identifier === identifier) {\n result = i;\n break;\n }\n }\n return result;\n}\nfunction modulesToDom(list, options) {\n var idCountMap = {};\n var identifiers = [];\n for (var i = 0; i < list.length; i++) {\n var item = list[i];\n var id = options.base ? item[0] + options.base : item[0];\n var count = idCountMap[id] || 0;\n var identifier = \"\".concat(id, \" \").concat(count);\n idCountMap[id] = count + 1;\n var indexByIdentifier = getIndexByIdentifier(identifier);\n var obj = {\n css: item[1],\n media: item[2],\n sourceMap: item[3],\n supports: item[4],\n layer: item[5]\n };\n if (indexByIdentifier !== -1) {\n stylesInDOM[indexByIdentifier].references++;\n stylesInDOM[indexByIdentifier].updater(obj);\n } else {\n var updater = addElementStyle(obj, options);\n options.byIndex = i;\n stylesInDOM.splice(i, 0, {\n identifier: identifier,\n updater: updater,\n references: 1\n });\n }\n identifiers.push(identifier);\n }\n return identifiers;\n}\nfunction addElementStyle(obj, options) {\n var api = options.domAPI(options);\n api.update(obj);\n var updater = function updater(newObj) {\n if (newObj) {\n if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) {\n return;\n }\n api.update(obj = newObj);\n } else {\n api.remove();\n }\n };\n return updater;\n}\nmodule.exports = function (list, options) {\n options = options || {};\n list = list || [];\n var lastIdentifiers = modulesToDom(list, options);\n return function update(newList) {\n newList = newList || [];\n for (var i = 0; i < lastIdentifiers.length; i++) {\n var identifier = lastIdentifiers[i];\n var index = getIndexByIdentifier(identifier);\n stylesInDOM[index].references--;\n }\n var newLastIdentifiers = modulesToDom(newList, options);\n for (var _i = 0; _i < lastIdentifiers.length; _i++) {\n var _identifier = lastIdentifiers[_i];\n var _index = getIndexByIdentifier(_identifier);\n if (stylesInDOM[_index].references === 0) {\n stylesInDOM[_index].updater();\n stylesInDOM.splice(_index, 1);\n }\n }\n lastIdentifiers = newLastIdentifiers;\n };\n};\n\n//# sourceURL=webpack://webpack-linters-module2/./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js?"); 70 | 71 | /***/ }), 72 | 73 | /***/ "./node_modules/style-loader/dist/runtime/insertBySelector.js": 74 | /*!********************************************************************!*\ 75 | !*** ./node_modules/style-loader/dist/runtime/insertBySelector.js ***! 76 | \********************************************************************/ 77 | /***/ ((module) => { 78 | 79 | eval("\n\nvar memo = {};\n\n/* istanbul ignore next */\nfunction getTarget(target) {\n if (typeof memo[target] === \"undefined\") {\n var styleTarget = document.querySelector(target);\n\n // Special case to return head of iframe instead of iframe itself\n if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {\n try {\n // This will throw an exception if access to iframe is blocked\n // due to cross-origin restrictions\n styleTarget = styleTarget.contentDocument.head;\n } catch (e) {\n // istanbul ignore next\n styleTarget = null;\n }\n }\n memo[target] = styleTarget;\n }\n return memo[target];\n}\n\n/* istanbul ignore next */\nfunction insertBySelector(insert, style) {\n var target = getTarget(insert);\n if (!target) {\n throw new Error(\"Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.\");\n }\n target.appendChild(style);\n}\nmodule.exports = insertBySelector;\n\n//# sourceURL=webpack://webpack-linters-module2/./node_modules/style-loader/dist/runtime/insertBySelector.js?"); 80 | 81 | /***/ }), 82 | 83 | /***/ "./node_modules/style-loader/dist/runtime/insertStyleElement.js": 84 | /*!**********************************************************************!*\ 85 | !*** ./node_modules/style-loader/dist/runtime/insertStyleElement.js ***! 86 | \**********************************************************************/ 87 | /***/ ((module) => { 88 | 89 | eval("\n\n/* istanbul ignore next */\nfunction insertStyleElement(options) {\n var element = document.createElement(\"style\");\n options.setAttributes(element, options.attributes);\n options.insert(element, options.options);\n return element;\n}\nmodule.exports = insertStyleElement;\n\n//# sourceURL=webpack://webpack-linters-module2/./node_modules/style-loader/dist/runtime/insertStyleElement.js?"); 90 | 91 | /***/ }), 92 | 93 | /***/ "./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js": 94 | /*!**********************************************************************************!*\ 95 | !*** ./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js ***! 96 | \**********************************************************************************/ 97 | /***/ ((module, __unused_webpack_exports, __webpack_require__) => { 98 | 99 | eval("\n\n/* istanbul ignore next */\nfunction setAttributesWithoutAttributes(styleElement) {\n var nonce = true ? __webpack_require__.nc : 0;\n if (nonce) {\n styleElement.setAttribute(\"nonce\", nonce);\n }\n}\nmodule.exports = setAttributesWithoutAttributes;\n\n//# sourceURL=webpack://webpack-linters-module2/./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js?"); 100 | 101 | /***/ }), 102 | 103 | /***/ "./node_modules/style-loader/dist/runtime/styleDomAPI.js": 104 | /*!***************************************************************!*\ 105 | !*** ./node_modules/style-loader/dist/runtime/styleDomAPI.js ***! 106 | \***************************************************************/ 107 | /***/ ((module) => { 108 | 109 | eval("\n\n/* istanbul ignore next */\nfunction apply(styleElement, options, obj) {\n var css = \"\";\n if (obj.supports) {\n css += \"@supports (\".concat(obj.supports, \") {\");\n }\n if (obj.media) {\n css += \"@media \".concat(obj.media, \" {\");\n }\n var needLayer = typeof obj.layer !== \"undefined\";\n if (needLayer) {\n css += \"@layer\".concat(obj.layer.length > 0 ? \" \".concat(obj.layer) : \"\", \" {\");\n }\n css += obj.css;\n if (needLayer) {\n css += \"}\";\n }\n if (obj.media) {\n css += \"}\";\n }\n if (obj.supports) {\n css += \"}\";\n }\n var sourceMap = obj.sourceMap;\n if (sourceMap && typeof btoa !== \"undefined\") {\n css += \"\\n/*# sourceMappingURL=data:application/json;base64,\".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), \" */\");\n }\n\n // For old IE\n /* istanbul ignore if */\n options.styleTagTransform(css, styleElement, options.options);\n}\nfunction removeStyleElement(styleElement) {\n // istanbul ignore if\n if (styleElement.parentNode === null) {\n return false;\n }\n styleElement.parentNode.removeChild(styleElement);\n}\n\n/* istanbul ignore next */\nfunction domAPI(options) {\n if (typeof document === \"undefined\") {\n return {\n update: function update() {},\n remove: function remove() {}\n };\n }\n var styleElement = options.insertStyleElement(options);\n return {\n update: function update(obj) {\n apply(styleElement, options, obj);\n },\n remove: function remove() {\n removeStyleElement(styleElement);\n }\n };\n}\nmodule.exports = domAPI;\n\n//# sourceURL=webpack://webpack-linters-module2/./node_modules/style-loader/dist/runtime/styleDomAPI.js?"); 110 | 111 | /***/ }), 112 | 113 | /***/ "./node_modules/style-loader/dist/runtime/styleTagTransform.js": 114 | /*!*********************************************************************!*\ 115 | !*** ./node_modules/style-loader/dist/runtime/styleTagTransform.js ***! 116 | \*********************************************************************/ 117 | /***/ ((module) => { 118 | 119 | eval("\n\n/* istanbul ignore next */\nfunction styleTagTransform(css, styleElement) {\n if (styleElement.styleSheet) {\n styleElement.styleSheet.cssText = css;\n } else {\n while (styleElement.firstChild) {\n styleElement.removeChild(styleElement.firstChild);\n }\n styleElement.appendChild(document.createTextNode(css));\n }\n}\nmodule.exports = styleTagTransform;\n\n//# sourceURL=webpack://webpack-linters-module2/./node_modules/style-loader/dist/runtime/styleTagTransform.js?"); 120 | 121 | /***/ }), 122 | 123 | /***/ "./src/index.js": 124 | /*!**********************!*\ 125 | !*** ./src/index.js ***! 126 | \**********************/ 127 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { 128 | 129 | eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _index_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./index.css */ \"./src/index.css\");\n/* harmony import */ var _modules_boardApi_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./modules/boardApi.js */ \"./src/modules/boardApi.js\");\n\n\n\n// Refresh scores and update the UI\nconst refreshScores = async () => {\n const scoresContainer = document.getElementById('scores-container');\n scoresContainer.innerHTML = '';\n\n try {\n const scores = await (0,_modules_boardApi_js__WEBPACK_IMPORTED_MODULE_1__.retrieveScores)();\n\n if (scores.length === 0) {\n const noScoresMessage = document.createElement('p');\n noScoresMessage.textContent = 'Lets begin';\n scoresContainer.appendChild(noScoresMessage);\n } else {\n scores.forEach(({ user, score }) => {\n const listItem = document.createElement('li');\n const playerNameSpan = document.createElement('span');\n playerNameSpan.textContent = user;\n const scoreSpan = document.createElement('span');\n scoreSpan.textContent = score;\n const seperator = document.createElement('span');\n seperator.textContent = ': ';\n listItem.appendChild(playerNameSpan);\n listItem.appendChild(seperator);\n listItem.appendChild(scoreSpan);\n scoresContainer.appendChild(listItem);\n });\n }\n } catch (error) {\n // Handle API request error\n console.error('Error retrieving scores:', error.message);\n }\n};\n\n// Event listener for the Refresh button\nconst refreshButton = document.getElementById('refresh-button');\nrefreshButton.addEventListener('click', refreshScores);\n\n// Event listener for the Submit button\nconst submitForm = document.querySelector('.add-form');\nsubmitForm.addEventListener('submit', async (e) => {\n e.preventDefault();\n const { Player: userName, score } = submitForm.elements;\n\n (0,_modules_boardApi_js__WEBPACK_IMPORTED_MODULE_1__.addYourScore)(userName.value, score.value);\n submitForm.reset();\n refreshScores();\n});\n\n// Create a new game and initialize the app\ndocument.addEventListener('DOMContentLoaded', async () => {\n const gameName = 'My Beauty Game';\n try {\n await (0,_modules_boardApi_js__WEBPACK_IMPORTED_MODULE_1__.createGame)(gameName);\n await refreshScores();\n } catch (error) {\n // Handle API request error\n console.error('Error creating new game:', error.message);\n }\n});\n\n\n//# sourceURL=webpack://webpack-linters-module2/./src/index.js?"); 130 | 131 | /***/ }), 132 | 133 | /***/ "./src/modules/boardApi.js": 134 | /*!*********************************!*\ 135 | !*** ./src/modules/boardApi.js ***! 136 | \*********************************/ 137 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { 138 | 139 | eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ addYourScore: () => (/* binding */ addYourScore),\n/* harmony export */ createGame: () => (/* binding */ createGame),\n/* harmony export */ getGameId: () => (/* binding */ getGameId),\n/* harmony export */ retrieveScores: () => (/* binding */ retrieveScores)\n/* harmony export */ });\n// Helper function to handle API errors\nconst handleApiError = (error) => {\n // Handle API request error\n console.error('An error occurred:', error);\n};\n\n// Helper function to make API requests\nconst makeApiRequest = async (url, method, body) => {\n try {\n const response = await fetch(url, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n throw new Error('API request failed');\n }\n\n const { result } = await response.json();\n return result;\n } catch (error) {\n handleApiError(error);\n throw error; // Re-throw the error to be handled by the caller\n }\n};\n\n// Create a new game and save the game ID\nconst createGame = async (gameName) => {\n try {\n const response = await makeApiRequest('https://us-central1-js-capstone-backend.cloudfunctions.net/api/games/', 'POST', {\n name: gameName,\n });\n\n const gameId = response.split(' ')[3];\n localStorage.setItem('gameId', gameId);\n } catch (error) {\n handleApiError(error);\n throw error; // Re-throw the error to be handled by the caller\n }\n};\n\n// Retrieve the game ID from local storage\nconst getGameId = () => localStorage.getItem('gameId');\n\n// Retrieve all scores for the game\nconst retrieveScores = async () => {\n const gameId = getGameId();\n try {\n const response = await makeApiRequest(`https://us-central1-js-capstone-backend.cloudfunctions.net/api/games/${gameId}/scores/`, 'GET');\n return response;\n } catch (error) {\n handleApiError(error);\n return []; // Return an empty array to indicate no scores available\n }\n};\n\n// Save a score for the game\nconst addYourScore = async (userName, score) => {\n const gameId = getGameId();\n // Validate user input\n if (!userName || !score || Number.isNaN(parseInt(score, 10))) {\n // Invalid input, handle the error appropriately\n return;\n }\n\n try {\n await makeApiRequest(`https://us-central1-js-capstone-backend.cloudfunctions.net/api/games/${gameId}/scores/`, 'POST', {\n user: userName,\n score: parseInt(score, 10),\n });\n } catch (error) {\n handleApiError(error);\n throw error; // Re-throw the error to be handled by the caller\n }\n};\n\n\n//# sourceURL=webpack://webpack-linters-module2/./src/modules/boardApi.js?"); 140 | 141 | /***/ }), 142 | 143 | /***/ "./asset/background.jpg": 144 | /*!******************************!*\ 145 | !*** ./asset/background.jpg ***! 146 | \******************************/ 147 | /***/ ((module, __unused_webpack_exports, __webpack_require__) => { 148 | 149 | eval("module.exports = __webpack_require__.p + \"8074b963e8861cabb850.jpg\";\n\n//# sourceURL=webpack://webpack-linters-module2/./asset/background.jpg?"); 150 | 151 | /***/ }) 152 | 153 | /******/ }); 154 | /************************************************************************/ 155 | /******/ // The module cache 156 | /******/ var __webpack_module_cache__ = {}; 157 | /******/ 158 | /******/ // The require function 159 | /******/ function __webpack_require__(moduleId) { 160 | /******/ // Check if module is in cache 161 | /******/ var cachedModule = __webpack_module_cache__[moduleId]; 162 | /******/ if (cachedModule !== undefined) { 163 | /******/ return cachedModule.exports; 164 | /******/ } 165 | /******/ // Create a new module (and put it into the cache) 166 | /******/ var module = __webpack_module_cache__[moduleId] = { 167 | /******/ id: moduleId, 168 | /******/ // no module.loaded needed 169 | /******/ exports: {} 170 | /******/ }; 171 | /******/ 172 | /******/ // Execute the module function 173 | /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); 174 | /******/ 175 | /******/ // Return the exports of the module 176 | /******/ return module.exports; 177 | /******/ } 178 | /******/ 179 | /******/ // expose the modules object (__webpack_modules__) 180 | /******/ __webpack_require__.m = __webpack_modules__; 181 | /******/ 182 | /************************************************************************/ 183 | /******/ /* webpack/runtime/compat get default export */ 184 | /******/ (() => { 185 | /******/ // getDefaultExport function for compatibility with non-harmony modules 186 | /******/ __webpack_require__.n = (module) => { 187 | /******/ var getter = module && module.__esModule ? 188 | /******/ () => (module['default']) : 189 | /******/ () => (module); 190 | /******/ __webpack_require__.d(getter, { a: getter }); 191 | /******/ return getter; 192 | /******/ }; 193 | /******/ })(); 194 | /******/ 195 | /******/ /* webpack/runtime/define property getters */ 196 | /******/ (() => { 197 | /******/ // define getter functions for harmony exports 198 | /******/ __webpack_require__.d = (exports, definition) => { 199 | /******/ for(var key in definition) { 200 | /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { 201 | /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); 202 | /******/ } 203 | /******/ } 204 | /******/ }; 205 | /******/ })(); 206 | /******/ 207 | /******/ /* webpack/runtime/global */ 208 | /******/ (() => { 209 | /******/ __webpack_require__.g = (function() { 210 | /******/ if (typeof globalThis === 'object') return globalThis; 211 | /******/ try { 212 | /******/ return this || new Function('return this')(); 213 | /******/ } catch (e) { 214 | /******/ if (typeof window === 'object') return window; 215 | /******/ } 216 | /******/ })(); 217 | /******/ })(); 218 | /******/ 219 | /******/ /* webpack/runtime/hasOwnProperty shorthand */ 220 | /******/ (() => { 221 | /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) 222 | /******/ })(); 223 | /******/ 224 | /******/ /* webpack/runtime/make namespace object */ 225 | /******/ (() => { 226 | /******/ // define __esModule on exports 227 | /******/ __webpack_require__.r = (exports) => { 228 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 229 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 230 | /******/ } 231 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 232 | /******/ }; 233 | /******/ })(); 234 | /******/ 235 | /******/ /* webpack/runtime/publicPath */ 236 | /******/ (() => { 237 | /******/ var scriptUrl; 238 | /******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + ""; 239 | /******/ var document = __webpack_require__.g.document; 240 | /******/ if (!scriptUrl && document) { 241 | /******/ if (document.currentScript) 242 | /******/ scriptUrl = document.currentScript.src; 243 | /******/ if (!scriptUrl) { 244 | /******/ var scripts = document.getElementsByTagName("script"); 245 | /******/ if(scripts.length) { 246 | /******/ var i = scripts.length - 1; 247 | /******/ while (i > -1 && !scriptUrl) scriptUrl = scripts[i--].src; 248 | /******/ } 249 | /******/ } 250 | /******/ } 251 | /******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration 252 | /******/ // or pass an empty string ("") and set the __webpack_public_path__ variable from your code to use your own logic. 253 | /******/ if (!scriptUrl) throw new Error("Automatic publicPath is not supported in this browser"); 254 | /******/ scriptUrl = scriptUrl.replace(/#.*$/, "").replace(/\?.*$/, "").replace(/\/[^\/]+$/, "/"); 255 | /******/ __webpack_require__.p = scriptUrl; 256 | /******/ })(); 257 | /******/ 258 | /******/ /* webpack/runtime/jsonp chunk loading */ 259 | /******/ (() => { 260 | /******/ __webpack_require__.b = document.baseURI || self.location.href; 261 | /******/ 262 | /******/ // object to store loaded and loading chunks 263 | /******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched 264 | /******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded 265 | /******/ var installedChunks = { 266 | /******/ "main": 0 267 | /******/ }; 268 | /******/ 269 | /******/ // no chunk on demand loading 270 | /******/ 271 | /******/ // no prefetching 272 | /******/ 273 | /******/ // no preloaded 274 | /******/ 275 | /******/ // no HMR 276 | /******/ 277 | /******/ // no HMR manifest 278 | /******/ 279 | /******/ // no on chunks loaded 280 | /******/ 281 | /******/ // no jsonp function 282 | /******/ })(); 283 | /******/ 284 | /******/ /* webpack/runtime/nonce */ 285 | /******/ (() => { 286 | /******/ __webpack_require__.nc = undefined; 287 | /******/ })(); 288 | /******/ 289 | /************************************************************************/ 290 | /******/ 291 | /******/ // startup 292 | /******/ // Load entry module and return exports 293 | /******/ // This entry module can't be inlined because the eval devtool is used. 294 | /******/ var __webpack_exports__ = __webpack_require__("./src/index.js"); 295 | /******/ 296 | /******/ })() 297 | ; --------------------------------------------------------------------------------