Files
Portfolio/CONTRIBUTING.md
T

13 KiB

Contributing to Portfolio

Thank you for your interest in contributing to this project! This guide will help you get started with development.

Table of Contents

Getting Started

Prerequisites

  • Node.js 18.x or higher
  • npm 9.x or higher
  • Git for version control

Installation

  1. Clone the repository

    git clone <repository-url>
    cd portfolio
    
  2. Install dependencies

    npm install
    
  3. Set up environment variables

    Create a .env.local file in the root directory with the required environment variables:

    # Supabase Configuration
    NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
    NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
    
    # Optional: OpenAI (for image generation scripts)
    OPENAI_API_KEY=your_openai_api_key
    
  4. Start the development server

    npm run dev
    

    The application will be available at http://localhost:3000

Available Scripts

Command Description
npm run dev Start development server with hot reload
npm run build Build production bundle
npm start Start production server (after build)
npm run lint Run ESLint with strict mode
npm test Run unit tests with Vitest
npm run test:coverage Run tests with coverage report
npm run build:images Optimize images using Sharp
npm run generate:images Generate blog images using OpenAI
npm run generate:images:dry Preview image generation without creating files

Project Overview

This is a personal portfolio website for Damjan Savić, showcasing work as an AI & Automation Specialist. The site features:

  • Multi-language support - German, English, and Serbian with automatic language detection
  • Progressive Web App - Installable and offline-capable
  • SEO optimized - Structured data (Schema.org), sitemap generation
  • Responsive Design - Mobile-first approach with Tailwind CSS
  • Blog System - MDX-based content with frontmatter support
  • Portfolio Gallery - Dynamic project showcase with filtering
  • Contact Form - Integrated with Supabase backend

Tech Stack

Core Framework

  • Next.js 15 - React framework with App Router
  • React 19 - UI library with latest features
  • TypeScript 5.5 - Type-safe development

Styling & UI

  • Tailwind CSS 3.4 - Utility-first CSS framework
  • Framer Motion 11 - Animation library
  • Lucide React - Icon library
  • Tailwind Merge - Utility for merging Tailwind classes
  • CVA (Class Variance Authority) - Component variants management

Content & Internationalization

  • MDX - Markdown + JSX for content pages
    • @mdx-js/loader, @mdx-js/mdx, @mdx-js/react
    • @next/mdx, next-mdx-remote
  • next-intl 3.26 - Internationalization (i18n)
  • gray-matter - Frontmatter parsing

Backend & Services

  • Supabase - Database, authentication, and backend services
    • @supabase/supabase-js
    • @supabase/ssr
  • OpenAI 4.77 - AI integration for content generation

Development Tools

  • Vitest - Unit testing framework
  • ESLint 9 - Code linting with Next.js config
  • PostCSS - CSS processing
  • Autoprefixer - CSS vendor prefixes
  • Sharp - Image optimization

Performance & Analytics

  • web-vitals - Performance metrics
  • react-intersection-observer - Lazy loading and scroll animations

Project Structure

portfolio/
├── public/                    # Static assets (images, fonts, etc.)
├── scripts/                   # Build and utility scripts
│   ├── optimize-images.js     # Image optimization
│   └── generate-blog-images.mjs # AI-powered image generation
├── src/
│   ├── app/                   # Next.js App Router
│   │   ├── [locale]/          # Internationalized routes
│   │   │   ├── about/         # About page
│   │   │   ├── blog/          # Blog listing & posts
│   │   │   ├── contact/       # Contact form
│   │   │   ├── dashboard/     # Admin dashboard
│   │   │   ├── imprint/       # Legal imprint
│   │   │   ├── leistungen/    # Services page
│   │   │   ├── login/         # Authentication
│   │   │   ├── portfolio/     # Portfolio gallery & projects
│   │   │   ├── privacy/       # Privacy policy
│   │   │   ├── terms/         # Terms of service
│   │   │   ├── layout.tsx     # Locale-specific layout
│   │   │   └── page.tsx       # Homepage
│   │   ├── globals.css        # Global styles
│   │   ├── layout.tsx         # Root layout
│   │   ├── not-found.tsx      # 404 page
│   │   ├── robots.ts          # Robots.txt generation
│   │   └── sitemap.ts         # Sitemap generation
│   ├── components/            # Reusable React components
│   ├── components-vite/       # Legacy Vite components
│   ├── data/                  # Static data and content
│   ├── hooks/                 # Custom React hooks
│   ├── i18n/                  # Internationalization config
│   ├── lib/                   # Utility libraries and helpers
│   ├── messages/              # Translation files (de, en, sr)
│   ├── middleware.ts          # Next.js middleware (i18n routing)
│   ├── pages-vite/            # Legacy Vite pages
│   ├── services/              # API and service integrations
│   ├── styles/                # Additional styles
│   ├── types/                 # TypeScript type definitions
│   └── utils/                 # Helper functions
├── .env.local                 # Environment variables (not in git)
├── .eslintrc.json             # ESLint configuration
├── docker-compose.yml         # Docker Compose setup
├── Dockerfile                 # Docker container config
├── next.config.ts             # Next.js configuration
├── package.json               # Dependencies and scripts
├── postcss.config.js          # PostCSS configuration
├── tailwind.config.js         # Tailwind CSS configuration
└── tsconfig.json              # TypeScript configuration

