Add complete color manipulation interface: **Color Components:** - ColorPicker - Interactive hex color picker with text input - Uses react-colorful for visual selection - Manual input support for any color format - Real-time updates - ColorDisplay - Large color preview swatch - Configurable sizes (sm, md, lg, xl) - Optional border styling - Accessible with ARIA labels - ColorInfo - Comprehensive color information display - Shows all formats: Hex, RGB, HSL, Lab, OkLab - Copy to clipboard functionality for each format - Displays brightness, luminance, light/dark type - Shows named color matches **API Integration:** - React Query hooks for all Pastel API endpoints - useColorInfo - Get color information - useConvertFormat - Format conversion - useLighten, useDarken, useSaturate, etc. - Manipulations - useGenerateRandom, useGenerateDistinct, useGenerateGradient - useNamedColors - Cached named colors list - Automatic error handling and loading states **Playground Page (/playground):** - Two-column layout: picker + info - Live color preview with large swatch - Real-time API integration with loading states - Error handling with user-friendly messages - Quick action buttons (ready for implementation) - Responsive grid layout **Features:** - Toast notifications for clipboard copy - Loading spinners during API calls - Error display with helpful messages - Accessible keyboard navigation - Smooth transitions and animations Build successful with playground page rendering! Ready for color manipulation actions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
207 lines
5.1 KiB
TypeScript
207 lines
5.1 KiB
TypeScript
'use client';
|
|
|
|
import { useQuery, useMutation, UseQueryOptions } from '@tanstack/react-query';
|
|
import { pastelAPI } from './client';
|
|
import type {
|
|
ColorInfoRequest,
|
|
ColorInfoData,
|
|
ConvertFormatRequest,
|
|
ConvertFormatData,
|
|
ColorManipulationRequest,
|
|
ColorManipulationData,
|
|
ColorMixRequest,
|
|
ColorMixData,
|
|
RandomColorsRequest,
|
|
RandomColorsData,
|
|
DistinctColorsRequest,
|
|
DistinctColorsData,
|
|
GradientRequest,
|
|
GradientData,
|
|
NamedColorsData,
|
|
HealthData,
|
|
} from './types';
|
|
|
|
// Color Information
|
|
export const useColorInfo = (
|
|
request: ColorInfoRequest,
|
|
options?: Omit<UseQueryOptions<ColorInfoData>, 'queryKey' | 'queryFn'>
|
|
) => {
|
|
return useQuery({
|
|
queryKey: ['colorInfo', request.colors],
|
|
queryFn: async () => {
|
|
const response = await pastelAPI.getColorInfo(request);
|
|
if (!response.success) {
|
|
throw new Error(response.error.message);
|
|
}
|
|
return response.data;
|
|
},
|
|
enabled: request.colors.length > 0 && request.colors.every((c) => c.length > 0),
|
|
...options,
|
|
});
|
|
};
|
|
|
|
// Format Conversion
|
|
export const useConvertFormat = () => {
|
|
return useMutation({
|
|
mutationFn: async (request: ConvertFormatRequest) => {
|
|
const response = await pastelAPI.convertFormat(request);
|
|
if (!response.success) {
|
|
throw new Error(response.error.message);
|
|
}
|
|
return response.data;
|
|
},
|
|
});
|
|
};
|
|
|
|
// Color Manipulation
|
|
export const useLighten = () => {
|
|
return useMutation({
|
|
mutationFn: async (request: ColorManipulationRequest) => {
|
|
const response = await pastelAPI.lighten(request);
|
|
if (!response.success) {
|
|
throw new Error(response.error.message);
|
|
}
|
|
return response.data;
|
|
},
|
|
});
|
|
};
|
|
|
|
export const useDarken = () => {
|
|
return useMutation({
|
|
mutationFn: async (request: ColorManipulationRequest) => {
|
|
const response = await pastelAPI.darken(request);
|
|
if (!response.success) {
|
|
throw new Error(response.error.message);
|
|
}
|
|
return response.data;
|
|
},
|
|
});
|
|
};
|
|
|
|
export const useSaturate = () => {
|
|
return useMutation({
|
|
mutationFn: async (request: ColorManipulationRequest) => {
|
|
const response = await pastelAPI.saturate(request);
|
|
if (!response.success) {
|
|
throw new Error(response.error.message);
|
|
}
|
|
return response.data;
|
|
},
|
|
});
|
|
};
|
|
|
|
export const useDesaturate = () => {
|
|
return useMutation({
|
|
mutationFn: async (request: ColorManipulationRequest) => {
|
|
const response = await pastelAPI.desaturate(request);
|
|
if (!response.success) {
|
|
throw new Error(response.error.message);
|
|
}
|
|
return response.data;
|
|
},
|
|
});
|
|
};
|
|
|
|
export const useRotate = () => {
|
|
return useMutation({
|
|
mutationFn: async (request: ColorManipulationRequest) => {
|
|
const response = await pastelAPI.rotate(request);
|
|
if (!response.success) {
|
|
throw new Error(response.error.message);
|
|
}
|
|
return response.data;
|
|
},
|
|
});
|
|
};
|
|
|
|
export const useComplement = () => {
|
|
return useMutation({
|
|
mutationFn: async (colors: string[]) => {
|
|
const response = await pastelAPI.complement(colors);
|
|
if (!response.success) {
|
|
throw new Error(response.error.message);
|
|
}
|
|
return response.data;
|
|
},
|
|
});
|
|
};
|
|
|
|
export const useMixColors = () => {
|
|
return useMutation({
|
|
mutationFn: async (request: ColorMixRequest) => {
|
|
const response = await pastelAPI.mix(request);
|
|
if (!response.success) {
|
|
throw new Error(response.error.message);
|
|
}
|
|
return response.data;
|
|
},
|
|
});
|
|
};
|
|
|
|
// Color Generation
|
|
export const useGenerateRandom = () => {
|
|
return useMutation({
|
|
mutationFn: async (request: RandomColorsRequest) => {
|
|
const response = await pastelAPI.generateRandom(request);
|
|
if (!response.success) {
|
|
throw new Error(response.error.message);
|
|
}
|
|
return response.data;
|
|
},
|
|
});
|
|
};
|
|
|
|
export const useGenerateDistinct = () => {
|
|
return useMutation({
|
|
mutationFn: async (request: DistinctColorsRequest) => {
|
|
const response = await pastelAPI.generateDistinct(request);
|
|
if (!response.success) {
|
|
throw new Error(response.error.message);
|
|
}
|
|
return response.data;
|
|
},
|
|
});
|
|
};
|
|
|
|
export const useGenerateGradient = () => {
|
|
return useMutation({
|
|
mutationFn: async (request: GradientRequest) => {
|
|
const response = await pastelAPI.generateGradient(request);
|
|
if (!response.success) {
|
|
throw new Error(response.error.message);
|
|
}
|
|
return response.data;
|
|
},
|
|
});
|
|
};
|
|
|
|
// Named Colors
|
|
export const useNamedColors = () => {
|
|
return useQuery({
|
|
queryKey: ['namedColors'],
|
|
queryFn: async () => {
|
|
const response = await pastelAPI.getNamedColors();
|
|
if (!response.success) {
|
|
throw new Error(response.error.message);
|
|
}
|
|
return response.data;
|
|
},
|
|
staleTime: Infinity, // Named colors never change
|
|
});
|
|
};
|
|
|
|
// Health Check
|
|
export const useHealth = () => {
|
|
return useQuery({
|
|
queryKey: ['health'],
|
|
queryFn: async () => {
|
|
const response = await pastelAPI.getHealth();
|
|
if (!response.success) {
|
|
throw new Error(response.error.message);
|
|
}
|
|
return response.data;
|
|
},
|
|
refetchInterval: 60000, // Check every minute
|
|
});
|
|
};
|