Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
themeColor: '#0d0d0b',
viewportFit: 'cover',
}

export default function RootLayout({ children }: { children: React.ReactNode }) {
Expand Down
2 changes: 1 addition & 1 deletion src/components/layout/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const footerLinks = [

export function Footer() {
return (
<footer className="flex flex-col items-center justify-between gap-6 border-t border-[var(--border)] px-6 py-8 md:flex-row md:gap-0 md:px-12 md:py-12">
<footer className="page-x flex flex-col items-center justify-between gap-6 border-t border-[var(--border)] py-8 md:flex-row md:gap-0 md:py-12">
<span className={type.footer}>
© {site.copyrightYear} {site.name}
</span>
Expand Down
18 changes: 12 additions & 6 deletions src/components/layout/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function Navigation() {

return (
<nav
className="fixed top-0 right-0 left-0 z-[100] flex items-center justify-between px-6 py-6 md:px-12"
className="fixed top-0 right-0 left-0 z-[100] flex items-center justify-between page-x py-6"
style={{
background: 'linear-gradient(to bottom, rgba(13,13,11,0.95) 0%, transparent 100%)',
}}
Expand All @@ -25,19 +25,25 @@ export function Navigation() {

<button
type="button"
className="flex h-5 w-6 flex-col items-center justify-center gap-1.5 md:hidden"
className="relative grid h-10 w-10 shrink-0 place-items-center md:hidden"
onClick={toggleMobileNav}
aria-label={isMobileNavOpen ? 'Close menu' : 'Open menu'}
aria-expanded={isMobileNavOpen}
>
<span
className={`h-px w-full bg-[var(--accent)] transition-all duration-300 ${isMobileNavOpen ? 'translate-y-[5px] rotate-45' : ''}`}
className={`absolute h-px w-5 origin-center bg-[var(--accent)] transition-all duration-300 ${
isMobileNavOpen ? 'rotate-45' : '-translate-y-[6px]'
}`}
/>
<span
className={`h-px w-full bg-[var(--accent)] transition-all duration-300 ${isMobileNavOpen ? 'opacity-0' : ''}`}
className={`absolute h-px w-5 bg-[var(--accent)] transition-all duration-300 ${
isMobileNavOpen ? 'scale-x-0 opacity-0' : ''
}`}
/>
<span
className={`h-px w-full bg-[var(--accent)] transition-all duration-300 ${isMobileNavOpen ? '-translate-y-[5px] -rotate-45' : ''}`}
className={`absolute h-px w-5 origin-center bg-[var(--accent)] transition-all duration-300 ${
isMobileNavOpen ? '-rotate-45' : 'translate-y-[6px]'
}`}
/>
</button>

Expand All @@ -58,7 +64,7 @@ export function Navigation() {

{isMobileNavOpen && (
<div
className="fixed top-[72px] right-0 left-0 px-6 py-8 md:hidden"
className="fixed top-[72px] right-0 left-0 page-x py-8 md:hidden"
style={{
background: 'rgba(13,13,11,0.98)',
borderBottom: '1px solid var(--border)',
Expand Down
4 changes: 2 additions & 2 deletions src/components/pages/ArticlePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function ArticlePage({ slug }: ArticlePageProps) {
return (
<div>
<nav
className="fixed top-0 right-0 left-0 z-[100] flex items-center justify-between border-b px-6 py-6 md:px-12"
className="fixed top-0 right-0 left-0 z-[100] flex items-center justify-between border-b page-x py-6"
style={{ background: 'rgba(13,13,11,0.97)', borderColor: 'var(--border)' }}
>
<Link
Expand All @@ -62,7 +62,7 @@ export function ArticlePage({ slug }: ArticlePageProps) {
</a>
</nav>

<div className="mx-auto max-w-[720px] px-6 pt-32 pb-24 md:px-12">
<div className="page-x mx-auto max-w-[720px] pt-32 pb-24">
<div className="mb-16">
<div className="mb-6 flex items-center gap-4 font-mono text-[10px] font-medium tracking-[0.2em] text-[var(--accent2)] uppercase">
<span className="block h-px w-6 bg-[var(--accent2)]" />
Expand Down
8 changes: 4 additions & 4 deletions src/components/sections/AboutSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { type } from '@/lib/typography'

export function AboutSection() {
return (
<section className="px-6 py-16 md:px-12 md:py-24" id="about">
<section className="page-x py-16 md:py-24" id="about">
<SectionHeader number="01" title="About" />

<div className="grid grid-cols-1 items-start gap-12 lg:grid-cols-2 lg:gap-24">
Expand All @@ -20,15 +20,15 @@ export function AboutSection() {
{site.aboutDetails.map((detail) => (
<div
key={detail.label}
className="flex items-center justify-between border-b border-[var(--border)] py-[1.1rem]"
className="flex min-w-0 items-center justify-between border-b border-[var(--border)] py-[1.1rem]"
>
<span className={type.label}>{detail.label}</span>
{'link' in detail && detail.link ? (
<a href={detail.link} className={`text-right no-underline ${type.bodyAccent}`}>
<a href={detail.link} className={`min-w-0 shrink text-right no-underline ${type.bodyAccent}`}>
{detail.value}
</a>
) : (
<span className={`text-right whitespace-pre-line ${type.bodyEmphasis}`}>
<span className={`min-w-0 shrink text-right whitespace-pre-line ${type.bodyEmphasis}`}>
{detail.value}
</span>
)}
Expand Down
4 changes: 2 additions & 2 deletions src/components/sections/ExperienceSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { type } from '@/lib/typography'

export function ExperienceSection() {
return (
<section className="px-6 py-16 md:px-12 md:py-24" id="work">
<section className="page-x py-16 md:py-24" id="work">
<SectionHeader number="02" title="Experience" />

<div className="flex flex-col">
Expand All @@ -13,7 +13,7 @@ export function ExperienceSection() {
key={exp.company}
className="group relative grid grid-cols-1 gap-6 border-b border-[var(--border)] py-8 md:grid-cols-[200px_1fr_auto] md:gap-12 md:py-10"
>
<div className="pointer-events-none absolute -top-0 -right-6 -bottom-0 -left-6 bg-[var(--surface)] opacity-0 transition-opacity duration-[250ms] group-hover:opacity-100 md:-right-12 md:-left-12" />
<div className="pointer-events-none absolute inset-0 bg-[var(--surface)] opacity-0 transition-opacity duration-[250ms] group-hover:opacity-100" />

<div className="relative">
<div className={`mb-[0.4rem] ${type.eyebrowAccent}`}>{exp.company}</div>
Expand Down
7 changes: 5 additions & 2 deletions src/components/sections/HeroSection.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Button } from '@/components/ui/button'
import { ExternalArrow } from '@/components/shared/ExternalArrow'
import { site } from '@/data/site'
import { type } from '@/lib/typography'

export function HeroSection() {
return (
<section className="relative grid min-h-screen grid-cols-1 overflow-hidden px-6 md:px-12 lg:grid-cols-2">
<section className="relative grid min-h-screen grid-cols-1 overflow-x-clip page-x lg:grid-cols-2">
<div
className="pointer-events-none absolute -top-[20%] -right-[10%] h-[600px] w-[600px]"
style={{
Expand Down Expand Up @@ -41,7 +42,9 @@ export function HeroSection() {
<a href={site.links.email}>Get in touch →</a>
</Button>
<Button variant="outline" asChild>
<a href={site.links.github}>GitHub ↗</a>
<a href={site.links.github} className="inline-flex items-center gap-1.5">
GitHub <ExternalArrow className="h-3 w-3" />
</a>
</Button>
</div>
</div>
Expand Down
6 changes: 3 additions & 3 deletions src/components/sections/InterestsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import { type } from '@/lib/typography'

export function InterestsSection() {
return (
<section className="px-6 py-16 md:px-12 md:py-24" id="interests">
<section className="page-x py-16 md:py-24" id="interests">
<SectionHeader number="05" title="Interests" />

<div className="grid grid-cols-1 gap-6 md:grid-cols-2 md:gap-8">
{interests.map((interest, index) => (
<div
key={interest.title}
className="group relative border border-[var(--border)] p-6 transition-all duration-300 md:p-8"
className="group bleed-x relative border border-[var(--border)] py-6 transition-all duration-300 md:py-8"
style={{ background: 'var(--surface)' }}
onMouseEnter={(e) => {
e.currentTarget.style.background = 'var(--surface2)'
Expand All @@ -24,7 +24,7 @@ export function InterestsSection() {
e.currentTarget.style.borderColor = 'var(--border)'
}}
>
<div className={`absolute top-6 right-6 opacity-30 ${type.sectionNumber}`}>
<div className={`absolute top-6 right-[var(--page-gutter-right)] opacity-30 ${type.sectionNumber}`}>
0{index + 1}
</div>

Expand Down
11 changes: 6 additions & 5 deletions src/components/sections/ProjectsSection.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
'use client'

import { SectionHeader } from '@/components/shared/SectionHeader'
import { ExternalArrow } from '@/components/shared/ExternalArrow'
import { projects } from '@/data/projects'
import { type } from '@/lib/typography'

export function ProjectsSection() {
return (
<section className="px-6 py-16 md:px-12 md:py-24" id="projects">
<section className="page-x py-16 md:py-24" id="projects">
<SectionHeader number="03" title="Projects" />

<div className="max-w-2xl">
{projects.map((project) => (
<div
key={project.title}
className="interactive group relative overflow-hidden p-6 transition-all duration-200 md:p-10"
className="interactive group bleed-x relative overflow-hidden py-6 transition-all duration-200 md:py-10"
style={{ background: 'var(--surface)' }}
onMouseEnter={(e) => {
e.currentTarget.style.background = 'var(--surface2)'
Expand All @@ -22,7 +23,7 @@ export function ProjectsSection() {
e.currentTarget.style.background = 'var(--surface)'
}}
>
<div className="pointer-events-none absolute top-8 right-8 font-serif text-[72px] leading-none font-normal text-[var(--border)]">
<div className="pointer-events-none absolute top-8 right-[var(--page-gutter-right)] font-serif text-[72px] leading-none font-normal text-[var(--border)]">
{project.num}
</div>

Expand All @@ -48,9 +49,9 @@ export function ProjectsSection() {
target="_blank"
rel="noopener noreferrer"
aria-label={`Visit ${project.title}`}
className="text-[18px] text-[var(--dim)] no-underline transition-colors duration-200 hover:text-[var(--accent)]"
className="text-[var(--dim)] no-underline transition-colors duration-200 hover:text-[var(--accent)]"
>
↗
<ExternalArrow className="h-[18px] w-[18px]" />
</a>
</div>
</div>
Expand Down
6 changes: 3 additions & 3 deletions src/components/sections/WritingSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import { type } from '@/lib/typography'

export function WritingSection() {
return (
<section className="px-6 py-16 md:px-12 md:py-24" id="writing">
<section className="page-x py-16 md:py-24" id="writing">
<SectionHeader number="04" title="Writing" />

<div className="max-w-2xl">
{articles.map((article) => (
<Link
key={article.slug}
href={`/article/${article.slug}`}
className="interactive relative block overflow-hidden p-6 no-underline transition-all duration-200 md:p-10"
className="interactive bleed-x relative block overflow-hidden py-6 no-underline transition-all duration-200 md:py-10"
style={{ background: 'var(--surface)' }}
onMouseEnter={(e: React.MouseEvent<HTMLAnchorElement>) => {
e.currentTarget.style.background = 'var(--surface2)'
Expand All @@ -42,7 +42,7 @@ export function WritingSection() {
))}
</div>

<div className="flex items-center justify-between border-t border-[var(--border)] pt-4">
<div className="flex flex-col gap-3 border-t border-[var(--border)] pt-4 sm:flex-row sm:items-center sm:justify-between">
<span className={type.meta}>{article.date}</span>
<span className={type.meta}>{article.readTime}</span>
<span className={`flex items-center gap-2 ${type.action}`}>
Expand Down
16 changes: 16 additions & 0 deletions src/components/shared/ExternalArrow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export function ExternalArrow({ className }: { className?: string }) {
return (
<svg
aria-hidden="true"
viewBox="0 0 12 12"
className={className}
fill="none"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M3.5 8.5 8.5 3.5M8.5 3.5 3.5 3.5M8.5 3.5 8.5 8.5" />
</svg>
)
}
6 changes: 5 additions & 1 deletion src/components/shared/SectionHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,9 @@ export function SectionHeader({ number, title }: SectionHeaderProps) {
}

export function SectionDivider() {
return <div className="mx-6 h-px bg-[var(--border)] md:mx-12" />
return (
<div className="page-x">
<div className="h-px bg-[var(--border)]" />
</div>
)
}
2 changes: 1 addition & 1 deletion src/data/experience.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export const experiences = [
role: 'Senior Engineer I',
description:
'Designing and delivering scalable AI-enabled digital and automation transformations across service operations, utilities, MedTech, procurement, and GenAI. Built an AI-powered invoice reconciliation system processing $5B+ in procurement spend, surfacing cost reduction opportunities across client portfolios.',
highlight: '↑ $5B+ in procurement spend processed',
highlight: '↑ $5B+ in client spend analyzed',
},
{
company: 'Squamish.RealEstate',
Expand Down
2 changes: 1 addition & 1 deletion src/data/site.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const site = {
email: 'mailto:ngonidzashehh@gmail.com',
},
stats: [
{ num: '$5B+', label: 'Procurement spend processed' },
{ num: '$5B+', label: 'Client spend analyzed' },
{ num: '3+', label: 'Years at McKinsey' },
{ num: '10K+', label: 'Property listings managed' },
{ num: '97%', label: 'Model accuracy in production' },
Expand Down
27 changes: 26 additions & 1 deletion src/styles/theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

:root {
--font-size: 16px;
--page-gutter-left: max(1.5rem, env(safe-area-inset-left, 0px));
--page-gutter-right: max(1.5rem, env(safe-area-inset-right, 0px));

--bg: #0d0d0b;
--surface: #141412;
Expand Down Expand Up @@ -62,6 +64,27 @@
--radius-xl: calc(var(--radius) + 4px);
}

@media (min-width: 768px) {
:root {
--page-gutter-left: max(3rem, env(safe-area-inset-left, 0px));
--page-gutter-right: max(3rem, env(safe-area-inset-right, 0px));
}
}

@layer utilities {
.page-x {
padding-left: var(--page-gutter-left);
padding-right: var(--page-gutter-right);
}

.bleed-x {
margin-left: calc(-1 * var(--page-gutter-left));
margin-right: calc(-1 * var(--page-gutter-right));
padding-left: var(--page-gutter-left);
padding-right: var(--page-gutter-right);
}
}

@layer base {
*,
*::before,
Expand All @@ -75,14 +98,16 @@
html {
scroll-behavior: smooth;
font-size: var(--font-size);
overflow-x: clip;
}

body {
background: var(--bg);
color: var(--text);
font-family: var(--font-sans);
min-height: 100vh;
overflow-x: hidden;
max-width: 100%;
overflow-x: clip;
}

@media (pointer: fine) and (min-width: 1024px) {
Expand Down
Loading