🛠️ build(static): change from astro to gatsby

This commit is contained in:
Eshan Roy (Eshanized)
2024-06-20 04:16:43 +05:30
parent 1e87593338
commit da74d8c220
62 changed files with 34603 additions and 9054 deletions

167
src/components/about.js Normal file
View File

@@ -0,0 +1,167 @@
import React from 'react'
import styled from 'styled-components'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import bart from '../images/bart.jpg'
const AboutSection = styled.section`
display: flex;
justify-content: center;
align-items: flex-start;
padding: 100px 0;
`
const Container = styled.div`
align-items: center;
flex-direction: row;
justify-content: space-between;
`
const Wrapper = styled.div`
width: 50%;
`
const Title = styled.h2``
const Description = styled.p`
width: 80%;
margin-top: 50px;
color: #bdbdbd;
text-align: left;
`
const List = styled.ul`
list-style: none;
margin: 0;
padding: 0;
display: grid;
grid-template-columns: repeat(2, minmax(140px, 200px));
margin-top: 25px;
`
const Item = styled.li`
position: relative;
font-size: 14px;
color: #bdbdbd;
margin-bottom: 10px;
&:hover {
span {
color: #02d463;
transition: 0.2s;
}
}
.skill__icon {
margin-right: 15px;
color: #02d463;
width: 15px;
height: 15px;
}
&.skill__jquery {
transition: 0.2s;
.skill__icon,
span {
color: #333;
}
span {
text-decoration: line-through;
}
}
`
const ItemText = styled.span``
const Image = styled.img`
opacity: 0.4;
transition: 0.5s;
box-shadow: 0px 0px 20px rgba(0, 0, 0, 1);
border-radius: 4px;
&:hover {
opacity: 1;
transition: 0.5s;
}
`
export default function About() {
return (
<AboutSection id="about">
<div className="container container--secondary">
<Container className="container container--primary about__container">
<Wrapper className="about__wrapper">
<Title>About me</Title>
<Description className="about__desc section__desc">
I began my coding journey in December 2018 as a self-taught developer. My passion lies in crafting modern, visually appealing websites enhanced with subtle animations. I'm deeply committed to my work and always eager to collaborate on exciting projects. If you have an idea or project in mind, I'd love to hear from you!
</Description>
<Description className="section__desc">
Technologies that I use:
</Description>
<List>
<Item>
<FontAwesomeIcon
icon={['fab', 'react']}
className="skill__icon"
/>
<ItemText>React</ItemText>
</Item>
<Item>
<FontAwesomeIcon
icon={['fab', 'node-js']}
className="skill__icon"
/>
<ItemText>Node.js</ItemText>
</Item>
<Item>
<FontAwesomeIcon
icon={['fab', 'js-square']}
className="skill__icon"
/>
<ItemText>JavaScript</ItemText>
</Item>
<Item>
<FontAwesomeIcon
icon={['fab', 'php']}
className="skill__icon"
/>
<ItemText>PHP</ItemText>
</Item>
<Item>
<FontAwesomeIcon
icon={['fab', 'html5']}
className="skill__icon"
/>
<ItemText>HTML</ItemText>
</Item>
<Item>
<FontAwesomeIcon
icon={['fab', 'sass']}
className="skill__icon"
/>
<ItemText>S(CSS)</ItemText>
</Item>
<Item>
<FontAwesomeIcon icon="fire" className="skill__icon" />
<ItemText>Firebase</ItemText>
</Item>
<Item>
<FontAwesomeIcon
icon={['fab', 'bootstrap']}
className="skill__icon"
/>
<ItemText>Bootstrap</ItemText>
</Item>
<Item>
<FontAwesomeIcon
icon={['fab', 'figma']}
className="skill__icon"
/>
<ItemText>Figma</ItemText>
</Item>
<Item className="skill__jquery">
<FontAwesomeIcon icon="cross" className="skill__icon" />
<ItemText>jQuery</ItemText>
</Item>
</List>
</Wrapper>
<Image src={bart} alt="Bart Zalewski" loading="lazy" />
</Container>
</div>
</AboutSection>
)
}

118
src/components/blog.js Normal file
View File

