Files
nextjs-template/scripts/create-svg-sprite.js
S.Gromov a544d41a03 chore: перевести проект на SLM-структуру и добавить SVG-спрайты
- Добавлены devDependencies: svg-sprite, postcss-preset-mantine, postcss-simple-vars, colorette
- Добавлен npm-скрипт `sprite` для генерации SVG-спрайтов
- Обновлены настройки и расширения VS Code
- Переименованы слои: entities → business, features → infrastructure, shared/ui → ui
- Обновлены шаблоны генерации (.templates) под новые слои
- Обновлены path-алиасы в tsconfig.json: убран префикс @/, добавлены алиасы по слоям
- Импорт в src/app/page.tsx переведён на алиас слоя
- Удалён postcss.config.mjs
- Добавлен скрипт scripts/create-svg-sprite.js
- Добавлены исходные SVG-иконки и сгенерированные спрайты
- Добавлен модуль src/shared/sprites/icons.generated.ts
- Добавлены глобальные стилевые токены: variables.css, media.css
- Применён медиа-токен в src/screens/home/styles/home.module.css
- Добавлен AGENTS.md с инструкциями для AI-ассистента
2026-04-28 09:19:27 +03:00

127 lines
3.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Генерация SVG-спрайтов и TypeScript-типов имён иконок.
*
* Читает подпапки из ASSETS_DIR, для каждой собирает SVG в спрайт (stack или symbol)
* и генерирует .generated.ts файл с union-типом имён иконок.
*
* Режим спрайта определяется суффиксом папки: «icons?symbol» → symbol, иначе stack.
*
* Запуск: npm run sprite
*/
const fs = require('fs')
const path = require('path')
const SVGSpriter = require('svg-sprite')
const color = require('colorette')
const ROOT = process.cwd()
/** Папка с исходными SVG-файлами. */
const ASSETS_DIR = path.join(ROOT, 'src/shared/sprites')
/** Папка для сгенерированных спрайтов. */
const DEST_DIR = path.join(ROOT, 'public/img/sprites')
/**
* Преобразует kebab-case строку в PascalCase.
*/
const toPascalCase = (str) =>
str.replace(/(^|[-_])([a-z])/g, (_, __, c) => c.toUpperCase())
/**
* Возвращает конфигурацию режима для svg-sprite.
*/
const getModeConfig = (mode, destDir) => ({
dest: destDir,
sprite: `sprite.${mode}.svg`,
example: true,
rootviewbox: false,
})
/**
* Генерирует TypeScript-файл с union-типом имён иконок спрайта.
*/
const generateIconNames = (folderName, svgFiles) => {
const names = svgFiles
.map((filePath) => path.basename(filePath, '.svg'))
.sort()
const typeName = `${toPascalCase(folderName)}IconName`
const content = [
'/**',
` * Имена иконок спрайта «${folderName}».`,
' * @generated — файл создан автоматически (npm run sprite), не редактировать вручную.',
' */',
`export type ${typeName} =`,
names.map((name) => ` | '${name}'`).join('\n'),
'',
].join('\n')
const outputPath = path.join(ASSETS_DIR, `${folderName}.generated.ts`)
fs.writeFileSync(outputPath, content)
console.log(
color.green(`Generated types: ${folderName}.generated.ts (${names.length} icons)`),
)
}
/**
* Обрабатывает одну папку со спрайтами.
*/
const processFolder = (fullFolderName) => {
const folderPath = path.join(ASSETS_DIR, fullFolderName)
if (!fs.lstatSync(folderPath).isDirectory()) {
return
}
const hasCustomMode = fullFolderName.includes('?')
const parts = fullFolderName.split('?')
const mode = hasCustomMode ? parts.pop() : 'stack'
const folderName = parts[0]
const svgFiles = fs
.readdirSync(folderPath)
.filter((file) => file.endsWith('.svg'))
.map((file) => path.join(folderPath, file))
if (!svgFiles.length) {
return
}
const config = {
log: 'debug',
mode: {
[mode]: getModeConfig(mode, path.join(DEST_DIR, folderName)),
},
}
const spriter = new SVGSpriter(config)
for (const fileName of svgFiles) {
spriter.add(fileName, null, fs.readFileSync(fileName, 'utf-8'))
}
spriter.compile((error, result) => {
if (error) {
console.log(color.red(error.message))
return
}
for (const modeResult of Object.values(result)) {
for (const resource of Object.values(modeResult)) {
fs.mkdirSync(path.dirname(resource.path), { recursive: true })
fs.writeFileSync(resource.path, resource.contents)
}
}
})
generateIconNames(folderName, svgFiles)
}
try {
const entries = fs.readdirSync(ASSETS_DIR)
entries.forEach(processFolder)
} catch (err) {
console.log(color.red(err.message))
}