A fast, data-driven personal portfolio and curriculum vitae built with Astro, React, and Tailwind CSS v4.
This repository hosts the source code for the personal portfolio of Sy Sophaneth, a Software Developer & Educator based in Cambodia.
Engineered with performance, elegance, and maintainability in mind, the portfolio leverages Astro's Islands Architecture to deliver zero unnecessary client-side JavaScript by default, hydrating interactive components only where required. All personal milestones, professional experience, projects, skills, and contact channels are decoupled from presentation components and managed from a single typed source of truth.
- ⚡ Blazing Fast Static Delivery: Pre-rendered statically with Astro 7 for instant page loads and maximum SEO performance.
- 🏝️ Selective Island Hydration: Interactive controls (such as tooltips and dynamic action triggers) are isolated in React 19 components and hydrated on demand with
client:load. - 🌌 Interactive Canvas Particle Network: A lightweight, dependency-free HTML5 Canvas particle background (
NetworkBackground.astro) simulating interconnected nodes that adapt to viewport dimensions and render cycles. - ✍️ Dynamic Typewriter Animation: Smooth, cycling title headline in the hero section introducing developer and educator roles.
- 🧭 Scroll-Spy Sticky Navigation: Header nav items dynamically track the user's scroll position with an IntersectionObserver and highlight active sections in real time.
- 💫 Fluid Scroll-Reveal Motion: Global viewport reveal observer animating sections gracefully as they enter the screen.
- 🎨 Modern OKLCH Theme Architecture: Styled with Tailwind CSS v4 using perceptually uniform OKLCH color palettes, glassmorphism blur effects, and rich typography.
- 🗃️ Single Source of Truth (
src/data/cv.ts): All resume data (experience, projects, stack, education, languages) lives in one centralized file—no digging through HTML or layouts to update your resume. - 🚀 Automated CI/CD: GitHub Actions workflow automatically builds and publishes the production bundle directly to GitHub Pages on every push to
main.
| Layer | Technology | Description |
|---|---|---|
| Framework | Astro v7 | Static site generator & islands architecture orchestration |
| Interactive Islands | React 19 | Isolated client components (@astrojs/react) |
| Styling | Tailwind CSS v4 | Next-generation CSS framework compiled via @tailwindcss/vite |
| Theme System | OKLCH Color Space & CSS Variables | Perceptually uniform dark and light color tokens |
| UI Primitives | Base UI & Lucide React | Accessible tooltip wrappers and icon primitives |
| Iconography | Font Awesome | Comprehensive vector icons for tech tags, roles, and contacts |
| Typography | Space Grotesk, Aleo, Space Mono | Web font stack paired with @fontsource-variable packages |
| Language | TypeScript | Type-safe components, data models, and configurations |
| Deployment | GitHub Actions & Pages | Automated build & zero-downtime static hosting pipeline |
Netnet78.github.io/
├── .github/
│ └── workflows/
│ └── deploy.yml # GitHub Actions CI/CD to GitHub Pages
├── public/
│ ├── favicon.ico
│ ├── favicon.svg
│ └── images/
│ └── square-profile.jpg # Profile portrait photo
├── src/
│ ├── components/
│ │ ├── sections/ # Modular page sections
│ │ │ ├── Hero.astro # Headline, typewriter effect, CTA & profile card
│ │ │ ├── About.astro # Narrative bio, personal snapshot & languages
│ │ │ ├── Experiences.astro # Professional & volunteer timeline
│ │ │ ├── Projects.astro # Featured engineering projects & repositories
│ │ │ ├── Skills.astro # Categorized technical competencies
│ │ │ ├── Education.astro # Academic milestones & diplomas
│ │ │ └── Contact.astro # Direct channels & message submission form
│ │ ├── ui/ # Reusable UI primitives
│ │ │ ├── button.tsx # Styled button variants with CVA
│ │ │ └── tooltip.tsx # Accessible Base UI tooltip wrapper
│ │ ├── ContactButton.tsx # Header quick-contact action button
│ │ ├── DownloadCvButton.tsx # Header CV download button (external PDF)
│ │ ├── MainHeader.astro # Sticky navigation bar with scroll-spy
│ │ ├── MainFooter.astro # Footer branding, copyright & quick links
│ │ └── NetworkBackground.astro # Interactive canvas particle constellation
│ ├── data/
│ │ └── cv.ts # Centralized resume & portfolio content data
│ ├── layouts/
│ │ └── BaseLayout.astro # HTML scaffold, metadata, fonts, scroll observer
│ ├── lib/
│ │ └── utils.ts # Class merging utility (clsx + tailwind-merge)
│ ├── pages/
│ │ └── index.astro # Single-page portfolio root route
│ └── styles/
│ └── global.css # Global tokens, OKLCH themes & animation classes
├── astro.config.mjs # Astro configuration (Vite, React, Tailwind plugins)
├── package.json
└── tsconfig.json
All portfolio content is decoupled from layout markup. You can update virtually everything on the site simply by editing src/data/cv.ts:
Update your headline, location, and contact email:
export const profile = {
name: "Sy Sophaneth",
title: "Software Developer & Educator",
location: "Poipet, Banteay Meanchey, Cambodia",
email: "sysophaneth@gmail.com",
// ...
};Add or edit roles in the experiences array:
experiences: [
{
role: "Volunteer Computer Science Teacher",
org: "Don Bosco High School of Poipet",
period: "Aug 2026 - Present",
icon: "fa-solid fa-chalkboard-user",
skills: ["CS Fundamentals", "Lab Curriculum", "Mentorship"],
bullets: [
"Volunteered to instruct high school students in fundamental CS...",
],
},
]Add new software or media projects to the projects array:
projects: [
{
title: "School Management System",
category: "DESKTOP APP",
icon: "fa-solid fa-desktop",
description: "Comprehensive desktop application to streamline...",
tags: ["C#", "WPF", "XAML", "Database"],
github: "https://github.com/Netnet78/School-Management-System",
view: "https://www.youtube.com/watch?v=...",
},
]Organize skills under custom categories in the skills array:
skills: [
{
faIcon: "fa-solid fa-code",
category: "Development & Systems",
items: ["C# • .NET Ecosystem", "Desktop Dev (XAML & WPF)", "Full Stack Web"],
},
]When extending or maintaining this codebase, keep these rules in mind:
- Mandatory
revealClass on Sections: Every<section>element created across pages or components must include the.revealclass (e.g.<section id="..." class="... reveal">). This is required by the global IntersectionObserver inBaseLayout.astrofor entrance animations. - Astro Islands: Use
.astrocomponents for all static content. Only use.tsxwhen stateful DOM interaction or React hooks are required, and include an appropriate client directive (e.g.,<ContactButton client:load />). - Tailwind v4 Setup: Tailwind v4 runs directly through
@tailwindcss/vitewithinastro.config.mjsand imports styles via@import "tailwindcss";insrc/styles/global.css.
- Node.js:
>= 22.12.0 - Package Manager:
npm(orpnpm/bun)
git clone https://github.com/Netnet78/Netnet78.github.io.git
cd Netnet78.github.ionpm installnpm run devAlternatively, start the Astro dev server in background mode:
astro dev --backgroundOpen http://localhost:4321 in your browser to view the site.
# Build static files into ./dist
npm run build
# Preview the production build locally
npm run previewThe portfolio is continuously deployed to GitHub Pages using GitHub Actions:
- Whenever a commit is pushed to the
mainbranch, the workflow in.github/workflows/deploy.ymltriggers automatically. - The
withastro/action@v3action checks out the repository, installs dependencies, and runsastro buildon Node 22. - The generated
./distartifacts are uploaded and published to GitHub Pages with zero manual intervention.
This project is open-source under the MIT License. Feel free to use the structure as inspiration for your own portfolio!