@@ -0,0 +1,118 @@
import React from 'react'
import styled from 'styled-components'
import { Link, graphql, useStaticQuery } from 'gatsby'
const BlogSection = styled.section`
display: flex;
justify-content: center;
align-items: flex-start;
padding: 100px 0;
`
const Container = styled.div`
align-items: flex-end;
`
const Title = styled.h2``
const Description = styled.p`
text-align: center;
margin: 50px 0;
color: #bdbdbd;
`
const List = styled.ul`
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-gap: 20px;
width: 100%;
list-style: none;
margin: 0;
padding: 0;
text-align: left;
margin-bottom: 50px;
`
const Box = styled.li`
background: #111;
border-radius: 4px;
padding: 15px;
transition: 0.4s;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);
opacity: 0.4;
&:hover {
transform: translateY(-10px);
transition: 0.4s;
opacity: 1;
}
`
const Image = styled.img`
width: 100%;
height: 150px;
border-radius: 4px;
object-fit: cover;
`
const PostTitle = styled.p`
font-family: 'JetBrains Mono';
direction: ltr;
margin: 10px 0 5px;
`
const PostTime = styled.p`
font-size: 14px;
color: #bdbdbd;
direction: ltr;
`
export default function Blog() {
const data = useStaticQuery(graphql`
query {
allContentfulBlogPost(
sort: { fields: publishedDate, order: DESC }
limit: 8
) {
edges {
node {
id
title
slug
publishedDate(formatString: "MMMM Do, YYYY")
background {
file {
url
}
}
}
}
}
}
`)
const output = data.allContentfulBlogPost.edges.map((element) => {
const { id, slug, background, title, publishedDate } = element.node
return (
<Box key={id} className="blog__box">
<Link to={`/blog/${slug}`}>
<Image
className="blog__img"
src={background.file.url}
alt={title}
loading="lazy"
/>
<PostTitle className="blog__title">{title}</PostTitle>
<PostTime className="blog__time">{publishedDate}</PostTime>
</Link>
</Box>
)
})
return (
<BlogSection id="blog">
<div className="container container--secondary">
<Container className="container container--primary blog__container">
<Title>Blog</Title>
<Description className="blog__desc section__desc">
Check out my blog!
</Description>
<List className="blog__wrapper">{output}</List>
<Link to="/blog" className="btn btn--primary">
See more
</Link>
</Container>
</div>
</BlogSection>
)
}

View File

@@ -0,0 +1,57 @@
import React from 'react'
import styled from 'styled-components'
import BoardBox from './boardBox'
import grammarlyWebM from '../../images/projects/grammarlydark.webm'
import hoppWebM from '../../images/projects/hopp.webm'
import joindevsWebM from '../../images/projects/joindevs.webm'
import bartzalewskiV2WebM from '../../images/projects/bartzalewski-v2.webm'
const BoardWrapper = styled.div`
width: 100%;
background: #212121;
box-shadow: 0px 0px 40px rgba(0, 0, 0, 0.5);
position: absolute;
left: 15px;
top: -50px;
padding-top: 56.25%;
transform: rotate3d(0.5, -0.866, 0, 15deg) rotate(-1deg);
`
const Grid = styled.div`
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(2, 1fr);
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
outline: 10px solid #222;
`
const Board = () => {
return (
<BoardWrapper className="board__container">
<Grid className="board__grid">
<BoardBox
bgwebm={joindevsWebM}
title="JoinDevs"
url="https://joindevs.com/"
/>
<BoardBox bgwebm={hoppWebM} title="HOPP" url="https://hopp.pl/" />
<BoardBox
bgwebm={grammarlyWebM}
title="Grammarly Dark"
url="https://chrome.google.com/webstore/detail/grammarly-dark/noojmhngiheennhgaffkfboanjpbkpep"
/>
<BoardBox
bgwebm={bartzalewskiV2WebM}
title="Bart Zalewski v2"
url="https://bartzalewski.com/"
/>
</Grid>
</BoardWrapper>
)
}
export default Board

View File

