diff --git a/src/app/about/page.tsx b/src/app/about/page.tsx index 108e672..aaa668e 100644 --- a/src/app/about/page.tsx +++ b/src/app/about/page.tsx @@ -1,14 +1,15 @@ import Typography from '@mui/material/Typography'; -import Box from '@mui/material/Box'; import { Metadata } from 'next'; +import PageContainer from '@/components/PageContainer'; + export const metadata: Metadata = { title: 'About', }; const About: React.FC = () => { return ( - + About Lorem ipsum dolor, sit amet consectetur adipisicing elit. Ipsum tempore @@ -16,7 +17,7 @@ const About: React.FC = () => { blanditiis sunt ex consectetur asperiores assumenda nisi laboriosam et tempora quos. - + ); }; diff --git a/src/app/contact/page.tsx b/src/app/contact/page.tsx index d8b0753..e0f579c 100644 --- a/src/app/contact/page.tsx +++ b/src/app/contact/page.tsx @@ -5,6 +5,7 @@ import List from '@mui/material/List'; import ListItem from '@mui/material/ListItem'; import ExternalLink from '@/components/ExternalLink'; +import PageContainer from '@/components/PageContainer'; export const metadata: Metadata = { title: 'Contact', @@ -12,7 +13,7 @@ export const metadata: Metadata = { const Contact: React.FC = () => { return ( - + Contact @@ -47,7 +48,7 @@ const Contact: React.FC = () => { - + ); }; diff --git a/src/app/work/ChipList.tsx b/src/app/work/ChipList.tsx new file mode 100644 index 0000000..375286a --- /dev/null +++ b/src/app/work/ChipList.tsx @@ -0,0 +1,25 @@ +import List, { ListProps } from '@mui/material/List'; + +interface ChipListProps extends ListProps { + children: React.ReactNode; +} + +const ChipList: React.FC = ({ children, ...props }) => { + return ( + + {children} + + ); +}; + +export default ChipList; diff --git a/src/app/work/ChipListItem.tsx b/src/app/work/ChipListItem.tsx new file mode 100644 index 0000000..44e86c0 --- /dev/null +++ b/src/app/work/ChipListItem.tsx @@ -0,0 +1,23 @@ +import ListItem, { ListItemProps } from '@mui/material/ListItem'; + +interface ChipListItemProps extends ListItemProps { + children: React.ReactNode; +} + +const ChipListItem: React.FC = ({ children, ...props }) => { + return ( + + {children} + + ); +}; + +export default ChipListItem; diff --git a/src/app/work/WorkPanel.tsx b/src/app/work/WorkPanel.tsx new file mode 100644 index 0000000..5294f4f --- /dev/null +++ b/src/app/work/WorkPanel.tsx @@ -0,0 +1,79 @@ +import Box, { BoxProps } from '@mui/material/Box'; +import Typography from '@mui/material/Typography'; +import Chip from '@mui/material/Chip'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; + +import { WorkItemType } from './constants'; +import ChipList from './ChipList'; +import ChipListItem from './ChipListItem'; + +interface WorkPanelProps extends BoxProps { + item: WorkItemType; +} + +const WorkPanel: React.FC = ({ item, ...props }) => { + return ( + + + + {item.company} | {item.title} + + + {item.startDate} - {item.endDate} + + {item.location} + {!!item.experience.length && ( + + {item.experience.map((experience, index) => { + return ( + ({ + '&::before': { + content: '"-"', + pr: theme.spacing(0.5), + alignSelf: 'flex-start', + }, + })} + > + {experience} + + ); + })} + + )} + {!!item.skills.length && ( + + {item.skills.map((skill) => { + return ( + + + + ); + })} + + )} + {!!item.tools.length && ( + + {item.tools.map((tool) => { + return ( + + + + ); + })} + + )} + + + ); +}; + +export default WorkPanel; diff --git a/src/app/work/WorkTabs.tsx b/src/app/work/WorkTabs.tsx new file mode 100644 index 0000000..be3f2de --- /dev/null +++ b/src/app/work/WorkTabs.tsx @@ -0,0 +1,71 @@ +'use client'; + +import { useState, SyntheticEvent } from 'react'; +import Box from '@mui/material/Box'; +import Tabs from '@mui/material/Tabs'; +import Tab from '@mui/material/Tab'; + +import { WorkItemType } from './constants'; +import WorkPanel from './WorkPanel'; + +type GetIdType = (index: number) => string; + +const getTabId: GetIdType = (index) => `work-tab-${index}`; +const getTabPanelId: GetIdType = (index) => `work-tabpanel-${index}`; + +type TabsOnChange = (event: SyntheticEvent, value: any) => void; + +interface WorkTabsProps { + items: WorkItemType[]; +} + +const WorkTabs: React.FC = ({ items }) => { + const [value, setValue] = useState(0); + + const handleChange: TabsOnChange = (_, newValue) => { + setValue(newValue); + }; + + return ( + + + + {items.map((item, index) => { + return ( + + ); + })} + + + {items.map((item, index) => { + const isActive = value === index; + return ( + + ); +}; + +export default WorkTabs; diff --git a/src/app/work/__snapshots__/page.test.tsx.snap b/src/app/work/__snapshots__/page.test.tsx.snap new file mode 100644 index 0000000..702496b --- /dev/null +++ b/src/app/work/__snapshots__/page.test.tsx.snap @@ -0,0 +1,2900 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`The Work Page has expected snapshot 1`] = ` +[ + .emotion-0 { + background-color: #fff; + color: rgba(0, 0, 0, 0.87); + -webkit-transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + box-shadow: 0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12); + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + width: 100%; + box-sizing: border-box; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + position: fixed; + z-index: 1100; + top: 0; + left: auto; + right: 0; + background-color: #FA2742; + color: #fff; + background-color: #E8EAE3; + border: 8px solid; + border-color: #373833; + min-height: 60px; + height: 60px; + font-weight: 700; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + justify-content: space-between; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + box-shadow: none; +} + +@media print { + .emotion-0 { + position: absolute; + } +} + +.emotion-1 { + font-family: fontFamily; + font-size: 30px; + height: 100%; + width: 60px; + border-right: 8px solid; + border-right-color: #373833; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.emotion-1:hover { + cursor: pointer; +} + +.emotion-2 { + margin: 0; + font: inherit; + color: #FA2742; + -webkit-text-decoration: none; + text-decoration: none; + color: #373833; + width: 100%; + text-align: center; +} + +.emotion-2:hover { + -webkit-text-decoration: underline; + text-decoration: underline; +} + +.emotion-2:hover { + color: rgb(251, 82, 103); + -webkit-text-decoration: none; + text-decoration: none; +} + +.emotion-2::before { + content: "nf"; +} + +.emotion-3 { + position: absolute; + width: 1px; + height: 1px; + padding: 0px; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0px solid; +} + +.emotion-4 { + list-style: none; + margin: 0; + padding: 0; + position: relative; + padding-top: 8px; + padding-bottom: 8px; + list-style: none; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} + +.emotion-5 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -ms-flex-pack: start; + -webkit-justify-content: flex-start; + justify-content: flex-start; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + position: relative; + -webkit-text-decoration: none; + text-decoration: none; + width: 100%; + box-sizing: border-box; + text-align: left; + padding-top: 8px; + padding-bottom: 8px; + padding-left: 16px; + padding-right: 16px; + -webkit-transition: -webkit-transform 0.25s ease; + transition: transform 0.25s ease; +} + +.emotion-5.Mui-focusVisible { + background-color: rgba(0, 0, 0, 0.12); +} + +.emotion-5.Mui-selected { + background-color: rgba(250, 39, 66, 0.08); +} + +.emotion-5.Mui-selected.Mui-focusVisible { + background-color: rgba(250, 39, 66, 0.2); +} + +.emotion-5.Mui-disabled { + opacity: 0.38; +} + +.emotion-5:hover { + -webkit-transform: scale(1.2); + -moz-transform: scale(1.2); + -ms-transform: scale(1.2); + transform: scale(1.2); +} + +.emotion-6 { + margin: 0; + font: inherit; + color: #FA2742; + -webkit-text-decoration: none; + text-decoration: none; + box-sizing: border-box; + height: 100%; + -webkit-text-decoration: none; + text-decoration: none; + color: #373833; + -webkit-transition: color 0.25s ease; + transition: color 0.25s ease; +} + +.emotion-6:hover { + -webkit-text-decoration: underline; + text-decoration: underline; +} + +@media (min-width:600px) { + .emotion-6 { + letter-spacing: 2.75px; + } +} + +.emotion-6:hover { + color: rgb(251, 82, 103); + -webkit-text-decoration: none; + text-decoration: none; +} + +
+ + +
, + .emotion-0 { + width: 100%; + margin-left: auto; + box-sizing: border-box; + margin-right: auto; + display: block; + padding-left: 16px; + padding-right: 16px; + margin-top: 60px; + min-height: calc(100vh - 60px - 175px); + padding: 0!important; + max-width: 100%!important; +} + +@media (min-width:600px) { + .emotion-0 { + padding-left: 24px; + padding-right: 24px; + } +} + +@media (min-width:1200px) { + .emotion-0 { + max-width: 1200px; + } +} + +.emotion-1 { + width: 100%; + margin-left: auto; + box-sizing: border-box; + margin-right: auto; + display: block; + padding-left: 16px; + padding-right: 16px; + padding-top: 16px; + padding-bottom: 16px; +} + +@media (min-width:600px) { + .emotion-1 { + padding-left: 24px; + padding-right: 24px; + } +} + +@media (min-width:1200px) { + .emotion-1 { + max-width: 1200px; + } +} + +.emotion-2 { + margin: 0; + font-family: fontFamily; + font-weight: 300; + font-size: 3.5rem; + line-height: 1.167; +} + +@media (min-width:600px) { + .emotion-2 { + font-size: 4.7129rem; + } +} + +@media (min-width:900px) { + .emotion-2 { + font-size: 5.3556rem; + } +} + +@media (min-width:1200px) { + .emotion-2 { + font-size: 5.9983rem; + } +} + +.emotion-3 { + margin: 0; + font-family: fontFamily; + font-weight: 400; + font-size: 0.875rem; + line-height: 1.43; +} + +.emotion-4 { + width: 100%; +} + +.emotion-5 { + border-bottom: 1px solid; + border-color: rgba(0, 0, 0, 0.12); +} + +.emotion-6 { + overflow: hidden; + min-height: 48px; + -webkit-overflow-scrolling: touch; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} + +.emotion-7 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + position: relative; + box-sizing: border-box; + -webkit-tap-highlight-color: transparent; + background-color: transparent; + outline: 0; + border: 0; + margin: 0; + border-radius: 0; + padding: 0; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + vertical-align: middle; + -moz-appearance: none; + -webkit-appearance: none; + -webkit-text-decoration: none; + text-decoration: none; + color: inherit; + width: 40px; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + opacity: 0.8; +} + +.emotion-7::-moz-focus-inner { + border-style: none; +} + +.emotion-7.Mui-disabled { + pointer-events: none; + cursor: default; +} + +@media print { + .emotion-7 { + -webkit-print-color-adjust: exact; + color-adjust: exact; + } +} + +.emotion-7.Mui-disabled { + opacity: 0; +} + +.emotion-8 { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + width: 1em; + height: 1em; + display: inline-block; + fill: currentColor; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + -webkit-transition: fill 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + transition: fill 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + font-size: 1.25rem; +} + +.emotion-9 { + overflow-x: auto; + overflow-y: hidden; + scrollbar-width: none; +} + +.emotion-9::-webkit-scrollbar { + display: none; +} + +.emotion-10 { + position: relative; + display: inline-block; + -webkit-flex: 1 1 auto; + -ms-flex: 1 1 auto; + flex: 1 1 auto; + white-space: nowrap; + scrollbar-width: none; + overflow-x: auto; + overflow-y: hidden; +} + +.emotion-10::-webkit-scrollbar { + display: none; +} + +.emotion-11 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} + +.emotion-12 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + position: relative; + box-sizing: border-box; + -webkit-tap-highlight-color: transparent; + background-color: transparent; + outline: 0; + border: 0; + margin: 0; + border-radius: 0; + padding: 0; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + vertical-align: middle; + -moz-appearance: none; + -webkit-appearance: none; + -webkit-text-decoration: none; + text-decoration: none; + color: inherit; + font-family: fontFamily; + font-weight: 500; + font-size: 0.875rem; + line-height: 1.25; + text-transform: uppercase; + max-width: 360px; + min-width: 90px; + position: relative; + min-height: 48px; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding: 12px 16px; + overflow: hidden; + white-space: normal; + text-align: center; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + color: rgba(0, 0, 0, 0.6); +} + +.emotion-12::-moz-focus-inner { + border-style: none; +} + +.emotion-12.Mui-disabled { + pointer-events: none; + cursor: default; +} + +@media print { + .emotion-12 { + -webkit-print-color-adjust: exact; + color-adjust: exact; + } +} + +.emotion-12.Mui-selected { + color: #FA2742; +} + +.emotion-12.Mui-disabled { + color: rgba(0, 0, 0, 0.38); +} + +.emotion-13 { + position: absolute; + height: 2px; + bottom: 0; + width: 100%; + -webkit-transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + background-color: #FA2742; +} + +.emotion-19 { + padding: 24px; +} + +.emotion-20 { + margin: 0; + font-family: fontFamily; + font-weight: 400; + font-size: 1.25rem; + line-height: 1.334; +} + +@media (min-width:600px) { + .emotion-20 { + font-size: 1.3118rem; + } +} + +@media (min-width:900px) { + .emotion-20 { + font-size: 1.4993rem; + } +} + +@media (min-width:1200px) { + .emotion-20 { + font-size: 1.4993rem; + } +} + +.emotion-21 { + margin: 0; + font-family: fontFamily; + font-weight: 400; + font-size: 0.75rem; + line-height: 2.66; + text-transform: uppercase; +} + +.emotion-22 { + margin: 0; + font-family: fontFamily; + font-weight: 500; + font-size: 0.875rem; + line-height: 1.57; +} + +.emotion-23 { + list-style: none; + margin: 0; + padding: 0; + position: relative; + padding-top: 8px; + padding-bottom: 8px; +} + +.emotion-24 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -ms-flex-pack: start; + -webkit-justify-content: flex-start; + justify-content: flex-start; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + position: relative; + -webkit-text-decoration: none; + text-decoration: none; + width: 100%; + box-sizing: border-box; + text-align: left; + padding-top: 8px; + padding-bottom: 8px; + padding-left: 16px; + padding-right: 16px; +} + +.emotion-24.Mui-focusVisible { + background-color: rgba(0, 0, 0, 0.12); +} + +.emotion-24.Mui-selected { + background-color: rgba(250, 39, 66, 0.08); +} + +.emotion-24.Mui-selected.Mui-focusVisible { + background-color: rgba(250, 39, 66, 0.2); +} + +.emotion-24.Mui-disabled { + opacity: 0.38; +} + +.emotion-24::before { + content: "-"; + padding-right: 4px; + -webkit-align-self: flex-start; + -ms-flex-item-align: flex-start; + align-self: flex-start; +} + +.emotion-28 { + list-style: none; + margin: 0; + padding: 0; + position: relative; + padding-top: 8px; + padding-bottom: 8px; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -ms-flex-pack: start; + -webkit-justify-content: flex-start; + justify-content: flex-start; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; +} + +.emotion-29 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -ms-flex-pack: start; + -webkit-justify-content: flex-start; + justify-content: flex-start; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + position: relative; + -webkit-text-decoration: none; + text-decoration: none; + width: 100%; + box-sizing: border-box; + text-align: left; + padding-top: 8px; + padding-bottom: 8px; + padding-left: 16px; + padding-right: 16px; + padding-right: 8px; + padding-left: 0px; + width: initial; +} + +.emotion-29.Mui-focusVisible { + background-color: rgba(0, 0, 0, 0.12); +} + +.emotion-29.Mui-selected { + background-color: rgba(250, 39, 66, 0.08); +} + +.emotion-29.Mui-selected.Mui-focusVisible { + background-color: rgba(250, 39, 66, 0.2); +} + +.emotion-29.Mui-disabled { + opacity: 0.38; +} + +.emotion-30 { + max-width: 100%; + font-family: fontFamily; + font-size: 0.8125rem; + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + height: 24px; + color: #fff; + background-color: #FA2742; + border-radius: 16px; + white-space: nowrap; + -webkit-transition: background-color 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + transition: background-color 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + cursor: unset; + outline: 0; + -webkit-text-decoration: none; + text-decoration: none; + border: 0; + padding: 0; + vertical-align: middle; + box-sizing: border-box; +} + +.emotion-30.Mui-disabled { + opacity: 0.38; + pointer-events: none; +} + +.emotion-30 .MuiChip-avatar { + margin-left: 5px; + margin-right: -6px; + width: 24px; + height: 24px; + color: #616161; + font-size: 0.75rem; +} + +.emotion-30 .MuiChip-avatarColorPrimary { + color: #fff; + background-color: rgb(175, 27, 46); +} + +.emotion-30 .MuiChip-avatarColorSecondary { + color: #fff; + background-color: rgb(38, 39, 35); +} + +.emotion-30 .MuiChip-avatarSmall { + margin-left: 4px; + margin-right: -4px; + width: 18px; + height: 18px; + font-size: 0.625rem; +} + +.emotion-30 .MuiChip-icon { + margin-left: 4px; + margin-right: -4px; + font-size: 18px; + color: inherit; +} + +.emotion-30 .MuiChip-deleteIcon { + -webkit-tap-highlight-color: transparent; + color: rgba(255, 255, 255, 0.7); + font-size: 16px; + cursor: pointer; + margin: 0 5px 0 -6px; + margin-right: 4px; + margin-left: -4px; +} + +.emotion-30 .MuiChip-deleteIcon:hover { + color: rgba(0, 0, 0, 0.4); +} + +.emotion-30 .MuiChip-deleteIcon:hover, +.emotion-30 .MuiChip-deleteIcon:active { + color: #fff; +} + +.emotion-31 { + overflow: hidden; + text-overflow: ellipsis; + padding-left: 8px; + padding-right: 8px; + white-space: nowrap; +} + +.emotion-49 { + max-width: 100%; + font-family: fontFamily; + font-size: 0.8125rem; + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + height: 24px; + color: #fff; + background-color: #FA2742; + border-radius: 16px; + white-space: nowrap; + -webkit-transition: background-color 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + transition: background-color 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + cursor: unset; + outline: 0; + -webkit-text-decoration: none; + text-decoration: none; + border: 0; + padding: 0; + vertical-align: middle; + box-sizing: border-box; + background-color: transparent; + border: 1px solid rgba(250, 39, 66, 0.7); + color: #FA2742; +} + +.emotion-49.Mui-disabled { + opacity: 0.38; + pointer-events: none; +} + +.emotion-49 .MuiChip-avatar { + margin-left: 5px; + margin-right: -6px; + width: 24px; + height: 24px; + color: #616161; + font-size: 0.75rem; +} + +.emotion-49 .MuiChip-avatarColorPrimary { + color: #fff; + background-color: rgb(175, 27, 46); +} + +.emotion-49 .MuiChip-avatarColorSecondary { + color: #fff; + background-color: rgb(38, 39, 35); +} + +.emotion-49 .MuiChip-avatarSmall { + margin-left: 4px; + margin-right: -4px; + width: 18px; + height: 18px; + font-size: 0.625rem; +} + +.emotion-49 .MuiChip-icon { + margin-left: 4px; + margin-right: -4px; + font-size: 18px; + color: inherit; +} + +.emotion-49 .MuiChip-deleteIcon { + -webkit-tap-highlight-color: transparent; + color: rgba(255, 255, 255, 0.7); + font-size: 16px; + cursor: pointer; + margin: 0 5px 0 -6px; + margin-right: 4px; + margin-left: -4px; +} + +.emotion-49 .MuiChip-deleteIcon:hover { + color: rgba(0, 0, 0, 0.4); +} + +.emotion-49 .MuiChip-deleteIcon:hover, +.emotion-49 .MuiChip-deleteIcon:active { + color: #fff; +} + +.emotion-49.MuiChip-clickable:hover { + background-color: rgba(250, 39, 66, 0.04); +} + +.emotion-49.Mui-focusVisible { + background-color: rgba(250, 39, 66, 0.12); +} + +.emotion-49 .MuiChip-avatar { + margin-left: 4px; +} + +.emotion-49 .MuiChip-avatarSmall { + margin-left: 2px; +} + +.emotion-49 .MuiChip-icon { + margin-left: 4px; +} + +.emotion-49 .MuiChip-iconSmall { + margin-left: 2px; +} + +.emotion-49 .MuiChip-deleteIcon { + color: rgba(250, 39, 66, 0.7); +} + +.emotion-49 .MuiChip-deleteIcon:hover, +.emotion-49 .MuiChip-deleteIcon:active { + color: #FA2742; +} + +.emotion-49 .MuiChip-deleteIconSmall { + margin-right: 3px; +} + +.emotion-50 { + overflow: hidden; + text-overflow: ellipsis; + padding-left: 7px; + padding-right: 7px; + white-space: nowrap; +} + +
+
+

+ Work +

+

+ After graduating with a degree in Computer Engineering from the University of Florida in 2003, I worked in the defense industry for 7 years. Subsequently, I transitioned to working for niche food delivery service companies, where I honed my skills as a Full-Stack Developer. Throughout my career progression, I have assumed roles such as Technical Lead, providing mentorship to colleagues, and collaborating within agile, cross-functional teams. +

+
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+
, + .emotion-0 { + background-color: #373833; + color: #E8EAE3; + height: 175px; + padding: 16px; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.emotion-1 { + max-width: 600px; + display: grid; + gap: 4px; + text-align: center; + height: 100%; + width: 100%; +} + +@media (min-width:0px) { + .emotion-1 { + grid-template-areas: "nav" "madeby" "copyright" "source"; + } +} + +@media (min-width:600px) { + .emotion-1 { + grid-template-areas: "nav madeby" "nav copyright" "nav source"; + } +} + +.emotion-2 { + grid-area: nav; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 100%; + height: 100%; +} + +@media (min-width:0px) { + .emotion-2 { + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + } +} + +@media (min-width:600px) { + .emotion-2 { + -webkit-box-pack: start; + -ms-flex-pack: start; + -webkit-justify-content: flex-start; + justify-content: flex-start; + } +} + +.emotion-3 { + width: 25%; + height: 100%; +} + +.emotion-4 { + list-style: none; + margin: 0; + padding: 0; + position: relative; + padding-top: 8px; + padding-bottom: 8px; + list-style: none; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 100%; + height: 100%; + padding: 0px; +} + +@media (min-width:0px) { + .emotion-4 { + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + } +} + +@media (min-width:600px) { + .emotion-4 { + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + } +} + +.emotion-5 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -ms-flex-pack: start; + -webkit-justify-content: flex-start; + justify-content: flex-start; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + position: relative; + -webkit-text-decoration: none; + text-decoration: none; + width: 100%; + box-sizing: border-box; + text-align: left; + padding-top: 8px; + padding-bottom: 8px; + padding-left: 16px; + padding-right: 16px; + padding: 0px; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-transition: -webkit-transform 0.25s ease; + transition: transform 0.25s ease; +} + +.emotion-5.Mui-focusVisible { + background-color: rgba(0, 0, 0, 0.12); +} + +.emotion-5.Mui-selected { + background-color: rgba(250, 39, 66, 0.08); +} + +.emotion-5.Mui-selected.Mui-focusVisible { + background-color: rgba(250, 39, 66, 0.2); +} + +.emotion-5.Mui-disabled { + opacity: 0.38; +} + +@media (min-width:0px) { + .emotion-5 { + margin: 8px; + } +} + +@media (min-width:600px) { + .emotion-5 { + margin: 24px; + } +} + +.emotion-5:hover { + -webkit-transform: scale(1.2); + -moz-transform: scale(1.2); + -ms-transform: scale(1.2); + transform: scale(1.2); +} + +.emotion-6 { + margin: 0; + font: inherit; + color: #FA2742; + -webkit-text-decoration: none; + text-decoration: none; + -webkit-text-decoration: none; + text-decoration: none; + height: 100%; + width: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.emotion-6:hover { + -webkit-text-decoration: underline; + text-decoration: underline; +} + +.emotion-9 { + grid-area: madeby; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} + +@media (min-width:0px) { + .emotion-9 { + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + } +} + +@media (min-width:600px) { + .emotion-9 { + -webkit-box-pack: end; + -ms-flex-pack: end; + -webkit-justify-content: flex-end; + justify-content: flex-end; + -webkit-align-items: flex-end; + -webkit-box-align: flex-end; + -ms-flex-align: flex-end; + align-items: flex-end; + } +} + +.emotion-10 { + margin: 0; + font-family: fontFamily; + font-size: 26px; +} + +@media (min-width:0px) { + .emotion-10 { + font-size: 24px; + } +} + +@media (min-width:600px) { + .emotion-10 { + font-size: 34px; + } +} + +.emotion-11 { + margin: 0; + font-family: fontFamily; + font-weight: 400; + font-size: 1rem; + line-height: 1.5; + display: inline; + color: #FA2742; +} + +.emotion-12 { + grid-area: copyright; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} + +@media (min-width:0px) { + .emotion-12 { + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + } +} + +@media (min-width:600px) { + .emotion-12 { + -webkit-box-pack: end; + -ms-flex-pack: end; + -webkit-justify-content: flex-end; + justify-content: flex-end; + -webkit-align-items: flex-end; + -webkit-box-align: flex-end; + -ms-flex-align: flex-end; + align-items: flex-end; + } +} + +.emotion-13 { + margin: 0; + font-family: fontFamily; + font-weight: 400; + font-size: 0.75rem; + line-height: 2.66; + text-transform: uppercase; + text-transform: none; +} + +.emotion-14 { + grid-area: source; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} + +@media (min-width:0px) { + .emotion-14 { + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + } +} + +@media (min-width:600px) { + .emotion-14 { + -webkit-box-pack: end; + -ms-flex-pack: end; + -webkit-justify-content: flex-end; + justify-content: flex-end; + -webkit-align-items: flex-end; + -webkit-box-align: flex-end; + -ms-flex-align: flex-end; + align-items: flex-end; + } +} + +.emotion-15 { + margin: 0; + font-family: fontFamily; + font-weight: 400; + font-size: 0.75rem; + line-height: 2.66; + text-transform: uppercase; +} + +.emotion-16 { + margin: 0; + font: inherit; + color: #FA2742; + -webkit-text-decoration: none; + text-decoration: none; + color: #E8EAE3; +} + +.emotion-16:hover { + -webkit-text-decoration: underline; + text-decoration: underline; +} + +
+
+
+ +
+
+

+ Made with + + + ♥ + + + by Nichole Frey +

+
+
+

+ Copyright © + 2024 + - + + + All Rights Reserved + +

+
+ +
+
, +] +`; diff --git a/src/app/work/constants.ts b/src/app/work/constants.ts new file mode 100644 index 0000000..bc4b9cf --- /dev/null +++ b/src/app/work/constants.ts @@ -0,0 +1,108 @@ +export interface WorkItemType { + id: string; + company: string; + title: string; + location: string; + startDate: string; + endDate: string; + experience: string[]; + skills: string[]; + tools: string[]; +} + +export const items: WorkItemType[] = [ + { + id: 'portfolio-site', + company: 'Portfolio Site', + title: 'Owner, Developer', + location: 'Orlando, FL', + startDate: 'Nov 2017', + endDate: 'Present', + experience: [ + 'Current site is a React application, built on NextJS, and deployed to Vercel. Code is fully-tested and automated via Github Actions.', + 'Original site was built with React and Bulma, bundled with Webpack, and deployed to AWS via CircleCI.', + ], + skills: ['MaterialUI', 'Typescript', 'React', 'NextJS', 'Emotion', 'Jest'], + tools: ['Vercel', 'Cloudinary', 'Codecov', 'Github Actions'], + }, + { + id: 'imperfect-foods', + company: 'Imperfect Foods', + title: 'Full-Stack Developer', + location: 'Remote', + startDate: 'Jan 2018', + endDate: 'Dec 2022', + experience: [ + 'Founding member of a highly collaborative, cross-functional team where we facilitated a unique shopping experience, intended to solve food waste.', + "Contributed to the transition of our user base from the legacy site to the new platform after adapting the Door to Door Organics code to Imperfect's business model.", + 'Highly involved in architecture decisions and many technology improvements.', + 'Regularly involved in early exploration of new features with our design and project management team members.', + 'Responsible for the engineering side of our Stripe and Auth0 integrations, as well as collecting our site analytics using Segment and collaborating with merchandising and marketing efforts that relied on this data.', + 'Mentored junior and mid-level developers as we expanded our team.', + ], + skills: [ + 'Node', + 'TypeScript', + 'React', + 'React Router', + 'Redux', + 'Sagas', + 'Webpack', + 'Jest', + 'Express', + 'SQL', + 'Microservices', + 'Technical Writing', + ], + tools: [ + 'Auth0', + 'Stripe', + 'Algolia', + 'Segment', + 'Prismic', + 'CircleCI', + 'Cloudinary', + 'Storybook', + 'DataDog', + 'JIRA', + 'Codecov', + 'PostGRES', + 'AWS', + 'Docker', + ], + }, + { + id: 'dtdo', + company: 'Door to Door Organics', + title: 'Lead Front-End Developer', + location: 'Louisville, CO & Remote', + startDate: 'Mar 2014', + endDate: 'Nov 2017', + experience: [ + 'Led the architecture and deployment of the website.', + 'Contributed to the transition of our user base from our legacy monolithic site to the new micro-services based platform.', + 'Contributed to the development and deployment of our React Native iOS App.', + 'Promoted to Lead on the Front-End team prior to the merger with Relay Foods where I enabled the adoption of React components from within a legacy Java website.', + ], + skills: [ + 'Node', + 'JavaScript', + 'React', + 'React Native', + 'Redux', + 'Sagas', + 'Express', + 'SQL', + 'Microservices', + ], + tools: [ + 'AWS', + 'Auth0', + 'Stripe', + 'Algolia', + 'CircleCI', + 'Cloudinary', + 'PostGRES', + ], + }, +]; diff --git a/src/app/work/page.test.tsx b/src/app/work/page.test.tsx new file mode 100644 index 0000000..7be463f --- /dev/null +++ b/src/app/work/page.test.tsx @@ -0,0 +1,81 @@ +/* + * @jest-environment jsdom + */ +import { + render, + renderWithLayout, + screen, + renderSnapshotWithLayout, +} from 'test-utils'; +// import userEvent from '@testing-library/user-event'; + +import WorkPage from './page'; + +// Test TODO +// Work header nav element is underlined +// h1 is correct +// each panel can be clicked and the expected elments are on the page +// keyboard events work + +describe('The Work Page', () => { + test('has expected snapshot', () => { + const component = renderSnapshotWithLayout(); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); + + test.each([['header'], ['work-page'], ['footer']])( + 'contains the visible testid %i', + (testid) => { + renderWithLayout(); + const component = screen.getByTestId(testid); + expect(component).toBeVisible(); + } + ); + + test('works as expected', () => { + // const user = userEvent.setup(); + + render(); + + const heading = screen.getByRole('heading', { level: 1 }); + expect(heading).toBeVisible(); + expect(heading).toHaveTextContent('Work'); + + const portfolioHeading2 = screen.getByRole('heading', { level: 2 }); + expect(portfolioHeading2).toBeVisible(); + expect(portfolioHeading2).toHaveTextContent( + 'Portfolio Site | Owner, Developer' + ); + + const imperfectTab = screen.getByRole('tab', { name: 'Imperfect Foods' }); + expect(imperfectTab).toBeVisible(); + + // TODO https://github.com/nicholeuf/zen-site-next/issues/30 + // await user.click(imperfectTab); + + // const imperfectHeading2 = screen.getByRole('heading', { level: 2 }); + // expect(imperfectHeading2).toBeVisible(); + // expect(imperfectHeading2).toHaveTextContent( + // 'Portfolio Site | Owner, Developer' + // ); + + // const footer = screen.getByTestId('footer') as HTMLDivElement; + // expect(footer).toBeVisible(); + // expect(footer).toHaveStyleRule('color', '#E8EAE3'); + // expect(footer).toHaveStyleRule('background-color', '#373833'); + + // const nav = screen.getByTestId('footer-nav') as HTMLDivElement; + // expect(nav).toBeVisible(); + + // const madeWithLoveCopy = screen.getByText(/Made with/i); + // expect(madeWithLoveCopy).toBeVisible(); + + // const copyRightCopy = screen.getByText(/Copyright/i); + // expect(copyRightCopy).toBeVisible(); + + // const sourceCopy = screen.getByText(/View Source Code/i); + // expect(sourceCopy).toBeVisible(); + }); +}); diff --git a/src/app/work/page.tsx b/src/app/work/page.tsx index 491decf..3d1ce59 100644 --- a/src/app/work/page.tsx +++ b/src/app/work/page.tsx @@ -1,22 +1,29 @@ import Typography from '@mui/material/Typography'; -import Box from '@mui/material/Box'; import { Metadata } from 'next'; +import WorkTabs from './WorkTabs'; +import { items } from './constants'; +import PageContainer from '@/components/PageContainer'; + export const metadata: Metadata = { title: 'Work', }; const Work: React.FC = () => { return ( - + Work - - Lorem ipsum dolor, sit amet consectetur adipisicing elit. Ipsum tempore - a praesentium perferendis doloremque, veniam minus quis laborum, numquam - blanditiis sunt ex consectetur asperiores assumenda nisi laboriosam et - tempora quos. + + After graduating with a degree in Computer Engineering from the + University of Florida in 2003, I worked in the defense industry for 7 + years. Subsequently, I transitioned to working for niche food delivery + service companies, where I honed my skills as a Full-Stack Developer. + Throughout my career progression, I have assumed roles such as Technical + Lead, providing mentorship to colleagues, and collaborating within + agile, cross-functional teams. - + + ); }; diff --git a/src/components/PageContainer.tsx b/src/components/PageContainer.tsx new file mode 100644 index 0000000..f068e6e --- /dev/null +++ b/src/components/PageContainer.tsx @@ -0,0 +1,25 @@ +import Container, { ContainerProps } from '@mui/material/Container'; + +interface PageContainerProps extends ContainerProps { + children: React.ReactNode; +} + +const PageContainer: React.FC = ({ + children, + maxWidth = 'lg', + ...props +}) => { + return ( + + {children} + + ); +}; + +export default PageContainer;