svgtofont
Version:
Converts SVG to TTF/EOT/WOFF/WOFF2/SVG format fonts.
216 lines • 10.1 kB
JavaScript
/// <reference types="../src/types" />
import path from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs-extra';
import image2uri from 'image2uri';
import color from 'colors-cli';
import { autoConf, merge } from 'auto-config-loader';
import { log } from './log.js';
import { generateIconsSource, generateReactIcons, generateReactNativeIcons } from './generate.js';
import { createSVG, createTTF, createEOT, createWOFF, createWOFF2, createSvgSymbol, copyTemplate, createHTML, createTypescript } from './utils.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export default async (options = {}) => {
const defaultOptions = merge({
dist: path.resolve(process.cwd(), 'fonts'),
src: path.resolve(process.cwd(), 'svg'),
startUnicode: 0xea01,
svg2ttf: {},
svgicons2svgfont: {
fontName: 'iconfont',
},
fontName: 'iconfont',
symbolNameDelimiter: '-',
}, options);
const data = autoConf('svgtofont', {
mustExist: true,
default: defaultOptions,
...options.config,
});
options = merge(defaultOptions, data);
const pkgPath = path.join(process.cwd(), 'package.json');
if (fs.pathExistsSync(pkgPath)) {
const pkg = fs.readJSONSync(pkgPath);
if (pkg.svgtofont) {
const cssOptions = options.css;
options = merge(options, pkg.svgtofont);
if (pkg.svgtofont.css && cssOptions && typeof cssOptions === 'object') {
options.css = merge(cssOptions, pkg.svgtofont.css);
}
}
if (options.website && pkg.version) {
options.website.version = pkg.version;
}
}
if (options.log === undefined)
options.log = true;
log.disabled = !options.log;
if (options.logger && typeof options.logger === 'function')
log.logger = options.logger;
options.svgicons2svgfont.fontName = options.fontName;
options.classNamePrefix = options.classNamePrefix || options.fontName;
const fontSizeOpt = typeof options.css !== 'boolean' && options.css.fontSize;
const fontSize = typeof fontSizeOpt === 'boolean' ? (fontSizeOpt === true ? 'font-size: 16px;' : '') : `font-size: ${fontSizeOpt};`;
// If you generate a font you need to generate a style.
if (options.website && !options.css)
options.css = true;
const infoDataPath = path.resolve(options.dist, 'info.json');
try {
if (options.emptyDist) {
await fs.emptyDir(options.dist);
}
// Ensures that the directory exists.
await fs.ensureDir(options.dist);
const unicodeObject = await createSVG(options);
let cssToVars = [];
let cssString = [];
let cssRootVars = [];
let cssIconHtml = [];
let unicodeHtml = [];
let symbolHtml = [];
const prefix = options.classNamePrefix || options.fontName;
const infoData = {};
Object.keys(unicodeObject).forEach((name, index, self) => {
if (!infoData[name])
infoData[name] = {};
const _code = unicodeObject[name];
let symbolName = options.classNamePrefix + options.symbolNameDelimiter + name;
let iconPart = symbolName + '">';
let encodedCodes = _code.charCodeAt(0);
if (options.useNameAsUnicode) {
symbolName = name;
iconPart = prefix + '">' + name;
encodedCodes = _code.split('').map(x => x.charCodeAt(0)).join(';&#');
}
else {
cssToVars.push(`$${symbolName}: "\\${encodedCodes.toString(16)}";\n`);
if (options.useCSSVars) {
if (index === 0)
cssRootVars.push(`:root {\n`);
cssRootVars.push(`--${symbolName}: "\\${encodedCodes.toString(16)}";\n`);
cssString.push(`.${symbolName}:before { content: var(--${symbolName}); }\n`);
if (index === self.length - 1)
cssRootVars.push(`}\n`);
}
else {
cssString.push(`.${symbolName}:before { content: "\\${encodedCodes.toString(16)}"; }\n`);
}
}
infoData[name].encodedCode = `\\${encodedCodes.toString(16)}`;
infoData[name].prefix = prefix;
infoData[name].className = symbolName;
infoData[name].unicode = `&#${encodedCodes};`;
cssIconHtml.push(`<li class="class-icon"><i class="${iconPart}</i><p class="name">${name}</p></li>`);
unicodeHtml.push(`<li class="unicode-icon"><span class="iconfont">${_code}</span><h4>${name}</h4><span class="unicode">&#${encodedCodes};</span></li>`);
symbolHtml.push(`
<li class="symbol">
<svg class="icon" aria-hidden="true">
<use xlink:href="${options.fontName}.symbol.svg#${symbolName}"></use>
</svg>
<h4>${symbolName}</h4>
</li>
`);
});
if (options.useCSSVars) {
cssString = [...cssRootVars, ...cssString];
}
if (options.generateInfoData) {
await fs.writeJSON(infoDataPath, infoData, { spaces: 2 });
log.log(`${color.green('SUCCESS')} Created ${infoDataPath} `);
}
const ttf = await createTTF(options);
await createEOT(options, ttf);
await createWOFF(options, ttf);
await createWOFF2(options, ttf);
await createSvgSymbol(options);
if (options.css) {
const styleTemplatePath = options.styleTemplates || (!options.useNameAsUnicode ? path.resolve(__dirname, 'styles') : path.resolve(__dirname, 'ligature-styles'));
await copyTemplate(styleTemplatePath, options.dist, {
fontname: options.fontName,
cssString: cssString.join(''),
cssToVars: cssToVars.join(''),
fontSize: fontSize,
timestamp: new Date().getTime(),
prefix,
_opts: typeof options.css === 'boolean' ? {} : { ...options.css }
});
}
if (options.typescript) {
await createTypescript({ ...options, typescript: options.typescript });
}
if (options.website) {
const pageName = ['font-class', 'unicode', 'symbol'];
let fontClassPath = path.join(options.dist, 'index.html');
let unicodePath = path.join(options.dist, 'unicode.html');
let symbolPath = path.join(options.dist, 'symbol.html');
// setting default home page.
const indexName = pageName.includes(options.website.index) ? pageName.indexOf(options.website.index) : 0;
pageName.forEach((name, index) => {
const _path = path.join(options.dist, indexName === index ? 'index.html' : `${name}.html`);
if (name === 'font-class')
fontClassPath = _path;
if (name === 'unicode')
unicodePath = _path;
if (name === 'symbol')
symbolPath = _path;
});
// default template
options.website.template = options.website.template || path.join(__dirname, 'website', 'index.ejs');
// template data
const tempData = {
meta: null,
links: null,
corners: null,
description: null,
footerInfo: null,
...options.website,
fontname: options.fontName,
classNamePrefix: options.classNamePrefix,
_type: 'font-class',
_link: `${(options.css && typeof options.css !== 'boolean' && options.css.fileName) || options.fontName}.css`,
_IconHtml: cssIconHtml.join(''),
_title: options.website.title || options.fontName
};
// website logo
if (options.website.logo && fs.pathExistsSync(options.website.logo) && path.extname(options.website.logo) === '.svg') {
tempData.logo = fs.readFileSync(options.website.logo).toString();
}
// website favicon
if (options.website.favicon && fs.pathExistsSync(options.website.favicon)) {
tempData.favicon = await image2uri(options.website.favicon);
}
else {
tempData.favicon = '';
}
const classHtmlStr = await createHTML(options.website.template, tempData);
fs.outputFileSync(fontClassPath, classHtmlStr);
log.log(`${color.green('SUCCESS')} Created ${fontClassPath} `);
tempData._IconHtml = unicodeHtml.join('');
tempData._type = 'unicode';
const unicodeHtmlStr = await createHTML(options.website.template, tempData);
fs.outputFileSync(unicodePath, unicodeHtmlStr);
log.log(`${color.green('SUCCESS')} Created ${unicodePath} `);
tempData._IconHtml = symbolHtml.join('');
tempData._type = 'symbol';
const symbolHtmlStr = await createHTML(options.website.template, tempData);
fs.outputFileSync(symbolPath, symbolHtmlStr);
log.log(`${color.green('SUCCESS')} Created ${unicodePath} `);
}
if (options.outSVGPath) {
const outPath = await generateIconsSource(options);
log.log(`${color.green('SUCCESS')} Created ${outPath} `);
}
if (options.outSVGReact) {
const outPath = await generateReactIcons(options);
log.log(`${color.green('SUCCESS')} Created React Components. `);
}
if (options.outSVGReactNative) {
generateReactNativeIcons(options, unicodeObject);
log.log(`${color.green('SUCCESS')} Created React Native Components. `);
}
}
catch (error) {
log.log('SvgToFont:CLI:ERR:', error);
}
};
//# sourceMappingURL=index.js.map