new changes

This commit is contained in:
Niranjan
2026-04-07 05:05:28 +05:30
parent 7c070224bd
commit a18bba15f2
29975 changed files with 3247495 additions and 2761 deletions

View File

@@ -0,0 +1,2 @@
#!/usr/bin/env node
export {};

View File

@@ -0,0 +1,49 @@
#!/usr/bin/env node
import FS from 'fs-extra';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import path from 'path';
import svgtofont from './index.js';
import { log } from './log.js';
const argv = yargs(hideBin(process.argv))
.alias('s', 'sources')
.describe('s', 'The root from which all sources are relative.')
.alias('o', 'output')
.describe('o', 'Output directory.')
.alias('f', 'fontName')
.describe('f', 'Font Name.')
.demandOption(['output', 'sources'])
.help('h')
.alias('h', 'help')
.epilog('copyright 2019')
.argv;
const sourcesPath = path.resolve(process.cwd(), argv.sources);
const outputPath = path.resolve(process.cwd(), argv.output);
if (!FS.pathExistsSync(sourcesPath)) {
log.error('The directory does not exist!', sourcesPath);
process.exit();
}
if (!FS.pathExistsSync(outputPath)) {
FS.mkdirpSync(outputPath);
}
svgtofont({
src: sourcesPath, // svg path
dist: outputPath, // output path
// emptyDist: true, // Clear output directory contents
fontName: (argv.fontName) || "svgfont", // font name
css: true, // Create CSS files.
outSVGReact: true,
outSVGReactNative: false,
outSVGVue: true,
outSVGPath: true,
svgicons2svgfont: {
fontHeight: 1000,
normalize: true,
},
})
.then(() => {
log.log('done!');
}).catch((err) => {
log.log('SvgToFont:ERR:', err);
});
//# sourceMappingURL=cli.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,UAAU,CAAC;AAE1B,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAQ/B,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;KACtC,KAAK,CAAC,GAAG,EAAE,SAAS,CAAC;KACrB,QAAQ,CAAC,GAAG,EAAE,+CAA+C,CAAC;KAC9D,KAAK,CAAC,GAAG,EAAE,QAAQ,CAAC;KACpB,QAAQ,CAAC,GAAG,EAAE,mBAAmB,CAAC;KAClC,KAAK,CAAC,GAAG,EAAE,UAAU,CAAC;KACtB,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;KAC3B,YAAY,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;KACnC,IAAI,CAAC,GAAG,CAAC;KACT,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC;KAClB,MAAM,CAAC,gBAAgB,CAAC;KACxB,IAAkB,CAAC;AAEtB,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;AAC9D,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;AAE5D,IAAI,CAAC,EAAE,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,CAAC;IACpC,GAAG,CAAC,KAAK,CAAC,+BAA+B,EAAE,WAAW,CAAC,CAAC;IACxD,OAAO,CAAC,IAAI,EAAE,CAAC;AACjB,CAAC;AAED,IAAI,CAAC,EAAE,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,CAAC;IACnC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,CAAC;IACR,GAAG,EAAE,WAAW,EAAE,WAAW;IAC7B,IAAI,EAAE,UAAU,EAAE,cAAc;IAChC,sDAAsD;IACtD,QAAQ,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,SAAS,EAAE,YAAY;IACpD,GAAG,EAAE,IAAI,EAAE,oBAAoB;IAC/B,WAAW,EAAE,IAAI;IACjB,iBAAiB,EAAE,KAAK;IACxB,SAAS,EAAE,IAAI;IACf,UAAU,EAAE,IAAI;IAChB,gBAAgB,EAAE;QAChB,UAAU,EAAE,IAAI;QAChB,SAAS,EAAE,IAAI;KAChB;CACF,CAAC;KACD,IAAI,CAAC,GAAG,EAAE;IACT,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACf,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC;AACjC,CAAC,CAAC,CAAC"}

View File

@@ -0,0 +1,21 @@
import { type SvgToFontOptions } from './';
/**
* Generate Icon SVG Path Source
* <font-name>.json
*/
export declare function generateIconsSource(options?: SvgToFontOptions): Promise<string>;
/**
* Generate React Icon
* <font-name>.json
*/
export declare function generateReactIcons(options?: SvgToFontOptions): Promise<string>;
/**
* Generate ReactNative Icon
* <font-name>.json
*/
export declare function generateReactNativeIcons(options: SvgToFontOptions, unicodeObject: Record<string, string>): void;
/**
* Generate Vue Icon
* <font-name>.json
*/
export declare function generateVueIcons(options?: SvgToFontOptions): Promise<string>;

View File

