116 lines
65beb53 samthecodingguy Jan 29, 2026
// Pexels API Client
// Free tier: 200 requests/hour
// Docs: https://www.pexels.com/api/documentation/
export interface PexelsPhoto {
  id: number;
  width: number;
  height: number;
  url: string;
  photographer: string;
  photographer_url: string;
  photographer_id: number;
  avg_color: string;
  src: {
    original: string;
    large2x: string;
    large: string;
    medium: string;
    small: string;
    portrait: string;
    landscape: string;
    tiny: string;
  };
  liked: boolean;
  alt: string;
}
export interface PexelsSearchResponse {
  total_results: number;
  page: number;
  per_page: number;
  photos: PexelsPhoto[];
  next_page?: string;
}
export interface PexelsCuratedResponse {
  page: number;
  per_page: number;
  photos: PexelsPhoto[];
  next_page?: string;
}
const PEXELS_API_KEY = process.env.NEXT_PUBLIC_PEXELS_API_KEY || '';
const PEXELS_BASE_URL = 'https://api.pexels.com/v1';
async function fetchPexels<T>(endpoint: string): Promise<T> {
  if (!PEXELS_API_KEY) {
    throw new Error('Pexels API key not configured. Add NEXT_PUBLIC_PEXELS_API_KEY to .env.local');
  }
  const response = await fetch(`${PEXELS_BASE_URL}${endpoint}`, {
    headers: {
      Authorization: PEXELS_API_KEY,
    },
  });
  if (!response.ok) {
    throw new Error(`Pexels API error: ${response.status} ${response.statusText}`);
  }
  return response.json();
}
export async function searchPexelsPhotos(
  query: string,
  options: {
    page?: number;
    per_page?: number;
    orientation?: 'landscape' | 'portrait' | 'square';
    size?: 'large' | 'medium' | 'small';
    color?: string;
  } = {}
): Promise<PexelsSearchResponse> {
  const params = new URLSearchParams({
    query,
    page: String(options.page || 1),
    per_page: String(options.per_page || 20),
  });
  if (options.orientation) params.set('orientation', options.orientation);
  if (options.size) params.set('size', options.size);
  if (options.color) params.set('color', options.color);
  return fetchPexels<PexelsSearchResponse>(`/search?${params}`);
}
export async function getCuratedPhotos(
  options: {
    page?: number;
    per_page?: number;
  } = {}
): Promise<PexelsCuratedResponse> {
  const params = new URLSearchParams({
    page: String(options.page || 1),
    per_page: String(options.per_page || 20),
  });
  return fetchPexels<PexelsCuratedResponse>(`/curated?${params}`);
}
export async function getPhoto(id: number): Promise<PexelsPhoto> {
  return fetchPexels<PexelsPhoto>(`/photos/${id}`);
}
// Predefined categories for quick browsing
export const PEXELS_CATEGORIES = [
  { id: 'technology', label: 'Technology', query: 'technology app' },
  { id: 'business', label: 'Business', query: 'business professional' },
  { id: 'abstract', label: 'Abstract', query: 'abstract gradient' },
  { id: 'nature', label: 'Nature', query: 'nature landscape' },
  { id: 'minimal', label: 'Minimal', query: 'minimal clean' },
  { id: 'lifestyle', label: 'Lifestyle', query: 'lifestyle modern' },
  { id: 'workspace', label: 'Workspace', query: 'workspace desk' },
  { id: 'mobile', label: 'Mobile', query: 'smartphone mobile' },
] as const;