Changed font creation process (#1413)

* Changed font creation process

* Class name prefix

Class name prefix added for backward compatibility.

* Container option in workflow removed

Removed the container option in github workflow lucide-font because it is not needed anymore, workflow was changed to nodejs only

* Fixed whitespaces in package.json

* Use releaseInformation instead of info.json

* Added workflow step

* Moved unicode numbers to convert function

* Added locale argument to sort function

* Delete pnpm-lock

* Updated versions, recreated pnpm-lock

* Updated dependencies

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
This commit is contained in:
Oliver Schmidt
2023-09-13 21:05:22 +02:00
committed by GitHub
parent a4076db69b
commit b8c3a5fa0b
8 changed files with 1892 additions and 993 deletions

View File

@@ -10,7 +10,6 @@ on:
jobs:
lucide-font:
runs-on: ubuntu-latest
container: ericfennis/lucide-font:latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3.4.1
@@ -43,11 +42,11 @@ jobs:
- name: Outline svg Icons
run: pnpm build:outline-icons
- name: Create directory
run: mkdir lucide-font
- name: Install dependencies
run: pnpm install --filter build-font
- name: Build font
run: fontcustom compile "./outlined" -h -n "lucide" -o ./lucide-font -F
- name: Create font in ./lucide-font
run: pnpm build:font
- name: "Upload to Artifacts"
uses: actions/upload-artifact@v1

View File

@@ -16,6 +16,7 @@
"lucide-static": "pnpm --filter lucide-static",
"build:icons": "node ./scripts/buildIcons.mjs --templateSrc ./packages/lucide/scripts/exportTemplate.mjs",
"build:outline-icons": "pnpm --filter outline-svg start",
"build:font": "pnpm --filter docs prebuild:releaseJson && pnpm --filter build-font start",
"generate:supersprite": "node ./scripts/generateSuperSVG.mjs",
"optimize": "node ./scripts/optimizeSvgs.mjs",
"addjsons": "node scripts/addMissingIconJsonFiles.mjs",

2671
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

124
tools/build-font/main.mjs Normal file
View File

@@ -0,0 +1,124 @@
import { readJson } from 'fs-extra/esm';
import svgtofont from 'svgtofont';
import getArgumentOptions from 'minimist';
import path from 'path';
const fontName = 'lucide';
const classNamePrefix = 'icon';
const startUnicode = 57400;
const inputDir = path.join(process.cwd(), '../../', 'outlined');
const cliArguments = getArgumentOptions(process.argv.slice(2));
const { outputDir = 'lucide-font' } = cliArguments;
const targetDir = path.join(process.cwd(), '../../', outputDir);
const releaseMetaDataDir = path.join(process.cwd(), '../../', 'docs/.vitepress/data');
const releaseMetaDataPath = path.resolve(releaseMetaDataDir, 'releaseMetaData.json');
const releaseMetaData = convertReleaseMetaData(await getReleaseMetaData());
async function getReleaseMetaData() {
let releaseMetaData = {};
try {
releaseMetaData = await readJson(releaseMetaDataPath);
} catch (err) {
throw new Error('Execution stopped because no release information was found.');
}
return releaseMetaData;
}
function convertReleaseMetaData(releaseMetaData) {
return Object.entries(releaseMetaData)
.map(([key, value]) => [key, addAttribute(value, 'name', key)])
.map(([, value]) => value)
.sort((a, b) => sortMultiple(a, b, [sortByCreatedReleaseDate, sortByName]))
.map((value, index) => addAttribute(value, 'index', index))
.map((value, index) => addAttribute(value, 'unicode', index + startUnicode));
}
function addAttribute(obj, attribute, value) {
obj[attribute] = value;
return obj;
}
function sortMultiple(a, b, collators = []) {
const comparison = collators.shift()(a, b);
if (comparison === 0 && collators.length > 0) return sortMultiple(a, b, collators);
return comparison;
}
function sortByCreatedReleaseDate(a, b) {
const dates = [a, b].map((value) => new Date(value.createdRelease.date).valueOf());
return (dates[0] > dates[1]) - (dates[0] < dates[1]);
}
function sortByName(a, b) {
return new Intl.Collator('en-US').compare(a.name, b.name);
}
function getIconUnicode(name) {
const { unicode } = releaseMetaData.find(({ name: iconname }) => iconname === name);
return String.fromCharCode(unicode);
}
async function init() {
console.time('Font generation');
try {
await svgtofont({
src: path.resolve(process.cwd(), inputDir),
dist: path.resolve(process.cwd(), targetDir),
// styleTemplates: path.resolve(process.cwd(), 'styles'), // Add different templates if needed
fontName,
classNamePrefix,
css: {
fontSize: 'inherit',
},
emptyDist: true,
useCSSVars: false,
outSVGReact: false,
outSVGPath: false,
svgicons2svgfont: {
fontHeight: 1000, // At least 1000 is recommended
normalize: false,
},
generateInfoData: true,
website: {
title: 'Lucide',
logo: null,
meta: {
description: 'Lucide icons as TTF/EOT/WOFF/WOFF2/SVG.',
keywords: 'Lucide,TTF,EOT,WOFF,WOFF2,SVG',
},
corners: {
url: 'https://github.com/lucide-icons/lucide',
width: 62, // default: 60
height: 62, // default: 60
bgColor: '#dc3545', // default: '#151513'
},
links: [
{
title: 'GitHub',
url: 'https://github.com/lucide-icons/lucide',
},
{
title: 'Feedback',
url: 'https://github.com/lucide-icons/lucide/issues',
},
{
title: 'Font Class',
url: 'index.html',
},
{
title: 'Unicode',
url: 'unicode.html',
},
],
},
getIconUnicode,
});
} catch (err) {
console.log(err);
}
console.timeEnd('Font generation');
}
init();

View File

@@ -0,0 +1,18 @@
{
"name": "build-font",
"private": true,
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node ./main.mjs"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"fs-extra": "^11.1.1",
"minimist": "^1.2.8",
"svgtofont": "^3.25.4"
}
}

