Skip to content

Commit 82baa65

Browse files
authored
✨ Refactor Contact and Portfolio components for improved structure and readability; enhance constants for better styling management
1 parent 9df8700 commit 82baa65

6 files changed

Lines changed: 148 additions & 240 deletions

File tree

src/components/Contact.astro

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
import type { CollectionEntry } from "astro:content";
3+
import { CARD_CLASSES, TYPOGRAPHY_CLASSES, LINK_CLASSES, CONTAINER_CLASSES } from "@lib/constants";
34
45
interface Props {
56
homepage: CollectionEntry<"site">["data"];
@@ -9,37 +10,37 @@ const { homepage } = Astro.props as Props;
910
---
1011

1112
<section id="contact" data-reveal="up">
12-
<div class="section-content max-w-screen-lg mx-auto xl:max-w-screen-xl w-full">
13+
<div class={CONTAINER_CLASSES.sectionLg}>
1314
<p class="mx-auto mb-6 max-w-2xl text-center text-lg text-[var(--text-muted)]">
1415
Let's talk about how I can help with your next project. Whether it's building intelligent AI systems or scaling your growth.
1516
</p>
1617

1718
<div class="mb-6 grid gap-4 md:grid-cols-2">
18-
<div class="rounded-lg border border-[var(--border-strong)] bg-[color-mix(in_srgb,var(--surface-panel)_80%,transparent)] p-6 shadow-[0_10px_26px_rgba(0,0,0,0.2)] backdrop-blur-sm">
19-
<h3 class="mb-4 text-xl font-semibold text-[var(--text-strong)]">Quick Info</h3>
19+
<div class={`${CARD_CLASSES.glass} p-6`}>
20+
<h3 class={`mb-4 ${TYPOGRAPHY_CLASSES.cardTitle}`}>Quick Info</h3>
2021
<div class="space-y-4">
2122
<div>
22-
<p class="text-sm text-[var(--accent-strong)]">Location</p>
23-
<p class="text-base font-medium text-[var(--text-strong)]">{homepage.location}</p>
23+
<p class={TYPOGRAPHY_CLASSES.label}>Location</p>
24+
<p class={TYPOGRAPHY_CLASSES.cardBody}>{homepage.location}</p>
2425
</div>
2526
<div>
26-
<p class="text-sm text-[var(--accent-strong)]">Timezone</p>
27-
<p class="text-base font-medium text-[var(--text-strong)]">{homepage.timezone}</p>
27+
<p class={TYPOGRAPHY_CLASSES.label}>Timezone</p>
28+
<p class={TYPOGRAPHY_CLASSES.cardBody}>{homepage.timezone}</p>
2829
</div>
2930
<div>
30-
<p class="text-sm text-[var(--accent-strong)]">Response Time</p>
31-
<p class="text-base font-medium text-[var(--text-strong)]">{homepage.responseTime}</p>
31+
<p class={TYPOGRAPHY_CLASSES.label}>Response Time</p>
32+
<p class={TYPOGRAPHY_CLASSES.cardBody}>{homepage.responseTime}</p>
3233
</div>
3334
</div>
3435
</div>
3536

36-
<div class="rounded-lg border border-[var(--border-strong)] bg-[color-mix(in_srgb,var(--surface-panel)_80%,transparent)] p-6 shadow-[0_10px_26px_rgba(0,0,0,0.2)] backdrop-blur-sm">
37-
<h3 class="mb-4 text-xl font-semibold text-[var(--text-strong)]">Availability</h3>
38-
<p class="mb-6 text-base text-[var(--text-muted)]">{homepage.availability}</p>
37+
<div class={`${CARD_CLASSES.glass} p-6`}>
38+
<h3 class={`mb-4 ${TYPOGRAPHY_CLASSES.cardTitle}`}>Availability</h3>
39+
<p class={`mb-6 ${TYPOGRAPHY_CLASSES.body}`}>{homepage.availability}</p>
3940
<a
4041
href={homepage.bookingUrl}
4142
data-track="cta_booking_link"
42-
class="inline-block rounded-lg bg-[var(--accent-strong)] px-6 py-3 font-semibold text-[var(--accent-contrast)] hover:opacity-90"
43+
class={LINK_CLASSES.ctaButton}
4344
>
4445
Book a Strategy Call
4546
</a>
@@ -50,14 +51,14 @@ const { homepage } = Astro.props as Props;
5051
<a
5152
href={`mailto:${homepage.contactEmail}`}
5253
data-track="cta_contact_email"
53-
class="rounded-lg border border-[var(--border-strong)] bg-[color-mix(in_srgb,var(--surface-panel)_80%,transparent)] px-6 py-3 font-semibold text-[var(--text-strong)] shadow-[0_8px_18px_rgba(0,0,0,0.16)] backdrop-blur-sm"
54+
class={`${CARD_CLASSES.glass} px-6 py-3 font-semibold text-[var(--text-strong)]`}
5455
>
5556
Email: {homepage.contactEmail}
5657
</a>
5758
<a
5859
href={homepage.githubUrl}
5960
data-track="open_github_profile"
60-
class="rounded-lg border border-[var(--border-strong)] bg-[color-mix(in_srgb,var(--surface-panel)_88%,transparent)] px-6 py-3 font-semibold text-[var(--text-strong)] shadow-[0_8px_18px_rgba(0,0,0,0.16)] backdrop-blur-sm"
61+
class={`${CARD_CLASSES.glassVariant} px-6 py-3 font-semibold text-[var(--text-strong)]`}
6162
>
6263
GitHub
6364
</a>

src/components/Portfolio.astro

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,49 @@
11
---
22
import type { CollectionEntry } from "astro:content";
3+
import { CARD_CLASSES, TYPOGRAPHY_CLASSES, LINK_CLASSES, CONTAINER_CLASSES } from "@lib/constants";
34
45
interface Props {
56
items: CollectionEntry<"portfolio">[];
67
}
78
89
const { items } = Astro.props as Props;
910
const sorted = [...items].sort((a, b) => a.data.order - b.data.order);
11+
12+
const techBadgeClass = "rounded border border-[var(--border-strong)] bg-[color-mix(in_srgb,var(--surface-elevated)_78%,transparent)] px-1.5 py-0.5 text-[11px] text-[var(--text-strong)]";
1013
---
1114

1215
<section id="work" data-reveal="up">
13-
<div class="section-content max-w-screen-lg mx-auto xl:max-w-screen-xl w-full">
16+
<div class={CONTAINER_CLASSES.sectionLg}>
1417
<div class="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
1518
{
1619
sorted.map((item) => (
17-
<article class="rounded-lg border border-[var(--border-strong)] bg-[color-mix(in_srgb,var(--surface-panel)_80%,transparent)] p-4 shadow-[0_12px_30px_rgba(0,0,0,0.22)] backdrop-blur-sm hover:shadow-[0_14px_36px_rgba(0,0,0,0.28)]">
20+
<article class={CARD_CLASSES.portfolio}>
1821
<div class="mb-3 flex justify-between items-start">
1922
<div>
20-
<p class="text-xs font-semibold text-[var(--accent-strong)]">{item.data.category}</p>
21-
<h3 class="mt-1 text-xl font-bold leading-tight text-[var(--text-strong)]">{item.data.title}</h3>
23+
<p class={TYPOGRAPHY_CLASSES.labelXs}>{item.data.category}</p>
24+
<h3 class={`mt-1 ${TYPOGRAPHY_CLASSES.cardTitleBold}`}>{item.data.title}</h3>
2225
</div>
2326
</div>
2427

25-
<p class="mb-3 text-sm text-[var(--text-muted)]">{item.data.summary}</p>
28+
<p class={`mb-3 ${TYPOGRAPHY_CLASSES.cardBodySm}`}>{item.data.summary}</p>
2629

2730
<div class="mb-3 border-t border-[var(--border-strong)] pt-3">
28-
<p class="text-xs font-semibold text-[var(--accent-strong)]">Impact</p>
29-
<p class="mt-1 text-sm text-[var(--text-strong)]">{item.data.impact}</p>
31+
<p class={TYPOGRAPHY_CLASSES.labelXs}>Impact</p>
32+
<p class={`mt-1 ${TYPOGRAPHY_CLASSES.cardBodySm}`}>{item.data.impact}</p>
3033
</div>
3134

3235
<div class="mb-3 flex justify-between items-center">
3336
<div>
34-
<p class="text-xs font-semibold text-[var(--accent-strong)]">Timeframe</p>
35-
<p class="text-xs text-[var(--text-muted)]">{item.data.timeframe}</p>
37+
<p class={TYPOGRAPHY_CLASSES.labelXs}>Timeframe</p>
38+
<p class={TYPOGRAPHY_CLASSES.cardBodyXs}>{item.data.timeframe}</p>
3639
</div>
3740
</div>
3841

3942
<div class="mb-3">
40-
<p class="mb-2 text-xs font-semibold text-[var(--accent-strong)]">Tech Stack</p>
43+
<p class={`mb-2 ${TYPOGRAPHY_CLASSES.labelXs}`}>Tech Stack</p>
4144
<div class="flex flex-wrap gap-1.5">
4245
{item.data.stack.map((tech) => (
43-
<span class="rounded border border-[var(--border-strong)] bg-[color-mix(in_srgb,var(--surface-elevated)_78%,transparent)] px-1.5 py-0.5 text-[11px] text-[var(--text-strong)]">
46+
<span class={techBadgeClass}>
4447
{tech}
4548
</span>
4649
))}
@@ -49,7 +52,7 @@ const sorted = [...items].sort((a, b) => a.data.order - b.data.order);
4952

5053
<a
5154
href={item.data.proofUrl}
52-
class="inline-block border-b border-[var(--accent-strong)] pb-0.5 text-xs font-semibold text-[var(--accent-strong)]"
55+
class={LINK_CLASSES.underlined}
5356
>
5457
{item.data.proofLabel}
5558
</a>

src/lib/constants.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ export const TYPOGRAPHY_CLASSES = {
1212
"mt-4 text-balance font-['Sora','Segoe_UI',sans-serif] text-[clamp(2.1rem,5vw,4.3rem)] leading-[1.06] tracking-[-0.03em]",
1313
subheading: "text-2xl font-semibold text-[var(--text-strong)] md:text-3xl",
1414
body: "text-[clamp(1rem,2vw,1.2rem)] leading-[1.7] text-[var(--text-muted)]",
15+
label: "text-sm text-[var(--accent-strong)]",
16+
labelXs: "text-xs font-semibold text-[var(--accent-strong)]",
17+
cardTitle: "text-xl font-semibold text-[var(--text-strong)]",
18+
cardTitleBold: "text-xl font-bold leading-tight text-[var(--text-strong)]",
19+
cardBody: "text-base font-medium text-[var(--text-strong)]",
20+
cardBodySm: "text-sm text-[var(--text-muted)]",
21+
cardBodyXs: "text-xs text-[var(--text-muted)]",
1522
};
1623

1724
export const BUTTON_CLASSES = {
@@ -25,6 +32,9 @@ export const BUTTON_CLASSES = {
2532
export const CARD_CLASSES = {
2633
base: "rounded-[var(--card-radius)] border border-[var(--card-uniform-border)] bg-[var(--card-uniform-bg)] shadow-[var(--card-shadow)]",
2734
compact: "p-5",
35+
glass: "rounded-lg border border-[var(--border-strong)] bg-[color-mix(in_srgb,var(--surface-panel)_80%,transparent)] shadow-[0_10px_26px_rgba(0,0,0,0.2)] backdrop-blur-sm",
36+
glassVariant: "rounded-lg border border-[var(--border-strong)] bg-[color-mix(in_srgb,var(--surface-panel)_88%,transparent)] shadow-[0_8px_18px_rgba(0,0,0,0.16)] backdrop-blur-sm",
37+
portfolio: "rounded-lg border border-[var(--border-strong)] bg-[color-mix(in_srgb,var(--surface-panel)_80%,transparent)] p-4 shadow-[0_12px_30px_rgba(0,0,0,0.22)] backdrop-blur-sm hover:shadow-[0_14px_36px_rgba(0,0,0,0.28)]",
2838
};
2939

3040
export const FORM_CLASSES = {
@@ -49,4 +59,28 @@ export const SKIP_LINK_CLASSES =
4959
export const CONTAINER_CLASSES = {
5060
horizontal: "mx-auto max-w-screen-xl px-6",
5161
section: "mx-auto w-full max-w-screen-xl px-6",
62+
sectionLg: "section-content max-w-screen-lg mx-auto xl:max-w-screen-xl w-full",
63+
};
64+
65+
export const LINK_CLASSES = {
66+
underlined: "inline-block border-b border-[var(--accent-strong)] pb-0.5 text-xs font-semibold text-[var(--accent-strong)]",
67+
ctaButton: "inline-block rounded-lg bg-[var(--accent-strong)] px-6 py-3 font-semibold text-[var(--accent-contrast)] hover:opacity-90",
68+
};
69+
70+
export const LAYOUT_CLASSES = {
71+
siteBg: "fixed inset-0 -z-10 pointer-events-none site-bg",
72+
mainContent: "h-screen overflow-y-auto scroll-smooth-snap",
73+
slideSection: "min-h-screen snap-start snap-always flex items-center md:min-h-screen max-md:min-h-0 max-md:snap-normal",
74+
slideSectionChild: "w-full",
75+
homeSlide: "block",
76+
sectionSizeHome: "pt-[clamp(5.6rem,10vh,8rem)] pb-[clamp(2.5rem,6vh,5rem)] max-md:pt-[6.2rem] max-md:pb-10",
77+
sectionSizeWork: "pt-[clamp(4.5rem,8vh,6.5rem)] pb-[clamp(3rem,7vh,5.5rem)] max-md:pt-[6.2rem] max-md:pb-10",
78+
sectionSizeBlog: "pt-[clamp(4.2rem,7.5vh,6rem)] pb-[clamp(3rem,7vh,5.2rem)] max-md:pt-[6.2rem] max-md:pb-10",
79+
homeStack: "min-h-[clamp(35rem,calc(100vh-7rem),56rem)] flex flex-col justify-center gap-[clamp(1.5rem,3vh,2.5rem)] max-md:min-h-0 max-md:justify-start",
80+
};
81+
82+
export const TYPING_CLASSES = {
83+
live: "hidden js:inline",
84+
fallback: "js:hidden",
85+
cursor: "animate-blink",
5286
};

src/lib/observe.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const setupRevealObserver = (): (() => void) => {
1212
return () => {};
1313
}
1414

15-
const observerOptions = {
15+
const observerOptions: IntersectionObserverInit = {
1616
root: revealRoot,
1717
rootMargin: "-8% 0px -8% 0px",
1818
threshold: 0.15,
@@ -31,13 +31,9 @@ export const setupRevealObserver = (): (() => void) => {
3131
observerOptions,
3232
);
3333

34-
revealNodes.forEach((node) => {
35-
revealObserver.observe(node);
36-
});
37-
38-
revealListNodes.forEach((node) => {
39-
revealObserver.observe(node);
40-
});
34+
// Combine all nodes to observe
35+
const allNodes = [...revealNodes, ...revealListNodes];
36+
allNodes.forEach((node) => revealObserver.observe(node));
4137

4238
return () => revealObserver.disconnect();
4339
};

src/pages/index.astro

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import {
55
CONTAINER_CLASSES,
66
FORM_CLASSES,
77
TYPOGRAPHY_CLASSES,
8+
LAYOUT_CLASSES,
9+
TYPING_CLASSES,
810
} from "@lib/constants";
911
import { SEO } from "astro-seo";
1012
import "../styles/global.css";
@@ -201,23 +203,24 @@ const structuredData = {
201203
document.documentElement.classList.add("js");
202204
</script>
203205
</head>
204-
<body class="site-shell">
206+
<body class="m-0 min-h-screen overflow-hidden site-shell">
205207
<a href="#main-content" class="absolute left-4 top-[-100%] z-[200] rounded-[0.6rem] border border-[var(--border-strong)] bg-[var(--surface-panel)] px-[0.85rem] py-[0.55rem] font-bold text-[var(--text-strong)] focus-visible:top-[0.8rem]">Skip to main content</a>
208+
<div aria-hidden="true" class={LAYOUT_CLASSES.siteBg}></div>
206209
<Header background={headerBackground} />
207210

208-
<main id="main-content" tabindex="-1">
209-
<section id="home" class="slide-section home-slide section-size-home relative overflow-hidden" aria-labelledby="hero-title">
210-
<div class="home-stack mx-auto w-full max-w-screen-xl px-6">
211+
<main id="main-content" class={LAYOUT_CLASSES.mainContent} tabindex="-1">
212+
<section id="home" class={`${LAYOUT_CLASSES.slideSection} ${LAYOUT_CLASSES.homeSlide} ${LAYOUT_CLASSES.sectionSizeHome} relative overflow-hidden`} aria-labelledby="hero-title">
213+
<div class={`${LAYOUT_CLASSES.homeStack} mx-auto w-full max-w-screen-xl px-6`}>
211214
<div class="w-full">
212215
<div>
213216
<p class={kickerClass}>{homepage.kicker}</p>
214217
<h1 id="hero-title" class={TYPOGRAPHY_CLASSES.heroTitle}>
215218
Avaab Razzaq
216219
</h1>
217220
<p class={TYPOGRAPHY_CLASSES.subheading}>
218-
<span class="typing-fallback">I am an AI Growth Engineer.</span>
219-
<span class="typing-live" aria-hidden="true">
220-
I am <Typer text={rolePhrases} cursor loop typingSpeed={90} backspaceSpeed={80} typingPause={1300} client:load />
221+
<span class={TYPING_CLASSES.fallback}>I am an AI Growth Engineer.</span>
222+
<span class={TYPING_CLASSES.live} aria-hidden="true">
223+
I am <Typer text={rolePhrases} cursor cursorClassName={TYPING_CLASSES.cursor} loop typingSpeed={90} backspaceSpeed={80} typingPause={1300} client:load />
221224
</span>
222225
<span class="sr-only">
223226
I am an AI Growth Engineer. I am an Automations Architect. I am a Full-Stack Web Developer. I am an SEO and Marketing Strategist.
@@ -241,7 +244,7 @@ const structuredData = {
241244
</div>
242245
</section>
243246

244-
<section id="services" class="slide-section pb-8" aria-labelledby="services-title">
247+
<section id="services" class={`${LAYOUT_CLASSES.slideSection} pb-8`} aria-labelledby="services-title">
245248
<div class={CONTAINER_CLASSES.horizontal}>
246249
<h2 id="services-title" class={titleClass}>Services and Solutions</h2>
247250
<p class={`mt-4 max-w-3xl ${copyClass}`}>
@@ -260,7 +263,7 @@ const structuredData = {
260263
</div>
261264
</section>
262265

263-
<section id="work" class="slide-section work-slide section-size-work" aria-labelledby="work-title">
266+
<section id="work" class={`${LAYOUT_CLASSES.slideSection} work-slide ${LAYOUT_CLASSES.sectionSizeWork}`} aria-labelledby="work-title">
264267
<div class={CONTAINER_CLASSES.horizontal}>
265268
<div class="flex flex-wrap items-end justify-between gap-4">
266269
<h2 id="work-title" class={titleClass}>Proof-of-Concept Builds</h2>
@@ -305,7 +308,7 @@ const structuredData = {
305308
</div>
306309
</section>
307310

308-
<section id="contact" class="slide-section pt-10 pb-20" aria-labelledby="contact-title">
311+
<section id="contact" class={`${LAYOUT_CLASSES.slideSection} pt-10 pb-20`} aria-labelledby="contact-title">
309312
<div class={CONTAINER_CLASSES.horizontal}>
310313
<div class="grid items-start gap-[clamp(1.25rem,2.3vw,2rem)] min-[980px]:grid-cols-[1.1fr_0.9fr]">
311314
<div class="max-w-[38rem]">

0 commit comments

Comments
 (0)