├── .all-contributorsrc ├── .eslintignore ├── .eslintrc.json ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── custom.md │ └── feature_request.md └── workflows │ └── ci.yml ├── .gitignore ├── .husky ├── pre-commit └── pre-push ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── public ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── index.html ├── manifest.json └── robots.txt ├── src ├── App.css ├── App.js ├── Components │ ├── Footer.js │ ├── Navbar.js │ ├── NoData.js │ ├── Page.js │ ├── ScrollToTop.js │ ├── ScrollToTopBtn.js │ └── Spinner.js ├── Pages │ ├── Home │ │ ├── Contributor.js │ │ ├── Features.js │ │ ├── HeroSec.js │ │ └── index.js │ ├── ResourceREADME │ │ ├── OtherReposByAuthorModal.js │ │ ├── PdfContainer.js │ │ ├── ReadmeUtilsBtn.js │ │ ├── code-blocks.js │ │ └── index.js │ └── Resources │ │ ├── ResourceCard.js │ │ ├── ResourceCards.js │ │ ├── SearchInput.js │ │ ├── Suggestion.js │ │ └── index.js ├── assets │ └── no_data.svg ├── context │ ├── resources │ │ ├── resourceContext.js │ │ ├── resourceReducer.js │ │ └── resourceState.js │ ├── theme │ │ ├── themeContext.js │ │ ├── themeReducer.js │ │ └── themeState.js │ └── types.js ├── data │ ├── contributors.js │ └── resourcesData.js ├── index.css ├── index.js └── serviceWorker.js └── yarn.lock /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "contributors": [ 8 | { 9 | "login": "Binu42", 10 | "name": "Binu kumar", 11 | "avatar_url": "https://avatars2.githubusercontent.com/u/45959932?v=4", 12 | "profile": "http://www.binu.live", 13 | "contributions": [ 14 | "infra", 15 | "code", 16 | "test", 17 | "maintenance", 18 | "ideas" 19 | ] 20 | }, 21 | { 22 | "login": "jaydeepkhatri", 23 | "name": "Jaydeep Khatri", 24 | "avatar_url": "https://avatars0.githubusercontent.com/u/29619945?v=4", 25 | "profile": "https://jaydeepkhatri.me/", 26 | "contributions": [ 27 | "content" 28 | ] 29 | }, 30 | { 31 | "login": "zoltanszogyenyi", 32 | "name": "Zoltán Szőgyényi", 33 | "avatar_url": "https://avatars1.githubusercontent.com/u/8052108?v=4", 34 | "profile": "https://themesberg.com", 35 | "contributions": [ 36 | "content" 37 | ] 38 | }, 39 | { 40 | "login": "jackdolgin", 41 | "name": "Jack Dolgin", 42 | "avatar_url": "https://avatars0.githubusercontent.com/u/29798528?v=4", 43 | "contributions": [ 44 | "content" 45 | ] 46 | }, 47 | { 48 | "login": "hdquemada", 49 | "name": "Hector Quemada", 50 | "avatar_url": "https://avatars3.githubusercontent.com/u/44162051?v=4", 51 | "profile": "https://github.com/hdquemada", 52 | "contributions": [ 53 | "content" 54 | ] 55 | }, 56 | { 57 | "login": "pkumars397", 58 | "name": "Prashant Kumar", 59 | "avatar_url": "https://avatars1.githubusercontent.com/u/45540448?v=4", 60 | "profile": "https://github.com/pkumars397", 61 | "contributions": [ 62 | "content" 63 | ] 64 | }, 65 | { 66 | "login": "harshloco", 67 | "name": "Harshpreet Singh", 68 | "avatar_url": "https://avatars1.githubusercontent.com/u/5271603?v=4", 69 | "profile": "https://github.com/harshloco", 70 | "contributions": [ 71 | "content" 72 | ] 73 | }, 74 | { 75 | "login": "VolailleInc", 76 | "name": "Abdul-Razak", 77 | "avatar_url": "https://avatars1.githubusercontent.com/u/36109125?v=4", 78 | "profile": "http://www.panafsoft.com", 79 | "contributions": [ 80 | "content" 81 | ] 82 | }, 83 | { 84 | "login": "jmannfeld", 85 | "name": "Jordan Mannfeld", 86 | "avatar_url": "https://avatars2.githubusercontent.com/u/16351524?v=4", 87 | "profile": "https://github.com/jmannfeld", 88 | "contributions": [ 89 | "content" 90 | ] 91 | }, 92 | { 93 | "login": "Lord-Aman", 94 | "name": "Aman", 95 | "avatar_url": "https://avatars1.githubusercontent.com/u/65647302?v=4", 96 | "profile": "https://github.com/Lord-Aman", 97 | "contributions": [ 98 | "content" 99 | ] 100 | }, 101 | { 102 | "login": "Muhammed-Rahif", 103 | "name": "Muhammed Rahif", 104 | "avatar_url": "https://avatars.githubusercontent.com/u/73386156?v=4", 105 | "profile": "http://muhammed-rahif.github.io", 106 | "contributions": [ 107 | "data", 108 | "content" 109 | ] 110 | }, 111 | { 112 | "login": "eltociear", 113 | "name": "Ikko Ashimine", 114 | "avatar_url": "https://avatars.githubusercontent.com/u/22633385?v=4", 115 | "profile": "https://bandism.net/", 116 | "contributions": [ 117 | "content" 118 | ] 119 | } 120 | ], 121 | "contributorsPerLine": 7, 122 | "projectName": "webDevsCom", 123 | "projectOwner": "WebDevsCom", 124 | "repoType": "github", 125 | "repoHost": "https://github.com", 126 | "skipCi": true 127 | } 128 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/** -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true 5 | }, 6 | "extends": ["plugin:react/recommended", "airbnb"], 7 | "globals": { 8 | "Atomics": "readonly", 9 | "SharedArrayBuffer": "readonly" 10 | }, 11 | "parserOptions": { 12 | "ecmaFeatures": { 13 | "jsx": true 14 | }, 15 | "ecmaVersion": 2018, 16 | "sourceType": "module" 17 | }, 18 | "plugins": ["react"], 19 | "rules": { 20 | "trailing-comma": 0 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI/CD 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | matrix: 12 | node-version: [12.x] 13 | 14 | steps: 15 | - name: Checkout repository 16 | uses: actions/checkout@v2 17 | - name: Set up Node.js ${{ matrix.node-version }} 18 | uses: actions/setup-node@v1 19 | with: 20 | node-version: ${{ matrix.node-version }} 21 | 22 | - name: Install dependencies 23 | run: npm install 24 | 25 | - name: Build 26 | run: npm run build 27 | 28 | - name: Deploy 29 | uses: s0/git-publish-subdir-action@develop 30 | env: 31 | REPO: git@github.com:WebDevsCom/webDevsCom.github.io.git 32 | BRANCH: master 33 | FOLDER: build 34 | SSH_PRIVATE_KEY: ${{ secrets.ACTIONS_DEPLOY_KEY }} 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | # Local Netlify folder 26 | .netlify -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run lint:test -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run prepush -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 14.17.0 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /build 2 | /coverage 3 | /node_modules/** -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": true, 4 | "singleQuote": false, 5 | "tabWidth": 2, 6 | "trailingComma": "all", 7 | "bracketSpacing": false 8 | } 9 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at kbinu42@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contribute 2 | 3 | > Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. 4 | 5 | If you're new to contribute to Open Source on GitHub, [this guide](https://guides.github.com/activities/contributing-to-open-source/) can help you get started. Please check out the [contribution guide](CONTRIBUTING.md) for more details on how issues and pull requests work. 6 | 7 | ### Steps to add Resources 8 | 9 | - go to [/src/data/resourcesData.js](https://github.com/WebDevsCom/webDevsCom/blob/master/src/data/resourcesData.js) 10 | - structure of Data to add 11 | 12 | ```javascript 13 | { 14 | id: 9, // +1 than last available resource data 15 | link: 16 | 'https://raw.githubusercontent.com/dipakkr/A-to-Z-Resources-for-Students/master/README.md', // raw url Link of Repo. Readme file 17 | repoName: 'A-to-Z-Resources-for-Students', // Available Repo. name 18 | description: 19 | 'Curated list of resources for college students. you should definitely check this out.', // Description of Resources 20 | repoOwnerName: 'dipakkr', // Repo. owner name(Id) or Repo. owner organisation 21 | repoOwner: 'Deepak Kumar', // Repo. owner full name or Repo. owner organisation 22 | category: ['web-dev', 'mob-dev', 'course', 'language'], // category from which resource belong (choose from below available categories) 23 | } 24 | ``` 25 | 26 | - available categories:- 27 | - web-dev 28 | - mob-dev 29 | - frontend 30 | - backend 31 | - language 32 | - project 33 | - course 34 | - podcast 35 | - interview 36 | - productive 37 | - data-science 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 web Developer Community 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WEBDEVSCOM 2 | 3 | [![All Contributors](https://img.shields.io/badge/all_contributors-12-orange.svg?style=flat-square)](#contributors-) 4 | 5 | 6 | > Community to help developers by providing them all kinds of free resources at one place. 7 | 8 | [![Author](https://img.shields.io/badge/Author-Binu42-brightgreen.svg)](http://binu42.netlify.com/) 9 | [![Netlify Status](https://api.netlify.com/api/v1/badges/59163947-b980-4aac-a382-38e8fc98329b/deploy-status)](https://app.netlify.com/sites/webdevscom/deploys) 10 | ![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg) 11 | [![Repo Link](https://img.shields.io/badge/Repo-Link-black.svg)](https://github.com/WebDevsCom/webDevsCom) 12 | [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?)](https://github.com/prettier/prettier) 13 | 14 | #### [Looking for contributors in helping me to add this resources](https://github.com/WebDevsCom/webDevsCom/issues/9#issue-629936276) please not add more than 10 resources in one PR. 15 | 16 |

17 | 18 |

19 | 20 |

21 | View our Website on GitHub Pages | Website on Netlify. 22 |

23 | 24 | ## Main Libraries/Frameworks Used 25 | * [Bulma](https://bulma.io/documentation/components/card/) 26 | * [React](https://reactjs.org/) 27 | 28 | ## Installation 29 | if you have not installed nodeJS install it. then:- 30 |
31 | ```sh 32 | npm install && npm start 33 | ``` 34 | 35 | 36 | ## Contribute 37 | > Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. 38 | 39 | If you're new to contribute to Open Source on GitHub, [this guide](https://guides.github.com/activities/contributing-to-open-source/) can help you get started. Please check out the [contribution guide](CONTRIBUTING.md) for more details on how issues and pull requests work. 40 | 41 | ### Steps to add Resources 42 | * go to [/src/data/resourcesData.js](https://github.com/WebDevsCom/webDevsCom/blob/master/src/data/resourcesData.js) 43 | * structure of Data to add 44 | 45 | ```javascript 46 | { 47 | id: 9, // +1 than last available resource data 48 | link: 49 | 'https://raw.githubusercontent.com/dipakkr/A-to-Z-Resources-for-Students/master/README.md', // raw url Link of Repo. Readme file 50 | repoName: 'A-to-Z-Resources-for-Students', // Available Repo. name 51 | description: 52 | 'Curated list of resources for college students. you should definitely check this out.', // Description of Resources 53 | repoOwnerName: 'dipakkr', // Repo. owner name(Id) or Repo. owner organisation 54 | repoOwner: 'Deepak Kumar', // Repo. owner full name or Repo. owner organisation 55 | category: ['web-dev', 'mob-dev', 'course', 'language'], // category from which resource belong (choose from below available categories) 56 | } 57 | ``` 58 | 59 | * available categories:- 60 | - web-dev 61 | - mob-dev 62 | - frontend 63 | - backend 64 | - language 65 | - project 66 | - course 67 | - podcast 68 | - interview 69 | - productive 70 | - data-science 71 | 72 | 73 | ## Show your support 74 | 75 | show your :heart: and :+1: by giving :star: to this Repo. if this project helped you in anyways! 76 | 77 | ## Stars History 78 | 79 | [![Stargazers over time](https://starchart.cc/WebDevsCom/WebDevsCom.svg)](https://starchart.cc/WebDevsCom/WebDevsCom) 80 | 81 | ## License 82 | [MIT](https://choosealicense.com/licenses/mit/) 83 | 84 | ## Contributors ✨ 85 | 86 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 |

Binu kumar

🚇 💻 ⚠️ 🚧 🤔

Jaydeep Khatri

🖋

Zoltán Szőgyényi

🖋

Jack Dolgin
🖋

Hector Quemada

🖋

Prashant Kumar

🖋

Harshpreet Singh

🖋

Abdul-Razak

🖋

Jordan Mannfeld

🖋

Aman

🖋

Muhammed Rahif

🔣 🖋

Ikko Ashimine

🖋
109 | 110 | 111 | 112 | 113 | 114 | 115 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 116 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webdevscom", 3 | "version": "1.0.0", 4 | "type": "commonjs", 5 | "private": true, 6 | "homepage": "https://webDevsCom.github.io", 7 | "dependencies": { 8 | "@progress/kendo-drawing": "^1.7.0", 9 | "@progress/kendo-react-pdf": "^3.14.0", 10 | "axios": "^0.19.2", 11 | "bulma": "^0.8.2", 12 | "eslint": "^8.4.1", 13 | "github-slugger": "^1.3.0", 14 | "highlight.js": "^10.0.3", 15 | "react": "^16.13.1", 16 | "react-dom": "^16.13.1", 17 | "react-feather": "^2.0.8", 18 | "react-github-btn": "^1.2.0", 19 | "react-hotjar": "^2.2.1", 20 | "react-markdown": "^4.3.1", 21 | "react-router-dom": "^5.1.2", 22 | "react-scripts": "3.4.1", 23 | "react-tooltip": "^4.2.6" 24 | }, 25 | "scripts": { 26 | "start": "react-scripts start", 27 | "build": "SKIP_PREFLIGHT_CHECK=true react-scripts build && cp build/index.html build/404.html", 28 | "eject": "react-scripts eject", 29 | "netlify": "npm run build && netlify deploy --dir build && netlify deploy --prod --dir build", 30 | "deploy": "npm run netlify", 31 | "lint:test": "eslint . --ext .js --ext .jsx", 32 | "lint:fix": "eslint . --ext .js --ext .jsx --fix", 33 | "prettier": "prettier src/**/*.{js, jsx} --write", 34 | "precommit": "npm run lint:fix && npm run prettier", 35 | "prepush": "npm run lint:test", 36 | "prepare": "husky install" 37 | }, 38 | "eslintConfig": { 39 | "extends": "react-app" 40 | }, 41 | "browserslist": { 42 | "production": [ 43 | ">0.2%", 44 | "not dead", 45 | "not op_mini all" 46 | ], 47 | "development": [ 48 | "last 1 chrome version", 49 | "last 1 firefox version", 50 | "last 1 safari version" 51 | ] 52 | }, 53 | "devDependencies": { 54 | "eslint-config-airbnb": "^19.0.4", 55 | "eslint-config-prettier": "^8.5.0", 56 | "eslint-loader": "^4.0.2", 57 | "eslint-plugin-import": "^2.26.0", 58 | "eslint-plugin-jsx-a11y": "^6.6.1", 59 | "eslint-plugin-prettier": "^4.2.1", 60 | "eslint-plugin-react": "^7.31.10", 61 | "eslint-plugin-react-hooks": "^4.6.0", 62 | "husky": "^8.0.1", 63 | "lint-staged": "^13.0.3", 64 | "prettier": "2.7.1" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebDevsCom/webDevsCom/6d115a1ed64d8e8d14666e66f7a01249d9f5d5ed/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebDevsCom/webDevsCom/6d115a1ed64d8e8d14666e66f7a01249d9f5d5ed/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebDevsCom/webDevsCom/6d115a1ed64d8e8d14666e66f7a01249d9f5d5ed/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebDevsCom/webDevsCom/6d115a1ed64d8e8d14666e66f7a01249d9f5d5ed/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebDevsCom/webDevsCom/6d115a1ed64d8e8d14666e66f7a01249d9f5d5ed/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebDevsCom/webDevsCom/6d115a1ed64d8e8d14666e66f7a01249d9f5d5ed/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | WebDevsCom 14 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
53 | 54 | 55 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "WebDevsCom", 3 | "name": "Website to help developers by providing them helpful resources and giving experience of open source contribution.", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-512x512.png", 7 | "sizes": "512x512", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-192x192.png", 12 | "sizes": "192x192", 13 | "type": "image/png" 14 | } 15 | ], 16 | "start_url": ".", 17 | "display": "standalone", 18 | "theme_color": "#000000", 19 | "background_color": "#ffffff" 20 | } -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | /* Navbar */ 2 | .navbar .is-active { 3 | background-color: #f1eeee !important; 4 | color: #6c8eef !important; 5 | } 6 | 7 | .is-light { 8 | background-color: #f8faff !important; 9 | } 10 | 11 | .navbar-end > a.navbar-item:hover:not(.is-active) { 12 | color: #6c8eef !important; 13 | background-color: #f8faff !important; 14 | } 15 | 16 | .m-1 { 17 | margin: 10px !important; 18 | } 19 | 20 | /* Hero Section */ 21 | .space { 22 | background: linear-gradient(90deg, #f8faff 19px, transparent 1%) center, 23 | linear-gradient(#f8faff 19px, transparent 1%) center, #6c8eef; 24 | background-size: 22px 22px; 25 | transform: skewY(6deg); 26 | } 27 | 28 | .box-shadow-lift { 29 | box-shadow: rgba(0, 0, 0, 0.1) 0 7px 25px 0 !important; 30 | } 31 | 32 | .button-special:hover { 33 | box-shadow: rgba(50, 50, 93, 0.25) 0 30px 60px -12px !important; 34 | transform: translateY(-5px); 35 | } 36 | 37 | .card { 38 | border-radius: 5px; 39 | border-bottom: 2px solid #6c8eef; 40 | -webkit-transition: all 800ms cubic-bezier(0.19, 1, 0.22, 1); 41 | transition: all 800ms cubic-bezier(0.19, 1, 0.22, 1); 42 | } 43 | 44 | .card:hover { 45 | transform: translateY(-5px); 46 | border-bottom: 2px solid #505050; 47 | } 48 | 49 | .button-special { 50 | border: none !important; 51 | color: #363636 !important; 52 | -webkit-transition: all 800ms cubic-bezier(0.19, 1, 0.22, 1); 53 | transition: all 800ms cubic-bezier(0.19, 1, 0.22, 1); 54 | } 55 | 56 | .no-data { 57 | position: relative; 58 | width: 100%; 59 | -webkit-animation-duration: 1s; 60 | animation-duration: 1s; 61 | -webkit-animation-fill-mode: both; 62 | animation-fill-mode: both; 63 | } 64 | 65 | .no-data--image { 66 | width: 100%; 67 | height: 400px; 68 | } 69 | 70 | .no-data--text { 71 | position: absolute; 72 | width: 80%; 73 | top: 50%; 74 | left: 50%; 75 | transform: translate(-50%, -50%); 76 | color: #e7305b; 77 | } 78 | 79 | .fadeIn { 80 | -webkit-animation-name: fadeIn; 81 | animation-name: fadeIn; 82 | } 83 | 84 | @-webkit-keyframes fadeIn { 85 | 0% { 86 | opacity: 0; 87 | } 88 | 100% { 89 | opacity: 1; 90 | } 91 | } 92 | 93 | @keyframes fadeIn { 94 | 0% { 95 | opacity: 0; 96 | } 97 | 100% { 98 | opacity: 1; 99 | } 100 | } 101 | 102 | /* markdown */ 103 | #markdown { 104 | padding: 1rem; 105 | margin-top: 1rem; 106 | width: 100%; 107 | overflow-x: auto; 108 | } 109 | 110 | #markdown #markdown-content { 111 | background-color: #fff; 112 | padding: 1rem 2rem; 113 | border-radius: 5px; 114 | max-width: 70rem; 115 | box-shadow: -1px 3px 20px 0 rgba(0, 0, 0, 0.06); 116 | margin: auto; 117 | } 118 | 119 | #markdown blockquote { 120 | padding: 10px; 121 | border-left: 3px solid rgb(16, 99, 255); 122 | margin: 10px 0; 123 | border-radius: 5px; 124 | color: #808080; 125 | } 126 | 127 | #markdown p { 128 | text-align: justify; 129 | } 130 | 131 | #markdown a { 132 | color: #0479fb; 133 | word-wrap: break-word; 134 | } 135 | 136 | #markdown h1, 137 | #markdown h2, 138 | #markdown h3, 139 | #markdown h4 { 140 | margin: 1rem 0 !important; 141 | color: #209cee !important; 142 | } 143 | 144 | /* loader */ 145 | .loader-wrapper { 146 | position: absolute; 147 | top: 0; 148 | left: 0; 149 | height: 100%; 150 | width: 100%; 151 | z-index: 0; 152 | display: flex; 153 | justify-content: center; 154 | align-items: center; 155 | border-radius: 6px; 156 | } 157 | 158 | .loader-wrapper .loader { 159 | height: 4rem; 160 | width: 4rem; 161 | } 162 | 163 | #cover-spin { 164 | position: fixed; 165 | width: 100%; 166 | left: 0; 167 | right: 0; 168 | top: 0; 169 | bottom: 0; 170 | background-color: rgba(65, 65, 65, 0.7); 171 | z-index: 9999; 172 | display: block; 173 | } 174 | 175 | @-webkit-keyframes spin { 176 | from { 177 | -webkit-transform: rotate(0deg); 178 | } 179 | to { 180 | -webkit-transform: rotate(360deg); 181 | } 182 | } 183 | 184 | @keyframes spin { 185 | from { 186 | transform: rotate(0deg); 187 | } 188 | to { 189 | transform: rotate(360deg); 190 | } 191 | } 192 | 193 | .fadeInUp { 194 | animation-duration: 0.45s; 195 | animation-fill-mode: both; 196 | animation-name: fadeInUp; 197 | } 198 | 199 | @keyframes fadeInUp { 200 | 0% { 201 | opacity: 0; 202 | transform: translateY(20px); 203 | } 204 | 205 | 100% { 206 | opacity: 1; 207 | transform: translateY(0); 208 | } 209 | } 210 | 211 | .owner { 212 | box-shadow: 0 0 0 0 #21bf73; 213 | -webkit-animation: owner 1.25s infinite cubic-bezier(0.66, 0, 0, 1); 214 | -moz-animation: owner 1.25s infinite cubic-bezier(0.66, 0, 0, 1); 215 | -ms-animation: owner 1.25s infinite cubic-bezier(0.66, 0, 0, 1); 216 | animation: owner 1.25s infinite cubic-bezier(0.66, 0, 0, 1); 217 | } 218 | 219 | @-webkit-keyframes owner { 220 | to { 221 | box-shadow: 0 0 0 10px rgba(232, 76, 61, 0); 222 | } 223 | } 224 | @-moz-keyframes owner { 225 | to { 226 | box-shadow: 0 0 0 10px rgba(232, 76, 61, 0); 227 | } 228 | } 229 | @-ms-keyframes owner { 230 | to { 231 | box-shadow: 0 0 0 10px rgba(232, 76, 61, 0); 232 | } 233 | } 234 | @keyframes owner { 235 | to { 236 | box-shadow: 0 0 0 10px rgba(232, 76, 61, 0); 237 | } 238 | } 239 | 240 | #cover-spin::after { 241 | content: ''; 242 | display: block; 243 | position: absolute; 244 | left: 45%; 245 | top: 50%; 246 | width: 40px; 247 | height: 40px; 248 | border-style: solid; 249 | border-color: #dadada; 250 | border-top-color: transparent; 251 | border-width: 4px; 252 | border-radius: 50%; 253 | -webkit-animation: spin 0.8s linear infinite; 254 | animation: spin 0.8s linear infinite; 255 | } 256 | 257 | ul li { 258 | list-style-type: disc; 259 | list-style-position: outside; 260 | } 261 | ol { 262 | list-style-type: decimal; 263 | list-style-position: inside; 264 | } 265 | ul ul, 266 | ol ul { 267 | list-style-type: circle; 268 | list-style-position: inside; 269 | margin-left: 15px; 270 | } 271 | ol ol, 272 | ul ol { 273 | list-style-type: lower-latin; 274 | list-style-position: inside; 275 | margin-left: 15px; 276 | } 277 | 278 | #topBtn { 279 | display: none; 280 | position: fixed; 281 | bottom: 20px; 282 | right: 30px; 283 | z-index: 5; 284 | background-color: #c9cff8 !important; 285 | } 286 | 287 | .modal { 288 | opacity: 1; 289 | transition: opacity 300ms ease-in-out; 290 | } 291 | 292 | #bookmarkBtn { 293 | position: fixed; 294 | bottom: 24px; 295 | left: 30px; 296 | z-index: 5; 297 | background-color: #c9cff8 !important; 298 | } 299 | 300 | #repo-owner-info { 301 | position: fixed; 302 | bottom: 80px; 303 | left: 30px; 304 | z-index: 5; 305 | background-color: #c9cff8 !important; 306 | } 307 | 308 | .has-padding-bottom-10, 309 | .has-padding-top-10 { 310 | padding-bottom: 10px; 311 | } 312 | 313 | .features { 314 | padding: 10px; 315 | } 316 | 317 | .features .feature-card { 318 | cursor: pointer; 319 | padding: 20px; 320 | width: 100%; 321 | background: #fff; 322 | border: 1px solid #e8e8e8; 323 | border-left: 2px solid #6c8eef; 324 | box-shadow: -1px 3px 15px 0 rgba(0, 0, 0, 0.06); 325 | border-radius: 8px; 326 | display: flex; 327 | align-items: center; 328 | margin-bottom: 15px; 329 | -webkit-transition: all 500ms cubic-bezier(0.19, 1, 0.22, 1); 330 | transition: all 500ms cubic-bezier(0.19, 1, 0.22, 1); 331 | } 332 | 333 | .features .feature-card:hover { 334 | transform: translateY(-2px); 335 | } 336 | 337 | .features .feature-card .meta { 338 | margin-left: 12px; 339 | } 340 | 341 | .features .features-title { 342 | margin-bottom: 40px; 343 | } 344 | 345 | .features .feature-card .meta h3 { 346 | font-family: Montserrat, sans-serif; 347 | color: #182c56; 348 | font-weight: 600; 349 | margin-bottom: 4px; 350 | } 351 | 352 | #categories { 353 | display: flex; 354 | align-items: center; 355 | justify-content: center; 356 | height: 1rem; 357 | } 358 | 359 | .category { 360 | height: 1rem; 361 | width: 1rem; 362 | border-radius: 50%; 363 | margin-right: 10px; 364 | cursor: pointer; 365 | } 366 | 367 | #category-tags .tag { 368 | box-shadow: -2px 5px 15px 0 rgba(0, 0, 0, 0.06); 369 | } 370 | 371 | #category-tags .active-tag { 372 | background-color: #3333336e; 373 | cursor: default !important; 374 | pointer-events: none; 375 | } 376 | 377 | .all { 378 | background: #21bf73; 379 | } 380 | 381 | .podcast { 382 | background: #9a1f40; 383 | } 384 | 385 | .language { 386 | background: #ffcb74; 387 | } 388 | 389 | .course { 390 | background: #ffcbcb; 391 | } 392 | 393 | .project { 394 | background: #2042ff; 395 | } 396 | 397 | .interview { 398 | background: #d92027; 399 | } 400 | 401 | .frontend { 402 | background: #ff8364; 403 | } 404 | 405 | .backend { 406 | background: #4a47a3; 407 | } 408 | 409 | #active-dot { 410 | border: 2px solid #00ffea; 411 | cursor: default; 412 | pointer-events: none; 413 | } 414 | 415 | .web-dev { 416 | background: #018383; 417 | } 418 | 419 | .mob-dev { 420 | background: #00d1b2; 421 | } 422 | 423 | .productive { 424 | background: #2c0b1f; 425 | } 426 | 427 | .data-science { 428 | background: #f54752; 429 | } 430 | 431 | /* tag */ 432 | .tag:hover { 433 | opacity: 0.8; 434 | } 435 | 436 | pre { 437 | border-radius: 5px; 438 | background-color: #282a36 !important; 439 | margin: 10px 0 !important; 440 | } 441 | 442 | code { 443 | margin: 5px; 444 | } 445 | 446 | .language-null { 447 | color: #e9ecff !important; 448 | } 449 | 450 | .dark-mode code { 451 | background-color: #282a36; 452 | } 453 | 454 | @media (max-width: 600px) { 455 | .features .feature-card { 456 | flex-direction: column; 457 | text-align: center; 458 | } 459 | 460 | #markdown { 461 | padding: 0; 462 | overflow-x: hidden; 463 | } 464 | 465 | #markdown #markdown-content { 466 | padding: 1rem 15px; 467 | } 468 | 469 | #repo-owner-info { 470 | bottom: 24px; 471 | left: 50%; 472 | transform: translateX(-50%); 473 | } 474 | 475 | table { 476 | max-width: 100%; 477 | overflow-x: auto; 478 | display: block; 479 | } 480 | } 481 | 482 | @media (min-width: 600px) { 483 | .features .feature-card { 484 | height: 155px; 485 | } 486 | } 487 | 488 | /* Dark mode */ 489 | .dark-mode { 490 | background-color: #24292e !important; 491 | color: #eae7d9; 492 | } 493 | 494 | .dark-mode .navbar.is-white { 495 | background-color: #2f363d !important; 496 | } 497 | 498 | .dark-mode .navbar.is-light { 499 | background-color: #24292e !important; 500 | } 501 | 502 | .dark-mode .navbar .navbar-item:not(.is-active) { 503 | color: #f1eeee !important; 504 | } 505 | 506 | .dark-mode .navbar-end > a.navbar-item:hover:not(.is-active) { 507 | background-color: #24292e3f !important; 508 | } 509 | 510 | .dark-mode .navbar .navbar-burger { 511 | color: #fcfcfcb3 !important; 512 | } 513 | 514 | .navbar-brand #brand, 515 | .dark-mode .navbar-brand #brand:hover { 516 | color: #00d1b2 !important; 517 | background-color: inherit !important; 518 | } 519 | 520 | .dark-mode nav .is-active { 521 | color: #52c774 !important; 522 | background-color: #2c313c !important; 523 | } 524 | 525 | .dark-mode .footer { 526 | background-color: #24292e !important; 527 | } 528 | 529 | .dark-mode .title { 530 | color: #eae7d9 !important; 531 | } 532 | 533 | .dark-mode .title.has-text-success { 534 | color: #48c774 !important; 535 | } 536 | 537 | .dark-mode .button { 538 | background-color: #333; 539 | color: #eae7d9 !important; 540 | } 541 | 542 | .dark-mode #download-pdf { 543 | background-color: #00d1b2; 544 | } 545 | 546 | .dark-mode .box-shadow-lift { 547 | box-shadow: -1px -1px 1px 0 #ffffff3b, 1px 1px 1px 0 #0808088e !important; 548 | } 549 | 550 | .dark-mode .button-special:hover { 551 | box-shadow: inset 2px 2px 5px #ffffff3b, inset -3px -3px 7px #0808088e !important; 552 | } 553 | 554 | .dark-mode #markdown #markdown-content { 555 | background-color: #2f363d; 556 | box-shadow: 3px 3px 6px #2f2f2fea, -3px -3px 6px #272525c0; 557 | } 558 | 559 | .dark-mode #markdown a { 560 | transition: all 0.3s ease-in-out; 561 | } 562 | 563 | .dark-mode #markdown a:hover { 564 | color: #ff6584; 565 | } 566 | 567 | .dark-mode .space { 568 | background: linear-gradient(90deg, #1b262c 19px, transparent 1%) center, 569 | linear-gradient(#1b262c 19px, transparent 1%) center, #3a72ff; 570 | background-size: 22px 22px; 571 | } 572 | 573 | .dark-mode .features .feature-card { 574 | background-color: #2f363d; 575 | border: 1px solid #3b3b3bdc; 576 | border-left: 2px solid #eeeeee; 577 | box-shadow: -1px 3px 15px 0 #c3c3c31c; 578 | } 579 | 580 | .dark-mode strong { 581 | color: #f1f1f1; 582 | } 583 | 584 | .dark-mode .card { 585 | background-color: #2f363d; 586 | color: #e8e8e8; 587 | } 588 | 589 | .dark-mode .card a:hover { 590 | color: #e8e8e8; 591 | } 592 | 593 | .dark-mode .card:hover { 594 | border-bottom: 2px solid #e8e8e8; 595 | } 596 | 597 | .dark-mode .card .card-header-title, 598 | .dark-mode .card .media-content .subtitle { 599 | color: #f1f1f1; 600 | } 601 | 602 | .dark-mode table { 603 | background-color: #2f363d; 604 | border-radius: 5px; 605 | } 606 | 607 | .dark-mode thead tr th, 608 | .dark-mode table { 609 | color: #dfe6e9 !important; 610 | } 611 | 612 | .dark-mode .table.is-striped tbody tr:not(.is-selected):nth-child(even) { 613 | background-color: #3131318c; 614 | } 615 | 616 | .dark-mode .table.is-striped tbody tr:not(.is-selected):nth-child(even):hover, 617 | .dark-mode table tbody tr:hover { 618 | background-color: #2c2c2cbe !important; 619 | } 620 | 621 | .dark-mode .modal .modal-card-body, 622 | .dark-mode .modal .modal-card-head, 623 | .dark-mode .modal .modal-card-foot { 624 | background-color: #1b262c; 625 | } 626 | 627 | .dark-mode #category-tags .active-tag { 628 | background-color: #a0a0a06e; 629 | color: #f1f1f1; 630 | } 631 | 632 | .dark-mode #active-dot { 633 | border: 2px solid #f5f5f5; 634 | } 635 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, Suspense, lazy } from 'react'; 2 | import { Switch, Route, Redirect } from 'react-router-dom'; 3 | import { hotjar } from 'react-hotjar'; 4 | import Navbar from './Components/Navbar'; 5 | import Footer from './Components/Footer'; 6 | import ScrollToTopBtn from './Components/ScrollToTopBtn'; 7 | import Spinner from './Components/Spinner'; 8 | import ResourceREADME from './Pages/ResourceREADME'; 9 | import ThemeState from './context/theme/themeState' 10 | import ResourceState from './context/resources/resourceState' 11 | import './App.css'; 12 | 13 | const Home = lazy(() => import('./Pages/Home')); 14 | const Resources = lazy(() => import('./Pages/Resources')); 15 | 16 | function App() { 17 | useEffect(() => { 18 | hotjar.initialize(2074416, 6); 19 | }, []); 20 | 21 | return ( 22 |
23 | 24 | 25 | 26 |
27 | }> 28 | 29 | 30 | 31 | ( 35 | 36 | )} 37 | /> 38 | } 42 | /> 43 | 44 | 45 | 46 | 47 |
50 | ); 51 | } 52 | 53 | export default App; 54 | -------------------------------------------------------------------------------- /src/Components/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Heart, 4 | Facebook, 5 | Instagram, 6 | GitHub, 7 | Twitter, 8 | Linkedin, 9 | } from 'react-feather'; 10 | import ReactTooltip from 'react-tooltip'; 11 | 12 | function Footer() { 13 | return ( 14 | 91 | ); 92 | } 93 | 94 | export default Footer; 95 | -------------------------------------------------------------------------------- /src/Components/Navbar.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import { Terminal, Sun, Moon } from 'react-feather'; 3 | import { Link, withRouter } from 'react-router-dom'; 4 | import ThemeContext from '../context/theme/themeContext'; 5 | 6 | function Navbar() { 7 | const themeContext = useContext(ThemeContext); 8 | const { isDarkMode, toggleTheme } = themeContext; 9 | const active = window.location.pathname; 10 | document.addEventListener('DOMContentLoaded', () => { 11 | const $navbarBurgers = Array.prototype.slice.call( 12 | document.querySelectorAll('.navbar-burger'), 13 | 0, 14 | ); 15 | const anchors = document.querySelectorAll('.navbar-item'); 16 | anchors.forEach((anchor) => { 17 | anchor.addEventListener('click', () => { 18 | document 19 | .querySelector('#navbarBasicExample') 20 | .classList.remove('is-active'); 21 | 22 | document.querySelector('.navbar-burger').classList.remove('is-active'); 23 | }); 24 | }); 25 | 26 | if ($navbarBurgers.length > 0) { 27 | $navbarBurgers.forEach((el) => { 28 | el.addEventListener('click', () => { 29 | const { target } = el.dataset; 30 | const $target = document.getElementById(target); 31 | el.classList.toggle('is-active'); 32 | $target.classList.toggle('is-active'); 33 | }); 34 | }); 35 | } 36 | }); 37 | 38 | return ( 39 | 107 | ); 108 | } 109 | 110 | export default withRouter(Navbar); 111 | -------------------------------------------------------------------------------- /src/Components/NoData.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import no_data from '../assets/no_data.svg'; 3 | 4 | function NoData({ text }) { 5 | return ( 6 |
7 | no data found 8 |

11 | {text} 12 |

13 |
14 | ); 15 | } 16 | 17 | export default NoData; 18 | -------------------------------------------------------------------------------- /src/Components/Page.js: -------------------------------------------------------------------------------- 1 | import React, { memo, useContext, useEffect } from 'react'; 2 | import resourceContext from '../context/resources/resourceContext'; 3 | 4 | // used to change title of page 5 | function Page({ title, children }) { 6 | const ResourceContext = useContext(resourceContext) || {}; 7 | const { pageTitle } = ResourceContext; 8 | useEffect(() => { 9 | if (title) document.title = `${title} | WebDevsCom`; 10 | else document.title = `${pageTitle} | WebDevsCom`; 11 | // eslint-disable-next-line 12 | }, [pageTitle, title]); 13 | 14 | return ( 15 | <> 16 | {children} 17 | 18 | ); 19 | } 20 | 21 | export default memo(Page); 22 | -------------------------------------------------------------------------------- /src/Components/ScrollToTop.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { withRouter } from 'react-router-dom'; 3 | 4 | // used to scroll to top on router changes 5 | class ScrollToTop extends React.Component { 6 | componentDidUpdate(prevProps) { 7 | if (this.props.location.pathname !== prevProps.location.pathname) { 8 | window.scrollTo(0, 0); 9 | } 10 | } 11 | 12 | render() { 13 | return null; 14 | } 15 | } 16 | 17 | export default withRouter(ScrollToTop); 18 | -------------------------------------------------------------------------------- /src/Components/ScrollToTopBtn.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ArrowUpCircle } from 'react-feather'; 3 | import ReactTooltip from 'react-tooltip'; 4 | 5 | function ScrollToTopBtn() { 6 | let scrolling = false; 7 | window.onscroll = function () { 8 | scrolling = true; 9 | }; 10 | 11 | setInterval(() => { 12 | const topBtn = document.getElementById('topBtn'); 13 | const navbar = document.getElementById('navbar'); 14 | if (scrolling && topBtn) { 15 | if (window.pageYOffset > 20) { 16 | topBtn.style.display = 'block'; 17 | navbar.classList.add('box-shadow'); 18 | navbar.classList.remove('is-light'); 19 | navbar.classList.add('is-white'); 20 | } else { 21 | topBtn.style.display = 'none'; 22 | navbar.classList.remove('box-shadow'); 23 | navbar.classList.add('is-light'); 24 | navbar.classList.remove('is-white'); 25 | } 26 | scrolling = false; 27 | } 28 | }); 29 | 30 | // When the user clicks on the button, scroll to the top of the document 31 | function topFunction() { 32 | document.body.scrollTo({ top: 0, behavior: 'smooth' }); // For Safari 33 | document.documentElement.scrollTo({ top: 0, behavior: 'smooth' }); // For Chrome, Firefox, IE and Opera 34 | } 35 | return ( 36 | <> 37 | 38 |
45 | 46 |
47 | 48 | ); 49 | } 50 | 51 | export default ScrollToTopBtn; 52 | -------------------------------------------------------------------------------- /src/Components/Spinner.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | function Spinner() { 4 | return ( 5 |
6 |
7 |
8 | ); 9 | } 10 | 11 | export default Spinner; 12 | -------------------------------------------------------------------------------- /src/Pages/Home/Contributor.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import GitHubButton from 'react-github-btn'; 3 | import contributors from '../../data/contributors'; 4 | 5 | function Contributor() { 6 | return ( 7 |
8 |

Contributors for this website.

9 |
10 | { 11 | contributors.map((contributor) => { 12 | const { 13 | id, name, userId, avatar, 14 | } = contributor; 15 | return ( 16 |
22 | 27 | user-profile 33 | 34 |
35 | ); 36 | }) 37 | } 38 |
39 |

40 | Do you want to contribute or add some resource Feel free to visit below 41 | links. 42 |

43 |
44 | 51 | Star 52 | 53 | 54 | 61 | Fork 62 | 63 |
64 |
65 | ); 66 | } 67 | 68 | export default Contributor; 69 | -------------------------------------------------------------------------------- /src/Pages/Home/Features.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Codepen, 4 | Youtube, 5 | HelpCircle, 6 | Chrome, 7 | UserPlus, 8 | UploadCloud, 9 | AlertCircle, 10 | Star, 11 | GitMerge, 12 | Minimize, 13 | Filter, 14 | Folder, 15 | } from 'react-feather'; 16 | import { withRouter } from 'react-router-dom'; 17 | 18 | function Features({ history }) { 19 | return ( 20 |
21 |
22 |
23 |

24 | Access Hundreds of Resources in One Place. 25 |

26 |

Our contributors have aggregated all the information you need!

27 |
28 |
29 |
30 |
history.push('/resources/1')} 33 | > 34 | 35 |
36 |

Design Resources

37 |

38 | Take your UI/UX creative journey a little further. Find all 39 | the resources you need as a developer to create beautiful and 40 | memorable UI/UX. 41 |

42 |
43 |
44 | 45 |
history.push('/resources/4')} 48 | > 49 | 50 |
51 |