@@ -0,0 +1,230 @@
import fs from 'fs-extra';
import path from 'path';
import { optimize } from 'svgo';
import { filterSvgFiles, toPascalCase } from './utils.js';
/**
* Generate Icon SVG Path Source
* <font-name>.json
*/
export async function generateIconsSource(options = {}) {
const ICONS_PATH = filterSvgFiles(options.src);
const data = await buildPathsObject(ICONS_PATH, options);
const outPath = path.join(options.dist, `${options.fontName}.json`);
await fs.outputFile(outPath, `{${data}\n}`);
return outPath;
}
/**
* Loads SVG file for each icon, extracts path strings `d="path-string"`,
* and constructs map of icon name to array of path strings.
* @param {array} files
*/
async function buildPathsObject(files, options = {}) {
const svgoOptions = options.svgoOptions || {};
return Promise.all(files.map(async (filepath) => {
const name = path.basename(filepath, '.svg');
const svg = fs.readFileSync(filepath, 'utf-8');
const pathStrings = optimize(svg, {
path: filepath,
...options,
plugins: [
'convertTransform',
...(svgoOptions.plugins || [])
// 'convertShapeToPath'
],
});
const str = (pathStrings.data.match(/ d="[^"]+"/g) || []).map(s => s.slice(3));
return `\n"${name}": [${str.join(',\n')}]`;
}));
}
const reactSource = (name, size, fontName, source) => `import React from 'react';
export const ${name} = props => (
<svg viewBox="0 0 20 20" ${size ? `width="${size}" height="${size}"` : ''} {...props} className={\`${fontName} \${props.className ? props.className : ''}\`}>${source}</svg>
);
`;
const reactTypeSource = (name) => `import React from 'react';
export declare const ${name}: (props: React.SVGProps<SVGSVGElement>) => JSX.Element;
`;
/**
* Generate React Icon
* <font-name>.json
*/
export async function generateReactIcons(options = {}) {
const ICONS_PATH = filterSvgFiles(options.src);
const data = await outputReactFile(ICONS_PATH, options);
const outPath = path.join(options.dist, 'react', 'index.js');
fs.outputFileSync(outPath, data.join('\n'));
fs.outputFileSync(outPath.replace(/\.js$/, '.d.ts'), data.join('\n'));
return outPath;
}
async function outputReactFile(files, options = {}) {
const svgoOptions = options.svgoOptions || {};
const fontSizeOpt = typeof options.css !== 'boolean' && options.css.fontSize;
const fontSize = typeof fontSizeOpt === 'boolean' ? (fontSizeOpt === true ? '16px' : '') : fontSizeOpt;
const fontName = options.classNamePrefix || options.fontName;
return Promise.all(files.map(async (filepath) => {
let name = toPascalCase(path.basename(filepath, '.svg'));
if (/^[rR]eact$/.test(name)) {
name = name + toPascalCase(fontName);
}
const svg = fs.readFileSync(filepath, 'utf-8');
const pathData = optimize(svg, {
path: filepath,
...svgoOptions,
plugins: [
'removeXMLNS',
'removeEmptyAttrs',
'convertTransform',
// 'convertShapeToPath',
// 'removeViewBox'
...(svgoOptions.plugins || [])
]
});
const str = (pathData.data.match(/ d="[^"]+"/g) || []).map(s => s.slice(3));
const outDistPath = path.join(options.dist, 'react', `${name}.js`);
const pathStrings = str.map((d, i) => `<path d=${d} fillRule="evenodd" />`);
const comName = isNaN(Number(name.charAt(0))) ? name : toPascalCase(fontName) + name;
fs.outputFileSync(outDistPath, reactSource(comName, fontSize, fontName, pathStrings.join(',\n')));
fs.outputFileSync(outDistPath.replace(/\.js$/, '.d.ts'), reactTypeSource(comName));
return `export * from './${name}';`;
}));
}
const reactNativeSource = (fontName, defaultSize, iconMap) => `import { Text } from 'react-native';
const icons = ${JSON.stringify(Object.fromEntries(iconMap))};
export const ${fontName} = ({iconName, ...rest}) => {
return (<Text style={{fontFamily: '${fontName}', fontSize: ${defaultSize}, color: '#000000', ...rest}}>
{icons[iconName]}
</Text>);
};
`;
const reactNativeTypeSource = (name, iconMap) => `import { TextStyle } from 'react-native';
export type ${name}IconNames = ${[...iconMap.keys()].reduce((acc, key, index) => {
if (index === 0) {
acc = `'${key}'`;
}
else {
acc += ` | '${key}'`;
}
return acc;
}, `${'string'}`)}
export interface ${name}Props extends Omit<TextStyle, 'fontFamily' | 'fontStyle' | 'fontWeight'> {
iconName: ${name}IconNames
}
export declare const ${name}: (props: ${name}Props) => JSX.Element;
`;
/**
* Generate ReactNative Icon
* <font-name>.json
*/
export function generateReactNativeIcons(options = {}, unicodeObject) {
const ICONS_PATH = filterSvgFiles(options.src);
outputReactNativeFile(ICONS_PATH, options, unicodeObject);
}
function outputReactNativeFile(files, options = {}, unicodeObject) {
const fontSizeOpt = typeof options.css !== 'boolean' && options.css.fontSize;
const fontSize = typeof fontSizeOpt === 'boolean' ? 16 : parseInt(fontSizeOpt);
const fontName = options.classNamePrefix || options.fontName;
const iconMap = new Map();
files.map(filepath => {
const baseFileName = path.basename(filepath, '.svg');
iconMap.set(baseFileName, unicodeObject[baseFileName]);
});
const outDistPath = path.join(options.dist, 'reactNative', `${fontName}.jsx`);
const comName = isNaN(Number(fontName.charAt(0))) ? fontName : toPascalCase(fontName) + name;
fs.outputFileSync(outDistPath, reactNativeSource(comName, fontSize, iconMap));
fs.outputFileSync(outDistPath.replace(/\.jsx$/, '.d.ts'), reactNativeTypeSource(comName, iconMap));
}
/**
* Generate Vue Icon
* <font-name>.json
*/
export async function generateVueIcons(options = {}) {
const ICONS_PATH = filterSvgFiles(options.src);
const data = await outputVueFile(ICONS_PATH, options);
const outPath = path.join(options.dist, 'vue', 'index.js');
fs.outputFileSync(outPath, data.join('\n'));
fs.outputFileSync(outPath.replace(/\.js$/, '.d.ts'), data.join('\n'));
return outPath;
}
async function outputVueFile(files, options = {}) {
const svgoOptions = options.svgoOptions || {};
const fontSizeOpt = typeof options.css !== 'boolean' && options.css.fontSize;
const fontSize = typeof fontSizeOpt === 'boolean' ? (fontSizeOpt === true ? '16px' : '') : fontSizeOpt;
const fontName = options.classNamePrefix || options.fontName;
return Promise.all(files.map(async (filepath) => {
let name = toPascalCase(path.basename(filepath, '.svg'));
if (/^[vV]ue$/.test(name)) {
name = name + toPascalCase(fontName);
}
const svg = fs.readFileSync(filepath, 'utf-8');
const pathData = optimize(svg, {
path: filepath,
...svgoOptions,
plugins: [
'removeXMLNS',
'removeEmptyAttrs',
'convertTransform',
// 'convertShapeToPath',
// 'removeViewBox'
...(svgoOptions.plugins || [])
]
});
const str = (pathData.data.match(/ d="[^"]+"/g) || []).map(s => s.slice(3));
const outDistPath = path.join(options.dist, 'vue', `${name}.js`);
const pathStrings = str.map((d, i) => `<path d=${d} fillRule="evenodd" />`);
const comName = isNaN(Number(name.charAt(0))) ? name : toPascalCase(fontName) + name;
fs.outputFileSync(outDistPath, vueSource(comName, fontSize, fontName, pathStrings.join(',\n')));
fs.outputFileSync(outDistPath.replace(/\.js$/, '.d.ts'), vueTypeSource(comName));
return `export * from './${name}';`;
}));
}
const vueSource = (name, size, fontName, source) => `import { defineComponent, h } from 'vue';
export const ${name} = defineComponent({
name: '${name}',
props: {
class: {
type: String,
default: ''
}
},
setup(props, { attrs }) {
return () => h(
'svg',
{
viewBox: '0 0 20 20',
${size ? `width: '${size}', height: '${size}',` : ''}
class: \`${fontName} \${props.class}\`,
...attrs
},
[
${source
.split('\n')
.filter(Boolean)
.map(path => {
const attrPairs = [];
const attrRegex = /([a-zA-Z\-:]+)=("[^"]*"|'[^']*'|[^\s"']+)/g;
let match;
const pathContent = path.replace(/^<path\s*|\s*\/?>$/g, '');
while ((match = attrRegex.exec(pathContent)) !== null) {
const key = match[1];
const value = match[2];
attrPairs.push(`"${key}": ${value}`);
}
return `h('path', {${attrPairs.join(', ')}})`;
})
.join(',\n ')}
]
);
}
});
`;
const vueTypeSource = (name) => `import type { DefineComponent } from 'vue';
declare const ${name}: DefineComponent<Record<string, any>>;
export { ${name} };
`;
//# sourceMappingURL=generate.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,209 @@
import { type SVGIcons2SVGFontStreamOptions } from 'svgicons2svgfont';
import { type AutoConfOption } from 'auto-config-loader';
import type { FontOptions } from 'svg2ttf';
import type { Config } from 'svgo';
import { type CSSOptions, type TypescriptOptions } from './utils.js';
export type SvgToFontOptions = {
/** Support for .svgtofontrc and more configuration files. */
config?: AutoConfOption<SvgToFontOptions>;
/** A value of `false` disables logging */
log?: boolean;
/** log callback function */
logger?: (message: string) => void;
/**
* The output directory.
* @default fonts
* @example
* ```
* path.join(process.cwd(), 'fonts')
* ```
*/
dist?: string;
/**
* svg path
* @default svg
* @example
* ```
* path.join(process.cwd(), 'svg')
* ```
*/
src?: string;
/**
* The font family name you want.
* @default iconfont
*/
fontName?: string;
/**
* Create CSS/LESS/Scss/Styl files, default `true`.
*/
css?: boolean | CSSOptions;
/**
* Output `./dist/react/`, SVG generates `react` components.
*/
outSVGReact?: boolean;
/**
* Output `./dist/reactNative/`, SVG generates `reactNative` component.
*/
outSVGReactNative?: boolean;
/**
* Output `./dist/vue/`, SVG generates `vue` components.
*/
outSVGVue?: boolean;
/**
* Output `./dist/svgtofont.json`, The content is as follows:
* @example
* ```js
* {
* "adobe": ["M14.868 3H23v19L14.868 3zM1 3h8.8.447z...."],
* "git": ["M2.6 10.59L8.38 4.8l1.69 1.7c-.24c-.6.34-1 .99-1..."],
* "stylelint": ["M129.74 243.648c28-100.5.816c2.65..."]
* }
* ```
*/
outSVGPath?: boolean;
/**
* Output `./dist/info.json`, The content is as follows:
* @example
* ```js
* {
* "adobe": {
* "encodedCode": "\\ea01",
* "prefix": "svgtofont",
* "className": "svgtofont-adobe",
* "unicode": "&#59905;"
* },
* .....
* }
* ```
*/
generateInfoData?: boolean;
/**
* This is the setting for [svgicons2svgfont](https://github.com/nfroidure/svgicons2svgfont/tree/dd713bea4f97afa59f7dba6a21ff7f22db565bcf#api)
*/
svgicons2svgfont?: Partial<SVGIcons2SVGFontStreamOptions>;
/** Some options can be configured with svgoOptions though it. [svgo](https://github.com/svg/svgo#configuration) */
svgoOptions?: Config;
/**
* Create font class name prefix, default value font name.
* @default fontName
*/
classNamePrefix?: SvgToFontOptions['fontName'];
/**
* Symbol Name Delimiter, @default `-`
*/
symbolNameDelimiter?: string;
/**
* Directory of custom templates.
*/
styleTemplates?: string;
/**
* unicode start number
* @default 10000
*/
startUnicode?: number;
/** Get Icon Unicode */
getIconUnicode?: (name: string, unicode: string, startUnicode: number) => [string, number];
/**
* should the name(file name) be used as unicode? this switch allows for the support of ligatures.
* @default false
*/
useNameAsUnicode?: boolean;
/**
* adds possibility to use name (file name) in addition to codepoints. adds support of ligatures.
* @default false
*/
addLigatures?: boolean;
/**
* consoles whenever {{ cssString }} template outputs unicode characters or css vars
* @default false
*/
useCSSVars?: boolean;
/**
* Clear output directory contents
* @default false
*/
emptyDist?: boolean;
/**
* This is the setting for [svg2ttf](https://github.com/fontello/svg2ttf/tree/c33a126920f46b030e8ce960cc7a0e38a6946bbc#svg2ttfsvgfontstring-options---buf)
*/
svg2ttf?: FontOptions;
/**
* You can configure which font files to exclude from generation. By default, all font files will be generated.
* https://github.com/jaywcjlove/svgtofont/issues/238
*/
excludeFormat?: Array<"eot" | "woff" | "woff2" | "ttf" | "svg" | "symbol.svg">;
website?: {
/**
* Add a Github corner to your website
* @like https://github.com/uiwjs/react-github-corners
*/
corners?: {
/**
* @example `https://github.com/jaywcjlove/svgtofont`
*/
url?: string;
/**
* @default 60
*/
width?: number;
/**
* @default 60
*/
height?: number;
/**
* @default #151513
*/
bgColor?: '#dc3545';
};
/**
* @default unicode
*/
index?: 'font-class' | 'unicode' | 'symbol';
/**
* website title
*/
title?: string;
/**
* @example
* ```js
* path.resolve(rootPath, "favicon.png")
* ```
*/
favicon?: string;
/**
* Must be a .svg format image.
* @example
* ```js
* path.resolve(rootPath, "svg", "git.svg")
* ```
*/
logo?: string;
version?: string;
meta?: {
description?: string;
keywords?: string;
};
description?: string;
template?: string;
footerInfo?: string;
links: Array<{
title: string;
url: string;
}>;
};
/**
* Create typescript file with declarations for icon classnames
* @default false
*/
typescript?: boolean | TypescriptOptions;
};
export type IconInfo = {
prefix: string;
symbol: string;
unicode: string;
className: string;
encodedCode: string | number;
};
export type InfoData = Record<string, Partial<IconInfo>>;
declare const _default: (options?: SvgToFontOptions) => Promise<InfoData>;
export default _default;

View File

@@ -0,0 +1,235 @@
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, generateVueIcons } from './generate.js';
import { createSVG, createTTF, createEOT, createWOFF, createWOFF2, createSvgSymbol, copyTemplate, createHTML, createTypescript } from './utils.js';
import { generateFontFaceCSS, getDefaultOptions } from './utils.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const loadConfig = async (options) => {
const defaultOptions = getDefaultOptions(options);
const data = await autoConf('svgtofont', {
mustExist: true,
default: defaultOptions,
...options.config,
});
return merge(defaultOptions, data);
};
const handlePkgConfig = (options) => {
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 = options.website.version ?? pkg.version;
}
}
return options;
};
export default async (options = {}) => {
options = await loadConfig(options);
options = handlePkgConfig(options);
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 excludeFormat = options.excludeFormat || [];
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);
/** @deprecated */
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.codePointAt(0);
if (options.useNameAsUnicode) {
symbolName = name;
iconPart = prefix + '">' + name;
encodedCodes = [..._code].map(x => x.codePointAt(0)).join(';&amp;#');
}
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">&amp;#${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);
if (!excludeFormat.includes('eot'))
await createEOT(options, ttf);
if (!excludeFormat.includes('woff'))
await createWOFF(options, ttf);
if (!excludeFormat.includes('woff2'))
await createWOFF2(options, ttf);
if (!excludeFormat.includes('symbol.svg'))
await createSvgSymbol(options);
const ttfPath = path.join(options.dist, options.fontName + ".ttf");
if (excludeFormat.includes('ttf')) {
fs.removeSync(ttfPath);
}
const svgPath = path.join(options.dist, options.fontName + ".svg");
if (excludeFormat.includes('svg')) {
fs.removeSync(svgPath);
}
if (options.css) {
const styleTemplatePath = options.styleTemplates || path.resolve(__dirname, 'styles');
const outDir = typeof options.css === 'object' ? options.css.output || options.dist : options.dist;
const hasTimestamp = typeof options.css === 'object' ? options.css.hasTimestamp : true;
const cssOptions = typeof options.css === 'object' ? options.css : {};
const fontFamilyString = generateFontFaceCSS(options.fontName, cssOptions.cssPath || "", Date.now(), excludeFormat, hasTimestamp);
await copyTemplate(styleTemplatePath, outDir, {
fontname: options.fontName,
cssString: cssString.join(''),
cssToVars: cssToVars.join(''),
infoData,
fontSize: fontSize,
timestamp: new Date().getTime(),
prefix,
fontFamily: fontFamilyString,
nameAsUnicode: options.useNameAsUnicode,
_opts: cssOptions
});
}
if (options.typescript) {
await createTypescript({ ...options, typescript: options.typescript });
}
if (options.website) {
const pageNames = ['font-class', 'unicode', 'symbol'];
const htmlPaths = {};
// setting default home page.
const indexName = pageNames.includes(options.website.index) ? options.website.index : 'font-class';
pageNames.forEach(name => {
const fileName = name === indexName ? 'index.html' : `${name}.html`;
htmlPaths[name] = path.join(options.dist, fileName);
});
const fontClassPath = htmlPaths['font-class'];
const unicodePath = htmlPaths['unicode'];
const symbolPath = htmlPaths['symbol'];
// default template
options.website.template = options.website.template || path.join(__dirname, 'website', 'index.njk');
// 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 ${symbolPath} `);
}
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. `);
}
if (options.outSVGVue) {
const outPath = await generateVueIcons(options);
log.log(`${color.green('SUCCESS')} Created Vue Components. `);
}
return infoData;
}
catch (error) {
log.log('SvgToFont:CLI:ERR:', error);
}
};
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
export declare class Log {
_disabled?: boolean;
constructor(disabled?: boolean);
get disabled(): boolean;
set disabled(val: boolean);
log: (message?: any, ...optionalParams: any[]) => void | (() => void);
error: (message?: any, ...optionalParams: any[]) => void | (() => void);
logger: (message?: string) => void;
}
export declare const log: Log;

View File

@@ -0,0 +1,29 @@
export class Log {
_disabled;
constructor(disabled) {
this.disabled = disabled || false;
}
get disabled() {
return this._disabled;
}
set disabled(val) {
this._disabled = val;
}
log = (message, ...optionalParams) => {
if (this.logger)
this.logger(message);
if (this.disabled)
return () => { };
return console.log(message, ...optionalParams);
};
error = (message, ...optionalParams) => {
if (this.logger)
this.logger(message);
if (this.disabled)
return () => { };
return console.error(message, ...optionalParams);
};
logger = (message) => { };
}
export const log = new Log();
//# sourceMappingURL=log.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"log.js","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,GAAG;IACd,SAAS,CAAU;IACnB,YAAY,QAAkB;QAC5B,IAAI,CAAC,QAAQ,GAAG,QAAQ,IAAI,KAAK,CAAA;IACnC,CAAC;IACD,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IACD,IAAI,QAAQ,CAAC,GAAY;QACvB,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;IACvB,CAAC;IACD,GAAG,GAAG,CAAC,OAAa,EAAE,GAAG,cAAqB,EAAE,EAAE;QAChD,IAAI,IAAI,CAAC,MAAM;YAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACtC,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,GAAG,EAAE,GAAE,CAAC,CAAA;QAClC,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,cAAc,CAAC,CAAA;IAChD,CAAC,CAAA;IACD,KAAK,GAAG,CAAC,OAAa,EAAE,GAAG,cAAqB,EAAE,EAAE;QAClD,IAAI,IAAI,CAAC,MAAM;YAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACtC,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,GAAG,EAAE,GAAE,CAAC,CAAA;QAClC,OAAO,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,cAAc,CAAC,CAAA;IAClD,CAAC,CAAA;IACD,MAAM,GAAG,CAAC,OAAgB,EAAE,EAAE,GAAE,CAAC,CAAA;CAClC;AAED,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC"}

View File

@@ -0,0 +1,14 @@
@font-face {
{{fontFamily}}
}
{% if nameAsUnicode %}.{{prefix}}{% else %}[class^="{{prefix}}-"], [class*=" {{prefix}}-"]{% endif %} {
font-family: '{{fontname}}' !important;{{fontSize}}
font-style:normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
{% if not nameAsUnicode %}
{{cssString}}
{% endif %}

View File

@@ -0,0 +1,14 @@
@font-face {
{{fontFamily}}
}
{% if nameAsUnicode %}.{{prefix}}{% else %}[class^="{{prefix}}-"], [class*=" {{prefix}}-"]{% endif %} {
font-family: '{{fontname}}' !important;{{fontSize}}
font-style:normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
{% if not nameAsUnicode %}
{{cssString}}
{% endif %}

View File

@@ -0,0 +1,16 @@
@font-face {
{{fontFamily}}
}
{% if nameAsUnicode %}.{{prefix}}{% else %}[class^="{{prefix}}-"], [class*=" {{prefix}}-"]{% endif %} {
font-family: '{{fontname}}' !important;{{fontSize}}
font-style:normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
{% if not nameAsUnicode %}
:global {
{{cssString}}
}
{% endif %}

View File

@@ -0,0 +1,17 @@
@font-face {
{{fontFamily}}
}
{% if nameAsUnicode %}.{{prefix}}{% else %}[class^="{{prefix}}-"], [class*=" {{prefix}}-"]{% endif %} {
font-family: '{{fontname}}' !important;{{fontSize}}
font-style:normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
{% if not nameAsUnicode %}
{{ cssString }}
{% for name, value in infoData %}
${{prefix}}-{{ name }}: '{{ value.encodedCode }}';
{%- endfor %}
{% endif %}

View File

@@ -0,0 +1,17 @@
@font-face {
{{fontFamily}}
}
{% if nameAsUnicode %}.{{prefix}}{% else %}[class^="{{prefix}}-"], [class*=" {{prefix}}-"]{% endif %} {
font-family: '{{fontname}}' !important;{{fontSize}}
font-style:normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
{% if not nameAsUnicode %}
{{ cssString }}
{% for name, value in infoData %}
${{prefix}}-{{ name }} = '{{ value.encodedCode }}'
{%- endfor %}
{% endif %}

View File

@@ -0,0 +1,98 @@
import { type SvgToFontOptions } from './';
/**
* SVG to SVG font
*/
export declare function createSVG(options?: SvgToFontOptions): Promise<Record<string, string>>;
/**
* Converts a string to pascal case.
*
* @example
*
* ```js
* toPascalCase('some_database_field_name'); // 'SomeDatabaseFieldName'
* toPascalCase('Some label that needs to be pascalized');
* // 'SomeLabelThatNeedsToBePascalized'
* toPascalCase('some-javascript-property'); // 'SomeJavascriptProperty'
* toPascalCase('some-mixed_string with spaces_underscores-and-hyphens');
* // 'SomeMixedStringWithSpacesUnderscoresAndHyphens'
* ```
*/
export declare const toPascalCase: (str: string) => string;
export declare function filterSvgFiles(svgFolderPath: string): string[];
export declare function snakeToUppercase(str: string): string;
export type TypescriptOptions = {
extension?: 'd.ts' | 'ts' | 'tsx';
enumName?: string;
};
/**
* Create typescript declarations for icon classnames
*/
export declare function createTypescript(options: Omit<SvgToFontOptions, 'typescript'> & {
typescript: TypescriptOptions | true;
}): Promise<void>;
/**
* SVG font to TTF
*/
export declare function createTTF(options?: SvgToFontOptions): Promise<Buffer>;
/**
* TTF font to EOT
*/
export declare function createEOT(options: SvgToFontOptions, ttf: Buffer): Promise<unknown>;
/**
* TTF font to WOFF
*/
export declare function createWOFF(options: SvgToFontOptions, ttf: Buffer): Promise<unknown>;
/**
* TTF font to WOFF2
*/
export declare function createWOFF2(options: SvgToFontOptions, ttf: Buffer): Promise<unknown>;
/**
* Create SVG Symbol
*/
export declare function createSvgSymbol(options?: SvgToFontOptions): Promise<unknown>;
export type CSSOptions = {
/**
* Output the css file to the specified directory
*/
output?: string;
/**
* Which files are exported.
*/
include?: RegExp;
/**
* Setting font size.
*/
fontSize?: string | boolean;
/**
* Set the path in the css file
* https://github.com/jaywcjlove/svgtofont/issues/48#issuecomment-739547189
*/
cssPath?: string;
/**
* Set file name
* https://github.com/jaywcjlove/svgtofont/issues/48#issuecomment-739547189
*/
fileName?: string;
/**
* Ad hoc template variables.
*/
templateVars?: Record<string, any>;
/**
* When including CSS files in a CSS file,
* you can add a timestamp parameter or custom text to the file path to prevent browser caching issues and ensure style updates are applied. @default true
* @example `path/to/iconfont.css?t=1612345678`
*/
hasTimestamp?: boolean | string;
};
/**
* Copy template files
*/
export declare function copyTemplate(inDir: string, outDir: string, { _opts, ...vars }: Record<string, any> & {
_opts: CSSOptions;
}): Promise<void>;
/**
* Create HTML
*/
export declare function createHTML(templatePath: string, data: Record<string, any>): string;
export declare function generateFontFaceCSS(fontName: string, cssPath: string, timestamp: number, excludeFormat: string[], hasTimestamp?: boolean | string): string;
export declare const getDefaultOptions: (options: SvgToFontOptions) => SvgToFontOptions;

View File

@@ -0,0 +1,323 @@
import { SVGIcons2SVGFontStream } from 'svgicons2svgfont';
import fs from 'fs-extra';
import path from 'path';
import color from 'colors-cli';
import { load } from 'cheerio';
import svg2ttf from 'svg2ttf';
import ttf2eot from 'ttf2eot';
import ttf2woff from 'ttf2woff';
import ttf2woff2 from 'ttf2woff2';
import nunjucks from 'nunjucks';
import { merge } from 'auto-config-loader';
import { log } from './log.js';
let UnicodeObj = {};
/**
* Unicode Private Use Area start.
* https://en.wikipedia.org/wiki/Private_Use_Areas
*/
let startUnicode = 0xea01;
/**
* SVG to SVG font
*/
export function createSVG(options = {}) {
startUnicode = options.startUnicode;
UnicodeObj = {};
return new Promise(async (resolve, reject) => {
const fontStream = new SVGIcons2SVGFontStream({
...options.svgicons2svgfont
});
function writeFontStream(svgPath) {
// file name
let _name = path.basename(svgPath, ".svg");
const glyph = fs.createReadStream(svgPath);
const curUnicode = String.fromCodePoint(startUnicode);
const [_curUnicode, _startUnicode] = options.getIconUnicode
? (options.getIconUnicode(_name, curUnicode, startUnicode) || [curUnicode]) : [curUnicode];
if (_startUnicode)
startUnicode = _startUnicode;
const unicode = [_curUnicode];
if (curUnicode === _curUnicode && (!_startUnicode || startUnicode === _startUnicode))
startUnicode++;
UnicodeObj[_name] = unicode[0];
if (!!options.useNameAsUnicode) {
unicode[0] = _name;
UnicodeObj[_name] = _name;
}
if (!!options.addLigatures) {
unicode.push(_name);
}
glyph.metadata = { unicode, name: _name };
fontStream.write(glyph);
}
const DIST_PATH = path.join(options.dist, options.fontName + ".svg");
// Setting the font destination
fontStream.pipe(fs.createWriteStream(DIST_PATH))
.on("finish", () => {
log.log(`${color.green('SUCCESS')} ${color.blue_bt('SVG')} font successfully created!\n ╰┈▶ ${DIST_PATH}`);
resolve(UnicodeObj);
})
.on("error", (err) => {
if (err) {
reject(err);
}
});
filterSvgFiles(options.src).forEach((svg) => {
if (typeof svg !== 'string')
return false;
writeFontStream(svg);
});
// Do not forget to end the stream
fontStream.end();
});
}
/**
* Converts a string to pascal case.
*
* @example
*
* ```js
* toPascalCase('some_database_field_name'); // 'SomeDatabaseFieldName'
* toPascalCase('Some label that needs to be pascalized');
* // 'SomeLabelThatNeedsToBePascalized'
* toPascalCase('some-javascript-property'); // 'SomeJavascriptProperty'
* toPascalCase('some-mixed_string with spaces_underscores-and-hyphens');
* // 'SomeMixedStringWithSpacesUnderscoresAndHyphens'
* ```
*/
export const toPascalCase = (str) => str
.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
.map(x => x.charAt(0).toUpperCase() + x.slice(1).toLowerCase())
.join('');
/*
* Filter svg files
* @return {Array} svg files
*/
export function filterSvgFiles(svgFolderPath) {
let files = fs.readdirSync(svgFolderPath, 'utf-8');
let svgArr = [];
if (!files) {
throw new Error(`Error! Svg folder is empty.${svgFolderPath}`);
}
for (let i in files) {
if (typeof files[i] !== 'string' || path.extname(files[i]) !== '.svg')
continue;
if (!~svgArr.indexOf(files[i])) {
svgArr.push(path.join(svgFolderPath, files[i]));
}
}
return svgArr;
}
export function snakeToUppercase(str) {
return str.split(/[-_]/)
.map(partial => partial.charAt(0).toUpperCase() + partial.slice(1))
.join('');
}
/**
* Create typescript declarations for icon classnames
*/
export async function createTypescript(options) {
const tsOptions = options.typescript === true ? {} : options.typescript;
const uppercaseFontName = snakeToUppercase(options.fontName);
const { extension = 'd.ts', enumName = uppercaseFontName } = tsOptions;
const DIST_PATH = path.join(options.dist, `${options.fontName}.${extension}`);
const fileNames = filterSvgFiles(options.src).map(svgPath => path.basename(svgPath, path.extname(svgPath)));
await fs.writeFile(DIST_PATH, [
`export enum ${enumName} {`,
...fileNames.map(name => ` ${snakeToUppercase(name)} = "${options.classNamePrefix}-${name}",`),
'}',
`export type ${enumName}Classname = ${fileNames.map(name => `"${options.classNamePrefix}-${name}"`).join(' | ')}`,
`export type ${enumName}Icon = ${fileNames.map(name => `"${name}"`).join(' | ')}`,
`export const ${enumName}Prefix = "${options.classNamePrefix}-"`,
].join('\n'));
log.log(`${color.green('SUCCESS')} Created ${DIST_PATH}`);
}
/**
* SVG font to TTF
*/
export function createTTF(options = {}) {
return new Promise((resolve, reject) => {
options.svg2ttf = options.svg2ttf || {};
const DIST_PATH = path.join(options.dist, options.fontName + ".ttf");
let ttf = svg2ttf(fs.readFileSync(path.join(options.dist, options.fontName + ".svg"), "utf8"), options.svg2ttf);
const ttfBuf = Buffer.from(ttf.buffer);
fs.writeFile(DIST_PATH, ttfBuf, (err) => {
if (err) {
return reject(err);
}
log.log(`${color.green('SUCCESS')} ${color.blue_bt('TTF')} font successfully created!\n ╰┈▶ ${DIST_PATH}`);
resolve(ttfBuf);
});
});
}
;
/**
* TTF font to EOT
*/
export function createEOT(options = {}, ttf) {
return new Promise((resolve, reject) => {
const DIST_PATH = path.join(options.dist, options.fontName + '.eot');
const eot = Buffer.from(ttf2eot(ttf).buffer);
fs.writeFile(DIST_PATH, eot, (err) => {
if (err) {
return reject(err);
}
log.log(`${color.green('SUCCESS')} ${color.blue_bt('EOT')} font successfully created!\n ╰┈▶ ${DIST_PATH}`);
resolve(eot);
});
});
}
;
/**
* TTF font to WOFF
*/
export function createWOFF(options = {}, ttf) {
return new Promise((resolve, reject) => {
const DIST_PATH = path.join(options.dist, options.fontName + ".woff");
const woff = Buffer.from(ttf2woff(ttf).buffer);
fs.writeFile(DIST_PATH, woff, (err) => {
if (err) {
return reject(err);
}
log.log(`${color.green('SUCCESS')} ${color.blue_bt('WOFF')} font successfully created!\n ╰┈▶ ${DIST_PATH}`);
resolve(woff);
});
});
}
;
/**
* TTF font to WOFF2
*/
export function createWOFF2(options = {}, ttf) {
return new Promise((resolve, reject) => {
const DIST_PATH = path.join(options.dist, options.fontName + ".woff2");
const woff2 = Buffer.from(ttf2woff2(ttf).buffer);
fs.writeFile(DIST_PATH, woff2, (err) => {
if (err) {
return reject(err);
}
log.log(`${color.green('SUCCESS')} ${color.blue_bt('WOFF2')} font successfully created!\n ╰┈▶ ${DIST_PATH}`);
resolve({
path: DIST_PATH
});
});
});
}
;
/**
* Create SVG Symbol
*/
export function createSvgSymbol(options = {}) {
const DIST_PATH = path.join(options.dist, `${options.fontName}.symbol.svg`);
const $ = load('<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="0" height="0" style="display:none;"></svg>');
return new Promise((resolve, reject) => {
filterSvgFiles(options.src).forEach(svgPath => {
const fileName = path.basename(svgPath, path.extname(svgPath));
let file = fs.readFileSync(svgPath, "utf8");
// trim xml declaration
file = file.replace(/<\?xml.*?\?>\s*/g, '').trim();
const svgNode = $(file);
const symbolNode = $("<symbol></symbol>");
symbolNode.attr("viewBox", svgNode.attr("viewBox"));
symbolNode.attr("id", `${options.classNamePrefix}-${fileName}`);
symbolNode.append(svgNode.html());
$('svg').append(symbolNode);
});
fs.writeFile(DIST_PATH, $.html("svg"), (err) => {
if (err) {
return reject(err);
}
log.log(`${color.green('SUCCESS')} ${color.blue_bt('Svg Symbol')} font successfully created!\n ╰┈▶ ${DIST_PATH}`);
resolve({
path: DIST_PATH,
svg: $.html("svg")
});
});
});
}
;
// As we are processing css files, we need to eacape HTML entities.
const safeNunjucks = nunjucks.configure({ autoescape: false });
/**
* Copy template files
*/
export async function copyTemplate(inDir, outDir, { _opts, ...vars }) {
const files = await fs.readdir(inDir, { withFileTypes: true });
const context = {
...(_opts.templateVars || {}),
...vars,
cssPath: _opts.cssPath || '',
filename: _opts.fileName || vars.fontname,
};
await fs.ensureDir(outDir);
for (const file of files) {
if (!file.isFile())
continue;
if (_opts.include && !(new RegExp(_opts.include)).test(file.name))
continue;
let newFileName = file.name.replace(/\.template$/, '').replace(/^_/, '');
for (const key in context)
newFileName = newFileName.replace(`{{${key}}}`, `${context[key]}`);
const template = await fs.readFile(path.join(inDir, file.name), 'utf8');
const content = safeNunjucks.renderString(template, context);
const filePath = path.join(outDir, newFileName);
await fs.writeFile(filePath, content);
log.log(`${color.green('SUCCESS')} Created ${filePath} `);
}
}
;
/**
* Create HTML
*/
export function createHTML(templatePath, data) {
return nunjucks.renderString(fs.readFileSync(templatePath, 'utf8'), {
...data,
Date: Date,
JSON: JSON,
Math: Math,
Number: Number,
Object: Object,
RegExp: RegExp,
String: String,
typeof: (v) => typeof v,
});
}
;
export function generateFontFaceCSS(fontName, cssPath, timestamp, excludeFormat, hasTimestamp = true) {
const timestamString = hasTimestamp === true ? `?t=${timestamp}` : (typeof hasTimestamp == 'string' ? `?t=${hasTimestamp}` : undefined);
const formats = [
{ ext: 'eot', format: 'embedded-opentype', ieFix: true },
{ ext: 'woff2', format: 'woff2' },
{ ext: 'woff', format: 'woff' },
{ ext: 'ttf', format: 'truetype' },
{ ext: 'svg', format: 'svg' }
];
let cssString = ` font-family: "${fontName}";\n`;
if (!excludeFormat.includes('eot')) {
cssString += ` src: url('${cssPath}${fontName}.eot${timestamString || ''}'); /* IE9*/\n`;
}
cssString += ' src: ';
const srcParts = formats
.filter(format => !excludeFormat.includes(format.ext))
.map(format => {
if (format.ext === 'eot') {
return `url('${cssPath}${fontName}.eot${timestamString || '?'}#iefix') format('${format.format}') /* IE6-IE8 */`;
}
return `url('${cssPath}${fontName}.${format.ext}${timestamString || ''}') format('${format.format}')`;
});
cssString += srcParts.join(',\n ') + ';';
return cssString;
}
export const getDefaultOptions = (options) => {
return merge({
dist: path.resolve(process.cwd(), 'fonts'),
src: path.resolve(process.cwd(), 'svg'),
startUnicode: 0xea01,
svg2ttf: {},
svgicons2svgfont: {
fontName: 'iconfont',
},
fontName: 'iconfont',
symbolNameDelimiter: '-',
}, options);
};
//# sourceMappingURL=utils.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,159 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ _title }}</title>
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
{% for k, v in meta|default({}) %}
<meta name="{{ k }}" content="{{ v }}">
{% endfor %}
{% if favicon %}
<link rel="icon" type="image/x-icon" href="{{ favicon }}">
{% endif %}
{% if _type === 'font-class' and _link %}
<link rel="stylesheet" href="{{ _link }}" />
{% endif %}
<style>
*{margin: 0;padding: 0;list-style: none;}
body { color: #696969; font: 12px/1.5 tahoma, arial, \5b8b\4f53, sans-serif; }
a { color: #333; text-decoration: underline; }
a:hover { color: rgb(9, 73, 209); }
.header { color: #333; text-align: center; padding: 80px 0 60px 0; min-height: 153px; font-size: 14px; }
.header .logo svg { height: 120px; width: 120px; }
.header h1 { font-size: 42px; padding: 26px 0 10px 0; }
.header sup {font-size: 14px; margin: 8px 0 0 8px; position: absolute; color: #7b7b7b; }
.info {
color: #999;
font-weight: normal;
max-width: 346px;
margin: 0 auto;
padding: 20px 0;
font-size: 14px;
}
.icons { max-width: 1190px; margin: 0 auto; }
.icons ul { text-align: center; }
.icons ul li {
vertical-align: top;
width: 120px;
display: inline-block;
text-align: center;
background-color: rgba(0,0,0,.02);
border-radius: 3px;
padding: 29px 0 10px 0;
margin-right: 10px;
margin-top: 10px;
transition: all 0.6s ease;
}
.icons ul li:hover { background-color: rgba(0,0,0,.06); }
.icons ul li:hover span { color: #3c75e4; opacity: 1; }
.icons ul li .unicode { color: #8c8c8c; opacity: 0.3; }
.icons ul li h4 {
font-weight: normal;
padding: 10px 0 5px 0;
display: block;
color: #8c8c8c;
font-size: 14px;
line-height: 12px;
opacity: 0.8;
}
.icons ul li:hover h4 { opacity: 1; }
.icons ul li svg { width: 24px; height: 24px; }
.icons ul li:hover { color: #3c75e4; }
.footer { text-align: center; padding: 10px 0 90px 0; }
.footer a { text-align: center; padding: 10px 0 90px 0; color: #696969;}
.footer a:hover { color: #0949d1; }
.links { text-align: center; padding: 50px 0 0 0; font-size: 14px; }
{% if _type === 'font-class' %}
.icons ul li.class-icon { font-size: 21px; line-height: 21px; padding-bottom: 20px; }
.icons ul li.class-icon p{ font-size: 12px; }
.icons ul li.class-icon [class^="{{ classNamePrefix }}-"]{ font-size: 26px; }
{% elif _type === 'unicode' %}
.icons ul .unicode-icon span { display: block; }
.icons ul .unicode-icon h4 { font-size: 12px; }
@font-face {
font-family: "{{ fontname }}";
src: url("{{ fontname }}.eot");
/* IE9*/
src: url("{{ fontname }}.eot#iefix") format("embedded-opentype"),
/* IE6-IE8 */
url("{{ fontname }}.woff2?{{ Date.now() }}") format("woff2"),
url("{{ fontname }}.woff?{{ Date.now() }}") format("woff"),
/* chrome, firefox */
url("{{ fontname }}.ttf?{{ Date.now() }}") format("truetype"),
/* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
url("{{ fontname }}.svg#{{ fontname }}?{{ Date.now() }}") format("svg");
/* iOS 4.1- */
}
.iconfont {
font-family: "{{ fontname }}" !important;
font-size: 26px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-webkit-text-stroke-width: 0.2px;
-moz-osx-font-smoothing: grayscale;
}
{% elif _type === 'symbol' %}
.icons ul li.symbol {padding: 28px 10px 16px 10px; width: 100px;}
.icons ul li.symbol svg {width: 34px; height: 34px;}
.icons ul li.symbol h4 {font-size: 12px;}
{% endif %}
{% if corners and corners.url %}
.github-corner:hover .octo-arm { animation: octocat-wave 560ms ease-in-out; }
.github-corner svg { position: fixed; z-index: 999; border: 0px; top: 0px; right: 0px;}
@keyframes octocat-wave{
0%, 100% { transform: rotate(0); }
20%, 60% { transform: rotate(-25deg); }
40%, 80% { transform: rotate(10deg); }
}
@media (max-width:500px){
.github-corner:hover .octo-arm { animation: none; }
.github-corner .octo-arm { animation: octocat-wave 560ms ease-in-out; }
}
{% endif %}
</style>
</head>
<body>
{% if corners and corners.url %}
<a href="{{ corners.url|default('#') }}" target="__blank" class="github-corner">
<svg width="{{ corners.width|default(60) }}" height="{{ corners.width|default(60) }}" viewBox="0 0 250 250" aria-hidden="true" style="fill: {{ corners.bgColor|default('#151513') }}; color: rgb(255, 255, 255); ">
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
<path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" class="octo-arm" style="transform-origin: 130px 106px;"></path>
<path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path>
</svg>
</a>
{% endif %}
<div class="header">
{% if typeof(logo) === 'string' %}
<div class="logo">
<a href="./">{{ logo }}</a>
</div>
{% endif %}
<h1>{{ _title }}<sup>{{ version }}</sup></h1>
<div class="info">
{{ description|default(meta.description) }}
</div>
<p>
{% for linkItem in links|default([]) %}
<a href="{{ linkItem.url }}">{{ linkItem.title }}</a>{% if not loop.last %} · {% endif %}
{% endfor %}
</p>
</div>
<div class="icons">
<ul>
{{ _IconHtml|safe }}
</ul>
</div>
<p class="links">
{% for linkItem in links|default([]) %}
<a href="{{ linkItem.url }}">{{ linkItem.title }}</a>{% if not loop.last %} · {% endif %}
{% endfor %}
</p>
<div class="footer">
{{ footerInfo|safe }}
<div><a target="_blank" href="https://github.com/jaywcjlove/svgtofont">Created By svgtofont</a></div>
</div>
</body>
</html>