@@ -0,0 +1,100 @@
import React, { useState } from 'react'
import styled from 'styled-components'
import { useSpring, animated as a } from 'react-spring'
const Container = styled.div`
width: 100%;
height: 100%;
background: #111;
border-radius: 4px;
position: relative;
`
const Wrapper = styled.div`
width: 100%;
height: 100%;
position: absolute;
outline: none;
left: -10px;
top: -10px;
filter: drop-shadow(0px 0px 10px rgba(0, 0, 0, 0.5));
.back {
background-size: cover;
background-position: center;
border-radius: 4px;
}
.front {
background: #222;
width: 100%;
height: 100%;
border-radius: 4px;
display: flex;
justify-content: space-evenly;
align-items: center;
flex-direction: column;
}
video,
.back {
position: absolute;
width: 100%;
height: 100%;
object-fit: fill;
will-change: transform, opacity;
}
`
const Source = styled.source``
const Title = styled.p``
const Button = styled.a``
const BoardBox = ({ bgwebm, title, url }) => {
const [flipped, set] = useState(false)
const { transform, opacity } = useSpring({
opacity: flipped ? 1 : 0,
transform: `perspective(600px) rotateX(${flipped ? 180 : 0}deg)`,
config: { mass: 5, tension: 500, friction: 80 },
})
return (
<Container className="board__wrapper">
<Wrapper
className="board__box"
onMouseEnter={() => set((state) => !state)}
onMouseLeave={() => set((state) => !state)}
role="button"
tabIndex="0"
>
<a.video
className="back"
loop={true}
autoPlay={true}
muted={true}
playsInline={true}
style={{
opacity: opacity.interpolate((o) => 1 - o),
transform,
}}
>
<Source src={bgwebm} type="video/webm" />
</a.video>
<a.div
className="front"
style={{
opacity,
transform: transform.interpolate((t) => `${t} rotateX(180deg)`),
}}
>
<Title>{title}</Title>
<Button
className="btn btn--secondary"
href={url}
target="_blank"
rel="noopener noreferrer"
>
View
</Button>
</a.div>
</Wrapper>
</Container>
)
}
export default BoardBox

251
src/components/contact.js Normal file
View File

