Thanks to visit codestin.com
Credit goes to github.com

Skip to content

rlajous/website

Repository files navigation

Portfolio Website - Rodrigo Manuel Navarro Lajous

Next.js TypeScript Tailwind CSS License: MIT

A modern, SEO-optimized portfolio website showcasing professional experience, projects, speaking engagements, and education.

🌐 Live Site: navarrolajous.com | www.navarrolajous.com


Table of Contents


Overview

This is a professional portfolio website built with Next.js 14 (App Router) and TypeScript, featuring a modern design system with dark mode support, comprehensive SEO optimization, and dynamic content sections. The site showcases professional experience, project portfolio, academic background, and speaking engagements at conferences.

Key Highlights:

  • πŸ“± Fully responsive design (mobile-first approach)
  • πŸŒ“ Dark/Light theme with system detection
  • πŸ” SEO optimized with sitemap, robots.txt, and Schema.org structured data
  • ⚑ Static generation for optimal performance
  • πŸ“Š Integrated Umami Analytics
  • πŸ“§ Contact form with Resend email integration
  • 🎀 Speaking engagements and conference talks showcase

✨ Features

Core Sections

🏒 Experience

  • Jobs & Startups: Separate tabs for employment history and entrepreneurial ventures
  • Detail Pages: Individual pages for each role with dynamic routes (/experience/[slug])
  • Rich Content: Responsibilities, achievements, tech stack, location, and period
  • Company Links: Direct links to company websites and profiles

πŸ’Ό Projects

  • Three Categories: Freelance, Hobby, and Open Source projects
  • Detail Pages: Comprehensive project showcase (/projects/[slug])
  • Project Details: Features, challenges, impact, screenshots, and banners
  • Links: GitHub repositories and live project URLs
  • Visual Content: Project banners and multiple screenshots

🎀 Talks & Speaking Engagements

  • Conference Presentations: Showcase of talks at DuneCon, DeFi Security Summit, etc.
  • Detail Pages: Full talk information with descriptions and topics (/talks/[slug])
  • Media Integration: YouTube video embeds and PDF slide viewers
  • Event Information: Date, location, and event details

πŸŽ“ Education

  • Academic Background: Degrees and certifications
  • Detail Pages: In-depth educational credentials (/education/[slug])
  • Academic Details: Thesis information, coursework, achievements, and tech stack

πŸ“¬ Contact

  • Contact Form: Validated form with Zod schema
  • Email Integration: Automated email notifications via Resend API
  • User Feedback: Toast notifications for form submission status

Additional Features

  • πŸ“„ Resume Download: Direct PDF download from header navigation
  • πŸ”— Social Links: GitHub and LinkedIn integration
  • 🎨 Theme Toggle: Smooth dark/light mode switching with persistence
  • πŸ“± Mobile Navigation: Responsive header with mobile menu
  • πŸ” SEO: Meta tags, OpenGraph, Twitter cards, and JSON-LD structured data
  • πŸ—ΊοΈ Sitemap: Auto-generated sitemap for all routes
  • πŸ€– Robots.txt: Search engine crawler configuration
  • πŸ“ˆ Analytics: Umami Analytics integration for privacy-friendly tracking

πŸ› οΈ Tech Stack

Frontend Framework

Styling

UI Components

Features & Utilities

Development Tools

Deployment & Analytics


πŸ“ Project Structure

