Skip to content

chrisnltr/portfolio

Repository files navigation

Portfolio – Chris Leon Noltemeier

A minimal, bilingual (DE/EN) Nuxt 3 portfolio with locale-based routing, SEO, and accessibility optimizations.

Setup & Development

  • Node: Use Node 22.x (see engines in package.json).
  • Install: npm install
  • Dev: npm run dev — runs the app at http://localhost:3000. Visiting / redirects to /de or /en based on your preferred locale.
  • Build: npm run build
  • Preview: npm run preview — serves the production build locally.

Environment Variables

Configure these in .env (or in your host’s dashboard, e.g. Vercel).

Variable Description
NUXT_PUBLIC_SITE_URL Full public URL of the site (e.g. https://chrisnoltemeier.dev). Used for sitemap, robots.txt, and canonical/OG URLs when the request host is not reliable (e.g. serverless). Optional; falls back to request host.

Contact form:

  • RESEND_API_KEY — API key for Resend (or use another provider supported by the API route).
  • CONTACT_TO_EMAIL — Address where contact form submissions are sent.
  • CONTACT_FROM_EMAIL — Sender address used by the mail provider.
  • Optional: FORMSPREE_ENDPOINT — If set, form submissions are proxied to Formspree instead of sending mail directly (useful if no mail provider is configured).

CV – Updating PDFs

  • CVs are served from the public folder. Paths are defined in data/profile.ts under profile.cv:
    • en: /cv/chris-leon-noltemeier-en.pdf
    • de: /cv/chris-leon-noltemeier-de.pdf
  • To update: Place your PDFs in public/cv/ with the same file names, or change the paths in data/profile.ts and add the corresponding files to public/cv/.
  • No code change is required if you keep the same file names; just replace the files in public/cv/.

Content & i18n

Routing

  • Locale is part of the URL: /:locale (e.g. /de, /en).
  • The useI18n composable (composables/useI18n.ts) provides:
    • locale — current locale ("de" or "en").
    • messages — typed translations for the current locale.
    • setLocale(newLocale) — switches locale and persists the choice in localStorage.
  • Global middleware in middleware/locale.global.ts redirects requests without a valid locale to the preferred locale (from localStorage or browser language, fallback en).

Adding or editing content

  • Translations: Edit data/i18n/de.ts and data/i18n/en.ts. Types are in types/i18n.ts; keep keys in sync across both files.
  • Profile (name, CV paths, social links): data/profile.ts. Types in types/content.ts.
  • Projects (case studies): data/projects.ts. Each project has translations.de and translations.en; add or adjust entries there.
  • Experience & education: data/experience.ts — structure and translations per locale.
  • Impact, Automation & AI, Now: Copy lives in the i18n files under impact, automationAi, and now.

New projects or experience entries are added in the corresponding data files and, where needed, in the i18n namespaces (e.g. labels, section titles).

Deployment (Vercel)

  • Connect the repo to Vercel. Use the Nuxt preset (build command and output are set automatically). Otherwise: Build Command npm run build and the output directory from the Nuxt preset.
  • Set Environment Variables in the Vercel project: at least NUXT_PUBLIC_SITE_URL for production; add RESEND_API_KEY, CONTACT_TO_EMAIL, and CONTACT_FROM_EMAIL (or FORMSPREE_ENDPOINT) for the contact form. Names must match Environment Variables above.
  • Production: Set NUXT_PUBLIC_SITE_URL to your canonical URL (e.g. https://chrisnoltemeier.dev) so sitemap, robots.txt, and OG URLs are correct.
  • Preview deployments: If NUXT_PUBLIC_SITE_URL is not set, the app uses the preview URL as origin for meta and sitemap.

SEO & technical notes

  • Meta tags: Locale-specific title, description, html lang, and Open Graph / Twitter tags are set in pages/[locale]/index.vue via useSeoMeta() and useHead(), using the seo block from data/i18n/de.ts and data/i18n/en.ts. Optional seo.ogImage (path or full URL) can be set in i18n for social share images.
  • Sitemap: Served at /sitemap.xml (generated by server/routes/sitemap.xml.get.ts), listing /de and /en with lastmod and changefreq.
  • Robots: Served at /robots.txt (generated by server/routes/robots.txt.get.ts), allowing all crawlers and pointing to the sitemap.
  • Accessibility: One h1 in the hero; sections use h2/h3. Links, buttons, and focusable elements have visible focus rings (focus-visible). Nav and language toggle use aria-labels from i18n; the contact form status uses an aria-live region. Images use loading="lazy", decoding="async", and descriptive alt text. Particle animation is reduced on small viewports for performance and motion sensitivity.

Releases

No releases published

Packages

 
 
 

Contributors