@@ -0,0 +1,251 @@
import React, { useEffect } from 'react'
import styled from 'styled-components'
import axios from 'axios'
const ContactSection = styled.section`
display: flex;
justify-content: center;
align-items: center;
background: #111;
padding: 100px 0;
`
const Title = styled.h2``
const Description = styled.p`
text-align: center;
margin: 50px 0;
color: #bdbdbd;
`
const Success = styled.span``
const Failure = styled.span``
const Form = styled.form`
margin: 50px 0;
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
.btn {
margin-top: 2rem;
}
input[type='submit'] {
font-family: 'JetBrains Mono';
cursor: pointer;
font-size: inherit;
background: #02d463 !important;
color: inherit;
width: fit-content;
padding: 10px 17.5px;
height: auto;
border: 2px solid #02d463;
border-radius: 4px;
&:hover {
color: #02d463;
background: transparent !important;
}
}
`
const InputField = styled.div`
display: flex;
flex-direction: column;
&.focus input,
&.focus textarea {
border-color: #02d463;
}
&.focus label {
color: #02d463;
transition: 0.2s;
}
`
const InputFieldGrid = styled.div`
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: 10px;
width: 50%;
`
const InputFieldTextarea = styled.div`
margin-top: 1rem;
width: 50%;
&.focus input,
&.focus textarea {
border-color: #02d463;
}
&.focus label {
color: #02d463;
transition: 0.2s;
}
`
const Label = styled.label`
color: #333;
margin-bottom: 0.5rem;
text-shadow: 0px 0px 10px black;
font-size: 14px;
`
const Input = styled.input`
border-radius: 4px;
border: 2px solid #1a1a1a;
height: 60px;
width: 100%;
font-family: 'JetBrains Mono';
background: transparent;
color: #02d463;
transition: 0.2s;
outline: none;
font-size: inherit;
padding: 15px;
background: #1a1a1a;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);
&:focus {
border-color: #02d463;
transition: 0.2s;
}
`
const Textarea = styled.textarea`
border-radius: 4px;
border: 2px solid #1a1a1a;
width: 100%;
font-family: 'JetBrains Mono';
background: transparent;
color: #02d463;
transition: 0.2s;
outline: none;
font-size: inherit;
padding: 15px;
background: #1a1a1a;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);
height: 200px;
resize: none;
margin-top: 6px;
&:focus {
border-color: #02d463;
transition: 0.2s;
}
`
export default function Contact() {
const resetForm = () => document.getElementById('contact-form').reset()
const handleSubmit = (e) => {
e.preventDefault()
const name = document.getElementById('name').value
const email = document.getElementById('email').value
const message = document.getElementById('message').value
const success = document.getElementById('success')
const failure = document.getElementById('failure')
axios({
method: 'POST',
url: 'https://bartzalewski-v2-api.herokuapp.com/send',
data: {
name: name,
email: email,
message: message,
},
}).then((response) => {
if (response.data.msg === 'success') {
success.style.display = 'block'
resetForm()
} else if (response.data.msg === 'fail') {
failure.style.display = 'block'
}
})
}
useEffect(() => {
const inputs = document.querySelectorAll('.input__field-input')
function addcl() {
let parent = this.parentNode
parent.classList.add('focus')
}
function remcl() {
let parent = this.parentNode
if (this.value === '') {
parent.classList.remove('focus')
}
}
inputs.forEach((input) => {
input.addEventListener('focus', addcl)
input.addEventListener('blur', remcl)
})
}, [])
return (
<ContactSection id="contact">
<div className="container container--secondary">
<div className="container container--primary">
<Title>Get in touch</Title>
<Description className="contact__desc section__desc">
Contact me!
</Description>
<Success id="success" className="colored" style={{ display: 'none' }}>
Message sent!
</Success>
<Failure id="failure" style={{ color: '#FF5252', display: 'none' }}>
Message failed to sent!
</Failure>
<Form
onSubmit={handleSubmit}
method="POST"
className="contact__wrapper"
id="contact-form"
>
<InputFieldGrid className="input__field--grid">
<InputField className="input__field">
<Label htmlFor="name">Name</Label>
<Input
aria-label="Name"
required
className="input__field-input"
id="name"
name="name"
type="text"
autoComplete="off"
/>
</InputField>
<InputField className="input__field">
<Label htmlFor="email">Email</Label>
<Input
aria-label="Email"
required
className="input__field-input"
id="email"
name="email"
type="email"
autoComplete="off"
/>
</InputField>
</InputFieldGrid>
<InputFieldTextarea className="input__field input__textarea">
<Label htmlFor="message">Message</Label>
<Textarea
aria-label="Message"
required
className="input__field-input"
id="message"
name="message"
></Textarea>
</InputFieldTextarea>
<Input
aria-label="Submit"
type="submit"
value="Submit"
className="btn btn--primary"
/>
</Form>
</div>
</div>
</ContactSection>
)
}

View File

@@ -0,0 +1,29 @@
import React from 'react'
import { Helmet } from 'react-helmet'
import { useStaticQuery, graphql } from 'gatsby'
const Head = ({ title }) => {
const data = useStaticQuery(graphql`
query {
site {
siteMetadata {
title
}
}
}
`)
return (
<Helmet
title={
title
? `${title} - ${data.site.siteMetadata.title}`
: `${data.site.siteMetadata.title}`
}
>
<meta name="description" content="Bart Zalewski | Front-end Developer" />
</Helmet>
)
}
export default Head

View File

@@ -0,0 +1,37 @@
import React, { useEffect } from 'react'
import GlobalStyle from '../../theme/globalStyle'
import styled from 'styled-components'
import Footer from '../footer'
const LayoutWrapper = styled.div`
display: flex;
flex-direction: column;
min-height: 100vh;
main {
flex-grow: 1;
}
`
const Main = styled.main``
const Layout = ({ children }) => {
if (typeof window !== 'undefined') require('smooth-scroll')('a[href*="#"]')
useEffect(() => {
window.addEventListener('scroll', () => {
const isTop = window.scrollY > 200
const nav = document.getElementById('nav')
if (nav)
isTop ? nav.classList.add('scrolled') : nav.classList.remove('scrolled')
})
}, [])
return (
<LayoutWrapper>
<GlobalStyle />
<Main>{children}</Main>
<Footer />
</LayoutWrapper>
)
}
export default Layout

130
src/components/footer.js Normal file
View File

