├── images ├── mockup1.png └── dev-portfolio.gif ├── public ├── robots.txt ├── images │ ├── logo.png │ ├── skills │ │ ├── css.png │ │ ├── git.png │ │ ├── js.png │ │ ├── php.png │ │ ├── html.png │ │ ├── java.png │ │ ├── mysql.png │ │ ├── react.png │ │ ├── bamboo.png │ │ ├── django.png │ │ ├── docker.png │ │ ├── firebase.png │ │ ├── kotlin.jpeg │ │ ├── mongo-db.png │ │ ├── newrelic.png │ │ ├── nodejs.png │ │ ├── python.png │ │ ├── cloudflare.png │ │ ├── openshift.png │ │ ├── photoshop.png │ │ ├── typescript.png │ │ ├── android_new.png │ │ ├── google-play.png │ │ ├── react-native.png │ │ ├── android-jetpack.png │ │ ├── android-studio.png │ │ └── c-plus-plus.svg │ ├── about │ │ └── profile.png │ ├── education │ │ └── lorem-ipsum.png │ └── projects │ │ ├── caaring-poster.png │ │ ├── portfolio-poster.png │ │ └── quiet-hours-poster.jpg ├── profile │ ├── home.json │ ├── social.json │ ├── education.json │ ├── about.json │ ├── routes.json │ ├── navbar.json │ ├── experiences.json │ ├── skills.json │ └── projects.json ├── manifest.json └── index.html ├── src ├── AppContext.js ├── css │ ├── experience.css │ └── education.css ├── setupTests.js ├── App.test.js ├── theme │ ├── GlobalStyles.js │ └── themes.js ├── components │ ├── Header.jsx │ ├── FallbackSpinner.jsx │ ├── ThemeToggler.jsx │ ├── Social.jsx │ ├── Home.jsx │ ├── About.jsx │ ├── Skills.jsx │ ├── Projects.jsx │ ├── Education.jsx │ ├── projects │ │ └── ProjectCard.jsx │ ├── Experience.jsx │ └── NavBar.jsx ├── index.css ├── constants │ └── endpoints.js ├── reportWebVitals.js ├── index.jsx ├── App.jsx ├── MainApp.jsx ├── logo.svg └── App.css ├── .gitignore ├── .eslintrc.js ├── LICENSE.md ├── package.json └── README.md /images/mockup1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/images/mockup1.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/logo.png -------------------------------------------------------------------------------- /images/dev-portfolio.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/images/dev-portfolio.gif -------------------------------------------------------------------------------- /public/images/skills/css.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/css.png -------------------------------------------------------------------------------- /public/images/skills/git.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/git.png -------------------------------------------------------------------------------- /public/images/skills/js.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/js.png -------------------------------------------------------------------------------- /public/images/skills/php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/php.png -------------------------------------------------------------------------------- /public/profile/home.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Your Name", 3 | "roles": ["a Developer", "a Freelancer"] 4 | } -------------------------------------------------------------------------------- /public/images/skills/html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/html.png -------------------------------------------------------------------------------- /public/images/skills/java.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/java.png -------------------------------------------------------------------------------- /public/images/skills/mysql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/mysql.png -------------------------------------------------------------------------------- /public/images/skills/react.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/react.png -------------------------------------------------------------------------------- /public/images/about/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/about/profile.png -------------------------------------------------------------------------------- /public/images/skills/bamboo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/bamboo.png -------------------------------------------------------------------------------- /public/images/skills/django.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/django.png -------------------------------------------------------------------------------- /public/images/skills/docker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/docker.png -------------------------------------------------------------------------------- /public/images/skills/firebase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/firebase.png -------------------------------------------------------------------------------- /public/images/skills/kotlin.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/kotlin.jpeg -------------------------------------------------------------------------------- /public/images/skills/mongo-db.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/mongo-db.png -------------------------------------------------------------------------------- /public/images/skills/newrelic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/newrelic.png -------------------------------------------------------------------------------- /public/images/skills/nodejs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/nodejs.png -------------------------------------------------------------------------------- /public/images/skills/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/python.png -------------------------------------------------------------------------------- /public/images/skills/cloudflare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/cloudflare.png -------------------------------------------------------------------------------- /public/images/skills/openshift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/openshift.png -------------------------------------------------------------------------------- /public/images/skills/photoshop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/photoshop.png -------------------------------------------------------------------------------- /public/images/skills/typescript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/typescript.png -------------------------------------------------------------------------------- /public/images/skills/android_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/android_new.png -------------------------------------------------------------------------------- /public/images/skills/google-play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/google-play.png -------------------------------------------------------------------------------- /public/images/skills/react-native.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/react-native.png -------------------------------------------------------------------------------- /public/images/education/lorem-ipsum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/education/lorem-ipsum.png -------------------------------------------------------------------------------- /public/images/skills/android-jetpack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/android-jetpack.png -------------------------------------------------------------------------------- /public/images/skills/android-studio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/skills/android-studio.png -------------------------------------------------------------------------------- /src/AppContext.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const AppContext = React.createContext(); 4 | 5 | export default AppContext; 6 | -------------------------------------------------------------------------------- /public/images/projects/caaring-poster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/projects/caaring-poster.png -------------------------------------------------------------------------------- /public/images/projects/portfolio-poster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/projects/portfolio-poster.png -------------------------------------------------------------------------------- /public/images/projects/quiet-hours-poster.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetmental1122/sweet/HEAD/public/images/projects/quiet-hours-poster.jpg -------------------------------------------------------------------------------- /src/css/experience.css: -------------------------------------------------------------------------------- 1 | .entry .body{ 2 | margin: 0 0 1em; 3 | } 4 | 5 | @media only screen and (max-width: 768px) { 6 | .item-title { 7 | margin-top: 10px !important; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /src/theme/GlobalStyles.js: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from 'styled-components'; 2 | 3 | const GlobalStyles = createGlobalStyle` 4 | body { 5 | background: ${({ theme }) => theme.background}; 6 | color: ${({ theme }) => theme.color}; 7 | transition: all 0.50s linear; 8 | } 9 | `; 10 | 11 | export default GlobalStyles; 12 | -------------------------------------------------------------------------------- /src/components/Header.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import '../App.css'; 4 | 5 | function Header(props) { 6 | const { title } = props; 7 | return
{title}
; 8 | } 9 | 10 | Header.propTypes = { 11 | title: PropTypes.string.isRequired, 12 | }; 13 | 14 | export default Header; 15 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Mayank Agarwal", 3 | "name": "Mayank Agarwal - Portfolio", 4 | "icons": [ 5 | { 6 | "src": "images/logo.png", 7 | "type": "image/png", 8 | "sizes": "425x225" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /public/profile/social.json: -------------------------------------------------------------------------------- 1 | { 2 | "social": [ 3 | { 4 | "network" : "linkedin", 5 | "href": "https://linkedin.com/" 6 | }, 7 | { 8 | "network" : "github", 9 | "href": "https://github.com/mayankagarwal09" 10 | }, 11 | { 12 | "network" : "email", 13 | "href": "mailto:test@test.com" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /src/constants/endpoints.js: -------------------------------------------------------------------------------- 1 | const endpoints = { 2 | navbar: 'profile/navbar.json', 3 | routes: 'profile/routes.json', 4 | home: 'profile/home.json', 5 | social: 'profile/social.json', 6 | about: 'profile/about.json', 7 | skills: 'profile/skills.json', 8 | education: 'profile/education.json', 9 | experiences: 'profile/experiences.json', 10 | projects: 'profile/projects.json', 11 | }; 12 | 13 | export default endpoints; 14 | -------------------------------------------------------------------------------- /.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 | package-lock.json 8 | 9 | # testing 10 | /coverage 11 | 12 | # production 13 | /build 14 | 15 | # misc 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | -------------------------------------------------------------------------------- /src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = (onPerfEntry) => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ 4 | getCLS, getFID, getFCP, getLCP, getTTFB, 5 | }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /src/css/education.css: -------------------------------------------------------------------------------- 1 | .vertical { 2 | justify-content: center; 3 | } 4 | 5 | .vertical_alternating { 6 | justify-content: center; 7 | } 8 | 9 | @media only screen and (max-width: 578px) { 10 | div.vertical-item-row > div:nth-child(1) { 11 | width: 20% !important; 12 | } 13 | div.vertical-item-row > div:nth-child(2) { 14 | width: 65% !important; 15 | } 16 | div.vertical-item-row > div:nth-child(3) { 17 | width: 15% !important; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | }, 6 | extends: [ 7 | 'plugin:react/recommended', 8 | 'airbnb', 9 | ], 10 | parserOptions: { 11 | ecmaFeatures: { 12 | jsx: true, 13 | }, 14 | ecmaVersion: 12, 15 | sourceType: 'module', 16 | }, 17 | plugins: [ 18 | 'react', 19 | ], 20 | rules: { 21 | 'prefer-template': 0, 22 | 'react/no-children-prop': [0], 23 | 'linebreak-style': 0 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /src/components/FallbackSpinner.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Spinner } from 'react-bootstrap'; 3 | 4 | const styles = { 5 | spinnerContainerStyle: { 6 | display: 'flex', 7 | justifyContent: 'center', 8 | alignItems: 'center', 9 | height: '100%', 10 | }, 11 | }; 12 | 13 | function FallbackSpinner() { 14 | return ( 15 |
16 | 17 |
18 | ); 19 | } 20 | 21 | export default FallbackSpinner; 22 | -------------------------------------------------------------------------------- /src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root'), 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /public/profile/education.json: -------------------------------------------------------------------------------- 1 | { 2 | "education":[ 3 | { 4 | "title": "Jun 20XX - Jun 20YY", 5 | "cardTitle": "B.Tech, Computer Science", 6 | "cardSubtitle":"XYZ University, City", 7 | "cardDetailedText": "CGPA - 9.5", 8 | "icon" : { 9 | "src": "images/education/lorem-ipsum.png" 10 | } 11 | }, 12 | { 13 | "title": "Apr 20XX", 14 | "cardTitle": "High School", 15 | "cardSubtitle":"ABC School, City", 16 | "cardDetailedText": "Marks - 95%" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /public/profile/about.json: -------------------------------------------------------------------------------- 1 | { 2 | "about": " This is where you can describe about **yourself**. The more you describe about yourself, the better it is!\n\n\nExtra Information about you, like hobbies and your goals.\nExample Paragraph: I am passionate about my work. Because I love what I do, I have a steady source of motivation that drives me to do my best. In my last job, this passion led me to challenge myself daily and learn new skills that helped me to do better work. For example, I taught myself how to use Photoshop to improve the quality of our photos and graphics. I soon became the go-to person for any design needs.", 3 | "imageSource": "images/about/profile.png" 4 | 5 | } -------------------------------------------------------------------------------- /public/profile/routes.json: -------------------------------------------------------------------------------- 1 | { 2 | "sections": [ 3 | { 4 | "component": "About", 5 | "path": "/about", 6 | "headerTitle": "About" 7 | }, 8 | { 9 | "component": "Skills", 10 | "path": "/skills", 11 | "headerTitle": "Skills" 12 | }, 13 | { 14 | "component": "Education", 15 | "path": "/education", 16 | "headerTitle": "Education" 17 | }, 18 | { 19 | "component": "Experience", 20 | "path": "/experience", 21 | "headerTitle": "Experience" 22 | }, 23 | { 24 | "component": "Projects", 25 | "path": "/projects", 26 | "headerTitle": "Projects" 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './App.css'; 3 | import 'bootstrap/dist/css/bootstrap.min.css'; 4 | import { BrowserRouter } from 'react-router-dom'; 5 | import { ThemeProvider } from 'styled-components'; 6 | import useDarkMode from 'use-dark-mode'; 7 | import AppContext from './AppContext'; 8 | import MainApp from './MainApp'; 9 | import GlobalStyles from './theme/GlobalStyles'; 10 | import { lightTheme, darkTheme } from './theme/themes'; 11 | 12 | function App() { 13 | window.matchMedia = null; 14 | const darkMode = useDarkMode(true); 15 | 16 | return ( 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 |
25 |
26 |
27 | ); 28 | } 29 | 30 | export default App; 31 | -------------------------------------------------------------------------------- /src/components/ThemeToggler.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import DarkModeToggle from 'react-dark-mode-toggle'; 3 | import PropTypes from 'prop-types'; 4 | import AppContext from '../AppContext'; 5 | 6 | function ThemeToggler(props) { 7 | const { onClick } = props; 8 | const handleOnChange = (darkMode) => { 9 | darkMode.toggle(); 10 | onClick(); 11 | }; 12 | 13 | return ( 14 | <> 15 | 16 | {(values) => ( 17 |
18 | handleOnChange(values.darkMode)} 20 | checked={values.darkMode.value} 21 | size={50} 22 | /> 23 |
24 | )} 25 |
26 | 27 | ); 28 | } 29 | 30 | ThemeToggler.propTypes = { 31 | onClick: PropTypes.func, 32 | }; 33 | ThemeToggler.defaultProps = { 34 | onClick: () => {}, 35 | }; 36 | 37 | export default ThemeToggler; 38 | -------------------------------------------------------------------------------- /public/profile/navbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "logo" : { 3 | "source": "images/logo.png", 4 | "height" : 45, 5 | "width" : 50 6 | }, 7 | "sections": [ 8 | { 9 | "title": "Home", 10 | "href": "/" 11 | }, 12 | { 13 | "title": "About", 14 | "href": "/about" 15 | }, 16 | { 17 | "title": "Skills", 18 | "href": "/skills" 19 | }, 20 | { 21 | "title": "Education", 22 | "href": "/education" 23 | }, 24 | { 25 | "title": "Experience", 26 | "href": "/experience" 27 | }, 28 | { 29 | "title": "Projects", 30 | "href": "/projects" 31 | }, 32 | { 33 | "title": "Resume", 34 | "href": "https://drive.google.com/file/d/13kaPsdMNDsM4LV9g7m5-E5PTildp-yYf/view?usp=sharing", 35 | "type": "link" 36 | } 37 | ] 38 | 39 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Mayank Agarwal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /public/profile/experiences.json: -------------------------------------------------------------------------------- 1 | { 2 | "experiences": [ 3 | { 4 | "title": "Software Engineer", 5 | "subtitle": "XYZ Ltd", 6 | "workType": "Full-time", 7 | "workDescription": [ 8 | "Integrated **2** new product.", 9 | "Worked on adding **def** to **bcd**. Improved speed by 50%." 10 | ], 11 | "dateText": "06/20XX – Present" 12 | }, 13 | { 14 | "title": "Software Engineer", 15 | "subtitle": "XYZ Ltd", 16 | "workType": "Internship", 17 | "workDescription": [ 18 | "Worked on abc." 19 | ], 20 | "dateText": "01/20XX – 05/20XX" 21 | }, 22 | { 23 | "title": "App Developer", 24 | "subtitle": "ABC Pvt Ltd", 25 | "workType": "Freelance", 26 | "workDescription": [ 27 | "Developed the official apps for the startup for both Android and iOS using hybrid framework.", 28 | "Done bcd work." 29 | ], 30 | "dateText": "09/20XX – 01/20YY" 31 | } 32 | ] 33 | } -------------------------------------------------------------------------------- /src/components/Social.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState, useContext } from 'react'; 2 | import { SocialIcon } from 'react-social-icons'; 3 | import { ThemeContext } from 'styled-components'; 4 | import endpoints from '../constants/endpoints'; 5 | 6 | const styles = { 7 | iconStyle: { 8 | marginLeft: 10, 9 | marginRight: 10, 10 | marginBottom: 10, 11 | }, 12 | }; 13 | 14 | function Social() { 15 | const theme = useContext(ThemeContext); 16 | const [data, setData] = useState(null); 17 | 18 | useEffect(() => { 19 | fetch(endpoints.social, { 20 | method: 'GET', 21 | }) 22 | .then((res) => res.json()) 23 | .then((res) => setData(res)) 24 | .catch((err) => err); 25 | }, []); 26 | 27 | return ( 28 |
29 | {data ? data.social.map((social) => ( 30 | 39 | )) : null} 40 |
41 | ); 42 | } 43 | 44 | export default Social; 45 | -------------------------------------------------------------------------------- /src/theme/themes.js: -------------------------------------------------------------------------------- 1 | export const lightTheme = { 2 | background: '#fff', 3 | color: '#121212', 4 | accentColor: '#3D84C6', 5 | chronoTheme: { 6 | cardBgColor: 'white', 7 | cardForeColor: 'black', 8 | titleColor: 'white', 9 | }, 10 | timelineLineColor: '#ccc', 11 | cardBackground: '#fff', 12 | cardFooterBackground: '#f7f7f7', 13 | cardBorderColor: '#00000020', 14 | navbarTheme: { 15 | linkColor: '#dedede', 16 | linkHoverColor: '#fefefe', 17 | linkActiveColor: '#fefefe', 18 | }, 19 | bsPrimaryVariant: 'light', 20 | bsSecondaryVariant: 'dark', 21 | socialIconBgColor: '#121212', 22 | }; 23 | 24 | export const darkTheme = { 25 | background: '#121212', 26 | color: '#eee', 27 | accentColor: '#3D84C6', 28 | chronoTheme: { 29 | cardBgColor: '#1B1B1B', 30 | cardForeColor: '#eee', 31 | titleColor: 'black', 32 | }, 33 | timelineLineColor: '#444', 34 | cardBackground: '#060606', 35 | cardFooterBackground: '#181818', 36 | cardBorderColor: '#ffffff20', 37 | navbarTheme: { 38 | linkColor: '#dedede', 39 | linkHoverColor: '#fefefe', 40 | linkActiveColor: '#fefefe', 41 | }, 42 | bsPrimaryVariant: 'dark', 43 | bsSecondaryVariant: 'light', 44 | socialIconBgColor: '#fefefe', 45 | }; 46 | -------------------------------------------------------------------------------- /src/components/Home.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import Typewriter from 'typewriter-effect'; 3 | import Fade from 'react-reveal'; 4 | import endpoints from '../constants/endpoints'; 5 | import Social from './Social'; 6 | import FallbackSpinner from './FallbackSpinner'; 7 | 8 | const styles = { 9 | nameStyle: { 10 | fontSize: '5em', 11 | }, 12 | inlineChild: { 13 | display: 'inline-block', 14 | }, 15 | mainContainer: { 16 | height: '100%', 17 | display: 'flex', 18 | flexDirection: 'column', 19 | justifyContent: 'center', 20 | alignItems: 'center', 21 | }, 22 | }; 23 | 24 | function Home() { 25 | const [data, setData] = useState(null); 26 | 27 | useEffect(() => { 28 | fetch(endpoints.home, { 29 | method: 'GET', 30 | }) 31 | .then((res) => res.json()) 32 | .then((res) => setData(res)) 33 | .catch((err) => err); 34 | }, []); 35 | 36 | return data ? ( 37 | 38 |
39 |

{data?.name}

40 |
41 |

I'm 

42 | 49 |
50 | 51 |
52 |
53 | ) : ; 54 | } 55 | 56 | export default Home; 57 | -------------------------------------------------------------------------------- /src/MainApp.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, Suspense } from 'react'; 2 | import { Switch, Route } from 'react-router-dom'; 3 | import FallbackSpinner from './components/FallbackSpinner'; 4 | import NavBarWithRouter from './components/NavBar'; 5 | import Home from './components/Home'; 6 | import endpoints from './constants/endpoints'; 7 | 8 | function MainApp() { 9 | const [data, setData] = useState(null); 10 | 11 | useEffect(() => { 12 | fetch(endpoints.routes, { 13 | method: 'GET', 14 | }) 15 | .then((res) => res.json()) 16 | .then((res) => setData(res)) 17 | .catch((err) => err); 18 | }, []); 19 | 20 | return ( 21 |
22 | 23 |
24 | 25 | }> 26 | 27 | {data 28 | && data.sections.map((route) => { 29 | const SectionComponent = React.lazy(() => import('./components/' + route.component)); 30 | return ( 31 | ( 35 | 36 | )} 37 | /> 38 | ); 39 | })} 40 | 41 | 42 |
43 |
44 | ); 45 | } 46 | 47 | export default MainApp; 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "portfolio-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "bootstrap": "^5.1.1", 10 | "prop-types": "^15.7.2", 11 | "react": "^17.0.2", 12 | "react-bootstrap": "^2.0.0-rc.0", 13 | "react-chrono": "^1.12.1", 14 | "react-dark-mode-toggle": "^0.2.0", 15 | "react-dom": "^17.0.2", 16 | "react-markdown": "^7.0.1", 17 | "react-reveal": "^1.2.2", 18 | "react-router": "^5.2.1", 19 | "react-router-dom": "^5.3.0", 20 | "react-scripts": "^5.0.1", 21 | "react-social-icons": "^5.6.1", 22 | "styled-components": "^5.3.1", 23 | "typewriter-effect": "^2.18.2", 24 | "use-dark-mode": "^2.3.1", 25 | "vertical-timeline-component-for-react": "^1.0.7", 26 | "web-vitals": "^1.0.1", 27 | "webpack": "^5.64.4" 28 | }, 29 | "browserslist": { 30 | "production": [ 31 | ">0.2%", 32 | "not dead", 33 | "not op_mini all" 34 | ], 35 | "development": [ 36 | "last 1 chrome version", 37 | "last 1 firefox version", 38 | "last 1 safari version" 39 | ] 40 | }, 41 | "scripts": { 42 | "start": "react-scripts start", 43 | "build": "react-scripts build", 44 | "test": "react-scripts test", 45 | "eject": "react-scripts eject" 46 | }, 47 | "devDependencies": { 48 | "eslint": "^7.32.0", 49 | "eslint-config-airbnb": "^18.2.1", 50 | "eslint-plugin-import": "^2.24.2", 51 | "eslint-plugin-jsx-a11y": "^6.4.1", 52 | "eslint-plugin-react": "^7.26.1", 53 | "eslint-plugin-react-hooks": "^4.2.0", 54 | "react-error-overlay": "6.0.9" 55 | }, 56 | "resolutions": { 57 | "react-error-overlay": "6.0.9" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | Portfolio Website 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/images/skills/c-plus-plus.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/components/About.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import ReactMarkdown from 'react-markdown'; 3 | import { Container, Col, Row } from 'react-bootstrap'; 4 | import PropTypes from 'prop-types'; 5 | import Fade from 'react-reveal'; 6 | import Header from './Header'; 7 | import endpoints from '../constants/endpoints'; 8 | import FallbackSpinner from './FallbackSpinner'; 9 | 10 | const styles = { 11 | introTextContainer: { 12 | margin: 10, 13 | flexDirection: 'column', 14 | whiteSpace: 'pre-wrap', 15 | textAlign: 'left', 16 | fontSize: '1.2em', 17 | fontWeight: 500, 18 | }, 19 | introImageContainer: { 20 | margin: 10, 21 | justifyContent: 'center', 22 | alignItems: 'center', 23 | display: 'flex', 24 | }, 25 | }; 26 | 27 | function About(props) { 28 | const { header } = props; 29 | const [data, setData] = useState(null); 30 | 31 | const parseIntro = (text) => ( 32 | 35 | ); 36 | 37 | useEffect(() => { 38 | fetch(endpoints.about, { 39 | method: 'GET', 40 | }) 41 | .then((res) => res.json()) 42 | .then((res) => setData(res)) 43 | .catch((err) => err); 44 | }, []); 45 | 46 | return ( 47 | <> 48 |
49 |
50 | 51 | {data 52 | ? ( 53 | 54 | 55 | 56 | {parseIntro(data.about)} 57 | 58 | 59 | profile 60 | 61 | 62 | 63 | ) 64 | : } 65 | 66 |
67 | 68 | ); 69 | } 70 | 71 | About.propTypes = { 72 | header: PropTypes.string.isRequired, 73 | }; 74 | 75 | export default About; 76 | -------------------------------------------------------------------------------- /public/profile/skills.json: -------------------------------------------------------------------------------- 1 | { 2 | "intro": "I love to learn new things and experiment with new technologies.\nThese are some of the major languages, technologies, tools and platforms I have worked with:", 3 | "skills": [{ 4 | 5 | "title": "Languages & Databases", 6 | "items" : [ 7 | 8 | { 9 | "icon": "images/skills/java.png", 10 | "title": "Java" 11 | }, 12 | { 13 | "icon": "images/skills/php.png", 14 | "title": "PHP" 15 | }, 16 | { 17 | "icon": "images/skills/js.png", 18 | "title": "JavaScript" 19 | }, 20 | { 21 | "icon": "images/skills/python.png", 22 | "title": "Python" 23 | }, 24 | { 25 | "icon": "images/skills/mysql.png", 26 | "title": "MySQL" 27 | } 28 | ]}, 29 | { 30 | "title": "Frameworks & Technologies", 31 | "items" : [ 32 | { 33 | "icon": "images/skills/android_new.png", 34 | "title": "Android" 35 | }, 36 | { 37 | "icon": "images/skills/react.png", 38 | "title": "React" 39 | }, 40 | { 41 | "icon": "images/skills/nodejs.png", 42 | "title": "Nodejs" 43 | } 44 | ] 45 | }, 46 | { 47 | "title" : "Tools & Platforms", 48 | "items": [ 49 | { 50 | "icon": "images/skills/android-studio.png", 51 | "title": "Android Studio" 52 | }, 53 | { 54 | "icon": "images/skills/git.png", 55 | "title": "Git" 56 | }, 57 | { 58 | "icon": "images/skills/docker.png", 59 | "title": "Docker" 60 | } 61 | ] 62 | } 63 | ]} -------------------------------------------------------------------------------- /src/components/Skills.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import ReactMarkdown from 'react-markdown'; 3 | import PropTypes from 'prop-types'; 4 | import Fade from 'react-reveal'; 5 | import { Container } from 'react-bootstrap'; 6 | import Header from './Header'; 7 | import endpoints from '../constants/endpoints'; 8 | import FallbackSpinner from './FallbackSpinner'; 9 | 10 | const styles = { 11 | iconStyle: { 12 | height: 75, 13 | width: 75, 14 | margin: 10, 15 | marginBottom: 0, 16 | }, 17 | introTextContainer: { 18 | whiteSpace: 'pre-wrap', 19 | }, 20 | }; 21 | 22 | function Skills(props) { 23 | const { header } = props; 24 | const [data, setData] = useState(null); 25 | 26 | const renderSkillsIntro = (intro) => ( 27 |

28 | 29 |

30 | ); 31 | 32 | useEffect(() => { 33 | fetch(endpoints.skills, { 34 | method: 'GET', 35 | }) 36 | .then((res) => res.json()) 37 | .then((res) => setData(res)) 38 | .catch((err) => err); 39 | }, []); 40 | 41 | return ( 42 | <> 43 |
44 | {data ? ( 45 | 46 |
47 | 48 | {renderSkillsIntro(data.intro)} 49 | {data.skills?.map((rows) => ( 50 |
51 |
52 |

{rows.title}

53 | {rows.items.map((item) => ( 54 |
55 | {item.title} 60 |

{item.title}

61 |
62 | ))} 63 |
64 | ))} 65 |
66 |
67 |
68 | ) : } 69 | 70 | ); 71 | } 72 | 73 | Skills.propTypes = { 74 | header: PropTypes.string.isRequired, 75 | }; 76 | 77 | export default Skills; 78 | -------------------------------------------------------------------------------- /src/components/Projects.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useContext } from 'react'; 2 | import { Container, Row, Button } from 'react-bootstrap'; 3 | import { ThemeContext } from 'styled-components'; 4 | import PropTypes from 'prop-types'; 5 | import Fade from 'react-reveal/Fade'; 6 | import Header from './Header'; 7 | import endpoints from '../constants/endpoints'; 8 | import ProjectCard from './projects/ProjectCard'; 9 | import FallbackSpinner from './FallbackSpinner'; 10 | 11 | const styles = { 12 | containerStyle: { 13 | marginBottom: 25, 14 | }, 15 | showMoreStyle: { 16 | margin: 25, 17 | }, 18 | }; 19 | 20 | const Projects = (props) => { 21 | const theme = useContext(ThemeContext); 22 | const { header } = props; 23 | const [data, setData] = useState(null); 24 | const [showMore, setShowMore] = useState(false); 25 | 26 | useEffect(() => { 27 | fetch(endpoints.projects, { 28 | method: 'GET', 29 | }) 30 | .then((res) => res.json()) 31 | .then((res) => setData(res)) 32 | .catch((err) => err); 33 | }, []); 34 | const numberOfItems = showMore && data ? data.length : 6; 35 | return ( 36 | <> 37 |
38 | {data 39 | ? ( 40 |
41 | 42 | 43 | {data.projects?.slice(0, numberOfItems).map((project) => ( 44 | 45 | 46 | 47 | ))} 48 | 49 | 50 | {!showMore 51 | && ( 52 | 59 | )} 60 | 61 |
62 | ) : } 63 | 64 | ); 65 | }; 66 | 67 | Projects.propTypes = { 68 | header: PropTypes.string.isRequired, 69 | }; 70 | 71 | export default Projects; 72 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Education.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState, useContext } from 'react'; 2 | import { Chrono } from 'react-chrono'; 3 | import { Container } from 'react-bootstrap'; 4 | import PropTypes from 'prop-types'; 5 | import Fade from 'react-reveal'; 6 | import { ThemeContext } from 'styled-components'; 7 | import endpoints from '../constants/endpoints'; 8 | import Header from './Header'; 9 | import FallbackSpinner from './FallbackSpinner'; 10 | import '../css/education.css'; 11 | 12 | function Education(props) { 13 | const theme = useContext(ThemeContext); 14 | const { header } = props; 15 | const [data, setData] = useState(null); 16 | const [width, setWidth] = useState('50vw'); 17 | const [mode, setMode] = useState('VERTICAL_ALTERNATING'); 18 | 19 | useEffect(() => { 20 | fetch(endpoints.education, { 21 | method: 'GET', 22 | }) 23 | .then((res) => res.json()) 24 | .then((res) => setData(res)) 25 | .catch((err) => err); 26 | 27 | if (window?.innerWidth < 576) { 28 | setMode('VERTICAL'); 29 | } 30 | 31 | if (window?.innerWidth < 576) { 32 | setWidth('90vw'); 33 | } else if (window?.innerWidth >= 576 && window?.innerWidth < 768) { 34 | setWidth('90vw'); 35 | } else if (window?.innerWidth >= 768 && window?.innerWidth < 1024) { 36 | setWidth('75vw'); 37 | } else { 38 | setWidth('50vw'); 39 | } 40 | }, []); 41 | 42 | return ( 43 | <> 44 |
45 | {data ? ( 46 | 47 |
48 | 49 | 64 |
65 | {data.education.map((education) => (education.icon ? ( 66 | {education.icon.alt} 71 | ) : null))} 72 |
73 |
74 |
75 |
76 |
77 | ) : } 78 | 79 | ); 80 | } 81 | 82 | Education.propTypes = { 83 | header: PropTypes.string.isRequired, 84 | }; 85 | 86 | export default Education; 87 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | 2 | .App { 3 | text-align: center; 4 | align-items: center; 5 | justify-content: center; 6 | display: flex; 7 | height: 100vh; 8 | flex-direction: row; 9 | } 10 | 11 | .navbar-custom { 12 | font-size:large; 13 | } 14 | 15 | .navbar__link { 16 | margin-left: 0.75em; 17 | margin-right: 0.75em; 18 | font-size: 1em; 19 | cursor: pointer; 20 | text-decoration: none; 21 | letter-spacing: .1em; 22 | text-indent: .3em; 23 | border-bottom: 3px solid transparent; 24 | } 25 | 26 | .navbar__link::after { 27 | transition: all ease-in-out .2s; 28 | background: none repeat scroll 0 0; 29 | content: ""; 30 | display: block; 31 | margin-top: 2px; 32 | height: 3px; 33 | width: 0; 34 | } 35 | 36 | .navbar__link:hover::after { 37 | visibility: visible; 38 | width: 40%; 39 | } 40 | 41 | .navbar__link--active::after { 42 | transition: all ease-in-out .2s; 43 | width: 100%; 44 | } 45 | 46 | .navbar__link--active:hover::after { 47 | width: 100%; 48 | } 49 | 50 | .MainApp { 51 | margin-top: 8vh; 52 | height: 90vh; 53 | } 54 | 55 | .main { 56 | display: flex; 57 | flex-direction: column; 58 | height: 100%; 59 | } 60 | 61 | .section-content-container { 62 | display: flex; 63 | flex-direction: column; 64 | flex-grow: 1; 65 | justify-content: center; 66 | align-items: center; 67 | } 68 | 69 | .Typewriter { 70 | display: inline-block; 71 | } 72 | 73 | .Typewriter__wrapper { 74 | font-size: xx-large; 75 | font-weight: bold; 76 | } 77 | 78 | .Typewriter__cursor { 79 | font-size: xx-large; 80 | font-weight: bold; 81 | } 82 | 83 | section.timeline-card-content { 84 | justify-content: center; 85 | } 86 | 87 | section.timeline-card-content p.card-title { 88 | font-size: 1.5em; 89 | margin-top: 25px; 90 | } 91 | 92 | section.timeline-card-content p.card-sub-title { 93 | font-size: 1.25em; 94 | margin-top: 10px; 95 | } 96 | 97 | section.timeline-card-content div.card-description > p { 98 | font-size: 1.1em; 99 | margin-top: 10px; 100 | font-weight: 500; 101 | } 102 | 103 | .social { 104 | position: relative; 105 | margin-top: 60px; 106 | } 107 | 108 | 109 | @media only screen and (min-width: 768px) and (max-width: 992px) { 110 | 111 | .navbar__link { 112 | margin-left: 0.4em; 113 | margin-right: 0.4em; 114 | font-size: 0.9em; 115 | cursor: pointer; 116 | letter-spacing: .1em; 117 | text-indent: .2em; 118 | } 119 | } 120 | 121 | @media (max-width: 768px) { 122 | 123 | .navbar__link::after { 124 | background: none; 125 | content: ""; 126 | display: none; 127 | margin-top: 0; 128 | height: 0; 129 | width: 0; 130 | } 131 | 132 | .navbar__link--active::after { 133 | width: 0; 134 | } 135 | 136 | .navbar__link--active:hover::after { 137 | width: 0; 138 | } 139 | 140 | .navbar__link:hover::after { 141 | width: 0; 142 | } 143 | } 144 | 145 | .header { 146 | font-size: 3em; 147 | font-weight: bold; 148 | margin-bottom: 25px; 149 | } 150 | 151 | -------------------------------------------------------------------------------- /src/components/projects/ProjectCard.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import { 3 | Button, Card, Badge, Col, 4 | } from 'react-bootstrap'; 5 | import PropTypes from 'prop-types'; 6 | import { ThemeContext } from 'styled-components'; 7 | import ReactMarkdown from 'react-markdown'; 8 | 9 | const styles = { 10 | badgeStyle: { 11 | paddingLeft: 10, 12 | paddingRight: 10, 13 | paddingTop: 5, 14 | paddingBottom: 5, 15 | margin: 5, 16 | }, 17 | cardStyle: { 18 | borderRadius: 10, 19 | }, 20 | cardTitleStyle: { 21 | fontSize: 24, 22 | fontWeight: 700, 23 | }, 24 | cardTextStyle: { 25 | textAlign: 'left', 26 | }, 27 | linkStyle: { 28 | textDecoration: 'none', 29 | padding: 10, 30 | }, 31 | buttonStyle: { 32 | margin: 5, 33 | }, 34 | }; 35 | 36 | const ProjectCard = (props) => { 37 | const theme = useContext(ThemeContext); 38 | const parseBodyText = (text) => ; 39 | 40 | const { project } = props; 41 | 42 | return ( 43 | 44 | 52 | 53 | 54 | {project.title} 55 | 56 | {parseBodyText(project.bodyText)} 57 | 58 | 59 | 60 | 61 | {project?.links?.map((link) => ( 62 | 70 | ))} 71 | 72 | {project.tags && ( 73 | 74 | {project.tags.map((tag) => ( 75 | 82 | {tag} 83 | 84 | ))} 85 | 86 | )} 87 | 88 | 89 | ); 90 | }; 91 | 92 | ProjectCard.propTypes = { 93 | project: PropTypes.shape({ 94 | title: PropTypes.string.isRequired, 95 | bodyText: PropTypes.string.isRequired, 96 | image: PropTypes.string, 97 | links: PropTypes.arrayOf(PropTypes.shape({ 98 | text: PropTypes.string.isRequired, 99 | href: PropTypes.string.isRequired, 100 | })), 101 | tags: PropTypes.arrayOf(PropTypes.string), 102 | }).isRequired, 103 | }; 104 | 105 | export default ProjectCard; 106 | -------------------------------------------------------------------------------- /src/components/Experience.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState, useContext } from 'react'; 2 | import { Timeline, TimelineItem } from 'vertical-timeline-component-for-react'; 3 | import { Container } from 'react-bootstrap'; 4 | import ReactMarkdown from 'react-markdown'; 5 | import PropTypes from 'prop-types'; 6 | import { ThemeContext } from 'styled-components'; 7 | import Fade from 'react-reveal'; 8 | import Header from './Header'; 9 | import endpoints from '../constants/endpoints'; 10 | import FallbackSpinner from './FallbackSpinner'; 11 | import '../css/experience.css'; 12 | 13 | const styles = { 14 | ulStyle: { 15 | listStylePosition: 'outside', 16 | paddingLeft: 20, 17 | }, 18 | subtitleContainerStyle: { 19 | marginTop: 10, 20 | marginBottom: 10, 21 | }, 22 | subtitleStyle: { 23 | display: 'inline-block', 24 | }, 25 | inlineChild: { 26 | display: 'inline-block', 27 | }, 28 | itemStyle: { 29 | marginBottom: 10, 30 | }, 31 | }; 32 | 33 | function Experience(props) { 34 | const theme = useContext(ThemeContext); 35 | const { header } = props; 36 | const [data, setData] = useState(null); 37 | 38 | useEffect(() => { 39 | fetch(endpoints.experiences, { 40 | method: 'GET', 41 | }) 42 | .then((res) => res.json()) 43 | .then((res) => setData(res.experiences)) 44 | .catch((err) => err); 45 | }, []); 46 | 47 | return ( 48 | <> 49 |
50 | 51 | {data 52 | ? ( 53 |
54 | 55 | 58 | {data.map((item) => ( 59 | 60 | 67 |

68 | {item.title} 69 |

70 |
71 |

72 | {item.subtitle} 73 |

74 | {item.workType && ( 75 |
76 |  · 77 | {' '} 78 | {item.workType} 79 |
80 | )} 81 |
82 |
    83 | {item.workDescription.map((point) => ( 84 |
    85 |
  • 86 | 92 |
  • 93 |
    94 |
    95 | ))} 96 |
97 |
98 |
99 | ))} 100 |
101 |
102 |
103 | ) : } 104 | 105 | ); 106 | } 107 | 108 | Experience.propTypes = { 109 | header: PropTypes.string.isRequired, 110 | }; 111 | 112 | export default Experience; 113 | -------------------------------------------------------------------------------- /src/components/NavBar.jsx: -------------------------------------------------------------------------------- 1 | import { Navbar, Nav, Container } from 'react-bootstrap'; 2 | import React, { useEffect, useState, useContext } from 'react'; 3 | import { withRouter } from 'react-router'; 4 | import { NavLink } from 'react-router-dom'; 5 | import styled, { ThemeContext } from 'styled-components'; 6 | import endpoints from '../constants/endpoints'; 7 | import ThemeToggler from './ThemeToggler'; 8 | 9 | const styles = { 10 | logoStyle: { 11 | width: 50, 12 | height: 40, 13 | }, 14 | }; 15 | 16 | const ExternalNavLink = styled.a` 17 | color: ${(props) => props.theme.navbarTheme.linkColor}; 18 | &:hover { 19 | color: ${(props) => props.theme.navbarTheme.linkHoverColor}; 20 | } 21 | &::after { 22 | background-color: ${(props) => props.theme.accentColor}; 23 | } 24 | `; 25 | 26 | const InternalNavLink = styled(NavLink)` 27 | color: ${(props) => props.theme.navbarTheme.linkColor}; 28 | &:hover { 29 | color: ${(props) => props.theme.navbarTheme.linkHoverColor}; 30 | } 31 | &::after { 32 | background-color: ${(props) => props.theme.accentColor}; 33 | } 34 | &.navbar__link--active { 35 | color: ${(props) => props.theme.navbarTheme.linkActiveColor}; 36 | } 37 | `; 38 | 39 | const NavBar = () => { 40 | const theme = useContext(ThemeContext); 41 | const [data, setData] = useState(null); 42 | const [expanded, setExpanded] = useState(false); 43 | 44 | useEffect(() => { 45 | fetch(endpoints.navbar, { 46 | method: 'GET', 47 | }) 48 | .then((res) => res.json()) 49 | .then((res) => setData(res)) 50 | .catch((err) => err); 51 | }, []); 52 | 53 | return ( 54 | 62 | 63 | {data?.logo && ( 64 | 65 | main logo 75 | 76 | )} 77 | setExpanded(!expanded)} 80 | /> 81 | 82 |