feat: add tool popularity and icons
This commit is contained in:
@@ -21,5 +21,8 @@
|
|||||||
"typescript": "^6.0.3",
|
"typescript": "^6.0.3",
|
||||||
"vite": "^8.0.16",
|
"vite": "^8.0.16",
|
||||||
"vitest": "^4.1.11"
|
"vitest": "^4.1.11"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@lucide/svelte": "^1.33.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+13
@@ -7,6 +7,10 @@ settings:
|
|||||||
importers:
|
importers:
|
||||||
|
|
||||||
.:
|
.:
|
||||||
|
dependencies:
|
||||||
|
'@lucide/svelte':
|
||||||
|
specifier: ^1.33.0
|
||||||
|
version: 1.33.0(svelte@5.56.9)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@sveltejs/adapter-static':
|
'@sveltejs/adapter-static':
|
||||||
specifier: ^3.0.10
|
specifier: ^3.0.10
|
||||||
@@ -51,6 +55,11 @@ packages:
|
|||||||
'@jridgewell/trace-mapping@0.3.31':
|
'@jridgewell/trace-mapping@0.3.31':
|
||||||
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
||||||
|
|
||||||
|
'@lucide/svelte@1.33.0':
|
||||||
|
resolution: {integrity: sha512-b+osTYG2V4dge5Lr7tnaTaahhy/4vH7Xb8zcqVjmctjwgkpXS0NNOJPkGzHHZoxtw/OO+2YAU28omeMfYCaawg==}
|
||||||
|
peerDependencies:
|
||||||
|
svelte: ^5
|
||||||
|
|
||||||
'@oxc-project/types@0.144.0':
|
'@oxc-project/types@0.144.0':
|
||||||
resolution: {integrity: sha512-nuhZIOLuI6TFQ32I/WnUx+SCPY7SdSKwgnFHydAuoS1+Z4BRcaP+RRJmGzl9lw+0OFF7UmaESf7KQRXaNLHypg==}
|
resolution: {integrity: sha512-nuhZIOLuI6TFQ32I/WnUx+SCPY7SdSKwgnFHydAuoS1+Z4BRcaP+RRJmGzl9lw+0OFF7UmaESf7KQRXaNLHypg==}
|
||||||
|
|
||||||
@@ -627,6 +636,10 @@ snapshots:
|
|||||||
'@jridgewell/resolve-uri': 3.1.2
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
|
'@lucide/svelte@1.33.0(svelte@5.56.9)':
|
||||||
|
dependencies:
|
||||||
|
svelte: 5.56.9
|
||||||
|
|
||||||
'@oxc-project/types@0.144.0': {}
|
'@oxc-project/types@0.144.0': {}
|
||||||
|
|
||||||
'@polka/url@1.0.0-next.29': {}
|
'@polka/url@1.0.0-next.29': {}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { describe, expect, it } from 'vitest';
|
import { describe, expect, it } from 'vitest';
|
||||||
import { CATEGORIES } from './categories';
|
import { CATEGORIES } from './categories';
|
||||||
|
import { TOOL_ICONS } from './tools/tool-icons';
|
||||||
import {
|
import {
|
||||||
defaultParams,
|
defaultParams,
|
||||||
getTool,
|
getTool,
|
||||||
@@ -150,6 +151,21 @@ describe('реестр инструментов', () => {
|
|||||||
const resize = getToolOrThrow('resize-png');
|
const resize = getToolOrThrow('resize-png');
|
||||||
expect(defaultParams(resize)).toEqual({ width: 0, height: 0, keepAspect: true });
|
expect(defaultParams(resize)).toEqual({ width: 0, height: 0, keepAspect: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('словарь иконок покрывает все инструменты', () => {
|
||||||
|
for (const tool of TOOLS) {
|
||||||
|
expect(TOOL_ICONS[tool.id]).toBeDefined();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('у каждого инструмента популярность в диапазоне 0..100 и ключ иконки', () => {
|
||||||
|
for (const tool of TOOLS) {
|
||||||
|
expect(tool.popularity).toBeGreaterThanOrEqual(0);
|
||||||
|
expect(tool.popularity).toBeLessThanOrEqual(100);
|
||||||
|
expect(typeof tool.icon).toBe('string');
|
||||||
|
expect(tool.icon!.length).toBeGreaterThan(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('sanitizeParams', () => {
|
describe('sanitizeParams', () => {
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ export type ToolEntry = {
|
|||||||
img: PixelImage,
|
img: PixelImage,
|
||||||
params: Record<string, unknown>
|
params: Record<string, unknown>
|
||||||
) => Promise<PixelImage> | PixelImage;
|
) => Promise<PixelImage> | PixelImage;
|
||||||
|
popularity?: number;
|
||||||
|
icon?: string;
|
||||||
resultType?: 'image' | 'info' | 'text';
|
resultType?: 'image' | 'info' | 'text';
|
||||||
output?: OutputFormat;
|
output?: OutputFormat;
|
||||||
};
|
};
|
||||||
@@ -803,6 +805,14 @@ export const TOOLS: ToolEntry[] = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
import { TOOL_ICONS } from './tools/tool-icons';
|
||||||
|
import { TOOL_POPULARITY } from './tools/tool-popularity';
|
||||||
|
|
||||||
|
for (const entry of TOOLS) {
|
||||||
|
entry.icon = entry.id;
|
||||||
|
entry.popularity = TOOL_POPULARITY[entry.id] ?? 50;
|
||||||
|
}
|
||||||
|
|
||||||
export function getTool(id: string): ToolEntry | undefined {
|
export function getTool(id: string): ToolEntry | undefined {
|
||||||
return TOOLS.find((tool) => tool.id === id);
|
return TOOLS.find((tool) => tool.id === id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
import {
|
||||||
|
AppWindow,
|
||||||
|
Binary,
|
||||||
|
Blend,
|
||||||
|
ClipboardPaste,
|
||||||
|
Contrast,
|
||||||
|
Crop,
|
||||||
|
Crosshair,
|
||||||
|
Dices,
|
||||||
|
Droplet,
|
||||||
|
Droplets,
|
||||||
|
Eye,
|
||||||
|
FileImage,
|
||||||
|
FileOutput,
|
||||||
|
FilePlus2,
|
||||||
|
Film,
|
||||||
|
FlipHorizontal2,
|
||||||
|
Focus,
|
||||||
|
Frame,
|
||||||
|
Grid3x3,
|
||||||
|
Hash,
|
||||||
|
Image as ImageIcon,
|
||||||
|
Info,
|
||||||
|
Layers,
|
||||||
|
Link2,
|
||||||
|
Maximize2,
|
||||||
|
PaintBucket,
|
||||||
|
Palette,
|
||||||
|
Rainbow,
|
||||||
|
Repeat2,
|
||||||
|
RotateCw,
|
||||||
|
Ruler,
|
||||||
|
Scaling,
|
||||||
|
Scissors,
|
||||||
|
SearchCheck,
|
||||||
|
Square,
|
||||||
|
Sun
|
||||||
|
} from '@lucide/svelte';
|
||||||
|
|
||||||
|
export const TOOL_ICONS: Record<string, typeof AppWindow> = {
|
||||||
|
'resize-png': Scaling,
|
||||||
|
'crop-png': Crop,
|
||||||
|
'rotate-png': RotateCw,
|
||||||
|
'flip-png': FlipHorizontal2,
|
||||||
|
'grayscale-png': Contrast,
|
||||||
|
'invert-colors-png': Blend,
|
||||||
|
'adjust-brightness-contrast-png': Sun,
|
||||||
|
'convert-png-to-jpg': FileImage,
|
||||||
|
'convert-png-to-webp': FileImage,
|
||||||
|
'remove-color-from-png': Scissors,
|
||||||
|
'png-info': Info,
|
||||||
|
'jpg-to-png': FileImage,
|
||||||
|
'webp-to-png': FileImage,
|
||||||
|
'gif-to-png': Film,
|
||||||
|
'bmp-to-png': FileImage,
|
||||||
|
'ico-to-png': AppWindow,
|
||||||
|
'png-to-bmp': FileOutput,
|
||||||
|
'png-to-base64': Binary,
|
||||||
|
'base64-to-png': ClipboardPaste,
|
||||||
|
'png-to-data-uri': Link2,
|
||||||
|
'data-uri-to-png': ClipboardPaste,
|
||||||
|
'png-to-hex': Hash,
|
||||||
|
'hex-to-png': Hash,
|
||||||
|
'change-png-opacity': Droplet,
|
||||||
|
'sepia-png': Palette,
|
||||||
|
'change-png-hue': Rainbow,
|
||||||
|
'extract-channel-png': Layers,
|
||||||
|
'swap-channels-png': Repeat2,
|
||||||
|
'black-and-white-png': Contrast,
|
||||||
|
'posterize-png': Layers,
|
||||||
|
'two-colors-png': Blend,
|
||||||
|
'invert-alpha-png': Droplets,
|
||||||
|
'remove-alpha-channel-png': Square,
|
||||||
|
'set-alpha-channel-png': Droplet,
|
||||||
|
'extract-alpha-mask-png': Layers,
|
||||||
|
'round-corners-png': Frame,
|
||||||
|
'add-padding-png': Maximize2,
|
||||||
|
'add-border-png': Frame,
|
||||||
|
'fit-on-background-png': ImageIcon,
|
||||||
|
'tile-png': Grid3x3,
|
||||||
|
'center-by-alpha-png': Crosshair,
|
||||||
|
'create-empty-png': FilePlus2,
|
||||||
|
'single-color-png': PaintBucket,
|
||||||
|
'random-noise-png': Dices,
|
||||||
|
'linear-gradient-png': Sun,
|
||||||
|
'png-is-grayscale': SearchCheck,
|
||||||
|
'png-is-transparent': Eye,
|
||||||
|
'png-orientation': Ruler,
|
||||||
|
'blur-png': Droplets,
|
||||||
|
'sharpen-png': Focus,
|
||||||
|
'remove-background-png': Scissors
|
||||||
|
};
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
export const TOOL_POPULARITY: Record<string, number> = {
|
||||||
|
'crop-png': 92,
|
||||||
|
'resize-png': 90,
|
||||||
|
'remove-background-png': 95,
|
||||||
|
'blur-png': 85,
|
||||||
|
'sharpen-png': 80,
|
||||||
|
'convert-png-to-jpg': 82,
|
||||||
|
'jpg-to-png': 78,
|
||||||
|
'rotate-png': 75,
|
||||||
|
'flip-png': 70,
|
||||||
|
'convert-png-to-webp': 68,
|
||||||
|
'webp-to-png': 62,
|
||||||
|
'grayscale-png': 60,
|
||||||
|
'adjust-brightness-contrast-png': 58,
|
||||||
|
'invert-colors-png': 52,
|
||||||
|
'remove-color-from-png': 65,
|
||||||
|
'change-png-opacity': 45,
|
||||||
|
'sepia-png': 40,
|
||||||
|
'change-png-hue': 38,
|
||||||
|
'add-padding-png': 42,
|
||||||
|
'add-border-png': 38,
|
||||||
|
'two-colors-png': 35,
|
||||||
|
'black-and-white-png': 42,
|
||||||
|
'posterize-png': 30,
|
||||||
|
'round-corners-png': 36,
|
||||||
|
'fit-on-background-png': 34,
|
||||||
|
'extract-channel-png': 24,
|
||||||
|
'swap-channels-png': 22,
|
||||||
|
'invert-alpha-png': 26,
|
||||||
|
'remove-alpha-channel-png': 30,
|
||||||
|
'set-alpha-channel-png': 24,
|
||||||
|
'extract-alpha-mask-png': 20,
|
||||||
|
'tile-png': 28,
|
||||||
|
'center-by-alpha-png': 26,
|
||||||
|
'png-info': 44,
|
||||||
|
'png-is-transparent': 18,
|
||||||
|
'png-is-grayscale': 14,
|
||||||
|
'png-orientation': 16,
|
||||||
|
'png-to-base64': 40,
|
||||||
|
'base64-to-png': 32,
|
||||||
|
'png-to-data-uri': 34,
|
||||||
|
'data-uri-to-png': 26,
|
||||||
|
'png-to-hex': 10,
|
||||||
|
'hex-to-png': 8,
|
||||||
|
'gif-to-png': 30,
|
||||||
|
'bmp-to-png': 18,
|
||||||
|
'ico-to-png': 20,
|
||||||
|
'png-to-bmp': 12,
|
||||||
|
'create-empty-png': 25,
|
||||||
|
'single-color-png': 20,
|
||||||
|
'random-noise-png': 12,
|
||||||
|
'linear-gradient-png': 22
|
||||||
|
};
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
||||||
import { defineConfig } from 'vitest/config';
|
import { defineConfig } from 'vitest/config';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
plugins: [svelte()],
|
||||||
test: {
|
test: {
|
||||||
include: ['src/**/*.test.ts'],
|
include: ['src/**/*.test.ts'],
|
||||||
environment: 'node'
|
environment: 'node'
|
||||||
|
|||||||
Reference in New Issue
Block a user