diff --git a/bun.lockb b/bun.lockb index 41960ad..09d4db9 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/public/assets/images/avatars/eric.webp b/public/assets/images/avatars/eric.webp new file mode 100644 index 0000000..59b3809 Binary files /dev/null and b/public/assets/images/avatars/eric.webp differ diff --git a/public/assets/images/avatars/matt.webp b/public/assets/images/avatars/matt.webp new file mode 100644 index 0000000..365c729 Binary files /dev/null and b/public/assets/images/avatars/matt.webp differ diff --git a/public/assets/images/avatars/nana.webp b/public/assets/images/avatars/nana.webp new file mode 100644 index 0000000..2eac550 Binary files /dev/null and b/public/assets/images/avatars/nana.webp differ diff --git a/public/assets/images/avatars/praneeth.webp b/public/assets/images/avatars/praneeth.webp new file mode 100644 index 0000000..86cad8c Binary files /dev/null and b/public/assets/images/avatars/praneeth.webp differ diff --git a/public/assets/images/avatars/roy.webp b/public/assets/images/avatars/roy.webp new file mode 100644 index 0000000..05547e6 Binary files /dev/null and b/public/assets/images/avatars/roy.webp differ diff --git a/public/assets/images/avatars/todd.webp b/public/assets/images/avatars/todd.webp new file mode 100644 index 0000000..b98a91d Binary files /dev/null and b/public/assets/images/avatars/todd.webp differ diff --git a/public/assets/images/avatars/travis.webp b/public/assets/images/avatars/travis.webp new file mode 100644 index 0000000..161b8fd Binary files /dev/null and b/public/assets/images/avatars/travis.webp differ diff --git a/public/assets/images/logos/adoptive.webp b/public/assets/images/logos/adoptive.webp new file mode 100644 index 0000000..f14b599 Binary files /dev/null and b/public/assets/images/logos/adoptive.webp differ diff --git a/public/assets/images/logos/blue-chair-bay.webp b/public/assets/images/logos/blue-chair-bay.webp new file mode 100644 index 0000000..47284ef Binary files /dev/null and b/public/assets/images/logos/blue-chair-bay.webp differ diff --git a/public/assets/images/logos/ncpc.webp b/public/assets/images/logos/ncpc.webp new file mode 100644 index 0000000..42a3ffe Binary files /dev/null and b/public/assets/images/logos/ncpc.webp differ diff --git a/public/assets/images/logos/wwglass.webp b/public/assets/images/logos/wwglass.webp new file mode 100644 index 0000000..aeffbfd Binary files /dev/null and b/public/assets/images/logos/wwglass.webp differ diff --git a/src/api/experience.md b/src/api/experience.md index acec7ca..728c8f9 100644 --- a/src/api/experience.md +++ b/src/api/experience.md @@ -1,4 +1,6 @@ --- +title: Experience +subtitle: Showcasing over a decade of expertise and innovation across various roles and industries experience: - company: Unqork logo: ${basePath}/assets/images/logos/unqork.svg @@ -120,7 +122,8 @@ experience: Brand Development, ] - company: Adoptive - logo: ${basePath}/assets/images/logos/adoptive.jpg + logo: ${basePath}/assets/images/logos/adoptive.webp + remote: true roles: - title: UX, Lead Front-end Engineer location: Soho, New York City @@ -237,7 +240,7 @@ experience: Print Media, ] - company: National Crime Prevention Council - logo: ${basePath}/assets/images/logos/ncpc.png + logo: ${basePath}/assets/images/logos/ncpc.webp location: Washington, DC disabled: true roles: diff --git a/src/api/recommendations.md b/src/api/recommendations.md index 894844f..5e14208 100644 --- a/src/api/recommendations.md +++ b/src/api/recommendations.md @@ -1,52 +1,84 @@ --- +title: Recommendations +subtitle: Read what clients and colleagues have to say recommendations: - received: - - name: Eric Ma - connection: 1st - title: Engineering Manager + Caregivers ERSG Engagement Co-Chair at Unqork - date: 2024-06-03 - relationship: Eric was senior to Joseph but didn't manage Joseph directly - visibility: All LinkedIn members - recommendation: > - Joe epitomizes the qualities of what like to call a responsible engineer. It's one thing to be good at writing code (which Joe is) and it's another to go the extra mile. - - He just doesn't do the work that he's assigned to do. Joe makes sure to understand the why. This is how you get output from an engineering team that is high quality, that catches edge cases, and that truly solves the problems presenting your users, by having an engineer like Joe asking the right questions and leading by example. - - I count myself lucky I had the opportunity to rely on his work and envy whoever gets to work with him in his career. - - name: Travis Hubbard - connection: 1st - title: Staff Engineer | Technical Leadership & Mentorship - date: 2024-06-03 - relationship: Travis was senior to Joseph but didn't manage Joseph directly - visibility: All LinkedIn members - recommendation: > - I had the pleasure of working with Joe at Unqork, and he is a fantastic engineer with a remarkable eye for UI/UX and accessibility. Joe excels at asking insightful questions and raising important considerations, helping teams break down work and fully understand requirements. His deeply analytical mindset enables him to solve business challenges in a holistic and effective manner. - - Joe is not only a skilled problem-solver but also a great team player. He actively supports his teammates, always being one of the first to jump on calls to answer questions or provide a second pair of eyes. His commitment to driving code quality is evident through his thorough PR comments and willingness to pair with other developers. - - I thoroughly enjoyed my time working with Joe, and I believe he would be a brilliant addition to any team. - - name: Nana T. Baffour-Awuah - connection: 1st - title: Writer | Strategist | Consultant - date: 2016-07-23 - relationship: Nana T. worked with Joseph but on different teams - visibility: All LinkedIn members - recommendation: > - Over the two years that I've known Joe, since meeting at Adoptive, I've had the opportunity to work with and get to know one of the most hardworking, creative, resolute and generous people I've met in my career thus far. Joe's work ethic is impeccable, and he is a genuinely generous person who gives of himself to both his work and his team. Joe is an asset--any team would be very lucky to have him! - - name: Matt Staudt - connection: 1st - title: Bootstrap Entrepreneur + Marketing Pro | CEO @ GAME UP® Nutrition | President STAUDT agency | Created/Sold High Rollerz® Jiu Jitsu - date: 2014-03-06 - relationship: Matt worked with Joseph but they were at different companies - visibility: All LinkedIn members - recommendation: > - I wanted to take a moment to recommend Joe Burdick. I have worked with Joe not only in his current role as Founder of Joey Labs but also during both of our time at SGC. Having worked with Joe on multiple projects I am extremely confident in his abilities and work ethic which both exceed what I am accustomed to. Joe is my first call when I have a technical question and he has never ceased to amaze me with his insight and can-do attitude. He is extremely knowledgable and is a problem solver. Joe is a rare find, a pleasure to work with and as a result of his expertise and professionalism is an extremely valuable addition to any team. - - name: Todd Post - connection: 1st - title: Strategic Communications Executive | Senior Public Affairs Advisor | Communications Specialist | Vice President of Communications / In-House + Agency → Humanizing integrated strategic communications - date: 2007-01-24 - relationship: Todd managed Joseph directly - visibility: All LinkedIn members - recommendation: > - Joe's creativity and attention to detail coupled with his great attitude and sense of humor made him a valuable asset to the department, especially when it came to graphic design, web page management, and other technical skills. + - name: Praneeth Moka + company: unqork + avatar: ${basePath}/assets/images/avatars/praneeth.webp + title: Staff Engineer at Unqork | Full Stack Development + shortTitle: Staff Engineer + date: 2024-06-25 + relationship: Praneeth was senior to Joe but didn't manage Joe directly + body: > + I had the pleasure of working with Joe for over 2 years on various projects. Joe is one of the nicest and hardworking individuals I have ever met. Joe has a very good eye for catching things that can be simplified which often helped our team immensely. + + Joe has a lot of patience which is a very good asset to have and it was evident in the way he was able to successfully handle long running tasks while also maintaining excellent communication with the team on the progress of the task. He’s always available to help his teammates when they are in need. + + Any team would be lucky to have him and I strongly recommend Joe. + - name: Roy V. Sutton + company: unqork + avatar: ${basePath}/assets/images/avatars/roy.webp + title: Director of Engineering at Unqork + shortTitle: Director of Engineering + date: 2024-06-20 + relationship: Roy V. managed Joe directly + body: > + I had the pleasure to manage Joe during my time at Unqork. Joe is someone I consider to be a craftsman. His approach when working with code is to leave the code better than he found it. He has a passion for user interface and for making things right for the users and developers. + + One notable project Joe worked on was the company's internal design system. As part of his work, Joe assisted teams throughout the platform with getting the most from the system and helping them leverage the components to reduce code and styling. This work greatly improved readability, maintainability and consistency. In addition, Joe is a person I enjoyed working with. + - name: Travis Hubbard + company: unqork + avatar: ${basePath}/assets/images/avatars/travis.webp + title: Staff Engineer | Technical Leadership & Mentorship + shortTitle: Staff Engineer + date: 2024-06-03 + relationship: Travis was senior to Joe but didn't manage Joe directly + body: > + I had the pleasure of working with Joe at Unqork, and he is a fantastic engineer with a remarkable eye for UI/UX and accessibility. Joe excels at asking insightful questions and raising important considerations, helping teams break down work and fully understand requirements. His deeply analytical mindset enables him to solve business challenges in a holistic and effective manner. + + Joe is not only a skilled problem-solver but also a great team player. He actively supports his teammates, always being one of the first to jump on calls to answer questions or provide a second pair of eyes. His commitment to driving code quality is evident through his thorough PR comments and willingness to pair with other developers. + + I thoroughly enjoyed my time working with Joe, and I believe he would be a brilliant addition to any team. + - name: Eric Ma + company: unqork + avatar: ${basePath}/assets/images/avatars/eric.webp + title: Engineering Manager + Caregivers ERSG Engagement Co-Chair at Unqork + shortTitle: Engineering Manager + date: 2024-06-03 + relationship: Eric was senior to Joe but didn't manage Joe directly + body: > + Joe epitomizes the qualities of what like to call a responsible engineer. It's one thing to be good at writing code (which Joe is) and it's another to go the extra mile. + + He just doesn't do the work that he's assigned to do. Joe makes sure to understand the why. This is how you get output from an engineering team that is high quality, that catches edge cases, and that truly solves the problems presenting your users, by having an engineer like Joe asking the right questions and leading by example. + + I count myself lucky I had the opportunity to rely on his work and envy whoever gets to work with him in his career. + - name: Nana T. Baffour-Awuah + company: Adoptive + avatar: ${basePath}/assets/images/avatars/nana.webp + title: Writer | Strategist | Consultant + shortTitle: Writer + date: 2016-07-23 + relationship: Nana T. worked with Joe but on different teams + body: > + Over the two years that I've known Joe, since meeting at Adoptive, I've had the opportunity to work with and get to know one of the most hardworking, creative, resolute and generous people I've met in my career thus far. Joe's work ethic is impeccable, and he is a genuinely generous person who gives of himself to both his work and his team. + + Joe is an asset--any team would be very lucky to have him! + - name: Matt Staudt + company: studiographica + avatar: ${basePath}/assets/images/avatars/matt.webp + title: Bootstrap Entrepreneur + Marketing Pro | CEO @ GAME UP® Nutrition | President STAUDT agency | Created/Sold High Rollerz® Jiu Jitsu + shortTitle: CEO, Serial Entrepreneur + date: 2014-03-06 + relationship: Matt worked with Joe but they were at different companies + body: > + I wanted to take a moment to recommend Joe Burdick. I have worked with Joe not only in his current role as Founder of Joey Labs but also during both of our time at SGC. Having worked with Joe on multiple projects I am extremely confident in his abilities and work ethic which both exceed what I am accustomed to. Joe is my first call when I have a technical question and he has never ceased to amaze me with his insight and can-do attitude. He is extremely knowledgable and is a problem solver. Joe is a rare find, a pleasure to work with and as a result of his expertise and professionalism is an extremely valuable addition to any team. + - name: Todd Post + company: ncpc + avatar: ${basePath}/assets/images/avatars/todd.webp + title: Strategic Communications Executive | Senior Public Affairs Advisor + shortTitle: Communications Executive + date: 2007-01-24 + relationship: Todd managed Joe directly + body: > + Joe's creativity and attention to detail coupled with his great attitude and sense of humor made him a valuable asset to the department, especially when it came to graphic design, web page management, and other technical skills. --- diff --git a/src/app/_content/About.tsx b/src/app/_content/About.tsx index 2428dfb..f6c3161 100644 --- a/src/app/_content/About.tsx +++ b/src/app/_content/About.tsx @@ -21,6 +21,7 @@ export default function Footer() { ] return (
+
diff --git a/src/app/_content/Experience.tsx b/src/app/_content/Experience.tsx index 6288523..582a55f 100644 --- a/src/app/_content/Experience.tsx +++ b/src/app/_content/Experience.tsx @@ -83,7 +83,7 @@ export default function Experience() {
  • @@ -128,8 +128,15 @@ export default function Experience() { "md:py16 min-h-[800px] items-center justify-center space-y-8 bg-secondary py-8 lg:py-24 xl:py-36", )} > -
    -

    Experience

    +
    +
    + + {data.experience.attributes.title} + +
    + {data.experience.attributes.subtitle} +
    +
    {renderExperiences}
    diff --git a/src/app/_content/Intro.tsx b/src/app/_content/Intro.tsx index e29ccab..fc8c7be 100644 --- a/src/app/_content/Intro.tsx +++ b/src/app/_content/Intro.tsx @@ -32,7 +32,7 @@ function Intro() { }, []) return ( <> -
    +
    diff --git a/src/app/_content/Recommendations.tsx b/src/app/_content/Recommendations.tsx new file mode 100644 index 0000000..47cc95d --- /dev/null +++ b/src/app/_content/Recommendations.tsx @@ -0,0 +1,164 @@ +"use client" + +import Icon from "@/components/global/Icon" +import RuleHeader from "@/components/global/RuleHeader" +import { useApi } from "@/components/providers/DataProvider" +import { + Carousel, + CarouselApi, + CarouselContent, + CarouselItem, + CarouselNext, + CarouselPrevious, +} from "@/components/ui/carousel" +import convertNewLinesToHTML from "@/lib/convertNewLinesToHTML" +import { Recommendation as RecommendationType } from "@/lib/types" +import { cn } from "@/lib/utils" +import Image from "next/image" +import { useEffect, useState } from "react" + +export default function Recommendations() { + const [api, setApi] = useState() + const [current, setCurrent] = useState(0) + const { data } = useApi() + const recommendations: RecommendationType[] = + data.recommendations.attributes.recommendations + + useEffect(() => { + if (!api) return + + api.scrollTo(current) + }, [api, current]) + const carouselButtonClassName = + "relative top-0 left-0 right-0 translate-x-0 translate-y-0" + const renderRecommendation = ( + recommendation: RecommendationType, + index: number, + ) => ( + +
    +
    +
    +
    + {`${recommendation.name} +
    +
    + + {recommendation.name} + + + {recommendation.title} + +
    + {" "} + {recommendation.relationship} +
    +
    +
    + + +
    +
    +
    + {" "} + {recommendation.relationship} +
    +
    +
    + +
    +
    +
    + + ) + + const renderAvatarButtons = ( + recommendation: RecommendationType, + key: number, + ) => { + return ( + + ) + } + + const renderRecommendations = ( + + + {recommendations.map(renderRecommendation)} + +
    + {recommendations.map(renderAvatarButtons)} +
    +
    + ) + + return ( +
    +
    +
    + + {data.recommendations.attributes.title} + +
    + {data.recommendations.attributes.subtitle} +
    +
    + {renderRecommendations} +
    +
    + ) +} diff --git a/src/app/page.tsx b/src/app/page.tsx index cf38316..0da948a 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -4,6 +4,7 @@ import { DataProvider } from "@/components/providers/DataProvider" import About from "./_content/About" import Experience from "./_content/Experience" import Intro from "./_content/Intro" +import Recommendations from "./_content/Recommendations" export default async function Home() { const data = await api() @@ -13,6 +14,7 @@ export default async function Home() {
    +
    diff --git a/src/components/global/RuleHeader.tsx b/src/components/global/RuleHeader.tsx index 8f832fc..9a2146b 100644 --- a/src/components/global/RuleHeader.tsx +++ b/src/components/global/RuleHeader.tsx @@ -1,10 +1,23 @@ +import { cn } from "@/lib/utils" import type { PropsWithChildren } from "react" -export default function RuleHeader(props: PropsWithChildren) { +export default function RuleHeader( + props: PropsWithChildren & { + className?: string; + side?: "left" | "right" | "both"; + }, +) { + const { side = "right", className } = props + return ( -
    - {props.children} -
    +
    + {["left", "both"].includes(side) && ( +
    + )} + {props.children} + {["right", "both"].includes(side) && ( +
    + )}
    ) } diff --git a/src/components/global/Weather.tsx b/src/components/global/Weather.tsx index 03675cf..3a7c0f4 100644 --- a/src/components/global/Weather.tsx +++ b/src/components/global/Weather.tsx @@ -58,7 +58,7 @@ const WeatherComponent: React.FC = () => { return `${Math.round(temperature)}º F in` } else if (unit === "celsius" && temperature !== null) { const celsius = ((temperature - 32) * 5) / 9 - return `${celsius.toFixed(2)}º C in` + return `${celsius.toFixed(1)}º C in` } else { return "" } diff --git a/src/lib/convertNewLinesToHTML.ts b/src/lib/convertNewLinesToHTML.ts index 0150824..061b180 100644 --- a/src/lib/convertNewLinesToHTML.ts +++ b/src/lib/convertNewLinesToHTML.ts @@ -1,7 +1,9 @@ function convertNewLinesToHTML(inputString: string) { const paragraphs = inputString.split("\n") - const htmlParagraphs = paragraphs.map((paragraph) => `

    ${paragraph}

    `) + const htmlParagraphs = paragraphs + .filter(Boolean) + .map((paragraph) => `

    ${paragraph}

    `) const htmlString = htmlParagraphs.join("") diff --git a/src/lib/icons.tsx b/src/lib/icons.tsx index 5695d23..7750af6 100644 --- a/src/lib/icons.tsx +++ b/src/lib/icons.tsx @@ -1,4 +1,5 @@ import { + BadgeInfo, Ellipsis, ExternalLink, File, @@ -23,9 +24,9 @@ const InstagramSVG = () => ( viewBox="0 0 24 24" fill="none" stroke="currentColor" - stroke-width="2" - stroke-linecap="round" - stroke-linejoin="round" + strokeWidth="2" + strokeLinecap="round" + strokeLinejoin="round" > @@ -55,6 +56,7 @@ const LinkedInSVG = () => ( ) const icons: IconsMap = { + badgeInfo: BadgeInfo, ellipsis: Ellipsis, send: Send, mail: Mail, diff --git a/src/lib/types.ts b/src/lib/types.ts index 39715c3..077f86f 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -43,3 +43,13 @@ export type Experience = { hidden?: boolean; roles: Role[]; }; + +export type Recommendation = { + name: string; + avatar: string; + title: string; + shortTitle: string; + date: string; + relationship: string; + body: string; +}; diff --git a/tailwind.config.ts b/tailwind.config.ts index 7ddfad7..18bf896 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,5 +1,4 @@ import type { Config } from "tailwindcss" -import colors from "tailwindcss/colors" const config = { darkMode: "class", @@ -25,6 +24,9 @@ const config = { p: { fontSize: "clamp(0.875rem, 1vw + 0.5rem, 1.5rem)", }, + "p + p": { + marginTop: "1.5rem", + }, h1: { fontSize: "clamp(2rem, 3.5vw + 1.5rem, 3.5rem)", fontWeight: "normal",