├── Devfolio Performance.png
├── LICENSE
├── README.md
├── gatsby-browser.js
├── gatsby-node.js
└── src
├── components
├── Blog.js
├── Blogs.js
├── Footer.js
├── Hero.js
├── Interests.js
├── Jobs.js
├── Layout.js
├── Navbar.js
├── Project.js
├── Projects.js
├── Quotes.js
├── Radar.js
├── SEO.js
├── Services.js
├── Sidebar.js
└── Title.js
├── pages
├── 404.js
├── about.js
├── blog.js
├── contact.js
├── index.js
└── projects.js
└── templates
└── blog-template.js
/Devfolio Performance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/engineeringwitharavind/devfolio/e565c277e298c45669c038f1332e49193f448259/Devfolio Performance.png
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Aravind
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## devfolio
2 |
3 | > Built 🛠 a personal Portfolio using React, Gatsby, and Strapi.
4 |
5 | #### Tech Stack
6 |
7 | [](https://github.com/engineeringwitharavind/devFolio/blob/master/LICENSE)
8 | [](https://www.npmjs.com/package/npm)
9 | [](https://reactjs.org/)
10 | [](https://graphql.org/)
11 | [](https://www.gatsbyjs.com/)
12 | [](https://strapi.io/)
13 | [](https://react-icons.github.io/react-icons/)
14 |
15 | 
16 |
17 | 
18 |
--------------------------------------------------------------------------------
/gatsby-browser.js:
--------------------------------------------------------------------------------
1 | import "./src/css/main.css";
2 |
--------------------------------------------------------------------------------
/gatsby-node.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 |
3 | // create pages dynamically
4 | exports.createPages = async ({ graphql, actions }) => {
5 | const { createPage } = actions;
6 | const result = await graphql(`
7 | {
8 | blogs: allStrapiBlogs {
9 | nodes {
10 | slug
11 | }
12 | }
13 | }
14 | `);
15 |
16 | result.data.blogs.nodes.forEach((blog) => {
17 | createPage({
18 | path: `/blogs/${blog.slug}`,
19 | component: path.resolve(`src/templates/blog-template.js`),
20 | context: {
21 | slug: blog.slug,
22 | },
23 | });
24 | });
25 | };
26 |
--------------------------------------------------------------------------------
/src/components/Blog.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import Image from "gatsby-image";
4 | import { Link } from "gatsby";
5 |
6 | const Blog = ({ id, title, image, date, stack, slug, desc }) => {
7 | return (
8 |
14 |
15 | {image && (
16 |
17 | )}
18 |
19 |
{title}
20 |
{desc}
21 |
22 | {stack.map((item) => {
23 | return
{item.title} ;
24 | })}
25 |
{date}
26 |
27 |
28 |
29 |
30 | );
31 | };
32 |
33 | Blog.propTypes = {
34 | id: PropTypes.string.isRequired,
35 | title: PropTypes.string.isRequired,
36 | date: PropTypes.string.isRequired,
37 | stack: PropTypes.string.isRequired,
38 | desc: PropTypes.string.isRequired,
39 | slug: PropTypes.string.isRequired,
40 | image: PropTypes.object.isRequired,
41 | };
42 |
43 | export default Blog;
44 |
--------------------------------------------------------------------------------
/src/components/Blogs.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Title from "./Title";
3 | import Blog from "./Blog";
4 | import { Link } from "gatsby";
5 |
6 | export const Blogs = ({ blogs, title, showLink }) => {
7 | return (
8 |
9 |
10 |
11 | {blogs.map((blog) => {
12 | return ;
13 | })}
14 |
15 | {showLink && (
16 |
21 | all articles
22 |
23 | )}
24 |
25 | );
26 | };
27 |
28 | export default Blogs;
29 |
--------------------------------------------------------------------------------
/src/components/Footer.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import SocialLinks from "../constants/socialLinks";
3 | import { GrGatsbyjs } from "react-icons/gr";
4 | // npm install --save-dev @iconify/react @iconify/icons-simple-icons
5 | import { Icon } from "@iconify/react";
6 | import netlifyIcon from "@iconify/icons-simple-icons/netlify";
7 | import { FaReact } from "react-icons/fa";
8 |
9 | const Footer = () => {
10 | return (
11 |
23 | );
24 | };
25 |
26 | export default Footer;
27 |
--------------------------------------------------------------------------------
/src/components/Hero.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Image from "gatsby-image";
3 | import { Link } from "gatsby";
4 | import TextLoop from "react-text-loop";
5 | import { graphql, useStaticQuery } from "gatsby";
6 | import SocialLinks from "../constants/socialLinks";
7 | // ...GatsbyImageSharpFluid
8 |
9 | const query = graphql`
10 | {
11 | file(relativePath: { eq: "hero-img.png" }) {
12 | childImageSharp {
13 | fluid {
14 | ...GatsbyImageSharpFluid
15 | }
16 | }
17 | }
18 | }
19 | `;
20 |
21 | const Hero = () => {
22 | const {
23 | file: {
24 | childImageSharp: { fluid },
25 | },
26 | } = useStaticQuery(query);
27 |
28 | return (
29 |
30 |
31 |
32 |
33 |
34 |
35 |
I'm Aravind
36 |
37 | A{" "}
38 |
39 | self-taught
40 | passionate
41 | pragmatic
42 | {" "}
43 | Software engineer
44 |
45 |
46 | Contact me
47 |
48 |
49 |
50 |
51 |
52 |
53 | );
54 | };
55 |
56 | export default Hero;
57 |
--------------------------------------------------------------------------------
/src/components/Interests.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Title from "./Title";
3 | import interests from "../constants/interests";
4 |
5 | const Interests = () => {
6 | return (
7 |
8 |
9 |
10 | {interests.map((interest) => {
11 | const { id, icon, title, text } = interest;
12 |
13 | return (
14 |
15 | {icon}
16 | {title}
17 |
18 | {text}
19 |
20 | );
21 | })}
22 |
23 |
24 | );
25 | };
26 |
27 | export default Interests;
28 |
--------------------------------------------------------------------------------
/src/components/Jobs.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Title from "./Title";
3 | import { FaAngleDoubleRight } from "react-icons/fa";
4 | import { graphql, useStaticQuery } from "gatsby";
5 |
6 | const query = graphql`
7 | {
8 | allStrapiJobs(sort: { fields: strapiId, order: DESC }) {
9 | nodes {
10 | strapiId
11 | company
12 | date
13 | position
14 | desc {
15 | id
16 | name
17 | }
18 | }
19 | }
20 | }
21 | `;
22 |
23 | const Jobs = () => {
24 | const data = useStaticQuery(query);
25 | const {
26 | allStrapiJobs: { nodes: jobs },
27 | } = data;
28 | const [value, setValue] = React.useState(0);
29 | const { company, position, date, desc } = jobs[value];
30 |
31 | return (
32 |
33 |
34 |
35 | {/* btn container */}
36 |
37 | {jobs.map((item, index) => {
38 | return (
39 | setValue(index)}
43 | className={`job-btn ${index === value && "active-btn"}`}
44 | >
45 | {item.company}
46 |
47 | );
48 | })}
49 |
50 | {/* job info */}
51 |
52 | {position}
53 | {company}
54 | {date}
55 | {desc.map((item) => {
56 | return (
57 |
58 |
59 |
{item.name}
60 |
61 | );
62 | })}
63 |
64 |
65 |
66 | );
67 | };
68 |
69 | export default Jobs;
70 |
--------------------------------------------------------------------------------
/src/components/Layout.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | // import "../css/main.css"
3 | import Navbar from "./Navbar";
4 | import Sidebar from "./Sidebar";
5 | import Footer from "./Footer";
6 |
7 | const Layout = ({ children }) => {
8 | const [isOpen, setIsOpen] = React.useState(false);
9 |
10 | const toggleSidebar = () => {
11 | setIsOpen(!isOpen);
12 | };
13 |
14 | return (
15 | <>
16 |
17 |
18 | {children}
19 |
20 | >
21 | );
22 | };
23 |
24 | export default Layout;
25 |
--------------------------------------------------------------------------------
/src/components/Navbar.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import logo from "../assets/aravind-logo.svg";
3 | import { FaAlignRight } from "react-icons/fa";
4 | import PageLinks from "../constants/links";
5 |
6 | const Navbar = ({ toggleSidebar }) => {
7 | return (
8 |
9 |
10 |
11 |
12 |
18 |
19 |
20 |
21 |
25 |
26 |
27 | );
28 | };
29 |
30 | export default Navbar;
31 |
--------------------------------------------------------------------------------
/src/components/Project.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import Image from "gatsby-image";
4 | import { FaGithub, FaExternalLinkAlt } from "react-icons/fa";
5 |
6 | const Project = ({ description, title, github, stack, url, image }) => {
7 | return (
8 |
9 | {image && (
10 |
11 | )}
12 |
13 |
{title}
14 |
{description}
15 |
16 | {stack.map((item) => {
17 | return {item.title} ;
18 | })}
19 |
20 |
38 |
39 |
40 | );
41 | };
42 |
43 | // For Projects Number => 0{index + 1}.
44 |
45 | Project.propTypes = {
46 | title: PropTypes.string.isRequired,
47 | github: PropTypes.string.isRequired,
48 | url: PropTypes.string.isRequired,
49 | description: PropTypes.string.isRequired,
50 | image: PropTypes.object.isRequired,
51 | stack: PropTypes.arrayOf(PropTypes.object).isRequired,
52 | };
53 |
54 | export default Project;
55 |
--------------------------------------------------------------------------------
/src/components/Projects.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Title from "./Title";
3 | import Project from "./Project";
4 | import { Link } from "gatsby";
5 | const Projects = ({ projects, title, showLink }) => {
6 | return (
7 |
8 |
9 |
10 | {projects.map((project, index) => {
11 | return
;
12 | })}
13 |
14 | {showLink && (
15 |
20 | view all projects
21 |
22 | )}
23 |
24 | );
25 | };
26 |
27 | export default Projects;
28 |
--------------------------------------------------------------------------------
/src/components/Quotes.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Title from "./Title"
3 | import { FaQuoteLeft } from "react-icons/fa";
4 |
5 | const Quotes = () => {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 | Your work is going to fill a large part of your life, and
13 | the only way to be truly satisfied is to do what you believe
14 | is great work. And the only way to do great work is to love
15 | what you do. If you haven’t found it yet, keep looking.
16 | Don’t settle. As with all matters of the heart, you’ll know
17 | when you find it.
18 |
19 |
- Steve Jobs
20 |
21 |
22 | )
23 | }
24 |
25 | export default Quotes;
--------------------------------------------------------------------------------
/src/components/Radar.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { Radar } from "react-chartjs-2";
3 | import Title from "./Title";
4 |
5 | const ChartData = () => {
6 | const [chartData, setChartData] = useState({});
7 |
8 | const chart = () => {
9 | setChartData({
10 | labels: [
11 | "HTML5",
12 | "CSS3",
13 | "JavaScript",
14 | "Python",
15 | "Git",
16 | "SQL",
17 | "Gatsby.js",
18 | "MongoDB",
19 | "React.js",
20 | "Node.js",
21 | ],
22 | datasets: [
23 | {
24 | label: "Interests",
25 | backgroundColor: "rgba(73,174,186,0.2)",
26 | borderColor: "rgba(73,174,186,1)",
27 | pointBackgroundColor: "rgba(255,99,132,1)",
28 | pointBorderColor: "#fff",
29 | pointHoverBackgroundColor: "#fff",
30 | pointHoverBorderColor: "rgba(255,99,132,1)",
31 | data: [85, 70, 90, 70, 75, 65, 75, 70, 85, 65],
32 | },
33 | ],
34 | });
35 | };
36 |
37 | const options = {
38 | legend: {
39 | display: false,
40 | },
41 | scale: {
42 | ticks: {
43 | beginAtZero: true,
44 | display: false,
45 | },
46 | },
47 | maintainAspectRatio: false,
48 | };
49 |
50 | useEffect(() => {
51 | chart();
52 | }, []);
53 |
54 | return (
55 |
61 | );
62 | };
63 |
64 | export default ChartData;
65 |
--------------------------------------------------------------------------------
/src/components/SEO.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Helmet } from "react-helmet";
3 | import { useStaticQuery, graphql } from "gatsby";
4 |
5 | const query = graphql`
6 | {
7 | site {
8 | siteMetadata {
9 | author
10 | siteDesc: description
11 | image
12 | siteUrl
13 | siteTitle: title
14 | twitterUsername
15 | }
16 | }
17 | }
18 | `;
19 |
20 | const SEO = ({ title, description }) => {
21 | const { site } = useStaticQuery(query);
22 | const {
23 | siteDesc,
24 | siteTitle,
25 | siteUrl,
26 | image,
27 | author,
28 | twitterUsername,
29 | } = site.siteMetadata;
30 | return (
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | {/* twitter Cards */}
41 |
42 |
43 |
44 |
45 |
46 |
47 | );
48 | };
49 |
50 | export default SEO;
51 |
--------------------------------------------------------------------------------
/src/components/Services.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Title from "./Title";
3 | import services from "../constants/services";
4 | import Radar from "./Radar";
5 |
6 | const Services = () => {
7 | return (
8 |
9 |
10 |
11 | {services.map((service) => {
12 | const { id, icon, title, text } = service;
13 |
14 | return (
15 |
16 | {icon}
17 | {title}
18 |
19 | {text}
20 |
21 | );
22 | })}
23 |
24 |
25 |
26 | );
27 | };
28 |
29 | export default Services;
30 |
--------------------------------------------------------------------------------
/src/components/Sidebar.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Links from "../constants/links";
3 | import SocialLinks from "../constants/socialLinks";
4 | import { FaTimes } from "react-icons/fa";
5 |
6 | const Sidebar = ({ isOpen, toggleSidebar }) => {
7 | return (
8 |
9 |
14 |
15 |
16 |
17 |
21 |
25 |
26 |
27 | );
28 | };
29 |
30 | export default Sidebar;
31 |
--------------------------------------------------------------------------------
/src/components/Title.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const Title = ({ title }) => {
4 | return (
5 |
6 |
{title || "default title"}
7 |
8 |
9 | );
10 | };
11 |
12 | export default Title;
13 |
--------------------------------------------------------------------------------
/src/pages/404.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Layout from "../components/Layout";
3 | import { Link } from "gatsby";
4 | import SEO from "../components/SEO";
5 |
6 | const Error = () => {
7 | return (
8 |
9 |
13 |
14 | oops! it's a dead end
15 |
16 | back to home
17 |
18 |
19 |
20 | );
21 | };
22 |
23 | export default Error;
24 |
--------------------------------------------------------------------------------
/src/pages/about.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Layout from "../components/Layout";
3 | import { graphql } from "gatsby";
4 | import Title from "../components/Title";
5 | import Image from "gatsby-image";
6 | import ReactMarkdown from "react-markdown";
7 | import Interests from "../components/Interests";
8 | import SEO from "../components/SEO";
9 | import Quotes from "../components/Quotes";
10 | // ...GatsbyImageSharpFluid
11 |
12 | const About = ({
13 | data: {
14 | about: { nodes },
15 | },
16 | }) => {
17 | const { info, stack, title, image } = nodes[0];
18 |
19 | return (
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | {stack.map((item) => {
30 | return {item.title} ;
31 | })}
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | );
40 | };
41 |
42 | export const query = graphql`
43 | {
44 | about: allStrapiAbout {
45 | nodes {
46 | stack {
47 | id
48 | title
49 | }
50 | title
51 | info
52 | image {
53 | childImageSharp {
54 | fluid {
55 | ...GatsbyImageSharpFluid
56 | }
57 | }
58 | }
59 | }
60 | }
61 | }
62 | `;
63 |
64 | export default About;
65 |
--------------------------------------------------------------------------------
/src/pages/blog.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Layout from "../components/Layout";
3 | import { graphql } from "gatsby";
4 | import Blogs from "../components/Blogs";
5 | import SEO from "../components/SEO";
6 | // ...GatsbyImageSharpFluid
7 |
8 | const Blog = ({
9 | data: {
10 | allStrapiBlogs: { nodes: blogs },
11 | },
12 | }) => {
13 | return (
14 |
15 |
16 |
19 |
20 | );
21 | };
22 |
23 | export const query = graphql`
24 | {
25 | allStrapiBlogs(sort: { fields: date, order: DESC }, limit: 3) {
26 | nodes {
27 | slug
28 | desc
29 | date(formatString: "MMMM Do, YYYY")
30 | id
31 | title
32 | stack {
33 | id
34 | title
35 | }
36 | image {
37 | childImageSharp {
38 | fluid {
39 | ...GatsbyImageSharpFluid
40 | }
41 | }
42 | }
43 | }
44 | }
45 | }
46 | `;
47 |
48 | export default Blog;
49 |
--------------------------------------------------------------------------------
/src/pages/contact.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Layout from "../components/Layout";
3 | import SEO from "../components/SEO";
4 |
5 | const contact = () => {
6 | return (
7 |
8 |
9 |
10 |
11 | get in touch
12 |
37 |
38 |
39 |
40 | );
41 | };
42 |
43 | export default contact;
44 |
--------------------------------------------------------------------------------
/src/pages/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { graphql } from "gatsby";
3 | import Layout from "../components/Layout";
4 | import Hero from "../components/Hero";
5 | import Services from "../components/Services";
6 | import Jobs from "../components/Jobs";
7 | import Projects from "../components/Projects";
8 | import Blogs from "../components/Blogs";
9 | import SEO from "../components/SEO";
10 |
11 | export default ({ data }) => {
12 | const {
13 | allStrapiProjects: { nodes: projects },
14 | allStrapiBlogs: { nodes: blogs },
15 | } = data;
16 |
17 | return (
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | );
27 | };
28 |
29 | export const query = graphql`
30 | {
31 | allStrapiProjects(filter: { featured: { eq: true } }) {
32 | nodes {
33 | github
34 | id
35 | description
36 | title
37 | url
38 | image {
39 | childImageSharp {
40 | fluid {
41 | ...GatsbyImageSharpFluid
42 | }
43 | }
44 | }
45 | stack {
46 | id
47 | title
48 | }
49 | }
50 | }
51 | allStrapiBlogs(sort: { fields: date, order: DESC }, limit: 3) {
52 | nodes {
53 | slug
54 | content
55 | desc
56 | date(formatString: "MMMM Do, YYYY")
57 | id
58 | title
59 | stack {
60 | id
61 | title
62 | }
63 | image {
64 | childImageSharp {
65 | fluid {
66 | ...GatsbyImageSharpFluid
67 | }
68 | }
69 | }
70 | }
71 | }
72 | }
73 | `;
74 |
--------------------------------------------------------------------------------
/src/pages/projects.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Layout from "../components/Layout";
3 | import { graphql } from "gatsby";
4 | import Projects from "../components/Projects";
5 | import SEO from "../components/SEO";
6 |
7 | const ProjectsPage = ({
8 | data: {
9 | allStrapiProjects: { nodes: projects },
10 | },
11 | }) => {
12 | return (
13 |
14 |
15 |
18 |
19 | );
20 | };
21 |
22 | export const query = graphql`
23 | {
24 | allStrapiProjects {
25 | nodes {
26 | github
27 | id
28 | description
29 | title
30 | url
31 | image {
32 | childImageSharp {
33 | fluid {
34 | ...GatsbyImageSharpFluid
35 | }
36 | }
37 | }
38 | stack {
39 | id
40 | title
41 | }
42 | }
43 | }
44 | }
45 | `;
46 |
47 | export default ProjectsPage;
48 |
--------------------------------------------------------------------------------
/src/templates/blog-template.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { graphql, Link } from "gatsby";
3 | import Layout from "../components/Layout";
4 | import ReactMarkdown from "react-markdown";
5 | import SEO from "../components/SEO";
6 |
7 | const ComponentName = ({ data }) => {
8 | const { content, title, desc } = data.blog;
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | blog
19 |
20 |
21 |
22 |
23 | );
24 | };
25 |
26 | export const query = graphql`
27 | query GetSingleBlog($slug: String) {
28 | blog: strapiBlogs(slug: { eq: $slug }) {
29 | content
30 | title
31 | desc
32 | }
33 | }
34 | `;
35 |
36 | export default ComponentName;
37 |
--------------------------------------------------------------------------------