wmt-polyicon 0.1.5 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +268 -62
- package/package.json +8 -3
- package/src/cli/commands/generate.js +11 -2
- package/src/cli/commands/init.js +27 -1
- package/src/cli/index.js +4 -4
- package/src/config/defaults.js +8 -6
- package/src/config/load.js +3 -1
- package/src/constants.js +1 -1
- package/src/generator/index.js +47 -7
- package/src/generator/parse_svg.js +2 -4
- package/src/generator/run_svgtofont.js +3 -3
- package/src/generator/write_css.js +8 -10
- package/src/generator/write_fonts.js +3 -5
- package/src/generator/write_html.js +5 -7
- package/src/generator/write_polyicon_config.js +2 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.2.0] — 2026-04-08
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **`fontName` config option** — controls font-family name and output filenames (default: `"fontello"`). Generate drop-in replacements for existing Fontello fonts
|
|
9
|
+
- **`hashOutput` config option** — appends a content hash to the output folder for cache busting (default: `true`). Same icons = same hash; change an SVG = new hash. Old hashed folders are auto-deleted on regenerate
|
|
10
|
+
- **Commented `.polyiconrc`** — `polyicon init` now creates a config file with inline comments explaining every field
|
|
11
|
+
- **Improved CLI output** — `polyicon init` shows next steps; `polyicon generate` shows full output paths and usage example
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- Default output paths changed from `./src/assets/` to `./public/assets/` (more common in modern web projects)
|
|
15
|
+
- Default `fontName` changed from `"polyicon"` to `"fontello"` — output now matches traditional Fontello structure
|
|
16
|
+
- Default `outputStyles` changed from `polyicon.css` to `fontello.css`
|
|
17
|
+
- Preview file renamed from `{fontName}-preview.html` to `demo.html`
|
|
18
|
+
- Config parser now supports `//` comments in `.polyiconrc`
|
|
19
|
+
|
|
20
|
+
## [0.1.6] — 2026-04-02
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
- Configurable `classPrefix` — the `.polyiconrc` `classPrefix` field now correctly propagates to CSS selectors, HTML preview, and config.json output
|
|
24
|
+
|
|
5
25
|
## [0.1.5] — 2026-04-02
|
|
6
26
|
|
|
7
27
|
### Fixed
|
package/README.md
CHANGED
|
@@ -1,121 +1,327 @@
|
|
|
1
|
-
#
|
|
1
|
+
# wmt-polyicon
|
|
2
2
|
|
|
3
|
-
SVG to icon font generator
|
|
3
|
+
SVG to icon font generator — drop in SVGs, get a production-ready Fontello-style icon font with one command.
|
|
4
4
|
|
|
5
|
-
Converts a folder of SVGs into `woff2`, `woff`, `ttf`, `eot`, `svg` font files plus
|
|
5
|
+
Converts a folder of SVGs into `woff2`, `woff`, `ttf`, `eot`, `svg` font files plus CSS, JS constants, and an interactive preview page.
|
|
6
|
+
|
|
7
|
+
---
|
|
6
8
|
|
|
7
9
|
## Install
|
|
8
10
|
|
|
9
11
|
```bash
|
|
10
|
-
#
|
|
11
|
-
npm i -
|
|
12
|
+
# global (recommended)
|
|
13
|
+
npm i -g wmt-polyicon
|
|
12
14
|
|
|
13
|
-
# or
|
|
14
|
-
npm i -
|
|
15
|
+
# or project dev dependency
|
|
16
|
+
npm i -D wmt-polyicon
|
|
15
17
|
|
|
16
18
|
# or one-off
|
|
17
|
-
npx polyicon init
|
|
19
|
+
npx wmt-polyicon init
|
|
18
20
|
```
|
|
19
21
|
|
|
20
22
|
## Quick Start
|
|
21
23
|
|
|
22
24
|
```bash
|
|
23
|
-
polyicon init
|
|
24
|
-
|
|
25
|
+
polyicon init # creates .polyiconrc with defaults
|
|
26
|
+
# edit .polyiconrc → set "svg" to your SVG folder
|
|
27
|
+
polyicon generate # builds fonts, CSS, types, and preview
|
|
25
28
|
```
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
That's it — 3 steps:
|
|
31
|
+
|
|
32
|
+
1. `polyicon init`
|
|
33
|
+
2. Change `"svg"` path in `.polyiconrc`
|
|
34
|
+
3. `polyicon generate`
|
|
35
|
+
|
|
36
|
+
---
|
|
28
37
|
|
|
29
38
|
## Config (`.polyiconrc`)
|
|
30
39
|
|
|
31
|
-
|
|
40
|
+
Running `polyicon init` creates a fully commented config file:
|
|
41
|
+
|
|
42
|
+
```jsonc
|
|
32
43
|
{
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"
|
|
44
|
+
// Path to your SVG icons folder (change this to your SVG folder)
|
|
45
|
+
"svg": "./public/assets/svg",
|
|
46
|
+
|
|
47
|
+
// Output paths
|
|
48
|
+
"outputFonts": "./public/assets/fontello/font",
|
|
49
|
+
"outputStyles": "./public/assets/fontello/css/fontello.css",
|
|
50
|
+
"outputTypes": "./public/assets/fontello/IconTypes.js",
|
|
51
|
+
"polyiconConfig": "./public/assets/fontello/config.json",
|
|
52
|
+
|
|
53
|
+
// Font URL prefix used inside the generated CSS (relative to CSS file)
|
|
38
54
|
"importFontsPath": "../font/",
|
|
39
|
-
|
|
55
|
+
// Font file formats to generate
|
|
56
|
+
"formats": ["eot", "svg", "ttf", "woff", "woff2"],
|
|
57
|
+
// Font family name used in CSS and font filenames
|
|
58
|
+
"fontName": "fontello",
|
|
59
|
+
// CSS class prefix (e.g. "icon" → .icon-home, "pi" → .pi-home)
|
|
60
|
+
"classPrefix": "icon",
|
|
61
|
+
// Append content hash to output folder for cache busting (e.g. fontello-a3f7b2c1/)
|
|
62
|
+
"hashOutput": true
|
|
40
63
|
}
|
|
41
64
|
```
|
|
42
65
|
|
|
43
|
-
|
|
66
|
+
### Config Reference
|
|
67
|
+
|
|
68
|
+
| Field | Default | Description |
|
|
44
69
|
|---|---|---|
|
|
45
|
-
| `svg` |
|
|
46
|
-
| `outputFonts` |
|
|
47
|
-
| `outputStyles` | | CSS file output path |
|
|
48
|
-
| `outputTypes` |
|
|
49
|
-
| `polyiconConfig` | | Fontello-compatible
|
|
50
|
-
| `importFontsPath` | | Font URL prefix in
|
|
51
|
-
| `formats` | | Font formats to generate
|
|
70
|
+
| `svg` | `./public/assets/svg` | **Required.** Folder containing your `.svg` icon files |
|
|
71
|
+
| `outputFonts` | `./public/assets/fontello/font` | Where font files (`fontello.woff2`, etc.) are written |
|
|
72
|
+
| `outputStyles` | `./public/assets/fontello/css/fontello.css` | CSS file output path |
|
|
73
|
+
| `outputTypes` | `./public/assets/fontello/IconTypes.js` | JS constants file output path |
|
|
74
|
+
| `polyiconConfig` | `./public/assets/fontello/config.json` | Fontello-compatible config output path |
|
|
75
|
+
| `importFontsPath` | `../font/` | Font URL prefix in generated CSS — use relative path or CDN URL |
|
|
76
|
+
| `formats` | `["eot","svg","ttf","woff","woff2"]` | Font formats to generate |
|
|
77
|
+
| `fontName` | `fontello` | Font family name in CSS and font filenames |
|
|
78
|
+
| `classPrefix` | `icon` | CSS class prefix for icons |
|
|
79
|
+
| `hashOutput` | `true` | Append content hash to output folder for cache busting |
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Features
|
|
84
|
+
|
|
85
|
+
### Font Name (`fontName`)
|
|
86
|
+
|
|
87
|
+
Controls the font-family name in CSS and the output filenames.
|
|
88
|
+
|
|
89
|
+
```jsonc
|
|
90
|
+
"fontName": "fontello" // → fontello.woff2, font-family: "fontello"
|
|
91
|
+
"fontName": "myicons" // → myicons.woff2, font-family: "myicons"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
This means you can generate a **drop-in replacement** for an existing Fontello font — same filenames, same `font-family`, just upload to CDN.
|
|
95
|
+
|
|
96
|
+
### Class Prefix (`classPrefix`)
|
|
97
|
+
|
|
98
|
+
Controls the CSS class prefix for all icons. SVG filename becomes the icon name.
|
|
99
|
+
|
|
100
|
+
```jsonc
|
|
101
|
+
"classPrefix": "icon" // → .icon-home, .icon-settings, .icon-user
|
|
102
|
+
"classPrefix": "pi" // → .pi-home, .pi-settings, .pi-user
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Cache Busting (`hashOutput`)
|
|
52
106
|
|
|
53
|
-
|
|
107
|
+
When `true`, the output folder gets a content hash suffix:
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
fontello-5f3f3c64/
|
|
111
|
+
├── css/fontello.css
|
|
112
|
+
├── font/fontello.woff2 ...
|
|
113
|
+
├── IconTypes.js
|
|
114
|
+
├── config.json
|
|
115
|
+
└── demo.html
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- **Same icons** → same hash → CDN cache works
|
|
119
|
+
- **Add/remove/change an SVG** → new hash → CDN cache is busted automatically
|
|
120
|
+
- Old hashed folders are auto-deleted on regenerate
|
|
121
|
+
|
|
122
|
+
Set `"hashOutput": false` for a plain `fontello/` folder without hash.
|
|
123
|
+
|
|
124
|
+
### CDN Support (`importFontsPath`)
|
|
125
|
+
|
|
126
|
+
Controls the font URL prefix inside the generated CSS.
|
|
127
|
+
|
|
128
|
+
```jsonc
|
|
129
|
+
// Relative (default) — for local hosting
|
|
130
|
+
"importFontsPath": "../font/"
|
|
131
|
+
// → url('../font/fontello.woff2')
|
|
132
|
+
|
|
133
|
+
// CDN — for remote hosting
|
|
134
|
+
"importFontsPath": "https://cdn.example.com/font/"
|
|
135
|
+
// → url('https://cdn.example.com/font/fontello.woff2')
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Stroke-to-Fill Conversion
|
|
139
|
+
|
|
140
|
+
Line/stroke icons (e.g. from Figma, Heroicons) are automatically converted to filled outlines. Icon fonts only support fills — this conversion happens transparently so your stroke-based SVGs work out of the box.
|
|
141
|
+
|
|
142
|
+
### SVG Sanitisation
|
|
143
|
+
|
|
144
|
+
- Spaces and special characters in filenames are auto-sanitised to hyphens
|
|
145
|
+
- `<defs>`, `clip-path`, `filter`, `mask` elements are stripped
|
|
146
|
+
- White background `<rect>` elements are removed
|
|
147
|
+
- Non-path elements (`<circle>`, `<ellipse>`, `<rect>`, `<polygon>`, `<polyline>`, `<line>`) are fully supported
|
|
148
|
+
|
|
149
|
+
---
|
|
54
150
|
|
|
55
151
|
## Output
|
|
56
152
|
|
|
57
153
|
```
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
css
|
|
61
|
-
|
|
62
|
-
font
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
config.json
|
|
69
|
-
|
|
70
|
-
IconTypes.js
|
|
154
|
+
fontello-5f3f3c64/
|
|
155
|
+
├── css/
|
|
156
|
+
│ └── fontello.css ← @font-face + all .icon-* classes
|
|
157
|
+
├── font/
|
|
158
|
+
│ ├── fontello.woff2 ← primary web font
|
|
159
|
+
│ ├── fontello.woff
|
|
160
|
+
│ ├── fontello.ttf
|
|
161
|
+
│ ├── fontello.eot
|
|
162
|
+
│ └── fontello.svg
|
|
163
|
+
├── IconTypes.js ← JS constants for icon names
|
|
164
|
+
├── config.json ← Fontello-compatible glyph metadata
|
|
165
|
+
└── demo.html ← interactive icon browser (search, click to copy)
|
|
71
166
|
```
|
|
72
167
|
|
|
73
|
-
Open `
|
|
168
|
+
Open `demo.html` in a browser to browse all icons, search by name, and click any card to copy its class name.
|
|
74
169
|
|
|
75
|
-
|
|
170
|
+
---
|
|
76
171
|
|
|
77
|
-
|
|
172
|
+
## Usage
|
|
173
|
+
|
|
174
|
+
### HTML
|
|
175
|
+
|
|
176
|
+
```html
|
|
177
|
+
<!-- Load CSS once -->
|
|
178
|
+
<link rel="stylesheet" href="fontello/css/fontello.css" />
|
|
179
|
+
|
|
180
|
+
<!-- Use icons -->
|
|
181
|
+
<i class="icon-home"></i>
|
|
182
|
+
<i class="icon-settings"></i>
|
|
183
|
+
<i class="icon-arrow-right"></i>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### React / Next.js
|
|
187
|
+
|
|
188
|
+
Import the CSS once in your root layout or entry file:
|
|
78
189
|
|
|
79
190
|
```jsx
|
|
80
|
-
|
|
191
|
+
// Option 1: <link> tag (for public/ assets or CDN)
|
|
192
|
+
<link rel="stylesheet" href="/assets/fontello/css/fontello.css" />
|
|
193
|
+
|
|
194
|
+
// Option 2: CSS import (for src/ assets)
|
|
195
|
+
import "./assets/fontello/css/fontello.css";
|
|
81
196
|
```
|
|
82
197
|
|
|
83
|
-
Use icons
|
|
198
|
+
Use icons anywhere:
|
|
84
199
|
|
|
85
200
|
```jsx
|
|
86
|
-
|
|
201
|
+
// Direct class name
|
|
202
|
+
<i className="icon-home" />
|
|
203
|
+
|
|
204
|
+
// With Tailwind — control size and color
|
|
205
|
+
<i className="icon-home text-4xl text-blue-500" />
|
|
206
|
+
|
|
207
|
+
// Dynamic from variable or CMS
|
|
208
|
+
<i className={`icon-${iconName} text-2xl`} />
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Using IconTypes.js
|
|
212
|
+
|
|
213
|
+
The generated `IconTypes.js` provides constants for every icon name:
|
|
214
|
+
|
|
215
|
+
```js
|
|
216
|
+
const IconTypes = {
|
|
217
|
+
HOME: 'home',
|
|
218
|
+
SETTINGS: 'settings',
|
|
219
|
+
ARROW_RIGHT: 'arrow-right',
|
|
220
|
+
// ...
|
|
221
|
+
};
|
|
222
|
+
export default IconTypes;
|
|
87
223
|
```
|
|
88
224
|
|
|
89
|
-
|
|
225
|
+
Use for consistent, typo-free icon references:
|
|
90
226
|
|
|
91
227
|
```jsx
|
|
92
|
-
import IconTypes from "./
|
|
228
|
+
import IconTypes from "./fontello/IconTypes";
|
|
93
229
|
|
|
94
|
-
<i className={`
|
|
230
|
+
<i className={`icon-${IconTypes.HOME}`} />
|
|
231
|
+
<i className={`icon-${IconTypes.SETTINGS}`} />
|
|
95
232
|
```
|
|
96
233
|
|
|
234
|
+
### Sizing and Coloring
|
|
235
|
+
|
|
236
|
+
Icons are a **font**, so standard text CSS properties control their appearance:
|
|
237
|
+
|
|
238
|
+
```css
|
|
239
|
+
/* Size — use font-size */
|
|
240
|
+
.icon-home { font-size: 24px; }
|
|
241
|
+
.icon-home { font-size: 2rem; }
|
|
242
|
+
|
|
243
|
+
/* Color — use color */
|
|
244
|
+
.icon-home { color: #335fff; }
|
|
245
|
+
|
|
246
|
+
/* Tailwind shorthand */
|
|
247
|
+
<i class="icon-home text-4xl text-blue-500" />
|
|
248
|
+
<i class="icon-home text-6xl text-red-600 hover:text-red-800" />
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
97
253
|
## Programmatic API
|
|
98
254
|
|
|
99
255
|
```js
|
|
100
|
-
const { buildIcons } = require("polyicon");
|
|
101
|
-
|
|
102
|
-
await buildIcons({
|
|
103
|
-
svg: "./
|
|
104
|
-
outputFonts: "./dist/
|
|
105
|
-
outputStyles: "./dist/
|
|
106
|
-
outputTypes: "./
|
|
107
|
-
importFontsPath: "
|
|
256
|
+
const { buildIcons } = require("wmt-polyicon");
|
|
257
|
+
|
|
258
|
+
const result = await buildIcons({
|
|
259
|
+
svg: "./icons",
|
|
260
|
+
outputFonts: "./dist/fontello/font",
|
|
261
|
+
outputStyles: "./dist/fontello/css/fontello.css",
|
|
262
|
+
outputTypes: "./dist/fontello/IconTypes.js",
|
|
263
|
+
importFontsPath: "../font/",
|
|
264
|
+
fontName: "fontello",
|
|
265
|
+
classPrefix: "icon",
|
|
266
|
+
hashOutput: true,
|
|
108
267
|
formats: ["woff2", "woff", "ttf"]
|
|
109
268
|
});
|
|
269
|
+
|
|
270
|
+
console.log(result.outputDir);
|
|
271
|
+
// → ./dist/fontello-a3f7b2c1
|
|
110
272
|
```
|
|
111
273
|
|
|
112
|
-
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## CLI Reference
|
|
113
277
|
|
|
114
278
|
```
|
|
115
|
-
polyicon
|
|
116
|
-
|
|
279
|
+
polyicon <command> [options]
|
|
280
|
+
|
|
281
|
+
Commands:
|
|
282
|
+
init Create .polyiconrc with defaults and comments
|
|
283
|
+
generate Generate fonts, CSS, types, and preview
|
|
117
284
|
|
|
118
285
|
Options:
|
|
119
|
-
-c, --config Path to config (default: .polyiconrc)
|
|
120
|
-
-f, --force Overwrite config on init
|
|
286
|
+
-c, --config Path to config file (default: .polyiconrc)
|
|
287
|
+
-f, --force Overwrite existing config on init
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Examples
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
# Standard workflow
|
|
294
|
+
polyicon init
|
|
295
|
+
polyicon generate
|
|
296
|
+
|
|
297
|
+
# Custom config path
|
|
298
|
+
polyicon init --config icons.json
|
|
299
|
+
polyicon generate --config icons.json
|
|
300
|
+
|
|
301
|
+
# Overwrite existing config
|
|
302
|
+
polyicon init --force
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## SVG Guidelines
|
|
308
|
+
|
|
309
|
+
For best results, your SVG icons should be:
|
|
310
|
+
|
|
311
|
+
- **Single colour** — icon fonts are monochrome (colour is applied via CSS)
|
|
312
|
+
- **Square artboard** — e.g. 24×24, 32×32, or any consistent size
|
|
313
|
+
- **Clean paths** — remove masks, filters, clip-paths (auto-stripped but cleaner input = better output)
|
|
314
|
+
- **Filled or stroked** — both work (strokes are auto-converted to fills)
|
|
315
|
+
|
|
316
|
+
SVG filenames become CSS class names:
|
|
121
317
|
```
|
|
318
|
+
mobile-app.svg → .icon-mobile-app
|
|
319
|
+
Web-Development.svg → .icon-Web-Development
|
|
320
|
+
AI ML Model.svg → .icon-AI-ML-Model (spaces → hyphens)
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## License
|
|
326
|
+
|
|
327
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wmt-polyicon",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "SVG to icon font generator
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "SVG to icon font generator — drop in SVGs, get a production-ready Fontello-style icon font with one command.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"main": "src/index.js",
|
|
@@ -13,11 +13,16 @@
|
|
|
13
13
|
"font",
|
|
14
14
|
"iconfont",
|
|
15
15
|
"fontello",
|
|
16
|
+
"svg-to-font",
|
|
17
|
+
"icon-font",
|
|
18
|
+
"webfont",
|
|
16
19
|
"react",
|
|
20
|
+
"nextjs",
|
|
17
21
|
"cli",
|
|
18
22
|
"woff",
|
|
19
23
|
"woff2",
|
|
20
|
-
"ttf"
|
|
24
|
+
"ttf",
|
|
25
|
+
"cache-busting"
|
|
21
26
|
],
|
|
22
27
|
"files": [
|
|
23
28
|
"bin",
|
|
@@ -18,8 +18,17 @@ async function generateCommand({ configPath }) {
|
|
|
18
18
|
`SVG path not found: ${conf.svg}. Update \`svg\` in ${configPath}.`
|
|
19
19
|
);
|
|
20
20
|
}
|
|
21
|
-
await buildIcons(conf);
|
|
22
|
-
|
|
21
|
+
const result = await buildIcons(conf);
|
|
22
|
+
const fontName = conf.fontName || "fontello";
|
|
23
|
+
const outDir = result.outputDir;
|
|
24
|
+
console.log(`\n✔ Generated successfully!\n`);
|
|
25
|
+
console.log(` Output: ${outDir}`);
|
|
26
|
+
console.log(` Fonts: ${outDir}/font/${fontName}.woff2 (+woff, ttf, eot, svg)`);
|
|
27
|
+
console.log(` CSS: ${outDir}/css/${fontName}.css`);
|
|
28
|
+
console.log(` Types: ${outDir}/IconTypes.js`);
|
|
29
|
+
console.log(` Preview: ${outDir}/demo.html\n`);
|
|
30
|
+
console.log(`Usage in HTML/JSX:`);
|
|
31
|
+
console.log(` <i class="icon-YourIconName"></i>\n`);
|
|
23
32
|
}
|
|
24
33
|
|
|
25
34
|
module.exports = {
|
package/src/cli/commands/init.js
CHANGED
|
@@ -13,7 +13,33 @@ async function initCommand({ configPath, force }) {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
await ensureDir(path.dirname(targetPath));
|
|
16
|
-
|
|
16
|
+
|
|
17
|
+
const configWithComments = `{
|
|
18
|
+
// ── REQUIRED ──────────────────────────────────────────────────
|
|
19
|
+
// Path to your SVG icons folder (change this to your SVG folder)
|
|
20
|
+
"svg": "${DEFAULT_CONFIG.svg}",
|
|
21
|
+
|
|
22
|
+
// ── OUTPUT PATHS ──────────────────────────────────────────────
|
|
23
|
+
"outputFonts": "${DEFAULT_CONFIG.outputFonts}",
|
|
24
|
+
"outputStyles": "${DEFAULT_CONFIG.outputStyles}",
|
|
25
|
+
"outputTypes": "${DEFAULT_CONFIG.outputTypes}",
|
|
26
|
+
"polyiconConfig": "${DEFAULT_CONFIG.polyiconConfig}",
|
|
27
|
+
|
|
28
|
+
// ── FONT SETTINGS ────────────────────────────────────────────
|
|
29
|
+
// Font URL prefix used inside the generated CSS (relative to CSS file)
|
|
30
|
+
"importFontsPath": "${DEFAULT_CONFIG.importFontsPath}",
|
|
31
|
+
// Font file formats to generate
|
|
32
|
+
"formats": ${JSON.stringify(DEFAULT_CONFIG.formats)},
|
|
33
|
+
// Font family name used in CSS and font filenames
|
|
34
|
+
"fontName": "${DEFAULT_CONFIG.fontName}",
|
|
35
|
+
// CSS class prefix (e.g. "icon" → .icon-home, "pi" → .pi-home)
|
|
36
|
+
"classPrefix": "${DEFAULT_CONFIG.classPrefix}",
|
|
37
|
+
// Append content hash to output folder for cache busting (e.g. fontello-a3f7b2c1/)
|
|
38
|
+
"hashOutput": ${DEFAULT_CONFIG.hashOutput}
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
fs.writeFileSync(targetPath, configWithComments);
|
|
17
43
|
|
|
18
44
|
}
|
|
19
45
|
|
package/src/cli/index.js
CHANGED
|
@@ -34,10 +34,10 @@ async function run(argv) {
|
|
|
34
34
|
try {
|
|
35
35
|
if (command === "init") {
|
|
36
36
|
await initCommand({ configPath, force });
|
|
37
|
-
console.log(
|
|
38
|
-
console.log(
|
|
39
|
-
|
|
40
|
-
);
|
|
37
|
+
console.log(`\n✔ Created ${configPath}\n`);
|
|
38
|
+
console.log(`Next steps:`);
|
|
39
|
+
console.log(` 1. Update "svg" path in ${configPath} to your SVG folder`);
|
|
40
|
+
console.log(` 2. Run: polyicon generate\n`);
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
43
|
|
package/src/config/defaults.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
const DEFAULT_CONFIG = {
|
|
2
|
-
svg: "./
|
|
3
|
-
outputFonts: "./
|
|
2
|
+
svg: "./public/assets/svg",
|
|
3
|
+
outputFonts: "./public/assets/fontello/font",
|
|
4
4
|
importFontsPath: "../font/",
|
|
5
|
-
outputTypes: "./
|
|
6
|
-
outputStyles: "./
|
|
5
|
+
outputTypes: "./public/assets/fontello/IconTypes.js",
|
|
6
|
+
outputStyles: "./public/assets/fontello/css/fontello.css",
|
|
7
7
|
formats: ["eot", "svg", "ttf", "woff", "woff2"],
|
|
8
|
-
polyiconConfig: "./
|
|
9
|
-
classPrefix: "icon"
|
|
8
|
+
polyiconConfig: "./public/assets/fontello/config.json",
|
|
9
|
+
classPrefix: "icon",
|
|
10
|
+
fontName: "fontello",
|
|
11
|
+
hashOutput: true
|
|
10
12
|
};
|
|
11
13
|
|
|
12
14
|
module.exports = {
|
package/src/config/load.js
CHANGED
|
@@ -2,8 +2,10 @@ const fs = require("fs");
|
|
|
2
2
|
|
|
3
3
|
function loadConfig(filePath) {
|
|
4
4
|
const raw = fs.readFileSync(filePath, "utf8");
|
|
5
|
+
// Strip single-line comments (// ...) so users can annotate .polyiconrc
|
|
6
|
+
const stripped = raw.replace(/^\s*\/\/.*$/gm, "").replace(/,\s*([}\]])/g, "$1");
|
|
5
7
|
try {
|
|
6
|
-
return JSON.parse(
|
|
8
|
+
return JSON.parse(stripped);
|
|
7
9
|
} catch (err) {
|
|
8
10
|
const message = err && err.message ? err.message : "Invalid JSON";
|
|
9
11
|
throw new Error(`Invalid JSON in ${filePath}: ${message}`);
|
package/src/constants.js
CHANGED
package/src/generator/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const path = require("path");
|
|
2
|
+
const crypto = require("crypto");
|
|
2
3
|
const fse = require("fs-extra");
|
|
3
|
-
const { TMP_DIR, CLASS_PREFIX } = require("../constants");
|
|
4
|
+
const { TMP_DIR, CLASS_PREFIX, FONT_NAME } = require("../constants");
|
|
4
5
|
const { resolveFromCwd } = require("../utils/paths");
|
|
5
6
|
const { runSvgToFont } = require("./run_svgtofont");
|
|
6
7
|
const { parseGlyphs } = require("./parse_svg");
|
|
@@ -24,6 +25,7 @@ async function buildIcons(conf) {
|
|
|
24
25
|
const importFontsPath = conf.importFontsPath || "";
|
|
25
26
|
const formats = conf.formats || ["eot", "svg", "ttf", "woff", "woff2"];
|
|
26
27
|
const classPrefix = conf.classPrefix || CLASS_PREFIX;
|
|
28
|
+
const fontName = conf.fontName || FONT_NAME;
|
|
27
29
|
const tmpPath = path.resolve(process.cwd(), TMP_DIR);
|
|
28
30
|
const tmpSvgPath = path.resolve(process.cwd(), `${TMP_DIR}_svgs`);
|
|
29
31
|
|
|
@@ -94,21 +96,59 @@ async function buildIcons(conf) {
|
|
|
94
96
|
await fse.writeFile(outputPath, outputSvg, "utf8");
|
|
95
97
|
}
|
|
96
98
|
|
|
97
|
-
await runSvgToFont({ svgPath: tmpSvgPath, tmpPath, classPrefix });
|
|
98
|
-
const glyphs = await parseGlyphs(tmpPath);
|
|
99
|
+
await runSvgToFont({ svgPath: tmpSvgPath, tmpPath, classPrefix, fontName });
|
|
100
|
+
const glyphs = await parseGlyphs(tmpPath, fontName);
|
|
99
101
|
|
|
100
102
|
await writeTypes({ outputTypesPath, glyphs });
|
|
101
|
-
await writePolyiconConfig({ outputPath: polyiconConfigPath, glyphs, classPrefix });
|
|
103
|
+
await writePolyiconConfig({ outputPath: polyiconConfigPath, glyphs, classPrefix, fontName });
|
|
102
104
|
await writeCss({
|
|
103
105
|
tmpPath,
|
|
104
106
|
outputStylesPath,
|
|
105
|
-
importFontsPath
|
|
107
|
+
importFontsPath,
|
|
108
|
+
fontName
|
|
106
109
|
});
|
|
107
|
-
await writeFonts({ tmpPath, outputFontsPath, formats });
|
|
108
|
-
await writeHtml({ tmpPath, outputFontsPath, glyphs, classPrefix });
|
|
110
|
+
await writeFonts({ tmpPath, outputFontsPath, formats, fontName });
|
|
111
|
+
await writeHtml({ tmpPath, outputFontsPath, glyphs, classPrefix, fontName });
|
|
112
|
+
|
|
113
|
+
// Compute content hash BEFORE cleaning up tmp files
|
|
114
|
+
let contentHash = null;
|
|
115
|
+
if (conf.hashOutput !== false) {
|
|
116
|
+
const hashInput = crypto.createHash("md5");
|
|
117
|
+
const sortedFiles = [...seen.keys()].sort();
|
|
118
|
+
for (const name of sortedFiles) {
|
|
119
|
+
hashInput.update(name);
|
|
120
|
+
const svgContent = await fse.readFile(path.resolve(tmpSvgPath, `${name}.svg`), "utf8");
|
|
121
|
+
hashInput.update(svgContent);
|
|
122
|
+
}
|
|
123
|
+
contentHash = hashInput.digest("hex").slice(0, 8);
|
|
124
|
+
}
|
|
109
125
|
|
|
110
126
|
await fse.remove(tmpPath);
|
|
111
127
|
await fse.remove(tmpSvgPath);
|
|
128
|
+
|
|
129
|
+
// Rename output folder with hash suffix for cache busting
|
|
130
|
+
let finalOutputDir = path.dirname(outputFontsPath);
|
|
131
|
+
if (contentHash) {
|
|
132
|
+
const baseDir = path.dirname(outputFontsPath);
|
|
133
|
+
const baseName = path.basename(baseDir);
|
|
134
|
+
const parentDir = path.dirname(baseDir);
|
|
135
|
+
const hashedDir = path.resolve(parentDir, `${baseName}-${contentHash}`);
|
|
136
|
+
|
|
137
|
+
// Remove previous hashed folders
|
|
138
|
+
const siblings = await fse.readdir(parentDir);
|
|
139
|
+
for (const sibling of siblings) {
|
|
140
|
+
if (sibling.startsWith(`${baseName}-`) && sibling !== path.basename(hashedDir)) {
|
|
141
|
+
await fse.remove(path.resolve(parentDir, sibling));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Rename fontello/ → fontello-<hash>/
|
|
146
|
+
if (await fse.pathExists(hashedDir)) await fse.remove(hashedDir);
|
|
147
|
+
await fse.move(baseDir, hashedDir);
|
|
148
|
+
finalOutputDir = hashedDir;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return { outputDir: finalOutputDir };
|
|
112
152
|
}
|
|
113
153
|
|
|
114
154
|
module.exports = {
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
const fse = require("fs-extra");
|
|
2
2
|
const { XMLParser } = require("fast-xml-parser");
|
|
3
3
|
const path = require("path");
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
async function parseGlyphs(tmpPath) {
|
|
7
|
-
const svgPath = path.resolve(tmpPath, `${FONT_NAME}.svg`);
|
|
4
|
+
async function parseGlyphs(tmpPath, fontName) {
|
|
5
|
+
const svgPath = path.resolve(tmpPath, `${fontName}.svg`);
|
|
8
6
|
const svg = await fse.readFile(svgPath, "utf8");
|
|
9
7
|
const parser = new XMLParser({
|
|
10
8
|
ignoreAttributes: false,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
const { WEBSITE
|
|
1
|
+
const { WEBSITE } = require("../constants");
|
|
2
2
|
|
|
3
|
-
async function runSvgToFont({ svgPath, tmpPath, classPrefix }) {
|
|
3
|
+
async function runSvgToFont({ svgPath, tmpPath, classPrefix, fontName }) {
|
|
4
4
|
const mod = await import("svgtofont");
|
|
5
5
|
const svgtofont = mod.default;
|
|
6
6
|
await svgtofont({
|
|
7
7
|
src: svgPath,
|
|
8
8
|
dist: tmpPath,
|
|
9
|
-
fontName
|
|
9
|
+
fontName,
|
|
10
10
|
css: true,
|
|
11
11
|
classNamePrefix: classPrefix,
|
|
12
12
|
website: WEBSITE,
|
|
@@ -1,28 +1,26 @@
|
|
|
1
1
|
const fse = require("fs-extra");
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const { ensureDir } = require("../utils/fs");
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
async function writeCss({ tmpPath, outputStylesPath, importFontsPath }) {
|
|
4
|
+
async function writeCss({ tmpPath, outputStylesPath, importFontsPath, fontName }) {
|
|
7
5
|
if (!outputStylesPath) return;
|
|
8
6
|
|
|
9
7
|
await ensureDir(path.dirname(outputStylesPath));
|
|
10
8
|
|
|
11
9
|
let css = await fse.readFile(
|
|
12
|
-
path.resolve(tmpPath, `${
|
|
10
|
+
path.resolve(tmpPath, `${fontName}.css`),
|
|
13
11
|
"utf8"
|
|
14
12
|
);
|
|
15
13
|
|
|
16
|
-
while (css.indexOf(`url('${
|
|
14
|
+
while (css.indexOf(`url('${fontName}`) > -1) {
|
|
17
15
|
css = css.replace(
|
|
18
|
-
`url('${
|
|
19
|
-
`url('${importFontsPath}${
|
|
16
|
+
`url('${fontName}`,
|
|
17
|
+
`url('${importFontsPath}${fontName}`
|
|
20
18
|
);
|
|
21
19
|
}
|
|
22
|
-
while (css.indexOf(`url("${
|
|
20
|
+
while (css.indexOf(`url("${fontName}`) > -1) {
|
|
23
21
|
css = css.replace(
|
|
24
|
-
`url("${
|
|
25
|
-
`url("${importFontsPath}${
|
|
22
|
+
`url("${fontName}`,
|
|
23
|
+
`url("${importFontsPath}${fontName}`
|
|
26
24
|
);
|
|
27
25
|
}
|
|
28
26
|
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
const fse = require("fs-extra");
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const { ensureDir } = require("../utils/fs");
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
async function writeFonts({ tmpPath, outputFontsPath, formats }) {
|
|
4
|
+
async function writeFonts({ tmpPath, outputFontsPath, formats, fontName }) {
|
|
7
5
|
await ensureDir(outputFontsPath);
|
|
8
6
|
|
|
9
7
|
const copyIf = async (ext) => {
|
|
10
8
|
await fse.copy(
|
|
11
|
-
path.resolve(tmpPath, `${
|
|
12
|
-
path.resolve(outputFontsPath, `${
|
|
9
|
+
path.resolve(tmpPath, `${fontName}.${ext}`),
|
|
10
|
+
path.resolve(outputFontsPath, `${fontName}.${ext}`)
|
|
13
11
|
);
|
|
14
12
|
};
|
|
15
13
|
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
const fse = require("fs-extra");
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const { ensureDir } = require("../utils/fs");
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
async function writeHtml({ tmpPath, outputFontsPath, glyphs, classPrefix }) {
|
|
4
|
+
async function writeHtml({ tmpPath, outputFontsPath, glyphs, classPrefix, fontName }) {
|
|
7
5
|
const outputDir = path.dirname(outputFontsPath);
|
|
8
6
|
const fontsSubDir = path.basename(outputFontsPath);
|
|
9
7
|
|
|
10
8
|
let css = await fse.readFile(
|
|
11
|
-
path.resolve(tmpPath, `${
|
|
9
|
+
path.resolve(tmpPath, `${fontName}.css`),
|
|
12
10
|
"utf8"
|
|
13
11
|
);
|
|
14
12
|
|
|
@@ -50,7 +48,7 @@ async function writeHtml({ tmpPath, outputFontsPath, glyphs, classPrefix }) {
|
|
|
50
48
|
<head>
|
|
51
49
|
<meta charset="UTF-8" />
|
|
52
50
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
53
|
-
<title>${
|
|
51
|
+
<title>${fontName} — Icon Preview</title>
|
|
54
52
|
<style>
|
|
55
53
|
${css}
|
|
56
54
|
|
|
@@ -230,7 +228,7 @@ ${css}
|
|
|
230
228
|
|
|
231
229
|
<header class="header">
|
|
232
230
|
<div class="header-left">
|
|
233
|
-
<h1>${
|
|
231
|
+
<h1>${fontName}</h1>
|
|
234
232
|
<p id="count">${glyphs.length} icon${glyphs.length !== 1 ? "s" : ""}</p>
|
|
235
233
|
</div>
|
|
236
234
|
<div class="search-wrap">
|
|
@@ -293,7 +291,7 @@ ${items}
|
|
|
293
291
|
|
|
294
292
|
await ensureDir(outputDir);
|
|
295
293
|
await fse.writeFile(
|
|
296
|
-
path.resolve(outputDir,
|
|
294
|
+
path.resolve(outputDir, "demo.html"),
|
|
297
295
|
html,
|
|
298
296
|
"utf8"
|
|
299
297
|
);
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
const { ensureFile, writeJson } = require("../utils/fs");
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
async function writePolyiconConfig({ outputPath, glyphs, classPrefix }) {
|
|
2
|
+
async function writePolyiconConfig({ outputPath, glyphs, classPrefix, fontName }) {
|
|
5
3
|
if (!outputPath) return;
|
|
6
4
|
|
|
7
5
|
const config = {
|
|
8
|
-
name:
|
|
6
|
+
name: fontName,
|
|
9
7
|
css_prefix_text: `${classPrefix}-`,
|
|
10
8
|
css_use_suffix: false,
|
|
11
9
|
hinting: true,
|