website/
β”œβ”€β”€ app/                          # Next.js App Router
β”‚   β”œβ”€β”€ api/
β”‚   β”‚   └── contact/
β”‚   β”‚       └── route.ts         # Contact form API endpoint
β”‚   β”œβ”€β”€ contact/
β”‚   β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”‚   └── ContactForm.tsx  # Contact form component
β”‚   β”‚   └── page.tsx             # Contact page
β”‚   β”œβ”€β”€ education/
β”‚   β”‚   β”œβ”€β”€ [slug]/
β”‚   β”‚   β”‚   └── page.tsx         # Education detail pages
β”‚   β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”‚   └── EducationCard.tsx
β”‚   β”‚   └── page.tsx             # Education list page
β”‚   β”œβ”€β”€ experience/
β”‚   β”‚   β”œβ”€β”€ [slug]/
β”‚   β”‚   β”‚   └── page.tsx         # Experience detail pages
β”‚   β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”‚   β”œβ”€β”€ ExperienceCard/
β”‚   β”‚   β”‚   └── ExperiencesTab.tsx
β”‚   β”‚   β”œβ”€β”€ layout.tsx           # Experience layout for metadata
β”‚   β”‚   └── page.tsx             # Experience list with tabs
β”‚   β”œβ”€β”€ projects/
β”‚   β”‚   β”œβ”€β”€ [slug]/
β”‚   β”‚   β”‚   └── page.tsx         # Project detail pages
β”‚   β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”‚   β”œβ”€β”€ ProjectCard/
β”‚   β”‚   β”‚   └── ProjectTabs.tsx
β”‚   β”‚   β”œβ”€β”€ layout.tsx           # Projects layout for metadata
β”‚   β”‚   └── page.tsx             # Projects list with tabs
β”‚   β”œβ”€β”€ talks/
β”‚   β”‚   β”œβ”€β”€ [slug]/
β”‚   β”‚   β”‚   └── page.tsx         # Talk detail pages
β”‚   β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”‚   β”œβ”€β”€ PDFViewer.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€ TalkCard.tsx
β”‚   β”‚   β”‚   └── YouTubeEmbed.tsx
β”‚   β”‚   └── page.tsx             # Talks list page
β”‚   β”œβ”€β”€ favicon.ico
β”‚   β”œβ”€β”€ globals.css              # Global styles
β”‚   β”œβ”€β”€ layout.tsx               # Root layout
β”‚   β”œβ”€β”€ page.tsx                 # Home page
β”‚   β”œβ”€β”€ robots.ts                # Robots.txt generation
β”‚   └── sitemap.ts               # Sitemap generation
β”‚
β”œβ”€β”€ components/                   # Shared components
β”‚   β”œβ”€β”€ emails-templates/        # Email templates for Resend
β”‚   β”œβ”€β”€ Footer/
β”‚   β”œβ”€β”€ Header/                  # Navigation header
β”‚   β”œβ”€β”€ ModeToggle/              # Dark/light theme toggle
β”‚   β”œβ”€β”€ SchemaOrgScripts/        # SEO structured data
β”‚   β”œβ”€β”€ ui/                      # shadcn/ui components
β”‚   └── theme-provider.tsx       # Theme provider wrapper
β”‚
β”œβ”€β”€ constants/                    # Application constants
β”‚   └── routes.ts                # Route definitions and SITE_URL config
β”‚
β”œβ”€β”€ domains/                      # TypeScript interfaces/types
β”‚   β”œβ”€β”€ Education.ts             # Education interface
β”‚   β”œβ”€β”€ Experience.ts            # Experience interface
β”‚   β”œβ”€β”€ Project.ts               # Project interface
β”‚   └── Talk.ts                  # Talk interface
β”‚
β”œβ”€β”€ lib/                         # Library utilities
β”‚   └── utils.ts                 # Tailwind utility (cn function)
β”‚
β”œβ”€β”€ public/                      # Static assets
β”‚   β”œβ”€β”€ assets/                  # Images, banners, etc.
β”‚   └── resume.pdf               # Downloadable resume
β”‚
β”œβ”€β”€ services/                    # Data services (static data)
β”‚   β”œβ”€β”€ education.ts             # Education data
β”‚   β”œβ”€β”€ experience.ts            # Jobs, startups, skills data
β”‚   β”œβ”€β”€ projects.ts              # Projects data (freelance, hobby, opensource)
β”‚   └── talks.ts                 # Talks and presentations data
β”‚
β”œβ”€β”€ utils/                       # Utility functions
β”‚   β”œβ”€β”€ getEnv.ts               # Environment variable helper
β”‚   └── iconUtils.ts            # Icon utilities
β”‚
β”œβ”€β”€ .claude/                     # Claude Code configuration
β”‚   β”œβ”€β”€ commands/                # Custom slash commands
β”‚   β”‚   β”œβ”€β”€ start.md            # /start - Create feature branch
β”‚   β”‚   β”œβ”€β”€ commit.md           # /commit - Stage and commit
β”‚   β”‚   β”œβ”€β”€ sync.md             # /sync - Sync with main
β”‚   β”‚   β”œβ”€β”€ build.md            # /build - Build and validate
β”‚   β”‚   β”œβ”€β”€ release.md          # /release - Create release
β”‚   β”‚   β”œβ”€β”€ dev.md              # /dev - Start dev server
β”‚   β”‚   β”œβ”€β”€ finish.md           # /finish - Create PR
β”‚   β”‚   └── release-notes.md    # /release-notes - Enhance release
β”‚   └── CLAUDE.md               # AI assistant guidance
β”‚
β”œβ”€β”€ .env.template                # Environment variables template
β”œβ”€β”€ .nvmrc                       # Node version specification
β”œβ”€β”€ components.json              # shadcn/ui configuration
β”œβ”€β”€ next.config.js               # Next.js configuration
β”œβ”€β”€ package.json                 # Dependencies and scripts
β”œβ”€β”€ postcss.config.js            # PostCSS configuration
β”œβ”€β”€ tailwind.config.ts           # Tailwind configuration
└── tsconfig.json                # TypeScript configuration

