├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── features-request-for-backend-or-frontend.md │ └── proposal.md └── workflows │ └── deploy-on-release.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── demo ├── images │ ├── 1.png │ ├── 10.png │ ├── 11.png │ ├── 12.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ ├── 6.png │ ├── 7.png │ ├── 8.png │ └── 9.png └── video │ └── StackOverflow CLONE - Dem0 Video.mp4 ├── package.json ├── public ├── LogoGlyphMd.svg ├── favicon.ico ├── index.html ├── manifest.json └── robots.txt └── src ├── App.css ├── App.js ├── Router.jsx ├── api ├── answersApi.js ├── authApi.js ├── commentsApi.js ├── postsApis.js ├── tagsApi.js ├── urls.js └── usersApi.js ├── assets ├── ArrowDownLg.svg ├── ArrowUpLg.svg ├── Database.svg ├── Edit.svg ├── ExternalLink.svg ├── GitHub.svg ├── Globe.svg ├── LogoGlyphMd.svg ├── LogoMd.svg ├── PageSpinner.svg ├── Quote.svg ├── Search.svg ├── StackExchange.svg ├── Tags.svg ├── Trophy.svg ├── Vote.svg └── three-dots.svg ├── components ├── Alert │ ├── Alert.component.jsx │ └── Alert.styles.scss ├── PageTitle │ └── PageTitle.component.jsx ├── atoms │ └── box.atom.jsx ├── molecules │ ├── BaseButton │ │ └── BaseButton.component.jsx │ ├── ButtonGroup │ │ └── ButtonGroup.component.jsx │ ├── LinkButton │ │ └── LinkButton.component.jsx │ ├── PostItem │ │ ├── PostItem.component.jsx │ │ └── PostItem.styles.scss │ ├── SearchBox │ │ ├── SearchBox.component.jsx │ │ └── SearchBox.styles.scss │ ├── Spinner │ │ ├── Spinner.component.jsx │ │ └── Spinner.styles.scss │ ├── TagBadge │ │ ├── TagBadge.component.jsx │ │ └── TagBadge.styles.scss │ └── UserCard │ │ ├── UserCard.component.jsx │ │ └── UserCard.styles.scss └── organisms │ ├── AuthForm │ ├── AuthForm.component.jsx │ └── AuthForm.styles.scss │ ├── Footer │ ├── Footer.component.jsx │ └── Footer.styles.scss │ ├── Header │ ├── Header.component.jsx │ └── Header.styles.scss │ ├── LayoutWrapper │ ├── LayoutWrapper.component.jsx │ ├── RightSideBar │ │ ├── RightSideBar.component.jsx │ │ ├── RightSideBar.styles.scss │ │ ├── SideBarWidget │ │ │ ├── SideBarWidget.component.jsx │ │ │ ├── SideBarWidget.styles.scss │ │ │ └── SideBarWidgetData.js │ │ └── TagsWidget │ │ │ ├── TagsWidget.component.jsx │ │ │ ├── TagsWidget.styles.scss │ │ │ ├── TagsWidgetItem.component.jsx │ │ │ └── TagsWidgetItem.styles.scss │ └── SideBar │ │ ├── SideBar.component.jsx │ │ ├── SideBar.styles.scss │ │ ├── SideBarData.js │ │ └── SideBarItem.component.jsx │ ├── MarkdownEditor │ ├── MarkdownEditor.component.jsx │ └── MarkdownEditor.styles.scss │ ├── MobileSideBar │ ├── MobileSideBar.component.jsx │ └── MobileSideBar.styles.scss │ └── Pagination │ └── Pagination.component.jsx ├── config └── index.js ├── hooks └── usePageTitle.jsx ├── index.js ├── modules ├── AllTagsPage │ ├── AllTagsPage.component.jsx │ ├── AllTagsPage.styles.scss │ └── TagPanel │ │ └── TagPanel.component.jsx ├── AllUsersPage │ ├── AllUsersPage.component.jsx │ ├── AllUsersPage.styles.scss │ └── UserPanel │ │ ├── UserPanel.component.jsx │ │ └── UserPanel.styles.scss ├── HomePage │ ├── HomePage.component.jsx │ └── HomePage.styles.scss ├── Login │ └── Login.component.jsx ├── NotFound │ ├── NotFound.component.jsx │ └── NotFound.styles.scss ├── Post │ ├── AnswerSection │ │ ├── AnswerForm │ │ │ ├── AnswerForm.component.jsx │ │ │ └── AnswerForm.styles.scss │ │ ├── AnswerItem │ │ │ ├── AnswerItem.component.jsx │ │ │ └── AnswerItem.styles.scss │ │ ├── AnswerSection.component.jsx │ │ └── AnswerSection.styles.scss │ ├── Post.component.jsx │ ├── Post.styles.scss │ └── QuestionSection │ │ ├── CommentCell │ │ ├── CommentCell.component.jsx │ │ └── CommentCell.styles.scss │ │ ├── PostCell │ │ ├── PostCell.component.jsx │ │ └── PostCell.styles.scss │ │ ├── QuestionSection.component.jsx │ │ ├── QuestionSection.styles.scss │ │ └── VoteCell │ │ ├── VoteCell.component.jsx │ │ └── VoteCell.styles.scss ├── PostForm │ ├── AskForm │ │ ├── AskForm.component.jsx │ │ └── AskForm.styles.scss │ ├── AskWidget │ │ ├── AskWidget.component.jsx │ │ └── AskWidget.styles.scss │ ├── PostForm.component.jsx │ └── PostForm.styles.scss ├── ProfilePage │ ├── ExternalUserDetails │ │ ├── ExternalUserDetails.component.jsx │ │ └── ExternalUserDetails.styles.scss │ ├── ProfilePage.component.jsx │ ├── ProfilePage.styles.scss │ ├── UserActivity │ │ ├── UserActivity.component.jsx │ │ └── UserActivity.styles.scss │ └── UserSection │ │ ├── AvatarCard │ │ ├── AvatarCard.component.jsx │ │ └── AvatarCard.styles.scss │ │ ├── ContentCard │ │ ├── ContentCard.component.jsx │ │ └── ContentCard.styles.scss │ │ ├── UserSection.component.jsx │ │ └── UserSection.styles.scss ├── QuestionsPage │ ├── QuestionsPage.component.jsx │ └── QuestionsPage.styles.scss ├── Register │ ├── Caption │ │ ├── Caption.component.jsx │ │ └── Caption.styles.scss │ ├── Register.component.jsx │ └── Register.styles.scss └── TagPage │ ├── TagPage.component.jsx │ └── TagPage.styles.scss ├── redux ├── alert │ ├── alert.actions.js │ ├── alert.reducer.js │ └── alert.types.js ├── answers │ ├── answers.actions.js │ ├── answers.reducer.js │ └── answers.types.js ├── auth │ ├── auth.actions.js │ ├── auth.reducer.js │ ├── auth.types.js │ └── auth.utils.js ├── comments │ ├── comments.actions.js │ ├── comments.reducer.js │ └── comments.types.js ├── posts │ ├── posts.actions.js │ ├── posts.reducer.js │ └── posts.types.js ├── root-reducer.js ├── store.js ├── tags │ ├── tags.actions.js │ ├── tags.reducer.js │ └── tags.types.js └── users │ ├── users.actions.js │ ├── users.reducer.js │ └── users.types.js └── utils ├── censorBadWords.js ├── handleFilter.js ├── handleSorting.js ├── htmlSubstring.js └── injectEllipsis.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [Mayank0255] 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]: Write a descriptive title" 5 | labels: bug 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 | **Additional context** 27 | Add any other context about the problem here. 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/features-request-for-backend-or-frontend.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Features Request for Backend or Frontend 3 | about: Suggest an idea for the project 4 | title: "[Backend/Frontend]: Write a descriptive idea title" 5 | labels: enhancement, feature 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/ISSUE_TEMPLATE/proposal.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Proposal 3 | about: Propose a non-trivial change 4 | title: "[Proposal]: Write a descriptive title here" 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Proposal 11 | 12 | (A clear and concise description of what the proposal is.) 13 | -------------------------------------------------------------------------------- /.github/workflows/deploy-on-release.yml: -------------------------------------------------------------------------------- 1 | name: "Deploy" 2 | 3 | on: 4 | release: 5 | types: 6 | - published 7 | push: 8 | branches: 9 | - dev 10 | workflow_dispatch: 11 | 12 | jobs: 13 | vercel: 14 | runs-on: ubuntu-latest 15 | name: "Deploy Front-End" 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - uses: actions/setup-node@v1 20 | with: 21 | node-version: "14" 22 | registry-url: https://registry.npmjs.org/ 23 | 24 | - name: "Deploy to Vercel" 25 | run: | 26 | prodRun="" 27 | if [[ ${GITHUB_REF} == "refs/heads/main" ]]; then 28 | prodRun="--prod" 29 | fi 30 | 31 | npx vercel --token ${VERCEL_TOKEN} $prodRun 32 | env: 33 | VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} 34 | VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} 35 | VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /.idea 3 | /.vscode 4 | /client/node_modules 5 | .env 6 | package-lock.json 7 | /client/package-lock.json 8 | yarn.lock 9 | .vercel 10 | -------------------------------------------------------------------------------- /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 mayank2aggarwal@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 | # Contributing to Stackoverflow Clone 2 | We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's: 3 | 4 | - Reporting a bug 5 | - Discussing the current state of the code 6 | - Submitting a fix 7 | - Proposing new features 8 | - Becoming a maintainer 9 | 10 | ## Our Development Process 11 | We use GitHub to sync code to and from our internal repository. We'll use GitHub 12 | to track issues and feature requests, as well as accept pull requests. 13 | 14 | ## Pull Requests 15 | We actively welcome your pull requests. 16 | 17 | 1. Fork the repo and create your branch from `master`. 18 | 2. If you've added code that should be tested, then state about it in the PR description. 19 | 3. If you've changed APIs, update the documentation (in the readme file at the moment). 20 | 4. The PR title should begin with _(): _ e.g. - "feat(#12): ", "chore(#12): ", "fix(#12): ", "refactor(#12):" and "test(#12):" 21 | 5. Make sure your code satisfies the coding conventions used in the rest of the project. 22 | 23 | ## Issues 24 | We use GitHub issues to track public bugs. Please ensure your description is 25 | clear and has sufficient instructions to be able to reproduce the issue. 26 | 27 | ## License 28 | By contributing, you agree that your contributions will be licensed under its MIT License. 29 | 30 | ## References 31 | This document was adapted from the open-source contribution guidelines for [Facebook's Draft](https://github.com/facebook/draft-js/blob/a9316a723f9e918afde44dea68b5f9f39b7d9b00/CONTRIBUTING.md) 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Mayank Aggarwal 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 | -------------------------------------------------------------------------------- /demo/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mayank0255/Stackoverflow-Clone-Frontend/488073c643c9bc8e4735f1fac424eb1c0448dec1/demo/images/1.png -------------------------------------------------------------------------------- /demo/images/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mayank0255/Stackoverflow-Clone-Frontend/488073c643c9bc8e4735f1fac424eb1c0448dec1/demo/images/10.png -------------------------------------------------------------------------------- /demo/images/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mayank0255/Stackoverflow-Clone-Frontend/488073c643c9bc8e4735f1fac424eb1c0448dec1/demo/images/11.png -------------------------------------------------------------------------------- /demo/images/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mayank0255/Stackoverflow-Clone-Frontend/488073c643c9bc8e4735f1fac424eb1c0448dec1/demo/images/12.png -------------------------------------------------------------------------------- /demo/images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mayank0255/Stackoverflow-Clone-Frontend/488073c643c9bc8e4735f1fac424eb1c0448dec1/demo/images/2.png -------------------------------------------------------------------------------- /demo/images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mayank0255/Stackoverflow-Clone-Frontend/488073c643c9bc8e4735f1fac424eb1c0448dec1/demo/images/3.png -------------------------------------------------------------------------------- /demo/images/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mayank0255/Stackoverflow-Clone-Frontend/488073c643c9bc8e4735f1fac424eb1c0448dec1/demo/images/4.png -------------------------------------------------------------------------------- /demo/images/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mayank0255/Stackoverflow-Clone-Frontend/488073c643c9bc8e4735f1fac424eb1c0448dec1/demo/images/5.png -------------------------------------------------------------------------------- /demo/images/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mayank0255/Stackoverflow-Clone-Frontend/488073c643c9bc8e4735f1fac424eb1c0448dec1/demo/images/6.png -------------------------------------------------------------------------------- /demo/images/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mayank0255/Stackoverflow-Clone-Frontend/488073c643c9bc8e4735f1fac424eb1c0448dec1/demo/images/7.png -------------------------------------------------------------------------------- /demo/images/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mayank0255/Stackoverflow-Clone-Frontend/488073c643c9bc8e4735f1fac424eb1c0448dec1/demo/images/8.png -------------------------------------------------------------------------------- /demo/images/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mayank0255/Stackoverflow-Clone-Frontend/488073c643c9bc8e4735f1fac424eb1c0448dec1/demo/images/9.png -------------------------------------------------------------------------------- /demo/video/StackOverflow CLONE - Dem0 Video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mayank0255/Stackoverflow-Clone-Frontend/488073c643c9bc8e4735f1fac424eb1c0448dec1/demo/video/StackOverflow CLONE - Dem0 Video.mp4 -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@emotion/react": "^11.8.1", 7 | "@emotion/styled": "^11.8.1", 8 | "@mui/icons-material": "^5.5.0", 9 | "@mui/material": "^5.5.0", 10 | "@stackoverflow/stacks-icons": "^2.25.1", 11 | "@testing-library/jest-dom": "^5.16.1", 12 | "@testing-library/react": "^12.1.2", 13 | "@testing-library/user-event": "^13.5.0", 14 | "axios": "^0.24.0", 15 | "bad-words": "^3.0.4", 16 | "feather-icons": "^4.28.0", 17 | "moment": "^2.29.4", 18 | "prop-types": "^15.8.0", 19 | "react": "^17.0.2", 20 | "react-dom": "^17.0.2", 21 | "react-helmet": "^6.1.0", 22 | "react-logger": "^1.1.0", 23 | "react-redux": "^7.2.6", 24 | "react-router-dom": "^5.3.0", 25 | "react-router-redux": "^4.0.8", 26 | "react-rte": "^0.16.4", 27 | "react-scripts": "^5.0.0", 28 | "redux": "^4.1.2", 29 | "redux-devtools-extension": "^2.13.9", 30 | "redux-persist": "^6.0.0", 31 | "redux-thunk": "^2.4.1", 32 | "reselect": "^4.1.5", 33 | "sass": "^1.45.2", 34 | "styled-system": "^5.1.5", 35 | "uuid": "^8.3.2" 36 | }, 37 | "scripts": { 38 | "start": "react-scripts start", 39 | "build": "react-scripts build", 40 | "test": "react-scripts test", 41 | "eject": "react-scripts eject" 42 | }, 43 | "eslintConfig": { 44 | "extends": "react-app" 45 | }, 46 | "browserslist": { 47 | "production": [ 48 | ">0.2%", 49 | "not dead", 50 | "not op_mini all" 51 | ], 52 | "development": [ 53 | "last 1 chrome version", 54 | "last 1 firefox version", 55 | "last 1 safari version" 56 | ] 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /public/LogoGlyphMd.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mayank0255/Stackoverflow-Clone-Frontend/488073c643c9bc8e4735f1fac424eb1c0448dec1/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | CLONE Stack Overflow - Where Developers Learn, Share, & Build Careers 14 | 15 | 16 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --yellow-200: #675c37; 3 | --yellow-050: #464236; 4 | } 5 | 6 | *{ 7 | margin: 0; 8 | padding: 0; 9 | box-sizing: border-box; 10 | font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Liberation Sans",sans-serif !important; 11 | transition: all 300ms ease-in-out; 12 | } 13 | 14 | body { 15 | background-color: #2d2d2d !important; 16 | padding-top: 0 !important; 17 | } 18 | 19 | a { 20 | text-decoration: none !important; 21 | } 22 | 23 | button { 24 | margin: 3px; 25 | } -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, {useEffect} from 'react'; 2 | import {Provider} from 'react-redux'; 3 | import {Switch} from 'react-router-dom'; 4 | 5 | import store from './redux/store'; 6 | import setAuthToken from './redux/auth/auth.utils'; 7 | import {loadUser} from './redux/auth/auth.actions'; 8 | 9 | import Header from './components/organisms/Header/Header.component'; 10 | import Alert from './components/Alert/Alert.component'; 11 | import HomePage from './modules/HomePage/HomePage.component'; 12 | import QuestionsPage from './modules/QuestionsPage/QuestionsPage.component'; 13 | import AllTagsPage from './modules/AllTagsPage/AllTagsPage.component'; 14 | import AllUsersPage from './modules/AllUsersPage/AllUsersPage.component'; 15 | import Register from './modules/Register/Register.component'; 16 | import Login from './modules/Login/Login.component'; 17 | import Post from './modules/Post/Post.component'; 18 | import PostForm from './modules/PostForm/PostForm.component'; 19 | import TagPage from './modules/TagPage/TagPage.component'; 20 | import ProfilePage from './modules/ProfilePage/ProfilePage.component'; 21 | import NotFound from './modules/NotFound/NotFound.component'; 22 | 23 | import { BaseRoute, LayoutRoute } from './Router'; 24 | 25 | import './App.css'; 26 | 27 | if (localStorage.token) { 28 | setAuthToken(localStorage.token); 29 | } 30 | 31 | const App = () => { 32 | useEffect(() => { 33 | store.dispatch(loadUser()); 34 | }, []); 35 | 36 | return ( 37 | 38 |
39 |
40 | 41 | 42 | 47 | 48 | 49 | 54 | 55 | 56 | 61 | 62 | 63 | 68 | 69 | 70 | 75 | 76 | 77 | 82 | 83 | 84 | 89 | 90 | 91 | 96 | 97 | 98 | 103 | 104 | 105 | 110 | 111 | 112 | 116 | 117 | 118 | 119 |
120 |
121 | ); 122 | }; 123 | 124 | export default App; 125 | -------------------------------------------------------------------------------- /src/Router.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Route } from 'react-router-dom'; 3 | 4 | import LayoutWrapper from './components/organisms/LayoutWrapper/LayoutWrapper.component'; 5 | 6 | import usePageTitle from './hooks/usePageTitle'; 7 | 8 | export const LayoutRoute = ({ title, children, ...props }) => { 9 | usePageTitle(title); 10 | 11 | return ( 12 | 13 | 14 | {children} 15 | 16 | 17 | ) 18 | } 19 | 20 | export const BaseRoute = ({ title, children, ...props }) => { 21 | usePageTitle(title); 22 | 23 | return ( 24 | 25 | {children} 26 | 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /src/api/answersApi.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | import { 4 | allAnswersData as _allAnswersData, 5 | createSingleAnswer as _createSingleAnswer, 6 | deleteSingleAnswer as _deleteSingleAnswer 7 | } from './urls'; 8 | 9 | export const allAnswersData = (id) => { 10 | return axios.get(_allAnswersData.replace('{id}', id)); 11 | } 12 | 13 | export const createSingleAnswer = (postId, formData) => { 14 | const config_headers = { 15 | headers: { 16 | "Content-Type": "application/json", 17 | }, 18 | }; 19 | 20 | return axios.post(_createSingleAnswer.replace('{postId}', postId), formData, config_headers); 21 | } 22 | 23 | export const deleteSingleAnswer = (AnswerId) => { 24 | return axios.delete(_deleteSingleAnswer.replace('{AnswerId}', AnswerId)); 25 | } -------------------------------------------------------------------------------- /src/api/authApi.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | import {loadUserData as _loadUserData, registerUser as _registerUser, loginUser as _loginUser} from './urls'; 4 | 5 | export const loadUserData = () => { 6 | return axios.get(_loadUserData); 7 | }; 8 | 9 | export const registerUser = (username, password) => { 10 | const config_headers = { 11 | headers: { 12 | 'Content-Type': 'application/json', 13 | Accept: "application/json", 14 | }, 15 | }; 16 | 17 | const body = JSON.stringify({ username, password }); 18 | 19 | return axios.post(_registerUser, body, config_headers); 20 | }; 21 | 22 | export const loginUser = (username, password) => { 23 | const config_headers = { 24 | headers: { 25 | 'Content-Type': 'application/json', 26 | Accept: "application/json", 27 | }, 28 | }; 29 | 30 | const body = JSON.stringify({username, password}); 31 | 32 | return axios.post(_loginUser, body, config_headers); 33 | }; -------------------------------------------------------------------------------- /src/api/commentsApi.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | import { 4 | allCommentsData as _allCommentsData, 5 | createSingleComment as _createSingleComment, 6 | deleteSingleComment as _deleteSingleComment 7 | } from './urls'; 8 | 9 | export const allCommentsData = (id) => { 10 | return axios.get(_allCommentsData.replace('{id}', id)); 11 | } 12 | 13 | export const createSingleComment = (postId, formData) => { 14 | const config_headers = { 15 | headers: { 16 | "Content-Type": "application/json", 17 | }, 18 | }; 19 | 20 | return axios.post(_createSingleComment.replace('{postId}', postId), formData, config_headers); 21 | } 22 | 23 | export const deleteSingleComment = (CommentId) => { 24 | return axios.delete(_deleteSingleComment.replace('{CommentId}', CommentId)); 25 | } -------------------------------------------------------------------------------- /src/api/postsApis.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | import { 4 | allPostsData as _allPostsData, 5 | singlePostData as _singlePostData, 6 | allTagPostsData as _allTagPostsData, 7 | createSinglePost as _createSinglePost, 8 | deleteSinglePost as _deleteSinglePost 9 | } from './urls'; 10 | 11 | export const allPostsData = () => { 12 | return axios.get(_allPostsData); 13 | } 14 | 15 | export const singlePostData = (id) => { 16 | return axios.get(_singlePostData.replace('{id}', id)); 17 | } 18 | 19 | export const allTagPostsData = (tagName) => { 20 | return axios.get(_allTagPostsData.replace('{tagName}', tagName)); 21 | } 22 | 23 | export const createSinglePost = (formData) => { 24 | const config_headers = { 25 | headers: { 26 | "Content-Type": "application/json", 27 | }, 28 | }; 29 | 30 | return axios.post(_createSinglePost, formData, config_headers); 31 | } 32 | 33 | export const deleteSinglePost = (id) => { 34 | return axios.delete(_deleteSinglePost.replace('{id}', id)); 35 | } -------------------------------------------------------------------------------- /src/api/tagsApi.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | import { allTagsData as _allTagsData, singleTagData as _singleTagData } from './urls'; 4 | 5 | export const allTagsData = () => { 6 | return axios.get(_allTagsData); 7 | } 8 | 9 | export const singleTagData = (tagName) => { 10 | return axios.get(_singleTagData.replace('{tagName}', tagName)); 11 | } -------------------------------------------------------------------------------- /src/api/urls.js: -------------------------------------------------------------------------------- 1 | import config from "../config"; 2 | 3 | // Users 4 | export const usersData = config.BASE_URL + '/api/users'; 5 | export const profileData = config.BASE_URL + '/api/users/{id}'; 6 | 7 | // Auth 8 | export const loadUserData = config.BASE_URL + '/api/auth'; 9 | export const registerUser = config.BASE_URL + '/api/users'; 10 | export const loginUser = config.BASE_URL + '/api/auth'; 11 | 12 | // Posts 13 | export const allPostsData = config.BASE_URL + '/api/posts'; 14 | export const singlePostData = config.BASE_URL + '/api/posts/{id}'; 15 | export const allTagPostsData = config.BASE_URL + '/api/posts/tag/{tagName}'; 16 | export const createSinglePost = config.BASE_URL + '/api/posts'; 17 | export const deleteSinglePost = config.BASE_URL + '/api/posts/{id}'; 18 | 19 | // Answers 20 | export const allAnswersData = config.BASE_URL + '/api/posts/answers/{id}'; 21 | export const createSingleAnswer = config.BASE_URL + '/api/posts/answers/{postId}'; 22 | export const deleteSingleAnswer = config.BASE_URL + '/api/posts/answers/{AnswerId}'; 23 | 24 | // Comments 25 | export const allCommentsData = config.BASE_URL + '/api/posts/comments/{id}'; 26 | export const createSingleComment = config.BASE_URL + '/api/posts/comments/{postId}'; 27 | export const deleteSingleComment = config.BASE_URL + '/api/posts/comments/{CommentId}'; 28 | 29 | // Tags 30 | export const allTagsData = config.BASE_URL + '/api/tags'; 31 | export const singleTagData = config.BASE_URL + '/api/tags/{tagName}'; -------------------------------------------------------------------------------- /src/api/usersApi.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | import {usersData as _usersData, profileData as _profileData} from './urls'; 4 | 5 | export const usersData = () => { 6 | return axios.get(_usersData); 7 | }; 8 | 9 | export const profileData = (id) => { 10 | return axios.get(_profileData.replace('{id}', id)); 11 | }; -------------------------------------------------------------------------------- /src/assets/ArrowDownLg.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/ArrowUpLg.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/Database.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/Edit.svg: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/assets/ExternalLink.svg: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /src/assets/GitHub.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/Globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/LogoGlyphMd.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/PageSpinner.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/Quote.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/Search.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/StackExchange.svg: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /src/assets/Tags.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/Trophy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/Vote.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/three-dots.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Alert/Alert.component.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import {connect} from 'react-redux'; 4 | 5 | import './Alert.styles.scss'; 6 | 7 | const Alert = ({ alerts }) => { 8 | return alerts.length > 0 && 9 | alerts.map((alert, index) => { 10 | if (alert.alertType === 'success') { 11 | return ( 12 | 15 | ) 16 | } else { 17 | return ( 18 | 21 | ) 22 | } 23 | } 24 | ) 25 | } 26 | 27 | Alert.propTypes = { 28 | alerts: PropTypes.array.isRequired, 29 | }; 30 | 31 | const mapStateToProps = (state) => ({ 32 | alerts: state.alert, 33 | }); 34 | 35 | export default connect(mapStateToProps)(Alert); 36 | -------------------------------------------------------------------------------- /src/components/Alert/Alert.styles.scss: -------------------------------------------------------------------------------- 1 | .alert { 2 | top: 75px; 3 | z-index: 10; 4 | position: fixed; 5 | width: 70%; 6 | max-width: 1000px; 7 | min-width: 320px; 8 | left: 50%; 9 | transform: translateX(-50%); 10 | } -------------------------------------------------------------------------------- /src/components/PageTitle/PageTitle.component.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Helmet from 'react-helmet'; 3 | 4 | const PageTitle = ({title}) => { 5 | let defaultTitle = 6 | 'CLONE Stack Overflow - Where Developers Learn, Share, & Build Careers'; 7 | 8 | return ( 9 | 10 | {title ? title : defaultTitle} 11 | 12 | ); 13 | }; 14 | 15 | export default PageTitle; 16 | -------------------------------------------------------------------------------- /src/components/atoms/box.atom.jsx: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled'; 2 | import { 3 | space, 4 | color, 5 | layout, 6 | flexbox, 7 | position, 8 | typography, 9 | border, 10 | background, 11 | } from 'styled-system'; 12 | 13 | export const Box = styled.div` 14 | box-sizing: border-box; 15 | min-width: 0; 16 | ${space} 17 | ${color} 18 | ${layout} 19 | ${flexbox} 20 | ${position} 21 | ${typography} 22 | ${border} 23 | ${background} 24 | `; 25 | 26 | export const FlexBox = styled(Box)` 27 | display: flex; 28 | `; 29 | 30 | export const FlexBoxColumn = styled(Box)` 31 | display: flex; 32 | flex-direction: column; 33 | `; 34 | 35 | export const GapFlexBox = styled(FlexBox)` 36 | gap: ${({ gap = "0" }) => gap}; 37 | `; 38 | 39 | export const GapFlexBoxColumn = styled(FlexBoxColumn)` 40 | gap: ${({ gap = "0" }) => gap}; 41 | `; -------------------------------------------------------------------------------- /src/components/molecules/BaseButton/BaseButton.component.jsx: -------------------------------------------------------------------------------- 1 | import React, {Fragment} from 'react'; 2 | 3 | const BaseButton = ({text, selected, onClick}) => { 4 | return ( 5 | 6 | 15 | 16 | ); 17 | }; 18 | 19 | export default BaseButton; 20 | -------------------------------------------------------------------------------- /src/components/molecules/ButtonGroup/ButtonGroup.component.jsx: -------------------------------------------------------------------------------- 1 | import React, {Fragment} from 'react'; 2 | import BaseButton from '../BaseButton/BaseButton.component'; 3 | 4 | const ButtonGroup = ({buttons, selected, setSelected}) => { 5 | return ( 6 | 7 |
8 |
9 | {buttons.map((button, index) => ( 10 | setSelected(button)} 15 | /> 16 | ))} 17 |
18 |
19 |
20 | ); 21 | }; 22 | 23 | export default ButtonGroup; 24 | -------------------------------------------------------------------------------- /src/components/molecules/LinkButton/LinkButton.component.jsx: -------------------------------------------------------------------------------- 1 | import React, {Fragment} from 'react'; 2 | import {Link} from 'react-router-dom'; 3 | 4 | const LinkButton = ({text, link, type, handleClick, marginTop}) => { 5 | return ( 6 | 7 | 8 | 11 | 12 | 13 | ); 14 | }; 15 | 16 | export default LinkButton; 17 | -------------------------------------------------------------------------------- /src/components/molecules/PostItem/PostItem.component.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { connect } from "react-redux"; 3 | import PropTypes from "prop-types"; 4 | import { Link } from "react-router-dom"; 5 | 6 | import censorBadWords from "../../../utils/censorBadWords"; 7 | 8 | import htmlSubstring from "../../../utils/htmlSubstring"; 9 | import injectEllipsis from "../../../utils/injectEllipsis"; 10 | 11 | import UserCard from "../UserCard/UserCard.component"; 12 | import TagBadge from "../TagBadge/TagBadge.component"; 13 | 14 | import "./PostItem.styles.scss"; 15 | 16 | const PostItem = ({ 17 | post: { 18 | id, 19 | title, 20 | body, 21 | username, 22 | gravatar, 23 | user_id, 24 | answer_count, 25 | comment_count, 26 | views, 27 | created_at, 28 | tags, 29 | }, 30 | }) => { 31 | const answerVoteUp = ( 32 |
33 | {answer_count} 34 |
answers
35 |
36 | ); 37 | 38 | const answerVoteDown = ( 39 |
40 | {answer_count} 41 |
answers
42 |
43 | ); 44 | 45 | return ( 46 |
47 |
48 |
49 |
50 | {comment_count} 51 |
comments
52 |
53 | {answer_count > 0 ? answerVoteUp : answerVoteDown} 54 |
55 | {tags.length} 56 |
tags
57 |
58 |
59 |
{views} views
60 |
61 |
62 |
63 |
64 |

65 | {censorBadWords(title)} 66 |

67 |
73 |
74 | {tags.map((tag, index) => ( 75 | 76 | ))} 77 |
78 | 86 |
87 |
88 | ); 89 | }; 90 | 91 | PostItem.propTypes = { 92 | post: PropTypes.object.isRequired, 93 | }; 94 | 95 | export default connect(null)(PostItem); 96 | -------------------------------------------------------------------------------- /src/components/molecules/PostItem/PostItem.styles.scss: -------------------------------------------------------------------------------- 1 | .posts { 2 | padding: 12px 8px 12px 8px; 3 | width: 100%; 4 | box-sizing: border-box; 5 | display: flex; 6 | border-bottom: 1px solid #4a4e51; 7 | 8 | .profile-tags { 9 | display: flex; 10 | } 11 | 12 | .stats { 13 | display: flex; 14 | flex-direction: column; 15 | flex-shrink: 0; 16 | flex-wrap: wrap; 17 | align-items: flex-end; 18 | } 19 | 20 | .stats-container { 21 | width: 58px; 22 | color: #6a737c; 23 | margin-left: 20px; 24 | font-size: 11px; 25 | } 26 | .vote { 27 | padding: 0; 28 | margin-bottom: 8px; 29 | text-align: center; 30 | display: flex; 31 | 32 | .vote-count { 33 | font-size: 14px; 34 | margin-right: 2px; 35 | } 36 | 37 | .count-text { 38 | font-size: 12px; 39 | } 40 | } 41 | 42 | 43 | .answer { 44 | border: 2px solid #63b47c; 45 | background-color: #63b47c; 46 | color: white; 47 | border-radius: 3px; 48 | padding: 4px; 49 | 50 | .vote-count { 51 | color: white; 52 | font-size: 12px; 53 | padding: 1px; 54 | } 55 | .count-text{ 56 | color: white; 57 | font-size: 12px; 58 | padding: 1px; 59 | } 60 | } 61 | 62 | 63 | .vote { 64 | padding: 0; 65 | margin-bottom: 8px; 66 | text-align: center; 67 | display: flex; 68 | 69 | .vote-count { 70 | font-size: 12px; 71 | margin-right: 2px; 72 | } 73 | 74 | .count-text { 75 | font-size: 12px; 76 | } 77 | 78 | .views { 79 | .count-text { 80 | font-size: 12px; 81 | color: #ffa600; 82 | } 83 | } 84 | 85 | } 86 | 87 | .summary { 88 | margin-left: 30px; 89 | width: 600px; 90 | 91 | h3 { 92 | font-weight: 400; 93 | font-size: 15px; 94 | line-height: 1.4; 95 | margin-bottom: 7.5px; 96 | 97 | a { 98 | color: #0077cc; 99 | line-height: 1.3; 100 | margin-bottom: 1.2em; 101 | font-size: 16px; 102 | text-decoration: none; 103 | 104 | &:hover { 105 | color: #0095ff; 106 | } 107 | } 108 | } 109 | 110 | .brief { 111 | padding: 0 0 5px 0; 112 | margin: 0; 113 | font-family: Arial, serif; 114 | font-size: 13px; 115 | } 116 | 117 | .question-user { 118 | width: 200px; 119 | line-height: 18px; 120 | float: right; 121 | 122 | .user-info { 123 | color: #848d95; 124 | padding: 5px 6px 7px 7px; 125 | 126 | .user-action-time { 127 | margin-bottom: 2px; 128 | margin-top: 1px; 129 | font-size: 12px; 130 | } 131 | 132 | .user-gravatar { 133 | float: left; 134 | width: 32px; 135 | height: 32px; 136 | border-radius: 1px; 137 | 138 | .logo-wrapper { 139 | padding: 0; 140 | overflow: hidden; 141 | 142 | img { 143 | width: 32px; 144 | height: 32px; 145 | } 146 | } 147 | } 148 | 149 | .user-details { 150 | margin-left: 40px; 151 | float: none; 152 | line-height: 17px; 153 | width: 80%; 154 | 155 | a { 156 | color: #0077cc; 157 | font-size: 12px; 158 | text-decoration: none; 159 | 160 | &:hover { 161 | color: #0095ff; 162 | } 163 | } 164 | } 165 | } 166 | } 167 | } 168 | } 169 | 170 | @media (max-width: 420px) { 171 | .owner .user-block .user-profile .user-profile-link { 172 | font-size: 11px; 173 | } 174 | } -------------------------------------------------------------------------------- /src/components/molecules/SearchBox/SearchBox.component.jsx: -------------------------------------------------------------------------------- 1 | import React, {Fragment} from 'react'; 2 | import {ReactComponent as Search} from '../../../assets/Search.svg'; 3 | 4 | const SearchBox = ({ 5 | placeholder, 6 | value, 7 | name, 8 | handleSubmit, 9 | handleChange, 10 | pt, 11 | px, 12 | width, 13 | }) => { 14 | return ( 15 | 16 | 36 | 37 | ); 38 | }; 39 | 40 | export default SearchBox; 41 | -------------------------------------------------------------------------------- /src/components/molecules/SearchBox/SearchBox.styles.scss: -------------------------------------------------------------------------------- 1 | .search-frame { 2 | width: 220px; 3 | //float: right; 4 | } 5 | 6 | .search-box:focus { 7 | border-color: #2b5f8a; 8 | box-shadow: 0 0 0 4px #378ad326; 9 | color: #fff; 10 | outline: 0; 11 | } -------------------------------------------------------------------------------- /src/components/molecules/Spinner/Spinner.component.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import {ReactComponent as PageSpinner} from '../../../assets/PageSpinner.svg'; 4 | import {ReactComponent as ComponentSpinner} from '../../../assets/three-dots.svg'; 5 | 6 | import './Spinner.styles.scss'; 7 | 8 | const Spinner = ({type, width, height}) => { 9 | return ( 10 |
11 | {type === 'page' ? : } 12 |
13 | ); 14 | }; 15 | 16 | export default Spinner; 17 | -------------------------------------------------------------------------------- /src/components/molecules/Spinner/Spinner.styles.scss: -------------------------------------------------------------------------------- 1 | .spinner { 2 | margin: auto; 3 | display: flex; 4 | justify-content: center; 5 | align-items: center; 6 | } -------------------------------------------------------------------------------- /src/components/molecules/TagBadge/TagBadge.component.jsx: -------------------------------------------------------------------------------- 1 | import React, {Fragment} from 'react'; 2 | import {Link} from 'react-router-dom'; 3 | 4 | import './TagBadge.styles.scss'; 5 | 6 | const TagBadge = ({tag_name, size, display, link, href}) => { 7 | return ( 8 | 9 |
10 | {href === true ? ( 11 | 12 | {tag_name} 13 | 14 | ) : ( 15 | 16 | {tag_name} 17 | 18 | )} 19 |
20 |
21 | ); 22 | }; 23 | 24 | export default TagBadge; 25 | -------------------------------------------------------------------------------- /src/components/molecules/TagBadge/TagBadge.styles.scss: -------------------------------------------------------------------------------- 1 | .tags-badge { 2 | color: #242729; 3 | line-height: 18px; 4 | margin-right: 4px; 5 | } -------------------------------------------------------------------------------- /src/components/molecules/UserCard/UserCard.component.jsx: -------------------------------------------------------------------------------- 1 | import React, {Fragment} from 'react'; 2 | import moment from 'moment'; 3 | import {Link} from 'react-router-dom'; 4 | 5 | import './UserCard.styles.scss'; 6 | 7 | const UserCard = ({ 8 | created_at, 9 | user_id, 10 | gravatar, 11 | username, 12 | dateType, 13 | float, 14 | backgroundColor, 15 | }) => { 16 | return ( 17 | 18 |
22 |
23 |
24 | {dateType ? dateType : 'asked'} {moment(created_at).fromNow(true)}{' '} 25 | ago 26 |
27 |
28 | 29 |
30 | user_logo 34 |
35 | 36 |
37 |
38 | 42 | {username} 43 | 44 |
45 |
46 |
47 |
48 | ); 49 | }; 50 | 51 | export default UserCard; 52 | -------------------------------------------------------------------------------- /src/components/molecules/UserCard/UserCard.styles.scss: -------------------------------------------------------------------------------- 1 | .owner { 2 | margin-top: 4px; 3 | margin-bottom: 4px; 4 | border-radius: 3px; 5 | background-color: #3e4a52; 6 | text-align: left; 7 | vertical-align: top; 8 | width: 200px; 9 | 10 | .user-block { 11 | box-sizing: border-box; 12 | padding: 5px 6px 0 7px; 13 | color: #6a737c; 14 | 15 | .action-time { 16 | margin-top: 1px; 17 | margin-bottom: 4px; 18 | font-size: 12px; 19 | white-space: nowrap; 20 | } 21 | 22 | .user-logo { 23 | float: left; 24 | width: 32px; 25 | height: 32px; 26 | border-radius: 1px; 27 | margin-bottom: 6px; 28 | 29 | .user-link { 30 | color: #0077cc; 31 | text-decoration: none; 32 | cursor: pointer; 33 | 34 | .logo-wrapper { 35 | width: 32px; 36 | height: 32px; 37 | padding: 0; 38 | overflow: hidden; 39 | 40 | img { 41 | width: 32px; 42 | height: 32px; 43 | border-radius: 3px !important; 44 | } 45 | } 46 | } 47 | } 48 | 49 | .user-profile { 50 | margin-left: 8px; 51 | width: calc(100% - 40px); 52 | float: left; 53 | line-height: 17px; 54 | word-wrap: break-word; 55 | 56 | .user-profile-link { 57 | color: #0077cc; 58 | text-decoration: none; 59 | cursor: pointer; 60 | font-size: 14px; 61 | 62 | &:hover { 63 | color:#0095ff; 64 | } 65 | } 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /src/components/organisms/AuthForm/AuthForm.styles.scss: -------------------------------------------------------------------------------- 1 | .form-container { 2 | width: 320px; 3 | box-shadow: 0 10px 25px rgba(0,0,0,0.05), 0 20px 48px rgba(0,0,0,0.05), 0 1px 4px rgba(0,0,0,0.1); 4 | padding: 24px; 5 | margin-left: auto; 6 | margin-right: auto; 7 | margin-bottom: 24px; 8 | background-color: #2d2d2d; 9 | border-radius: 7px; 10 | box-sizing: inherit; 11 | display: block; 12 | 13 | div { 14 | margin: 6px 0; 15 | 16 | button { 17 | margin: 5px 0 3px 0; 18 | width: 100%; 19 | } 20 | } 21 | 22 | .fs-caption { 23 | color:#6a737c; 24 | font-size: 12px; 25 | } 26 | 27 | .license { 28 | margin-top: 32px; 29 | } 30 | .form-label { 31 | font-weight: 600; 32 | } 33 | } 34 | 35 | .icon-holder { 36 | text-align: center; 37 | margin-bottom: 15px; 38 | 39 | .icon { 40 | width: 45px; 41 | height: 45px; 42 | } 43 | } 44 | 45 | .redirects { 46 | padding: 16px 16px 0 16px; 47 | text-align: center; 48 | font-size: 13px; 49 | margin-bottom: 24px; 50 | } -------------------------------------------------------------------------------- /src/components/organisms/Footer/Footer.component.jsx: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from "react"; 2 | 3 | import {ReactComponent as GitHub} from "../../../assets/GitHub.svg"; 4 | import {ReactComponent as Database} from "../../../assets/Database.svg"; 5 | 6 | import './Footer.styles.scss'; 7 | 8 | const Footer = () => { 9 | return 10 |
11 |
12 |
13 | 18 | 19 | 20 |

Frontend

21 |
22 |
23 | 28 | 29 | 30 |

Backend

31 |
32 |
33 |
34 |
35 | }; 36 | 37 | export default Footer; -------------------------------------------------------------------------------- /src/components/organisms/Footer/Footer.styles.scss: -------------------------------------------------------------------------------- 1 | .footer { 2 | height: 300px; 3 | display: flex; 4 | justify-content: center; 5 | padding-top: 32px; 6 | background-color: #232629; 7 | 8 | .socials { 9 | display: flex; 10 | justify-content: space-between; 11 | width: 120px; 12 | 13 | .social-item { 14 | display: flex; 15 | flex-direction: column; 16 | align-items: center; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/components/organisms/LayoutWrapper/LayoutWrapper.component.jsx: -------------------------------------------------------------------------------- 1 | import React, {Fragment} from 'react'; 2 | 3 | import SideBar from './SideBar/SideBar.component'; 4 | import RightSideBar from './RightSideBar/RightSideBar.component'; 5 | import Footer from "../Footer/Footer.component"; 6 | 7 | const LayoutWrapper = ({ children }) => { 8 | return ( 9 | 10 |
11 | 12 |
13 | {children} 14 | 15 |
16 |
17 |