Skip to content

Commit 4e92dcd

Browse files
committed
update text, rearrange projects
1 parent 7f50aae commit 4e92dcd

27 files changed

Lines changed: 287 additions & 453 deletions

.prettierrc

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
"semi": false,
33
"singleQuote": false,
44
"trailingComma": "es5",
5-
"plugins": [
6-
"prettier-plugin-tailwindcss"
7-
],
5+
"plugins": ["prettier-plugin-tailwindcss"],
86
"tabWidth": 2,
97
"printWidth": 160
10-
}
8+
}

.zero-ui/attributes.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* AUTO-GENERATED - DO NOT EDIT */
22
export declare const bodyAttributes: {
3+
"data-faq": "closed" | "open";
34
"data-mobile-menu": string;
45
"data-phase": "1" | "2" | "3" | "4" | "5";
56
"data-reveal": "false" | "true";

.zero-ui/attributes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export const bodyAttributes = {
55
"data-scrolled": "up"
66
};
77
export const variantKeyMap = {
8+
"data-faq": true,
89
"data-mobile-menu": true,
910
"data-phase": true,
1011
"data-reveal": true,

app/(site)/page.tsx

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,23 @@ import { Metadata } from "next"
77
import { SITE_SLUGS } from "@/config/siteConfig"
88

99
export const metadata: Metadata = {
10-
title: "Austin Serb - Developer Portfolio",
10+
title: "Web Developer Portfolio | Austin Serb | React & Next.js",
1111
description:
12-
"Portfolio of Austin Serb, Seattle-based full-stack engineer. Creator of React Zero-UI. Ships production Next.js + TypeScript systems. Projects & contact.",
13-
keywords: ["Austin Serb", "Serbyte", "React Zero-UI", "Next.js", "React", "TypeScript", "Full-Stack Engineer", "Seattle"],
12+
"Explore the web developer portfolio of Austin Serb, a full-stack engineer building fast, modern web applications. See what a professional coding portfolio looks like, featuring projects in React, Next.js, and the custom-built React-Zero-UI library.",
13+
14+
keywords: [
15+
"Web Developer Portfolio",
16+
"Austin Serb",
17+
"Serbyte",
18+
"React Zero-UI",
19+
"Next.js",
20+
"React",
21+
"TypeScript",
22+
"Full-Stack Engineer",
23+
"Seattle",
24+
25+
"React Developer Portfolio",
26+
],
1427
authors: [{ name: "Austin Serb" }],
1528
creator: "Austin Serb",
1629
alternates: {
@@ -21,12 +34,13 @@ export const metadata: Metadata = {
2134
const PortfolioPage: React.FC = () => {
2235
return (
2336
<main className="overflow-hidden">
24-
<HeroV2 /> {/* Rewritten for job seeking */}
37+
<HeroV2 />
2538
<div className="border-b border-gray-200" />
26-
<ProjectsSection /> {/* Expanded with case studies */}
27-
<AboutSectionV2 /> {/* Technical journey focus */}
28-
<ServicesSectionV2 /> {/* NEW: Technical skills showcase */}
39+
<ProjectsSection />
40+
<AboutSectionV2 />
41+
<ServicesSectionV2 />
2942
<RecruiterContact />
43+
{/* <FAQSection /> */}
3044
</main>
3145
)
3246
}

app/components/AboutSectionV2.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export const AboutSectionV2 = ({ className = "" }: { className?: string }) => {
5858
</p>
5959

6060
{/* signature */}
61-
<Image src={signature} alt="Austin Serb Signature" width={90} height={45} className="mt-6 -ml-3 -rotate-6 relative" />
61+
<Image src={signature} alt="Austin Serb Signature" width={90} height={45} className="relative mt-6 -ml-3 -rotate-6" />
6262
</Typography>
6363
</div>
6464
</div>

app/components/FAQ/FAQSection.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { FAQTable } from "./FAQTable"
2+
import { AnimatedH2 } from "../ui/AnimatedH2"
3+
import { faqData } from "./faq-data"
4+
5+
export const FAQSection: React.FC = () => {
6+
return (
7+
<section className="inside-container flex-col border-t border-gray-200 md:gap-8 lg:flex-row">
8+
<div className="flex flex-col gap-12 md:[flex:1.5_0_0px] md:gap-16">
9+
<AnimatedH2>
10+
Your questions <br /> <span className="text-slate-500">answered.</span>
11+
</AnimatedH2>
12+
<FAQTable faqData={faqData} />
13+
</div>
14+
15+
{/* <NotSureCard className="md:[flex:1_0_0px]" /> */}
16+
</section>
17+
)
18+
}

app/components/FAQ/FAQTable.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import clsx from "clsx"
2+
import { SingleFAQ } from "./SingleFAQ"
3+
export interface FAQ {
4+
index: number
5+
question: string
6+
answer: React.ReactNode
7+
}
8+
export const FAQTable: React.FC<{ className?: string; faqData: FAQ[] }> = ({ className, faqData }) => {
9+
return (
10+
<div className={clsx("flex flex-col gap-4", className)}>
11+
{faqData.map((faq, index) => (
12+
<SingleFAQ key={faq.question + index} {...faq} index={index} />
13+
))}
14+
</div>
15+
)
16+
}

app/components/FAQ/NotSureCard.tsx

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// import Image from "next/image"
2+
// import profilePhoto from "../../images/profile.webp"
3+
// import { Icon } from "../Icon"
4+
// import { CalIcon } from "../../icons/Cal.icon"
5+
// import { H3 } from "@/app/ui/Elements"
6+
// import clsx from "clsx"
7+
// import { AnimatedAvatars } from "../ui/AnimatedAvatars"
8+
// import { AnimatedElement } from "../ui/AnimatedElement"
9+
// import { BlackButton } from "../ui/BlackButton"
10+
// import { MotionDiv } from "@/app/utils/lazy-ui"
11+
12+
// export const NotSureCard: React.FC<{ className?: string; projectsPage?: boolean }> = ({ className, projectsPage = false }) => {
13+
// return (
14+
// <MotionDiv
15+
// initial={{ opacity: 0, x: -40 }}
16+
// whileInView={{ opacity: 1, x: 0 }}
17+
// transition={{ type: "spring", stiffness: 100, damping: 10 }}
18+
// viewport={{ once: true, amount: 0.8 }}
19+
// className={clsx(
20+
// "relative flex flex-col gap-8 rounded-2xl border border-gray-300 bg-white p-8 max-lg:text-center",
21+
// className,
22+
// projectsPage ? "h-full w-full items-center justify-center" : "lg:h-fit lg:w-fit"
23+
// )}
24+
// >
25+
// <div className="flex flex-col gap-6 max-lg:items-center">
26+
// {projectsPage ? (
27+
// <div className="flex items-center gap-4 whitespace-nowrap">
28+
// <AnimatedAvatars />
29+
// <AnimatedElement element="div" fadeDirection="right" offsetPx={20} duration={0.4} delay={0.15} className="flex flex-col">
30+
// <div className="flex items-center gap-0.5 text-base text-gray-600">
31+
// {Array.from({ length: 5 }).map((_, i) => (
32+
// <span key={i}>★</span>
33+
// ))}
34+
// </div>
35+
// <span className="text-sm font-medium text-slate-900">Rated 5.0</span>
36+
// </AnimatedElement>
37+
// </div>
38+
// ) : (
39+
// <Image src={profilePhoto} height={64} width={64} alt="Austin Serb" className="aspect-square rounded-full object-cover" sizes="200px" />
40+
// )}
41+
// <H3 className={clsx("font-normal text-nowrap", projectsPage && "text-center")}>
42+
// <span className="text-slate-500">{projectsPage ? "Like what you see?" : "Still not sure?"}</span> <br />
43+
// Book a free discovery call.
44+
// </H3>
45+
// {!projectsPage && <p className="max-w-xs text-sm">Learn more about how I work and how I can help you and your business take the next step.</p>}
46+
// </div>
47+
// <div className="flex items-center gap-4 max-lg:flex-col">
48+
// <BlackButton>
49+
// <Icon name="calendar" height={20} width={20} className="h-5 w-5 text-white" />
50+
// Schedule Now
51+
// </BlackButton>
52+
53+
// <CalIcon className="h-auto w-20 text-gray-500" />
54+
// </div>
55+
// </MotionDiv>
56+
// )
57+
// }

app/components/FAQ/SingleFAQ.tsx

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"use client"
2+
3+
import { type FAQ } from "./FAQTable"
4+
import { useScopedUI } from "@react-zero-ui/core"
5+
6+
export const SingleFAQ = ({ question, answer, index }: FAQ) => {
7+
const [isOpen, setIsOpen] = useScopedUI<"open" | "closed">("faq", "closed")
8+
9+
return (
10+
<div
11+
data-faq={isOpen}
12+
ref={setIsOpen.ref}
13+
className="relative flex flex-col overflow-hidden rounded-xl border border-gray-300 bg-white text-sm hover:cursor-pointer"
14+
onClick={() => setIsOpen((prev) => (prev === "open" ? "closed" : "open"))}
15+
>
16+
{/* header */}
17+
<div className="flex items-center justify-between gap-4 px-4 py-3">
18+
<div
19+
// animate={{ x: isOpen ? -30 : 0 }}
20+
// transition={{ duration: 0.2, ease: "easeOut" }}
21+
className="faq-open:-translate-x-7.5 flex items-center gap-4 overflow-hidden duration-200 ease-out will-change-transform"
22+
>
23+
<span className="faq-open:opacity-0 text-slate-500 duration-200 ease-out">0{index + 1}</span>
24+
<h3 className="font-medium">{question}</h3>
25+
</div>
26+
27+
{/* toggle */}
28+
<button
29+
aria-label={"Toggle Faq Answer"}
30+
type="button"
31+
className="relative flex h-5 w-5 items-center justify-center text-sm hover:cursor-pointer"
32+
title="Toggle Faq Answer"
33+
>
34+
<div className="absolute h-0.5 w-2.5 rounded-full bg-black" />
35+
<div
36+
// animate={{ rotate: isOpen ? 0 : 270 }}
37+
// transition={{ duration: 0.2, ease: "easeOut" }}
38+
className="faq-closed:rotate-[270deg] absolute h-0.5 w-2.5 rounded-full bg-black duration-200 ease-out will-change-transform"
39+
/>
40+
</button>
41+
</div>
42+
43+
{/* answer */}
44+
<div
45+
className="faq-open:grid-rows-[1fr] faq-open:pt-4 faq-open:pb-4 faq-closed:grid-rows-[0fr] faq-closed:opacity-0 grid overflow-hidden border-t border-gray-300 px-4 [transition:padding_300ms_ease-out,opacity_200ms_ease-out,grid-template-rows_200ms_ease-out]"
46+
// initial={false}
47+
// animate={{ gridTemplateRows: isOpen ? "1fr" : "0fr", opacity: isOpen ? 1 : 0, paddingTop: isOpen ? 16 : 0, paddingBottom: isOpen ? 16 : 0 }}
48+
// transition={{ duration: 0.2, ease: "easeOut", paddingTop: { duration: 0.3 }, paddingBottom: { duration: 0.3 } }}
49+
>
50+
<div className="min-h-0">{answer}</div>
51+
</div>
52+
</div>
53+
)
54+
}

app/components/FAQ/faq-data.tsx

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { type FAQ } from "./FAQTable"
2+
3+
export const faqData: FAQ[] = [
4+
{
5+
index: 0,
6+
question: "What is the purpose of a developer portfolio?",
7+
answer: (
8+
<>
9+
A great developer portfolio is more than a resume; it&apos;s a live demonstration of your skills and philosophies. This site, for example, isn&apos;t
10+
just a list of projects; it&apos;s built on my own performance-oriented library (React-Zero-UI). to showcase your commitment to simple, fast, and
11+
elegant code. a recent study found that portfolios DO have a future.{" "}
12+
<a href="https://pmc.ncbi.nlm.nih.gov/articles/PMC5306426/" className="text-slate-500">
13+
Do portfolios have a future?
14+
</a>
15+
</>
16+
),
17+
},
18+
{
19+
index: 1,
20+
question: "What's actually included in your web design packages?",
21+
answer: (
22+
<>
23+
Everything you need for a successful launch and nothing you don&apos;t. Every package includes a strategic game plan, conversion-focused copywriting, a
24+
custom mobile-first design, SEO foundation setup, and our 90-day post-launch support guarantee. We believe in total transparency—no hidden fees, ever.
25+
</>
26+
),
27+
},
28+
{
29+
index: 2,
30+
question: "What are the 'golden rules' of a great business website?",
31+
answer: (
32+
<>
33+
A great website isn&apos;t just about looks; it&apos;s about results. Our five golden rules are:
34+
<ul className="list-disc pl-4">
35+
<li>Speed: If it doesn&apos;t load in under 2 seconds, you&apos;re losing customers.</li>
36+
<li>Clarity: It must pass the &quot;5-second test&quot;: visitors must know what you do instantly.</li>
37+
<li>Action: Every page needs a clear call-to-action guiding the user.</li>
38+
<li>Mobile-First: It must be flawless on a phone, where most users will see it.</li>
39+
<li>SEO-Ready: It must be built to be found on Google from day one.</li>
40+
</ul>
41+
</>
42+
),
43+
},
44+
{
45+
index: 3,
46+
question: "How do I find the right web designer for my business?",
47+
answer: (
48+
<>
49+
Look for three things:
50+
<ul className="list-disc pl-4">
51+
<li>A Portfolio with Results: Don&apos;t just look for pretty sites; ask for proof that their work actually helped grow a business.</li>
52+
<li>A Transparent Process: They should be able to clearly explain their steps from start to finish.</li>
53+
<li>
54+
A Focus on ROI: The right partner talks less about colors and fonts and more about how they&apos;ll turn your website into a predictable source of
55+
revenue.
56+
</li>
57+
</ul>
58+
</>
59+
),
60+
},
61+
{
62+
index: 4,
63+
question: "What is the 3 second rule in web design?",
64+
answer: (
65+
<>
66+
First impressions matter. Your have 3 seconds to make a good impression. and capture attention. After a first impression is formed on a website, it is
67+
difficult to change. <strong className="text-slate-500">We focus on making a good first impression.</strong>
68+
<a href={"https://academicworks.cuny.edu/cgi/viewcontent.cgi?referer=&httpsredir=1&article=1157&context=ny_pubs"} className="text-xs text-slate-500">
69+
An Analysis of First Impression{" "}
70+
</a>
71+
</>
72+
),
73+
},
74+
]

0 commit comments

Comments
 (0)