πŸ—„οΈ Data Architecture

This project uses a static TypeScript data pattern where all content is stored as typed data in the services/ directory. This approach provides:

  • βœ… Type safety for all content
  • βœ… Easy content management
  • βœ… Fast builds (static generation)
  • βœ… No database needed

Domain Interfaces

All content types are defined as TypeScript interfaces in domains/:

// domains/Experience.ts
export interface Experience {
  id: number;
  slug: string;
  type: 'job' | 'startup';
  company: string;
  position: string;
  period: string;
  location?: string;
  companyUrl?: string;
  responsibilities: string[];
  achievements?: string[];
  technologies: string[];
  banner?: string;
}

// domains/Project.ts
export interface Project {
  id: number;
  slug: string;
  type: 'freelance' | 'hobby' | 'opensource';
  name: string;
  company: string;
  github?: string;
  website?: string;
  period: string;
  description: string;
  detailedDescription?: string;
  features?: string[];
  challenges?: string[];
  technologies: string[];
  banner?: string;
  screenshots?: string[];
  impact?: string;
}

Data Services

Content is stored in services/ files as typed arrays:

// services/experience.ts
import { Experience } from "@/domains/Experience";

export const jobs: Experience[] = [
  {
    id: 1,
    slug: "webacy",
    type: "job",
    company: "Webacy",
    position: "Staff Software Engineer",
    period: "Jan 2023 β€” Present",
    // ... more fields
  },
  // ... more jobs
];

export const startups: Experience[] = [
  // ... startups
];

πŸš€ Getting Started

Prerequisites

  • Node.js: Version specified in .nvmrc (use nvm use if you have nvm installed)
  • npm: Comes with Node.js
  • Resend Account: For contact form email functionality (sign up at resend.com)

Installation

  1. Clone the repository:

    git clone https://github.com/rlajous/website.git
    cd website
  2. Set up Node.js version:

    nvm use

    If you don't have nvm, ensure you're using the Node.js version from .nvmrc.

  3. Install dependencies:

    npm install
  4. Configure environment variables:

    cp .env.template .env.local

    Update .env.local with your values:

    # Resend API Key (get from https://resend.com/api-keys)
    RESEND_API_KEY=re_your_api_key_here
    
    # Email recipient for contact form
    RECIPIENT_EMAIL=[email protected]
    
    # Optional: Override site URL for different environments
    NEXT_PUBLIC_SITE_URL=https://navarrolajous.com
  5. Start the development server:

    npm run dev
  6. Open your browser: Navigate to http://localhost:3000

Troubleshooting

Issue: Module not found errors

  • Solution: Delete node_modules and .next, then run npm install again

Issue: Environment variables not working

  • Solution: Restart the dev server after changing .env.local
  • Ensure variables start with NEXT_PUBLIC_ for client-side access

Issue: Build fails

  • Solution: Run npm run build locally to see detailed error messages
  • Check TypeScript errors with npm run lint

πŸ’» Development Workflow

This project uses custom slash commands (in .claude/commands/) for streamlined development:

Available Commands

  • /start - Start a new PR by creating a feature branch

    • Creates branch following naming convention (feat/, fix/, etc.)
    • Stores context for other commands
  • /commit - Stage and commit changes with proper formatting

    • Follows conventional commit format
    • Adds co-author attribution
  • /sync - Sync your feature branch with latest main

    • Prevents merge conflicts
    • Keeps branch up to date
  • /build - Build and validate the production bundle locally

    • Runs npm run build
    • Validates output
  • /dev - Start the development server with environment validation

    • Checks environment variables
    • Starts npm run dev
  • /finish - Create a pull request with comprehensive description

    • Generates PR description
    • Creates PR on GitHub
  • /release - Create a new release version and trigger deployment

    • Bumps version (patch/minor/major)
    • Creates git tag
    • Triggers Vercel deployment
  • /release-notes - Enhance GitHub release with detailed notes

    • Generates categorized changelog
    • Updates GitHub release

Git Workflow

Branch Naming Convention:

feat/feature-name       # New features
fix/bug-description     # Bug fixes
refactor/what-changed   # Code improvements
content/what-updated    # Content updates
design/what-improved    # Design changes
docs/what-documented    # Documentation

Commit Message Format:

[ Type ] Description

Examples:
[ Feature ] Add blog section with MDX support
[ Bug ] Fix mobile navigation overflow
[ Content ] Update experience with Webacy role
[ Design ] Improve dark mode theme transitions
[ Refactor ] Simplify contact form validation

βž• Adding Content

Adding a New Job/Experience

  1. Open services/experience.ts
  2. Add a new entry to the jobs or startups array:
export const jobs: Experience[] = [
  {
    id: 8, // Increment ID
    slug: "company-name", // URL-friendly slug
    type: "job",
    company: "Company Name",
    position: "Your Position",
    period: "Jan 2024 β€” Present",
    location: "Remote", // Optional
    companyUrl: "https://company.com", // Optional
    responsibilities: [
      "Key responsibility 1",
      "Key responsibility 2",
      "Key responsibility 3",
    ],
    achievements: [ // Optional
      "Achievement 1",
      "Achievement 2",
    ],
    technologies: ["React", "TypeScript", "Node.js"],
    banner: "/experience/company-banner.jpg", // Optional
  },
  // ... existing jobs
];
  1. Add banner image to public/assets/experience/ (if using)
  2. The detail page will be auto-generated at /experience/company-name

Adding a New Project

  1. Open services/projects.ts
  2. Add to freelance, hobby, or opensource array:
export const freelance: Project[] = [
  {
    id: 8, // Increment ID
    slug: "project-name",
    type: "freelance",
    name: "Project Name",
    company: "Client Name",
    github: "https://github.com/user/repo", // Optional
    website: "https://project.com", // Optional
    period: "2024",
    description: "Brief description for card view",
    detailedDescription: "Longer description for detail page", // Optional
    features: [ // Optional
      "Feature 1",
      "Feature 2",
    ],
    challenges: [ // Optional
      "Challenge 1",
      "Challenge 2",
    ],
    technologies: ["Next.js", "Tailwind CSS"],
    banner: "/projects/project-banner.jpg", // Optional
    screenshots: [ // Optional
      "/projects/project-screenshot-1.jpg",
      "/projects/project-screenshot-2.jpg",
    ],
    impact: "Impact description", // Optional
  },
  // ... existing projects
];
  1. Add images to public/assets/projects/
  2. Detail page will be at /projects/project-name

Adding a New Talk/Speaking Engagement

  1. Open services/talks.ts
  2. Add a new talk:
export const talks: Talk[] = [
  {
    id: 3, // Increment ID
    slug: "event-name-year",
    title: "Talk Title",
    event: "Conference Name",
    location: "City, Country",
    date: "2025-03-15",
    description: "Talk description and key points",
    topics: ["Topic 1", "Topic 2", "Topic 3"],
    slides: "https://slides.com/presentation", // Optional
    video: "https://youtube.com/watch?v=...", // Optional
    banner: "/talks/event-banner.jpg", // Optional
  },
  // ... existing talks
];
  1. Add banner to public/assets/talks/
  2. Detail page will be at /talks/event-name-year

