iconfont build

This commit is contained in:
codecalm 2024-02-17 17:28:56 +01:00
parent 34dda0cb41
commit 489afa542f
7 changed files with 151 additions and 125 deletions

View File

@ -1,6 +1,6 @@
import fs from 'fs-extra'
import path from 'path'
import { PACKAGES_DIR, readAliases, toPascalCase, getAllIcons } from './helpers.mjs'
import { PACKAGES_DIR, getAliases, toPascalCase, getAllIcons } from './helpers.mjs'
import { stringify } from 'svgson'
import prettier from "@prettier/sync"
@ -27,7 +27,7 @@ export const buildJsIcons = ({
indexFile = 'icons.ts'
}) => {
const DIST_DIR = path.resolve(PACKAGES_DIR, name);
const aliases = readAliases(),
const aliases = getAliases(),
allIcons = getAllIcons(false, true)
let index = []

View File

@ -150,23 +150,39 @@ export const readSvgDirectory = (directory) => {
return fs.readdirSync(directory).filter((file) => path.extname(file) === '.svg')
}
export const readAliases = () => {
export const getAliases = (groupped = false) => {
const allAliases = JSON.parse(fs.readFileSync(resolve(HOME_DIR, 'aliases.json'), 'utf-8'));
const allIcons = getAllIcons()
let aliases = [];
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] = {};
for (const [key, value] of Object.entries(allAliases[type])) {
if (icons.includes(value)) {
aliases[`${key}${type !== 'outline' ? `-${type}` : ''}`] = `${value}${type !== 'outline' ? `-${type}` : ''}`;
for (const [key, value] of Object.entries(allAliases[type])) {
if (icons.includes(value)) {
aliases[type][key] = value;
}
}
}
});
});
return aliases
return aliases
} else {
let aliases = [];
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}` : ''}`;
}
}
});
return aliases
}
}
/**

View File

@ -6,8 +6,7 @@
"**/CVS": true,
"**/.DS_Store": true,
"**/Thumbs.db": true,
"**/.idea/": true,
"icons": false
"**/.idea/": true
},
"explorerExclude.backup": {}
}

View File