@@ -0,0 +1,130 @@
import React from 'react'
import styled from 'styled-components'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { OutboundLink } from 'gatsby-plugin-google-analytics'
const FooterWrapper = styled.footer`
height: 100px;
display: flex;
justify-content: center;
align-items: center;
background: #111;
color: white;
border-top: 1px solid #212121;
`
const Container = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
`
const Links = styled.div`
.footer__link {
color: white;
margin-right: 20px;
transition: 0.2s;
&:hover {
color: #02d463;
transition: 0.2s;
}
svg {
width: 20px;
height: 20px;
filter: drop-shadow(0px 0px 3px black);
}
}
`
const Descriptions = styled.div`
.footer__copy {
font-size: 14px;
}
.footer__credit {
font-size: 12px;
color: #333;
}
`
const Description = styled.p``
const Footer = () => {
return (
<FooterWrapper>
<div className="container container--secondary">
<Container className="footer__container container--primary">
<Links className="footer__links">
<OutboundLink
href="https://www.instagram.com/bart.code/"
target="_blank"
rel="noopener noreferrer"
className="footer__link"
title="Instagram"
>
<FontAwesomeIcon
icon={['fab', 'instagram']}
className="about__icon"
/>
</OutboundLink>
<OutboundLink
href="https://github.com/bartzalewski"
target="_blank"
rel="noopener noreferrer"
className="footer__link"
title="GitHub"
>
<FontAwesomeIcon
icon={['fab', 'github']}
className="about__icon"
/>
</OutboundLink>
<OutboundLink
href="https://www.linkedin.com/in/bartzalewski/"
target="_blank"
rel="noopener noreferrer"
className="footer__link"
title="LinkedIn"
>
<FontAwesomeIcon
icon={['fab', 'linkedin']}
className="about__icon"
/>
</OutboundLink>
<a
href="mailto:me@bartzalewski.com"
className="footer__link"
title="Email"
>
<FontAwesomeIcon icon="envelope" />
</a>
<OutboundLink
href="/resume.pdf"
target="_blank"
rel="noopener noreferrer"
className="footer__link"
title="Resume"
>
<FontAwesomeIcon icon="paperclip" />
</OutboundLink>
</Links>
<Descriptions className="footer__desc section__desc">
<Description className="footer__copy">
Copyright {new Date().getFullYear()} &copy; Bart Zalewski
</Description>
<Description className="footer__credit">
Created by{' '}
<a
href="https://github.com/bartzalewski/bartzalewski.com-v2"
target="_blank"
rel="noopener noreferrer"
title="Bart Zalewski | Front-end Developer"
>
Bart Zalewski
</a>
</Description>
</Descriptions>
</Container>
</div>
</FooterWrapper>
)
}
export default Footer

137
src/components/header.js Normal file
View File

@@ -0,0 +1,137 @@
import React, { useState } from 'react'
import styled from 'styled-components'
import { Link } from 'gatsby'
import Scrollspy from 'react-scrollspy'
import Resume from './resume'
const HeaderWrapper = styled.header`
height: 100px;
display: flex;
justify-content: center;
align-items: center;
background: transparent;
width: 100%;
transition: 0.4s;
position: absolute;
`
const Navbar = styled.nav`
display: flex;
justify-content: space-between;
align-items: center;
z-index: 10;
.navbar__logo {
font-family: 'Grand Hotel';
font-size: 36px;
color: white;
transition: 0.2s ease;
text-shadow: 0px 0px 10px black;
&:hover {
color: #02d463;
transition: 0.2s ease;
}
}
`
const LinkItem = styled(Link)`
margin-right: 20px;
transition: 0.2s;
text-shadow: 0px 0px 10px black;
&:hover:not(.navbar__resume) {
color: #02d463;
transition: 0.2s;
}
`
const Header = () => {
const [sidenavOpened, setSidenavOpened] = useState(false)
return (
<HeaderWrapper id="nav">
<Scrollspy
id="sidenav"
className={sidenavOpened ? 'sidenav sidenav--open' : 'sidenav'}
style={{ padding: 0 }}
items={['home', 'about', 'projects', 'blog', 'contact']}
currentClassName="colored"
offset={-60}
>
<LinkItem
href="/#home"
className="navbar__link"
style={{ display: 'none' }}
>
Home
</LinkItem>
<div role="button" onClick={() => setSidenavOpened(!sidenavOpened)}>
<LinkItem href="/#about">About</LinkItem>
</div>
<div role="button" onClick={() => setSidenavOpened(!sidenavOpened)}>
<LinkItem href="/#projects">Projects</LinkItem>
</div>
<div role="button" onClick={() => setSidenavOpened(!sidenavOpened)}>
<LinkItem href="/#blog">Blog</LinkItem>
</div>
<div role="button" onClick={() => setSidenavOpened(!sidenavOpened)}>
<LinkItem href="/#contact">Contact</LinkItem>
</div>
<Resume />
</Scrollspy>
<Navbar id="navbar" className="navbar__container container--secondary">
<LinkItem href="/#" className="navbar__logo">
Bart
</LinkItem>
<div className="hamburger__container">
<button
aria-label="menu"
className="hamburger"
onClick={() => setSidenavOpened(!sidenavOpened)}
onKeyDown={() => setSidenavOpened(!sidenavOpened)}
>
<div
className={
sidenavOpened
? 'hamburger__wrapper icon close'
: 'hamburger__wrapper icon'
}
>
<span className="hamburger--line top"></span>
<span className="hamburger--line middle"></span>
<span className="hamburger--line bottom"></span>
</div>
</button>
</div>
<Scrollspy
className="navbar__links"
items={['home', 'about', 'projects', 'blog', 'contact']}
currentClassName="colored"
offset={-60}
>
<LinkItem
href="/#home"
className="navbar__link"
style={{ display: 'none' }}
>
Home
</LinkItem>
<LinkItem href="/#about" className="navbar__link">
About
</LinkItem>
<LinkItem href="/#projects" className="navbar__link">
Projects
</LinkItem>
<LinkItem href="/#blog" className="navbar__link">
Blog
</LinkItem>
<LinkItem href="/#contact" className="navbar__link">
Contact
</LinkItem>
<Resume />
</Scrollspy>
</Navbar>
</HeaderWrapper>
)
}
export default Header

178
src/components/hero.js Normal file
View File

@@ -0,0 +1,178 @@
import React from 'react'
import { graphql, useStaticQuery } from 'gatsby'
import styled from 'styled-components'
import { trackCustomEvent } from 'gatsby-plugin-google-analytics'
import { Link } from 'gatsby'
import Header from './header'
import Board from './board/board'
import bg from '../images/bg.jpg'
import cross from '../images/decorations/cross.svg'
import tick from '../images/decorations/tick.svg'
import circle from '../images/decorations/circle.svg'
const HeroSection = styled.section`
background-image: url(${bg});
background-size: cover;
background-position: center;
background-repeat: no-repeat;
background-attachment: fixed;
height: fit-content;
display: flex;
justify-content: flex-start;
align-items: center;
flex-direction: column;
.container__hero--secondary {
display: flex;
justify-content: center;
margin: 5rem 0;
}
.colored {
text-shadow: 0px 0px 10px black;
}
`
const Container = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
flex-direction: row;
@media screen and (max-width: 768px) {
flex-direction: column !important;
align-items: flex-start !important;
}
`
const HeroContainer = styled.div`
justify-content: flex-start;
position: relative;
width: 100%;
margin-top: 100px;
`
const Left = styled.div`
width: 50%;
z-index: 1;
`
const Greeting = styled.p``
const Author = styled.h1``
const Role = styled.h2``
const Description = styled.p`
width: 80%;
margin: 50px 0;
color: #bdbdbd;
text-align: left;
`
const Right = styled.div`
width: 50%;
z-index: 1;
position: relative;
perspective: 700px;
`
const Image = styled.img`
position: absolute;
z-index: 0;
&.decoration__cross {
left: 50%;
top: 0;
transition: 0.2s;
filter: drop-shadow(0px 0px 15px #ff5252);
&:hover {
transform: rotate(180deg);
transition: 0.2s;
filter: none;
}
}
&.decoration__tick {
left: 35%;
bottom: 10%;
transition: 0.2s;
filter: drop-shadow(0px 0px 15px #02d463);
&:hover {
transform: scale(0.9);
transition: 0.2s;
filter: none;
}
}
&.decoration__circle {
left: 75%;
top: 20%;
transition: 0.2s;
filter: drop-shadow(0px 0px 15px #00cde2);
&:hover {
transform: scale(1.1);
transition: 0.2s;
filter: none;
}
}
`
export default function Hero() {
const data = useStaticQuery(graphql`
query {
site {
siteMetadata {
author
role
}
}
}
`)
const { author, role } = data.site.siteMetadata
return (
<HeroSection id="home">
<Header />
<HeroContainer className="container hero__container">
<div className="container__hero--secondary container--secondary">
<Container className="container--primary">
<Left className="hero__left">
<Greeting className="colored">Hi, I am</Greeting>
<Author>{author}</Author>
<Role className="hero__sub">{role}</Role>
<Description className="hero__desc section__desc">
I specialize in designing, building, shipping, and scaling
beautiful, usable products with blazing-fast efficiency.
</Description>
<Link
href="#projects"
className="btn btn--primary"
onClick={(e) => {
e.preventDefault()
trackCustomEvent({
category: 'See my work Button',
action: 'Click',
label: 'Gatsby Google Analytics See my work Button',
})
}}
>
See my work
</Link>
</Left>
<Right className="hero__right">
<Board />
</Right>
<Image
className="decoration decoration__cross"
src={cross}
alt="cross"
loading="lazy"
/>
<Image
className="decoration decoration__tick"
src={tick}
alt="tick"
loading="lazy"
/>
<Image
className="decoration decoration__circle"
src={circle}
alt="circle"
loading="lazy"
/>
</Container>
</div>
</HeroContainer>
</HeroSection>
)
}