Adding Education

  1. Open services/education.ts
  2. Add new entry:
export const education: Education[] = [
  {
    id: 3, // Increment ID
    slug: "degree-institution",
    degree: "Degree Name",
    institution: "University Name",
    period: "2020 β€” 2024",
    location: "City, Country", // Optional
    institutionUrl: "https://university.edu", // Optional
    specialization: "Specialization", // Optional
    thesis: { // Optional
      title: "Thesis Title",
      description: "Thesis description",
      link: "https://thesis-link.com",
    },
    coursework: ["Course 1", "Course 2"], // Optional
    achievements: ["Achievement 1"], // Optional
    technologies: ["Python", "R", "MATLAB"],
    banner: "/education/institution-banner.jpg", // Optional
  },
  // ... existing education
];

🎨 Customization

Changing Theme Colors

Edit app/globals.css to modify the color palette:

@layer base {
  :root {
    --primary: 222.2 47.4% 11.2%; /* Change primary color */
    --secondary: 210 40% 96.1%; /* Change secondary color */
    /* ... other colors */
  }

  .dark {
    --primary: 210 40% 98%; /* Dark mode primary */
    /* ... other colors */
  }
}

Modifying Components

Components follow the shadcn/ui pattern. To modify a component:

  1. Find it in components/ui/
  2. Edit the component file
  3. Maintain the CVA pattern for variants

Adding New Pages

  1. Create a new directory in app/
  2. Add page.tsx:
    export default function NewPage() {
      return <div>New Page Content</div>
    }
  3. Add to navigation in components/Header/
  4. Update constants/routes.ts

Updating SEO Metadata

Edit app/layout.tsx for global metadata:

export const metadata: Metadata = {
  title: "Your Name | Title",
  description: "Your description",
  // ... other metadata
};

For page-specific metadata, add generateMetadata to page files.


πŸ“œ Available Scripts

# Development
npm run dev          # Start development server (http://localhost:3000)

# Production
npm run build        # Build for production
npm start            # Start production server

# Code Quality
npm run lint         # Run ESLint

🌐 Deployment

Vercel Deployment (Recommended)

This site is optimized for Vercel deployment with automatic CI/CD:

  1. Fork/Clone this repository

  2. Connect to Vercel:

    • Go to vercel.com
    • Click "New Project"
    • Import your repository
    • Vercel will auto-detect Next.js
  3. Configure Environment Variables: In Vercel project settings, add:

    RESEND_API_KEY=your_resend_api_key
    [email protected]
    NEXT_PUBLIC_SITE_URL=https://yourdomain.com
    
  4. Configure Domains:

    • Add your custom domain in Vercel project settings
    • Update DNS records as instructed by Vercel
    • Both apex and www domains are supported
  5. Deploy:

    • Push to main branch to trigger deployment
    • Vercel builds and deploys automatically
    • Preview deployments created for pull requests

Post-Deployment

  • Analytics: Configure Umami Analytics in app/layout.tsx
  • Sitemap: Automatically generated at /sitemap.xml
  • Robots: Configured at /robots.txt
  • Monitoring: Check Vercel dashboard for build logs and analytics

🀝 Contributing

Contributions are welcome! Whether you're fixing bugs, adding features, or improving documentation, your help is appreciated.

How to Contribute

  1. Fork the repository

  2. Create a feature branch:

    git checkout -b feat/amazing-feature
  3. Make your changes:

    • Follow the existing code style
    • Add types for all TypeScript code
    • Test your changes locally
    • Update documentation if needed
  4. Commit your changes:

    git commit -m "[ Feature ] Add amazing feature"
  5. Push to your fork:

    git push origin feat/amazing-feature
  6. Open a Pull Request

Code Style Guidelines

  • TypeScript: Use strict mode, add types for all variables
  • Components: Follow shadcn/ui patterns
  • Naming: Use descriptive names, camelCase for variables/functions
  • Comments: Add comments for complex logic
  • Formatting: Use Prettier (if configured) or follow existing style

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.


πŸ“§ Contact

Rodrigo Manuel Navarro Lajous


Built with ❀️ using Next.js, TypeScript, and Tailwind CSS