Skip to main content

Prerequisites

Before you begin, ensure you have the following installed on your system:

Required Software

Node.js

Version 20 or higher is requiredCheck your version:
node --version
Download from nodejs.org

pnpm

Version 10.19.0 (specified in package.json)Install globally:
npm install -g [email protected]
Verify installation:
pnpm --version

Git

For version control and cloning the repositoryCheck if installed:
git --version
Download from git-scm.com

Code Editor

We recommend VS Code with extensions:
  • ESLint
  • Tailwind CSS IntelliSense
  • TypeScript and JavaScript Language Features

API Credentials

You’ll need API keys for full functionality:
1

Azure AI API Token

Required for the AI chat assistant feature.
  1. Sign up for Azure AI services
  2. Create a new AI resource
  3. Get your API token from the resource dashboard
  4. The chat uses the endpoint: https://models.inference.ai.azure.com/chat/completions
The chat is configured to use the gpt-4o-mini model by default (see ChatBox.tsx:125)
2

GitHub API Token

Optional, but recommended for the GitHub contribution graph.
  1. Go to GitHub Settings > Developer settings > Personal access tokens
  2. Generate a new token (classic)
  3. Select the read:user scope
  4. Copy the token for your .env file

Installation Steps

1. Clone the Repository

git clone https://github.com/eclinick/personal-portfolio.git
cd personal-portfolio

2. Install Dependencies

Install all required packages:
pnpm install
This will install:
  • React 18.3.1 - UI library
  • React DOM 18.3.1 - React renderer
  • React Router DOM 6.30.1 - Client-side routing
  • TypeScript 5.5.3 - Type safety
  • Vite 5.4.2 - Build tool
  • Tailwind CSS 3.4.1 - Styling framework
  • Framer Motion 12.23.5 - Animations
  • Lucide React 0.344.0 - Icons
  • React Markdown 9.0.1 - Markdown rendering
  • Convex 1.31.4 - Real-time backend
  • And more…
  • ESLint - Code linting
  • TypeScript ESLint - TS linting rules
  • Autoprefixer - CSS vendor prefixes
  • PostCSS - CSS transformations
  • Vite Plugin React - React support for Vite
  • And more…
The installation may take 2-3 minutes depending on your internet connection.

3. Environment Configuration

Create a .env file in the root directory:
touch .env
Add the following environment variables:
# Azure AI Configuration
# Required for ChatBox.tsx AI assistant
API_TOKEN=your_azure_ai_api_token_here

# GitHub Configuration
# Used by github-contribution-graph.tsx
VITE_GITHUB_API_TOKEN=your_github_personal_access_token_here
Never commit your .env file to version control! It should already be in .gitignore, but double-check to avoid exposing your API keys.

4. Convex Setup (Optional)

If you want to use the blog functionality:
1

Sign up for Convex

Create a free account at convex.dev
2

Initialize Convex

npx convex dev
This will:
  • Create a new Convex project
  • Generate convex.json configuration
  • Set up development sync
3

Update Convex URL

Add your Convex deployment URL to .env:
VITE_CONVEX_URL=your_convex_deployment_url

5. Verify Installation

Run the development server to verify everything is set up correctly:
pnpm run dev
You should see output similar to:
  VITE v5.4.2  ready in 423 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h + enter to show help
The dev server uses Vite’s fast HMR (Hot Module Replacement) for instant updates during development.

Configuration Files

Vite Configuration

The vite.config.ts file is already configured with:
vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
  build: {
    outDir: 'dist'
  }
});
Key features:
  • React plugin for JSX support
  • Path alias @/ points to src/
  • Build output to dist/ directory

Tailwind Configuration

The tailwind.config.js includes custom theme extensions:
tailwind.config.js
export default {
  content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
  theme: {
    extend: {
      // Custom glassmorphism backgrounds
      backgroundColor: {
        'glass': 'rgba(24, 23, 23, 0.42)',
        'glass-dark': 'rgba(255, 255, 255, 0.15)',
        // ... more glass variants
      },
      // Custom animations
      animation: {
        'float': 'float 6s ease-in-out infinite',
        'glow-pulse': 'glow-pulse 4s ease-in-out infinite',
        'chat-bounce': 'chat-bounce 2s ease-in-out infinite',
        // ... more animations
      },
      // Custom keyframes for animations
      keyframes: {
        'float': {
          '0%, 100%': { transform: 'translateY(0px) rotate(0deg)' },
          '50%': { transform: 'translateY(-20px) rotate(5deg)' },
        },
        // ... more keyframes
      },
    },
  },
  plugins: [],
};

TypeScript Configuration

The project uses three TypeScript config files:
  • tsconfig.json - Base configuration
  • tsconfig.app.json - App-specific settings
  • tsconfig.node.json - Node/build tool settings

Netlify Functions Setup

The chat functionality uses a Netlify serverless function:

Function Structure

netlify/functions/chat.ts
import { Handler } from '@netlify/functions';

export const handler: Handler = async (event) => {
  // CORS headers
  const headers = {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Headers': 'Content-Type, Authorization',
    'Access-Control-Allow-Methods': 'POST, OPTIONS',
    'Content-Type': 'application/json'
  };

  // Proxy to Azure AI
  const response = await fetch(
    'https://models.inference.ai.azure.com/chat/completions',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${process.env.API_TOKEN}`
      },
      body: event.body
    }
  );

  return {
    statusCode: 200,
    headers,
    body: JSON.stringify(await response.json())
  };
};

Netlify Configuration

The netlify.toml file configures deployment:
netlify.toml
[build]
  command = "npx convex deploy --cmd \"npm run build\""
  publish = "dist"
  functions = "netlify/functions"

[build.environment]
  NODE_VERSION = "20"

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

[[headers]]
  for = "/*"
    [headers.values]
    Access-Control-Allow-Origin = "*"
    Access-Control-Allow-Methods = "GET, POST, OPTIONS"
    Access-Control-Allow-Headers = "Content-Type, Authorization"
The redirect rule ensures React Router works correctly on Netlify by serving index.html for all routes.

Testing Your Installation

1. Check Development Server

pnpm run dev
Navigate to http://localhost:5173 and verify:
  • Welcome animation plays
  • Hero section loads with profile image
  • Navigation menu works
  • Smooth scroll animations

2. Test the Build

pnpm run build
This should create a dist/ folder with optimized production files.

3. Preview Production Build

pnpm run preview
This serves the production build locally to test before deployment.

4. Run Linter

pnpm run lint
Ensure there are no linting errors in the codebase.

Common Issues

Clear cache and reinstall:
rm -rf node_modules pnpm-lock.yaml .vite
pnpm install
Either kill the process using the port or Vite will automatically use the next available port (5174, 5175, etc.)
Make sure your editor is using the workspace TypeScript version:
  • In VS Code: Cmd/Ctrl + Shift + P > “TypeScript: Select TypeScript Version” > “Use Workspace Version”
In local development, the chat function endpoint is /.netlify/functions/chat. Make sure you’re using netlify dev to test functions locally, not pnpm run dev.
Vite requires environment variables to be prefixed with VITE_ to be exposed to the client. Server-side variables (like API_TOKEN for Netlify Functions) don’t need this prefix.

Next Steps

Customization

Personalize your portfolio with your own content

Deployment

Deploy your portfolio to Netlify

AI Chat Configuration

Customize the AI assistant behavior

Components

Learn about reusable UI components
The portfolio is configured to work with both local development and Netlify deployment out of the box. No additional configuration needed!

Build docs developers (and LLMs) love