87
src/components/project.js Normal file
View File

@@ -0,0 +1,87 @@
import React from 'react'
import styled from 'styled-components'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
const Box = styled.div`
&:hover {
span,
svg,
video {
opacity: 1;
transition: 0.2s;
}
}
`
const Video = styled.video`
width: 100%;
opacity: 0.4;
transition: 0.5s;
border-radius: 4px;
box-shadow: 0px 0px 10px black;
`
const Source = styled.source``
const Links = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 10px;
span {
font-size: 14px;
text-shadow: 0px 0px 10px black;
opacity: 0.4;
transition: 0.2s;
}
`
const Wrapper = styled.div``
const Link = styled.a`
margin-right: 10px;
svg {
width: 20px;
height: 20px;
transition: 0.2s;
filter: drop-shadow(0px 0px 3px black);
opacity: 0.4;
&:hover {
color: #02d463;
transition: 0.2s;
}
}
`
const Title = styled.span``
const Project = ({ title, bgwebm, github, external }) => (
<Box className="work__box">
<Video
alt={title}
loop={true}
autoPlay={true}
muted={true}
playsInline={true}
>
<Source src={bgwebm} type="video/webm" />
</Video>
<Links className="work__links">
<Wrapper>
<Link
href={github}
target="_blank"
rel="noopener noreferrer"
title="GitHub"
>
<FontAwesomeIcon icon={['fab', 'github']} className="about__icon" />
</Link>
<Link
href={external}
target="_blank"
rel="noopener noreferrer"
title="External"
>
<FontAwesomeIcon icon="external-link-alt" />
</Link>
</Wrapper>
<Title>{title}</Title>
</Links>
</Box>
)
export default Project

165
src/components/projects.js Normal file
View File

@@ -0,0 +1,165 @@
import React from 'react'
import styled from 'styled-components'
import Project from './project'
import hoppWebM from '../images/projects/hopp.webm'
import grammarlyWebM from '../images/projects/grammarlydark.webm'
import pagetifyWebM from '../images/projects/pagetify.webm'
import schoolifyWebM from '../images/projects/schoolify.webm'
import dojrzewajWebM from '../images/projects/dojrzewaj.webm'
import centrummotoWebM from '../images/projects/centrummoto.webm'
import cz5pWebM from '../images/projects/cz5p.webm'
import teleanWebM from '../images/projects/telean.webm'
import darkpaypalWebM from '../images/projects/darkpaypal.webm'
import bartzalewskiV1WebM from '../images/projects/bartzalewski-v1.webm'
import joindevsWebM from '../images/projects/joindevs.webm'
import bartzalewskiV2WebM from '../images/projects/bartzalewski-v2.webm'
const ProjectsWrapper = styled.section`
display: flex;
justify-content: center;
align-items: flex-start;
background: #111;
padding: 100px 0;
`
const WorkWrapper = styled.div`
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 60px 20px;
width: 100%;
`
const Title = styled.h2``
const Description = styled.p`
text-align: center;
margin: 50px 0;
color: #bdbdbd;
`
const Animation = styled.div`
&:nth-of-type(2),
&:nth-of-type(5),
&:nth-of-type(8),
&:nth-of-type(11) {
margin-top: 50px;
}
&:nth-of-type(3),
&:nth-of-type(6),
&:nth-of-type(9),
&:nth-of-type(12) {
margin-top: 100px;
}
`
export default function Projects() {
return (
<ProjectsWrapper id="projects">
<div className="container container--secondary">
<div className="container container--primary">
<Title>My side projects</Title>
<Description className="work__desc section__desc">
Check out my portfolio!
</Description>
<WorkWrapper className="work__wrapper">
<Animation className="work--animation">
<Project
title="JoinDevs"
bgwebm={joindevsWebM}
github="#!"
external="https://joindevs.com/"
/>
</Animation>
<Animation className="work--animation">
<Project
title="HOPP"
bgwebm={hoppWebM}
github="#!"
external="https://hopp.pl/"
/>
</Animation>
<Animation className="work--animation">
<Project
title="Grammarly Dark"
bgwebm={grammarlyWebM}
github="https://github.com/bartzalewski/grammarly-dark"
external="https://www.producthunt.com/posts/grammarly-dark"
/>
</Animation>
<Animation className="work--animation">
<Project
title="My second portfolio"
bgwebm={bartzalewskiV2WebM}
github="https://github.com/bartzalewski/bartzalewski.com-v2"
external="https://bartzalewski.com/"
/>
</Animation>
<Animation className="work--animation">
<Project
title="Pagetify"
bgwebm={pagetifyWebM}
github="https://github.com/bartzalewski/pagetify"
external="https://pagetify.com/"
/>
</Animation>
<Animation className="work--animation">
<Project
title="Schoolify"
bgwebm={schoolifyWebM}
github="https://github.com/bartzalewski/schoolify"
external="https://schoolify.app/"
/>
</Animation>
<Animation className="work--animation">
<Project
title="dojrzewaj.pl"
bgwebm={dojrzewajWebM}
github="#!"
external="https://dojrzewaj.pl/"
/>
</Animation>
<Animation className="work--animation">
<Project
title="Centrum Moto"
bgwebm={centrummotoWebM}
github="#!"
external="https://centrummoto.pl/"
/>
</Animation>
<Animation className="work--animation">
<Project
title="coza500plus.pl"
bgwebm={cz5pWebM}
github="https://github.com/bartzalewski/coza500plus"
external="https://coza500plus.pl/"
/>
</Animation>
<Animation className="work--animation">
<Project
title="Telean"
bgwebm={teleanWebM}
github="https://github.com/bartzalewski/telean-website"
external="https://telean-website.herokuapp.com/"
/>
</Animation>
<Animation className="work--animation">
<Project
title="Dark PayPal"
bgwebm={darkpaypalWebM}
github="https://github.com/bartzalewski/darkness"
external="#!"
/>
</Animation>
<Animation className="work--animation">
<Project
title="My first portfolio"
bgwebm={bartzalewskiV1WebM}
github="https://github.com/bartzalewski/bartzalewski.com-v1"
external="https://bartzalewski-v1.herokuapp.com/"
/>
</Animation>
</WorkWrapper>
</div>
</div>
</ProjectsWrapper>
)
}

15
src/components/resume.js Normal file
View File

@@ -0,0 +1,15 @@
import React from 'react'
import { OutboundLink } from 'gatsby-plugin-google-analytics'
const Resume = () => (
<OutboundLink
href="/resume.pdf"
target="_blank"
rel="noopener noreferrer"
className="navbar__link navbar__resume btn btn--secondary"
>
Resume
</OutboundLink>
)
export default Resume