diff --git a/src/modules/command-palette/command-palette.vue b/src/modules/command-palette/command-palette.vue index bceef5cd..5d953fee 100644 --- a/src/modules/command-palette/command-palette.vue +++ b/src/modules/command-palette/command-palette.vue @@ -128,7 +128,7 @@ function activateOption(option: PaletteOption) {
-
+
{{ category }}
diff --git a/src/tools/image-color-inverter/image-color-inverter.e2e.spec.ts b/src/tools/image-color-inverter/image-color-inverter.e2e.spec.ts index a73f9219..a27375e2 100644 --- a/src/tools/image-color-inverter/image-color-inverter.e2e.spec.ts +++ b/src/tools/image-color-inverter/image-color-inverter.e2e.spec.ts @@ -1,6 +1,7 @@ -import { test, expect } from '@playwright/test'; -import { promises as fs } from 'fs'; -import path from 'path'; +import { promises as fs } from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import { expect, test } from '@playwright/test'; test.describe('Tool - Image color inverter', () => { test.beforeEach(async ({ page }) => { @@ -31,7 +32,8 @@ test.describe('Tool - Image color inverter', () => { const errorAlert = page.locator('.n-alert--error'); await expect(errorAlert).toBeVisible(); await expect(errorAlert).toContainText('File must be an image'); - } finally { + } + finally { // Clean up await fs.unlink(testFilePath).catch(() => {}); } @@ -39,12 +41,13 @@ test.describe('Tool - Image color inverter', () => { test('Processes image upload successfully', async ({ page }) => { // Create a simple test image (1x1 pixel PNG in base64) - const testImageDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='; - + const testImageDataUrl + = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='; + // Create a blob from the data URL const response = await fetch(testImageDataUrl); const blob = await response.blob(); - + // Create a temporary file const buffer = await blob.arrayBuffer(); const testFilePath = path.join(process.cwd(), 'test-image.png'); @@ -62,7 +65,7 @@ test.describe('Tool - Image color inverter', () => { // Check that both images are displayed const originalImage = page.locator('text=Original Image'); const invertedImage = page.locator('text=Inverted Image'); - + await expect(originalImage).toBeVisible(); await expect(invertedImage).toBeVisible(); @@ -73,7 +76,8 @@ test.describe('Tool - Image color inverter', () => { // Check that copy button is available const copyButton = page.locator('text=Copy Base64'); await expect(copyButton).toBeVisible(); - } finally { + } + finally { // Clean up await fs.unlink(testFilePath).catch(() => {}); } @@ -81,8 +85,9 @@ test.describe('Tool - Image color inverter', () => { test('Clear button resets the tool', async ({ page }) => { // Create a simple test image - const testImageDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='; - + const testImageDataUrl + = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='; + const response = await fetch(testImageDataUrl); const blob = await response.blob(); const buffer = await blob.arrayBuffer(); @@ -93,7 +98,7 @@ test.describe('Tool - Image color inverter', () => { // Upload and process image const fileInput = page.locator('input[type="file"]'); await fileInput.setInputFiles(testFilePath); - + await page.waitForSelector('text=Inverted Image', { timeout: 5000 }); // Click clear button @@ -103,15 +108,16 @@ test.describe('Tool - Image color inverter', () => { // Check that images are cleared const originalImage = page.locator('text=Original Image'); const invertedImage = page.locator('text=Inverted Image'); - + await expect(originalImage).not.toBeVisible(); await expect(invertedImage).not.toBeVisible(); // Check that upload area is visible again const uploadArea = page.locator('text=Drag and drop an image here, or click to select'); await expect(uploadArea).toBeVisible(); - } finally { + } + finally { await fs.unlink(testFilePath).catch(() => {}); } }); -}); \ No newline at end of file +}); diff --git a/src/tools/image-color-inverter/image-color-inverter.service.test.ts b/src/tools/image-color-inverter/image-color-inverter.service.test.ts index 96869978..ac8c9269 100644 --- a/src/tools/image-color-inverter/image-color-inverter.service.test.ts +++ b/src/tools/image-color-inverter/image-color-inverter.service.test.ts @@ -1,8 +1,8 @@ -import { expect, describe, it, beforeEach } from 'vitest'; +import { describe, expect, it } from 'vitest'; import { invertImageColors } from './image-color-inverter.service'; // Mock ImageData for Node.js environment -Object.defineProperty(global, 'ImageData', { +Object.defineProperty(globalThis, 'ImageData', { value: class ImageData { data: Uint8ClampedArray; width: number; @@ -14,7 +14,8 @@ Object.defineProperty(global, 'ImageData', { this.width = data; this.height = width; this.data = new Uint8ClampedArray(data * width * 4); - } else { + } + else { // ImageData(data, width, height) this.data = data; this.width = width; @@ -25,30 +26,39 @@ Object.defineProperty(global, 'ImageData', { }); // Mock other browser APIs for completeness -Object.defineProperty(global, 'HTMLCanvasElement', { +Object.defineProperty(globalThis, 'HTMLCanvasElement', { value: class { width = 0; height = 0; + getContext() { return { drawImage: () => {}, - getImageData: () => new (global as any).ImageData(new Uint8ClampedArray([255, 0, 128, 255]), 1, 1), + getImageData: () => new (globalThis as any).ImageData(new Uint8ClampedArray([255, 0, 128, 255]), 1, 1), putImageData: () => {}, }; } - toDataURL() { return 'data:image/png;base64,mock'; } + + toDataURL() { + return 'data:image/png;base64,mock'; + } }, }); -Object.defineProperty(global, 'Image', { +Object.defineProperty(globalThis, 'Image', { value: class { onload: () => void = () => {}; onerror: () => void = () => {}; + width = 100; + height = 100; + set src(value: string) { setTimeout(() => this.onload(), 0); } - width = 100; - height = 100; + + get src(): string { + return ''; + } }, }); @@ -57,28 +67,34 @@ describe('image-color-inverter service', () => { it('should invert RGB colors while preserving alpha', () => { // Create test image data with known values const originalData = new Uint8ClampedArray([ - 255, 0, 128, 255, // Red=255, Green=0, Blue=128, Alpha=255 - 0, 255, 64, 128, // Red=0, Green=255, Blue=64, Alpha=128 + 255, + 0, + 128, + 255, // Red=255, Green=0, Blue=128, Alpha=255 + 0, + 255, + 64, + 128, // Red=0, Green=255, Blue=64, Alpha=128 ]); - const imageData = new (global as any).ImageData(originalData, 2, 1); + const imageData = new (globalThis as any).ImageData(originalData, 2, 1); const inverted = invertImageColors(imageData); // Check that colors are inverted correctly - expect(inverted.data[0]).toBe(0); // 255 - 255 = 0 - expect(inverted.data[1]).toBe(255); // 255 - 0 = 255 - expect(inverted.data[2]).toBe(127); // 255 - 128 = 127 - expect(inverted.data[3]).toBe(255); // Alpha unchanged + expect(inverted.data[0]).toBe(0); // 255 - 255 = 0 + expect(inverted.data[1]).toBe(255); // 255 - 0 = 255 + expect(inverted.data[2]).toBe(127); // 255 - 128 = 127 + expect(inverted.data[3]).toBe(255); // Alpha unchanged - expect(inverted.data[4]).toBe(255); // 255 - 0 = 255 - expect(inverted.data[5]).toBe(0); // 255 - 255 = 0 - expect(inverted.data[6]).toBe(191); // 255 - 64 = 191 - expect(inverted.data[7]).toBe(128); // Alpha unchanged + expect(inverted.data[4]).toBe(255); // 255 - 0 = 255 + expect(inverted.data[5]).toBe(0); // 255 - 255 = 0 + expect(inverted.data[6]).toBe(191); // 255 - 64 = 191 + expect(inverted.data[7]).toBe(128); // Alpha unchanged }); it('should preserve image dimensions', () => { const originalData = new Uint8ClampedArray([255, 0, 128, 255]); - const imageData = new (global as any).ImageData(originalData, 1, 1); + const imageData = new (globalThis as any).ImageData(originalData, 1, 1); const inverted = invertImageColors(imageData); @@ -88,10 +104,16 @@ describe('image-color-inverter service', () => { it('should handle pure black and white pixels', () => { const originalData = new Uint8ClampedArray([ - 0, 0, 0, 255, // Pure black - 255, 255, 255, 255, // Pure white + 0, + 0, + 0, + 255, // Pure black + 255, + 255, + 255, + 255, // Pure white ]); - const imageData = new (global as any).ImageData(originalData, 2, 1); + const imageData = new (globalThis as any).ImageData(originalData, 2, 1); const inverted = invertImageColors(imageData); @@ -108,4 +130,4 @@ describe('image-color-inverter service', () => { expect(inverted.data[7]).toBe(255); }); }); -}); \ No newline at end of file +}); diff --git a/src/tools/image-color-inverter/image-color-inverter.service.ts b/src/tools/image-color-inverter/image-color-inverter.service.ts index eac3e918..04fb71dc 100644 --- a/src/tools/image-color-inverter/image-color-inverter.service.ts +++ b/src/tools/image-color-inverter/image-color-inverter.service.ts @@ -14,16 +14,16 @@ export function invertImageFile(file: File): Promise { } const reader = new FileReader(); - + reader.onload = () => { const img = new Image(); img.src = reader.result as string; - + img.onload = () => { try { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); - + if (!ctx) { reject(new Error('Failed to get canvas context')); return; @@ -31,7 +31,7 @@ export function invertImageFile(file: File): Promise { canvas.width = img.width; canvas.height = img.height; - + // Draw the original image ctx.drawImage(img, 0, 0); @@ -41,7 +41,7 @@ export function invertImageFile(file: File): Promise { // Invert colors (RGB channels only, preserve alpha) for (let i = 0; i < data.length; i += 4) { - data[i] = 255 - data[i]; // Red + data[i] = 255 - data[i]; // Red data[i + 1] = 255 - data[i + 1]; // Green data[i + 2] = 255 - data[i + 2]; // Blue // data[i + 3] is alpha - keep unchanged @@ -49,38 +49,39 @@ export function invertImageFile(file: File): Promise { // Put the modified image data back ctx.putImageData(imageData, 0, 0); - + // Convert to base64 PNG const invertedDataUrl = canvas.toDataURL('image/png'); resolve(invertedDataUrl); - } catch (err) { + } + catch (err) { reject(new Error(`Failed to process image: ${err}`)); } }; - + img.onerror = () => { reject(new Error('Failed to load image')); }; }; - + reader.onerror = () => { reject(new Error('Failed to read file')); }; - + reader.readAsDataURL(file); }); } export function invertImageColors(imageData: ImageData): ImageData { const data = new Uint8ClampedArray(imageData.data); - + // Invert RGB values while preserving alpha for (let i = 0; i < data.length; i += 4) { - data[i] = 255 - data[i]; // Red + data[i] = 255 - data[i]; // Red data[i + 1] = 255 - data[i + 1]; // Green data[i + 2] = 255 - data[i + 2]; // Blue // data[i + 3] is alpha - keep unchanged } - + return new ImageData(data, imageData.width, imageData.height); } diff --git a/src/tools/image-color-inverter/image-color-inverter.vue b/src/tools/image-color-inverter/image-color-inverter.vue index d0999e28..d6a783cc 100644 --- a/src/tools/image-color-inverter/image-color-inverter.vue +++ b/src/tools/image-color-inverter/image-color-inverter.vue @@ -1,17 +1,17 @@