Fix API response format mismatches and implement all remaining features: **API Integration Fixes:** - Fix ManipulationPanel to use `colors` instead of `results` from API responses - Fix gradient endpoint to use `gradient` array from API response - Fix color blindness simulator to use correct field names (`input`/`output` vs `original`/`simulated`) - Fix text color optimizer request field (`backgrounds` vs `background_colors`) - Fix method name casing: `simulateColorBlindness` (capital B) - Add palette generation endpoint integration **Type Definition Updates:** - Update GradientData to match API structure with `gradient` array - Update ColorBlindnessData to use `colors` with `input`/`output`/`difference_percentage` - Update TextColorData to use `colors` with `textcolor`/`wcag_aa`/`wcag_aaa` fields - Add PaletteGenerateRequest and PaletteGenerateData types **Completed Features:** - Harmony Palettes: Now uses dedicated `/palettes/generate` API endpoint - Simplified from 80 lines of manual color theory to single API call - Supports 6 harmony types: monochromatic, analogous, complementary, split-complementary, triadic, tetradic - Text Color Optimizer: Full implementation with WCAG compliance checking - Automatic black/white text color selection - Live preview with contrast ratios - AA/AAA compliance indicators - Color Blindness Simulator: Fixed and working - Shows difference percentage for each simulation - Side-by-side comparison view - Gradient Creator: Fixed to use correct API response structure - Batch Operations: Fixed to extract output colors correctly **UI Improvements:** - Enable all accessibility tool cards (remove "Coming Soon" badges) - Enable harmony palettes card - Add safety check for gradient state to prevent undefined errors All features now fully functional and properly integrated with Pastel API. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
243 lines
6.7 KiB
TypeScript
243 lines
6.7 KiB
TypeScript
import type {
|
|
ApiResponse,
|
|
ColorInfoRequest,
|
|
ColorInfoData,
|
|
ConvertFormatRequest,
|
|
ConvertFormatData,
|
|
ColorManipulationRequest,
|
|
ColorManipulationData,
|
|
ColorMixRequest,
|
|
ColorMixData,
|
|
RandomColorsRequest,
|
|
RandomColorsData,
|
|
DistinctColorsRequest,
|
|
DistinctColorsData,
|
|
GradientRequest,
|
|
GradientData,
|
|
ColorDistanceRequest,
|
|
ColorDistanceData,
|
|
ColorSortRequest,
|
|
ColorSortData,
|
|
ColorBlindnessRequest,
|
|
ColorBlindnessData,
|
|
TextColorRequest,
|
|
TextColorData,
|
|
NamedColorsData,
|
|
NamedColorSearchRequest,
|
|
NamedColorSearchData,
|
|
HealthData,
|
|
CapabilitiesData,
|
|
PaletteGenerateRequest,
|
|
PaletteGenerateData,
|
|
} from './types';
|
|
|
|
export class PastelAPIClient {
|
|
private baseURL: string;
|
|
|
|
constructor(baseURL?: string) {
|
|
this.baseURL = baseURL || process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000';
|
|
}
|
|
|
|
private async request<T>(
|
|
endpoint: string,
|
|
options?: RequestInit
|
|
): Promise<ApiResponse<T>> {
|
|
const url = `${this.baseURL}/api/v1${endpoint}`;
|
|
|
|
try {
|
|
const response = await fetch(url, {
|
|
...options,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
...options?.headers,
|
|
},
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (!response.ok) {
|
|
return {
|
|
success: false,
|
|
error: data.error || {
|
|
code: 'INTERNAL_ERROR',
|
|
message: 'An unknown error occurred',
|
|
},
|
|
};
|
|
}
|
|
|
|
return data;
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
error: {
|
|
code: 'NETWORK_ERROR',
|
|
message: error instanceof Error ? error.message : 'Network request failed',
|
|
},
|
|
};
|
|
}
|
|
}
|
|
|
|
// Color Information
|
|
async getColorInfo(request: ColorInfoRequest): Promise<ApiResponse<ColorInfoData>> {
|
|
return this.request<ColorInfoData>('/colors/info', {
|
|
method: 'POST',
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|
|
|
|
// Format Conversion
|
|
async convertFormat(request: ConvertFormatRequest): Promise<ApiResponse<ConvertFormatData>> {
|
|
return this.request<ConvertFormatData>('/colors/convert', {
|
|
method: 'POST',
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|
|
|
|
// Color Manipulation
|
|
async lighten(request: ColorManipulationRequest): Promise<ApiResponse<ColorManipulationData>> {
|
|
return this.request<ColorManipulationData>('/colors/lighten', {
|
|
method: 'POST',
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|
|
|
|
async darken(request: ColorManipulationRequest): Promise<ApiResponse<ColorManipulationData>> {
|
|
return this.request<ColorManipulationData>('/colors/darken', {
|
|
method: 'POST',
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|
|
|
|
async saturate(request: ColorManipulationRequest): Promise<ApiResponse<ColorManipulationData>> {
|
|
return this.request<ColorManipulationData>('/colors/saturate', {
|
|
method: 'POST',
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|
|
|
|
async desaturate(request: ColorManipulationRequest): Promise<ApiResponse<ColorManipulationData>> {
|
|
return this.request<ColorManipulationData>('/colors/desaturate', {
|
|
method: 'POST',
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|
|
|
|
async rotate(request: ColorManipulationRequest): Promise<ApiResponse<ColorManipulationData>> {
|
|
return this.request<ColorManipulationData>('/colors/rotate', {
|
|
method: 'POST',
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|
|
|
|
async complement(colors: string[]): Promise<ApiResponse<ColorManipulationData>> {
|
|
return this.request<ColorManipulationData>('/colors/complement', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ colors }),
|
|
});
|
|
}
|
|
|
|
async grayscale(colors: string[]): Promise<ApiResponse<ColorManipulationData>> {
|
|
return this.request<ColorManipulationData>('/colors/grayscale', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ colors }),
|
|
});
|
|
}
|
|
|
|
async mix(request: ColorMixRequest): Promise<ApiResponse<ColorMixData>> {
|
|
return this.request<ColorMixData>('/colors/mix', {
|
|
method: 'POST',
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|
|
|
|
// Color Generation
|
|
async generateRandom(request: RandomColorsRequest): Promise<ApiResponse<RandomColorsData>> {
|
|
return this.request<RandomColorsData>('/colors/random', {
|
|
method: 'POST',
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|
|
|
|
async generateDistinct(request: DistinctColorsRequest): Promise<ApiResponse<DistinctColorsData>> {
|
|
return this.request<DistinctColorsData>('/colors/distinct', {
|
|
method: 'POST',
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|
|
|
|
async generateGradient(request: GradientRequest): Promise<ApiResponse<GradientData>> {
|
|
return this.request<GradientData>('/colors/gradient', {
|
|
method: 'POST',
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|
|
|
|
// Color Analysis
|
|
async calculateDistance(request: ColorDistanceRequest): Promise<ApiResponse<ColorDistanceData>> {
|
|
return this.request<ColorDistanceData>('/colors/distance', {
|
|
method: 'POST',
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|
|
|
|
async sortColors(request: ColorSortRequest): Promise<ApiResponse<ColorSortData>> {
|
|
return this.request<ColorSortData>('/colors/sort', {
|
|
method: 'POST',
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|
|
|
|
// Accessibility
|
|
async simulateColorBlindness(request: ColorBlindnessRequest): Promise<ApiResponse<ColorBlindnessData>> {
|
|
return this.request<ColorBlindnessData>('/colors/colorblind', {
|
|
method: 'POST',
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|
|
|
|
async getTextColor(request: TextColorRequest): Promise<ApiResponse<TextColorData>> {
|
|
return this.request<TextColorData>('/colors/textcolor', {
|
|
method: 'POST',
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|
|
|
|
// Named Colors
|
|
async getNamedColors(): Promise<ApiResponse<NamedColorsData>> {
|
|
return this.request<NamedColorsData>('/colors/names', {
|
|
method: 'GET',
|
|
});
|
|
}
|
|
|
|
async searchNamedColors(request: NamedColorSearchRequest): Promise<ApiResponse<NamedColorSearchData>> {
|
|
return this.request<NamedColorSearchData>('/colors/names/search', {
|
|
method: 'POST',
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|
|
|
|
// System
|
|
async getHealth(): Promise<ApiResponse<HealthData>> {
|
|
return this.request<HealthData>('/health', {
|
|
method: 'GET',
|
|
});
|
|
}
|
|
|
|
async getCapabilities(): Promise<ApiResponse<CapabilitiesData>> {
|
|
return this.request<CapabilitiesData>('/capabilities', {
|
|
method: 'GET',
|
|
});
|
|
}
|
|
|
|
// Palette Generation
|
|
async generatePalette(request: PaletteGenerateRequest): Promise<ApiResponse<PaletteGenerateData>> {
|
|
return this.request<PaletteGenerateData>('/palettes/generate', {
|
|
method: 'POST',
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|
|
}
|
|
|
|
// Export singleton instance
|
|
export const pastelAPI = new PastelAPIClient();
|