2026-01-10 21:46:54 +03:00
|
|
|
|
// Скрипт для генерации базовых PWA иконок
|
|
|
|
|
|
// Требует: npm install sharp
|
|
|
|
|
|
|
|
|
|
|
|
const sharp = require('sharp');
|
|
|
|
|
|
const fs = require('fs');
|
|
|
|
|
|
const path = require('path');
|
|
|
|
|
|
|
|
|
|
|
|
const publicDir = path.join(__dirname, 'public');
|
|
|
|
|
|
|
2026-01-11 14:55:11 +03:00
|
|
|
|
// Создаем SVG шаблон для обычной иконки (со скругленными углами)
|
2026-01-10 21:46:54 +03:00
|
|
|
|
const createIconSVG = (size) => `
|
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 100 100">
|
|
|
|
|
|
<defs>
|
|
|
|
|
|
<linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
|
|
|
|
<stop offset="0%" style="stop-color:#4f46e5;stop-opacity:1" />
|
|
|
|
|
|
<stop offset="100%" style="stop-color:#7c3aed;stop-opacity:1" />
|
|
|
|
|
|
</linearGradient>
|
|
|
|
|
|
</defs>
|
|
|
|
|
|
<rect width="100" height="100" rx="20" fill="url(#grad)"/>
|
2026-01-20 00:24:07 +03:00
|
|
|
|
<g transform="translate(50, 47) scale(0.136701675) translate(-488, -488)">
|
2026-01-19 22:48:55 +03:00
|
|
|
|
<path fill="white" d="M442 730V349h55c13 0 26-1 38 3 19 6 33 22 39 41 3 8 5 15 4 24a65 65 0 0 1-29 49c-2 2-6 3-7 6-1 5 4 13 6 17 3 12 4 24 4 36 10-2 19-8 27-13 57-36 69-114 33-168-16-24-45-44-73-49-22-4-46 0-69-1h-38c-9 0-18-1-26 3-9 3-17 15-18 24v358c0 11-1 23 4 33 9 21 31 18 50 18m28-254v254h105c14 0 33 3 46-4 18-11 16-40-3-48-9-4-21-2-31-2h-63V546c0-17 4-40-6-55-11-16-31-15-48-15z"/>
|
|
|
|
|
|
</g>
|
2026-01-10 21:46:54 +03:00
|
|
|
|
</svg>
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
2026-01-11 14:55:11 +03:00
|
|
|
|
// Создаем SVG шаблон для maskable иконки (без скругления, контент в безопасной зоне 80%)
|
|
|
|
|
|
const createMaskableIconSVG = (size) => `
|
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 100 100">
|
|
|
|
|
|
<defs>
|
|
|
|
|
|
<linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
|
|
|
|
<stop offset="0%" style="stop-color:#4f46e5;stop-opacity:1" />
|
|
|
|
|
|
<stop offset="100%" style="stop-color:#7c3aed;stop-opacity:1" />
|
|
|
|
|
|
</linearGradient>
|
|
|
|
|
|
</defs>
|
|
|
|
|
|
<rect width="100" height="100" fill="url(#grad)"/>
|
2026-01-20 00:24:07 +03:00
|
|
|
|
<g transform="translate(50, 47) scale(0.1139180625) translate(-501, -501)">
|
2026-01-19 22:48:55 +03:00
|
|
|
|
<path fill="white" d="M442 730V349h55c13 0 26-1 38 3 19 6 33 22 39 41 3 8 5 15 4 24a65 65 0 0 1-29 49c-2 2-6 3-7 6-1 5 4 13 6 17 3 12 4 24 4 36 10-2 19-8 27-13 57-36 69-114 33-168-16-24-45-44-73-49-22-4-46 0-69-1h-38c-9 0-18-1-26 3-9 3-17 15-18 24v358c0 11-1 23 4 33 9 21 31 18 50 18m28-254v254h105c14 0 33 3 46-4 18-11 16-40-3-48-9-4-21-2-31-2h-63V546c0-17 4-40-6-55-11-16-31-15-48-15z"/>
|
|
|
|
|
|
</g>
|
2026-01-11 14:55:11 +03:00
|
|
|
|
</svg>
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
2026-01-10 21:46:54 +03:00
|
|
|
|
async function generateIcons() {
|
2026-01-11 14:55:11 +03:00
|
|
|
|
// Создаем базовые SVG
|
2026-01-10 21:46:54 +03:00
|
|
|
|
const baseSVG = createIconSVG(512);
|
|
|
|
|
|
const svgBuffer = Buffer.from(baseSVG);
|
2026-01-11 14:55:11 +03:00
|
|
|
|
|
|
|
|
|
|
const maskableSVG = createMaskableIconSVG(512);
|
|
|
|
|
|
const maskableSvgBuffer = Buffer.from(maskableSVG);
|
2026-01-10 21:46:54 +03:00
|
|
|
|
|
|
|
|
|
|
// Генерируем иконки разных размеров
|
|
|
|
|
|
const sizes = [
|
2026-01-19 23:22:50 +03:00
|
|
|
|
{ name: 'favicon-new.ico', size: 32 },
|
2026-01-10 21:46:54 +03:00
|
|
|
|
{ name: 'apple-touch-icon.png', size: 180 },
|
|
|
|
|
|
{ name: 'pwa-192x192.png', size: 192 },
|
|
|
|
|
|
{ name: 'pwa-512x512.png', size: 512 },
|
2026-01-10 21:52:43 +03:00
|
|
|
|
{ name: 'pwa-maskable-192x192.png', size: 192, maskable: true },
|
2026-01-10 21:46:54 +03:00
|
|
|
|
{ name: 'pwa-maskable-512x512.png', size: 512, maskable: true }
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
for (const icon of sizes) {
|
2026-01-11 14:55:11 +03:00
|
|
|
|
// Для maskable иконок используем специальный SVG с контентом в безопасной зоне
|
|
|
|
|
|
const sourceBuffer = icon.maskable ? maskableSvgBuffer : svgBuffer;
|
|
|
|
|
|
const image = sharp(sourceBuffer).resize(icon.size, icon.size);
|
2026-01-10 21:46:54 +03:00
|
|
|
|
|
|
|
|
|
|
const outputPath = path.join(publicDir, icon.name);
|
|
|
|
|
|
await image.png().toFile(outputPath);
|
|
|
|
|
|
console.log(`✓ Создана иконка: ${icon.name} (${icon.size}x${icon.size})`);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log('\n✓ Все иконки успешно созданы!');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Проверяем наличие sharp
|
|
|
|
|
|
try {
|
|
|
|
|
|
require('sharp');
|
|
|
|
|
|
generateIcons().catch(console.error);
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.log('Для генерации иконок необходимо установить sharp:');
|
|
|
|
|
|
console.log('npm install sharp --save-dev');
|
|
|
|
|
|
console.log('\nИли создайте иконки вручную используя онлайн генераторы:');
|
|
|
|
|
|
console.log('- https://realfavicongenerator.net/');
|
|
|
|
|
|
console.log('- https://www.pwabuilder.com/imageGenerator');
|
|
|
|
|
|
}
|
|
|
|
|
|
|