Top Youtube Channels

52 |

53 | Watch time tested and top coding channels on youtube. Learn 54 | from the best. Learn all the tricks of the game here. We have 55 | your back. 56 |

57 |
58 |
59 | 60 |
history.push('/resources/55')} 63 | > 64 | 65 |
66 |

FAQ in Interview

67 |

68 | Here we give you links to resources of Frequently asked 69 | Interview Questions and their explainations with examples on 70 | how to answer them. 71 |

72 |
73 |
74 |
75 |
76 |
history.push('/resources/5')} 79 | > 80 | 81 |
82 |

App Ideas

83 |

84 | Pick from the pool of app development project ideas at all 85 | levels of programming. Learn and get Experience from Building 86 | them. 87 |

88 |
89 |
90 | 91 |
history.push('/resources/3')} 94 | > 95 | 96 |
97 |

Developer Portfolios

98 |

99 | Have a look at our collection of top Developers Portfolio. We 100 | hope you will be inspired to put in more effort to acheive 101 | greatness. 102 |

103 |
104 |
105 | 106 |
history.push('/resources/2')} 109 | > 110 | 111 |
112 |

Public APIs

113 |

114 | Play around with a collection of hundreds of public APIs to 115 | ease your software and web development experiences. 116 |

117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |

Contribute Code

