├── .devcontainer └── devcontainer.json ├── .eslintrc.json ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.md │ ├── developer_experience_issue.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── code-quality.yml │ └── storybook.yml ├── .gitignore ├── .npmrc ├── .storybook ├── main.js └── preview.js ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── cypress.config.ts ├── cypress ├── e2e │ ├── contactuspage.cy.ts │ └── homepage.cy.ts ├── fixtures │ └── example.json ├── support │ ├── commands.ts │ ├── component-index.html │ ├── component.ts │ └── e2e.ts ├── tsconfig.json └── util │ └── validateFooter.ts ├── declarations.d.ts ├── next-sitemap.config.js ├── next-types.d.ts ├── next.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── assets │ └── images │ │ └── hero-bg-image.jpg ├── chad-profile-social-card.jpg ├── favicon.ico ├── fonts │ ├── HirukoPro-Black.ttf │ ├── HirukoPro-BlackOblique.ttf │ ├── HirukoPro-Bold.ttf │ ├── HirukoPro-BoldOblique.ttf │ ├── HirukoPro-Book.ttf │ ├── HirukoPro-BookOblique.ttf │ ├── HirukoPro-ExtraLight.ttf │ ├── HirukoPro-ExtraLightOblique.ttf │ ├── HirukoPro-Light.ttf │ ├── HirukoPro-LightOblique.ttf │ ├── HirukoPro-Regular.ttf │ ├── HirukoPro-RegularOblique.ttf │ ├── HirukoProAlternate-Black.ttf │ ├── HirukoProAlternate-Bold.ttf │ ├── HirukoProAlternate-Book.ttf │ ├── HirukoProAlternate-ExtraLight.ttf │ ├── HirukoProAlternate-Light.ttf │ ├── HirukoProAlternate.ttf │ ├── HirukoProOutline-Regular.ttf │ ├── HirukoProOutline-RegularAlt.ttf │ └── HirukoProOutline-RegularOblique.ttf └── techishiring-social-card.png ├── src ├── components │ ├── atoms │ │ ├── button │ │ │ └── button.tsx │ │ ├── card │ │ │ └── card.tsx │ │ ├── icon │ │ │ └── icon.tsx │ │ ├── label │ │ │ └── label.tsx │ │ ├── link │ │ │ └── link.tsx │ │ ├── logo │ │ │ └── logo.tsx │ │ ├── nav-link │ │ │ └── nav-link.tsx │ │ ├── spinner │ │ │ └── spinner.tsx │ │ ├── text-input │ │ │ └── text-input.tsx │ │ ├── textbox │ │ │ └── textbox.tsx │ │ └── typography │ │ │ ├── default-text.tsx │ │ │ └── heading-text.tsx │ ├── molecules │ │ ├── about-banner │ │ │ └── about-banner.tsx │ │ ├── about-details │ │ │ └── about-details.tsx │ │ ├── about-header │ │ │ └── about-header.tsx │ │ ├── contact-form │ │ │ └── contact-form.tsx │ │ ├── contact-heading │ │ │ └── contact-heading.tsx │ │ ├── hero-section │ │ │ └── hero.tsx │ │ ├── highlights-details │ │ │ └── highlights-details.tsx │ │ ├── hire-chad-details │ │ │ └── hire-chad-details.tsx │ │ ├── main-nav │ │ │ └── main-nav.tsx │ │ └── why-choose │ │ │ └── why-choose-section.tsx │ ├── organisms │ │ ├── about-content │ │ │ └── about-content.tsx │ │ ├── contact-content │ │ │ └── contact-content.tsx │ │ ├── footer │ │ │ ├── footer.cy.tsx │ │ │ └── footer.tsx │ │ ├── header │ │ │ └── header.tsx │ │ ├── highlights-content │ │ │ └── highlights-content.tsx │ │ ├── hire-chad-content │ │ │ └── hire-chad-content.tsx │ │ ├── next-default-body │ │ │ └── next-default-body.tsx │ │ └── twitter-feed │ │ │ └── twitter-feed.tsx │ ├── particles │ │ └── head │ │ │ └── HeadContent.tsx │ └── templates │ │ └── layouts │ │ ├── default-layout.tsx │ │ └── example │ │ └── example.txt ├── images │ ├── Index.tsx │ ├── about-image1.png │ ├── about-image2.png │ ├── chad-profile-pic.jpg │ ├── contact-image-mobile.png │ ├── contact-image.png │ └── heroImage.svg ├── interfaces │ └── with-page-layouts.ts ├── lib │ ├── api │ │ ├── config │ │ │ ├── api.ts │ │ │ └── constants │ │ │ │ └── api-status.ts │ │ ├── example │ │ │ ├── example-api.txt │ │ │ ├── example-typing.txt │ │ │ ├── example-usage-next-js-specific.txt │ │ │ ├── example-usage.txt │ │ │ └── references.txt │ │ ├── external-apis │ │ │ └── .getkeep │ │ ├── hooks │ │ │ ├── useApi.ts │ │ │ └── useApiStatus.ts │ │ └── internal-apis │ │ │ └── send-grid │ │ │ └── index.ts │ ├── hooks │ │ └── use-nav.tsx │ └── utils │ │ ├── analytics.ts │ │ └── capitalize.ts ├── pages │ ├── _app.tsx │ ├── _document.tsx │ ├── about.tsx │ ├── api │ │ └── process-email.ts │ ├── contact.tsx │ ├── hire-chad.tsx │ └── index.tsx ├── stories │ ├── atoms │ │ ├── button.stories.tsx │ │ ├── card.stories.tsx │ │ ├── default-text.stories.tsx │ │ ├── heading-text.stories.tsx │ │ ├── icon.stories.tsx │ │ ├── label.stories.tsx │ │ ├── link.stories.tsx │ │ ├── logo.stories.tsx │ │ ├── nav-link.stories.tsx │ │ ├── spinner.stories.tsx │ │ ├── text-input.stories.tsx │ │ └── textbox.stories.tsx │ ├── molecules │ │ ├── about-banner.stories.tsx │ │ ├── about-details.stories.tsx │ │ ├── about-header.stories.tsx │ │ ├── contact-form.stories.tsx │ │ ├── contact-heading.stories.tsx │ │ ├── hero.stories.tsx │ │ ├── highlights-details.stories.tsx │ │ ├── hire-chad-details.stories.tsx │ │ ├── main-nav.stories.tsx │ │ └── why-choose-section.stories.tsx │ ├── organisms │ │ ├── about-content.stories.tsx │ │ ├── contact-content.stories.tsx │ │ ├── footer.stories.tsx │ │ ├── header.stories.tsx │ │ ├── highlight-content.stories.tsx │ │ ├── hire-chad-content.stories.tsx │ │ └── twitter-feed.stories.tsx │ ├── pages │ │ ├── about.stories.tsx │ │ ├── contact.stories.tsx │ │ └── home.stories.tsx │ ├── particles │ │ └── head-content.stories.tsx │ └── templates │ │ └── layouts │ │ └── default-layout.stories.tsx ├── styles │ └── globals.css └── tests │ └── capitalize.test.ts ├── tailwind.config.js ├── tsconfig.json └── vite.config.ts /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node 3 | { 4 | "name": "TechisHiring Website", 5 | "image": "mcr.microsoft.com/devcontainers/typescript-node:0-20", 6 | "hostRequirements": { 7 | "cpus": 4 8 | }, 9 | // install dependencies and start storybook 10 | "updateContentCommand": "npm install", 11 | "postAttachCommand": "npm run storybook", 12 | "customizations": { 13 | "codespaces": { 14 | "openFiles": [ 15 | "src/stories/pages/home.stories.tsx" 16 | ] 17 | }, 18 | // install some vscode extensions 19 | "vscode": { 20 | "extensions": [ 21 | "dbaeumer.vscode-eslint", 22 | "github.vscode-pull-request-github", 23 | "eamodio.gitlens", 24 | "christian-kohler.npm-intellisense" 25 | ] 26 | } 27 | }, 28 | // connect to remote server 29 | "forwardPorts": [6006], 30 | "portsAttributes": { 31 | "6006": { 32 | "label": "Storybook", 33 | "onAutoForward": "openPreview" 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals", 3 | "rules": { 4 | "camelcase": "warn" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "🐞 Bug Report" 3 | about: "I want to report a bug 😟..." 4 | title: "[BUG]: " 5 | labels: ["bug", "needs triage"] 6 | assignees: "chadstewart" 7 | --- 8 | 9 | 10 | 11 | ## Expected Behavior 12 | 13 | 14 | 15 | ## Current Behavior 16 | 17 | 18 | 19 | ## Possible Solution 20 | 21 | 22 | 23 | ## Steps to Reproduce 24 | 25 | 26 | 27 | 28 | 1. 29 | 2. 30 | 3. 31 | 4. 32 | 33 | ## Context (Environment) 34 | 35 | 36 | 37 | 38 | 39 | 40 | ## Detailed Description 41 | 42 | 43 | 44 | ## Possible Implementation 45 | 46 | 47 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/developer_experience_issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "🛠️ Developer Experience Issue" 3 | about: "I have a suggestion (and may want to implement it 🤔)!" 4 | title: "[Developer Experience]: " 5 | labels: ["developer experience", "needs triage"] 6 | assignees: "" 7 | --- 8 | 9 | ## Developer Experience Issue 10 | 11 | **Please describe your Developer Experience Issue.** 12 | A clear and concise description of what the problem is. Ex. I have an issue when [...] 13 | 14 | **Describe the solution you'd like** 15 | A clear and concise description of what you want to happen. Add any considered drawbacks. 16 | 17 | **Describe alternatives you've considered** 18 | A clear and concise description of any alternative solutions or features you've considered. 19 | 20 | **Teachability, Documentation, Adoption, Migration Strategy** 21 | If you can, explain how users will be able to use this and possibly write out a version in the docs. 22 | Maybe a screenshot or design? 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "🚀 Feature Request" 3 | about: "I have a suggestion (and may want to implement it 🙂)!" 4 | title: "[Feature]: " 5 | labels: ["enhancement"] 6 | assignees: "" 7 | --- 8 | 9 | ## Feature Request 10 | 11 | **Is your feature request related to a problem? Please describe.** 12 | A clear and concise description of what the problem is. Ex. I have an issue when [...] 13 | 14 | **Describe the solution you'd like** 15 | A clear and concise description of what you want to happen. Add any considered drawbacks. 16 | 17 | **Describe alternatives you've considered** 18 | A clear and concise description of any alternative solutions or features you've considered. 19 | 20 | **Teachability, Documentation, Adoption, Migration Strategy** 21 | If you can, explain how users will be able to use this and possibly write out a version in the docs. 22 | Maybe a screenshot or design? 23 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 6 | 7 | ## Related Issue 8 | 9 | 10 | 11 | 12 | 13 | 14 | Resolves: 15 | 16 | 17 | 18 | ## Motivation and Context 19 | 20 | 21 | 22 | 23 | ## How Has This Been Tested? 24 | 25 | 26 | 27 | 28 | 29 | ## Screenshots (if appropriate): 30 | -------------------------------------------------------------------------------- /.github/workflows/code-quality.yml: -------------------------------------------------------------------------------- 1 | name: Code Quality 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - dev 8 | pull_request: 9 | branches: 10 | - main 11 | - dev 12 | 13 | jobs: 14 | test: 15 | 16 | name: Run Unit Tests 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - uses: actions/checkout@v3 21 | - name: Use Node.js 22 | uses: actions/setup-node@v3 23 | with: 24 | node-version: 16 25 | - run: npm ci 26 | - run: npm run test --if-present 27 | 28 | 29 | lint: 30 | 31 | name: Run Linter 32 | runs-on: ubuntu-latest 33 | 34 | steps: 35 | - uses: actions/checkout@v3 36 | - name: Use Node.js 37 | uses: actions/setup-node@v3 38 | with: 39 | node-version: 16 40 | - run: npm ci 41 | - run: npm run format 42 | 43 | cypress-install: 44 | runs-on: ubuntu-latest 45 | container: cypress/browsers:node16.16.0-chrome107-ff107-edge 46 | steps: 47 | - name: Checkout 48 | uses: actions/checkout@v3 49 | 50 | - name: Cypress install 51 | uses: cypress-io/github-action@v5.8.3 52 | with: 53 | # Disable running of tests within install job 54 | runTests: false 55 | 56 | cypress-run-e2e: 57 | 58 | name: Run End-to-End Tests 59 | needs: cypress-install 60 | runs-on: ubuntu-latest 61 | container: cypress/browsers:node16.16.0-chrome107-ff107-edge 62 | strategy: 63 | # don't fail the entire matrix on failure 64 | fail-fast: false 65 | matrix: 66 | # run copies of the current job in parallel 67 | containers: [1, 2, 3] 68 | steps: 69 | - name: Checkout 70 | uses: actions/checkout@v3 71 | 72 | - name: Cypress run 73 | uses: cypress-io/github-action@v5.0.9 74 | with: 75 | # Specify Browser since container image is compile with Firefox 76 | browser: chrome 77 | start: npm run dev 78 | wait-on: 'http://localhost:3000' 79 | record: true 80 | parallel: true 81 | group: e2e 82 | env: 83 | CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} 84 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 85 | 86 | cypress-run-component: 87 | 88 | name: Run Component Tests 89 | needs: cypress-install 90 | runs-on: ubuntu-latest 91 | container: cypress/browsers:node16.16.0-chrome107-ff107-edge 92 | strategy: 93 | # don't fail the entire matrix on failure 94 | fail-fast: false 95 | matrix: 96 | # run copies of the current job in parallel 97 | containers: [1, 2, 3] 98 | steps: 99 | - name: Checkout 100 | uses: actions/checkout@v3 101 | 102 | - name: Cypress run 103 | uses: cypress-io/github-action@v5.0.9 104 | with: 105 | # Specify Browser since container image is compile with Firefox 106 | browser: chrome 107 | component: true 108 | record: true 109 | parallel: true 110 | group: component 111 | env: 112 | CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} 113 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 114 | -------------------------------------------------------------------------------- /.github/workflows/storybook.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy Storybook 2 | on: 3 | push: 4 | branches: 5 | - "dev" # Trigger the action only pushed to a specific branch 6 | - "!main" # Ignore if pushed to a specific branch 7 | jobs: 8 | build-and-deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 🛎️ 12 | uses: actions/checkout@v2.3.1 13 | 14 | - name: Merge dev -> storybook-deploy 🚀 15 | uses: devmasx/merge-branch@1.4.0 16 | with: 17 | type: now 18 | from_branch: dev 19 | target_branch: storybook-deploy 20 | github_token: ${{ github.token }} 21 | -------------------------------------------------------------------------------- /.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 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | storybook-static 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | .pnpm-debug.log* 28 | 29 | # local env files 30 | .env*.local 31 | 32 | # vercel 33 | .vercel 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | 39 | #SEO 40 | /public/robots.txt 41 | /public/sitemap* 42 | 43 | # VSCODE 44 | *.code-workspace 45 | .vscode 46 | 47 | # cypress 48 | cypress/videos 49 | cypress/screenshots -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | legacy-peer-deps=true 2 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: [ 3 | "../src/stories/**/*.stories.mdx", 4 | "../src/stories/**/*.stories.@(js|jsx|ts|tsx)" 5 | ], 6 | addons: [ 7 | "@storybook/addon-links", 8 | "@storybook/addon-essentials", 9 | "@storybook/addon-interactions", 10 | "@storybook/addon-postcss", 11 | "storybook-addon-next" 12 | ], 13 | framework: "@storybook/react", 14 | core: { 15 | builder: "@storybook/builder-webpack5" 16 | }, 17 | typescript: { reactDocgen: false } 18 | }; 19 | -------------------------------------------------------------------------------- /.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import "../src/styles/globals.css"; 2 | import { ChakraProvider } from "@chakra-ui/react"; 3 | 4 | export const decorators = [ 5 | (Story) => ( 6 | 7 | 8 | 9 | ), 10 | ]; 11 | 12 | export const parameters = { 13 | actions: { argTypesRegex: "^on[A-Z].*" }, 14 | controls: { 15 | matchers: { 16 | color: /(background|color)$/i, 17 | date: /Date$/ 18 | } 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct - TechIsHiring Website 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to make 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 a positive environment for our 15 | community include: 16 | 17 | - Demonstrating empathy and kindness toward other people 18 | - Being respectful of differing opinions, viewpoints, and experiences 19 | - Giving and gracefully accepting constructive feedback 20 | - Accepting responsibility and apologizing to those affected by our mistakes, 21 | and learning from the experience 22 | - Focusing on what is best not just for us as individuals, but for the 23 | overall community 24 | 25 | Examples of unacceptable behavior include: 26 | 27 | - The use of sexualized language or imagery, and sexual attention or 28 | advances 29 | - Trolling, insulting or derogatory comments, and personal or political attacks 30 | - Public or private harassment 31 | - Publishing others' private information, such as a physical or email 32 | address, without their explicit permission 33 | - Other conduct which could reasonably be considered inappropriate in a 34 | professional setting 35 | 36 | ## Our Responsibilities 37 | 38 | Project maintainers are responsible for clarifying and enforcing our standards of 39 | acceptable behavior and will take appropriate and fair corrective action in 40 | response to any instances of unacceptable behavior. 41 | 42 | Project maintainers have the right and responsibility to remove, edit, or reject 43 | comments, commits, code, wiki edits, issues, and other contributions that are 44 | not aligned to this Code of Conduct, or to ban 45 | temporarily or permanently any contributor for other behaviors that they deem 46 | inappropriate, threatening, offensive, or harmful. 47 | 48 | ## Scope 49 | 50 | This Code of Conduct applies within all community spaces, and also applies when 51 | an individual is officially representing the community in public spaces. 52 | Examples of representing our community include using an official e-mail address, 53 | posting via an official social media account, or acting as an appointed 54 | representative at an online or offline event. 55 | 56 | ## Enforcement 57 | 58 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 59 | reported to the community leaders responsible for enforcement at . 60 | All complaints will be reviewed and investigated promptly and fairly. 61 | 62 | All community leaders are obligated to respect the privacy and security of the 63 | reporter of any incident. 64 | 65 | ## Attribution 66 | 67 | This Code of Conduct is adapted from the [Contributor Covenant](https://contributor-covenant.org/), version 68 | [1.4](https://www.contributor-covenant.org/version/1/4/code-of-conduct/code_of_conduct.md) and 69 | [2.0](https://www.contributor-covenant.org/version/2/0/code_of_conduct/code_of_conduct.md), 70 | and was generated by [contributing-gen](https://github.com/bttger/contributing-gen). 71 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | !-- omit in toc --> 2 | 3 | # Contributing to the TechIsHiring Website 4 | 5 | Thank you so very much for taking the time to visit the TechIsHiring Website project! This project is a part of an ongoing effort to help make getting hired in Tech more accessible and easier. Any contribution to this project will contribute to that effort! ❤️ 6 | 7 | All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉 8 | 9 | > And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about: 10 | > 11 | > - Star the project 12 | > - Tweet about it 13 | > - Refer this project in your project's readme 14 | > - Mention the project at local meetups and tell your friends/colleagues 15 | 16 | 17 | 18 | ## Table of Contents 19 | 20 | - [Contributing to the TechIsHiring Website](#contributing-to-the-techishiring-website) 21 | - [Code of Conduct](#code-of-conduct) 22 | - [I Have a Question](#i-have-a-question) 23 | - [I Want To Contribute](#i-want-to-contribute) 24 | - [Reporting Bugs](#reporting-bugs) 25 | - [Suggesting Enhancements](#suggesting-enhancements) 26 | - [Your First Code Contribution](#your-first-code-contribution) 27 | 28 | ## Code of Conduct 29 | 30 | This project and everyone participating in it is governed by the 31 | [TechIsHiring Website Code of Conduct](https://github.com/TechIsHiring/techishiring-website/blob/dev/CODE_OF_CONDUCT.md). 32 | By participating, you are expected to uphold this code. Please report unacceptable behavior 33 | to . 34 | 35 | ## I Have a Question 36 | 37 | Before you ask a question, it is best to search for existing [Issues](https://github.com/techishiring/techishiring-website/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first. 38 | 39 | If you then still feel the need to ask a question and need clarification, we recommend the following: 40 | 41 | - Open an [Issue](https://github.com/techishiring/techishiring-website/issues/new). 42 | - Provide as much context as you can about what you're running into. 43 | - Provide project and platform versions (nodejs, npm, etc), depending on what seems relevant. 44 | 45 | We will then take care of the issue as soon as possible. 46 | 47 | 61 | 62 | ## I Want To Contribute 63 | 64 | > ### Legal Notice 65 | > 66 | > When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license. 67 | 68 | ### Reporting Bugs 69 | 70 | 71 | 72 | #### Before Submitting a Bug Report 73 | 74 | A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible. 75 | 76 | - Make sure that you are using the latest version. 77 | - Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions. If you are looking for support, you might want to check [this section](#i-have-a-question)). 78 | - To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/techishiring/techishiring-website/issues?q=label%3Abug). 79 | - Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue. 80 | - Collect information about the bug: 81 | - Stack trace (Traceback) 82 | - OS, Platform and Version (Windows, Linux, macOS, x86, ARM) 83 | - Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant. 84 | - Possibly your input and the output 85 | - Can you reliably reproduce the issue? And can you also reproduce it with older versions? 86 | 87 | 88 | 89 | #### How Do I Submit a Good Bug Report? 90 | 91 | > You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to . 92 | 93 | 94 | 95 | We use GitHub issues to track bugs and errors. If you run into an issue with the project: 96 | 97 | - Open an [Issue](https://github.com/techishiring/techishiring-website/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.) 98 | - Explain the behavior you would expect and the actual behavior. 99 | - Please provide as much context as possible and describe the _reproduction steps_ that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case. 100 | - Provide the information you collected in the previous section. 101 | 102 | Once it's filed: 103 | 104 | - The project team will label the issue accordingly. 105 | - A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as `needs-repro`. Bugs with the `needs-repro` tag will not be addressed until they are reproduced. 106 | - If the team is able to reproduce the issue, it will be marked `needs-fix`, as well as possibly other tags (such as `critical`), and the issue will be left to be [implemented by someone](#your-first-code-contribution). 107 | 108 | 109 | 110 | ### Suggesting Enhancements 111 | 112 | This section guides you through submitting an enhancement suggestion for the TechIsHiring Website, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions. 113 | 114 | 115 | 116 | #### Before Submitting an Enhancement 117 | 118 | - Make sure that you are using the latest version. 119 | - Perform a [search](https://github.com/techishiring/techishiring-website/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one. 120 | - Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library. 121 | 122 | 123 | 124 | #### How Do I Submit a Good Enhancement Suggestion? 125 | 126 | Enhancement suggestions are tracked as [GitHub issues](https://github.com/techishiring/techishiring-website/issues). 127 | 128 | - Use a **clear and descriptive title** for the issue to identify the suggestion. 129 | - Provide a **step-by-step description of the suggested enhancement** in as many details as possible. 130 | - **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you. 131 | - You may want to **include screenshots and animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to. You can use [this tool](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux. 132 | - **Explain why this enhancement would be useful** to most TechIsHiring users. You may also want to point out the other projects that solved it better and which could serve as inspiration. 133 | 134 | 135 | 136 | ### Your First Code Contribution 137 | 138 | 142 | 143 | If you're interested in making a contribution, [fork the TechIsHiring](https://docs.github.com/en/get-started/quickstart/fork-a-repo) and create a branch with a descriptive name. 144 | 145 | A good branch name would be (where issue #30 is the ticket you're working on): 146 | 147 | ```sh 148 | git checkout -b 325-implement-new-component 149 | ``` 150 | 151 | Add origin for upstream: 152 | 153 | ```sh 154 | git remote add upstream https://github.com/TechIsHiring/techishiring-website.git 155 | ``` 156 | 157 | Stage your Commit: 158 | 159 | ```sh 160 | git add . 161 | ``` 162 | Commit your Changes: 163 | 164 | ```sh 165 | git commit -m 'Feature: added an amazing feature' 166 | ``` 167 | 168 | Push to the Branch: 169 | 170 | ```sh 171 | git push origin 325-implement-new-component 172 | ``` 173 | 174 | Open a Pull Request 175 | 176 | ### alternatively, for existing contributors 177 | 178 | Fetch upstream: 179 | 180 | ```sh 181 | git fetch upstream 182 | ``` 183 | 184 | Merge upstream: 185 | 186 | ```sh 187 | git merge upstream/dev 188 | ``` 189 | 190 | **fix errors/ conflict (if any)**
191 | 192 | The project is structured in Atomic Design. If you need to familiarize yourself with Atomic Design, please check out the resources below: 193 | 194 | - [Atomic Design by Brad Frost](https://bradfrost.com/blog/post/atomic-web-design/) 195 | - [Atomic Design - How To Make Web and UI Design Easier](https://www.youtube.com/watch?v=W3A33dmp17E) 196 | 197 | We encourage that most component development take place in Storybook. This allows you to develop the component in isolation from the rest of the project and without needing to run the entire project to test your work. To familiarize yourself with Storybook, check out this tutorial on how to use Storybook: [Storybook Tutorial](https://www.youtube.com/watch?v=qSkHRVLcj6U) 198 | 199 | 208 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2022] [Chad Stewart] 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TechIsHiring Website 2 | 3 | TechIsHiring's website, focusing on showcasing the top tweets from the Twitter account and the TechIsHiring newsletter. 4 | 5 | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/TechIsHiring/techishiring-website) 6 | 7 | ## Technologies Used 8 | 9 | - Next.js 10 | - Tailwind CSS 11 | - Chakra UI 12 | - TypeScript 13 | - Zod 14 | - Storybook 15 | - SendGrid 16 | - Posthog 17 | 18 | ## Project Figma 19 | 20 | This is a link to the Figma File for the TechIsHiring Website: [TechIsHiring Website Figma](https://www.figma.com/file/AHf38Z5LQ4v1YBIgJv0tsM/TechIsHiring?t=ItybLH9XnPZ96T8A-6) 21 | 22 | ## Project Design Document 23 | 24 | This is a link to the Engineering Design Document for v1.0.0 release: [Engerineering Design Document](https://drive.google.com/file/d/15jYKdhq1NcL4rHJIvBxoLUuNlYRqOhMr/view?usp=sharing) 25 | 26 | ## Atomic Design 27 | 28 | This project uses Atomic Design for it's Components. Here are several resources for Atomic Design if you are unfamiliar: 29 | 30 | - [Atomic Design by Brad Frost](https://bradfrost.com/blog/post/atomic-web-design/) 31 | - [Atomic Design - How To Make Web and UI Design Easier](https://www.youtube.com/watch?v=W3A33dmp17E) 32 | 33 | ## Dev Environment 34 | 35 | Check out what the we're currently work on at [https://dev.techishiring.com](https://dev.techishiring.com) 36 | 37 | ## GitHub Codespaces Setup 38 | 39 | _A codespace is a development environment that's hosted in the cloud. You can build and run this plugin via a GitHub Codespace by following the directions below:_ 40 | 41 | 1. To open this environment, click the "Open in GitHub Codespaces" button at the top of this README or click on the green "Code" button on the repository > select the Codespaces tab > "Create new Codepsace on dev" button. 42 | 43 | 2. Allow this Codespace a few minutes to complete installing all needed dependencies. The first time you do this, it may take a while, so be patient. 44 | 45 | 3. Once the installation is complete, you should see a terminal window open in the bottom of the screen. You can click the link to open up the storybook in a new tab or your can go to the forward port tab to see the link to the storybook. 46 | 47 | A simple browser window will automatically open up for you so you can view the stories seamlessly. 48 | 49 | 4. You are now ready to start developing! 50 | 51 | ## Storybook 52 | 53 | The Stoybook for this project can be found at [https://stories.techishiring.com](https://stories.techishiring.com) 54 | 55 | ### Run it locally 56 | 57 | ```shell 58 | npm run storybook 59 | ``` 60 | 61 | ## Local development 62 | 63 | To install the application: 64 | 65 | ```shell 66 | npm ci 67 | ``` 68 | 69 | To run the application on a developement server: 70 | 71 | ```shell 72 | npm run dev 73 | ``` 74 | 75 | To reinstall your node_modules if a problem occurs with your dependencies: 76 | 77 | ```shell 78 | npm run reset-deps 79 | ``` 80 | 81 | ### Code linting 82 | 83 | To check the code and styles quality, use the following command: 84 | 85 | ```shell 86 | npm run lint 87 | ``` 88 | 89 | To fix the linting errors, use the following command: 90 | 91 | ```shell 92 | npm run format 93 | ``` 94 | 95 | ### Production deployment 96 | 97 | Run this command to build the project. 98 | 99 | ```shell 100 | npm run build 101 | ``` 102 | 103 | ## Contributing 104 | 105 | Check out the [CONTRIBUTING.md](CONTRIBUTING.md) guide to assist with all you need to know before getting started with making changes to the codebase. 106 | 107 | ## License 108 | 109 | [MIT License](LICENSE) 110 | -------------------------------------------------------------------------------- /cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "cypress"; 2 | 3 | export default defineConfig({ 4 | projectId: "1nng13", 5 | e2e: { 6 | baseUrl: 'http://localhost:3000', 7 | setupNodeEvents(on, config) { 8 | // implement node event listeners here 9 | }, 10 | }, 11 | 12 | component: { 13 | devServer: { 14 | framework: "next", 15 | bundler: "webpack", 16 | }, 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /cypress/e2e/contactuspage.cy.ts: -------------------------------------------------------------------------------- 1 | 2 | describe("Contact Us Image Rendering", () => { 3 | beforeEach(() => { 4 | cy.visit("/contact", { timeout: 30000 }); 5 | }); 6 | 7 | it("Image rendering on desktop", () =>{ 8 | cy.viewport('macbook-11') 9 | cy.get('[data-testid="desktop"] > img') 10 | .should('be.visible') 11 | .and('have.prop', 'naturalWidth') 12 | .should('be.greaterThan', 0) 13 | }) 14 | 15 | it("Background Image rendering on mobile", () =>{ 16 | cy.viewport('iphone-5') 17 | cy.get('[data-testid="mobile"] > img') 18 | .should("be.visible") 19 | .and('have.prop', 'naturalWidth') 20 | .should('be.greaterThan', 0) 21 | }) 22 | }) -------------------------------------------------------------------------------- /cypress/e2e/homepage.cy.ts: -------------------------------------------------------------------------------- 1 | import validateFooter from "../util/validateFooter"; 2 | 3 | describe("Homepage", () => { 4 | beforeEach(() => { 5 | cy.visit("/", { timeout: 30000 }); 6 | }); 7 | 8 | it("should display the homepage", () => { 9 | cy.title().should("include", "TechIsHiring"); 10 | cy.get("header").should("be.visible"); 11 | cy.get('.sticky > :nth-child(1) > a > .chakra-heading').contains('TechIsHiring'); 12 | cy.get('header > div > nav > ul').should('be.visible'); 13 | 14 | validateFooter('desktop') 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /cypress/support/commands.ts: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************** 3 | // This example commands.ts shows you how to 4 | // create various custom commands and overwrite 5 | // existing commands. 6 | // 7 | // For more comprehensive examples of custom 8 | // commands please read more here: 9 | // https://on.cypress.io/custom-commands 10 | // *********************************************** 11 | // 12 | // 13 | // -- This is a parent command -- 14 | // Cypress.Commands.add('login', (email, password) => { ... }) 15 | // 16 | // 17 | // -- This is a child command -- 18 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) 19 | // 20 | // 21 | // -- This is a dual command -- 22 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) 23 | // 24 | // 25 | // -- This will overwrite an existing command -- 26 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) 27 | // 28 | // declare global { 29 | // namespace Cypress { 30 | // interface Chainable { 31 | // login(email: string, password: string): Chainable 32 | // drag(subject: string, options?: Partial): Chainable 33 | // dismiss(subject: string, options?: Partial): Chainable 34 | // visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable 35 | // } 36 | // } 37 | // } 38 | export {}; 39 | 40 | declare global { 41 | namespace Cypress { 42 | interface Chainable { 43 | validateLink(name: string, destination : string, target?: 'new tab'): Chainable 44 | } 45 | } 46 | } 47 | 48 | 49 | /** 50 | * 51 | * @param name - the name of the link 52 | * @param destination - the URL the link navigates to 53 | * @param target - target attribute - e.g. "new tab" or not 54 | */ 55 | const validateLink = (name: string, destination : string, target?: 'new tab') => { 56 | const shouldOpenInNewTab = target === 'new tab' 57 | const targetAssertion = shouldOpenInNewTab ? 'have.attr' : 'not.have.attr' 58 | 59 | // find a link with the expected name 60 | cy.contains(`a`, name) 61 | .should('be.visible') // make sure it is visible 62 | .and('have.attr', 'href', destination) // and has the right href 63 | .and(targetAssertion, 'target', '_blank') // and opens in a new tab, or not 64 | } 65 | 66 | Cypress.Commands.add('validateLink', validateLink) -------------------------------------------------------------------------------- /cypress/support/component-index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Components App 8 | 9 |
10 | 11 | 12 |
13 | 14 | -------------------------------------------------------------------------------- /cypress/support/component.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/component.ts is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | import { ChakraProvider } from "@chakra-ui/react"; 19 | import { createElement } from "react"; 20 | import theme from "../../src/styles/globals.css"; 21 | 22 | // Alternatively you can use CommonJS syntax: 23 | // require('./commands') 24 | 25 | import { mount } from 'cypress/react18' 26 | 27 | // Augment the Cypress namespace to include type definitions for 28 | // your custom command. 29 | // Alternatively, can be defined in cypress/support/component.d.ts 30 | // with a at the top of your spec. 31 | declare global { 32 | namespace Cypress { 33 | interface Chainable { 34 | mount: typeof mount 35 | } 36 | } 37 | } 38 | 39 | 40 | Cypress.Commands.add("mount", (component, options) => { 41 | const wrappedComponent = createElement(ChakraProvider, {theme}, component); 42 | 43 | return mount(wrappedComponent, options); 44 | }); 45 | -------------------------------------------------------------------------------- /cypress/support/e2e.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/e2e.ts is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import "./commands"; 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es5", "dom"], 5 | "types": ["cypress", "node"] 6 | }, 7 | "include": ["**/*.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /cypress/util/validateFooter.ts: -------------------------------------------------------------------------------- 1 | type Size = 'mobile' | 'desktop' 2 | 3 | const validateFooter = (size: Size) => { 4 | 5 | cy.log('-----START FOOTER-----') 6 | // since both mobile and desktop versions are in the DOM as the same time, we scope with [data-cy] 7 | cy.get(`[data-cy=${size}-footer]`).within(() => { 8 | cy.validateLink('Home', '/') 9 | cy.validateLink('TechIsHiring', '/') 10 | cy.validateLink('Newsletter', 'https://newsletter.techishiring.com/', 'new tab') 11 | cy.validateLink('About', '/about') 12 | cy.validateLink('Contact Us', '/contact') 13 | 14 | // now test the SVG icon links at the bottom 15 | cy.validateLink('Twitter for Tech Is Hiring', 'https://www.twitter.com/techishiring', 'new tab') 16 | cy.validateLink('GitHub for Tech Is Hiring', 'https://www.github.com/techishiring', 'new tab') 17 | cy.validateLink('LinkedIn for Tech Is Hiring', 'https://www.linkedin.com/company/techishiring', 'new tab') 18 | cy.validateLink('Patreon for Tech Is Hiring', 'https://www.patreon.com/techishiring', 'new tab') 19 | cy.validateLink('Tech Is Hiring Newsletter on Substack', 'https://newsletter.techishiring.com/', 'new tab') 20 | 21 | cy.contains(`p`, `© Copyright ${new Date().getFullYear()}, All rights reserved.`).should('be.visible') 22 | cy.contains(`p`, `Website designed by Inetimi Ade (aidinetimi@gmail.com)`).should('be.visible') 23 | }) 24 | // test the main navigation links for the site 25 | cy.log('-----END FOOTER-----') 26 | } 27 | 28 | export default validateFooter -------------------------------------------------------------------------------- /declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.css'; // needed for Cypress component tests to import CSS files -------------------------------------------------------------------------------- /next-sitemap.config.js: -------------------------------------------------------------------------------- 1 | const siteUrl = "https://www.techishiring.com"; 2 | 3 | module.exports = { 4 | siteUrl, 5 | generateRobotsTxt: true 6 | }; 7 | -------------------------------------------------------------------------------- /next-types.d.ts: -------------------------------------------------------------------------------- 1 | // Base Project Types 2 | 3 | interface Link { 4 | externalLink?: boolean; 5 | externalLinkAlt?: string; 6 | } 7 | 8 | interface NavLink extends Link { 9 | url: string; 10 | text: string; 11 | activeLink?: boolean; 12 | button?: boolean; 13 | footer?: boolean; 14 | } 15 | 16 | // API Return Types 17 | 18 | /* 19 | 20 | Example: 21 | 22 | readonly interface Countries { 23 | name: string; 24 | topLeveDomain: string[]; 25 | alpha2Code: string; 26 | ...etc 27 | } 28 | 29 | */ 30 | 31 | readonly interface Email { 32 | email: string; 33 | name: string; 34 | message: string; 35 | } -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | module.exports = { 3 | reactStrictMode: true 4 | 5 | }; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "next dev", 5 | "build": "next build", 6 | "start": "next start", 7 | "storybook": "start-storybook -p 6006", 8 | "build-storybook": "build-storybook", 9 | "lint": "next lint", 10 | "format": "next lint -- --fix --dir .", 11 | "test": "vitest", 12 | "cypress:open:e2e": "npx cypress open --e2e", 13 | "cypress:open:component": "npx cypress open --component", 14 | "cypress:run:e2e": "npx cypress run", 15 | "cypress:run:component": "npx cypress run --component", 16 | "reset-deps": "rm -rf node_modules && npm ci", 17 | "postbuild": "next-sitemap", 18 | "check-ts": "tsc --noEmit" 19 | }, 20 | "dependencies": { 21 | "@chakra-ui/react": "^2.3.6", 22 | "@emotion/react": "^11.10.4", 23 | "@emotion/styled": "^11.10.4", 24 | "@sendgrid/mail": "^7.7.0", 25 | "framer-motion": "^6.5.1", 26 | "next": "^13.2.4", 27 | "next-sitemap": "^3.1.29", 28 | "posthog-js": "^1.33.0", 29 | "react": "^18.2.0", 30 | "react-dom": "^18.2.0", 31 | "react-icons": "^4.6.0", 32 | "react-twitter-embed": "^4.0.4", 33 | "sharp": "^0.32.0", 34 | "storybook-addon-next": "^1.8.0", 35 | "zod": "^3.21.4" 36 | }, 37 | "devDependencies": { 38 | "@babel/core": "^7.19.3", 39 | "@storybook/addon-actions": "^6.5.16", 40 | "@storybook/addon-essentials": "^6.5.16", 41 | "@storybook/addon-interactions": "^6.5.16", 42 | "@storybook/addon-links": "^6.5.16", 43 | "@storybook/addon-postcss": "^2.0.0", 44 | "@storybook/builder-webpack5": "^6.5.16", 45 | "@storybook/manager-webpack5": "^6.5.16", 46 | "@storybook/react": "^6.5.16", 47 | "@storybook/testing-library": "^0.0.13", 48 | "@testing-library/react": "^13.4.0", 49 | "@types/node": "17.0.35", 50 | "@types/react": "18.0.9", 51 | "@types/react-dom": "18.0.5", 52 | "@vitejs/plugin-react": "^3.1.0", 53 | "autoprefixer": "^10.4.7", 54 | "babel-loader": "^8.2.5", 55 | "cypress": "^12.17.1", 56 | "eslint": "8.26.0", 57 | "eslint-config-next": "^13.2.4", 58 | "eslint-plugin-storybook": "^0.6.11", 59 | "jsdom": "^21.1.0", 60 | "postcss": "^8.4.14", 61 | "prettier": "^2.8.4", 62 | "prettier-plugin-tailwindcss": "^0.2.2", 63 | "tailwindcss": "^3.1.2", 64 | "typescript": "^5.0.3", 65 | "vitest": "^0.28.4" 66 | }, 67 | "prettier": { 68 | "singleQuote": false, 69 | "tabWidth": 2, 70 | "trailingComma": "none", 71 | "arrowParens": "always", 72 | "bracketSpacing": true 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {} 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /public/assets/images/hero-bg-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/assets/images/hero-bg-image.jpg -------------------------------------------------------------------------------- /public/chad-profile-social-card.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/chad-profile-social-card.jpg -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/favicon.ico -------------------------------------------------------------------------------- /public/fonts/HirukoPro-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoPro-Black.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoPro-BlackOblique.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoPro-BlackOblique.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoPro-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoPro-Bold.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoPro-BoldOblique.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoPro-BoldOblique.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoPro-Book.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoPro-Book.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoPro-BookOblique.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoPro-BookOblique.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoPro-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoPro-ExtraLight.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoPro-ExtraLightOblique.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoPro-ExtraLightOblique.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoPro-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoPro-Light.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoPro-LightOblique.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoPro-LightOblique.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoPro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoPro-Regular.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoPro-RegularOblique.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoPro-RegularOblique.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoProAlternate-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoProAlternate-Black.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoProAlternate-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoProAlternate-Bold.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoProAlternate-Book.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoProAlternate-Book.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoProAlternate-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoProAlternate-ExtraLight.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoProAlternate-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoProAlternate-Light.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoProAlternate.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoProAlternate.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoProOutline-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoProOutline-Regular.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoProOutline-RegularAlt.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoProOutline-RegularAlt.ttf -------------------------------------------------------------------------------- /public/fonts/HirukoProOutline-RegularOblique.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/fonts/HirukoProOutline-RegularOblique.ttf -------------------------------------------------------------------------------- /public/techishiring-social-card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TechIsHiring/techishiring-website/287ad148bb84afeb78ae45a71b15552acc30228e/public/techishiring-social-card.png -------------------------------------------------------------------------------- /src/components/atoms/button/button.tsx: -------------------------------------------------------------------------------- 1 | import { Button as ChakraButtonComponent } from "@chakra-ui/react"; 2 | 3 | interface ButtonProps 4 | extends React.ComponentProps { 5 | //Add additional prop definitions here 6 | } 7 | 8 | const DefaultButton = (props: ButtonProps) => { 9 | return ( 10 | {props.children} 11 | ); 12 | }; 13 | 14 | export default DefaultButton; 15 | -------------------------------------------------------------------------------- /src/components/atoms/card/card.tsx: -------------------------------------------------------------------------------- 1 | interface CardCommonProps { 2 | children: JSX.Element; 3 | className?: string; 4 | } 5 | 6 | interface IsSection extends CardCommonProps { 7 | section: boolean; 8 | article?: never; 9 | } 10 | 11 | interface IsArticle extends CardCommonProps { 12 | article: boolean; 13 | section?: never; 14 | } 15 | 16 | interface NeitherArticleOrSection extends CardCommonProps { 17 | article?: never; 18 | section?: never; 19 | } 20 | 21 | type CardProps = IsArticle | IsSection | NeitherArticleOrSection; 22 | 23 | const Card = ({ children, className, section, article }: CardProps) => { 24 | const cardClassDefinition = `${ 25 | className ? className : "" 26 | } w-full p-8 shadow-md rounded-lg`; 27 | 28 | return ( 29 | <> 30 | {section &&
{children}
} 31 | {article &&
{children}
} 32 | {!article && !section && ( 33 |
{children}
34 | )} 35 | 36 | ); 37 | }; 38 | 39 | export default Card; 40 | -------------------------------------------------------------------------------- /src/components/atoms/icon/icon.tsx: -------------------------------------------------------------------------------- 1 | import { IconType } from "react-icons"; 2 | 3 | interface IconProps { 4 | Icon: IconType; 5 | iconAlt: string; 6 | size?: number; 7 | color?: string; 8 | } 9 | 10 | const Icon = ({ Icon, iconAlt, size = 24, color = "#000" }: IconProps) => { 11 | return ; 12 | }; 13 | 14 | export default Icon; 15 | -------------------------------------------------------------------------------- /src/components/atoms/label/label.tsx: -------------------------------------------------------------------------------- 1 | 2 | const Label = ({children}: any) => { 3 | return ( 4 | 5 | ); 6 | }; 7 | 8 | export default Label; -------------------------------------------------------------------------------- /src/components/atoms/link/link.tsx: -------------------------------------------------------------------------------- 1 | import NextLink from "next/link"; 2 | 3 | interface NextLinkProps 4 | extends React.ComponentProps { 5 | //Add additional prop definitions here 6 | } 7 | 8 | interface LinkProps extends Link, NextLinkProps { 9 | children: JSX.Element; 10 | } 11 | 12 | const Link = (props: LinkProps) => { 13 | return ( 14 | 19 | {props.children} 20 | 21 | ); 22 | }; 23 | 24 | export default Link; 25 | -------------------------------------------------------------------------------- /src/components/atoms/logo/logo.tsx: -------------------------------------------------------------------------------- 1 | import Link from "components/atoms/link/link"; 2 | import { Heading } from "@chakra-ui/react"; 3 | 4 | const Logo = () => { 5 | return ( 6 | 7 | 8 | TechIsHiring 9 | 10 | 11 | ); 12 | }; 13 | 14 | export default Logo; 15 | -------------------------------------------------------------------------------- /src/components/atoms/nav-link/nav-link.tsx: -------------------------------------------------------------------------------- 1 | import DefaultText from "../typography/default-text"; 2 | import DefaultButton from "components/atoms/button/button"; 3 | import Link from "components/atoms/link/link"; 4 | type NavLinkProps = NavLink; 5 | 6 | const NavLink = ({ url, text, activeLink, button, externalLink, footer = false }: NavLinkProps) => { 7 | return ( 8 | 15 | {footer === false && button === true ? 16 | 22 | 23 | {text} 24 | 25 | 26 | : 27 | 31 | {text} 32 | 33 | } 34 | 35 | ); 36 | }; 37 | 38 | export default NavLink; 39 | -------------------------------------------------------------------------------- /src/components/atoms/spinner/spinner.tsx: -------------------------------------------------------------------------------- 1 | import { Spinner as ChakraSpinnerComponent } from "@chakra-ui/react"; 2 | import React from "react"; 3 | 4 | interface SpinnerProps extends React.ComponentProps { 5 | //Add additional prop definitions here 6 | } 7 | 8 | const Spinner = (props: SpinnerProps) => { 9 | return ( 10 | 18 | ); 19 | }; 20 | 21 | export default Spinner; 22 | -------------------------------------------------------------------------------- /src/components/atoms/text-input/text-input.tsx: -------------------------------------------------------------------------------- 1 | import { Input as ChakraInputComponent } from "@chakra-ui/react"; 2 | import React from "react"; 3 | 4 | interface InputProps extends React.ComponentProps { 5 | //Add additional prop definitions here 6 | } 7 | 8 | const TextInput = (props: InputProps) => { 9 | return ( 10 | 17 | ); 18 | }; 19 | 20 | export default TextInput; 21 | -------------------------------------------------------------------------------- /src/components/atoms/textbox/textbox.tsx: -------------------------------------------------------------------------------- 1 | import { Textarea as ChakraTextboxComponent } from "@chakra-ui/react"; 2 | import React from "react"; 3 | 4 | interface TextboxProps extends React.ComponentProps { 5 | //Add additional prop definitions here 6 | } 7 | 8 | type Textbox = TextboxProps; 9 | 10 | const TextBox = (props: Textbox) => { 11 | return ( 12 | 19 | ); 20 | }; 21 | 22 | export default TextBox; -------------------------------------------------------------------------------- /src/components/atoms/typography/default-text.tsx: -------------------------------------------------------------------------------- 1 | import { Text as ChakraTextComponent } from "@chakra-ui/react"; 2 | 3 | interface DefaultTextProps 4 | extends React.ComponentProps { 5 | //Add additional prop definitions here 6 | } 7 | 8 | const DefaultText = (props: DefaultTextProps) => { 9 | return {props.children}; 10 | }; 11 | 12 | export default DefaultText; 13 | -------------------------------------------------------------------------------- /src/components/atoms/typography/heading-text.tsx: -------------------------------------------------------------------------------- 1 | import { Heading as ChakraHeaderTextComponent } from "@chakra-ui/react"; 2 | 3 | interface HeaderTextProps 4 | extends React.ComponentProps { 5 | //Add additional prop definitions here 6 | level: "h1" | "h2" | "h3" | "h4" | "h5" | "h6"; 7 | } 8 | 9 | const HeaderText = (props: HeaderTextProps) => { 10 | return ( 11 | 12 | {props.children} 13 | 14 | ); 15 | }; 16 | 17 | export default HeaderText; 18 | -------------------------------------------------------------------------------- /src/components/molecules/about-banner/about-banner.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import DefaultText from "components/atoms/typography/default-text"; 3 | import HeaderText from "components/atoms/typography/heading-text"; 4 | import DefaultButton from "components/atoms/button/button"; 5 | import Link from 'components/atoms/link/link'; 6 | import Icon from "components/atoms/icon/icon"; 7 | import { 8 | SiTwitter, 9 | SiLinkedin, 10 | SiYoutube 11 | } from "react-icons/si"; 12 | 13 | export default function AboutBanner() { 14 | return ( 15 |
16 |
17 |
18 | Have a question? 19 | If you have any questions, please contact us 20 |
21 |
22 | 36 | Contact Us 37 | 38 | 39 |
40 |
41 |
42 | Follow us on Social Media: 43 |
44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 |
54 |
55 |
56 | ) 57 | } 58 | -------------------------------------------------------------------------------- /src/components/molecules/about-details/about-details.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import DefaultText from "components/atoms/typography/default-text"; 3 | import Link from "components/atoms/link/link"; 4 | import Icon from "components/atoms/icon/icon"; 5 | import { 6 | SiTwitter, 7 | SiLinkedin, 8 | SiYoutube 9 | } from "react-icons/si"; 10 | 11 | export default function AboutDetails() { 12 | return ( 13 |
14 | 15 | TechIsHiring tries to assist tech professionals in finding employment 16 | by encouraging meaningful interactions between people looking for employment 17 | and those who can assist, rather than focusing primarily on advertising job openings. 18 | 19 | 20 | During the pandemic, 21 | 22 | Chad R. Stewart 23 | 24 | , the Founder of TechIsHiring, noticed that many 25 | people were tweeting about job openings they had discovered and advertising possibilities 26 | that they had come across, which is how TechIsHiring came to be. Since there was no one place 27 | where these tweets could be collected, the hashtag 28 | 30 | #TechIsHiring 31 | and the TechIsHiring account were created. 32 | 33 | 34 | Looking to work with the Founder directly? 35 | 36 | Hire Chad R. Stewart 37 | 38 | . 39 | 40 |
41 | Follow us 42 |
43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
53 |
54 | 55 | 56 | 57 |
58 | ) 59 | } 60 | -------------------------------------------------------------------------------- /src/components/molecules/about-header/about-header.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import HeaderText from "components/atoms/typography/heading-text"; 3 | import { aboutImage } from "images/Index"; 4 | 5 | export default function AboutHeader() { 6 | 7 | return ( 8 |
12 |
13 | 14 | 15 | Transnational Job Listing Channel 16 | 17 | 18 |
19 |

20 | So many jobs available, all you have to do is keep up with our posts. Check below for recent job openings. 21 |

22 |
23 | 24 |
25 |
26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /src/components/molecules/contact-form/contact-form.tsx: -------------------------------------------------------------------------------- 1 | import { Box, VStack } from "@chakra-ui/react"; 2 | import Label from "components/atoms/label/label"; 3 | import TextInput from "components/atoms/text-input/text-input"; 4 | import TextBox from "components/atoms/textbox/textbox"; 5 | import DefaultButton from "components/atoms/button/button"; 6 | import DefaultText from "components/atoms/typography/default-text"; 7 | import Spinner from "components/atoms/spinner/spinner"; 8 | import ContactHeading from "components/molecules/contact-heading/contact-heading"; 9 | import { useState } from "react"; 10 | import React from "react"; 11 | import { sendEmail } from "lib/api/internal-apis/send-grid"; 12 | import useApi from "lib/api/hooks/useApi"; 13 | import { ZodString, string as zodStringCheck } from "zod"; 14 | import HeaderText from "components/atoms/typography/heading-text"; 15 | 16 | const ContactForm = () => { 17 | const[ email, setEmail ] = useState(""); 18 | const[ name, setName ] = useState(""); 19 | const[ message, setMessage ] = useState(""); 20 | 21 | const [ error, setError ] = useState({ 22 | email: false, 23 | name: false, 24 | message: false 25 | }); 26 | 27 | const { executeApiCall: handleEmail , statuses } = useApi(sendEmail); 28 | 29 | const verifyInput = () => { 30 | let badInput = false; 31 | 32 | setError(prevState => { 33 | return { 34 | ...prevState, 35 | email: false, 36 | name: false, 37 | message: false 38 | } 39 | }); 40 | 41 | const zodCheck = (zodVariable: ZodString, stringToTest: string) => { 42 | try { 43 | return zodVariable.parse(stringToTest); 44 | } catch { 45 | return false; 46 | } 47 | }; 48 | 49 | const wrongEmail = !zodCheck(zodStringCheck().nonempty().email(), email); 50 | const noName = !zodCheck(zodStringCheck().nonempty(), name); 51 | const noMessage = !zodCheck(zodStringCheck().nonempty(), message); 52 | 53 | if ( noName ) { 54 | badInput = true; 55 | 56 | setError(prevState => { 57 | 58 | return { 59 | ...prevState, 60 | name: true 61 | }; 62 | }); 63 | }; 64 | 65 | if ( wrongEmail ) { 66 | badInput = true; 67 | 68 | setError(prevState => { 69 | 70 | return { 71 | ...prevState, 72 | email: true 73 | }; 74 | }); 75 | }; 76 | 77 | if ( noMessage ) { 78 | badInput = true; 79 | 80 | setError(prevState => { 81 | 82 | return { 83 | ...prevState, 84 | message: true 85 | }; 86 | }) 87 | }; 88 | 89 | return badInput; 90 | }; 91 | 92 | const handleClick = async () => { 93 | const badInput = verifyInput(); 94 | if( badInput ) return; 95 | 96 | try { 97 | await handleEmail({ 98 | email, 99 | name, 100 | message 101 | }); 102 | } catch ( error ) { 103 | //console.log(error); 104 | } 105 | }; 106 | 107 | return ( 108 | 109 | {statuses.isIdle && 110 | <> 111 | 112 |
113 | 114 | 117 | setName(e.target.value)} 124 | /> 125 | {error.name && Please add a name} 126 | 127 | 128 | 129 | 132 | setEmail(e.target.value)} 139 | /> 140 | {error.email && Please add a proper email address} 141 | 142 | 143 | 144 | 147 | setMessage(e.target.value)} 154 | /> 155 | {error.message && Please add a message} 156 | 157 | 158 |
159 | 170 | Send message 171 | 172 |
173 |
174 | 175 | } 176 | 177 | {statuses.isPending && 178 | 179 | 180 | 181 | } 182 | 183 | {statuses.isSuccess && 184 | 185 | 186 | Thank you for your feedback! 187 | 188 | 189 | We will get back to you as soon as possible! 190 | 191 | 192 | } 193 | 194 | {statuses.isError && 195 | 196 | 197 | Sorry, we were not able to send your email! 198 | 199 | 200 | Please try again later. 201 | 202 | 203 | } 204 |
205 | ); 206 | }; 207 | 208 | export default ContactForm; -------------------------------------------------------------------------------- /src/components/molecules/contact-heading/contact-heading.tsx: -------------------------------------------------------------------------------- 1 | import { Box, VStack } from "@chakra-ui/react"; 2 | import HeaderText from "components/atoms/typography/heading-text"; 3 | import DefaultText from "components/atoms/typography/default-text"; 4 | import Link from "components/atoms/link/link"; 5 | import React from "react"; 6 | 7 | const ContactHeading = () => { 8 | return ( 9 | 10 | 11 | 12 | Contact Us 13 | 14 | 15 | You can reach us anytime via 16 |
17 | 21 | <>techishiring@gmail.com 22 | 23 | 24 | 25 |
26 |
27 |
28 | ); 29 | }; 30 | 31 | export default ContactHeading; -------------------------------------------------------------------------------- /src/components/molecules/hero-section/hero.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | import React from "react"; 3 | import { HeroImage } from "../../../images/Index"; 4 | 5 | import Icon from "components/atoms/icon/icon"; 6 | import { AiOutlineSearch } from "react-icons/ai"; 7 | 8 | const Hero = () => { 9 | return ( 10 |
11 |
12 |
13 |
14 |

15 | Where great Jobs and great{" "} 16 | Engineers come to find one 17 | another! 18 |

19 |

20 | So many jobs available, all you have to do is keep up with our 21 | posts. Check below for recent job openings. 22 |

23 | 24 | {/* Commented out based on whether we commit to continuing to use the Twitter API 25 | 26 |
27 |
28 | 29 | 30 | 35 |
36 |
37 | 40 |
41 |
*/} 42 | 43 |
44 |
45 | Hero Image 46 |
47 |
48 |
49 |
50 | ); 51 | }; 52 | 53 | export default Hero; 54 | -------------------------------------------------------------------------------- /src/components/molecules/highlights-details/highlights-details.tsx: -------------------------------------------------------------------------------- 1 | import Spinner from "components/atoms/spinner/spinner"; 2 | import { TwitterTweetEmbed } from "react-twitter-embed"; 3 | 4 | const HighlightsDetails = () => { 5 | return ( 6 |
7 | } 10 | /> 11 | } 14 | /> 15 | } 18 | /> 19 |
20 | ) 21 | }; 22 | 23 | export default HighlightsDetails; -------------------------------------------------------------------------------- /src/components/molecules/hire-chad-details/hire-chad-details.tsx: -------------------------------------------------------------------------------- 1 | import { Box, VStack } from "@chakra-ui/react"; 2 | import HeaderText from "components/atoms/typography/heading-text"; 3 | import DefaultText from "components/atoms/typography/default-text"; 4 | import Link from "components/atoms/link/link"; 5 | import Icon from "components/atoms/icon/icon"; 6 | import { 7 | SiTwitter, 8 | SiLinkedin, 9 | SiGithub, 10 | SiDevdotto 11 | } from "react-icons/si"; 12 | 13 | const HireChadDetails = () => { 14 | return ( 15 | 16 | 17 | 18 | Hire Chad R. Stewart 19 | 20 | 21 | Chad R. Stewart is a Full Stack Software Engineer with a Front-End Engineering 22 | focused skill set. He has worked on several software projects and lead teams 23 | in the FinTech and Developer Tools space. He has also spoken on several podcasts 24 | and events, more recently on Open Source Friday, run by GitHub, to talk about 25 | TechIsHiring and hiring. 26 | 27 | 28 | 29 | Check out my resume 30 | 31 | 32 |
33 | Check out my links 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 |
48 |
49 |
50 |
51 | ); 52 | }; 53 | 54 | export default HireChadDetails; -------------------------------------------------------------------------------- /src/components/molecules/main-nav/main-nav.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Drawer, 3 | DrawerBody, 4 | DrawerHeader, 5 | DrawerOverlay, 6 | DrawerContent, 7 | DrawerCloseButton, 8 | useDisclosure 9 | } from "@chakra-ui/react"; 10 | import { Fragment } from "react"; 11 | import NavLink from "components/atoms/nav-link/nav-link"; 12 | import Icon from "components/atoms/icon/icon"; 13 | import { FiMenu, FiExternalLink } from "react-icons/fi"; 14 | import { useRouter } from "next/router"; 15 | 16 | interface MainNavProps { 17 | navList: NavLink[]; 18 | } 19 | 20 | const MainNav = ({ navList }: MainNavProps) => { 21 | const { isOpen, onOpen, onClose } = useDisclosure(); 22 | const router = useRouter(); 23 | 24 | return ( 25 | 85 | ); 86 | }; 87 | 88 | export default MainNav; 89 | -------------------------------------------------------------------------------- /src/components/molecules/why-choose/why-choose-section.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import DefaultText from "components/atoms/typography/default-text"; 3 | import { SiTwitter } from "react-icons/si"; 4 | import { TbRefresh } from "react-icons/tb"; 5 | import { BsFillKeyFill } from "react-icons/bs"; 6 | import Icon from "components/atoms/icon/icon"; 7 | import HeaderText from "components/atoms/typography/heading-text"; 8 | 9 | const WhyChooseSection = () => { 10 | return ( 11 |
12 |
13 |
14 | 15 | Why Choose TechIsHiring ? 16 | 17 |
18 |
19 |
20 |
21 | 27 |
28 |
29 | 30 | Sources from Twitter 31 | 32 |
33 |
34 | 35 | Curates job openings and links from twitter posts.Curates job 36 | openings and links from twitter posts. 37 | 38 |
39 |
40 |
41 |
42 | 48 |
49 |
50 | 51 | Up to date 52 | 53 |
54 |
55 | 56 | Shares the latest job postings and daily job vacancies.Shares 57 | the latest job postings and daily job vacancies. 58 | 59 |
60 |
61 |
62 |
63 | 69 |
70 |
71 | 72 | Permissions 73 | 74 |
75 |
76 | 77 | Obtains the author's consent before retweeting and sharing 78 | content on TechIsHiring. 79 | 80 |
81 |
82 |
83 |
84 |
85 | ); 86 | }; 87 | 88 | export default WhyChooseSection; 89 | -------------------------------------------------------------------------------- /src/components/organisms/about-content/about-content.tsx: -------------------------------------------------------------------------------- 1 | import AboutHeader from "components/molecules/about-header/about-header" 2 | import AboutBanner from "components/molecules/about-banner/about-banner" 3 | import AboutDetails from "components/molecules/about-details/about-details" 4 | 5 | const AboutContent = () => { 6 | 7 | return ( 8 |
9 | 10 |
11 | 12 |
13 | 14 |
15 | 16 |
17 | 18 |
19 | 20 |
21 | 22 |
23 | 24 | ); 25 | }; 26 | 27 | export default AboutContent; 28 | -------------------------------------------------------------------------------- /src/components/organisms/contact-content/contact-content.tsx: -------------------------------------------------------------------------------- 1 | import { contactImg, contactMobileImg } from "images/Index"; 2 | import Image from "next/image"; 3 | import ContactForm from "components/molecules/contact-form/contact-form"; 4 | import React from "react"; 5 | 6 | const ContactContent = () => { 7 | 8 | return ( 9 |
10 |
11 | 12 | Contact Form Image 13 | 14 |
15 | 16 |
17 | 18 |
19 | contact form mobile image 20 |
21 | 22 | 23 | 24 |
25 |
26 | 27 | ); 28 | }; 29 | 30 | export default ContactContent; -------------------------------------------------------------------------------- /src/components/organisms/footer/footer.cy.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Footer from './footer' 3 | import validateFooter from '../../../../cypress/util/validateFooter' 4 | 5 | describe('