mimeforge 0.1.2 → 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 +7 -0
- package/README.md +36 -6
- 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,13 @@
|
|
|
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
|
+
|
|
6
13
|
## [0.1.2] - 2026-10-08
|
|
7
14
|
|
|
8
15
|
Documentation only.
|
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ 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
|
|
|
@@ -85,11 +85,39 @@ Then `npm run icons` and reference `/icons/<ext>.svg`. `public/icons/manifest.js
|
|
|
85
85
|
category, which is handy for lookups. If you only show a few types, list them instead of `--all`. To render icons at
|
|
86
86
|
runtime instead (a server, a build plugin), use the [library API](#library-api).
|
|
87
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
|
|
100
|
+
```
|
|
101
|
+
|
|
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' })`).
|
|
114
|
+
|
|
88
115
|
## Everyday use
|
|
89
116
|
|
|
90
117
|
```bash
|
|
91
118
|
mimeforge pdf docx webm -o icons # a few icons
|
|
92
|
-
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
|
|
93
121
|
mimeforge --list # which extension gets which category
|
|
94
122
|
mimeforge --test-run # visual check, see below
|
|
95
123
|
```
|
|
@@ -209,7 +237,7 @@ optional dependency `@resvg/resvg-js` (installed by default; if it is missing, M
|
|
|
209
237
|
|
|
210
238
|
| Situation | What happens |
|
|
211
239
|
|---|---|
|
|
212
|
-
| 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`) |
|
|
213
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 |
|
|
214
242
|
| Light accent color | label text switches to a dark ink when white would have less than 3:1 contrast |
|
|
215
243
|
| Character the font does not have | skipped |
|
|
@@ -229,9 +257,10 @@ how to change it.
|
|
|
229
257
|
Install with `npm i mimeforge`. The package is ESM, so use `import` (from CommonJS: `const { renderIcon } = await import('mimeforge')`).
|
|
230
258
|
|
|
231
259
|
```ts
|
|
232
|
-
import { renderIcon, loadFont, loadBodies, createPalette } from 'mimeforge';
|
|
260
|
+
import { renderIcon, renderDefaultIcon, loadFont, loadBodies, createPalette } from 'mimeforge';
|
|
233
261
|
|
|
234
262
|
renderIcon('pdf').svg; // SVG string
|
|
263
|
+
renderDefaultIcon().svg; // fallback icon: generic body, no label
|
|
235
264
|
renderIcon('docx', { accent: '#0a7', label: 'WORD' }).svg; // custom accent and label text
|
|
236
265
|
|
|
237
266
|
renderIcon('xyz', {
|
|
@@ -243,14 +272,15 @@ renderIcon('xyz', {
|
|
|
243
272
|
});
|
|
244
273
|
```
|
|
245
274
|
|
|
246
|
-
`renderIcon` returns `{ svg, ext, category, accent }`. Other exports: `categoryFor`, `allExtensions`, `CATEGORIES`,
|
|
275
|
+
`renderIcon` returns `{ svg, ext, category, accent }`. Other exports: `renderDefaultIcon`, `categoryFor`, `allExtensions`, `CATEGORIES`,
|
|
247
276
|
`DEFAULT_PALETTE`, `validateBody`, `renderLabel`, `bitmapFont`, `outlineFont` (see `src/index.ts`). Types are included.
|
|
248
277
|
|
|
249
278
|
## CLI reference
|
|
250
279
|
|
|
251
280
|
```
|
|
252
281
|
mimeforge <ext...> [options] write <out>/<ext>.svg for the given extensions
|
|
253
|
-
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)
|
|
254
284
|
mimeforge --test-run [options] HTML preview page (default dir: out/test-run)
|
|
255
285
|
```
|
|
256
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