@ -1,5 +1,5 @@
import outlineStroke from 'svg-outline-stroke'
import { asyncForEach, getCompileOptions, getPackageDir, HOME_DIR, readSvgs } from '../../../.build/helpers.mjs'
import { asyncForEach, getAllIcons, getCompileOptions, getPackageDir, HOME_DIR } from '../../../.build/helpers.mjs'
import fs from 'fs'
import { resolve, basename } from 'path'
import crypto from 'crypto'
@ -9,98 +9,102 @@ import { execSync } from 'child_process'
const DIR = getPackageDir('icons-webfont')
const buildOutline = async () => {
let files = readSvgs(),
filesList = []
let filesList = {}
const icons = getAllIcons(true)
const compileOptions = getCompileOptions(),
iconfontUnicode = JSON.parse(fs.readFileSync(resolve(HOME_DIR, 'tags.json'), 'utf-8'))
const compileOptions = getCompileOptions()
await asyncForEach(files, async function ({ name, contents }) {
if (compileOptions.includeIcons.length === 0 || compileOptions.includeIcons.indexOf(name) >= 0) {
await asyncForEach(Object.entries(icons), async ([type, icons]) => {
fs.mkdirSync(resolve(DIR, `icons-outlined/${type}`), { recursive: true })
filesList[type] = []
if (iconfontUnicode[name]) {
const unicode = iconfontUnicode[name].unicode
console.log('Stroke for:', name, unicode)
await asyncForEach(icons, async function ({ name, content, unicode }) {
console.log(type, name);
if (compileOptions.includeIcons.length === 0 || compileOptions.includeIcons.indexOf(name) >= 0) {
let filename = `${name}.svg`
if (unicode) {
filename = `u${unicode.toUpperCase()}-${name}.svg`
}
console.log('Stroke for:', name, unicode)
filesList.push(filename)
contents = contents
.replace('width="24"', 'width="1000"')
.replace('height="24"', 'height="1000"')
if (compileOptions.strokeWidth) {
contents = contents
.replace('stroke-width="2"', `stroke-width="${compileOptions.strokeWidth}"`)
}
const cachedFilename = `u${unicode.toUpperCase()}-${name}.svg`;
if (unicode && fs.existsSync(resolve(DIR, `icons-outlined/${cachedFilename}`))) {
// Get content
let cachedContent = fs.readFileSync(resolve(DIR, `icons-outlined/${cachedFilename}`), 'utf-8')
// Get hash
let cachedHash = '';
cachedContent = cachedContent.replace(/<!--\!cache:([a-z0-9]+)-->/, function (m, hash) {
cachedHash = hash;
return '';
})
// Check hash
if (crypto.createHash('sha1').update(cachedContent).digest("hex") === cachedHash) {
console.log('Cached stroke for:', name, unicode)
return true;
let filename = `${name}.svg`
if (unicode) {
filename = `u${unicode.toUpperCase()}-${name}.svg`
}
filesList[type].push(filename)
content = content
.replace('width="24"', 'width="1000"')
.replace('height="24"', 'height="1000"')
if (compileOptions.strokeWidth) {
content = content
.replace('stroke-width="2"', `stroke-width="${compileOptions.strokeWidth}"`)
}
const cachedFilename = `u${unicode.toUpperCase()}-${name}.svg`;
if (unicode && fs.existsSync(resolve(DIR, `icons-outlined/${type}/${cachedFilename}`))) {
// Get content
let cachedContent = fs.readFileSync(resolve(DIR, `icons-outlined/${type}/${cachedFilename}`), 'utf-8')
// Get hash
let cachedHash = '';
cachedContent = cachedContent.replace(/<!--\!cache:([a-z0-9]+)-->/, function (m, hash) {
cachedHash = hash;
return '';
})
// Check hash
if (crypto.createHash('sha1').update(cachedContent).digest("hex") === cachedHash) {
console.log('Cached stroke for:', name, unicode)
return true;
}
}
await outlineStroke(content, {
optCurve: true,
steps: 4,
round: 0,
centerHorizontally: true,
fixedWidth: false,
color: 'black'
}).then(outlined => {
// Save file
fs.writeFileSync(resolve(DIR, `icons-outlined/${type}/${filename}`), outlined, 'utf-8')
// Fix outline
execSync(`fontforge -lang=py -script .build/fix-outline.py icons-outlined/${type}/${filename}`).toString()
execSync(`svgo icons-outlined/${type}/${filename}`).toString()
// Add hash
const fixedFileContent = fs
.readFileSync(resolve(DIR, `icons-outlined/${type}/${filename}`), 'utf-8')
.replace(/\n/g, ' ')
.trim(),
hashString = `<!--!cache:${crypto.createHash('sha1').update(fixedFileContent).digest("hex")}-->`
// Save file
fs.writeFileSync(
resolve(DIR, `icons-outlined/${type}/${filename}`),
fixedFileContent + hashString,
'utf-8'
)
}).catch(error => console.log(error))
}
await outlineStroke(contents, {
optCurve: true,
steps: 4,
round: 0,
centerHorizontally: true,
fixedWidth: false,
color: 'black'
}).then(outlined => {
filesList[filename]
// Save file
fs.writeFileSync(resolve(DIR, `icons-outlined/${filename}`), outlined, 'utf-8')
// Fix outline
execSync(`fontforge -lang=py -script .build/fix-outline.py icons-outlined/${filename}`)
execSync(`svgo icons-outlined/${filename}`)
// Add hash
const fixedFileContent = fs
.readFileSync(resolve(DIR, `icons-outlined/${filename}`), 'utf-8')
.replace(/\n/g, ' ')
.trim(),
hashString = `<!--!cache:${crypto.createHash('sha1').update(fixedFileContent).digest("hex")}-->`
// Save file
fs.writeFileSync(
resolve(DIR, `icons-outlined/${filename}`),
fixedFileContent + hashString,
'utf-8'
)
}).catch(error => console.log(error))
}
}
})
})
// Remove old files
const existedFiles = (await glob(resolve(DIR, `icons-outlined/*.svg`))).map(file => basename(file))
existedFiles.forEach(file => {
if (filesList.indexOf(file) === -1) {
console.log('Remove:', file)
fs.unlinkSync(resolve(DIR, `icons-outlined/${file}`))
}
await asyncForEach(Object.entries(icons), async ([type, icons]) => {
const existedFiles = (await glob(resolve(DIR, `icons-outlined/${type}/*.svg`))).map(file => basename(file))
existedFiles.forEach(file => {
if (filesList[type].indexOf(file) === -1) {
console.log('Remove:', file)
fs.unlinkSync(resolve(DIR, `icons-outlined/${type}/${file}`))
}
})
})
console.log('Done')

View File

@ -1,54 +1,61 @@
import { webfont } from "webfont";
import * as fs from 'fs'
import template from 'lodash.template'
import { getPackageDir, getPackageJson, PACKAGES_DIR, readAliases } from '../../../.build/helpers.mjs'
import { getPackageDir, getPackageJson, getAliases, types, asyncForEach } from '../../../.build/helpers.mjs'
const formats = ['ttf', 'eot', 'woff', 'woff2']
const formats = ['ttf', 'woff', 'woff2']
const p = getPackageJson()
const DIR = getPackageDir('icons-webfont')
const fontHeight = 1000
const aliases = readAliases()
const aliases = getAliases(true)
webfont({
files: 'icons-outlined/*.svg',
fontName: 'tabler-icons',
prependUnicode: true,
formats,
normalize: true,
fontHeight,
descent: 100,
ascent: 900,
fixedWidth: false
})
fs.mkdirSync(`${DIR}/dist/fonts`, { recursive: true })
asyncForEach(types, async type => {
console.log(`Building webfont for ${type} icons`)
await webfont({
files: `icons-outlined/${type}/*.svg`,
fontName: 'tabler-icons',
prependUnicode: true,
formats,
normalize: true,
fontHeight,
descent: 100,
ascent: 900,
fixedWidth: false
})
.then((result) => {
formats.forEach(format => {
fs.writeFileSync(`${PACKAGES_DIR}/icons-webfont/fonts/tabler-icons.${format}`, result[format])
fs.writeFileSync(`${DIR}/dist/fonts/tabler-icons${type !== 'outline' ? `-${type}` : ''}.${format}`, result[format])
})
const glyphs = result.glyphsData
.map(icon => icon.metadata)
.sort(function(a, b) {
return ('' + a.name).localeCompare(b.name)
})
.map(icon => icon.metadata)
.sort(function (a, b) {
return ('' + a.name).localeCompare(b.name)
})
let options = {
console.log(aliases[type])
const options = {
fileName: 'tabler-icons',
glyphs,
v: p.version,
aliases
aliases: aliases[type] || {}
}
//scss
const compiled = template(fs.readFileSync(`${DIR}/.build/iconfont.scss`).toString())
const resultSCSS = compiled(options)
fs.writeFileSync(`${DIR}/tabler-icons.scss`, resultSCSS)
fs.writeFileSync(`${DIR}/dist/tabler-icons${type !== 'outline' ? `-${type}` : ''}.scss`, resultSCSS)
//html
const compiledHtml = template(fs.readFileSync(`${DIR}/.build/iconfont.html`).toString())
const resultHtml = compiledHtml(options)
fs.writeFileSync(`${DIR}/tabler-icons.html`, resultHtml)
fs.writeFileSync(`${DIR}/dist/tabler-icons${type !== 'outline' ? `-${type}` : ''}.html`, resultHtml)
})
.catch((error) => {
throw error;
});
})

View File

@ -13,9 +13,7 @@ $ti-prefix: 'ti' !default;
font-style: normal;
font-weight: 400;
font-display: $ti-font-display;
src: url('#{$ti-font-path}/<%= fileName %>.eot?v<%= v %>');
src: url('#{$ti-font-path}/<%= fileName %>.eot?#iefix-v<%= v %>') format('embedded-opentype'),
url('#{$ti-font-path}/<%= fileName %>.woff2?v<%= v %>') format('woff2'),
src: url('#{$ti-font-path}/<%= fileName %>.woff2?v<%= v %>') format('woff2'),
url('#{$ti-font-path}/<%= fileName %>.woff?') format('woff'),
url('#{$ti-font-path}/<%= fileName %>.ttf?v<%= v %>') format('truetype');
}

View File

@ -17,11 +17,13 @@
},
"scripts": {
"build": "pnpm run copy && pnpm run build:prepare && pnpm run build:outline && pnpm run build:webfont && pnpm run build:css",
"build:prepare": "mkdir -p icons-outlined fonts && rm -fd fonts/*",
"build:prepare": "mkdir -p icons-outlined dist && rm -fdr dist/*",
"build:outline": "node .build/build-outline.mjs",
"build:webfont": "rm -fd fonts/* && node .build/build-webfont.mjs",
"build:css": "sass tabler-icons.scss tabler-icons.css --style expanded && sass tabler-icons.scss tabler-icons.min.css --style compressed",
"build:clean": "rm -rf ./icons-outlined",
"build:webfont": "rm -fd dist/fonts/* && node .build/build-webfont.mjs",
"build:css": "pnpm run build:css:outline && pnpm run build:css:filled",
"build:css:outline": "sass dist/tabler-icons.scss dist/tabler-icons.css --style expanded && sass dist/tabler-icons.scss dist/tabler-icons.min.css --style compressed",
"build:css:filled": "sass dist/tabler-icons-filled.scss dist/tabler-icons-filled.css --style expanded && sass dist/tabler-icons-filled.scss dist/tabler-icons-filled.min.css --style compressed",
"clean": "rm -rf dist && rm -rf ./icons-outlined",
"copy": "pnpm run copy:license",
"copy:license": "cp ../../LICENSE ./LICENSE"
},