diff --git a/CLAUDE.md b/CLAUDE.md index f5904d8..47a8c34 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,6 +1,6 @@ # jonathanperis.github.io — Claude Code Guide -Personal developer portfolio built with Next.js 16, deployed as a static site to GitHub Pages. +Personal developer portfolio built with Astro 6 and React 19, deployed as a static site to GitHub Pages. **Live:** https://jonathanperis.github.io/ @@ -10,90 +10,101 @@ Personal developer portfolio built with Next.js 16, deployed as a static site to | Technology | Purpose | |-----------|---------| -| Next.js 16.2 | App Router, static export | -| React 19.2 | Component rendering | -| TypeScript 5 | Type safety | -| Tailwind CSS 4 | Utility-first styling | -| GitHub GraphQL API | Fetch pinned repos at build time | -| Google Analytics 4 | Traffic tracking | +| Astro 6 | Static site build and GitHub Pages export | +| React 19 | Hydrated interactive portfolio UI | +| TypeScript 6 | Strict type checking through `astro/tsconfigs/strict` | +| Tailwind CSS 4 | Custom low-glare terminal-style design system via `@tailwindcss/vite` | +| GitHub GraphQL + REST APIs | Build-time repository and GitHub Pages URL discovery | +| Google Analytics 4 | Traffic and CTA event tracking when `PUBLIC_GA_ID` is set | +| Bun | Local and CI package manager/script runner | --- ## Build Commands ```sh -npm run dev # Dev server on :3000 -npm run build # Static export to ./out -npm run lint # ESLint (Next.js web vitals + TypeScript) -npm start # Production server (local only) +bun install # install dependencies +bun run dev # Astro dev server on :4321 +bun run lint # astro check +bun run build # static export to ./out +bun run preview # preview the built ./out artifact +``` + +For live repository data during local builds: + +```sh +GITHUB_TOKEN=$(gh auth token) PUBLIC_GA_ID=G-35CN95481D bun run build ``` --- ## Architecture -``` -Server Components (RSC) -├── app/page.tsx # Async: fetches GitHub repos, renders Portfolio -├── app/layout.tsx # Root: metadata, fonts, GA, JSON-LD -└── app/resume/layout.tsx # Resume metadata - -Client Components ("use client") -├── Portfolio # Main interactive UI (terminal, typing, scroll) -├── ResumePage # Print-optimized resume with PDF download -├── Analytics # GA4 script injection -└── JsonLd # Schema.org structured data - -Data Layer -├── lib/github.ts # GraphQL API + fallback repos -└── lib/data.ts # PROFILE, SKILLS, EXPERIENCES, FEATURED_PROJECTS +```text +Astro pages/layouts +├── src/pages/index.astro # Build-time fetchRepos(), renders Portfolio with client:load +├── src/pages/resume.astro # Print-optimized resume route +└── src/layouts/RootLayout.astro # HTML shell, metadata, fonts, JSON-LD, analytics + +Interactive island +└── src/components/Portfolio.tsx # Main React UI: hero, profile, stack, experience, Workbench, terminal + +Astro components +├── src/components/Analytics.astro # Conditional GA4 loader from PUBLIC_GA_ID +└── src/components/JsonLd.astro # Schema.org Person JSON-LD + +Data layer +├── src/lib/github.ts # GitHub GraphQL + REST client with fallback repo data +└── src/lib/data.ts # PROFILE, AVAILABILITY, SKILLS, EXPERIENCES, EDUCATION, SOCIALS ``` --- ## Key Patterns -- **Static export** — `output: "export"` in next.config.ts, no server at runtime -- **Build-time data fetching** — GitHub API called during `npm run build` -- **Fallback data** — Hardcoded repos in `github.ts` if API fails -- **Terminal easter egg** — CLI emulator with Konami code trigger -- **Typing animation** — Custom `useTyping()` hook for role cycling -- **Print optimization** — Resume page with A4 CSS, black/white media queries -- **SEO** — JSON-LD (Schema.org Person), OG/Twitter meta, sitemap.xml -- **Cache headers** — Static assets: `max-age=31536000, immutable` +- **Static export** — `astro.config.ts` sets `outDir: 'out'`; GitHub Pages deploys the generated artifact. +- **Build-time GitHub data** — `src/pages/index.astro` calls `fetchRepos()` during `bun run build`; the deployed browser page does not call GitHub APIs. +- **Pinned + ledger model** — `src/lib/github.ts` fetches GitHub profile pinned repos and owned public non-fork repos, excludes metadata repos, preserves pinned order, and removes pinned repos from the lower ledger. +- **Pages URL enrichment** — REST `GET /repos/jonathanperis/{repo}/pages` provides `pagesUrl`; standard `https://jonathanperis.github.io//` homepage URLs are fallback Pages links. +- **Fallback data** — Hardcoded repos keep local builds and PR checks working when `GITHUB_TOKEN` is absent. +- **Single profile source** — `src/lib/data.ts` powers the portfolio, resume, terminal snippets, and JSON-LD. +- **Terminal easter egg** — Konami code opens an in-page terminal. `runCmd()` in `Portfolio.tsx` handles `help`, `about`, `stack`, `contact`, `neofetch`, `git log`, `ls`, `cat availability.txt`, `whoami`, `pwd`, `date`, `sudo hire me`, `echo`, `clear`, `exit`, and `quit`. +- **SEO** — `RootLayout.astro` emits canonical, Open Graph, Twitter, icon, manifest, alternate-language, JSON-LD, and font tags; `public/robots.txt` and `public/sitemap.xml` are included. --- ## Project Structure -``` +```text jonathanperis.github.io/ -├── app/ -│ ├── page.tsx # Home page (server component) -│ ├── portfolio.tsx # Main UI (client component) -│ ├── layout.tsx # Root layout + metadata -│ ├── globals.css # Tailwind + custom theme + animations +├── src/ +│ ├── pages/ +│ │ ├── index.astro +│ │ └── resume.astro │ ├── components/ -│ │ ├── analytics.tsx # GA4 integration -│ │ └── json-ld.tsx # Structured data +│ │ ├── Portfolio.tsx +│ │ ├── Analytics.astro +│ │ └── JsonLd.astro +│ ├── layouts/ +│ │ └── RootLayout.astro │ ├── lib/ -│ │ ├── github.ts # GitHub GraphQL client + fallback -│ │ └── data.ts # Static profile/skills/experience data -│ └── resume/ -│ ├── layout.tsx # Resume layout -│ └── page.tsx # Print-optimized resume +│ │ ├── github.ts +│ │ └── data.ts +│ └── styles/ +│ └── globals.css ├── public/ -│ ├── cv_jonathan_peris.pdf # Downloadable CV -│ ├── manifest.json # PWA manifest +│ ├── cv_jonathan_peris.pdf +│ ├── manifest.json │ ├── robots.txt / sitemap.xml │ └── favicon.svg / apple-touch-icon.png -├── next.config.ts # Static export, cache headers -├── tsconfig.json # strict, ES2017, @/* alias -├── postcss.config.mjs # Tailwind CSS v4 +├── wiki/ +├── astro.config.ts +├── tsconfig.json +├── package.json └── .github/workflows/ - ├── build-check.yml # PR build check (lint + build) - ├── main-release.yml # GitHub Pages deploy on push to main - └── codeql.yml # Security analysis (JS/TS) + ├── build-check.yml + ├── main-release.yml + └── codeql.yml ``` --- @@ -102,8 +113,8 @@ jonathanperis.github.io/ | Variable | Purpose | |----------|---------| -| `GITHUB_TOKEN` | GitHub API auth (provided by Actions) | -| `NEXT_PUBLIC_GA_ID` | GA4 tracking ID (G-35CN95481D) | +| `GITHUB_TOKEN` | GitHub API auth for GraphQL repo data and REST Pages URL lookup; provided by Actions | +| `PUBLIC_GA_ID` | GA4 tracking ID consumed by `src/components/Analytics.astro` (`G-35CN95481D` in workflows) | --- @@ -111,32 +122,32 @@ jonathanperis.github.io/ | Workflow | Trigger | Purpose | |----------|---------|---------| -| `build-check.yml` | Pull requests to main | Lint + build validation | -| `main-release.yml` | Push to main / manual dispatch | Build → upload → deploy to GitHub Pages | -| `codeql.yml` | Push, PRs, weekly (Mon 06:00 UTC) | JavaScript/TypeScript security scanning | +| `build-check.yml` | Pull requests to `main`, manual dispatch | Bun install, `astro check`, Astro build | +| `main-release.yml` | Push to `main`, manual dispatch | Build `out/`, upload artifact, deploy GitHub Pages | +| `codeql.yml` | Push, PRs, weekly Monday 06:00 UTC | JavaScript/TypeScript security scanning | -- **Dependabot:** Weekly npm + GitHub Actions updates +- **Dependabot:** Weekly npm and GitHub Actions updates - **Merge strategy:** Rebase only (squash and merge commits disabled) -- **Branch protection:** Main branch is protected; all changes go through PRs -- **Auto-merge:** Enabled for Dependabot PRs +- **Branch protection:** Main branch is protected; changes go through PRs +- **Community health files:** CODE_OF_CONDUCT, CONTRIBUTING, SECURITY, and SUPPORT live in the [`.github` repo](https://github.com/jonathanperis/.github); do not duplicate them here --- ## Development Workflow -1. **Sync main first:** `git fetch origin main && git checkout main && git pull origin main` -2. Create a feature branch from `main` -3. Make changes and push -4. **Before opening a PR:** fetch and pull main again to ensure no conflicts -5. Open a PR targeting `main` — CI runs lint + build automatically -6. After review and green checks, rebase-merge the PR -7. `main-release.yml` triggers automatically on push to main +1. Sync main first: `git fetch origin main && git switch main && git pull --ff-only origin main` +2. Create a branch from `main` +3. Make changes and run `bun run lint` and `bun run build` +4. Push the branch and open a PR targeting `main` +5. Watch PR checks and resolve any failures +6. Rebase-merge when checks/review are green and merge is authorized +7. Watch `main-release.yml`, then verify the live GitHub Pages route(s) --- ## Repository Conventions -- **GitHub operations:** Always use `gh` CLI -- **Community health files** (CODE_OF_CONDUCT, CONTRIBUTING, SECURITY, SUPPORT) live in the [`.github` repo](https://github.com/jonathanperis/.github) — do not duplicate them here -- **PR strategy:** Branch + PR for all changes, rebase merge only -- **Commit style:** Conventional commits (`feat:`, `fix:`, `chore:`, `docs:`) +- Use the `gh` CLI for GitHub operations. +- Use Bun, not npm, for install/build commands in this repo. +- Keep README/wiki/Claude docs aligned with the Astro source tree (`src/...`) and workflow files. +- Commit messages should use Conventional Commits (`feat:`, `fix:`, `docs:`, `chore:`). diff --git a/README.md b/README.md index 3fb9a0e..35f0e16 100644 --- a/README.md +++ b/README.md @@ -4,45 +4,47 @@ [![Build Check](https://github.com/jonathanperis/jonathanperis.github.io/actions/workflows/build-check.yml/badge.svg)](https://github.com/jonathanperis/jonathanperis.github.io/actions/workflows/build-check.yml) [![Main Release](https://github.com/jonathanperis/jonathanperis.github.io/actions/workflows/main-release.yml/badge.svg)](https://github.com/jonathanperis/jonathanperis.github.io/actions/workflows/main-release.yml) [![CodeQL](https://github.com/jonathanperis/jonathanperis.github.io/actions/workflows/codeql.yml/badge.svg)](https://github.com/jonathanperis/jonathanperis.github.io/actions/workflows/codeql.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) -**[Live demo →](https://jonathanperis.github.io/)** | **[Documentation →](CLAUDE.md)** +**[Live demo →](https://jonathanperis.github.io/)** | **[Contributor guide →](CLAUDE.md)** | **[Wiki →](wiki/index.md)** --- ## About -Astro portfolio with a static export for GitHub Pages. It fetches the repositories pinned on Jonathan's GitHub profile plus public, non-fork repositories from the GitHub GraphQL API at build time, resolves live GitHub Pages links through the REST API, and renders them in a terminal-themed UI. +Astro portfolio with a static export for GitHub Pages. It fetches the repositories pinned on Jonathan's GitHub profile plus owned public, non-fork repositories from the GitHub GraphQL API at build time, resolves live GitHub Pages links through the REST API, and renders them in a terminal-themed UI. -The site includes a print-optimized resume page, SEO metadata, analytics, and a Konami code easter egg. The same shared data powers the on-page resume and the dedicated `/resume` route. - -It is built to stay simple to deploy: build locally, export statically, and publish through GitHub Actions. +The site includes a print-optimized `/resume` route, SEO metadata, JSON-LD, GA4 analytics, a PWA manifest, and a Konami-code terminal easter egg. Profile, skills, education, availability, social links, and experience data live in `src/lib/data.ts` and power both the portfolio and resume. ## Tech Stack -| Technology | Version | Purpose | -|-----------|---------|---------| -| Astro | 6 | Static site build and GitHub Pages export | -| React | 19 | Interactive portfolio UI | -| TypeScript | Latest | Type safety | -| Tailwind CSS | v4 | Styling system | -| GitHub GraphQL + REST APIs | v4 / REST | Fetches repositories and live Pages URLs at build time | -| Google Analytics 4 | GA4 | Traffic and engagement analytics | +| Technology | Version / source | Purpose | +|-----------|------------------|---------| +| Astro | `^6` | Static site build and GitHub Pages export | +| React | `^19` | Interactive portfolio UI (`client:load`) | +| TypeScript | `^6` with `astro/tsconfigs/strict` | Type safety | +| Tailwind CSS | `^4` via `@tailwindcss/vite` | Styling system | +| GitHub GraphQL + REST APIs | GraphQL + REST `2022-11-28` | Fetches repositories and live Pages URLs at build time | +| Google Analytics 4 | `PUBLIC_GA_ID` | Traffic and engagement analytics | +| Bun | Workflow/local package manager | Install, lint, and build commands | ## Features - Workbench major cards sourced from GitHub profile pinned repositories -- Dynamic "Other GitHub repos" ledger from GitHub GraphQL API (public, non-fork repos) +- Dynamic "Other GitHub repos" ledger from GitHub GraphQL API (owned public, non-fork repos) - Live GitHub Pages links resolved at build time via GitHub REST API -- Terminal-themed dark UI with typing animations and scroll effects -- Print-optimized resume page with download support -- PWA manifest and SEO optimizations -- Konami code easter egg -- Static export deployed to GitHub Pages +- Terminal-themed dark UI with scroll/reveal effects and responsive project cards +- Print-optimized `/resume` route with browser PDF download support +- PWA manifest, sitemap, robots.txt, Open Graph, Twitter, and JSON-LD metadata +- Google Analytics 4 loaded only when `PUBLIC_GA_ID` is set +- Konami-code terminal easter egg +- Static export deployed to GitHub Pages from `out/` ## Getting Started ### Prerequisites -- Node.js 22+, Bun +- Node.js 22+ +- Bun +- Optional: GitHub CLI (`gh`) for providing a local `GITHUB_TOKEN` ### Quick Start @@ -53,15 +55,21 @@ bun install bun run dev ``` -Open http://localhost:4321 +Open . + +To build with live repository data instead of fallback data: + +```bash +GITHUB_TOKEN=$(gh auth token) bun run build +``` ## CI/CD | Workflow | Trigger | Purpose | |----------|---------|---------| -| `build-check.yml` | Pull requests to main | Lint + build check | -| `main-release.yml` | Push to main / manual | Build and deploy to GitHub Pages | -| `codeql.yml` | Push, PRs, weekly schedule | JavaScript/TypeScript security analysis | +| `build-check.yml` | Pull requests to `main`, manual dispatch | Bun install, `astro check`, and Astro build | +| `main-release.yml` | Push to `main`, manual dispatch | Build `out/`, upload Pages artifact, deploy GitHub Pages | +| `codeql.yml` | Push, PRs, weekly Monday 06:00 UTC | JavaScript/TypeScript security analysis | Dependabot monitors npm and GitHub Actions dependencies weekly. diff --git a/wiki/architecture.md b/wiki/architecture.md index fca24cc..da662a5 100644 --- a/wiki/architecture.md +++ b/wiki/architecture.md @@ -2,43 +2,52 @@ ## Overview -The site is a **Next.js 16** static export deployed to **GitHub Pages**. It uses a Server Component / Client Component split to fetch data at build time while keeping all interactive UI client-side. +The site is an **Astro 6** static export deployed to **GitHub Pages**. Astro performs build-time data fetching in `src/pages/index.astro`, renders static HTML into `out/`, and hydrates the React portfolio UI with `client:load` for browser-only interactivity. + +There is no Next.js App Router or React Server Component layer in the current codebase. ## Component Architecture -``` -app/ -├── page.tsx # Server Component — fetches pinned repos -├── portfolio.tsx # Client Component — full interactive UI -├── resume/ -│ ├── page.tsx # Client Component — print-optimized resume -│ └── layout.tsx # Server Component — resume metadata -├── lib/ -│ ├── data.ts # Shared data (single source of truth) -│ └── github.ts # GitHub GraphQL API client +```text +src/ +├── pages/ +│ ├── index.astro # Build-time repo fetch, renders +│ └── resume.astro # Static resume route with print CSS +├── layouts/ +│ └── RootLayout.astro # Shared document shell, metadata, fonts, analytics, JSON-LD ├── components/ -│ ├── analytics.tsx # Google Analytics 4 -│ └── json-ld.tsx # Schema.org structured data -├── layout.tsx # Root layout, metadata, fonts, SEO -└── globals.css # Theme, animations, styles +│ ├── Portfolio.tsx # React interactive island: home UI, Workbench, terminal easter egg +│ ├── Analytics.astro # Emits GA4 scripts only when PUBLIC_GA_ID exists +│ └── JsonLd.astro # Schema.org Person JSON-LD from shared data +├── lib/ +│ ├── data.ts # Shared profile/resume/social data +│ └── github.ts # GitHub GraphQL + REST build-time data client +└── styles/ + └── globals.css # Tailwind v4 and custom design system ``` ## Data Flow -``` -Build Time: - page.tsx (Server) → github.ts → GitHub GraphQL API - → fetches pinned repos - → passes to portfolio.tsx as props - -Runtime (Static HTML): - portfolio.tsx (Client) → renders UI with baked-in data - → typing animation, scroll effects, terminal +```text +Build time: + src/pages/index.astro + -> fetchRepos() from src/lib/github.ts + -> GitHub GraphQL: profile pinned repositories + owned public non-fork repositories + -> GitHub REST: /repos/jonathanperis/{repo}/pages for live Pages URLs + -> fallback repository data when no token or API failure occurs + -> + +Runtime (static HTML + hydrated React): + Portfolio.tsx + -> renders baked-in project data + -> manages scroll progress, reveal state, terminal state, command history, and CTA analytics events ``` ## Key Design Decisions -- **Server/Client split** — Data fetching happens at build time (Server Component), UI interactions are client-side -- **Single source of truth** — `lib/data.ts` contains all profile data shared between portfolio and resume -- **Static export** — `output: "export"` in next.config.ts generates pure static HTML for GitHub Pages -- **Graceful fallback** — If `GITHUB_TOKEN` is missing, hardcoded project data is used +- **Astro static export** — `astro.config.ts` sets `outDir: 'out'`; GitHub Pages serves the generated static artifact. +- **Interactive island boundary** — `Portfolio.tsx` is hydrated with `client:load`; SEO-critical metadata and document shell remain Astro-rendered. +- **Single source of truth** — `src/lib/data.ts` contains profile, skills, education, experience, socials, and availability data shared by the portfolio, resume, and JSON-LD. +- **Dynamic-but-build-time projects** — `src/lib/github.ts` fetches GitHub data during `bun run build`; no GitHub API calls happen from the deployed browser page. +- **Graceful fallback** — If `GITHUB_TOKEN` is missing or GitHub APIs fail, hardcoded fallback project data keeps local builds and PR checks deterministic. +- **Analytics opt-in by environment** — GA4 scripts are emitted only when `PUBLIC_GA_ID` is present. diff --git a/wiki/deployment.md b/wiki/deployment.md index d5c1c59..737f1ca 100644 --- a/wiki/deployment.md +++ b/wiki/deployment.md @@ -2,55 +2,54 @@ ## GitHub Actions -The site deploys automatically via `.github/workflows/deploy.yml` on every push to `master`. +The site deploys automatically through `.github/workflows/main-release.yml` on every push to `main` and can also be run manually with `workflow_dispatch`. ### Pipeline Steps -1. **Checkout** — Clone the repository -2. **Setup Node** — Node.js 20 with npm cache -3. **Setup Pages** — Configure GitHub Pages -4. **Install** — `npm ci` -5. **Build** — `npm run build` with environment variables: +1. **Checkout** — Clone the repository (`actions/checkout@v6`) +2. **Setup Node** — Node.js 22 (`actions/setup-node@v6`) +3. **Setup Bun** — Bun latest (`oven-sh/setup-bun@v2`) +4. **Configure Pages** — `actions/configure-pages@v6` +5. **Install** — `bun install` +6. **Build** — `bun run build` with environment variables: - `GITHUB_TOKEN` — Fetches public repositories and Pages URLs (auto-provided by GitHub Actions) - - `NEXT_PUBLIC_GA_ID` — Google Analytics measurement ID -6. **Upload** — Uploads `out/` directory as Pages artifact -7. **Deploy** — Deploys to GitHub Pages + - `PUBLIC_GA_ID` — Google Analytics measurement ID (`G-35CN95481D`) +7. **Upload** — Uploads `out/` as the Pages artifact (`actions/upload-pages-artifact@v5`) +8. **Deploy** — Deploys to GitHub Pages (`actions/deploy-pages@v5`) ### Environment Variables | Variable | Source | Purpose | |---|---|---| -| `GITHUB_TOKEN` | `secrets.GITHUB_TOKEN` (auto) | GitHub GraphQL and REST APIs for public repo + Pages data | -| `NEXT_PUBLIC_GA_ID` | Hardcoded in workflow | GA4 measurement ID | +| `GITHUB_TOKEN` | `secrets.GITHUB_TOKEN` / Actions token | GitHub GraphQL and REST APIs for public repo + Pages data | +| `PUBLIC_GA_ID` | Workflow env | GA4 measurement ID consumed by `src/components/Analytics.astro` | ## Static Export -Next.js is configured with `output: "export"` which generates pure static HTML/CSS/JS in the `out/` directory. No server required. +Astro builds the site into the `out/` directory configured in `astro.config.ts`. The deployed artifact is pure static HTML/CSS/JS plus files from `public/`; no server runtime is required on GitHub Pages. -## Cache Headers +## CI Workflows -`next.config.ts` defines aggressive caching for static assets: +| Workflow | Trigger | What it does | +|---|---|---| +| `build-check.yml` | Pull requests to `main`, manual dispatch | `bun install`, `bun run lint`, `bun run build` | +| `main-release.yml` | Pushes to `main`, manual dispatch | Builds and deploys the Pages artifact | +| `codeql.yml` | Pushes, PRs, weekly Monday 06:00 UTC | Runs CodeQL JavaScript/TypeScript analysis | -```typescript -headers: async () => [ - { - source: "/:all*(svg|jpg|jpeg|png|gif|ico|webp|woff|woff2)", - headers: [ - { key: "Cache-Control", value: "public, max-age=31536000, immutable" }, - ], - }, -] -``` +## Manual Local Build -## Manual Deploy +```bash +GITHUB_TOKEN=$(gh auth token) PUBLIC_GA_ID=G-35CN95481D bun run build +``` -To deploy manually: +Then preview the generated artifact locally: ```bash -GITHUB_TOKEN=$(gh auth token) NEXT_PUBLIC_GA_ID=G-GFK73008MT npm run build -# Then push the out/ directory to GitHub Pages +bun run preview ``` +Publishing is handled by GitHub Actions; do not commit `out/`. + ## Domain The site is served at `https://jonathanperis.github.io` via GitHub Pages with automatic HTTPS. diff --git a/wiki/easter_egg.md b/wiki/easter_egg.md index d4cac9a..e81e312 100644 --- a/wiki/easter_egg.md +++ b/wiki/easter_egg.md @@ -6,53 +6,52 @@ The site includes a hidden interactive terminal triggered by the **Konami code** ### How to Activate -Press these keys in sequence anywhere on the page: +Press these keys in sequence anywhere on the page while the terminal is closed: -``` +```text ↑ ↑ ↓ ↓ ← → ← → B A ``` ### Terminal Features -- macOS-style window with traffic light buttons -- Command history (arrow up/down) -- Ctrl+L to clear -- Escape or red button to close -- Click outside to dismiss +- In-page modal terminal with focus restoration when closed +- Command history with arrow up/down +- Tab focuses the close button +- Ctrl+L or `clear` clears the terminal +- Escape, `exit`, `quit`, or the close button closes the terminal +- Auto-scrolls to the newest terminal output ### Available Commands | Command | Description | |---|---| -| `help` | List all commands | -| `about` | Bio and Seu Madruga quote | -| `skills` | Tech stack overview | -| `contact` | Social links and email | -| `neofetch` | ASCII art "JP" logo with system info | -| `git log` | Career history as commits | -| `ls` | List sections | -| `cat about.txt` | Read about section | -| `whoami` | Current user info | -| `pwd` | Current directory | -| `date` | Current date/time | -| `sudo hire me` | Fake auth flow | -| `rm -rf /` | Plot armor response | -| `cat .easter-egg` | Hidden file | -| `echo ` | Echo text back | -| `clear` | Clear terminal | -| `exit` | Close terminal | +| `help` | Lists supported commands | +| `about` | Short Jonathan Peris profile summary | +| `stack` | Backend, architecture, delivery, and data stack overview | +| `contact` | GitHub, LinkedIn, and email | +| `neofetch` | ASCII "JP" logo with Astro/React/TypeScript runtime info | +| `git log` | Most recent career roles rendered as commit-style rows | +| `ls` | Lists faux terminal files/directories | +| `cat availability.txt` | Prints current availability text from `AVAILABILITY.full` | +| `whoami` | Current user/profile summary | +| `pwd` | Faux current directory | +| `date` | Current browser date/time | +| `sudo hire me` | Fake recruiter-auth flow | +| `echo ` | Echoes text back | +| `clear` | Clears terminal output | +| `exit` / `quit` | Closes the terminal | ### Hint The footer contains a subtle hint: -``` +```text // ↑↑↓↓←→←→BA ``` ### Implementation -- Konami code listener in a `useEffect` hook -- Tracks last 10 keystrokes and matches against the sequence -- Terminal state managed with `useState` (history, input, command history) -- `handleTerminalCommand()` function maps commands to responses +- Konami listener lives in `src/components/Portfolio.tsx` inside a `useEffect` hook. +- The listener tracks the last 10 keystrokes and compares them with the target sequence. +- Terminal state is managed with React state (`termOpen`, `termInput`, `termHist`, `cmdHist`, `histIdx`). +- `runCmd()` maps commands to responses and uses `EXPERIENCES`, `AVAILABILITY`, and hardcoded terminal strings. diff --git a/wiki/getting_started.md b/wiki/getting_started.md index 2fd9b02..8bdc0ed 100644 --- a/wiki/getting_started.md +++ b/wiki/getting_started.md @@ -2,16 +2,16 @@ ## Prerequisites -- [Node.js](https://nodejs.org/) v20 or later -- [npm](https://www.npmjs.com/) -- [GitHub CLI](https://cli.github.com/) (`gh`) — for local development with dynamic projects +- [Node.js](https://nodejs.org/) v22 or later (the GitHub Actions workflows use Node 22) +- [Bun](https://bun.sh/) for dependency installation and scripts +- Optional: [GitHub CLI](https://cli.github.com/) (`gh`) to provide a local `GITHUB_TOKEN` when testing dynamic project fetching ## Installation ```bash git clone https://github.com/jonathanperis/jonathanperis.github.io.git cd jonathanperis.github.io -npm install +bun install ``` ## Development @@ -19,40 +19,52 @@ npm install ### Without dynamic projects (fallback data) ```bash -npm run dev +bun run dev ``` ### With dynamic projects (live GitHub data) ```bash -GITHUB_TOKEN=$(gh auth token) npm run dev +GITHUB_TOKEN=$(gh auth token) bun run dev ``` -Open [http://localhost:3000](http://localhost:3000). +Open [http://localhost:4321](http://localhost:4321). ## Build ```bash -npm run build +bun run build ``` -Produces a static export in the `out/` directory. +Produces a static Astro export in the `out/` directory. -### With dynamic projects +### With dynamic projects and analytics ```bash -GITHUB_TOKEN=$(gh auth token) npm run build +GITHUB_TOKEN=$(gh auth token) PUBLIC_GA_ID=G-35CN95481D bun run build ``` -## Lint +`GITHUB_TOKEN` enables live GitHub GraphQL/REST data. `PUBLIC_GA_ID` controls whether GA4 tags are emitted into the built HTML. + +## Lint / Type Check ```bash -npm run lint +bun run lint ``` +The `lint` script runs `astro check` using `@astrojs/check` and TypeScript strict settings. + +## Preview + +```bash +bun run preview +``` + +Astro previews the already-built `out/` output locally. + ## Environment Variables | Variable | Required | Purpose | |---|---|---| -| `GITHUB_TOKEN` | No (has fallback) | Fetches pinned repos via GraphQL at build time | -| `NEXT_PUBLIC_GA_ID` | No | Google Analytics 4 measurement ID | +| `GITHUB_TOKEN` | No (fallback data is used when absent) | Fetches pinned repositories through GitHub GraphQL and resolves Pages URLs through the REST API at build time | +| `PUBLIC_GA_ID` | No | Google Analytics 4 measurement ID used by `src/components/Analytics.astro` | diff --git a/wiki/index.md b/wiki/index.md index 2c30c11..7c858ee 100644 --- a/wiki/index.md +++ b/wiki/index.md @@ -1,18 +1,27 @@ -# jonathanperis.github.io +# jonathanperis.github.io Wiki -Personal developer portfolio for **Jonathan Peris** — Software Engineer with 12+ years of experience in .NET and Fintech. +Personal developer portfolio for **Jonathan Peris** — Software Engineer with 12+ years of experience in .NET, Azure, backend architecture, and reliable delivery. **Live site:** [jonathanperis.github.io](https://jonathanperis.github.io) +## Current Implementation Snapshot + +- **Framework:** Astro 6 static site with React 19 interactive islands. +- **Package manager:** Bun for install, lint, dev, build, and preview. +- **Source tree:** `src/pages`, `src/components`, `src/layouts`, `src/lib`, and `src/styles`. +- **Build output:** `out/`, uploaded as a GitHub Pages artifact by `main-release.yml`. +- **Data source:** `src/lib/data.ts` for profile/resume data; `src/lib/github.ts` for GitHub repository discovery. +- **Production URL:** `https://jonathanperis.github.io/`. + ## Features -- Developer-themed dark UI with terminal aesthetic -- Typing role animation, scroll animations, progress bar +- Developer-themed dark UI with terminal/system-console aesthetic +- Scroll progress bar and reveal animations - Dynamic Workbench pinned-repo cards and "Other GitHub repos" ledger fetched at build time via GitHub GraphQL + Pages REST APIs - Print-optimized resume page generated from shared data (`/resume`) -- Interactive terminal easter egg (Konami code) -- SEO optimized: JSON-LD, sitemap, robots.txt, Open Graph, Twitter cards -- Google Analytics 4 integration +- Interactive terminal easter egg triggered by Konami code +- SEO optimized: JSON-LD, sitemap, robots.txt, Open Graph, Twitter cards, canonical URLs, and alternate language link +- Google Analytics 4 integration through `PUBLIC_GA_ID` - PWA-ready with manifest and icons ## Wiki Pages diff --git a/wiki/project_structure.md b/wiki/project_structure.md index 9aff4f6..065ad0f 100644 --- a/wiki/project_structure.md +++ b/wiki/project_structure.md @@ -1,40 +1,46 @@ # Project Structure -``` +```text jonathanperis.github.io/ -├── app/ -│ ├── page.tsx # Server Component — fetches pinned repos, renders Portfolio -│ ├── portfolio.tsx # Client Component — main UI (hero, about, experience, projects) -│ ├── layout.tsx # Root layout: metadata, fonts, SEO, analytics, JSON-LD -│ ├── globals.css # Theme colors, animations, card/tag/timeline styles -│ ├── resume/ -│ │ ├── page.tsx # Print-optimized resume (shared data from lib/data.ts) -│ │ └── layout.tsx # Resume page metadata +├── src/ +│ ├── pages/ +│ │ ├── index.astro # Home page: fetches repos, renders Portfolio with client:load +│ │ └── resume.astro # Print-optimized resume route +│ ├── components/ +│ │ ├── Portfolio.tsx # Main interactive UI, Workbench, terminal easter egg +│ │ ├── Analytics.astro # GA4 conditional loader (reads PUBLIC_GA_ID) +│ │ └── JsonLd.astro # Schema.org Person structured data +│ ├── layouts/ +│ │ └── RootLayout.astro # HTML shell, metadata, fonts, JSON-LD, analytics slot │ ├── lib/ -│ │ ├── data.ts # Single source of truth: profile, experiences, skills, education -│ │ └── github.ts # GitHub GraphQL client: fetches pinned repos at build time -│ └── components/ -│ ├── analytics.tsx # GA4 conditional loader (reads NEXT_PUBLIC_GA_ID) -│ └── json-ld.tsx # Schema.org Person structured data +│ │ ├── data.ts # Single source of truth: profile, availability, experience, skills, socials +│ │ └── github.ts # GitHub GraphQL + REST client with fallback repo data +│ └── styles/ +│ └── globals.css # Tailwind import, theme tokens, animations, layout styles ├── public/ -│ ├── sitemap.xml # Sitemap for search engines -│ ├── robots.txt # Crawler directives -│ ├── manifest.json # PWA manifest -│ ├── favicon.svg # SVG favicon (JP monogram) -│ └── apple-touch-icon.png # iOS icon +│ ├── cv_jonathan_peris.pdf # Downloadable CV asset +│ ├── manifest.json # PWA manifest +│ ├── robots.txt / sitemap.xml # SEO crawler files +│ ├── favicon.svg # SVG favicon +│ └── apple-touch-icon.png # iOS icon +├── wiki/ # Repository wiki Markdown source ├── .github/workflows/ -│ └── deploy.yml # GitHub Actions: build → GitHub Pages -├── next.config.ts # Static export, cache headers -├── tsconfig.json -└── package.json +│ ├── build-check.yml # PR build check: bun install + lint + build +│ ├── main-release.yml # GitHub Pages deploy on push to main +│ └── codeql.yml # JavaScript/TypeScript security analysis +├── astro.config.ts # Astro site URL, outDir, React/sitemap/Tailwind integrations +├── tsconfig.json # Astro strict TS config and @/* alias +├── package.json # Bun scripts and dependencies +└── bun.lock # Bun lockfile ``` ## Key Files | File | Role | |---|---| -| `lib/data.ts` | All profile data — experiences, skills, education, socials. Shared by portfolio and resume. | -| `lib/github.ts` | Fetches pinned repos via GitHub GraphQL API. Falls back to hardcoded data if no token. | -| `portfolio.tsx` | The entire interactive UI — hero, typing animation, about, experience timeline, project cards, terminal easter egg. | -| `resume/page.tsx` | Print-optimized resume. "Download PDF" button triggers browser print dialog. | -| `globals.css` | Custom theme tokens, dot grid, scroll progress, cursor blink, git timeline, glass cards, terminal overlay. | +| `src/lib/data.ts` | All profile data — availability, operating signals, engineering principles, experiences, skills, education, socials, and legacy featured-project records. Shared by portfolio, resume, and JSON-LD. | +| GitHub data client (`src/lib/`) | Fetches profile pinned repositories and owned public non-fork repositories, excludes metadata repos, resolves GitHub Pages URLs, and falls back to hardcoded data when no token is available. | +| `src/components/Portfolio.tsx` | Interactive home UI — hero, profile packet, capability map, experience trace, Workbench project cards, social/contact surface, and terminal easter egg. | +| `src/pages/resume.astro` | Print-optimized resume page. The "Download PDF" button triggers the browser print dialog. | +| `src/layouts/RootLayout.astro` | Shared page shell with canonical links, Open Graph/Twitter tags, fonts, JSON-LD, manifest, icons, and analytics. | +| `src/styles/globals.css` | Tailwind v4 import plus custom dark theme tokens, grid/scanline effects, cards, timeline, resume print styles, and terminal overlay styles. | diff --git a/wiki/resume_page.md b/wiki/resume_page.md index 5275a4d..2d110ea 100644 --- a/wiki/resume_page.md +++ b/wiki/resume_page.md @@ -2,39 +2,41 @@ ## Overview -The `/resume` route renders a **print-optimized resume** from the same data that powers the portfolio. No static PDF needed — the resume is always up to date. +The `/resume` route renders a **print-optimized resume** from the same data that powers the portfolio. No generated PDF needs to be kept in sync; the page can be printed or saved to PDF from the browser. ## How It Works -- `resume/page.tsx` imports from `lib/data.ts` (the single source of truth) -- Renders: Header, Summary, Technical Skills, Experience (all 10 roles), Education -- "Download PDF" button calls `window.print()` — the browser's print dialog saves as PDF +- `src/pages/resume.astro` imports `PROFILE`, `SKILLS`, `EDUCATION`, and `EXPERIENCES` from `src/lib/data.ts`. +- The page is wrapped in `RootLayout` with resume-specific title, description, and canonical path (`/resume`). +- It renders header, summary, technical skills, all experience entries, and education. +- The "Download PDF" button calls `window.print()` so the browser print dialog can save as PDF. ## Sections | Section | Data Source | |---|---| -| Header | `PROFILE.name`, `PROFILE.email`, `PROFILE.location`, etc. | +| Header | `PROFILE.name`, `PROFILE.email`, `PROFILE.location`, `PROFILE.linkedin`, `PROFILE.github`, `PROFILE.website` | | Summary | `PROFILE.summary` | | Technical Skills | `SKILLS` (languages, backend, architecture, cloud, databases, frontend) | -| Experience | `EXPERIENCES[]` (10 entries with title, company, location, description, tags) | -| Education | `EDUCATION` (BTech from UNIESP) | +| Experience | `EXPERIENCES[]` from `src/lib/data.ts` | +| Education | `EDUCATION` | ## Print Styling The page has dual styles: -- **Screen**: Dark theme matching the portfolio -- **Print**: White background, black text, proper margins, `break-inside-avoid` on experience entries + +- **Screen:** Dark theme matching the portfolio. +- **Print:** White background, black text, compact A4 margins, and `print:break-inside-avoid` on experience entries. ```css @media print { - body { background: white; color: black; } - .resume-page { padding: 0.4in 0.5in; } + body { background: white !important; color: black !important; } + .resume-page { padding: 0.4in 0.5in !important; } @page { size: A4; margin: 0; } } ``` ## Navigation -- The "resume" button in the portfolio navbar links to `/resume` -- The resume page has a "Back to portfolio" link +- The portfolio navbar and hero CTA link to `/resume`. +- The resume page has a "Back to portfolio" link to `/`. diff --git a/wiki/seo_and_analytics.md b/wiki/seo_and_analytics.md index 82e25ca..a1097c2 100644 --- a/wiki/seo_and_analytics.md +++ b/wiki/seo_and_analytics.md @@ -2,41 +2,46 @@ ## Structured Data (JSON-LD) -`components/json-ld.tsx` generates Schema.org `Person` markup: +`src/components/JsonLd.astro` generates Schema.org `Person` markup from `src/lib/data.ts`: -- Name, job title, employer (Derivative Path) -- Social links (GitHub, LinkedIn, X, Instagram, Bluesky) -- Skills (`knowsAbout`) — 23 technologies across 6 categories -- Education (`alumniOf`) — UNIESP -- Email, location - -This helps Google display rich knowledge panels. +- Name, job title, and current employer (Derivative Path) +- Social links (`SOCIALS`) including GitHub, LinkedIn, X, Instagram, Bluesky, and Workana +- Skills (`knowsAbout`) from the six `SKILLS` categories +- Education (`alumniOf`) from `EDUCATION` +- Email and location ## Meta Tags -Configured in `layout.tsx`: +Configured in `src/layouts/RootLayout.astro`: -| Tag | Value | +| Tag | Current value / source | |---|---| -| `metadataBase` | `https://jonathanperis.github.io` | -| `canonical` | `/` | -| `keywords` | 12 relevant terms | -| `og:title` | Jonathan Peris — Software Engineer | -| `og:image` | profile-image-sharing.jpeg | -| `twitter:card` | summary_large_image | -| `twitter:creator` | @jperis_silva | -| `theme-color` | #09090b | -| `hreflang` | en | +| Canonical base | `https://jonathanperis.github.io` plus the page `canonical` prop | +| Default canonical path | `/` | +| Default title | `Jonathan Peris — Software Engineer` | +| Default description | Software Engineer specializing in .NET and Fintech, 12+ years, enterprise/cloud-native systems | +| Keywords | Jonathan Peris, Software Engineer, .NET, C#, Fintech, Azure, Microservices, CQRS, DDD, Clean Architecture, Backend Developer, Cloud-Native | +| Open Graph image | `https://jonathanperis.github.io/profile-image-sharing.jpeg` | +| Open Graph image size | `460x844` | +| Twitter card | `summary_large_image` | +| Twitter creator | `@jperis_silva` | +| Theme color | `#0a0a0f` | +| Alternate language | `hreflang="en"` | + +The `/resume` route overrides title, description, and canonical path in `src/pages/resume.astro`. ## Sitemap -`public/sitemap.xml` includes: +`public/sitemap.xml` currently includes: + - `/` (priority 1.0, weekly) - `/resume` (priority 0.8, monthly) +Astro also has the `@astrojs/sitemap` integration enabled in `astro.config.ts`. + ## robots.txt -``` +```txt User-agent: * Allow: / Sitemap: https://jonathanperis.github.io/sitemap.xml @@ -44,14 +49,21 @@ Sitemap: https://jonathanperis.github.io/sitemap.xml ## Google Analytics 4 -`components/analytics.tsx` loads GA4 conditionally: -- Only activates when `NEXT_PUBLIC_GA_ID` env var is set -- Measurement ID: `G-GFK73008MT` -- Loaded with `afterInteractive` strategy (non-blocking) +`src/components/Analytics.astro` loads GA4 conditionally: + +- Activates only when `PUBLIC_GA_ID` is set. +- The production workflow passes `PUBLIC_GA_ID=G-35CN95481D`. +- Emits the standard async `https://www.googletagmanager.com/gtag/js?id=...` loader and inline `gtag('config', GA_ID)` initialization. +- `Portfolio.tsx` calls `trackEvent('cta_click', ...)` for resume and LinkedIn CTAs; events are sent only when `window.gtag` exists. ## PWA Manifest -`public/manifest.json` with: -- App name, short name (JP) -- Theme color (#4ade80), background (#09090b) -- SVG favicon + apple-touch-icon +`public/manifest.json` includes: + +- App name: `Jonathan Peris — Software Engineer` +- Short name: `JP` +- `start_url`: `/` +- `display`: `standalone` +- Theme color: `#4ade80` +- Background color: `#09090b` +- SVG favicon and Apple touch icon entries