87 lines
2.5 KiB
TypeScript
87 lines
2.5 KiB
TypeScript
import { resizeImage } from '../media/converters/imagemagickService';
|
|
import type { FaviconIcon, FaviconSet, FaviconOptions } from '@/types/favicon';
|
|
|
|
export const ICON_CONFIGS = [
|
|
{ name: 'favicon-16x16.png', width: 16, height: 16 },
|
|
{ name: 'favicon-32x32.png', width: 32, height: 32 },
|
|
{ name: 'apple-touch-icon.png', width: 180, height: 180 },
|
|
{ name: 'android-chrome-192x192.png', width: 192, height: 192 },
|
|
{ name: 'android-chrome-512x512.png', width: 512, height: 512 },
|
|
{ name: 'favicon.ico', width: 48, height: 48 }, // Simple ICO fallback
|
|
];
|
|
|
|
export async function generateFaviconSet(
|
|
file: File,
|
|
options: FaviconOptions,
|
|
onProgress?: (progress: number) => void
|
|
): Promise<FaviconSet> {
|
|
const icons: FaviconIcon[] = [];
|
|
const totalSteps = ICON_CONFIGS.length;
|
|
|
|
for (let i = 0; i < ICON_CONFIGS.length; i++) {
|
|
const config = ICON_CONFIGS[i];
|
|
const format = config.name.endsWith('.ico') ? 'ico' : 'png';
|
|
|
|
const result = await resizeImage(file, config.width, config.height, format);
|
|
|
|
if (result.success && result.blob) {
|
|
icons.push({
|
|
name: config.name,
|
|
width: config.width,
|
|
height: config.height,
|
|
size: result.blob.size,
|
|
blob: result.blob,
|
|
previewUrl: URL.createObjectURL(result.blob),
|
|
});
|
|
}
|
|
|
|
if (onProgress) {
|
|
onProgress(Math.round(((i + 1) / totalSteps) * 100));
|
|
}
|
|
}
|
|
|
|
const manifest = generateManifest(options);
|
|
const htmlCode = generateHtmlCode(options);
|
|
|
|
return {
|
|
icons,
|
|
manifest,
|
|
htmlCode,
|
|
};
|
|
}
|
|
|
|
function generateManifest(options: FaviconOptions): string {
|
|
const manifest = {
|
|
name: options.name,
|
|
short_name: options.shortName,
|
|
icons: [
|
|
{
|
|
src: '/android-chrome-192x192.png',
|
|
sizes: '192x192',
|
|
type: 'image/png',
|
|
},
|
|
{
|
|
src: '/android-chrome-512x512.png',
|
|
sizes: '512x512',
|
|
type: 'image/png',
|
|
},
|
|
],
|
|
theme_color: options.themeColor,
|
|
background_color: options.backgroundColor,
|
|
display: 'standalone',
|
|
};
|
|
|
|
return JSON.stringify(manifest, null, 2);
|
|
}
|
|
|
|
function generateHtmlCode(options: FaviconOptions): string {
|
|
return `
|
|
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
|
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
|
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
|
<link rel="manifest" href="/site.webmanifest">
|
|
<meta name="msapplication-TileColor" content="${options.backgroundColor}">
|
|
<meta name="theme-color" content="${options.themeColor}">
|
|
`.trim();
|
|
}
|