Update portfolio: GitHub projects, localized SEO, cleanup, a11y + CI#2
Merged
Conversation
Surface Santiago's public GitHub repositories on the Work page as a new "Open work on GitHub" section below the featured Directa case study. Four verified public projects are added to a `projects` array in the single source of truth (site.ts), with EN/ES copy derived from each repo's own description — no invented content. Each renders as a neo-brutalist card (language swatch, topic tags, WIP badge, "View on GitHub" link), and the GitHub profile is wired into the footer, the contact panel and the Person JSON-LD `sameAs`. Private repositories are intentionally excluded. While here, fix two pre-existing SEO defects surfaced by an audit: - Canonical, hreflang alternates and sitemap.xml were built from internal route paths, so every Spanish sub-page pointed at /es/work, /es/about… which 404 (the real paths are /es/trabajo, /es/sobre-mi…). Both now derive each locale's real public URL via next-intl getPathname and add an x-default alternate. - Person JSON-LD emitted an unverified (pending) role as jobTitle, i.e. a hard claim with no "pending" badge; it is now omitted until confirmed. Also localize two hardcoded Directa strings (the "Gallery" heading and the case-study meta title) that shipped in English on the Spanish site. Verified: typecheck, lint and build pass; a production server confirms the projects render in both locales, sitemap emits localized URLs, and /es/trabajo returns 200 with correct canonical/hreflang/x-default. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HGqP6dAJYGsYKiX4TnR5Dh
The site was redesigned from an editorial light/dark theme (Instrument Serif, next-themes, a react-three-fiber WebGL hero) to a light-only neo-brutalist look with a DOM CardStack hero. That left dead weight behind. This removes it and fixes the low-risk accessibility issues an audit surfaced. Dead code / dependencies (verified unused by grep; build still passes without them, which proves it): - Drop unused deps: three, @react-three/fiber, @react-three/drei, @types/three, framer-motion; remove the framer-motion optimizePackageImports entry from next.config.mjs; prune the lockfile. - Delete src/components/three/SignatureCanvas.tsx (a null stub with no importers) and the empty three/ dir. - Remove the never-read `visual` (enableSignatureField / preferWebGPU) block from site.ts. - Remove dead i18n keys from both locales: meta.ogAlt, home.heroEyebrow, common.theme/themeLight/themeDark/themeSystem/scrollHint/backHome, footer.colophonHeading/colophonBody. (Kept the hero* keys CardStack uses.) Docs drift: rewrite/trim README, DESIGN_SYSTEM, CLAUDE.md and CONTENT_GUIDE so they describe the shipped light-only neo-brutalist system (no dark mode, no Three.js, CalmToggle not ThemeToggle) and the real remaining pending items (WhatsApp/calendar/CV are done; GitHub projects added). Accessibility: - ContactPanel takes an `asPageHeading` prop so the /contact route renders a real <h1> (it had none — only an <h2>); the home page keeps it an <h2>. - :focus-visible gets a cream halo so the focus ring stays visible on royal/ink dark surfaces where the royal accent outline vanished. - CalmToggle gains an aria-label (its visible label is hidden below sm). - LocaleSwitcher's aria-label is localized via common.language. - Header logo link gets a stable aria-label. - Bump the CardStack 'BASE' sub-label contrast to full on-accent (was ~4.3:1). Verified: pnpm install, typecheck, lint and build all pass; a production server confirms /contact and /contacto each have exactly one <h1>, the home page keeps one, the locale switcher aria-label localizes, and the focus ring is visible on the royal contact panel. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HGqP6dAJYGsYKiX4TnR5Dh
Section titles were rendered as styled "chip" <div>s and some per-item titles skipped a heading level (h1 -> h3 with no h2; capability groups as h4), so screen-reader/SEO document outlines were broken. Convert section-title chips to <h2> and demote/promote sub-item titles to <h3>, keeping page-eyebrow chips (the ones directly above a page's <h1>) as decorative <div>s. Tailwind's preflight strips default heading styles, so the tag swaps are visually identical — the chips render exactly as before. Files: IntroBlock, WorkPreview, ServicesGrid, CapabilitiesGrid (home sections), work/page (featured card name), about/page (On Directa / Experience / Education chips + role/degree items), work/directa/page (Block label + Features + Gallery). services/page and the contact route were already correct and are untouched. Favicon: replace the leftover old-design dark-serif "Sr" (icon.tsx) with the neo-brutalist "SR" lockup — cream on ink — matching the header logo and the OG card. The OpenGraph image was already neo-brutalist; only the stale MEDIA_PROMPTS note claiming otherwise is corrected, and its brand-kit blue is aligned to the real royal token (#2746D0). Verified: typecheck, lint and build pass; a production server confirms every route (/en, /es, /en/work, /es/trabajo, /en/work/directa, /en/about, /en/services, /en/contact) has exactly one <h1> and no skipped heading levels, the section chips look unchanged, and /icon renders the new favicon. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HGqP6dAJYGsYKiX4TnR5Dh
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Add .github/workflows/ci.yml so pull requests to main and pushes to main run the documented CI gate — pnpm typecheck && lint && build — plus a Playwright e2e job. This gives branch protection a required status check to gate merges into main (the branch Vercel deploys to production); until now the gate only ran locally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HGqP6dAJYGsYKiX4TnR5Dh
The Playwright config runs two projects — Desktop Chrome (chromium) and iPhone 13 (webkit). CI only installed chromium, so the mobile project failed with "Executable doesn't exist ... webkit". Install both engines. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HGqP6dAJYGsYKiX4TnR5Dh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Several focused passes over the portfolio, plus a CI workflow so
main(the branch Vercel deploys to production) can be protected with a required status check.Changes
1. Public GitHub projects on /work + localized SEO fix —
4ad126bsite.ts → projects; private repos excluded.sameAs.sitemap.xmlwere built from internal route paths, so every Spanish sub-page pointed at/es/work,/es/about… which 404 (real paths are/es/trabajo,/es/sobre-mi…). Both now derive each locale's real URL via next-intlgetPathname, plus anx-default. JSON-LD no longer emits the still-pending role as a hardjobTitle.2. Prune post-redesign dead code/deps + targeted a11y —
8cb3930three,@react-three/*,@types/three,framer-motion) and the deadSignatureCanvasstub /visualconfig / dead i18n keys.<h1>on/contact; focus ring visible on royal/ink surfaces;aria-labels on the motion toggle, locale switcher and logo; bump the CardStack 'BASE' label contrast to AA.3. Correct heading outline across pages + favicon —
9aaef20<h2>and skipped sub-item levels →<h3>so every route has one<h1>and no skipped levels (Tailwind preflight keeps the chips visually identical).4. CI —
10480ec.github/workflows/ci.yml: achecksjob (pnpm typecheck && lint && build) and a Playwrighte2ejob, on PRs tomainand pushes tomain.Verification
pnpm typecheck && pnpm lint && pnpm buildpass locally; CI runs on this PR.sitemap.xmlemits localized URLs,/es/trabajoreturns 200 with correct canonical/hreflang, every route has a valid heading outline, and the new favicon renders.Follow-up (not in this PR — needs the repo owner)
main(require thechecksstatus check, block force-push/deletion) in Settings → Branches.🤖 Generated with Claude Code