├── .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 |
12 |
13 |
14 |
23 |
24 |
25 | Add you score
26 |
31 |
32 |
33 | Your score has been added successfully. ✅ 🎯
34 |
35 |
36 | Something went wrong, please try again. 🚫
37 |
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 |
46 | - HTML
47 | - CSS
48 | - JavaScript
49 | - Webpack
50 |
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 |
--------------------------------------------------------------------------------