mimeforge 0.1.1 → 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 +14 -0
- package/README.md +75 -17
- package/dist/cli.js +7 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/png.js +2 -1
- package/dist/render.d.ts +5 -0
- package/dist/render.js +7 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,20 @@
|
|
|
3
3
|
All notable changes are listed here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the
|
|
4
4
|
project uses [Semantic Versioning](https://semver.org/).
|
|
5
5
|
|
|
6
|
+
## [0.2.0] - 2026-10-08
|
|
7
|
+
|
|
8
|
+
- Fallback icon: `mimeforge default` and `mimeforge --all` write `default.svg` (generic body without a label), and
|
|
9
|
+
`--png` adds `<size>/default.png`; library: `renderDefaultIcon()`. For apps that need a file to point at when an
|
|
10
|
+
extension has no icon.
|
|
11
|
+
- PNG export no longer loads system fonts: `--all --png 16` takes about half a second instead of minutes.
|
|
12
|
+
|
|
13
|
+
## [0.1.2] - 2026-10-08
|
|
14
|
+
|
|
15
|
+
Documentation only.
|
|
16
|
+
|
|
17
|
+
- README: separate install paths (npx, global, project dependency, from source), a "use it in a project" example,
|
|
18
|
+
library install and ESM notes
|
|
19
|
+
|
|
6
20
|
## [0.1.1] - 2026-10-08
|
|
7
21
|
|
|
8
22
|
Maintenance release, the first one published through GitHub Actions (npm Trusted Publishing). No code changes.
|
package/README.md
CHANGED
|
@@ -29,40 +29,95 @@ And, frankly, why not? :)
|
|
|
29
29
|
|
|
30
30
|
## Contents
|
|
31
31
|
|
|
32
|
-
[Quick start](#quick-start) · [Everyday use](#everyday-use) · [Customize](#customize) ([colors](#change-colors) · [label](#change-the-label) · [font](#change-the-font) · [bodies](#change-the-bodies) · [config file](#use-a-config-file) · [PNG](#export-png)) · [Edge cases](#edge-cases) · [Library API](#library-api) · [CLI reference](#cli-reference) · [Categories](#categories) · [Development](#development)
|
|
32
|
+
[Quick start](#quick-start) · [Static hosts](#use-it-on-a-static-host-with-a-fallback-icon) · [Everyday use](#everyday-use) · [Customize](#customize) ([colors](#change-colors) · [label](#change-the-label) · [font](#change-the-font) · [bodies](#change-the-bodies) · [config file](#use-a-config-file) · [PNG](#export-png)) · [Edge cases](#edge-cases) · [Library API](#library-api) · [CLI reference](#cli-reference) · [Categories](#categories) · [Development](#development)
|
|
33
33
|
|
|
34
34
|
## Quick start
|
|
35
35
|
|
|
36
36
|
Requires Node.js 20 or newer.
|
|
37
37
|
|
|
38
|
+
**Try it, nothing to install:**
|
|
39
|
+
|
|
38
40
|
```bash
|
|
39
|
-
npx mimeforge pdf docx webm -o icons
|
|
40
|
-
npm i mimeforge # or add it to a project (CLI + library)
|
|
41
|
+
npx mimeforge pdf docx webm -o icons
|
|
41
42
|
```
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
This writes `icons/pdf.svg`, `icons/docx.svg` and `icons/webm.svg`. Use them like any image:
|
|
45
|
+
|
|
46
|
+
```html
|
|
47
|
+
<img src="icons/pdf.svg" width="32" height="32" alt="PDF">
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Install:**
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm i -g mimeforge # a global `mimeforge` command
|
|
54
|
+
npm i mimeforge # or as a dependency of your project (CLI via npx, plus the library API)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**From source** (to hack on it):
|
|
44
58
|
|
|
45
59
|
```bash
|
|
46
60
|
git clone https://github.com/reachdevel/mimeforge.git
|
|
47
61
|
cd mimeforge
|
|
48
|
-
npm install
|
|
62
|
+
npm install # also builds the project
|
|
49
63
|
node dist/cli.js pdf docx webm -o icons
|
|
50
64
|
```
|
|
51
65
|
|
|
52
|
-
|
|
66
|
+
The examples below use the `mimeforge` command. Without a global install, put `npx` in front of it
|
|
67
|
+
(`npx mimeforge --all`); from a source checkout use `node dist/cli.js` or run `npm link` once.
|
|
53
68
|
|
|
54
|
-
|
|
55
|
-
|
|
69
|
+
### Use it in a project
|
|
70
|
+
|
|
71
|
+
Generate the icons at build time, so your app only ships the SVGs it needs:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"scripts": {
|
|
76
|
+
"icons": "mimeforge --all -o public/icons"
|
|
77
|
+
},
|
|
78
|
+
"devDependencies": {
|
|
79
|
+
"mimeforge": "^0.1.1"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Then `npm run icons` and reference `/icons/<ext>.svg`. `public/icons/manifest.json` maps every extension to its
|
|
85
|
+
category, which is handy for lookups. If you only show a few types, list them instead of `--all`. To render icons at
|
|
86
|
+
runtime instead (a server, a build plugin), use the [library API](#library-api).
|
|
87
|
+
|
|
88
|
+
### Use it on a static host (with a fallback icon)
|
|
89
|
+
|
|
90
|
+
If your app serves a prebuilt set of files, say `/m/<size>/<ext>.png`, generate the whole set once:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
mimeforge --all --png 16,20,32,48 -o m
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
m/pdf.svg m/16/pdf.png m/20/pdf.png m/32/pdf.png m/48/pdf.png
|
|
98
|
+
m/default.svg m/16/default.png … the fallback, see below
|
|
99
|
+
m/manifest.json { "pdf": "pdf", "gdoc": "word", … } every known extension and its category
|
|
56
100
|
```
|
|
57
101
|
|
|
58
|
-
|
|
59
|
-
|
|
102
|
+
Extensions MimeForge does not know (a `.hoppa` file) have no file of their own. `default.svg` and
|
|
103
|
+
`<size>/default.png` are the fallback for those: the generic page with a question mark and **no label** (an unknown
|
|
104
|
+
extension cannot be named). Point your app at it when an icon is missing:
|
|
105
|
+
|
|
106
|
+
```js
|
|
107
|
+
const manifest = await (await fetch('/m/manifest.json')).json();
|
|
108
|
+
const src = ext in manifest ? `/m/32/${ext}.png` : '/m/32/default.png';
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
or let the browser do it: `<img src="/m/32/hoppa.png" onerror="this.onerror=null;this.src='/m/32/default.png'">`.
|
|
112
|
+
To give one unknown extension its own icon instead, generate it explicitly (`mimeforge hoppa`, which draws the generic
|
|
113
|
+
body with the label `HOPPA`) or, from code, with a category of your choice (`renderIcon('hoppa', { category: 'archive' })`).
|
|
60
114
|
|
|
61
115
|
## Everyday use
|
|
62
116
|
|
|
63
117
|
```bash
|
|
64
118
|
mimeforge pdf docx webm -o icons # a few icons
|
|
65
|
-
mimeforge --all -o icons # every known extension, plus icons/manifest.json (ext → category)
|
|
119
|
+
mimeforge --all -o icons # every known extension, plus icons/default.svg and icons/manifest.json (ext → category)
|
|
120
|
+
mimeforge default -o icons # only the fallback icon: generic body, no label
|
|
66
121
|
mimeforge --list # which extension gets which category
|
|
67
122
|
mimeforge --test-run # visual check, see below
|
|
68
123
|
```
|
|
@@ -182,7 +237,7 @@ optional dependency `@resvg/resvg-js` (installed by default; if it is missing, M
|
|
|
182
237
|
|
|
183
238
|
| Situation | What happens |
|
|
184
239
|
|---|---|
|
|
185
|
-
| Unknown extension (`mimeforge xyz`) | generic body (question mark) with the label `XYZ` |
|
|
240
|
+
| Unknown extension (`mimeforge xyz`) | generic body (question mark) with the label `XYZ`; for a label-less fallback file use `mimeforge default` (also written by `--all`) |
|
|
186
241
|
| Long extension (`webmanifest`) | up to 6 letters are drawn at full size; longer text is scaled down proportionally to fit the label, and below about a third of the size letters are dropped from the end |
|
|
187
242
|
| Light accent color | label text switches to a dark ink when white would have less than 3:1 contrast |
|
|
188
243
|
| Character the font does not have | skipped |
|
|
@@ -199,10 +254,13 @@ how to change it.
|
|
|
199
254
|
|
|
200
255
|
## Library API
|
|
201
256
|
|
|
257
|
+
Install with `npm i mimeforge`. The package is ESM, so use `import` (from CommonJS: `const { renderIcon } = await import('mimeforge')`).
|
|
258
|
+
|
|
202
259
|
```ts
|
|
203
|
-
import { renderIcon, loadFont, loadBodies, createPalette } from 'mimeforge';
|
|
260
|
+
import { renderIcon, renderDefaultIcon, loadFont, loadBodies, createPalette } from 'mimeforge';
|
|
204
261
|
|
|
205
262
|
renderIcon('pdf').svg; // SVG string
|
|
263
|
+
renderDefaultIcon().svg; // fallback icon: generic body, no label
|
|
206
264
|
renderIcon('docx', { accent: '#0a7', label: 'WORD' }).svg; // custom accent and label text
|
|
207
265
|
|
|
208
266
|
renderIcon('xyz', {
|
|
@@ -214,15 +272,15 @@ renderIcon('xyz', {
|
|
|
214
272
|
});
|
|
215
273
|
```
|
|
216
274
|
|
|
217
|
-
`renderIcon` returns `{ svg, ext, category, accent }`. Other exports: `categoryFor`, `allExtensions`, `CATEGORIES`,
|
|
218
|
-
`DEFAULT_PALETTE`, `validateBody`, `renderLabel`, `bitmapFont`, `outlineFont` (see `src/index.ts`).
|
|
219
|
-
The package is ESM only.
|
|
275
|
+
`renderIcon` returns `{ svg, ext, category, accent }`. Other exports: `renderDefaultIcon`, `categoryFor`, `allExtensions`, `CATEGORIES`,
|
|
276
|
+
`DEFAULT_PALETTE`, `validateBody`, `renderLabel`, `bitmapFont`, `outlineFont` (see `src/index.ts`). Types are included.
|
|
220
277
|
|
|
221
278
|
## CLI reference
|
|
222
279
|
|
|
223
280
|
```
|
|
224
281
|
mimeforge <ext...> [options] write <out>/<ext>.svg for the given extensions
|
|
225
|
-
mimeforge --all [options] every known extension + manifest.json
|
|
282
|
+
mimeforge --all [options] every known extension + default.svg + manifest.json
|
|
283
|
+
mimeforge default [options] only the fallback icon (generic body, no label)
|
|
226
284
|
mimeforge --test-run [options] HTML preview page (default dir: out/test-run)
|
|
227
285
|
```
|
|
228
286
|
|
package/dist/cli.js
CHANGED
|
@@ -8,13 +8,14 @@ import { renderPng } from './png.js';
|
|
|
8
8
|
import { loadFont } from './font.js';
|
|
9
9
|
import { allExtensions, categoryFor } from './mime.js';
|
|
10
10
|
import { createPalette } from './palette.js';
|
|
11
|
-
import { renderIcon } from './render.js';
|
|
11
|
+
import { renderDefaultIcon, renderIcon } from './render.js';
|
|
12
12
|
import { testRun } from './testrun.js';
|
|
13
13
|
import { ROOT } from './paths.js';
|
|
14
14
|
const HELP = `MimeForge – generate file-type icons (SVG) from file extensions
|
|
15
15
|
|
|
16
16
|
Usage
|
|
17
17
|
mimeforge <ext...> [options] write <out>/<ext>.svg for the given extensions
|
|
18
|
+
("default" = the fallback icon without a label)
|
|
18
19
|
mimeforge --all [options] every known extension (mime-db + extras) + manifest.json
|
|
19
20
|
mimeforge --test-run [options] write an HTML page with all body types at 16/48/128 px
|
|
20
21
|
|
|
@@ -107,21 +108,22 @@ async function main() {
|
|
|
107
108
|
const out = resolve(values.out ?? cfg.out ?? 'out');
|
|
108
109
|
mkdirSync(out, { recursive: true });
|
|
109
110
|
const pngSizes = (values.png ? values.png.split(',').map(Number) : cfg.png ?? []).filter((n) => Number.isFinite(n) && n > 0);
|
|
110
|
-
const exts = values.all ? allExtensions() : positionals.map((e) => e.toLowerCase().replace(/^\./, ''));
|
|
111
|
+
const exts = values.all ? [...allExtensions(), 'default'] : positionals.map((e) => e.toLowerCase().replace(/^\./, ''));
|
|
111
112
|
const manifest = {};
|
|
112
113
|
let bytes = 0;
|
|
113
114
|
for (const ext of exts) {
|
|
114
|
-
const r = renderIcon(ext, opts);
|
|
115
|
+
const r = ext === 'default' ? renderDefaultIcon(opts) : renderIcon(ext, opts);
|
|
115
116
|
writeFileSync(join(out, `${ext}.svg`), r.svg);
|
|
116
117
|
for (const size of pngSizes) {
|
|
117
118
|
mkdirSync(join(out, String(size)), { recursive: true });
|
|
118
119
|
writeFileSync(join(out, String(size), `${ext}.png`), await renderPng(r.svg, size));
|
|
119
120
|
}
|
|
120
|
-
|
|
121
|
+
if (ext !== 'default')
|
|
122
|
+
manifest[ext] = r.category;
|
|
121
123
|
bytes += r.svg.length;
|
|
122
124
|
}
|
|
123
125
|
if (values.all)
|
|
124
126
|
writeFileSync(join(out, 'manifest.json'), JSON.stringify(manifest, null, 1));
|
|
125
|
-
console.log(`${exts.length} icon(s) → ${out} (${(bytes / 1024).toFixed(0)} KB total, ${(bytes / exts.length / 1024).toFixed(1)} KB avg)`);
|
|
127
|
+
console.log(`${exts.length} icon(s)${values.all ? ' (incl. default)' : ''} → ${out} (${(bytes / 1024).toFixed(0)} KB total, ${(bytes / exts.length / 1024).toFixed(1)} KB avg)`);
|
|
126
128
|
}
|
|
127
129
|
main().catch((e) => fail(e.message));
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { renderIcon, type RenderOptions, type RenderResult } from './render.js';
|
|
1
|
+
export { renderIcon, renderDefaultIcon, type RenderOptions, type RenderResult } from './render.js';
|
|
2
2
|
export { CATEGORIES, classify, classifyMime, isCategory, type Category } from './categories.js';
|
|
3
3
|
export { allExtensions, categoryFor, extToMime } from './mime.js';
|
|
4
4
|
export { DEFAULT_PALETTE, createPalette, accentFor, type Palette } from './palette.js';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { renderIcon } from './render.js';
|
|
1
|
+
export { renderIcon, renderDefaultIcon } from './render.js';
|
|
2
2
|
export { CATEGORIES, classify, classifyMime, isCategory } from './categories.js';
|
|
3
3
|
export { allExtensions, categoryFor, extToMime } from './mime.js';
|
|
4
4
|
export { DEFAULT_PALETTE, createPalette, accentFor } from './palette.js';
|
package/dist/png.js
CHANGED
|
@@ -7,5 +7,6 @@ export async function renderPng(svg, size) {
|
|
|
7
7
|
catch {
|
|
8
8
|
throw new Error('PNG export needs the optional dependency @resvg/resvg-js (npm i @resvg/resvg-js).');
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
// Our icons contain no <text>, so skip loading system fonts (it dominates the render time).
|
|
11
|
+
return new mod.Resvg(svg, { fitTo: { mode: 'width', value: size }, font: { loadSystemFonts: false } }).render().asPng();
|
|
11
12
|
}
|
package/dist/render.d.ts
CHANGED
|
@@ -24,3 +24,8 @@ export interface RenderResult {
|
|
|
24
24
|
accent: string;
|
|
25
25
|
}
|
|
26
26
|
export declare function renderIcon(extension: string, opts?: RenderOptions): RenderResult;
|
|
27
|
+
/**
|
|
28
|
+
* The fallback icon for extensions that have no icon of their own: the generic body without a label
|
|
29
|
+
* (an unknown extension cannot be named). Written as `default.svg` by `mimeforge --all`.
|
|
30
|
+
*/
|
|
31
|
+
export declare function renderDefaultIcon(opts?: RenderOptions): RenderResult;
|
package/dist/render.js
CHANGED
|
@@ -21,3 +21,10 @@ export function renderIcon(extension, opts = {}) {
|
|
|
21
21
|
}
|
|
22
22
|
return { svg: svg.replace(/>\s*\n\s*</g, '><').trim() + '\n', ext, category, accent };
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* The fallback icon for extensions that have no icon of their own: the generic body without a label
|
|
26
|
+
* (an unknown extension cannot be named). Written as `default.svg` by `mimeforge --all`.
|
|
27
|
+
*/
|
|
28
|
+
export function renderDefaultIcon(opts = {}) {
|
|
29
|
+
return renderIcon('default', { ...opts, category: 'generic', label: false });
|
|
30
|
+
}
|
package/package.json
CHANGED