diff --git a/README.md b/README.md index 7bf3df67..9204925c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

Personal Portfolio

- Software and Full-Stack Developer.
Creating beautiful user-centered interactivity and experiences. + Full-Stack Software Engineer.
Creating beautiful user-centered interactivity and experiences.


diff --git a/web/common/components/GlassRectangle/styles.ts b/web/common/components/GlassRectangle/styles.ts index 31ebc6f8..b0946b34 100644 --- a/web/common/components/GlassRectangle/styles.ts +++ b/web/common/components/GlassRectangle/styles.ts @@ -48,6 +48,33 @@ export const GlassContainer = styled.div` }, 0.27)`}; overflow: hidden; + &.home-page { + width: 51rem; + height: 37rem; + margin-right: auto; + margin-left: auto; + + @media ${({ theme }) => theme.responsive.below1199} { + width: 35rem; + height: 25rem; + } + + @media ${({ theme }) => theme.responsive.below599} { + width: 32rem; + height: 23rem; + } + + @media ${({ theme }) => theme.responsive.below479} { + width: 24rem; + height: 17rem; + } + + @media ${({ theme }) => theme.responsive.below379} { + width: 100%; + height: 16rem; + } + } + &.about-page { width: 51rem; height: 37rem; @@ -150,6 +177,10 @@ export const GlassImageWrapper = styled.div` margin-right: auto; opacity: ${({ opacity }) => opacity ?? '1'}; + &.home-page { + width: 100%; + } + &.about-page { width: 100%; } @@ -192,6 +223,16 @@ export const GlassImageWrapper = styled.div` export const GlassImage = styled.img` width: 100%; + &.home-page { + &--image-1 { + transform: scale(1.1); + } + + &--image-2 { + transform: scale(1.5); + } + } + &.about-page { transform: scale(1.1); } diff --git a/web/common/components/ItemLink/itemData.ts b/web/common/components/ItemLink/itemData.ts index d038543e..c99cf7c7 100644 --- a/web/common/components/ItemLink/itemData.ts +++ b/web/common/components/ItemLink/itemData.ts @@ -15,11 +15,11 @@ const itemData: TItemData[] = [ title: 'Articles', path: '/articles', }, - { - id: '4c5c324a-92ed-4575-a731-25370c21379a', - title: 'About', - path: '/about', - }, + // { + // id: '4c5c324a-92ed-4575-a731-25370c21379a', + // title: 'About', + // path: '/about', + // }, ]; export default itemData; diff --git a/web/components/home/AboutImage/index.tsx b/web/components/home/AboutImage/index.tsx new file mode 100644 index 00000000..f1e8a6c6 --- /dev/null +++ b/web/components/home/AboutImage/index.tsx @@ -0,0 +1,56 @@ +import { FC, useEffect } from 'react'; +import { useAnimation } from 'framer-motion'; +import { useInView } from 'react-intersection-observer'; + +import GlassRectangle from 'common/components/GlassRectangle'; + +import { ImageWrapper } from './styles'; + +interface IAboutImageProps { + customClassName?: string; + imgAlt: string; + imgSrc: string; +} + +const AboutImage: FC = ({ + customClassName, + imgAlt, + imgSrc, +}) => { + const imageAnimateControls = useAnimation(); + + const { inView: imageInView, ref: imageRef } = useInView(); + + useEffect(() => { + const timer = setTimeout(() => { + if (imageInView) { + imageAnimateControls.start('visible'); + } + }, 200); + + return () => clearTimeout(timer); + }, [imageAnimateControls, imageInView]); + + return ( + + + + ); +}; + +export default AboutImage; diff --git a/web/components/home/AboutImage/styles.ts b/web/components/home/AboutImage/styles.ts new file mode 100644 index 00000000..780f4d56 --- /dev/null +++ b/web/components/home/AboutImage/styles.ts @@ -0,0 +1,19 @@ +import styled from 'styled-components'; +import { motion } from 'framer-motion'; + +export const ImageWrapper = styled(motion.div).attrs(() => ({ + initial: 'hidden', + variants: { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { duration: 0.5 }, + }, + }, +}))` + margin-top: 5rem; + + @media ${({ theme }) => theme.responsive.below899} { + margin-top: 0; + } +`; diff --git a/web/components/home/AboutSection/index.tsx b/web/components/home/AboutSection/index.tsx new file mode 100644 index 00000000..7fd61381 --- /dev/null +++ b/web/components/home/AboutSection/index.tsx @@ -0,0 +1,31 @@ +import { FC } from 'react'; + +import HeadingPrimary from 'common/typography/HeadingPrimary'; +import Paragraph from 'common/typography/Paragraph'; + +import { MainAboutWrapper, SecondaryAboutWrapper, Section } from './styles'; + +const AboutSection: FC = () => ( +

+ + + Hello! I love drinking coffee while learning and improving on new and + existing technologies + + + + + + A passionate and curious individual with a BS degree in Physics from + UCLA currently working as a Full-Stack Software Engineer at Aerobotics7 + to remove landmines from around the world. I have experiences with + Python, Django, Node.js, React.js, Figma/Lucid Charts and other + platforms and tools to facilitate on creating and solving real-world + problems for the users to enjoy, and the companies to succeed their + vision + + +
+); + +export default AboutSection; diff --git a/web/components/home/AboutSection/styles.ts b/web/components/home/AboutSection/styles.ts new file mode 100644 index 00000000..55847805 --- /dev/null +++ b/web/components/home/AboutSection/styles.ts @@ -0,0 +1,44 @@ +import styled from 'styled-components'; + +export const Section = styled.section` + width: 100%; + text-align: right; +`; + +export const MainAboutWrapper = styled.div` + width: 80%; + margin-bottom: 3rem; + margin-left: auto; + + @media ${({ theme }) => theme.responsive.below1199} { + width: 97%; + } + + @media ${({ theme }) => theme.responsive.below899} { + width: 100%; + margin-bottom: 5rem; + } + + @media ${({ theme }) => theme.responsive.below479} { + margin-bottom: 3rem; + } +`; + +export const SecondaryAboutWrapper = styled.div` + width: 95%; + margin-bottom: 3rem; + margin-left: auto; + + @media ${({ theme }) => theme.responsive.below1199} { + width: 97%; + } + + @media ${({ theme }) => theme.responsive.below899} { + width: 100%; + margin-bottom: 5rem; + } + + @media ${({ theme }) => theme.responsive.below479} { + margin-bottom: 3rem; + } +`; diff --git a/web/components/home/ArticleSection/ArticleContainer.tsx b/web/components/home/ArticleSection/ArticleContainer.tsx deleted file mode 100644 index 360c7141..00000000 --- a/web/components/home/ArticleSection/ArticleContainer.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import { FC, useEffect } from 'react'; -import Link from 'next/link'; -import { useAnimation } from 'framer-motion'; -import { useInView } from 'react-intersection-observer'; - -import GlassCircle from 'common/components/GlassCircle'; - -import { useIsHovering } from 'common/hooks'; - -import HeadingTertiary from 'common/typography/HeadingTertiary'; - -import { isHoveringOverall } from 'utils'; - -import { - ArticleContainerStyle, - ArticleDescriptionContainer, - ArticleImageLink, - ArticleImageWrapper, - ArticleTitle, - ArticleTitleLink, -} from './styles'; - -export interface IArticleContainer { - articleClass: string; - articleImageAlt: string; - articleImageSrc: string; - articleLinkPath: string; - articleTitle: string; - finishIsFirstMount: boolean; - isExploreLinkHovering: boolean; -} - -const ArticleContainer: FC = ({ - articleClass, - articleImageAlt, - articleImageSrc, - articleLinkPath, - articleTitle, - finishIsFirstMount, - isExploreLinkHovering, -}) => { - const titleAnimateControls = useAnimation(); - const { inView: titleInView, ref: titleRef } = useInView(); - - const imageAnimateControls = useAnimation(); - const { inView: imageInView, ref: imageRef } = useInView(); - - const [isTitleLinkHovering, setIsTitleLinkHovering] = useIsHovering(); - const [isImageLinkHovering, setIsImageLinkHovering] = useIsHovering(); - - useEffect(() => { - const timer = setTimeout(() => { - if (!finishIsFirstMount && titleInView) { - titleAnimateControls.start('visible'); - } - - return () => clearTimeout(timer); - }, 600); - }, [finishIsFirstMount, titleAnimateControls, titleInView]); - - useEffect(() => { - const timer = setTimeout(() => { - if (!finishIsFirstMount && imageInView) { - imageAnimateControls.start('visible'); - } - }, 900); - - return () => clearTimeout(timer); - }, [finishIsFirstMount, imageAnimateControls, imageInView]); - - useEffect(() => { - if ( - !finishIsFirstMount && - isHoveringOverall(isImageLinkHovering, isExploreLinkHovering) - ) { - imageAnimateControls.start('hovering'); - } else { - imageAnimateControls.start('nonHovering'); - } - }, [ - finishIsFirstMount, - isImageLinkHovering, - isExploreLinkHovering, - imageAnimateControls, - ]); - - return ( - - - setIsImageLinkHovering(true)} - onHoverEnd={() => setIsImageLinkHovering(false)} - ref={imageRef} - > - - - - - - - - - - setIsTitleLinkHovering(true)} - onMouseLeave={() => setIsTitleLinkHovering(false)} - > - - {articleTitle} - - - - - - - ); -}; - -export default ArticleContainer; diff --git a/web/components/home/ArticleSection/index.tsx b/web/components/home/ArticleSection/index.tsx deleted file mode 100644 index 2ec628de..00000000 --- a/web/components/home/ArticleSection/index.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import React, { FC, useEffect } from 'react'; -import Link from 'next/link'; -import { useAnimation } from 'framer-motion'; -import { useInView } from 'react-intersection-observer'; - -import LineSeparator from 'common/components/LineSeparator'; - -import { useIsHovering } from 'common/hooks'; - -import { IArticle } from 'common/models'; - -import HeadingSecondary from 'common/typography/HeadingSecondary'; -import Paragraph from 'common/typography/Paragraph'; - -import environment from 'environment'; - -import { - Container, - ExploreMoreLink, - ExploreMoreWrapper, - Introduction, - Section, - SectionTitle, - Wrapper, -} from './styles'; -import ArticleContainer from './ArticleContainer'; - -type TArticlesData = Pick< - IArticle, - | 'description' - | 'header_image' - | 'id' - | 'title' - | 'uuid' - | 'reading_time' - | 'category' - | 'tags' -> & { - meta: Pick; -}; - -interface IArticleSection { - articlesData: TArticlesData[] | []; - finishIsFirstMount: boolean; -} - -const ArticleSection: FC = ({ - articlesData, - finishIsFirstMount, -}) => { - const titleAnimateControls = useAnimation(); - const { inView: titleInView, ref: titleRef } = useInView(); - - const introAnimateControls = useAnimation(); - const { inView: introInView, ref: introRef } = useInView(); - - const viewMoreAnimateControls = useAnimation(); - const { inView: viewMoreInView, ref: viewMoreRef } = useInView(); - - const [isHovering, setIsHovering] = useIsHovering(); - - useEffect(() => { - const timer = setTimeout(() => { - if (!finishIsFirstMount && titleInView) { - titleAnimateControls.start('visible'); - } - }, 500); - - return () => clearTimeout(timer); - }, [finishIsFirstMount, titleAnimateControls, titleInView]); - - useEffect(() => { - const timer = setTimeout(() => { - if (!finishIsFirstMount && introInView) { - introAnimateControls.start('visible'); - } - }, 600); - - return () => clearTimeout(timer); - }, [finishIsFirstMount, introAnimateControls, introInView]); - - useEffect(() => { - const timer = setTimeout(() => { - if (!finishIsFirstMount && viewMoreInView) { - viewMoreAnimateControls.start('visible'); - } - }, 2000); - - return () => clearTimeout(timer); - }, [finishIsFirstMount, viewMoreAnimateControls, viewMoreInView]); - - return ( -
- - - Articles - - - - - - - - - I love to write to help others understand programming, mathematics, - science, and other related technical fields. I also write film and - book analysis, philosophy, and other things that interest me. - - - - - {articlesData.length > 0 && - articlesData.map((articleData, articleIndex) => ( - - - - ))} - - - - - - setIsHovering(true)} - onMouseLeave={() => setIsHovering(false)} - > - Explore all articles - - - -
- ); -}; - -export default ArticleSection; diff --git a/web/components/home/ArticleSection/styles.ts b/web/components/home/ArticleSection/styles.ts deleted file mode 100644 index eff05161..00000000 --- a/web/components/home/ArticleSection/styles.ts +++ /dev/null @@ -1,328 +0,0 @@ -import styled from 'styled-components'; -import { motion } from 'framer-motion'; - -// ARTICLE SECTION -export const Section = styled.section``; - -export const SectionTitle = styled(motion.div).attrs(() => ({ - initial: 'hidden', - variants: { - hidden: { - opacity: 0, - y: 10, - }, - visible: { - opacity: 1, - y: 0, - transition: { duration: 0.5 }, - }, - }, -}))``; - -export const Container = styled.div` - display: flex; - flex-direction: column; - padding-top: 4rem; - - @media ${({ theme }) => theme.responsive.below1199} { - padding-top: 2.5rem; - } - - @media ${({ theme }) => theme.responsive.below899} { - padding-top: 2.3rem; - } - - @media ${({ theme }) => theme.responsive.below479} { - padding-top: 1rem; - } -`; - -export const Introduction = styled(motion.div).attrs(() => ({ - initial: 'hidden', - variants: { - hidden: { - opacity: 0, - y: -10, - }, - visible: { - opacity: 1, - y: 0, - transition: { duration: 0.5 }, - }, - }, -}))` - text-align: center; - padding: 5rem 15rem; - - @media ${({ theme }) => theme.responsive.below899} { - padding: 5rem 8rem; - } - - @media ${({ theme }) => theme.responsive.below599} { - padding: 5rem 5rem; - } - - @media ${({ theme }) => theme.responsive.below479} { - padding: 5rem 1rem; - } - - @media ${({ theme }) => theme.responsive.below379} { - padding: 4rem 1rem; - } -`; - -export const Wrapper = styled.div` - display: grid; - grid-template-rows: 1fr 1fr; - grid-template-columns: 1fr 1fr; - grid-template-areas: - 'article1 article1' - 'article2 article3'; - margin-bottom: 10rem; - - @media ${({ theme }) => theme.responsive.below899} { - margin-bottom: 0; - } - - @media ${({ theme }) => theme.responsive.below479} { - display: flex; - flex-direction: column; - } -`; - -export const ExploreMoreWrapper = styled(motion.div).attrs(() => ({ - variants: { - visible: { - rotate: [0, 15, 7.5, 15, 0], - transition: { - duration: 1, - ease: 'easeInOut', - times: [0, 0.2, 0.5, 0.8, 1], - }, - }, - }, -}))` - margin-top: 10rem; - text-align: center; - - @media ${({ theme }) => theme.responsive.below599} { - margin-top: 6rem; - } - - @media ${({ theme }) => theme.responsive.below479} { - margin-top: 5rem; - } - - @media ${({ theme }) => theme.responsive.below379} { - margin-top: 3rem; - } -`; - -export const ExploreMoreLink = styled.a` - font-size: 2rem; - font-weight: 700; - color: ${({ theme }) => theme.colors.primary.hex}; - text-decoration: none; - - &:hover { - text-decoration: underline; - cursor: pointer; - opacity: 0.9; - } - - @media ${({ theme }) => theme.responsive.below479} { - font-size: 1.7rem; - } -`; - -// ARTICLE CONTAINER -export const ArticleContainerStyle = styled.div` - padding-top: 5rem; - padding-bottom: 5rem; - - &.article1 { - position: relative; - grid-area: article1; - } - - &.article2 { - position: relative; - grid-area: article2; - padding-left: 15rem; - - &:before, - &:after { - content: ''; - position: absolute; - width: 36rem; - height: 0.2rem; - background-color: ${({ theme }) => - `rgba(${theme.colors.primary.rgb}, 0.5)`}; - - @media ${({ theme }) => theme.responsive.below899} { - content: none; - } - } - - &:before { - top: -4.7rem; - left: 24.1rem; - transform: rotate(40deg); - - @media ${({ theme }) => theme.responsive.below1199} { - left: 5.7rem; - } - } - - &:after { - bottom: 5.4rem; - left: 38rem; - transform: rotate(90deg); - - @media ${({ theme }) => theme.responsive.below1199} { - left: 19.5rem; - } - } - - @media ${({ theme }) => theme.responsive.below899} { - padding-left: 3rem; - } - - @media ${({ theme }) => theme.responsive.below599} { - padding-top: 2rem; - padding-bottom: 2rem; - padding-left: 2rem; - } - - @media ${({ theme }) => theme.responsive.below479} { - padding-bottom: 3rem; - padding-left: 0; - } - } - - &.article3 { - position: relative; - grid-area: article3; - padding-right: 15rem; - - &:before { - content: ''; - position: absolute; - top: -4.7rem; - right: 24.1rem; - width: 36rem; - height: 0.2rem; - background-color: ${({ theme }) => - `rgba(${theme.colors.primary.rgb}, 0.5)`}; - transform: rotate(-40deg); - - @media ${({ theme }) => theme.responsive.below1199} { - right: 5.7rem; - } - - @media ${({ theme }) => theme.responsive.below899} { - content: none; - } - } - - @media ${({ theme }) => theme.responsive.below899} { - padding-right: 3rem; - } - - @media ${({ theme }) => theme.responsive.below599} { - padding-top: 2rem; - padding-right: 2rem; - padding-bottom: 2rem; - } - - @media ${({ theme }) => theme.responsive.below479} { - padding-right: 0; - padding-bottom: 3rem; - } - } - - @media ${({ theme }) => theme.responsive.below599} { - padding-top: 2rem; - padding-bottom: 2rem; - } - - @media ${({ theme }) => theme.responsive.below479} { - padding-bottom: 3rem; - } -`; - -export const ArticleDescriptionContainer = styled.div` - display: flex; - flex-direction: column; - align-items: center; -`; - -export const ArticleImageWrapper = styled(motion.div).attrs( - ({ className }) => ({ - initial: 'hidden', - variants: { - hidden: { - opacity: 0, - rotate: 0, - scale: 0, - }, - hovering: { - rotate: !className?.includes('article2') ? -720 : 720, - scale: 1.12, - transition: { - type: 'spring', - bounce: 0.4, - duration: 0.2, - }, - }, - nonHovering: { - rotate: 0, - scale: 1, - }, - visible: { - opacity: 1, - rotate: !className?.includes('article2') ? 720 : -720, - scale: 1, - transition: { - type: 'spring', - bounce: 0.4, - duration: 0.5, - }, - }, - }, - }) -)` - margin-bottom: 2rem; -`; - -export const ArticleImageLink = styled.a``; - -export const ArticleTitle = styled(motion.div).attrs(() => ({ - initial: 'hidden', - variants: { - hidden: { - opacity: 0, - }, - visible: { - opacity: 1, - transition: { duration: 0.3 }, - }, - }, -}))``; - -export const ArticleTitleLink = styled.a` - text-align: center; - text-decoration: none; - - & h3 { - max-width: 30.1rem; - max-height: 3.4rem; - overflow: hidden; - text-overflow: ellipsis; - word-wrap: break-word; - - @media ${({ theme }) => theme.responsive.below899} { - max-height: 2.5rem; - } - } -`; diff --git a/web/components/home/BeliefsSection/index.tsx b/web/components/home/BeliefsSection/index.tsx new file mode 100644 index 00000000..f59bed4e --- /dev/null +++ b/web/components/home/BeliefsSection/index.tsx @@ -0,0 +1,82 @@ +import { FC, useEffect } from 'react'; +import { useAnimation } from 'framer-motion'; +import { useInView } from 'react-intersection-observer'; + +import HeadingSecondary from 'common/typography/HeadingSecondary'; +import Paragraph from 'common/typography/Paragraph'; + +import { ParagraphWrapper, Section, SectionTitle } from './styles'; + +const BeliefsSection: FC = () => { + const sectionAnimateControls = useAnimation(); + const { inView: sectionInView, ref: sectionRef } = useInView(); + + const titleAnimateControls = useAnimation(); + const { inView: titleInView, ref: titleRef } = useInView(); + + useEffect(() => { + const timer = setTimeout(() => { + if (sectionInView) { + sectionAnimateControls.start('visible'); + } + }, 200); + + return () => clearTimeout(timer); + }, [sectionAnimateControls, sectionInView]); + + useEffect(() => { + const timer = setTimeout(() => { + if (titleInView) { + titleAnimateControls.start('visible'); + } + }, 200); + + return () => clearTimeout(timer); + }, [titleAnimateControls, titleInView]); + + return ( +
+ + + Beliefs + + + + + + As an avid learner, I was a self-taught programmer many years ago, and + being self-taught was difficult and created imposter syndrome within + myself. I always felt like I was not good enough and needed to know + more about the magic of coding. Overtime, I have learned to have + self-confidence in my abilities, asking for guidance, and knowing when + to just get up and take a walk. + + + + + + I believe that anyone can become a programmer no matter what + background they come from. I believe that if you have tenacity, + perseverance, and tolerance within yourself then you can understand + the complexities of programming. + + + + + + I also believe in having good communication, understanding, and + patience with others to develop healthy relationships. When these + three pillars are achieved, then achieving three more are possible: + Better user experience, painless documentation for developers to read, + and accomplishing a feat together within the team. + + +
+ ); +}; + +export default BeliefsSection; diff --git a/web/components/home/BeliefsSection/styles.ts b/web/components/home/BeliefsSection/styles.ts new file mode 100644 index 00000000..f882641e --- /dev/null +++ b/web/components/home/BeliefsSection/styles.ts @@ -0,0 +1,88 @@ +import styled from 'styled-components'; +import { motion } from 'framer-motion'; + +export const Section = styled(motion.section).attrs(() => ({ + initial: 'hidden', + variants: { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { duration: 0.5 }, + }, + }, +}))` + margin-top: -28rem; + padding-right: 12rem; + text-align: left; + + @media ${({ theme }) => theme.responsive.below1199} { + padding-right: 3rem; + } + + @media ${({ theme }) => theme.responsive.below899} { + margin-top: 0; + padding-left: 3rem; + } + + @media ${({ theme }) => theme.responsive.below599} { + padding-right: 0; + padding-left: 0; + } +`; + +export const SectionTitle = styled(motion.div).attrs(() => ({ + initial: 'hidden', + variants: { + hidden: { + opacity: 0, + y: 10, + }, + visible: { + opacity: 1, + y: 0, + transition: { duration: 0.5 }, + }, + }, +}))` + margin-bottom: 2.5rem; + + @media ${({ theme }) => theme.responsive.below599} { + margin-bottom: 1.75rem; + } + + @media ${({ theme }) => theme.responsive.below479} { + margin-bottom: 1.5rem; + } +`; + +export const ParagraphWrapper = styled.div` + margin-top: 2.5rem; + margin-bottom: 2.5rem; + line-height: 1.5; + + &:first-child { + margin-top: 0; + } + + &:last-child { + margin-bottom: 0; + } + + @media ${({ theme }) => theme.responsive.below899} { + line-height: 1.8; + } + + @media ${({ theme }) => theme.responsive.below599} { + margin-top: 1.75rem; + margin-bottom: 1.75rem; + } + + @media ${({ theme }) => theme.responsive.below479} { + margin-top: 1.5rem; + margin-bottom: 1.5rem; + } + + @media ${({ theme }) => theme.responsive.below379} { + line-height: 1.5; + } +`; diff --git a/web/components/home/Col/index.tsx b/web/components/home/Col/index.tsx new file mode 100644 index 00000000..90aed802 --- /dev/null +++ b/web/components/home/Col/index.tsx @@ -0,0 +1,11 @@ +import styled from 'styled-components'; + +const Col = styled.div` + width: 50%; + + @media ${({ theme }) => theme.responsive.below899} { + width: 100%; + } +`; + +export default Col; diff --git a/web/components/home/ExperienceSection/index.tsx b/web/components/home/ExperienceSection/index.tsx new file mode 100644 index 00000000..71708836 --- /dev/null +++ b/web/components/home/ExperienceSection/index.tsx @@ -0,0 +1,91 @@ +import { FC, useEffect } from 'react'; +import { useAnimation } from 'framer-motion'; +import { useInView } from 'react-intersection-observer'; + +import HeadingSecondary from 'common/typography/HeadingSecondary'; +import Paragraph from 'common/typography/Paragraph'; + +import { ParagraphWrapper, Section, SectionTitle } from './styles'; + +const ExperienceSection: FC = () => { + const sectionAnimateControls = useAnimation(); + const { inView: sectionInView, ref: sectionRef } = useInView(); + + const titleAnimateControls = useAnimation(); + const { inView: titleInView, ref: titleRef } = useInView(); + + useEffect(() => { + const timer = setTimeout(() => { + if (sectionInView) { + sectionAnimateControls.start('visible'); + } + }, 200); + + return () => clearTimeout(timer); + }, [sectionAnimateControls, sectionInView]); + + useEffect(() => { + const timer = setTimeout(() => { + if (titleInView) { + titleAnimateControls.start('visible'); + } + }, 200); + + return () => clearTimeout(timer); + }, [titleAnimateControls, titleInView]); + + return ( +
+ + + Experience + + + + + + At Aerobotics7, I spearheaded the creation of software architectures + for controlling drones and efficiently storing landmine detection data + at a high-speed receiver rate. Managing the full technology stack, + including DevOps, SQL databases, and security protocols, I + successfully ensured real-time communication and authentication + between the drone and users. Additionally, I presented our hardware + and software technology at the Geneva International Centre for + Humanitarian Demining (held in Switzerland once a year) to showcase + our capabilities to government officials, scientists, and engineers. + + + + + + Previously at Listing Alert, I helped to develop the mobile app with + bare React Native (non-Expo) along with developing our own API with + Node.js, Express.js, MongoDB and AWS S3 to be used for the real estate + agents to get notifications on property listings from potential + buyers. Additionally, the team and I developed a web dashboard with + React.js for companies to create agents, offices, and other tasks for + their needs. In all of the development process, we used Apollo + GraphQL. Over 1600 agents across the country from RE/MAX to Century 21 + Black Bear Realty use Listing Alert. + + + + + + In addition, I worked on React for about two and a half years, and + before that I worked on vanilla JavaScript for three years. I also + worked on Django, Python, Node, Express, MongoDB, MySQL, and + PostgreSQL for three to four years. Over the course of these years, I + learned how to make better and reusable code that is readable along + with clean file structure which follows best practices. + + +
+ ); +}; + +export default ExperienceSection; diff --git a/web/components/home/ExperienceSection/styles.ts b/web/components/home/ExperienceSection/styles.ts new file mode 100644 index 00000000..2bae38f7 --- /dev/null +++ b/web/components/home/ExperienceSection/styles.ts @@ -0,0 +1,88 @@ +import styled from 'styled-components'; +import { motion } from 'framer-motion'; + +export const Section = styled(motion.section).attrs(() => ({ + initial: 'hidden', + variants: { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { duration: 0.5 }, + }, + }, +}))` + padding-left: 12rem; + text-align: right; + + @media ${({ theme }) => theme.responsive.below1199} { + padding-left: 3rem; + } + + @media ${({ theme }) => theme.responsive.below899} { + padding-right: 3rem; + } + + @media ${({ theme }) => theme.responsive.below599} { + padding-right: 0; + padding-left: 0; + } +`; + +export const SectionTitle = styled(motion.div).attrs(() => ({ + initial: 'hidden', + variants: { + hidden: { + opacity: 0, + y: 10, + }, + visible: { + opacity: 1, + y: 0, + transition: { duration: 0.5 }, + }, + }, +}))` + margin-bottom: 2.5rem; + + @media ${({ theme }) => theme.responsive.below599} { + margin-bottom: 1.75rem; + } + + @media ${({ theme }) => theme.responsive.below479} { + margin-bottom: 1.5rem; + } +`; + +export const ParagraphWrapper = styled.div` + margin-top: 2.5rem; + margin-bottom: 2.5rem; + line-height: 1.5; + + &:first-child { + margin-top: 0; + } + + &:last-child { + margin-bottom: 0; + } + + @media ${({ theme }) => theme.responsive.below899} { + line-height: 1.8; + } + + @media ${({ theme }) => theme.responsive.below599} { + margin-top: 1.75rem; + margin-bottom: 1.75rem; + } + + @media ${({ theme }) => theme.responsive.below479} { + margin-top: 1.5rem; + margin-bottom: 1.5rem; + } + + @media ${({ theme }) => theme.responsive.below379} { + line-height: 1.5; + } +`; + +export const Italic = styled.i``; diff --git a/web/components/home/HeroBanner/index.tsx b/web/components/home/HeroBanner/index.tsx index 5ad68aea..410340d1 100644 --- a/web/components/home/HeroBanner/index.tsx +++ b/web/components/home/HeroBanner/index.tsx @@ -33,15 +33,20 @@ const HeroBanner: FC = () => ( Hello! I'm Elias Gutierrez, and I'm a Full-Stack Software - Engineer + Engineer 🤓. I love drinking coffee ☕️ while learning and improving + on new and existing technologies 💾 - I enjoy creating beautiful user-centered interactivities and solving - abstract software puzzles to create efficiency and scalability for - teams and companies + A passionate and curious individual with a BS degree in Physics from + UCLA currently working as a Full-Stack Software Engineer at + Aerobotics7 to remove landmines from around the world. I have + experiences with Python, Django, Node.js, React.js, Figma/Lucid Charts + and other platforms and tools to facilitate on creating and solving + real-world problems for the users to enjoy, and the companies to + succeed their vision diff --git a/web/components/home/MoreSection/index.tsx b/web/components/home/MoreSection/index.tsx new file mode 100644 index 00000000..704c4bc0 --- /dev/null +++ b/web/components/home/MoreSection/index.tsx @@ -0,0 +1,204 @@ +import { FC, useEffect } from 'react'; +import { useAnimation } from 'framer-motion'; +import { useInView } from 'react-intersection-observer'; + +import HeadingSecondary from 'common/typography/HeadingSecondary'; +import Paragraph from 'common/typography/Paragraph'; + +import { + ExternalLink, + Italic, + ParagraphWrapper, + Section, + SectionTitle, +} from './styles'; + +const MoreSection: FC = () => { + const sectionAnimateControls = useAnimation(); + const { inView: sectionInView, ref: sectionRef } = useInView(); + + const titleAnimateControls = useAnimation(); + const { inView: titleInView, ref: titleRef } = useInView(); + + useEffect(() => { + const timer = setTimeout(() => { + if (sectionInView) { + sectionAnimateControls.start('visible'); + } + }, 200); + + return () => clearTimeout(timer); + }, [sectionAnimateControls, sectionInView]); + + useEffect(() => { + const timer = setTimeout(() => { + if (titleInView) { + titleAnimateControls.start('visible'); + } + }, 200); + + return () => clearTimeout(timer); + }, [titleAnimateControls, titleInView]); + + return ( +
+ + + More + + + + + + I enjoy reading as many books as I can. I am currently reading George + R.R. Martin's Game of Thrones series + (currently at the fourth book 😄), War and Peace by + Leo Tolstoy 😮, Michael Mann's  + Heat 2 (the author is the actual famous film + director), and Basic Writings of Nietzsche translated + and edited by Walter Kaufmann. My favorite book is{' '} + Dune by Frank Herbert. + + + + + + I also enjoy watching films and television with  + Children of Men by Alfonso Cuarón being my favorite + movie of all time, and my favorite TV show is a tie between  + Breaking Bad and Attack on Titan. + + + + + + A few minor things about me is that I like to be active by going to + the gym, running, and hiking with rock climbing as my next goal. I + love videogames with Half-Life 2 being my all-time + favorite. From time-to-time, I continue to learn physics and how to + apply them computationally. Lastly, I enjoy helping others whether it + is community service or teaching. + + + + + + If you want to connect with me for coffee, collaboration, or anything + else, then  + + hit me up on Twitter + +  or email ( + + gutierrezelias1991@gmail.com + + ). + + + + + + This site was created with  + + Next.js + + ,  + + TypeScript + + ,  + + Redux Toolkit + + ,  + + Styled-Components + + , and  + + Framer + +  for the Frontend being hosted in  + + Netlify + + . It was also created with  + + Django + + ,  + + Wagtail CMS + + , and  + + Django REST Framework + +  for the Backend being hosted in  + + PythonAnywhere + + . The images for the work and articles are stored in  + + AWS S3 + + . + + +
+ ); +}; + +export default MoreSection; diff --git a/web/components/home/MoreSection/styles.ts b/web/components/home/MoreSection/styles.ts new file mode 100644 index 00000000..9b7cbc58 --- /dev/null +++ b/web/components/home/MoreSection/styles.ts @@ -0,0 +1,107 @@ +import styled from 'styled-components'; +import { motion } from 'framer-motion'; + +export const Section = styled(motion.section).attrs(() => ({ + initial: 'hidden', + variants: { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { duration: 0.5 }, + }, + }, +}))` + margin-top: 12rem; + padding-left: 12rem; + text-align: right; + + &.home-page__more-section { + margin-top: 0; + } + + @media ${({ theme }) => theme.responsive.below1199} { + padding-left: 3rem; + } + + @media ${({ theme }) => theme.responsive.below899} { + margin-top: 0; + padding-right: 3rem; + } + + @media ${({ theme }) => theme.responsive.below599} { + padding-right: 0; + padding-left: 0; + } +`; + +export const SectionTitle = styled(motion.div).attrs(() => ({ + initial: 'hidden', + variants: { + hidden: { + opacity: 0, + y: 10, + }, + visible: { + opacity: 1, + y: 0, + transition: { duration: 0.5 }, + }, + }, +}))` + margin-bottom: 2.5rem; + + @media ${({ theme }) => theme.responsive.below599} { + margin-bottom: 1.75rem; + } + + @media ${({ theme }) => theme.responsive.below479} { + margin-bottom: 1.5rem; + } +`; + +export const ParagraphWrapper = styled.div` + margin-top: 2.5rem; + margin-bottom: 2.5rem; + line-height: 1.5; + + &:first-child { + margin-top: 0; + } + + &:last-child { + margin-bottom: 0; + } + + @media ${({ theme }) => theme.responsive.below899} { + line-height: 1.8; + } + + @media ${({ theme }) => theme.responsive.below599} { + margin-top: 1.75rem; + margin-bottom: 1.75rem; + } + + @media ${({ theme }) => theme.responsive.below479} { + margin-top: 1.5rem; + margin-bottom: 1.5rem; + } + + @media ${({ theme }) => theme.responsive.below379} { + line-height: 1.5; + } +`; + +export const Italic = styled.i``; + +export const ExternalLink = styled.a` + font-weight: 700; + color: ${({ theme }) => theme.colors.primary.hex}; + text-decoration: none; + word-break: break-all; + + &:hover { + text-decoration: underline; + cursor: pointer; + opacity: 0.9; + } +`; diff --git a/web/components/home/Row/index.tsx b/web/components/home/Row/index.tsx new file mode 100644 index 00000000..683177a3 --- /dev/null +++ b/web/components/home/Row/index.tsx @@ -0,0 +1,12 @@ +import styled from 'styled-components'; + +const Row = styled.div` + display: flex; + flex-direction: row; + + @media ${({ theme }) => theme.responsive.below899} { + flex-direction: column; + } +`; + +export default Row; diff --git a/web/components/home/TalkSection/TalkContainer.tsx b/web/components/home/TalkSection/TalkContainer.tsx deleted file mode 100644 index 5cc798db..00000000 --- a/web/components/home/TalkSection/TalkContainer.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import { FC, useEffect } from 'react'; -import { useAnimation } from 'framer-motion'; -import { useInView } from 'react-intersection-observer'; - -import GlassTriangle from 'common/components/GlassTriangle'; - -import { useIsHovering } from 'common/hooks'; - -import HeadingTertiary from 'common/typography/HeadingTertiary'; - -import { - TalkContainerStyle, - TalkDescriptionContainer, - TalkImageLink, - TalkImageWrapper, - TalkTitle, - TalkTitleLink, -} from './styles'; - -export interface ITalkContainer { - finishIsFirstMount: boolean; - reverseClass?: string; - talkImageAlt: string; - talkImageSrc: string; - talkLinkPath: string; - talkTitle: string; -} - -const TalkContainer: FC = ({ - finishIsFirstMount, - reverseClass, - talkImageAlt, - talkImageSrc, - talkLinkPath, - talkTitle, -}) => { - const titleAnimateControls = useAnimation(); - const { inView: titleInView, ref: titleRef } = useInView(); - - const imageAnimateControls = useAnimation(); - const { inView: imageInView, ref: imageRef } = useInView(); - - const [isTitleLinkHovering, setIsTitleLinkHovering] = useIsHovering(); - const [isImageLinkHovering, setIsImageLinkHovering] = useIsHovering(); - - useEffect(() => { - const timer = setTimeout(() => { - if (!finishIsFirstMount && titleInView) { - titleAnimateControls.start('visible'); - } - }, 700); - - return () => clearTimeout(timer); - }, [finishIsFirstMount, titleAnimateControls, titleInView]); - - useEffect(() => { - const timer = setTimeout(() => { - if (!finishIsFirstMount && imageInView) { - imageAnimateControls.start('visible'); - } - }, 1000); - - return () => clearTimeout(timer); - }, [finishIsFirstMount, imageAnimateControls, imageInView]); - - return ( - - - setIsImageLinkHovering(true)} - onHoverEnd={() => setIsImageLinkHovering(false)} - ref={imageRef} - > - - - - - - - setIsTitleLinkHovering(true)} - onMouseLeave={() => setIsTitleLinkHovering(false)} - > - - {talkTitle} - - - - - - ); -}; - -export default TalkContainer; diff --git a/web/components/home/TalkSection/index.tsx b/web/components/home/TalkSection/index.tsx deleted file mode 100644 index 93d612b3..00000000 --- a/web/components/home/TalkSection/index.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import React, { FC, useEffect } from 'react'; -import { useAnimation } from 'framer-motion'; -import { useInView } from 'react-intersection-observer'; - -import LineSeparator from 'common/components/LineSeparator'; - -import HeadingSecondary from 'common/typography/HeadingSecondary'; - -import { Container, Section, SectionTitle } from './styles'; -import TalkContainer, { ITalkContainer } from './TalkContainer'; - -const talkContainerData: Omit[] = [ - { - talkImageAlt: 'Django Part 1 Presentation', - talkImageSrc: '/talk-presentation1.png', - talkLinkPath: 'https://vimeo.com/659389997', - talkTitle: - '"Django Magic: MVT" Developer Connect Presentation @ Bitwise Industries', - }, - { - reverseClass: 'reverse', - talkImageAlt: 'Redux Toolkit Presentation', - talkImageSrc: '/talk-presentation2.png', - talkLinkPath: - 'https://us02web.zoom.us/rec/play/coJ_z0w_gxEy5gP6iFtG1FLEuzuWey7dumrFH2xZ3rQQwGCBdy91Exb3Jyu2odOXj39rp-WKgEmPad2J.9De7TgEACj6xPmx3?continueMode=true', - talkTitle: - '"Converting Legacy Redux To Redux Toolkit" Developer Connect Presentation @ Bitwise Industries', - }, -]; - -interface ITalkSection { - finishIsFirstMount: boolean; -} - -const TalkSection: FC = ({ finishIsFirstMount }) => { - const controls = useAnimation(); - const { inView, ref } = useInView(); - - useEffect(() => { - const timer = setTimeout(() => { - if (!finishIsFirstMount && inView) { - controls.start('visible'); - } - }, 500); - - return () => clearTimeout(timer); - }, [finishIsFirstMount, controls, inView]); - - return ( -
- - - Talks - - - - - - - {talkContainerData.map((talkData) => ( - - - - ))} - -
- ); -}; - -export default TalkSection; diff --git a/web/components/home/TalkSection/styles.ts b/web/components/home/TalkSection/styles.ts deleted file mode 100644 index 41ed0677..00000000 --- a/web/components/home/TalkSection/styles.ts +++ /dev/null @@ -1,141 +0,0 @@ -import styled from 'styled-components'; -import { motion } from 'framer-motion'; - -// TALK SECTION -export const Section = styled.section``; - -export const SectionTitle = styled(motion.div).attrs(() => ({ - initial: 'hidden', - variants: { - hidden: { - opacity: 0, - y: 10, - }, - visible: { - opacity: 1, - y: 0, - transition: { duration: 0.5 }, - }, - }, -}))` - text-align: center; -`; - -export const Container = styled.div` - display: flex; - padding-top: 4rem; - - @media ${({ theme }) => theme.responsive.below899} { - flex-direction: column; - } - - @media ${({ theme }) => theme.responsive.below479} { - padding-top: 1rem; - } -`; - -// TALK CONTAINER -export const TalkContainerStyle = styled.div` - padding-top: 5rem; - padding-bottom: 5rem; - - @media ${({ theme }) => theme.responsive.below899} { - padding-top: 5rem; - padding-bottom: 5rem; - } - - @media ${({ theme }) => theme.responsive.below479} { - padding-bottom: 1rem; - } - - @media ${({ theme }) => theme.responsive.below379} { - padding-top: 3rem; - } -`; - -export const TalkDescriptionContainer = styled.div` - display: flex; - flex-direction: column; - align-items: center; - text-align: center; - - &.reverse { - flex-direction: column-reverse; - padding-top: 10rem; - - @media ${({ theme }) => theme.responsive.below899} { - padding-top: 0; - } - } - - @media ${({ theme }) => theme.responsive.below599} { - overflow-x: hidden; - } -`; - -export const TalkImageWrapper = styled(motion.div).attrs(({ className }) => ({ - initial: 'hidden', - variants: { - hidden: { - opacity: 0, - x: className?.includes('reverse') ? 100 : -100, - }, - visible: { - opacity: 1, - x: 0, - transition: { - type: 'spring', - bounce: 0.4, - duration: 0.5, - }, - }, - }, -}))` - margin-bottom: 2rem; - - &.reverse { - margin-top: 2rem; - margin-bottom: 0; - } -`; - -export const TalkImageLink = styled.a``; - -export const TalkTitle = styled(motion.div).attrs(() => ({ - initial: 'hidden', - variants: { - hidden: { - opacity: 0, - }, - visible: { - opacity: 1, - transition: { duration: 0.3 }, - }, - }, -}))``; - -export const TalkTitleLink = styled.a` - padding-left: 7rem; - padding-right: 7rem; - text-decoration: none; - - @media ${({ theme }) => theme.responsive.below1199} { - padding-left: 4rem; - padding-right: 4rem; - } - - @media ${({ theme }) => theme.responsive.below899} { - padding-left: 7rem; - padding-right: 7rem; - } - - @media ${({ theme }) => theme.responsive.below599} { - padding-left: 2rem; - padding-right: 2rem; - } - - @media ${({ theme }) => theme.responsive.below479} { - padding-left: 1rem; - padding-right: 1rem; - } -`; diff --git a/web/components/home/WorkSection/WorkContainer.tsx b/web/components/home/WorkSection/WorkContainer.tsx deleted file mode 100644 index c4e2250e..00000000 --- a/web/components/home/WorkSection/WorkContainer.tsx +++ /dev/null @@ -1,302 +0,0 @@ -import { FC, useEffect } from 'react'; -import Link from 'next/link'; -import { useAnimation } from 'framer-motion'; -import { useInView } from 'react-intersection-observer'; - -import GlassRectangle from 'common/components/GlassRectangle'; - -import { useIsHovering } from 'common/hooks'; - -import HeadingTertiary from 'common/typography/HeadingTertiary'; -import Paragraph from 'common/typography/Paragraph'; - -import { isHoveringOverall } from 'utils'; - -import { - WorkContainerStyle, - WorkDescription, - WorkDescriptionContainer, - WorkExternalLink, - WorkImageLink, - WorkImageWrapper, - WorkLink, - WorkLinkWrapper, - WorkTitle, - WorkTitleLink, -} from './styles'; - -export interface IWorkContainer { - finishIsFirstMount: boolean; - isExploreLinkHovering: boolean; - reverseClass?: string; - workDescription: string; - workExternalLinkPath: string; - workImageAlt: string; - workImageSrc: string; - workLinkPath: string; - workTitle: string; -} - -const WorkContainer: FC = ({ - finishIsFirstMount, - isExploreLinkHovering, - reverseClass, - workDescription, - workExternalLinkPath, - workImageAlt, - workImageSrc, - workLinkPath, - workTitle, -}) => { - const titleAnimateControls = useAnimation(); - const { inView: titleInView, ref: titleRef } = useInView(); - - const descriptionAnimateControls = useAnimation(); - const { inView: descriptionInView, ref: descriptionRef } = useInView(); - - const externalLinkAnimateControls = useAnimation(); - const { inView: externalLinkInView, ref: externalLinkRef } = useInView(); - - const linkAnimateControls = useAnimation(); - const { inView: linkInView, ref: linkRef } = useInView(); - - const imageAnimateControls = useAnimation(); - const { inView: imageInView, ref: imageRef } = useInView(); - - const [isTitleLinkHovering, setIsTitleLinkHovering] = useIsHovering(); - const [isImageLinkHovering, setIsImageLinkHovering] = useIsHovering(); - const [isWorkLinkHovering, setIsWorkLinkHovering] = useIsHovering(); - - useEffect(() => { - const timer = setTimeout(() => { - if (!finishIsFirstMount && titleInView) { - titleAnimateControls.start('visible'); - } - }, 600); - - return () => clearTimeout(timer); - }, [finishIsFirstMount, titleAnimateControls, titleInView]); - - useEffect(() => { - const timer = setTimeout(() => { - if (!finishIsFirstMount && descriptionInView) { - descriptionAnimateControls.start('visible'); - } - }, 800); - - return () => clearTimeout(timer); - }, [finishIsFirstMount, descriptionAnimateControls, descriptionInView]); - - useEffect(() => { - const timer = setTimeout(() => { - if (!finishIsFirstMount && externalLinkInView) { - externalLinkAnimateControls.start('visible'); - } - }, 1700); - - return () => clearTimeout(timer); - }, [finishIsFirstMount, externalLinkAnimateControls, externalLinkInView]); - - useEffect(() => { - const timer = setTimeout(() => { - if (!finishIsFirstMount && linkInView) { - linkAnimateControls.start('visible'); - } - }, 1700); - - return () => clearTimeout(timer); - }, [finishIsFirstMount, linkAnimateControls, linkInView]); - - useEffect(() => { - const timer = setTimeout(() => { - if (!finishIsFirstMount && imageInView) { - imageAnimateControls.start('visible'); - } - }, 1500); - - return () => clearTimeout(timer); - }, [finishIsFirstMount, imageAnimateControls, imageInView]); - - useEffect(() => { - if ( - !finishIsFirstMount && - isHoveringOverall( - isImageLinkHovering, - isWorkLinkHovering, - isExploreLinkHovering - ) - ) { - imageAnimateControls.start('hovering'); - } else { - imageAnimateControls.start('nonHovering'); - } - }, [ - finishIsFirstMount, - isImageLinkHovering, - isWorkLinkHovering, - isExploreLinkHovering, - imageAnimateControls, - ]); - - return ( - - - - setIsTitleLinkHovering(true)} - onMouseLeave={() => setIsTitleLinkHovering(false)} - > - - {workTitle} - - - - - - - - - {workDescription} - - - - {workExternalLinkPath.length > 0 && ( - - - App - - - )} - - - - setIsWorkLinkHovering(true)} - onMouseLeave={() => setIsWorkLinkHovering(false)} - > - About - - - - - - setIsImageLinkHovering(true)} - onHoverEnd={() => setIsImageLinkHovering(false)} - ref={imageRef} - > - - - - - - - - ); -}; - -export default WorkContainer; diff --git a/web/components/home/WorkSection/index.tsx b/web/components/home/WorkSection/index.tsx deleted file mode 100644 index f6190a68..00000000 --- a/web/components/home/WorkSection/index.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import React, { FC, useEffect } from 'react'; -import Link from 'next/link'; -import { useAnimation } from 'framer-motion'; -import { useInView } from 'react-intersection-observer'; - -import LineSeparator from 'common/components/LineSeparator'; - -import { useIsHovering } from 'common/hooks'; - -import HeadingSecondary from 'common/typography/HeadingSecondary'; - -import { IWork } from 'common/models'; - -import environment from 'environment'; - -import { - Container, - ExploreMoreLink, - ExploreMoreWrapper, - Section, - SectionTitle, -} from './styles'; -import WorkContainer from './WorkContainer'; - -type TWorksData = Pick< - IWork, - | 'category' - | 'description' - | 'first_released_at' - | 'id' - | 'logo_image' - | 'title' - | 'uuid' - | 'work_url' -> & { - meta: Pick; -}; - -interface IWorkSection { - finishIsFirstMount: boolean; - worksData: TWorksData[]; -} - -const WorkSection: FC = ({ finishIsFirstMount, worksData }) => { - const titleAnimateControls = useAnimation(); - const { inView: titleInView, ref: titleRef } = useInView(); - - const viewMoreAnimateControls = useAnimation(); - const { inView: viewMoreInView, ref: viewMoreRef } = useInView(); - - const [isHovering, setIsHovering] = useIsHovering(); - - useEffect(() => { - const timer = setTimeout(() => { - if (!finishIsFirstMount && titleInView) { - titleAnimateControls.start('visible'); - } - }, 500); - - return () => clearTimeout(timer); - }, [finishIsFirstMount, titleAnimateControls, titleInView]); - - useEffect(() => { - const timer = setTimeout(() => { - if (!finishIsFirstMount && viewMoreInView) { - viewMoreAnimateControls.start('visible'); - } - }, 2000); - - return () => clearTimeout(timer); - }, [finishIsFirstMount, viewMoreAnimateControls, viewMoreInView]); - - return ( -
- - - Work - - - - - {worksData.length > 0 && - worksData.slice(0, 3).map((workData, workIndex) => ( - - - - - - ))} - - - - - setIsHovering(true)} - onMouseLeave={() => setIsHovering(false)} - > - Explore all work - - - -
- ); -}; - -export default WorkSection; diff --git a/web/components/home/WorkSection/styles.ts b/web/components/home/WorkSection/styles.ts deleted file mode 100644 index 09d3cf4e..00000000 --- a/web/components/home/WorkSection/styles.ts +++ /dev/null @@ -1,343 +0,0 @@ -import styled from 'styled-components'; -import { motion } from 'framer-motion'; - -// WORK SECTION -export const Section = styled.section``; - -export const SectionTitle = styled(motion.div).attrs(() => ({ - initial: 'hidden', - variants: { - hidden: { - opacity: 0, - y: 10, - }, - visible: { - opacity: 1, - y: 0, - transition: { duration: 0.5 }, - }, - }, -}))` - text-align: right; -`; - -export const Container = styled.div` - display: flex; - flex-direction: column; - padding-top: 4rem; - - @media ${({ theme }) => theme.responsive.below1199} { - padding-top: 2.5rem; - } - - @media ${({ theme }) => theme.responsive.below899} { - padding-top: 2.3rem; - } - - @media ${({ theme }) => theme.responsive.below479} { - padding-top: 1rem; - } -`; - -export const ExploreMoreWrapper = styled(motion.div).attrs(() => ({ - variants: { - visible: { - rotate: [0, 15, 7.5, 15, 0], - transition: { - duration: 1, - ease: 'easeInOut', - times: [0, 0.2, 0.5, 0.8, 1], - }, - }, - }, -}))` - margin-top: 5rem; - text-align: center; - - @media ${({ theme }) => theme.responsive.below599} { - margin-top: 2rem; - } - - @media ${({ theme }) => theme.responsive.below479} { - margin-top: 1rem; - } -`; - -export const ExploreMoreLink = styled.a` - font-size: 2rem; - font-weight: 700; - color: ${({ theme }) => theme.colors.primary.hex}; - text-decoration: none; - - &:hover { - text-decoration: underline; - cursor: pointer; - opacity: 0.9; - } - - @media ${({ theme }) => theme.responsive.below479} { - font-size: 1.7rem; - } -`; - -// WORK CONTAINER -export const WorkContainerStyle = styled.div` - display: flex; - justify-content: space-between; - margin-top: 9rem; - margin-bottom: 9rem; - padding-top: 1rem; - padding-bottom: 1rem; - - &.reverse { - flex-direction: row-reverse; - - @media ${({ theme }) => theme.responsive.below899} { - flex-direction: column-reverse; - } - } - - @media ${({ theme }) => theme.responsive.below899} { - flex-direction: column; - margin-top: 5rem; - margin-bottom: 5rem; - } - - @media ${({ theme }) => theme.responsive.below479} { - margin-top: 3rem; - margin-bottom: 3rem; - } - - @media ${({ theme }) => theme.responsive.below379} { - margin-top: 2rem; - margin-bottom: 2rem; - } -`; - -export const WorkTitle = styled(motion.div).attrs(() => ({ - initial: 'hidden', - variants: { - hidden: { - opacity: 0, - }, - visible: { - opacity: 1, - transition: { duration: 0.3 }, - }, - }, -}))` - width: 35%; - - &.reverse { - text-align: right; - - @media ${({ theme }) => theme.responsive.below899} { - text-align: center; - } - - @media ${({ theme }) => theme.responsive.below379} { - text-align: left; - } - } - - @media ${({ theme }) => theme.responsive.below899} { - width: 100%; - padding: 1rem 4.5rem; - text-align: center; - } - - @media ${({ theme }) => theme.responsive.below479} { - padding: 1rem 1rem; - } - - @media ${({ theme }) => theme.responsive.below379} { - text-align: left; - } -`; - -export const WorkTitleLink = styled.a` - text-decoration: none; -`; - -export const WorkDescriptionContainer = styled.div` - display: flex; - flex-direction: column; - width: 100%; - padding: 2rem 4.5rem; - - @media ${({ theme }) => theme.responsive.below899} { - padding: 1rem 4.5rem; - } - - @media ${({ theme }) => theme.responsive.below479} { - padding: 1rem 1rem; - } -`; - -export const WorkDescription = styled(motion.div).attrs(() => ({ - initial: 'hidden', - variants: { - hidden: { - opacity: 0, - }, - visible: { - opacity: 1, - transition: { duration: 0.3 }, - }, - }, -}))` - margin-bottom: 2rem; - - &.reverse { - text-align: right; - - @media ${({ theme }) => theme.responsive.below899} { - text-align: center; - } - - @media ${({ theme }) => theme.responsive.below379} { - margin-bottom: 1rem; - text-align: left; - } - } - - @media ${({ theme }) => theme.responsive.below899} { - text-align: center; - } - - @media ${({ theme }) => theme.responsive.below379} { - text-align: left; - } -`; - -export const WorkLinkWrapper = styled(motion.div).attrs(({ className }) => ({ - initial: 'hidden', - variants: { - hidden: { - opacity: 0, - y: className?.includes('reverse') ? -100 : -150, - }, - visible: { - opacity: 1, - y: 0, - transition: { - type: 'spring', - bounce: 0.4, - duration: 0.5, - }, - }, - }, -}))` - text-align: right; - - &.external-link { - margin-bottom: 2rem; - } - - &.reverse { - text-align: left; - - @media ${({ theme }) => theme.responsive.below899} { - text-align: center; - } - - @media ${({ theme }) => theme.responsive.below379} { - order: -1; - margin-bottom: 2rem; - text-align: right; - } - } - - @media ${({ theme }) => theme.responsive.below899} { - padding: 1rem 4.5rem; - text-align: center; - } - - @media ${({ theme }) => theme.responsive.below479} { - padding: 0rem 1rem; - } - - @media ${({ theme }) => theme.responsive.below379} { - text-align: right; - } -`; - -export const WorkLink = styled.a` - font-size: ${({ theme }) => theme.fonts.paragraph}; - font-weight: 700; - color: ${({ theme }) => theme.colors.primary.hex}; - text-decoration: none; - - &:hover { - opacity: 0.7; - } -`; - -export const WorkExternalLink = styled.a` - font-size: ${({ theme }) => theme.fonts.paragraph}; - font-weight: 700; - color: ${({ theme }) => theme.colors.primary.hex}; - text-decoration: none; - - &:hover { - opacity: 0.7; - } -`; - -export const WorkImageWrapper = styled(motion.div).attrs(({ className }) => ({ - initial: 'hidden', - variants: { - hidden: { - opacity: 0, - y: className?.includes('reverse') ? -100 : -150, - }, - hovering: { - rotate: className?.includes('reverse') ? 5 : -5, - scale: 1.01, - transition: { - type: 'spring', - bounce: 0.4, - duration: 0.2, - }, - }, - nonHovering: { - rotate: 0, - scale: 1, - }, - visible: { - opacity: 1, - y: 0, - transition: { - type: 'spring', - bounce: 0.4, - duration: 0.5, - }, - }, - }, -}))` - width: 18%; - margin-left: 3rem; - - &.reverse { - margin-left: 0; - margin-right: 3rem; - - @media ${({ theme }) => theme.responsive.below899} { - margin-right: auto; - margin-left: auto; - } - } - - @media ${({ theme }) => theme.responsive.below899} { - width: 85%; - margin-right: auto; - margin-left: auto; - padding: 1rem 4.5rem; - } - - @media ${({ theme }) => theme.responsive.below479} { - padding: 1rem 1rem; - } -`; - -export const WorkImageLink = styled.a``; diff --git a/web/components/home/index.ts b/web/components/home/index.ts index e9bcd71b..66d9da93 100644 --- a/web/components/home/index.ts +++ b/web/components/home/index.ts @@ -1,5 +1,9 @@ -export { default as ArticleSection } from './ArticleSection'; +export { default as AboutImage } from './AboutImage'; +export { default as AboutSection } from './AboutSection'; +export { default as BeliefsSection } from './BeliefsSection'; +export { default as Col } from './Col'; +export { default as ExperienceSection } from './ExperienceSection'; export { default as HeroBanner } from './HeroBanner'; export { default as InitialSiteTransition } from './InitialSiteTransition'; -export { default as TalkSection } from './TalkSection'; -export { default as WorkSection } from './WorkSection'; +export { default as MoreSection } from './MoreSection'; +export { default as Row } from './Row'; diff --git a/web/pages/about/index.tsx b/web/pages/about/index.tsx deleted file mode 100644 index 7abbe4d8..00000000 --- a/web/pages/about/index.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import type { NextPage } from 'next'; -import Head from 'next/head'; - -import LineSeparator from 'common/components/LineSeparator'; -import LoadingIcon from 'common/components/LoadingIcon'; -import PageContainer from 'common/components/PageContainer'; -import WithLoadingOverlay from 'common/components/WithLoadingOverlay'; - -import { - AboutImage, - AboutSection, - BeliefsSection, - Col, - ExperienceSection, - MoreSection, - Row, -} from 'components/about'; - -import environment from 'environment'; - -const About: NextPage = () => ( - <> - - About | Elias Gutierrez, Software Developer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - } - isLoading={false} - loaderComponent={} - loaderDuration={1000} - /> - - -); - -export default About; diff --git a/web/pages/articles/[slug].tsx b/web/pages/articles/[slug].tsx index 6334bdfe..92a0a227 100644 --- a/web/pages/articles/[slug].tsx +++ b/web/pages/articles/[slug].tsx @@ -78,7 +78,7 @@ const Article: NextPage = () => { articleData.meta.seo_title.length > 0 ? articleData.meta.seo_title : articleData.title - } - Articles | Elias Gutierrez, Software Developer` + } - Articles | Elias Gutierrez, Software Engineer` : ''} @@ -95,7 +95,7 @@ const Article: NextPage = () => { { return ( <> - Articles | Elias Gutierrez, Software Developer + Articles | Elias Gutierrez, Software Engineer diff --git a/web/pages/index.tsx b/web/pages/index.tsx index 7fdfe11b..e336925f 100644 --- a/web/pages/index.tsx +++ b/web/pages/index.tsx @@ -6,30 +6,30 @@ import { nextReduxWrapper } from 'app'; import { getArticles, getRunningOperationPromises as getArticlesRunningOperationPromises, - useGetArticlesQuery, } from 'app/api/articleExtendedApi'; import { getWorksByCategory, getRunningOperationPromises as getWorksRunningOperationPromises, - useGetWorksByCategoryQuery, } from 'app/api/workExtendedApi'; +import LineSeparator from 'common/components/LineSeparator'; import LoadingIcon from 'common/components/LoadingIcon'; import PageContainer from 'common/components/PageContainer'; import WithLoadingOverlay from 'common/components/WithLoadingOverlay'; import { - ArticleSection, + AboutImage, + BeliefsSection, + Col, + ExperienceSection, HeroBanner, InitialSiteTransition, - TalkSection, - WorkSection, + MoreSection, + Row, } from 'components/home'; import environment from 'environment'; -import { isLoadingOverall } from 'utils'; - interface IHome { isFirstMount: boolean; } @@ -64,28 +64,6 @@ export const getStaticProps = nextReduxWrapper.getStaticProps( const Home: NextPage = ({ isFirstMount }) => { const [finishIsFirstMount, setFinishIsFirstMount] = useState(isFirstMount); - const { data: articlesData, isFetching: articlesFetching } = - useGetArticlesQuery({ - category: 0, - limit: 3, - tags: [], - }); - - const { selectedData: worksData, isFetching: worksFetching } = - useGetWorksByCategoryQuery( - { category: 'Work', limit: 5 }, - { - selectFromResult: (result) => ({ - ...result, - selectedData: result.data - ? result.data.items.filter( - (resultData) => resultData.title !== 'Node News API' - ) - : [], - }), - } - ); - useEffect(() => { const timer = setTimeout(() => { if (!isFirstMount) setFinishIsFirstMount(isFirstMount); @@ -97,28 +75,28 @@ const Home: NextPage = ({ isFirstMount }) => { return ( <> - Elias Gutierrez, Software Developer + Elias Gutierrez, Software Engineer @@ -134,12 +112,12 @@ const Home: NextPage = ({ isFirstMount }) => { = ({ isFirstMount }) => { - - - - - + + + + + + + + + + + + + + + + + + + + + + + + {/* */} + + + + + } - isLoading={isLoadingOverall(worksFetching, articlesFetching)} + isLoading={false} loaderDuration={1000} {...(!finishIsFirstMount && { loaderComponent: , diff --git a/web/pages/work/[slug].tsx b/web/pages/work/[slug].tsx index 7de458e2..96c0dc30 100644 --- a/web/pages/work/[slug].tsx +++ b/web/pages/work/[slug].tsx @@ -75,7 +75,7 @@ const Work: NextPage = () => { workData.meta.seo_title.length > 0 ? workData.meta.seo_title : workData.title - } - Work | Elias Gutierrez, Software Developer` + } - Work | Elias Gutierrez, Software Engineer` : ''} @@ -92,7 +92,7 @@ const Work: NextPage = () => { { return ( <> - Work | Elias Gutierrez, Software Developer + Work | Elias Gutierrez, Software Engineer { diff --git a/web/public/about-pic.jpeg b/web/public/about-pic1.jpeg similarity index 100% rename from web/public/about-pic.jpeg rename to web/public/about-pic1.jpeg diff --git a/web/public/about-pic3.jpg b/web/public/about-pic3.jpg new file mode 100644 index 00000000..8c4b1504 Binary files /dev/null and b/web/public/about-pic3.jpg differ diff --git a/web/public/manifest.json b/web/public/manifest.json index 5a45d276..deb04673 100644 --- a/web/public/manifest.json +++ b/web/public/manifest.json @@ -1,7 +1,7 @@ { "short_name": "Portfolio", "name": "Elias Gutierrez's Portfolio", - "description": "Software and Full-Stack Developer. Creating beautiful user-centered interactivity and experiences.", + "description": "Full-Stack Software Engineer. Drinking coffee while learning and improving on new and existing tech.", "icons": [ { "src": "/favicon.ico",