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
- Project Overview
- Tech Stack
- Project Structure
- Development Workflow
- Code Style & Standards
- Testing
- Commit Guidelines
Getting Started
Prerequisites
- Node.js 18.x or higher
- npm 9.x or higher
- Git for version control
Installation
-
Clone the repository
git clone <repository-url> cd portfolio -
Install dependencies
npm install -
Set up environment variables
Create a
.env.localfile 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 -
Start the development server
npm run devThe 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 systemsrc/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 logicsrc/lib/- Utility libraries (Supabase client, helpers, etc.)src/messages/- Translation JSON files for each languagesrc/services/- API integrations and external service wrapperssrc/types/- TypeScript interfaces and type definitionssrc/utils/- Helper functions and utilitiespublic/- 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 optimizationsnext/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 lintbefore committing changes - Fix all linting errors - the project uses
--strictmode - 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 orunknown - Export types from a central
types/directory when shared
React Components
- Use functional components with hooks
- Follow the component structure:
- Imports
- Type definitions
- Component definition
- Helper functions (if needed)
- 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 fromtailwind-mergeto 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.tssuffix (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 fromnext-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.tsor.test.tsxextension
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 featurefix- Bug fixdocs- Documentation changesstyle- Code style changes (formatting, etc.)refactor- Code refactoringtest- Adding or updating testschore- 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