mirror of
https://github.com/tabler/tabler-icons.git
synced 2025-08-31 09:32:04 +02:00
Generate dynamic imports for icons-react (#1081)
Co-authored-by: Paweł Kuna <1282324+codecalm@users.noreply.github.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import fs from 'fs-extra'
|
||||
import path from 'path'
|
||||
import { PACKAGES_DIR, getAliases, toPascalCase, getAllIcons } from './helpers.mjs'
|
||||
import { stringify } from 'svgson'
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import { PACKAGES_DIR, getAliases, toPascalCase, getAllIcons } from './helpers.mjs';
|
||||
import { stringify } from 'svgson';
|
||||
|
||||
/**
|
||||
* Build icons
|
||||
@@ -22,40 +22,39 @@ export const buildJsIcons = ({
|
||||
key = true,
|
||||
pascalCase = false,
|
||||
pascalName = true,
|
||||
indexFile = 'icons.ts'
|
||||
indexFile = 'icons.ts',
|
||||
}) => {
|
||||
const DIST_DIR = path.resolve(PACKAGES_DIR, name);
|
||||
const aliases = getAliases(),
|
||||
allIcons = getAllIcons(false, true)
|
||||
allIcons = getAllIcons(false, true);
|
||||
|
||||
let index = []
|
||||
let index = [];
|
||||
Object.entries(allIcons).forEach(([type, icons]) => {
|
||||
icons.forEach((icon, i) => {
|
||||
process.stdout.write(`Building \`${name}\` ${type} ${i}/${icons.length}: ${icon.name.padEnd(42)}\r`)
|
||||
process.stdout.write(
|
||||
`Building \`${name}\` ${type} ${i}/${icons.length}: ${icon.name.padEnd(42)}\r`,
|
||||
);
|
||||
|
||||
const children = icon.obj.children
|
||||
.map(({
|
||||
name,
|
||||
attributes
|
||||
}, i) => {
|
||||
.map(({ name, attributes }, i) => {
|
||||
if (key) {
|
||||
attributes.key = `svg-${i}`
|
||||
attributes.key = `svg-${i}`;
|
||||
}
|
||||
|
||||
if (pascalCase) {
|
||||
attributes.strokeWidth = attributes['stroke-width']
|
||||
delete attributes['stroke-width']
|
||||
attributes.strokeWidth = attributes['stroke-width'];
|
||||
delete attributes['stroke-width'];
|
||||
}
|
||||
|
||||
return [name, attributes]
|
||||
return [name, attributes];
|
||||
})
|
||||
.filter((i) => {
|
||||
const [name, attributes] = i
|
||||
return !attributes.d || attributes.d !== 'M0 0h24v24H0z'
|
||||
})
|
||||
const [name, attributes] = i;
|
||||
return !attributes.d || attributes.d !== 'M0 0h24v24H0z';
|
||||
});
|
||||
|
||||
const iconName = `${icon.name}${type !== 'outline' ? `-${type}` : ''}`,
|
||||
iconNamePascal = `${icon.namePascal}${type !== 'outline' ? toPascalCase(type) : ''}`
|
||||
iconNamePascal = `${icon.namePascal}${type !== 'outline' ? toPascalCase(type) : ''}`;
|
||||
|
||||
let component = componentTemplate({
|
||||
type,
|
||||
@@ -63,21 +62,27 @@ export const buildJsIcons = ({
|
||||
namePascal: iconNamePascal,
|
||||
children,
|
||||
stringify,
|
||||
svg: icon.content
|
||||
})
|
||||
svg: icon.content,
|
||||
});
|
||||
|
||||
let filePath = path.resolve(DIST_DIR, 'src/icons', `${pascalName ? iconNamePascal : iconName}.${extension}`)
|
||||
fs.writeFileSync(filePath, component, 'utf-8')
|
||||
let filePath = path.resolve(
|
||||
DIST_DIR,
|
||||
'src/icons',
|
||||
`${pascalName ? iconNamePascal : iconName}.${extension}`,
|
||||
);
|
||||
fs.writeFileSync(filePath, component, 'utf-8');
|
||||
|
||||
index.push(indexItemTemplate({
|
||||
type,
|
||||
name: iconName,
|
||||
namePascal: iconNamePascal
|
||||
}))
|
||||
})
|
||||
})
|
||||
index.push(
|
||||
indexItemTemplate({
|
||||
type,
|
||||
name: iconName,
|
||||
namePascal: iconNamePascal,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
fs.writeFileSync(path.resolve(DIST_DIR, `src/icons/${indexFile}`), index.join('\n'), 'utf-8')
|
||||
fs.writeFileSync(path.resolve(DIST_DIR, `src/icons/${indexFile}`), index.join('\n'), 'utf-8');
|
||||
|
||||
// Write aliases
|
||||
let aliasesStr = '';
|
||||
@@ -87,28 +92,61 @@ export const buildJsIcons = ({
|
||||
from,
|
||||
to,
|
||||
fromPascal: toPascalCase(from),
|
||||
toPascal: toPascalCase(to)
|
||||
})
|
||||
})
|
||||
toPascal: toPascalCase(to),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fs.writeFileSync(path.resolve(DIST_DIR, `./src/aliases.ts`), aliasesStr || `export {};`, 'utf-8')
|
||||
}
|
||||
fs.writeFileSync(path.resolve(DIST_DIR, `./src/aliases.ts`), aliasesStr || `export {};`, 'utf-8');
|
||||
};
|
||||
|
||||
export const buildIconsList = (name) => {
|
||||
const DIST_DIR = path.resolve(PACKAGES_DIR, name);
|
||||
const allIcons = getAllIcons(false, true)
|
||||
const allIcons = getAllIcons(false, true);
|
||||
|
||||
let index = []
|
||||
let index = [];
|
||||
Object.entries(allIcons).forEach(([type, icons]) => {
|
||||
icons.forEach((icon, i) => {
|
||||
process.stdout.write(`Building \`${name}\` ${type} ${i}/${icons.length}: ${icon.name.padEnd(42)}\r`)
|
||||
process.stdout.write(
|
||||
`Building \`${name}\` ${type} ${i}/${icons.length}: ${icon.name.padEnd(42)}\r`,
|
||||
);
|
||||
|
||||
const iconName = `${icon.name}${type !== 'outline' ? `-${type}` : ''}`
|
||||
const iconName = `${icon.name}${type !== 'outline' ? `-${type}` : ''}`;
|
||||
|
||||
index.push(iconName)
|
||||
})
|
||||
})
|
||||
index.push(iconName);
|
||||
});
|
||||
});
|
||||
|
||||
fs.writeFileSync(path.resolve(DIST_DIR, `./src/icons-list.ts`), `export default ${JSON.stringify(index, null, 2)};`, 'utf-8')
|
||||
}
|
||||
fs.writeFileSync(
|
||||
path.resolve(DIST_DIR, `./src/icons-list.ts`),
|
||||
`export default ${JSON.stringify(index, null, 2)};`,
|
||||
'utf-8',
|
||||
);
|
||||
};
|
||||
|
||||
export const buildIconsDynamicImport = (name) => {
|
||||
const DIST_DIR = path.resolve(PACKAGES_DIR, name);
|
||||
const allIcons = getAllIcons(false, true);
|
||||
|
||||
let dynamicImportString = 'export default {';
|
||||
Object.entries(allIcons).forEach(([type, icons]) => {
|
||||
icons.forEach((icon, i) => {
|
||||
process.stdout.write(
|
||||
`Building \`${name}\` ${type} ${i}/${icons.length}: ${icon.name.padEnd(42)}\r`,
|
||||
);
|
||||
|
||||
const iconName = `${icon.name}${type !== 'outline' ? `-${type}` : ''}`,
|
||||
iconNamePascal = `${icon.namePascal}${type !== 'outline' ? toPascalCase(type) : ''}`;
|
||||
|
||||
dynamicImportString += ` '${iconName}': () => import('./icons/${iconNamePascal}'),\n`;
|
||||
});
|
||||
});
|
||||
|
||||
dynamicImportString += '};\n';
|
||||
|
||||
fs.writeFileSync(
|
||||
path.resolve(DIST_DIR, `./src/dynamic-imports.ts`),
|
||||
dynamicImportString,
|
||||
'utf-8',
|
||||
);
|
||||
};
|
||||
|
@@ -1,19 +1,22 @@
|
||||
import fs from 'fs'
|
||||
import path, { resolve, basename } from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import svgParse from 'parse-svg-path'
|
||||
import svgpath from 'svgpath'
|
||||
import fs from 'fs';
|
||||
import path, { resolve, basename } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import svgParse from 'parse-svg-path';
|
||||
import svgpath from 'svgpath';
|
||||
import cheerio from 'cheerio';
|
||||
import { minify } from 'html-minifier';
|
||||
import { parseSync } from 'svgson'
|
||||
import { optimize } from 'svgo'
|
||||
import cp from 'child_process'
|
||||
import minimist from 'minimist'
|
||||
import matter from 'gray-matter'
|
||||
import { globSync } from 'glob'
|
||||
import { exec } from 'child_process'
|
||||
import { parseSync } from 'svgson';
|
||||
import { optimize } from 'svgo';
|
||||
import cp from 'child_process';
|
||||
import minimist from 'minimist';
|
||||
import matter from 'gray-matter';
|
||||
import { globSync } from 'glob';
|
||||
import { exec } from 'child_process';
|
||||
import slash from 'slash';
|
||||
|
||||
export const iconTemplate = (type) => type === 'outline' ? `<svg
|
||||
export const iconTemplate = (type) =>
|
||||
type === 'outline'
|
||||
? `<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
@@ -23,53 +26,54 @@ export const iconTemplate = (type) => type === 'outline' ? `<svg
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>` : `<svg
|
||||
>`
|
||||
: `<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
>`
|
||||
>`;
|
||||
|
||||
export const blankSquare = '<path stroke="none" d="M0 0h24v24H0z" fill="none"/>'
|
||||
export const blankSquare = '<path stroke="none" d="M0 0h24v24H0z" fill="none"/>';
|
||||
|
||||
export const types = ['outline', 'filled']
|
||||
export const types = ['outline', 'filled'];
|
||||
|
||||
export const getCurrentDirPath = () => {
|
||||
return path.dirname(fileURLToPath(import.meta.url));
|
||||
}
|
||||
};
|
||||
|
||||
export const HOME_DIR = resolve(getCurrentDirPath(), '..')
|
||||
export const HOME_DIR = resolve(getCurrentDirPath(), '..');
|
||||
|
||||
export const ICONS_SRC_DIR = resolve(HOME_DIR, 'icons')
|
||||
export const PACKAGES_DIR = resolve(HOME_DIR, 'packages')
|
||||
export const GITHUB_DIR = resolve(HOME_DIR, '.github')
|
||||
export const ICONS_SRC_DIR = resolve(HOME_DIR, 'icons');
|
||||
export const PACKAGES_DIR = resolve(HOME_DIR, 'packages');
|
||||
export const GITHUB_DIR = resolve(HOME_DIR, '.github');
|
||||
|
||||
export const parseMatter = (icon) => {
|
||||
const { data, content } = matter.read(icon, { delims: ['<!--', '-->'] })
|
||||
const { data, content } = matter.read(icon, { delims: ['<!--', '-->'] });
|
||||
|
||||
return { data, content }
|
||||
}
|
||||
return { data, content };
|
||||
};
|
||||
|
||||
const getSvgContent = (svg, type, name) => {
|
||||
return svg
|
||||
.replace(/<svg([^>]+)>/, (m, m1) => {
|
||||
return `<svg${m1} class="icon icon-tabler icons-tabler-${type} icon-tabler-${name}"\n>\n ${blankSquare}`
|
||||
return `<svg${m1} class="icon icon-tabler icons-tabler-${type} icon-tabler-${name}"\n>\n ${blankSquare}`;
|
||||
})
|
||||
.trim()
|
||||
}
|
||||
.trim();
|
||||
};
|
||||
|
||||
export const getAllIcons = (withContent = false, withObject = false) => {
|
||||
let icons = {}
|
||||
let icons = {};
|
||||
const limit = process.env['ICONS_LIMIT'] || Infinity;
|
||||
|
||||
types.forEach(type => {
|
||||
icons[type] = globSync(path.join(ICONS_SRC_DIR, `${type}/*.svg`))
|
||||
types.forEach((type) => {
|
||||
icons[type] = globSync(slash(path.join(ICONS_SRC_DIR, `${type}/*.svg`)))
|
||||
.slice(0, limit)
|
||||
.sort()
|
||||
.map(i => {
|
||||
.map((i) => {
|
||||
const { data, content } = parseMatter(i),
|
||||
name = basename(i, '.svg')
|
||||
name = basename(i, '.svg');
|
||||
|
||||
return {
|
||||
name,
|
||||
@@ -80,20 +84,20 @@ export const getAllIcons = (withContent = false, withObject = false) => {
|
||||
version: data.version || '',
|
||||
unicode: data.unicode || '',
|
||||
...(withContent ? { content: getSvgContent(content, type, name) } : {}),
|
||||
...(withObject ? { obj: parseSync(content.replace(blankSquare, '')) } : {})
|
||||
}
|
||||
...(withObject ? { obj: parseSync(content.replace(blankSquare, '')) } : {}),
|
||||
};
|
||||
})
|
||||
.sort()
|
||||
})
|
||||
.sort();
|
||||
});
|
||||
|
||||
return icons
|
||||
}
|
||||
return icons;
|
||||
};
|
||||
|
||||
export const getAllIconsMerged = (withContent = false, withObject = false) => {
|
||||
const allIcons = getAllIcons(true)
|
||||
const allIcons = getAllIcons(true);
|
||||
|
||||
const icons = {};
|
||||
allIcons.outline.forEach(icon => {
|
||||
allIcons.outline.forEach((icon) => {
|
||||
icons[icon.name] = {
|
||||
name: icon.name,
|
||||
category: icon.category || '',
|
||||
@@ -103,42 +107,41 @@ export const getAllIconsMerged = (withContent = false, withObject = false) => {
|
||||
version: icon.version || '',
|
||||
unicode: icon.unicode || '',
|
||||
...(withContent ? { content: icon.content } : {}),
|
||||
...(withObject ? { obj: icon.obj } : {})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
...(withObject ? { obj: icon.obj } : {}),
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
allIcons.filled.forEach(icon => {
|
||||
allIcons.filled.forEach((icon) => {
|
||||
if (icons[icon.name]) {
|
||||
icons[icon.name].styles.filled = {
|
||||
version: icon.version || '',
|
||||
unicode: icon.unicode || '',
|
||||
...(withContent ? { content: icon.content } : {}),
|
||||
...(withObject ? { obj: icon.obj } : {})
|
||||
}
|
||||
...(withObject ? { obj: icon.obj } : {}),
|
||||
};
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
return icons;
|
||||
}
|
||||
};
|
||||
|
||||
export const getArgvs = () => {
|
||||
return minimist(process.argv.slice(2))
|
||||
}
|
||||
return minimist(process.argv.slice(2));
|
||||
};
|
||||
|
||||
export const getPackageDir = (packageName) => {
|
||||
return `${PACKAGES_DIR}/${packageName}`
|
||||
}
|
||||
|
||||
return `${PACKAGES_DIR}/${packageName}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return project package.json
|
||||
* @returns {any}
|
||||
*/
|
||||
export const getPackageJson = () => {
|
||||
return JSON.parse(fs.readFileSync(resolve(HOME_DIR, 'package.json'), 'utf-8'))
|
||||
}
|
||||
return JSON.parse(fs.readFileSync(resolve(HOME_DIR, 'package.json'), 'utf-8'));
|
||||
};
|
||||
|
||||
/**
|
||||
* Reads SVGs from directory
|
||||
@@ -147,17 +150,17 @@ export const getPackageJson = () => {
|
||||
* @returns {string[]}
|
||||
*/
|
||||
export const readSvgDirectory = (directory) => {
|
||||
return fs.readdirSync(directory).filter((file) => path.extname(file) === '.svg')
|
||||
}
|
||||
return fs.readdirSync(directory).filter((file) => path.extname(file) === '.svg');
|
||||
};
|
||||
|
||||
export const getAliases = (groupped = false) => {
|
||||
const allAliases = JSON.parse(fs.readFileSync(resolve(HOME_DIR, 'aliases.json'), 'utf-8'));
|
||||
const allIcons = getAllIcons()
|
||||
const allIcons = getAllIcons();
|
||||
|
||||
if (groupped) {
|
||||
let aliases = [];
|
||||
types.forEach(type => {
|
||||
const icons = allIcons[type].map(i => i.name);
|
||||
types.forEach((type) => {
|
||||
const icons = allIcons[type].map((i) => i.name);
|
||||
|
||||
aliases[type] = {};
|
||||
|
||||
@@ -168,22 +171,23 @@ export const getAliases = (groupped = false) => {
|
||||
}
|
||||
});
|
||||
|
||||
return aliases
|
||||
return aliases;
|
||||
} else {
|
||||
let aliases = [];
|
||||
types.forEach(type => {
|
||||
const icons = allIcons[type].map(i => i.name);
|
||||
types.forEach((type) => {
|
||||
const icons = allIcons[type].map((i) => i.name);
|
||||
|
||||
for (const [key, value] of Object.entries(allAliases[type])) {
|
||||
if (icons.includes(value)) {
|
||||
aliases[`${key}${type !== 'outline' ? `-${type}` : ''}`] = `${value}${type !== 'outline' ? `-${type}` : ''}`;
|
||||
aliases[`${key}${type !== 'outline' ? `-${type}` : ''}`] =
|
||||
`${value}${type !== 'outline' ? `-${type}` : ''}`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return aliases
|
||||
return aliases;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Read SVG
|
||||
@@ -193,8 +197,8 @@ export const getAliases = (groupped = false) => {
|
||||
* @returns {string}
|
||||
*/
|
||||
export const readSvg = (fileName, directory) => {
|
||||
return fs.readFileSync(path.join(directory, fileName), 'utf-8')
|
||||
}
|
||||
return fs.readFileSync(path.join(directory, fileName), 'utf-8');
|
||||
};
|
||||
|
||||
/**
|
||||
* Create directory if not exists
|
||||
@@ -212,8 +216,8 @@ export const createDirectory = (dir) => {
|
||||
* @returns {string}
|
||||
*/
|
||||
export const getSvgName = (fileName) => {
|
||||
return path.basename(fileName, '.svg')
|
||||
}
|
||||
return path.basename(fileName, '.svg');
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert string to CamelCase
|
||||
@@ -221,48 +225,53 @@ export const getSvgName = (fileName) => {
|
||||
* @returns {*}
|
||||
*/
|
||||
export const toCamelCase = (string) => {
|
||||
return string.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase())
|
||||
}
|
||||
return string.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2) =>
|
||||
p2 ? p2.toUpperCase() : p1.toLowerCase(),
|
||||
);
|
||||
};
|
||||
|
||||
export const toPascalCase = (string) => {
|
||||
const camelCase = toCamelCase(string);
|
||||
|
||||
return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
|
||||
}
|
||||
};
|
||||
|
||||
export const addFloats = function (n1, n2) {
|
||||
return Math.round((parseFloat(n1) + parseFloat(n2)) * 1000) / 1000
|
||||
}
|
||||
return Math.round((parseFloat(n1) + parseFloat(n2)) * 1000) / 1000;
|
||||
};
|
||||
|
||||
export const optimizePath = function (path) {
|
||||
let transformed = svgpath(path).rel().round(3).toString()
|
||||
let transformed = svgpath(path).rel().round(3).toString();
|
||||
|
||||
return svgParse(transformed).map(function (a) {
|
||||
return a.join(' ')
|
||||
}).join('')
|
||||
}
|
||||
return svgParse(transformed)
|
||||
.map(function (a) {
|
||||
return a.join(' ');
|
||||
})
|
||||
.join('');
|
||||
};
|
||||
|
||||
export const optimizeSVG = (data) => {
|
||||
return optimize(data, {
|
||||
js2svg: {
|
||||
indent: 2,
|
||||
pretty: true
|
||||
pretty: true,
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {
|
||||
mergePaths: false
|
||||
}
|
||||
}
|
||||
}]
|
||||
}).data
|
||||
}
|
||||
mergePaths: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}).data;
|
||||
};
|
||||
|
||||
export function buildIconsObject(svgFiles, getSvg) {
|
||||
return svgFiles
|
||||
.map(svgFile => {
|
||||
.map((svgFile) => {
|
||||
const name = path.basename(svgFile, '.svg');
|
||||
const svg = getSvg(svgFile);
|
||||
const contents = getSvgContents(svg);
|
||||
@@ -281,251 +290,255 @@ function getSvgContents(svg) {
|
||||
|
||||
export const asyncForEach = async (array, callback) => {
|
||||
for (let index = 0; index < array.length; index++) {
|
||||
await callback(array[index], index, array)
|
||||
await callback(array[index], index, array);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const createScreenshot = (filePath, retina = true) => {
|
||||
cp.execSync(`rsvg-convert -x 2 -y 2 ${filePath} > ${filePath.replace('.svg', '.png')}`)
|
||||
cp.execSync(`rsvg-convert -x 2 -y 2 ${filePath} > ${filePath.replace('.svg', '.png')}`);
|
||||
|
||||
if (retina) {
|
||||
cp.execSync(`rsvg-convert -x 4 -y 4 ${filePath} > ${filePath.replace('.svg', '@2x.png')}`)
|
||||
cp.execSync(`rsvg-convert -x 4 -y 4 ${filePath} > ${filePath.replace('.svg', '@2x.png')}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const createSvgSymbol = (svg, name, stroke) => {
|
||||
return svg.replace('<svg', `<symbol id="${name}"`)
|
||||
return svg
|
||||
.replace('<svg', `<symbol id="${name}"`)
|
||||
.replace(' width="24" height="24"', '')
|
||||
.replace(' stroke-width="2"', ` stroke-width="${stroke}"`)
|
||||
.replace('</svg>', '</symbol>')
|
||||
.replace(/\n\s+/g, ' ')
|
||||
.replace(/<!--(.*?)-->/gis, '')
|
||||
.trim()
|
||||
}
|
||||
|
||||
export const generateIconsPreview = async function (files, destFile, {
|
||||
columnsCount = 19,
|
||||
paddingOuter = 7,
|
||||
color = '#354052',
|
||||
background = '#fff',
|
||||
png = true,
|
||||
stroke = 2,
|
||||
retina = true
|
||||
} = {}) {
|
||||
.trim();
|
||||
};
|
||||
|
||||
export const generateIconsPreview = async function (
|
||||
files,
|
||||
destFile,
|
||||
{
|
||||
columnsCount = 19,
|
||||
paddingOuter = 7,
|
||||
color = '#354052',
|
||||
background = '#fff',
|
||||
png = true,
|
||||
stroke = 2,
|
||||
retina = true,
|
||||
} = {},
|
||||
) {
|
||||
const padding = 20,
|
||||
iconSize = 24
|
||||
iconSize = 24;
|
||||
|
||||
const iconsCount = files.length,
|
||||
rowsCount = Math.ceil(iconsCount / columnsCount),
|
||||
width = columnsCount * (iconSize + padding) + 2 * paddingOuter - padding,
|
||||
height = rowsCount * (iconSize + padding) + 2 * paddingOuter - padding
|
||||
height = rowsCount * (iconSize + padding) + 2 * paddingOuter - padding;
|
||||
|
||||
let svgContentSymbols = '',
|
||||
svgContentIcons = '',
|
||||
x = paddingOuter,
|
||||
y = paddingOuter
|
||||
y = paddingOuter;
|
||||
|
||||
files.forEach(function (file, i) {
|
||||
const name = file.replace(/^(.*)\/([^\/]+)\/([^.]+).svg$/g, '$2-$3');
|
||||
|
||||
let svgFile = fs.readFileSync(file),
|
||||
svgFileContent = svgFile.toString()
|
||||
svgFileContent = svgFile.toString();
|
||||
|
||||
svgFileContent = createSvgSymbol(svgFileContent, name, stroke)
|
||||
svgFileContent = createSvgSymbol(svgFileContent, name, stroke);
|
||||
|
||||
svgContentSymbols += `\t${svgFileContent}\n`
|
||||
svgContentIcons += `\t<use xlink:href="#${name}" x="${x}" y="${y}" width="${iconSize}" height="${iconSize}" />\n`
|
||||
svgContentSymbols += `\t${svgFileContent}\n`;
|
||||
svgContentIcons += `\t<use xlink:href="#${name}" x="${x}" y="${y}" width="${iconSize}" height="${iconSize}" />\n`;
|
||||
|
||||
x += padding + iconSize
|
||||
x += padding + iconSize;
|
||||
|
||||
if (i % columnsCount === columnsCount - 1) {
|
||||
x = paddingOuter
|
||||
y += padding + iconSize
|
||||
x = paddingOuter;
|
||||
y += padding + iconSize;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
const svgContent = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 ${width} ${height}" width="${width}" height="${height}" style="color: ${color}"><rect x="0" y="0" width="${width}" height="${height}" fill="${background}"></rect>\n${svgContentSymbols}\n${svgContentIcons}\n</svg>`
|
||||
const svgContent = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 ${width} ${height}" width="${width}" height="${height}" style="color: ${color}"><rect x="0" y="0" width="${width}" height="${height}" fill="${background}"></rect>\n${svgContentSymbols}\n${svgContentIcons}\n</svg>`;
|
||||
|
||||
console.log(destFile)
|
||||
console.log(destFile);
|
||||
|
||||
fs.writeFileSync(destFile, svgContent)
|
||||
fs.writeFileSync(destFile, svgContent);
|
||||
|
||||
if (png) {
|
||||
await createScreenshot(destFile, retina)
|
||||
await createScreenshot(destFile, retina);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export const printChangelog = function (newIcons, modifiedIcons, renamedIcons, pretty = false) {
|
||||
if (newIcons.length > 0) {
|
||||
if (pretty) {
|
||||
console.log(`### ${newIcons.length} new icon${newIcons.length > 1 ? 's' : ''}:\n`)
|
||||
console.log(`### ${newIcons.length} new icon${newIcons.length > 1 ? 's' : ''}:\n`);
|
||||
|
||||
newIcons.forEach(function (icon, i) {
|
||||
console.log(`- \`${icon}\``)
|
||||
})
|
||||
console.log(`- \`${icon}\``);
|
||||
});
|
||||
} else {
|
||||
let str = ''
|
||||
str += `${newIcons.length} new icon${newIcons.length > 1 ? 's' : ''}: `
|
||||
let str = '';
|
||||
str += `${newIcons.length} new icon${newIcons.length > 1 ? 's' : ''}: `;
|
||||
|
||||
newIcons.forEach(function (icon, i) {
|
||||
str += `\`${icon}\``
|
||||
str += `\`${icon}\``;
|
||||
|
||||
if ((i + 1) <= newIcons.length - 1) {
|
||||
str += ', '
|
||||
if (i + 1 <= newIcons.length - 1) {
|
||||
str += ', ';
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
console.log(str)
|
||||
console.log(str);
|
||||
}
|
||||
|
||||
console.log('')
|
||||
console.log('');
|
||||
}
|
||||
|
||||
if (modifiedIcons.length > 0) {
|
||||
let str = ''
|
||||
str += `Fixed icon${modifiedIcons.length > 1 ? 's' : ''}: `
|
||||
let str = '';
|
||||
str += `Fixed icon${modifiedIcons.length > 1 ? 's' : ''}: `;
|
||||
|
||||
modifiedIcons.forEach(function (icon, i) {
|
||||
str += `\`${icon}\``
|
||||
str += `\`${icon}\``;
|
||||
|
||||
if ((i + 1) <= modifiedIcons.length - 1) {
|
||||
str += ', '
|
||||
if (i + 1 <= modifiedIcons.length - 1) {
|
||||
str += ', ';
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
console.log(str)
|
||||
console.log('')
|
||||
console.log(str);
|
||||
console.log('');
|
||||
}
|
||||
|
||||
if (renamedIcons.length > 0) {
|
||||
console.log(`Renamed icons: `)
|
||||
console.log(`Renamed icons: `);
|
||||
|
||||
renamedIcons.forEach(function (icon, i) {
|
||||
console.log(`- \`${icon[0]}\` renamed to \`${icon[1]}\``)
|
||||
})
|
||||
console.log(`- \`${icon[0]}\` renamed to \`${icon[1]}\``);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export const getCompileOptions = () => {
|
||||
const compileOptions = {
|
||||
includeIcons: [],
|
||||
strokeWidth: null,
|
||||
fontForge: 'fontforge'
|
||||
}
|
||||
fontForge: 'fontforge',
|
||||
};
|
||||
|
||||
if (fs.existsSync('../compile-options.json')) {
|
||||
try {
|
||||
const tempOptions = JSON.parse(fs.readFileSync('../compile-options.json').toString())
|
||||
const tempOptions = JSON.parse(fs.readFileSync('../compile-options.json').toString());
|
||||
|
||||
if (typeof tempOptions !== 'object') {
|
||||
throw 'Compile options file does not contain an json object'
|
||||
throw 'Compile options file does not contain an json object';
|
||||
}
|
||||
|
||||
if (typeof tempOptions.includeIcons !== 'undefined') {
|
||||
if (!Array.isArray(tempOptions.includeIcons)) {
|
||||
throw 'property inludeIcons is not an array'
|
||||
throw 'property inludeIcons is not an array';
|
||||
}
|
||||
compileOptions.includeIcons = tempOptions.includeIcons
|
||||
compileOptions.includeIcons = tempOptions.includeIcons;
|
||||
}
|
||||
|
||||
if (typeof tempOptions.includeCategories !== 'undefined') {
|
||||
if (typeof tempOptions.includeCategories === 'string') {
|
||||
tempOptions.includeCategories = tempOptions.includeCategories.split(' ')
|
||||
tempOptions.includeCategories = tempOptions.includeCategories.split(' ');
|
||||
}
|
||||
if (!Array.isArray(tempOptions.includeCategories)) {
|
||||
throw 'property includeCategories is not an array or string'
|
||||
throw 'property includeCategories is not an array or string';
|
||||
}
|
||||
const tags = Object.entries(require('./tags.json'))
|
||||
const tags = Object.entries(require('./tags.json'));
|
||||
tempOptions.includeCategories.forEach(function (category) {
|
||||
category = category.charAt(0).toUpperCase() + category.slice(1)
|
||||
category = category.charAt(0).toUpperCase() + category.slice(1);
|
||||
for (const [icon, data] of tags) {
|
||||
if (data.category === category && compileOptions.includeIcons.indexOf(icon) === -1) {
|
||||
compileOptions.includeIcons.push(icon)
|
||||
compileOptions.includeIcons.push(icon);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof tempOptions.excludeIcons !== 'undefined') {
|
||||
if (!Array.isArray(tempOptions.excludeIcons)) {
|
||||
throw 'property excludeIcons is not an array'
|
||||
throw 'property excludeIcons is not an array';
|
||||
}
|
||||
compileOptions.includeIcons = compileOptions.includeIcons.filter(function (icon) {
|
||||
return tempOptions.excludeIcons.indexOf(icon) === -1
|
||||
})
|
||||
return tempOptions.excludeIcons.indexOf(icon) === -1;
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof tempOptions.excludeOffIcons !== 'undefined' && tempOptions.excludeOffIcons) {
|
||||
// Exclude `*-off` icons
|
||||
compileOptions.includeIcons = compileOptions.includeIcons.filter(function (icon) {
|
||||
return !icon.endsWith('-off')
|
||||
})
|
||||
return !icon.endsWith('-off');
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof tempOptions.strokeWidth !== 'undefined') {
|
||||
if (typeof tempOptions.strokeWidth !== 'string' && typeof tempOptions.strokeWidth !== 'number') {
|
||||
throw 'property strokeWidth is not a string or number'
|
||||
if (
|
||||
typeof tempOptions.strokeWidth !== 'string' &&
|
||||
typeof tempOptions.strokeWidth !== 'number'
|
||||
) {
|
||||
throw 'property strokeWidth is not a string or number';
|
||||
}
|
||||
compileOptions.strokeWidth = tempOptions.strokeWidth.toString()
|
||||
compileOptions.strokeWidth = tempOptions.strokeWidth.toString();
|
||||
}
|
||||
|
||||
if (typeof tempOptions.fontForge !== 'undefined') {
|
||||
if (typeof tempOptions.fontForge !== 'string') {
|
||||
throw 'property fontForge is not a string'
|
||||
throw 'property fontForge is not a string';
|
||||
}
|
||||
compileOptions.fontForge = tempOptions.fontForge
|
||||
compileOptions.fontForge = tempOptions.fontForge;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
throw `Error reading compile-options.json: ${error}`
|
||||
throw `Error reading compile-options.json: ${error}`;
|
||||
}
|
||||
}
|
||||
|
||||
return compileOptions
|
||||
}
|
||||
|
||||
return compileOptions;
|
||||
};
|
||||
|
||||
export const convertIconsToImages = async (dir, extension, size = 240) => {
|
||||
const icons = getAllIcons()
|
||||
const icons = getAllIcons();
|
||||
|
||||
await asyncForEach(Object.entries(icons), async function ([type, svgFiles]) {
|
||||
fs.mkdirSync(path.join(dir, `./${type}`), { recursive: true })
|
||||
fs.mkdirSync(path.join(dir, `./${type}`), { recursive: true });
|
||||
|
||||
await asyncForEach(svgFiles, async function (file, i) {
|
||||
const distPath = path.join(dir, `./${type}/${file.name}.${extension}`)
|
||||
const distPath = path.join(dir, `./${type}/${file.name}.${extension}`);
|
||||
|
||||
process.stdout.write(`Building \`icons/${extension}\` ${type} ${i}/${svgFiles.length}: ${file.name.padEnd(42)}\r`)
|
||||
process.stdout.write(
|
||||
`Building \`icons/${extension}\` ${type} ${i}/${svgFiles.length}: ${file.name.padEnd(42)}\r`,
|
||||
);
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
exec(`rsvg-convert -f ${extension} -h ${size} ${file.path} > ${distPath}`, (error) => {
|
||||
error ? reject() : resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
error ? reject() : resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const getMaxUnicode = () => {
|
||||
const files = globSync(path.join(ICONS_SRC_DIR, '**/*.svg'))
|
||||
let maxUnicode = 0
|
||||
const files = globSync(path.join(ICONS_SRC_DIR, '**/*.svg'));
|
||||
let maxUnicode = 0;
|
||||
|
||||
files.forEach(function (file) {
|
||||
const svgFile = fs.readFileSync(file).toString()
|
||||
const svgFile = fs.readFileSync(file).toString();
|
||||
|
||||
svgFile.replace(/unicode: "([a-f0-9.]+)"/i, function (m, unicode) {
|
||||
const newUnicode = parseInt(unicode, 16)
|
||||
const newUnicode = parseInt(unicode, 16);
|
||||
|
||||
if (newUnicode) {
|
||||
maxUnicode = Math.max(maxUnicode, newUnicode)
|
||||
maxUnicode = Math.max(maxUnicode, newUnicode);
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
console.log(`Max unicode: ${maxUnicode}`)
|
||||
console.log(`Max unicode: ${maxUnicode}`);
|
||||
|
||||
return maxUnicode
|
||||
}
|
||||
return maxUnicode;
|
||||
};
|
||||
|
@@ -76,14 +76,15 @@
|
||||
"rollup-plugin-license": "^3.2.0",
|
||||
"rollup-plugin-peer-deps-external": "2.2.4",
|
||||
"rollup-plugin-visualizer": "^5.12.0",
|
||||
"slash": "^5.1.0",
|
||||
"svg-outline-stroke": "1.3.1",
|
||||
"svgo": "^3.2.0",
|
||||
"svgpath": "^2.6.0",
|
||||
"svgson": "^5.3.1",
|
||||
"turbo": "^1.12.4",
|
||||
"typescript": "^5.3.3",
|
||||
"vitest": "^1.3.1",
|
||||
"vite": "^5.1.4"
|
||||
"vite": "^5.1.4",
|
||||
"vitest": "^1.3.1"
|
||||
},
|
||||
"release-it": {
|
||||
"plugins": {
|
||||
|
1
packages/icons-react/.gitignore
vendored
1
packages/icons-react/.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
src/aliases.ts
|
||||
src/icons-list.ts
|
||||
src/dynamic-imports.ts
|
||||
|
@@ -1,22 +1,20 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { buildJsIcons, buildIconsList } from '../../.build/build-icons.mjs'
|
||||
import {
|
||||
buildJsIcons,
|
||||
buildIconsList,
|
||||
buildIconsDynamicImport,
|
||||
} from '../../.build/build-icons.mjs';
|
||||
|
||||
const componentTemplate = ({
|
||||
type,
|
||||
name,
|
||||
namePascal,
|
||||
children
|
||||
}) => `\
|
||||
const componentTemplate = ({ type, name, namePascal, children }) => `\
|
||||
import createReactComponent from '../createReactComponent';
|
||||
export default createReactComponent('${type}', '${name}', '${namePascal}', ${JSON.stringify(children)});`;
|
||||
|
||||
const indexItemTemplate = ({
|
||||
name,
|
||||
namePascal
|
||||
}) => `export { default as ${namePascal} } from './${namePascal}';`
|
||||
const indexItemTemplate = ({ name, namePascal }) =>
|
||||
`export { default as ${namePascal} } from './${namePascal}';`;
|
||||
|
||||
const aliasTemplate = ({ fromPascal, toPascal }) => `export { default as Icon${fromPascal} } from './icons/Icon${toPascal}';\n`
|
||||
const aliasTemplate = ({ fromPascal, toPascal }) =>
|
||||
`export { default as Icon${fromPascal} } from './icons/Icon${toPascal}';\n`;
|
||||
|
||||
buildJsIcons({
|
||||
name: 'icons-react',
|
||||
@@ -25,7 +23,9 @@ buildJsIcons({
|
||||
aliasTemplate,
|
||||
indexFile: 'index.ts',
|
||||
pascalCase: true,
|
||||
extension: 'ts'
|
||||
})
|
||||
extension: 'ts',
|
||||
});
|
||||
|
||||
buildIconsList('icons-react')
|
||||
buildIconsList('icons-react');
|
||||
|
||||
buildIconsDynamicImport('icons-react');
|
||||
|
@@ -1,6 +1,7 @@
|
||||
export * from './icons/index';
|
||||
export * as icons from './icons/index';
|
||||
export * as iconsList from './icons-list';
|
||||
export * as dynamicImports from './dynamic-imports';
|
||||
export * from './aliases';
|
||||
export { default as createReactComponent } from './createReactComponent';
|
||||
|
||||
|
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -93,6 +93,9 @@ importers:
|
||||
rollup-plugin-visualizer:
|
||||
specifier: ^5.12.0
|
||||
version: 5.12.0(rollup@4.12.0)
|
||||
slash:
|
||||
specifier: ^5.1.0
|
||||
version: 5.1.0
|
||||
svg-outline-stroke:
|
||||
specifier: 1.3.1
|
||||
version: 1.3.1
|
||||
|
Reference in New Issue
Block a user