Key Directories Explained

  • src/app/ - Next.js App Router pages and layouts using the new file-based routing system
  • src/app/[locale]/ - All pages are nested under locale for multi-language support (de, en, sr)
  • src/components/ - Reusable UI components (buttons, cards, forms, navigation, etc.)
  • src/hooks/ - Custom React hooks for shared logic
  • src/lib/ - Utility libraries (Supabase client, helpers, etc.)
  • src/messages/ - Translation JSON files for each language
  • src/services/ - API integrations and external service wrappers
  • src/types/ - TypeScript interfaces and type definitions
  • src/utils/ - Helper functions and utilities
  • public/ - Static files served directly (images, fonts, favicons)
  • scripts/ - Build automation and utility scripts

Development Workflow

1. Create a New Feature Branch

git checkout -b feature/your-feature-name

2. Make Your Changes

  • Follow the existing code patterns and structure
  • Use TypeScript for type safety
  • Write clean, readable code with appropriate comments
  • Test your changes locally

3. Test Your Changes

# Run development server
npm run dev

# Run linter
npm run lint

# Run tests
npm test

4. Build for Production

npm run build

Ensure the build completes without errors before submitting.

Code Style & Standards

ESLint & Code Linting

This project uses ESLint to enforce code quality and consistency. The configuration extends Next.js recommended presets:

ESLint Configuration (.eslintrc.json):

{
  "extends": [
    "next/core-web-vitals",
    "next/typescript"
  ]
}

Key ESLint Rules:

  • next/core-web-vitals - Enforces Next.js best practices and Core Web Vitals optimizations
  • next/typescript - TypeScript-specific rules for Next.js applications

Running the Linter:

# Run ESLint in strict mode (recommended before committing)
npm run lint

# The linter will check for:
# - Code quality issues
# - Next.js best practices violations
# - TypeScript type errors
# - Unused variables and imports
# - Accessibility issues

Important:

  • Always run npm run lint before committing changes
  • Fix all linting errors - the project uses --strict mode
  • The linter runs automatically during the build process
  • ESLint errors will prevent successful production builds

Code Formatting

General Formatting Guidelines:

  • Indentation: 2 spaces (no tabs)
  • Line Length: Aim for 80-100 characters, hard limit at 120
  • Semicolons: Required at the end of statements
  • Quotes: Single quotes for strings (except in JSX/TSX where double quotes are preferred)
  • Trailing Commas: Use trailing commas in multi-line objects and arrays

Example:

// ✅ Good
const user = {
  name: 'John Doe',
  email: 'john@example.com',
  role: 'admin',
};

// ❌ Bad
const user = {
  name: "John Doe",
  email: "john@example.com",
  role: "admin"
}

TypeScript

  • Use TypeScript for all new files
  • Define proper types and interfaces
  • Avoid using any - use proper typing or unknown
  • Export types from a central types/ directory when shared

React Components

  • Use functional components with hooks
  • Follow the component structure:
    1. Imports
    2. Type definitions
    3. Component definition
    4. Helper functions (if needed)
    5. Exports

Example:

import { useState } from 'react';
import { Button } from '@/components/ui/Button';

interface MyComponentProps {
  title: string;
  onSubmit: () => void;
}

export function MyComponent({ title, onSubmit }: MyComponentProps) {
  const [isLoading, setIsLoading] = useState(false);

  const handleClick = async () => {
    setIsLoading(true);
    await onSubmit();
    setIsLoading(false);
  };

  return (
    <div>
      <h2>{title}</h2>
      <Button onClick={handleClick} disabled={isLoading}>
        Submit
      </Button>
    </div>
  );
}

Styling

  • Use Tailwind CSS utility classes
  • Use cn() utility from tailwind-merge to merge classes
  • Follow the mobile-first responsive design approach
  • Use CSS variables for theme colors (defined in globals.css)

File Naming

  • Components: PascalCase (e.g., MyComponent.tsx)
  • Utilities: camelCase (e.g., formatDate.ts)
  • Pages: lowercase (e.g., page.tsx, layout.tsx)
  • Types: PascalCase with .types.ts suffix (e.g., User.types.ts)

Import Organization

// 1. External dependencies
import { useState } from 'react';
import { useTranslations } from 'next-intl';

// 2. Internal components and utilities
import { Button } from '@/components/ui/Button';
import { formatDate } from '@/utils/date';

// 3. Types
import type { User } from '@/types/User.types';

// 4. Styles (if any)
import styles from './Component.module.css';

Internationalization

  • All user-facing text must be internationalized
  • Use useTranslations() hook from next-intl
  • Add translation keys to all language files in src/messages/

Example:

import { useTranslations } from 'next-intl';

export function WelcomeMessage() {
  const t = useTranslations('home');

  return <h1>{t('welcome')}</h1>;
}

Testing

Unit Tests

  • Write tests for utility functions and complex logic
  • Use Vitest as the testing framework
  • Place test files next to the code they test with .test.ts or .test.tsx extension

Example:

// formatDate.test.ts
import { describe, it, expect } from 'vitest';
import { formatDate } from './formatDate';

describe('formatDate', () => {
  it('formats date correctly', () => {
    const date = new Date('2024-01-15');
    expect(formatDate(date)).toBe('15.01.2024');
  });
});

Running Tests

# Run tests in watch mode
npm test

# Run tests once with coverage
npm run test:coverage

Commit Guidelines

Commit Message Format

<type>: <subject>

<body>

Types

  • feat - New feature
  • fix - Bug fix
  • docs - Documentation changes
  • style - Code style changes (formatting, etc.)
  • refactor - Code refactoring
  • test - Adding or updating tests
  • chore - Maintenance tasks

Examples

git commit -m "feat: add contact form validation"
git commit -m "fix: resolve mobile navigation menu bug"
git commit -m "docs: update README with deployment instructions"

Questions?

If you have any questions or need help, please:

  • Check existing documentation
  • Review similar code in the codebase
  • Open an issue for discussion

Built with Next.js + TypeScript + Tailwind CSS