View File

View File

@@ -1,6 +1,5 @@
import { promises as fs } from 'fs';
import outlineStroke from 'svg-outline-stroke';
import { parse, stringify } from 'svgson';
import SVGFixer from 'oslllo-svg-fixer';
import getArgumentOptions from 'minimist';
import path from 'path';
@@ -9,31 +8,6 @@ const cliArguments = getArgumentOptions(process.argv.slice(2));
const { outputDir = 'outlined' } = cliArguments;
const targetDir = path.join(process.cwd(), '../../', outputDir);
function transformForward(node) {
if (node.name === 'svg') {
return {
...node,
attributes: {
...node.attributes,
width: 960,
height: 960,
},
};
}
return node;
}
function transformBackwards(node) {
if (node.name === 'svg') {
const { width, height, ...attributes } = node.attributes;
return {
...node,
attributes,
};
}
return node;
}
async function init() {
console.time('icon outliner');
try {
@@ -41,29 +15,10 @@ async function init() {
await fs.mkdir(targetDir);
} catch (error) {} // eslint-disable-line no-empty
const icons = (await fs.readdir(inputDir)).filter((file) => path.extname(file) === '.svg');
const parsedIconNodes = await Promise.all(
icons.map(async (file) => {
const inputFilePath = path.resolve(process.cwd(), inputDir, file);
const iconContent = await fs.readFile(inputFilePath);
const iconNode = await parse(iconContent.toString(), {
transformNode: transformForward,
});
return [file, iconNode];
}),
);
await Promise.all(
parsedIconNodes.map(async ([file, iconNode]) => {
const outlined = await outlineStroke(stringify(iconNode));
const outlinedWithoutAttrs = await parse(outlined, {
transformNode: transformBackwards,
});
const filePath = path.join(targetDir, file);
await fs.writeFile(filePath, stringify(outlinedWithoutAttrs));
}),
);
await SVGFixer(inputDir, targetDir, {
showProgressBar: true,
traceResolution: 800,
}).fix();
console.timeEnd('icon outliner');
} catch (err) {

View File

@@ -1,7 +1,7 @@
{
"name": "outline-svg",
"private": true,
"version": "1.0.0",
"version": "2.0.0",
"description": "",
"main": "index.js",
"scripts": {
@@ -11,8 +11,7 @@
"author": "",
"license": "ISC",
"dependencies": {
"minimist": "^1.2.6",
"svg-outline-stroke": "^1.3.1",
"svgson": "^5.2.1"
"minimist": "^1.2.8",
"oslllo-svg-fixer": "^2.2.0"
}
}