126 |

Contribute to this Open Source Project to Help Developers

127 |
128 |
129 | 130 |
131 |
132 | 133 | 134 | 135 | 136 |
Report Issue
137 |
138 | Open an issue if you want to suggest a new feature or report a 139 | bug. 140 |
141 |
142 | 143 |
144 | 145 | 146 | 147 | 148 |
Star
149 |
150 | We hope that, this website will help you to become a better 151 | programmer. Show your support by giving us a star on GitHub. 152 |
153 |
154 | 155 |
156 | 157 | 158 | 159 | 160 |
Pull Request
161 |
162 | You are welcomed to send a pull request if you want to make 163 | changes or increase publicity for this project! 164 |
165 |
166 |
167 |
168 |
172 |
173 |
174 |

Special Features

175 |

Special features of this website include...

176 |
177 |
178 | 179 |
180 |
181 | 182 | 183 | 184 | 185 |
Responsive
186 |
187 | Reading a Readme of a Repo on a mobile phone devices is a challenge 188 | for most users. This website supports responsiveness on all 189 | devices. 190 |
191 |
192 | 193 |
194 | 195 | 196 | 197 | 198 |
199 | Resource Filter 200 |
201 |
202 | Provides a good and handy feature to filter resources according to 203 | your requirements and needs. 204 |
205 |
206 | 207 |
208 | 209 | 210 | 211 | 212 |
Collection
213 |
214 | A collection of several useful resources we think might be helpful 215 | to you as a programmer. 216 |
217 |
218 |
219 |
220 |
221 | ); 222 | } 223 | 224 | export default withRouter(Features); 225 | -------------------------------------------------------------------------------- /src/Pages/Home/HeroSec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { GitHub, GitPullRequest } from 'react-feather'; 3 | import Contributor from './Contributor'; 4 | 5 | function HeroSec() { 6 | return ( 7 |
8 |
9 |
10 |
11 |

12 | 13 | Hello Developer, welcome home! 14 | 15 |

16 |

20 | We have collected over 1000+ free resources to make your 21 | development journey hassle free Enjoy the experience. 22 |

23 | 24 | 36 |
37 | 38 |
39 |

43 | Hello Developer, welcome home! 44 |

45 |

49 | We have collected over 1000+ free resources to make your 50 | development journey hassle free Enjoy the experience. 51 |

52 | 53 | 65 |
66 |
67 |
68 |
69 | ); 70 | } 71 | 72 | export default HeroSec; 73 | -------------------------------------------------------------------------------- /src/Pages/Home/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import HeroSec from './HeroSec'; 3 | import Features from './Features'; 4 | import Page from '../../Components/Page'; 5 | 6 | function Home() { 7 | return ( 8 | 9 | 10 | 11 |
12 |
13 |
14 |

18 | WEB DEVELOPERS COMMUNITY 19 |

20 |
21 |
22 |
23 |
24 | ); 25 | } 26 | 27 | export default Home; 28 | -------------------------------------------------------------------------------- /src/Pages/ResourceREADME/OtherReposByAuthorModal.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | 4 | function OtherReposByAuthorModal({ authorRepos, setModal, currentRepoId }) { 5 | return ( 6 |
7 |
setModal(false)} 11 | /> 12 |
13 |
14 |

15 | {authorRepos[0].repoOwner} 16 |

17 |
19 |
20 |
21 |
22 | 27 | {authorRepos[0].repoOwnerName} 32 | 33 |
34 |
35 |
36 |

40 | {authorRepos[0].repoOwner} 41 |

42 | 47 | @ 48 | {authorRepos[0].repoOwnerName} 49 | 50 |
51 |
52 |

53 | Resources available by 54 | {' '} 55 | {authorRepos[0].repoOwner} 56 |

57 | {authorRepos.map((repo) => ( 58 |
59 |
60 |

{repo.repoName}

61 |
62 | {repo.category.map((cat, index) => ( 63 | 69 | ))} 70 |
71 |
72 |
73 |
74 | {repo.description} 75 |
76 | {repo.id !== currentRepoId && ( 77 |
81 | 85 | View 86 | 87 |
88 | )} 89 |
90 |
91 |
92 | ))} 93 |
94 |
95 | 98 |
99 |
100 |
101 | ); 102 | } 103 | 104 | export default OtherReposByAuthorModal; 105 | -------------------------------------------------------------------------------- /src/Pages/ResourceREADME/PdfContainer.js: -------------------------------------------------------------------------------- 1 | import React, { createRef, useEffect, useState } from 'react'; 2 | import { Download, GitHub } from 'react-feather'; 3 | import { savePDF } from '@progress/kendo-react-pdf'; 4 | 5 | class DocService { 6 | createPdf = (html, name, setDisable) => { 7 | savePDF( 8 | html, 9 | { 10 | title: 'webdevscom.github.io', 11 | scale: 0.8, 12 | producer: 'WebDevsCom', 13 | subject: 'Learning Resources', 14 | creator: 'Binu kumar', 15 | paperSize: 'Letter', 16 | fileName: name + '.pdf', 17 | margin: 5, 18 | }, 19 | () => { 20 | setDisable(false); 21 | } 22 | ); 23 | }; 24 | } 25 | 26 | const Doc = new DocService(); 27 | 28 | export default ({ name, ownerName, children }) => { 29 | const bodyRef = createRef(); 30 | const [disable, setDisable] = useState(false); 31 | const createPdf = () => { 32 | setDisable(true); 33 | Doc.createPdf(bodyRef.current, name, setDisable); 34 | }; 35 | 36 | useEffect(() => { 37 | if (disable) { 38 | document.querySelector('body').classList.add('overflow-hidden'); 39 | } else { 40 | document.querySelector('body').classList.remove('overflow-hidden'); 41 | } 42 | }, [disable]); 43 | 44 | return ( 45 |
46 |
47 | {disable ? ( 48 |
49 | ) : ( 50 |
54 | 63 | 70 |  View on Github 71 | 72 |
73 | )} 74 |
75 |
76 | {children} 77 |
78 |
79 | ); 80 | }; 81 | -------------------------------------------------------------------------------- /src/Pages/ResourceREADME/ReadmeUtilsBtn.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Bookmark, MoreVertical } from 'react-feather'; 3 | import ReactTooltip from 'react-tooltip'; 4 | 5 | function ReadmeUtilsBtn({ 6 | isBookMarked, 7 | removeBookmark, 8 | bookmarkIt, 9 | setModal, 10 | }) { 11 | return ( 12 | <> 13 | 14 |
(isBookMarked ? removeBookmark() : bookmarkIt())} 19 | data-tip={isBookMarked ? 'Remove from Bookmark' : 'Add to Bookmark'} 20 | > 21 | 26 |
27 |
setModal(true)} 32 | data-tip="See more from Repo owners" 33 | > 34 | 35 |
36 | 37 | ); 38 | } 39 | 40 | export default ReadmeUtilsBtn; 41 | -------------------------------------------------------------------------------- /src/Pages/ResourceREADME/code-blocks.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import hljs from 'highlight.js/lib/core'; 4 | import 'highlight.js/lib'; 5 | import 'highlight.js/styles/dracula.css'; 6 | 7 | class CodeBlock extends React.PureComponent { 8 | constructor(props) { 9 | super(props); 10 | this.setRef = this.setRef.bind(this); 11 | } 12 | 13 | setRef(el) { 14 | this.codeEl = el; 15 | } 16 | 17 | componentDidMount() { 18 | this.highlightCode(); 19 | } 20 | 21 | componentDidUpdate() { 22 | this.highlightCode(); 23 | } 24 | 25 | highlightCode() { 26 | if (this.props.language === null) return; 27 | hljs.highlightBlock(this.codeEl); 28 | } 29 | 30 | render() { 31 | return ( 32 |
33 |         
34 |           {this.props.value}
35 |         
36 |       
37 | ); 38 | } 39 | } 40 | 41 | CodeBlock.defaultProps = { 42 | language: '', 43 | }; 44 | 45 | CodeBlock.propTypes = { 46 | value: PropTypes.string.isRequired, 47 | language: PropTypes.string, 48 | }; 49 | 50 | export default CodeBlock; 51 | -------------------------------------------------------------------------------- /src/Pages/ResourceREADME/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import ReactMarkdown from 'react-markdown'; 3 | import Axios from 'axios'; 4 | import Spinner from '../../Components/Spinner'; 5 | import resources from '../../data/resourcesData'; 6 | import CodeBlock from './code-blocks'; 7 | import ReadmeUtilsBtn from './ReadmeUtilsBtn'; 8 | import { slug } from 'github-slugger'; 9 | import PdfContainer from './PdfContainer'; 10 | import Page from '../../Components/Page'; 11 | import NoData from '../../Components/NoData'; 12 | import OtherReposByAuthorModal from './OtherReposByAuthorModal'; 13 | 14 | const ResourceREADME = (props) => { 15 | const [markdown, setMarkdown] = useState(''); 16 | const [repoInfo, setRepoInfo] = useState({}); 17 | const [loading, setLoading] = useState(true); 18 | const [bookmarks, setBookMarks] = useState([]); 19 | const [isBookMarked, setBookMarked] = useState(false); 20 | const [isModalOpen, setModalOpen] = useState(false); 21 | const [authorRepos, setAuthorRepos] = useState([]); 22 | 23 | useEffect(() => { 24 | setBookMarks(JSON.parse(localStorage.getItem('bookmarks'))); 25 | let BookMarked = 26 | bookmarks?.find((bookMarkId) => repoInfo?.id === bookMarkId); 27 | setBookMarked(BookMarked ? true : false); 28 | 29 | // Todo: need to make it better sometime later. 30 | if (loading === false) { 31 | const repos = []; 32 | resources.forEach((resource) => { 33 | if (resource.repoOwnerName === repoInfo?.repoOwnerName) { 34 | repos.push(resource); 35 | } 36 | }); 37 | 38 | setAuthorRepos(repos); 39 | 40 | const h1 = document.querySelectorAll('#markdown h1'); 41 | for (var i = 0; i < h1.length; i++) { 42 | h1[i].className = 'title is-2'; 43 | h1[i].setAttribute('id', slug(h1[i].innerHTML)); 44 | } 45 | 46 | const h2 = document.querySelectorAll('#markdown h2'); 47 | for (i = 0; i < h2.length; i++) { 48 | h2[i].className = 'title is-3'; 49 | h2[i].setAttribute('id', slug(h2[i].innerHTML)); 50 | } 51 | 52 | const h3 = document.querySelectorAll('#markdown h3'); 53 | for (i = 0; i < h3.length; i++) { 54 | h3[i].className = 'title is-4'; 55 | h3[i].setAttribute('id', slug(h3[i].innerHTML)); 56 | } 57 | 58 | const strong = document.querySelectorAll('#markdown strong'); 59 | for (i = 0; i < strong.length; i++) { 60 | strong[i].setAttribute('id', slug(strong[i].innerHTML)); 61 | } 62 | 63 | const table = document.querySelectorAll('#markdown table'); 64 | for (i = 0; i < table.length; i++) 65 | table[i].className = 66 | 'table is-hoverable is-dark is-fullwidth is-striped'; 67 | 68 | const images = document.querySelectorAll('img'); 69 | for (i = 0; i < images.length; i++) { 70 | if (images[i].src.includes(window.location.origin)) { 71 | images[i].setAttribute( 72 | 'src', 73 | `https://raw.githubusercontent.com/${repoInfo.repoOwnerName}/${repoInfo.repoName 74 | }/master${images[i].src 75 | .replace(window.location.origin, '') 76 | .replace(window.location.pathname, '') 77 | .replace('/resources', '')}` 78 | ); 79 | } 80 | } 81 | 82 | var el = document.querySelectorAll('#markdown a'); 83 | for (i = 0; i < el.length; i++) { 84 | if ( 85 | el[i].href.includes('./') || 86 | (el[i].href.includes('.md') && 87 | el[i].href.includes(window.location.origin)) 88 | ) { 89 | el[i].setAttribute( 90 | 'href', 91 | `https://github.com/${repoInfo.repoOwnerName}/${repoInfo.repoName 92 | }/blob/master${el[i].href 93 | .replace(window.location.origin, '') 94 | .replace(window.location.pathname, '') 95 | .replace('/resources', '')}` 96 | ); 97 | el[i].setAttribute('target', '_blank'); 98 | } else if (!el[i].href.includes('#')) { 99 | el[i].setAttribute('target', '_blank'); 100 | } else if (el[i].href.includes('#')) { 101 | el[i].setAttribute('href', el[i].href.toLowerCase()); 102 | } 103 | } 104 | } 105 | // eslint-disable-next-line 106 | }, [loading, repoInfo]); 107 | 108 | const bookmarkIt = () => { 109 | setBookMarked(true); 110 | if (bookmarks === null) { 111 | localStorage.setItem('bookmarks', JSON.stringify([repoInfo.id])); 112 | } else { 113 | bookmarks.push(repoInfo.id); 114 | setBookMarks(bookmarks); 115 | localStorage.setItem('bookmarks', JSON.stringify(bookmarks)); 116 | } 117 | }; 118 | 119 | const removeBookmark = () => { 120 | setBookMarked(false); 121 | const bookMarks = 122 | bookmarks && bookmarks.filter((bookmarkId) => bookmarkId !== repoInfo.id); 123 | setBookMarks(bookMarks); 124 | localStorage.setItem('bookmarks', JSON.stringify(bookMarks)); 125 | }; 126 | 127 | useEffect(() => { 128 | setLoading(true); 129 | setModalOpen(false); 130 | const id = props.match.params.id; 131 | const repo = resources.find( 132 | (resource) => String(resource.id) === String(id) 133 | ); 134 | setRepoInfo(repo); 135 | if (repo) { 136 | Axios.get(repo.link).then((markdown) => { 137 | setMarkdown(markdown.data); 138 | setLoading(false); 139 | }); 140 | } 141 | }, [props.match.params.id]); 142 | 143 | useEffect(() => { 144 | isModalOpen 145 | ? document.querySelector('html').classList.add('is-clipped') 146 | : document.querySelector('html').classList.remove('is-clipped'); 147 | }, [isModalOpen]); 148 | 149 | if (!repoInfo) 150 | return 151 | 152 | if (loading) return ; 153 | 154 | return ( 155 | 156 |
157 |
158 | 164 | 165 |
166 | 171 |
172 |
173 | 174 | {isModalOpen && ( 175 | 180 | )} 181 |
182 |
183 | ); 184 | }; 185 | 186 | export default ResourceREADME; 187 | -------------------------------------------------------------------------------- /src/Pages/Resources/ResourceCard.js: -------------------------------------------------------------------------------- 1 | import React, { memo, useContext } from 'react'; 2 | import { Link, withRouter } from 'react-router-dom'; 3 | import { Star, GitPullRequest, Eye } from 'react-feather'; 4 | import resourceContext from '../../context/resources/resourceContext'; 5 | 6 | const ResourceCard = memo(({ resource, history }) => { 7 | const { 8 | id, repoName, repoOwner, repoOwnerName, category: categories, description, 9 | } = resource; 10 | 11 | const ResourceContext = useContext(resourceContext); 12 | const { category, setCategory } = ResourceContext; 13 | 14 | return ( 15 |
19 |
28 |
history.push(`/resources/${id}`)} 32 | > 33 |

34 | {repoName} 35 |

36 |
37 |
38 |
39 |
43 |
44 |
45 | 50 | {repoOwnerName} 56 | 57 |
58 |
59 |
60 |

64 | {repoOwner} 65 |

66 | 71 | @ 72 | {repoOwnerName} 73 | 74 |
75 |
76 |
77 |
history.push(`/resources/${id}`)} 79 | style={{ cursor: 'pointer' }} 80 | className="has-text-justified" 81 | > 82 | {description} 83 |
84 |
85 |
86 |
87 |
88 | {categories.map((cat, index) => ( 89 | setCategory(cat.toLowerCase())} 93 | id={cat === category ? 'active-dot' : ''} 94 | className={`category ${cat}`} 95 | /> 96 | ))} 97 |
98 | 131 |
132 |
133 |
134 | ); 135 | }); 136 | 137 | export default withRouter(ResourceCard); 138 | -------------------------------------------------------------------------------- /src/Pages/Resources/ResourceCards.js: -------------------------------------------------------------------------------- 1 | import React, { memo, useContext } from 'react'; 2 | import NoData from '../../Components/NoData'; 3 | import resourceContext from '../../context/resources/resourceContext'; 4 | import ResourceCard from './ResourceCard'; 5 | 6 | const ResourceCards = memo(() => { 7 | const ResourceContext = useContext(resourceContext); 8 | const { category, searchText, resources } = ResourceContext; 9 | 10 | return ( 11 |
15 | { 16 | resources.length === 0 17 | && window.location.pathname === '/resources' ? ( 18 | 21 | ) : ( 22 | resources.length === 0 23 | && window.location.pathname === '/bookmarked') ? ( 24 | 33 | ) : ( 34 | resources.map((resource) => ( 35 | 36 | )) 37 | ) 38 | } 39 |
40 | ); 41 | }); 42 | 43 | export default ResourceCards; 44 | -------------------------------------------------------------------------------- /src/Pages/Resources/SearchInput.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect, useState } from 'react'; 2 | import { Search, XCircle } from 'react-feather'; 3 | import resourceContext from '../../context/resources/resourceContext'; 4 | 5 | function SearchInput() { 6 | const ResourceContext = useContext(resourceContext); 7 | const { setSearchText, searchText } = ResourceContext; 8 | const [placeholder, setPlaceholder] = useState(''); 9 | 10 | const suggestions = [ 11 | 'brad traversy', 12 | 'css', 13 | 'react', 14 | 'angular', 15 | 'bradtraversy', 16 | 'course', 17 | 'university', 18 | 'curated', 19 | ]; 20 | 21 | // search placeholder text 22 | useEffect(() => { 23 | let timeout; 24 | const fillPlaceholder = (index, cursorPosition, callback) => { 25 | const text = suggestions[index]; 26 | setPlaceholder(text.slice(0, cursorPosition)); 27 | 28 | if (cursorPosition < text.length) { 29 | timeout = setTimeout(() => { 30 | fillPlaceholder(index, cursorPosition + 1, callback); 31 | }, 200); 32 | return true; 33 | } 34 | callback(); 35 | }; 36 | 37 | const clearPlaceholder = (callback) => { 38 | if (placeholder.length > 0) { 39 | timeout = setTimeout(() => { 40 | setPlaceholder(''); 41 | clearPlaceholder(callback); 42 | }, 1000); 43 | return true; 44 | } 45 | callback(); 46 | }; 47 | 48 | const loopThroughSuggestions = (index) => { 49 | fillPlaceholder(index, 0, () => { 50 | timeout = setTimeout(() => { 51 | clearPlaceholder(() => { 52 | loopThroughSuggestions((index + 1) % suggestions.length); 53 | }); 54 | }, 2000); 55 | }); 56 | }; 57 | 58 | loopThroughSuggestions(0); 59 | return () => clearTimeout(timeout); 60 | // eslint-disable-next-line 61 | }, []); 62 | 63 | return ( 64 |
68 |

69 | setSearchText(e.target.value)} 73 | placeholder={`Search for ${placeholder}`} 74 | value={searchText} 75 | /> 76 | 77 | 78 | 79 |

