2026-04-21 23:07:34 +03:00
|
|
|
|
import fs from 'node:fs'
|
|
|
|
|
|
import path from 'node:path'
|
|
|
|
|
|
import SVGSpriter from 'svg-sprite'
|
|
|
|
|
|
import { createShapeTransform } from './transforms.js'
|
|
|
|
|
|
import type { SpriteFolder, SpriteMode, TransformOptions } from './types.js'
|
|
|
|
|
|
|
|
|
|
|
|
/** Конфигурация режима для svg-sprite. */
|
2026-04-22 16:54:35 +03:00
|
|
|
|
function getModeConfig(mode: SpriteMode, destDir: string, name: string) {
|
2026-04-21 23:07:34 +03:00
|
|
|
|
return {
|
|
|
|
|
|
dest: destDir,
|
2026-04-22 16:54:35 +03:00
|
|
|
|
sprite: `${name}.sprite.svg`,
|
2026-04-21 23:07:34 +03:00
|
|
|
|
example: false,
|
|
|
|
|
|
rootviewbox: false,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-22 16:54:35 +03:00
|
|
|
|
/** Строит массив shape.transform. */
|
|
|
|
|
|
function buildShapeTransforms(transform: TransformOptions = {}) {
|
2026-04-21 23:07:34 +03:00
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
2026-04-22 16:54:35 +03:00
|
|
|
|
const transforms: any[] = [
|
|
|
|
|
|
{
|
|
|
|
|
|
svgo: {
|
|
|
|
|
|
plugins: [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: 'preset-default',
|
|
|
|
|
|
params: {
|
|
|
|
|
|
overrides: {
|
|
|
|
|
|
removeViewBox: false,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
createShapeTransform(transform),
|
|
|
|
|
|
]
|
2026-04-21 23:07:34 +03:00
|
|
|
|
|
|
|
|
|
|
return transforms
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Компилирует папку с SVG-файлами в спрайт.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Возвращает путь к сгенерированному SVG-файлу.
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function compileSprite(
|
|
|
|
|
|
folder: SpriteFolder,
|
|
|
|
|
|
outputDir: string,
|
|
|
|
|
|
transform: TransformOptions = {},
|
|
|
|
|
|
): Promise<string> {
|
|
|
|
|
|
const config = {
|
|
|
|
|
|
shape: {
|
|
|
|
|
|
transform: buildShapeTransforms(transform),
|
|
|
|
|
|
},
|
|
|
|
|
|
mode: {
|
2026-04-22 16:54:35 +03:00
|
|
|
|
[folder.mode]: getModeConfig(folder.mode, outputDir, folder.name),
|
2026-04-21 23:07:34 +03:00
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const spriter = new SVGSpriter(config)
|
|
|
|
|
|
|
|
|
|
|
|
for (const filePath of folder.files) {
|
|
|
|
|
|
spriter.add(filePath, null, fs.readFileSync(filePath, 'utf-8'))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
|
spriter.compile((error, result) => {
|
|
|
|
|
|
if (error) {
|
|
|
|
|
|
reject(error)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let spritePath = ''
|
|
|
|
|
|
|
|
|
|
|
|
for (const modeResult of Object.values(result)) {
|
|
|
|
|
|
for (const resource of Object.values(
|
|
|
|
|
|
modeResult as Record<string, { path: string; contents: Buffer }>,
|
|
|
|
|
|
)) {
|
|
|
|
|
|
fs.mkdirSync(path.dirname(resource.path), { recursive: true })
|
|
|
|
|
|
fs.writeFileSync(resource.path, resource.contents)
|
|
|
|
|
|
if (resource.path.endsWith('.svg')) {
|
|
|
|
|
|
spritePath = resource.path
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
resolve(spritePath)
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|