├── .babelrc ├── .github └── FUNDING.yml ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── images │ ├── 1.png │ ├── 2.png │ ├── 3.jpg │ ├── 4.jpg │ ├── profile.jpeg │ └── projects.jpeg └── vercel.svg ├── src ├── components │ ├── Acomplishments │ │ ├── Acomplishments.js │ │ └── AcomplishmentsStyles.js │ ├── BackgrooundAnimation │ │ └── BackgroundAnimation.js │ ├── Footer │ │ ├── Footer.js │ │ └── FooterStyles.js │ ├── Header │ │ ├── Header.js │ │ └── HeaderStyles.js │ ├── Hero │ │ ├── Hero.js │ │ └── HeroStyles.js │ ├── NavDropDown │ │ ├── NavDropDown.js │ │ └── index.js │ ├── Projects │ │ ├── Projects.js │ │ └── ProjectsStyles.js │ ├── Technologies │ │ ├── Technologies.js │ │ └── TechnologiesStyles.js │ └── TimeLine │ │ ├── TimeLine.js │ │ └── TimeLineStyles.js ├── constants │ └── constants.js ├── layout │ ├── Layout.js │ └── LayoutStyles.js ├── pages │ ├── _app.js │ ├── _document.js │ ├── api │ │ └── hello.js │ └── index.js ├── styles │ ├── GlobalComponents │ │ ├── Button.js │ │ └── index.js │ ├── globals.js │ └── theme.js └── themes │ └── default.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["next/babel"], 3 | "plugins": [["styled-components", { "ssr": true }]] 4 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: adrianhajdin 2 | -------------------------------------------------------------------------------- /.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 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Personal Portfolio 2 | 3 | ### [Live Site](https://jsmasterypro.com) 4 | 5 | ![Portfolio Website](https://i.ibb.co/WgPMpts/image.png) 6 | 7 | ### [🌟 Become a top 1% Next.js 13 developer in only one course](https://jsmastery.pro/next13) 8 | ### [🚀 Land your dream programming job in 6 months](https://jsmastery.pro/masterclass) 9 | 10 | This is a code repository for the corresponding video tutorial. Your portfolio is your resume and your business card. 11 | 12 | In this video, we will create a full Personal Development Portfolio. We're going to use React and Next.js. 13 | 14 | Setup: 15 | - run ```npm i && npm start``` 16 | 17 | ## Launch your development career with project-based coaching - https://www.jsmastery.pro 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "portfolio_nextjs", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build && next export", 8 | "start": "next start" 9 | }, 10 | "dependencies": { 11 | "next": "10.2.3", 12 | "react": "17.0.2", 13 | "react-dom": "17.0.2", 14 | "styled-components": "^5.3.0", 15 | "styled-normalize": "^8.0.7", 16 | "react-icons": "^4.2.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrianhajdin/portfolio_website/beef893d5e9d5fa297edb51580ed41fe532f3d5b/public/favicon.ico -------------------------------------------------------------------------------- /public/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrianhajdin/portfolio_website/beef893d5e9d5fa297edb51580ed41fe532f3d5b/public/images/1.png -------------------------------------------------------------------------------- /public/images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrianhajdin/portfolio_website/beef893d5e9d5fa297edb51580ed41fe532f3d5b/public/images/2.png -------------------------------------------------------------------------------- /public/images/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrianhajdin/portfolio_website/beef893d5e9d5fa297edb51580ed41fe532f3d5b/public/images/3.jpg -------------------------------------------------------------------------------- /public/images/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrianhajdin/portfolio_website/beef893d5e9d5fa297edb51580ed41fe532f3d5b/public/images/4.jpg -------------------------------------------------------------------------------- /public/images/profile.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrianhajdin/portfolio_website/beef893d5e9d5fa297edb51580ed41fe532f3d5b/public/images/profile.jpeg -------------------------------------------------------------------------------- /public/images/projects.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adrianhajdin/portfolio_website/beef893d5e9d5fa297edb51580ed41fe532f3d5b/public/images/projects.jpeg -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /src/components/Acomplishments/Acomplishments.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Section, SectionDivider, SectionTitle } from '../../styles/GlobalComponents'; 4 | import { Box, Boxes, BoxNum, BoxText } from './AcomplishmentsStyles'; 5 | 6 | const data = [ 7 | { number: 20, text: 'Open Source Projects'}, 8 | { number: 1000, text: 'Students', }, 9 | { number: 1900, text: 'Github Followers', }, 10 | { number: 5000, text: 'Github Stars', } 11 | ]; 12 | 13 | const Acomplishments = () => ( 14 |
15 | Personal Achievements 16 | 17 | {data.map((card, index) => ( 18 | 19 | {`${card.number}+`} 20 | {card.text} 21 | 22 | ))} 23 | 24 | 25 |
26 | ); 27 | 28 | export default Acomplishments; 29 | -------------------------------------------------------------------------------- /src/components/Acomplishments/AcomplishmentsStyles.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components" 2 | 3 | export const Boxes = styled.div` 4 | width: 100%; 5 | display: grid; 6 | grid-template-columns: repeat(4, 1fr); 7 | gap: 24px; 8 | margin: 24px 0 40px; 9 | 10 | @media ${props => props.theme.breakpoints.md}{ 11 | gap: 16px; 12 | margin: 20px 0 32px; 13 | grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); 14 | } 15 | 16 | @media ${props => props.theme.breakpoints.sm}{ 17 | display: grid; 18 | grid-template-columns: repeat(2, 1fr); 19 | gap: 10px; 20 | max-width: 500px; 21 | margin: 24px auto; 22 | } 23 | ` 24 | 25 | export const Box = styled.div` 26 | background: #212D45; 27 | border-radius: 12px; 28 | height: 144px; 29 | padding: 24px; 30 | @media ${props => props.theme.breakpoints.lg} { 31 | height: 210px; 32 | 33 | } 34 | 35 | @media ${props => props.theme.breakpoints.md} { 36 | height: 135px; 37 | padding: 16px; 38 | } 39 | 40 | @media ${props => props.theme.breakpoints.sm} { 41 | height: 110px; 42 | padding: 12px; 43 | 44 | &:nth-child(2n){ 45 | grid-row:2; 46 | } 47 | } 48 | ` 49 | export const BoxNum = styled.h5` 50 | font-style: normal; 51 | font-weight: 600; 52 | font-size: 36px; 53 | line-height: 40px; 54 | letter-spacing: 0.01em; 55 | color: #FFFFFF; 56 | margin-bottom: 8px; 57 | 58 | @media ${props => props.theme.breakpoints.md} { 59 | font-size: 28px; 60 | line-height: 32px; 61 | } 62 | @media ${props => props.theme.breakpoints.sm} { 63 | font-size: 24px; 64 | line-height: 26px; 65 | } 66 | ` 67 | 68 | export const BoxText = styled.p` 69 | font-style: normal; 70 | font-weight: normal; 71 | font-size: 18px; 72 | line-height: 24px; 73 | letter-spacing: 0.02em; 74 | color: rgba(255, 255, 255, 0.75); 75 | 76 | @media ${props => props.theme.breakpoints.md}{ 77 | font-size: 16px; 78 | line-height: 20px; 79 | }; 80 | 81 | @media ${props => props.theme.breakpoints.sm} { 82 | font-size: 10px; 83 | line-height: 14px; 84 | } 85 | ` 86 | 87 | export const Join = styled.div` 88 | display: flex; 89 | max-width: 1040px; 90 | justify-content: center; 91 | align-items: center; 92 | padding-bottom: 80px; 93 | 94 | @media ${props => props.theme.breakpoints.md}{ 95 | display: flex; 96 | justify-content: center; 97 | padding-bottom: 64px; 98 | } 99 | 100 | @media ${props => props.theme.breakpoints.sm}{ 101 | display: flex; 102 | flex-direction: column; 103 | align-items: center; 104 | padding-bottom: 32px; 105 | } 106 | ` 107 | 108 | export const JoinText = styled.h5` 109 | display: flex; 110 | font-size: 24px; 111 | line-height: 40px; 112 | letter-spacing: 0.02em; 113 | color: rgba(255, 255, 255, 0.5); 114 | 115 | @media ${props => props.theme.breakpoints.md}{ 116 | line-height: 32px; 117 | font-size: 20px; 118 | }; 119 | 120 | @media ${props => props.theme.breakpoints.sm}{ 121 | font-size: 16px; 122 | line-height: 24px; 123 | margin: 0 0 16px; 124 | } 125 | ` 126 | 127 | export const IconContainer = styled.div` 128 | display: flex; 129 | 130 | @media ${props => props.theme.breakpoints.sm}{ 131 | width: 160px; 132 | justify-content: space-between; 133 | } 134 | ` 135 | -------------------------------------------------------------------------------- /src/components/BackgrooundAnimation/BackgroundAnimation.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const BackgroundAnimation = () => ( 4 |
5 | 11 | 12 | 19 | 24 | 29 | 30 | 38 | 39 | 40 | 41 | 42 | 47 | 48 | 49 | 50 | 51 | 59 | 65 | 66 | 67 | 68 | 73 | 79 | 80 | 81 | 82 | 90 | 91 | 92 | 93 | 94 | 99 | 100 | 101 | 102 | 103 | 111 | 117 | 118 | 119 | 120 | 125 | 131 | 132 | 133 | 134 | 142 | 148 | 149 | 150 | 151 | 156 | 162 | 163 | 164 | 165 | 173 | 179 | 180 | 181 | 182 | 187 | 193 | 194 | 195 | 196 | 204 | 210 | 211 | 212 | 213 | 218 | 224 | 225 | 226 | 227 | 228 | 236 | 237 | 238 | 239 | 247 | 248 | 249 | 250 | 258 | 259 | 260 | 261 | 269 | 270 | 271 | 272 | 280 | 281 | 282 | 283 | 291 | 292 | 293 | 294 | 302 | 303 | 304 | 305 | 313 | 314 | 315 | 316 | 324 | 325 | 326 | 327 | 335 | 336 | 337 | 338 | 346 | 347 | 348 | 349 | 357 | 358 | 359 | 360 | 361 | 362 |
363 | ); 364 | 365 | export default BackgroundAnimation; -------------------------------------------------------------------------------- /src/components/Footer/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { AiFillGithub, AiFillInstagram, AiFillLinkedin } from 'react-icons/ai'; 3 | 4 | import { SocialIcons } from '../Header/HeaderStyles'; 5 | import { CompanyContainer, FooterWrapper, LinkColumn, LinkItem, LinkList, LinkTitle, Slogan, SocialContainer, SocialIconsContainer } from './FooterStyles'; 6 | 7 | const Footer = () => { 8 | return ( 9 | 10 | 11 | 12 | Call 13 | 314-343-3432 14 | 15 | 16 | Email 17 | 18 | contact@jsmastery.com 19 | 20 | 21 | 22 | 23 | 24 | Innovating one project at a time 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | ); 40 | }; 41 | 42 | export default Footer; 43 | -------------------------------------------------------------------------------- /src/components/Footer/FooterStyles.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components" 2 | 3 | export const FooterWrapper = styled.section` 4 | width: calc(100vw - 96px); 5 | max-width: 1040px; 6 | padding: 2rem 48px 40px; 7 | margin: 1rem auto; 8 | box-sizing: content-box; 9 | 10 | 11 | @media ${props => props.theme.breakpoints.sm} { 12 | padding: 0 16px 48px; 13 | width: calc(100vw - 32px); 14 | } 15 | ` 16 | 17 | export const LinkItem = styled.a` 18 | font-size: 18px; 19 | line-height: 30px; 20 | color: rgba(255, 255, 255, 0.75); 21 | margin-bottom: 16px; 22 | transition: .3s ease; 23 | position: relative; 24 | left: 0; 25 | 26 | &:hover { 27 | color: #fff; 28 | left: 6px; 29 | } 30 | 31 | @media ${props => props.theme.breakpoints.md} { 32 | font-size: 16px; 33 | line-height: 28px; 34 | display: flex; 35 | } 36 | 37 | @media ${props => props.theme.breakpoints.sm} { 38 | font-size: 8px; 39 | line-height: 14px; 40 | margin-bottom: 8px; 41 | display: flex; 42 | align-items: center; 43 | } 44 | ` 45 | 46 | export const SocialIconsContainer = styled.div` 47 | max-width: 1040px; 48 | display: flex; 49 | justify-content: space-between; 50 | 51 | @media ${props => props.theme.breakpoints.md}{ 52 | display: flex; 53 | justify-content: space-between; 54 | } 55 | 56 | @media ${props => props.theme.breakpoints.sm}{ 57 | display: flex; 58 | width: 100%; 59 | flex-direction: column; 60 | } 61 | ` 62 | 63 | export const CompanyContainer = styled.div` 64 | display: flex; 65 | align-items:baseline; 66 | flex-wrap: wrap; 67 | margin-right: auto; 68 | 69 | 70 | @media ${props => props.theme.breakpoints.md}{ 71 | flex-direction: column; 72 | align-items: baseline; 73 | } 74 | 75 | @media ${props => props.theme.breakpoints.sm}{ 76 | display: flex; 77 | flex-direction: column; 78 | margin: 0 0 32px; 79 | align-items: center; 80 | } 81 | ` 82 | 83 | 84 | export const Slogan = styled.p` 85 | color: rgba(255, 255, 255, 0.5); 86 | min-width: 280px; 87 | letter-spacing: 0.02em; 88 | font-size: 18px; 89 | line-height: 30px; 90 | padding: 1rem; 91 | 92 | @media ${props => props.theme.breakpoints.md}{ 93 | font-size: 16px; 94 | line-height: 28px; 95 | } 96 | 97 | @media ${props => props.theme.breakpoints.sm}{ 98 | line-height: 22px; 99 | font-size: 14px; 100 | min-width: 100px; 101 | } 102 | ` 103 | 104 | export const SocialContainer = styled.div` 105 | display: flex; 106 | align-items: center; 107 | 108 | @media ${props => props.theme.breakpoints.md}{ 109 | justify-content: center; 110 | padding-right: 16px; 111 | flex-wrap: wrap; 112 | } 113 | ` 114 | 115 | 116 | export const LinkList = styled.ul` 117 | border-top: 1px solid rgba(255, 255, 255, 0.1); 118 | display: grid; 119 | grid-template-columns: repeat(3, minmax(85px, 220px)); 120 | gap: 40px; 121 | padding: 40px 0 28px; 122 | 123 | @media ${props => props.theme.breakpoints.lg} { 124 | padding: 32px 0 16px; 125 | } 126 | 127 | @media ${props => props.theme.breakpoints.md} { 128 | width: 100%; 129 | padding: 32px 0 16px; 130 | gap: 16px; 131 | } 132 | @media ${props => props.theme.breakpoints.sm} { 133 | width: 100%; 134 | padding: 32px 4px 16px; 135 | gap: 5px; 136 | } 137 | ` 138 | 139 | export const LinkColumn = styled.div` 140 | display: flex; 141 | flex-direction: column; 142 | max-width: 220px; 143 | width: 100%; 144 | ` 145 | export const LinkTitle = styled.h4` 146 | font-style: normal; 147 | font-weight: 600; 148 | font-size: 12px; 149 | line-height: 24px; 150 | text-transform: uppercase; 151 | color: rgba(255, 255, 255, 0.4); 152 | margin-bottom: 16px; 153 | 154 | @media ${props => props.theme.breakpoints.sm} { 155 | font-size: 10px; 156 | line-height: 12px; 157 | margin-bottom: 8px; 158 | } 159 | ` 160 | -------------------------------------------------------------------------------- /src/components/Header/Header.js: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | import React from 'react'; 3 | import { AiFillGithub, AiFillInstagram, AiFillLinkedin } from 'react-icons/ai'; 4 | import { DiCssdeck } from 'react-icons/di'; 5 | 6 | import { Container, Div1, Div2, Div3, NavLink, SocialIcons } from './HeaderStyles'; 7 | 8 | const Header = () => ( 9 | 10 | 11 | 12 | 13 | Portfolio 14 | 15 | 16 | 17 | 18 |
  • 19 | 20 | Projects 21 | 22 |
  • 23 |
  • 24 | 25 | Technologies 26 | 27 |
  • 28 |
  • 29 | 30 | About 31 | 32 |
  • 33 |
    34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
    46 | ); 47 | 48 | export default Header; 49 | -------------------------------------------------------------------------------- /src/components/Header/HeaderStyles.js: -------------------------------------------------------------------------------- 1 | import { IoIosArrowDropdown } from 'react-icons/io'; 2 | import styled from 'styled-components'; 3 | 4 | export const Container = styled.div` 5 | display: grid; 6 | grid-template-columns: repeat(5, 1fr); 7 | grid-template-rows: 1fr; 8 | grid-column-gap: 2rem; 9 | padding: 1rem; 10 | padding-top: 2rem; 11 | 12 | @media ${(props) => props.theme.breakpoints.sm} { 13 | display: grid; 14 | grid-template-columns: repeat(5, 1fr); 15 | grid-template-rows: repeat(2, 60px); 16 | grid-column-gap: 0.5rem; 17 | grid-row-gap: 0.5rem; 18 | } 19 | `; 20 | export const Div1 = styled.div` 21 | grid-area: 1 / 1 / 2 / 2; 22 | display: flex; 23 | flex-direction: row; 24 | align-content: center; 25 | @media ${(props) => props.theme.breakpoints.sm} { 26 | grid-area: 1 / 1 / 2 / 3; 27 | } 28 | `; 29 | export const Div2 = styled.div` 30 | grid-area: 1 / 2 / 2 / 4; 31 | display: flex; 32 | justify-content: space-around; 33 | @media ${(props) => props.theme.breakpoints.sm} { 34 | grid-area: 2 / 2 / 3 / 5; 35 | } 36 | `; 37 | export const Div3 = styled.div` 38 | grid-area: 1 / 5 / 2 / 6; 39 | display: flex; 40 | justify-content: space-around; 41 | align-items: center; 42 | @media ${(props) => props.theme.breakpoints.sm} { 43 | align-items: center; 44 | grid-area: 1 / 4 / 2 / 6; 45 | } 46 | `; 47 | 48 | // Navigation Links 49 | export const NavLink = styled.a` 50 | font-size: 2rem; 51 | line-height: 32px; 52 | color: rgba(255, 255, 255, 0.75); 53 | transition: 0.4s ease; 54 | &:hover { 55 | color: #fff; 56 | opacity: 1; 57 | cursor: pointer; 58 | } 59 | @media ${(props) => props.theme.breakpoints.sm} { 60 | padding: 0.5rem; 61 | } 62 | `; 63 | 64 | /// DropDown Contact 65 | export const ContactDropDown = styled.button` 66 | border: none; 67 | display: flex; 68 | position: relative; 69 | background: none; 70 | font-size: 1.7rem; 71 | 72 | line-height: 32px; 73 | color: rgba(255, 255, 255, 0.75); 74 | cursor: pointer; 75 | transition: 0.3s ease; 76 | 77 | &:focus { 78 | outline: none; 79 | } 80 | &:hover { 81 | color: #fff; 82 | } 83 | 84 | @media ${(props) => props.theme.breakpoints.sm} { 85 | padding: 0.4rem 0; 86 | } 87 | @media ${(props) => props.theme.breakpoints.md} { 88 | padding: 0; 89 | } 90 | `; 91 | 92 | export const NavProductsIcon = styled(IoIosArrowDropdown)` 93 | margin-left: 8px; 94 | display: flex; 95 | align-self: center; 96 | transition: 0.3s ease; 97 | opacity: ${({ isOpen }) => (isOpen ? '1' : '.75')}; 98 | transform: ${({ isOpen }) => (isOpen ? 'scaleY(-1)' : 'scaleY(1)')}; 99 | 100 | &:hover { 101 | opacity: 1; 102 | } 103 | 104 | @media ${(props) => props.theme.breakpoints.sm} { 105 | margin: 2px 0 0 2px; 106 | width: 15px; 107 | } 108 | `; 109 | 110 | 111 | // Social Icons 112 | 113 | export const SocialIcons = styled.a` 114 | transition: 0.3s ease; 115 | color: white; 116 | border-radius: 50px; 117 | padding: 8px; 118 | &:hover { 119 | background-color: #212d45; 120 | transform: scale(1.2); 121 | cursor: pointer; 122 | 123 | } 124 | ` -------------------------------------------------------------------------------- /src/components/Hero/Hero.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Section, SectionText, SectionTitle } from '../../styles/GlobalComponents'; 4 | import Button from '../../styles/GlobalComponents/Button'; 5 | import { LeftSection } from './HeroStyles'; 6 | 7 | const Hero = (props) => ( 8 | <> 9 |
    10 | 11 | 12 | Welcome To
    13 | My Personal Portfolio 14 |
    15 | 16 | The purpose of JavaScript Mastery is to help aspiring and established developers to take their development skills to the next level and build awesome apps. 17 | 18 | 19 |
    20 |
    21 | 22 | ); 23 | 24 | export default Hero; -------------------------------------------------------------------------------- /src/components/Hero/HeroStyles.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const LeftSection = styled.div` 4 | width: 100%; 5 | @media ${(props) => props.theme.breakpoints.sm} { 6 | width: 80%; 7 | display: flex; 8 | flex-direction: column; 9 | 10 | margin: 0 auto; 11 | } 12 | @media ${(props) => props.theme.breakpoints.md} { 13 | width: 100%; 14 | display: flex; 15 | flex-direction: column; 16 | 17 | margin: 0 auto; 18 | } 19 | `; 20 | -------------------------------------------------------------------------------- /src/components/NavDropDown/NavDropDown.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | export const DropDownContainer = styled.div` 4 | position: absolute; 5 | display: flex; 6 | flex-direction: column; 7 | right: -25%; 8 | top: 40px; 9 | width: 280px; 10 | background-color: #fff; 11 | border-radius: 8px; 12 | z-index: 100; 13 | padding: 4px 0; 14 | cursor: default; 15 | overflow: hidden; 16 | transition: 0.3s ease; 17 | visibility: ${({ active }) => active ? 'visible' : 'hidden'}; 18 | opacity: ${({ active }) => active ? '1' : '0'}; 19 | transform-origin: top; 20 | transform: ${({ active }) => active ? 'scaleY(1)' : 'scaleY(.3)'}; 21 | 22 | @media ${(props) => props.theme.breakpoints.md} { 23 | top: 32px; 24 | } 25 | @media ${(props) => props.theme.breakpoints.sm} { 26 | top: 24px; 27 | } 28 | ` 29 | export const DropDownItem = styled.a` 30 | width: 100%; 31 | display: flex; 32 | align-items: flex-start; 33 | cursor: pointer; 34 | transition: .3s ease; 35 | padding: 12px 16px; 36 | 37 | &:hover { 38 | transform: scale(1.05); 39 | background-color: #eee; 40 | box-shadow: 0 3px 6px 3px rgba(0,0,0,.3); 41 | } 42 | 43 | &:nth-of-type(2n):hover { 44 | box-shadow: 0 0 8px 4px rgba(0,0,0,.3); 45 | } 46 | 47 | &:nth-of-type(3n):hover { 48 | box-shadow: 0 -3px 6px 3px rgba(0,0,0,.3); 49 | } 50 | ` 51 | 52 | export const DropDownIcon = styled.div` 53 | width: 32px; 54 | height: 32px; 55 | margin-right: 16px; 56 | ` 57 | 58 | export const DropDownTextContainer = styled.div` 59 | display: flex; 60 | flex-direction: column; 61 | ` 62 | 63 | export const DropDownItemTitle = styled.h2` 64 | color: #0f1624; 65 | font-size: 18px; 66 | line-height: 26px; 67 | text-align: start; 68 | ` 69 | 70 | export const DropDownItemDesc = styled.p` 71 | color: #0f1624; 72 | opacity: 0.5; 73 | font-size: 14px; 74 | line-height: 22px; 75 | text-align: start; 76 | ` -------------------------------------------------------------------------------- /src/components/NavDropDown/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { AiFillPhone, AiOutlineMail } from 'react-icons/ai' 3 | import { FaLocationArrow } from "react-icons/fa" 4 | 5 | import { DropDownContainer, DropDownIcon, DropDownItem, DropDownItemDesc, DropDownItemTitle, DropDownTextContainer } from './NavDropDown' 6 | 7 | const NavDropDown = (props) => ( 8 | 9 | 10 | 11 | 12 | 13 | 14 | Phone 15 | Let's get together and have a chat?' 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Email 24 | If you want to talk jus send a message and I'll get back 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | Address 33 | 1405, Angelus Dr, Florissant. Mo 34 | 35 | 36 | 37 | ); 38 | 39 | export default NavDropDown 40 | -------------------------------------------------------------------------------- /src/components/Projects/Projects.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { BlogCard, CardInfo, ExternalLinks, GridContainer, HeaderThree, Hr, Tag, TagList, TitleContent, UtilityList, Img } from './ProjectsStyles'; 4 | import { Section, SectionDivider, SectionTitle } from '../../styles/GlobalComponents'; 5 | import { projects } from '../../constants/constants'; 6 | 7 | const Projects = () => ( 8 |
    9 | 10 | Projects 11 | 12 | {projects.map((p, i) => { 13 | return ( 14 | 15 | 16 | 17 | {p.title} 18 |
    19 |
    20 | {p.description} 21 |
    22 | Stack 23 | 24 | {p.tags.map((t, i) => { 25 | return {t}; 26 | })} 27 | 28 |
    29 | 30 | Code 31 | Source 32 | 33 |
    34 | ); 35 | })} 36 |
    37 |
    38 | ); 39 | 40 | export default Projects; -------------------------------------------------------------------------------- /src/components/Projects/ProjectsStyles.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const Img = styled.img` 4 | width:100%; 5 | height:100%; 6 | object-fit: cover; 7 | overflow: hidden; 8 | ` 9 | 10 | export const GridContainer = styled.section` 11 | display: grid; 12 | grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); 13 | padding: 3rem; 14 | place-items: center; 15 | column-gap: 2rem; 16 | row-gap: 3rem; 17 | @media ${(props) => props.theme.breakpoints.sm} { 18 | display: flex; 19 | flex-direction: column; 20 | padding: 2rem; 21 | padding-bottom: 0; 22 | } 23 | 24 | ` 25 | export const BlogCard = styled.div` 26 | border-radius: 10px; 27 | box-shadow: 3px 3px 20px rgba(80, 78, 78, 0.5); 28 | text-align: center; 29 | width: 400px; 30 | @media ${(props) => props.theme.breakpoints.sm} { 31 | width: 100%; 32 | } 33 | `; 34 | export const TitleContent = styled.div` 35 | text-align: center; 36 | z-index: 20; 37 | width: 100%; 38 | 39 | `; 40 | 41 | 42 | export const HeaderThree = styled.h3` 43 | font-weight: 500; 44 | letter-spacing: 2px; 45 | color: #9cc9e3; 46 | padding: .5rem 0; 47 | font-size: ${(props) => props.title ? '3rem' : '2rem'}; 48 | `; 49 | 50 | export const Hr = styled.hr` 51 | width: 50px; 52 | height: 3px; 53 | margin: 20px auto; 54 | border: 0; 55 | background: #d0bb57; 56 | `; 57 | 58 | export const Intro = styled.div` 59 | width: 170px; 60 | margin: 0 auto; 61 | color: #dce3e7; 62 | font-family: 'Droid Serif', serif; 63 | font-size: 13px; 64 | font-style: italic; 65 | line-height: 18px; 66 | `; 67 | 68 | 69 | export const CardInfo = styled.p` 70 | width: 100%; 71 | padding: 0 50px; 72 | color: #e4e6e7; 73 | font-style: 2rem; 74 | line-height: 24px; 75 | text-align: justify; 76 | @media ${(props) => props.theme.breakpoints.sm} { 77 | padding:.3rem 78 | 79 | } 80 | `; 81 | 82 | 83 | export const UtilityList = styled.ul` 84 | list-style-type: none; 85 | padding: 0; 86 | display: flex; 87 | justify-content: space-around; 88 | margin: 2.5rem 0; 89 | `; 90 | 91 | export const ExternalLinks = styled.a` 92 | color:#d4c0c0; 93 | font-size: 1.6rem; 94 | padding:1rem 1.5rem; 95 | background: #6b3030; 96 | border-radius: 15px; 97 | transition: 0.5s; 98 | &:hover{ 99 | background: #801414; 100 | 101 | } 102 | `; 103 | 104 | export const TagList = styled.ul` 105 | display: flex; 106 | justify-content: space-around; 107 | padding: 2rem; 108 | ` 109 | export const Tag = styled.li` 110 | color: #d8bfbf; 111 | font-size: 1.5rem; 112 | ` -------------------------------------------------------------------------------- /src/components/Technologies/Technologies.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { DiFirebase, DiReact, DiZend } from 'react-icons/di'; 3 | import { Section, SectionDivider, SectionText, SectionTitle } from '../../styles/GlobalComponents'; 4 | import { List, ListContainer, ListItem, ListParagraph, ListTitle } from './TechnologiesStyles'; 5 | 6 | const Technologies = () => ( 7 |
    8 | 9 | Technologies 10 | 11 | I've worked with a range a technologies in the web development world. 12 | From Back-end To Design 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Front-End 21 | 22 | Experiece with
    23 | React.js 24 |
    25 |
    26 |
    27 | 28 | 29 | 30 | 31 | 32 | Back-End 33 | 34 | Experience with
    35 | Node and Databases 36 |
    37 |
    38 |
    39 | 40 | 41 | 42 | 43 | 44 | UI/UX 45 | 46 | Experience with
    47 | tools like Figma 48 |
    49 |
    50 |
    51 |
    52 | 53 |
    54 | ); 55 | 56 | export default Technologies; 57 | -------------------------------------------------------------------------------- /src/components/Technologies/TechnologiesStyles.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | export const ImageContainer = styled.div` 4 | text-align: center; 5 | background-image: radial-gradient(50% 50% at 50% 50%, rgba(79, 108, 176, 0.25) 53.8%, rgba(79, 108, 176, 0) 100%); 6 | width: 100%; 7 | padding: 60px; 8 | margin-top: 48px; 9 | display: flex; 10 | flex-direction: column; 11 | align-items: center; 12 | justify-content: center; 13 | 14 | @media ${props => props.theme.breakpoints.lg} { 15 | background-image: none; 16 | padding: 0; 17 | margin-top: 40px; 18 | } 19 | @media ${props => props.theme.breakpoints.md} { 20 | background-image: none; 21 | padding: 0; 22 | margin-top: 16px; 23 | } 24 | ` 25 | 26 | export const MainImage = styled.img` 27 | width: 100%; 28 | ` 29 | 30 | export const List = styled.ul` 31 | list-style-type: none; 32 | display: grid; 33 | grid-template-columns: repeat(3, 1fr); 34 | gap: 40px; 35 | margin: 3rem 0; 36 | 37 | @media ${props => props.theme.breakpoints.lg}{ 38 | margin: 64px 0; 39 | } 40 | 41 | @media ${props => props.theme.breakpoints.md}{ 42 | margin: 64px 0; 43 | gap: 24px 44 | } 45 | 46 | @media ${props => props.theme.breakpoints.sm}{ 47 | display: flex; 48 | flex-direction: column; 49 | margin: 32px 0; 50 | } 51 | ` 52 | 53 | export const ListContainer = styled.div` 54 | display: flex; 55 | flex-direction: column; 56 | 57 | @media ${props => props.theme.breakpoints.sm}{ 58 | display: flex; 59 | margin-left: 18px; 60 | } 61 | ` 62 | 63 | export const ListTitle = styled.h4` 64 | font-weight: 700; 65 | font-size: 28px; 66 | line-height: 32px; 67 | letter-spacing: 0.02em; 68 | color: #FFFFFF; 69 | margin-bottom: 8px; 70 | 71 | @media ${props => props.theme.breakpoints.md}{ 72 | font-size: 24px; 73 | line-height: 28px; 74 | } 75 | 76 | @media ${props => props.theme.breakpoints.sm}{ 77 | font-size: 20px; 78 | line-height: 28px; 79 | letter-spacing: 0.02em; 80 | margin-bottom: 4px; 81 | } 82 | ` 83 | 84 | export const ListParagraph = styled.p` 85 | font-size: 18px; 86 | line-height: 30px; 87 | color: rgba(255, 255, 255, 0.75); 88 | 89 | @media ${props => props.theme.breakpoints.md}{ 90 | font-size: 16px; 91 | line-height: 28px; 92 | } 93 | 94 | @media ${props => props.theme.breakpoints.sm}{ 95 | font-size: 14px; 96 | line-height: 22px; 97 | } 98 | ` 99 | 100 | export const ListItem = styled.li` 101 | max-width: 320px; 102 | display: flex; 103 | flex-direction: column; 104 | 105 | @media ${props => props.theme.breakpoints.md}{ 106 | max-width: 203px; 107 | } 108 | 109 | @media ${props => props.theme.breakpoints.sm}{ 110 | margin-bottom: 14px; 111 | max-width: 320px; 112 | flex-direction: row; 113 | } 114 | ` 115 | 116 | export const ListIcon = styled.img` 117 | display: block; 118 | width: 48px; 119 | height: 48px; 120 | margin-bottom: 10px; 121 | 122 | @media ${props => props.theme.breakpoints.md}{ 123 | width: 40px; 124 | height: 40px; 125 | margin-bottom: 8px; 126 | } 127 | 128 | @media ${props => props.theme.breakpoints.sm}{ 129 | width: 32px; 130 | height: 32px; 131 | margin-bottom: 0px; 132 | } 133 | ` 134 | -------------------------------------------------------------------------------- /src/components/TimeLine/TimeLine.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useRef, useEffect } from 'react'; 2 | 3 | import { CarouselButton, CarouselButtonDot, CarouselButtons, CarouselContainer, CarouselItem, CarouselItemImg, CarouselItemText, CarouselItemTitle, CarouselMobileScrollNode } from './TimeLineStyles'; 4 | import { Section, SectionDivider, SectionText, SectionTitle } from '../../styles/GlobalComponents'; 5 | import { TimeLineData } from '../../constants/constants'; 6 | 7 | const TOTAL_CAROUSEL_COUNT = TimeLineData.length; 8 | 9 | const Timeline = () => { 10 | const [activeItem, setActiveItem] = useState(0); 11 | const carouselRef = useRef(); 12 | 13 | const scroll = (node, left) => { 14 | return node.scrollTo({ left, behavior: 'smooth' }); 15 | } 16 | 17 | const handleClick = (e, i) => { 18 | e.preventDefault(); 19 | 20 | if (carouselRef.current) { 21 | const scrollLeft = Math.floor(carouselRef.current.scrollWidth * 0.7 * (i / TimeLineData.length)); 22 | 23 | scroll(carouselRef.current, scrollLeft); 24 | } 25 | } 26 | 27 | const handleScroll = () => { 28 | if (carouselRef.current) { 29 | const index = Math.round((carouselRef.current.scrollLeft / (carouselRef.current.scrollWidth * 0.7)) * TimeLineData.length); 30 | 31 | setActiveItem(index); 32 | } 33 | } 34 | 35 | // snap back to beginning of scroll when window is resized 36 | // avoids a bug where content is covered up if coming from smaller screen 37 | useEffect(() => { 38 | const handleResize = () => { 39 | scroll(carouselRef.current, 0); 40 | } 41 | 42 | window.addEventListener('resize', handleResize); 43 | }, []); 44 | 45 | return ( 46 |
    47 | About Me 48 | 49 | The purpose of JavaScript Mastery is to help aspiring and established developers to take their development skills to the next level and build awesome apps. 50 | 51 | 52 | <> 53 | {TimeLineData.map((item, index) => ( 54 | 57 | handleClick(e, index)}> 62 | 63 | {`${item.year}`} 64 | 70 | 77 | 78 | 85 | 86 | 91 | 92 | 93 | 94 | 95 | {item.text} 96 | 97 | 98 | ))} 99 | 100 | 101 | 102 | {TimeLineData.map((item, index) => { 103 | return ( 104 | handleClick(e, index)} 109 | type="button"> 110 | 111 | 112 | ); 113 | })} 114 | 115 | 116 |
    117 | ); 118 | }; 119 | 120 | export default Timeline; 121 | -------------------------------------------------------------------------------- /src/components/TimeLine/TimeLineStyles.js: -------------------------------------------------------------------------------- 1 | 2 | import styled from 'styled-components' 3 | 4 | export const CarouselContainer = styled.ul` 5 | max-width: 1040px; 6 | background: #0F1624; 7 | padding: 0rem; 8 | list-style:none; 9 | display: flex; 10 | justify-content: space-between; 11 | /* overflow-x: hidden; */ 12 | 13 | margin-left: 32px; 14 | &:first-of-type{ 15 | margin-left: 0px; 16 | } 17 | 18 | margin-bottom: 80px; 19 | 20 | //remove scrollbar 21 | scrollbar-width: none; 22 | &::-webkit-scrollbar { 23 | display: none; 24 | } 25 | 26 | @media ${props => props.theme.breakpoints.sm} { 27 | overflow-x: scroll; 28 | -webkit-overflow-scrolling: touch; 29 | scroll-snap-type: x mandatory; 30 | touch-action: pan-x; 31 | justify-content: initial; 32 | margin-bottom: 8px; 33 | } 34 | ` 35 | export const CarouselMobileScrollNode = styled.div` 36 | @media ${props => props.theme.breakpoints.sm} { 37 | display: flex; 38 | min-width: ${({ final }) => final ? `120%;` : `min-content`} 39 | } 40 | ` 41 | 42 | export const CarouselItem = styled.div` 43 | background: #0F1624; 44 | border-radius: 3px; 45 | max-width: 196px; 46 | 47 | @media ${props => props.theme.breakpoints.md} { 48 | max-width: 124px; 49 | } 50 | 51 | @media ${props => props.theme.breakpoints.sm} { 52 | margin-left: 32px; 53 | min-width: 120px; 54 | background: #0E131F; 55 | padding: 4px; 56 | align-content: start; 57 | scroll-snap-align: start; 58 | border-radius: 3px; 59 | overflow: visible; 60 | position: relative; 61 | height: fit-content; 62 | 63 | ${(props) => props.active === props.index ? `opacity: 1` : `opacity: 0.5`}; 64 | } 65 | ` 66 | 67 | export const CarouselItemTitle = styled.h4` 68 | font-weight: bold; 69 | font-size: 24px; 70 | line-height: 32px; 71 | letter-spacing: 0.02em; 72 | display: flex; 73 | /* This gradient is different due to the size of the Title container, it must transition sooner to be visible on the text */ 74 | background: linear-gradient(121.57deg, #FFFFFF 10%, rgba(255, 255, 255, 0.66) 30.15%); 75 | -webkit-background-clip: text; 76 | -webkit-text-fill-color: transparent; 77 | margin-bottom: 8px; 78 | 79 | @media ${props => props.theme.breakpoints.md} { 80 | font-size: 20px; 81 | line-height: 28px; 82 | margin-bottom: 4px; 83 | } 84 | 85 | @media ${props => props.theme.breakpoints.sm} { 86 | font-size: 16px; 87 | line-height: 24px; 88 | } 89 | ` 90 | export const CarouselItemImg = styled.svg` 91 | margin-left: 21px; 92 | -webkit-mask-image: linear-gradient(to right, rgba(0,0,0,1), rgba(0,0,0,0)); 93 | width: 100%; 94 | 95 | @media ${props => props.theme.breakpoints.sm} { 96 | -webkit-mask-image: none; 97 | margin-left: 16px; 98 | overflow: visible; 99 | } 100 | ` 101 | 102 | export const CarouselItemText = styled.p` 103 | font-size: 14px; 104 | line-height: 22px; 105 | letter-spacing: 0.02em; 106 | color: rgba(255, 255, 255, 0.75); 107 | padding-right: 16px; 108 | 109 | @media ${props => props.theme.breakpoints.md} { 110 | font-size: 12px; 111 | line-height: 18px; 112 | padding-right: 32px; 113 | } 114 | @media ${props => props.theme.breakpoints.sm} { 115 | font-size: 10px; 116 | line-height: 16px; 117 | padding-right: 0; 118 | } 119 | ` 120 | export const CarouselButtons = styled.div` 121 | width: 288px; 122 | 123 | display: none; 124 | visibility: hidden; 125 | 126 | @media ${props => props.theme.breakpoints.sm} { 127 | display: flex; 128 | visibility: visible; 129 | margin-bottom: 48px; 130 | } 131 | ` 132 | 133 | export const CarouselButton = styled.button` 134 | box-sizing: border-box; 135 | background: none; 136 | padding: 4px; 137 | border: none; 138 | cursor: pointer; 139 | margin-right: 4px; 140 | opacity: ${(props) => props.active === props.index ? `1` : `.33`}; 141 | transform: ${(props) => props.active === props.index ? `scale(1.6)` : `scale(1)`}; 142 | 143 | &:focus { 144 | outline: none; 145 | } 146 | ` 147 | 148 | export const CarouselButtonDot = styled.div` 149 | background-color: white; 150 | border-radius: 10px; 151 | margin: auto; 152 | width: 3px; 153 | height: 3px; 154 | ` 155 | -------------------------------------------------------------------------------- /src/constants/constants.js: -------------------------------------------------------------------------------- 1 | export const projects = [ 2 | { 3 | title: 'MERN Memories', 4 | description: "Using React, Node.js, Express & MongoDB you'll learn how to build a Full Stack MERN Application - from start to finish. The App is called Memories and it is a simple social media app that allows users to post interesting events that happened in their lives.", 5 | image: '/images/1.png', 6 | tags: ['Mongo', 'Express', 'React', 'Node'], 7 | source: 'https://google.com', 8 | visit: 'https://google.com', 9 | id: 0, 10 | }, 11 | { 12 | title: 'E-Commerce', 13 | description:"While building it you're going to learn many advanced React & JavaScript topics, as well as how to use Stripe for card transactions. On top of that, at the end of the video, you will have this unique and complex webshop app that you will be able to add to your portfolio. And trust me, e-commerce applications are impressive.", 14 | image: '/images/2.png', 15 | tags: ['React', 'JavaScript'], 16 | source: 'https://google.com', 17 | visit: 'https://google.com', 18 | id: 1, 19 | }, 20 | { 21 | title: 'WebRTC App', 22 | description: "This is a code repository for the corresponding YouTube video. In this tutorial, we're going to build and deploy a React Video Chat Application using WebRTC.", 23 | image: '/images/3.jpg', 24 | tags: ['React', 'WebRTC'], 25 | source: 'https://google.com', 26 | visit: 'https://google.com', 27 | id: 2, 28 | }, 29 | { 30 | title: 'Unichat', 31 | description: "This is a code repository for the corresponding video tutorial. In this video, we will create a full Realtime Chat Application", 32 | image: '/images/4.jpg', 33 | tags: ['React', 'ChatEngine', 'Firebase'], 34 | source: 'https://google.com', 35 | visit: 'https://google.com', 36 | id: 3, 37 | }, 38 | ]; 39 | 40 | export const TimeLineData = [ 41 | { year: 2017, text: 'Started my journey', }, 42 | { year: 2018, text: 'Worked as a freelance developer', }, 43 | { year: 2019, text: 'Founded JavaScript Mastery', }, 44 | { year: 2020, text: 'Shared my projects with the world', }, 45 | { year: 2021, text: 'Started my own platform', }, 46 | ]; -------------------------------------------------------------------------------- /src/layout/Layout.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Footer from '../components/Footer/Footer' 4 | import Header from '../components/Header/Header' 5 | import { Container } from './LayoutStyles' 6 | 7 | export const Layout = ({children}) => { 8 | return ( 9 | 10 |
    11 |
    {children}
    12 |