80 |
81 |
setSearchText('')} 85 | style={{ backgroundColor: '#00d1b2' }} 86 | > 87 | 88 | 89 | 90 |
91 |
92 |
93 | ); 94 | } 95 | 96 | export default SearchInput; 97 | -------------------------------------------------------------------------------- /src/Pages/Resources/Suggestion.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useMemo } from 'react'; 2 | import resourceContext from '../../context/resources/resourceContext'; 3 | 4 | function Suggestion() { 5 | const filters = useMemo(() => ([ 6 | 'App', 7 | 'Book', 8 | 'computer science', 9 | 'Design', 10 | 'Developer', 11 | 'react', 12 | 'javascript', 13 | 'Programmer', 14 | 'code', 15 | 'Resources', 16 | 'web', 17 | ].sort((a, b) => a.localeCompare(b))), []); 18 | 19 | const categories = useMemo(() => ([ 20 | 'All', 21 | 'Web-dev', 22 | 'Mob-dev', 23 | 'data-science', 24 | 'Interview', 25 | 'Frontend', 26 | 'Backend', 27 | 'Language', 28 | 'Project', 29 | 'Course', 30 | 'Podcast', 31 | 'productive', 32 | ].sort((a, b) => a.localeCompare(b))), []); 33 | 34 | const ResourceContext = useContext(resourceContext); 35 | const { setSearchText, category, setCategory } = ResourceContext; 36 | 37 | return ( 38 | <> 39 |
40 |
44 | {filters.map((filter, index) => ( 45 | setSearchText(filter)} 50 | > 51 | {filter} 52 | 53 | ))} 54 |
55 |
56 |
66 | {categories.map((cat, i) => ( 67 | setCategory(cat.toLowerCase())} 78 | > 79 | 80 | {cat} 81 |   82 | 83 | ))} 84 |
85 | 86 | ); 87 | } 88 | 89 | export default Suggestion; 90 | -------------------------------------------------------------------------------- /src/Pages/Resources/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { Eye, EyeOff } from 'react-feather'; 3 | import ResourceCards from './ResourceCards'; 4 | import Page from '../../Components/Page'; 5 | import Suggestion from './Suggestion'; 6 | import SearchInput from './SearchInput'; 7 | 8 | function Resources() { 9 | const [showSuggestion, setShowSuggestion] = useState(false); 10 | 11 | return ( 12 | 13 |
14 | 15 |
19 | 29 |
30 | 31 | {(window.innerWidth > 767 || showSuggestion) && ( 32 | 33 | )} 34 | 35 |
36 |
37 | ); 38 | } 39 | 40 | export default Resources; 41 | -------------------------------------------------------------------------------- /src/assets/no_data.svg: -------------------------------------------------------------------------------- 1 | empty -------------------------------------------------------------------------------- /src/context/resources/resourceContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | const resourceContext = createContext(); 4 | 5 | export default resourceContext; 6 | -------------------------------------------------------------------------------- /src/context/resources/resourceReducer.js: -------------------------------------------------------------------------------- 1 | import { SET_FILTERED_RESOURCES, SET_PAGE_TITLE } from '../types'; 2 | 3 | export default (state, action) => { 4 | switch (action.type) { 5 | case SET_FILTERED_RESOURCES: 6 | return { ...state, ...action.payload }; 7 | case SET_PAGE_TITLE: 8 | return { ...state, ...action.payload }; 9 | default: 10 | return state; 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /src/context/resources/resourceState.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react-hooks/exhaustive-deps */ 2 | import React, { useEffect, useMemo, useReducer } from 'react'; 3 | import ResourceContext from './resourceContext'; 4 | import ResourceReducer from './resourceReducer'; 5 | import resources from "../../data/resourcesData" 6 | 7 | import { 8 | SET_FILTERED_RESOURCES, SET_PAGE_TITLE 9 | } from '../types'; 10 | 11 | const ResourceState = props => { 12 | const intialState = { resources: [], category: "all", searchText: "", pageTitle: "" }; 13 | const [state, dispatch] = useReducer(ResourceReducer, intialState); 14 | 15 | const localStorageResources = useMemo(() => { 16 | const bookmarks = JSON.parse(localStorage.getItem('bookmarks')); 17 | const bookmarkedResources = 18 | bookmarks?.map( 19 | (bookmark) => 20 | resources.filter((resource) => resource.id === bookmark)[0] 21 | ); 22 | return bookmarkedResources || []; 23 | }, [localStorage.getItem('bookmarks')]) 24 | 25 | const sortResources = (resources) => { 26 | return resources.sort((a, b) => 27 | ('' + a.repoName).localeCompare(b.repoName) 28 | ); 29 | } 30 | 31 | const isPresent = (value, checkValue) => value.toLowerCase().includes(checkValue); 32 | 33 | // get intial resources based upon route 34 | const getIntialResources = () => { 35 | const { pathname } = window.location; 36 | if (pathname === "/resources") 37 | return sortResources(resources); 38 | else if (pathname === "/bookmarked") 39 | return sortResources(localStorageResources); 40 | } 41 | 42 | // get intial filtered resources based upon searched text or category 43 | const getIntialFilteredResources = () => { 44 | const { category, searchText } = state; 45 | if (category !== "all") 46 | return filterResourcesOnChangeInCategory(category); 47 | else if (searchText.trim() !== "") 48 | return filterResourcesOnChangeInSearchText(searchText); 49 | else 50 | return getIntialResources(); 51 | } 52 | 53 | // filter resources based upon searched text 54 | const filterResourcesOnChangeInSearchText = (val) => { 55 | let filteredResources = []; 56 | const resources = getIntialResources(); 57 | 58 | const searchInput = val.toLowerCase(); 59 | filteredResources = 60 | resources.filter( 61 | ({ repoOwner, repoOwnerName, description, repoName }) => isPresent(repoName, searchInput) || isPresent(repoOwner, searchInput) || isPresent(description, searchInput) || isPresent(repoOwnerName, searchInput) 62 | ); 63 | 64 | return filteredResources; 65 | } 66 | 67 | // filter resources according to choosed category 68 | const filterResourcesOnChangeInCategory = (val) => { 69 | let filteredResources = []; 70 | const resources = getIntialResources(); 71 | 72 | if (val === "all") 73 | return resources; 74 | 75 | resources.forEach((resource) => { 76 | resource.category.forEach((cat) => { 77 | if (cat === val) { 78 | filteredResources.push(resource); 79 | } 80 | }); 81 | }); 82 | 83 | return filteredResources; 84 | } 85 | 86 | const setCategory = (val) => { 87 | dispatch({ 88 | type: SET_FILTERED_RESOURCES, 89 | payload: { 90 | category: val, searchText: "", resources: filterResourcesOnChangeInCategory(val) 91 | } 92 | }) 93 | } 94 | 95 | const setSearchText = (val) => { 96 | dispatch({ 97 | type: SET_FILTERED_RESOURCES, 98 | payload: { 99 | category: "all", searchText: val, resources: filterResourcesOnChangeInSearchText(val) 100 | } 101 | }) 102 | } 103 | 104 | // used to change title of page 105 | useEffect(() => { 106 | const { category, searchText } = state; 107 | if (window.location.pathname === '/resources') { 108 | dispatch({ 109 | type: SET_PAGE_TITLE, 110 | payload: { 111 | pageTitle: `${category}${searchText} Resources` 112 | } 113 | }) 114 | } else if (window.location.pathname === '/bookmarked') { 115 | dispatch({ 116 | type: SET_PAGE_TITLE, 117 | payload: { 118 | pageTitle: `${category}${searchText} BookMarked Resources` 119 | } 120 | }) 121 | } 122 | }, [window.location.pathname, state.category, state.searchText]) 123 | 124 | useEffect(() => { 125 | const { pathname } = window.location; 126 | if (pathname !== "/resources" && pathname !== "/bookmarked") 127 | return; 128 | dispatch({ 129 | type: SET_FILTERED_RESOURCES, 130 | payload: { 131 | resources: getIntialFilteredResources() 132 | } 133 | }) 134 | }, [window.location.pathname]) 135 | 136 | return 141 | {props.children} 142 | 143 | } 144 | export default ResourceState; -------------------------------------------------------------------------------- /src/context/theme/themeContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | const themeContext = createContext(); 4 | 5 | export default themeContext; 6 | -------------------------------------------------------------------------------- /src/context/theme/themeReducer.js: -------------------------------------------------------------------------------- 1 | import { TOGGLE_THEME } from '../types'; 2 | 3 | export default (state, action) => { 4 | switch (action.type) { 5 | case TOGGLE_THEME: 6 | return { isDarkMode: action.payload }; 7 | default: 8 | return state; 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /src/context/theme/themeState.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useReducer } from 'react'; 2 | import ThemeContext from './themeContext'; 3 | import ThemeReducer from './themeReducer'; 4 | 5 | import { 6 | TOGGLE_THEME, 7 | } from '../types'; 8 | 9 | function ThemeState(props) { 10 | const intialState = { isDarkMode: JSON.parse(localStorage.getItem('dark-mode')) }; 11 | 12 | const [state, dispatch] = useReducer(ThemeReducer, intialState); 13 | 14 | // Toggle Theme 15 | const toggleTheme = () => { 16 | dispatch({ 17 | type: TOGGLE_THEME, 18 | payload: !state.isDarkMode, 19 | }); 20 | }; 21 | 22 | useEffect(() => { 23 | localStorage.setItem('dark-mode', state.isDarkMode); 24 | if (state.isDarkMode) { 25 | document.querySelector('body').classList.add('dark-mode'); 26 | } else { 27 | document.querySelector('body').classList.remove('dark-mode'); 28 | } 29 | }, [state.isDarkMode]); 30 | 31 | return ( 32 | 37 | {props.children} 38 | 39 | ); 40 | } 41 | export default ThemeState; 42 | -------------------------------------------------------------------------------- /src/context/types.js: -------------------------------------------------------------------------------- 1 | export const TOGGLE_THEME = 'TOGGLE_THEME'; 2 | export const SET_FILTERED_RESOURCES = 'SET_FILTERED_RESOURCES'; 3 | export const SET_PAGE_TITLE = 'SET_PAGE_TITLE'; 4 | -------------------------------------------------------------------------------- /src/data/contributors.js: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | id: 1, 4 | name: 'Binu Kumar', 5 | userId: 'Binu42', 6 | avatar: 'https://avatars3.githubusercontent.com/u/45959932?s=400&u=c45629c87cad71dcdc8d2d86808c9c52ec1fc68b&v=4', 7 | }, 8 | { 9 | id: 2, 10 | name: 'Prashant Kumar', 11 | userId: 'pkumars397', 12 | avatar: 'https://avatars0.githubusercontent.com/u/45540448?s=400&u=7ee96b166eba6a3552aef0f9496271c5b13adb7a&v=4', 13 | }, 14 | { 15 | id: 3, 16 | name: 'Abdul-Razak', 17 | userId: 'VolailleInc', 18 | avatar: 'https://avatars1.githubusercontent.com/u/36109125?s=400&u=61d980bafcbcf617a189054bf3d5c9280340e9f9&v=4', 19 | }, 20 | { 21 | id: 4, 22 | name: 'Jaydeep Khatri', 23 | userId: 'jaydeepkhatri', 24 | avatar: 'https://avatars0.githubusercontent.com/u/29619945?v=4', 25 | }, 26 | { 27 | id: 5, 28 | name: 'Jordan Mannfeld', 29 | userId: 'jmannfeld', 30 | avatar: 'https://avatars1.githubusercontent.com/u/16351524?s=400&u=262ab7ef3ad8077b69faeb9d0b4ea187f41ab688&v=4', 31 | }, 32 | ]; 33 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | background-color: #f8faff !important; 4 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 5 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | width: 100%; 10 | transition: all 0.3s linear; 11 | } 12 | 13 | .overflow-hidden { 14 | height: 100vh; 15 | overflow: hidden; 16 | } 17 | 18 | ::selection { 19 | background-color: #013896; 20 | color: #f1f1f1; 21 | } 22 | 23 | .App { 24 | min-height: 100vh; 25 | display: flex; 26 | flex-direction: column; 27 | } 28 | 29 | .navbar { 30 | transition: all 0.3s ease-in-out; 31 | } 32 | 33 | .is-horizontal-center { 34 | justify-content: center; 35 | } 36 | 37 | .modal .modal-card-body a.disabled { 38 | pointer-events: none; 39 | cursor: default; 40 | } 41 | 42 | .modal .modal-card-body .message { 43 | box-shadow: rgba(19, 15, 235, 0.1) 1px 2px 20px; 44 | } 45 | 46 | /* Navbar */ 47 | .box-shadow { 48 | box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.12), inset 0 -1px 0 0 #dadce0; 49 | } 50 | 51 | .dark-mode .box-shadow { 52 | box-shadow: 0 2px 6px 0 #53535348, inset 0 -1px 0 0 #3b3b3b; 53 | } 54 | 55 | .footer { 56 | padding: 5rem 1.5rem 2rem !important; 57 | background-color: #f8faff !important; 58 | margin-top: auto; 59 | } 60 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import 'bulma/css/bulma.min.css'; 6 | import { BrowserRouter as Router } from 'react-router-dom'; 7 | import ScrollToTop from './Components/ScrollToTop'; 8 | import * as serviceWorker from './serviceWorker'; 9 | 10 | ReactDOM.render( 11 | 12 | 13 | 14 | 15 | 16 | , 17 | document.getElementById('root'), 18 | ); 19 | 20 | serviceWorker.register({ 21 | onUpdate: (registration) => { 22 | alert('New version is available!, please update?'); 23 | if (registration && registration.waiting) { 24 | registration.waiting.postMessage({ type: 'SKIP_WAITING' }); 25 | } 26 | window.location.reload(); 27 | }, 28 | }); 29 | -------------------------------------------------------------------------------- /src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' 15 | // [::1] is the IPv6 localhost address. 16 | || window.location.hostname === '[::1]' 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | || window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/, 20 | ), 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' 46 | + 'worker. To learn more, visit https://bit.ly/CRA-PWA', 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then((registration) => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' 74 | + 'tabs for this page are closed. See https://bit.ly/CRA-PWA.', 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch((error) => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then((response) => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 109 | || (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then((registration) => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.', 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then((registration) => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | --------------------------------------------------------------------------------