@morphemecms/cms 0.7.0 → 0.7.1
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 +6 -0
- package/lib/licenses.mjs +1 -1
- package/package.json +1 -1
- package/site/materialSymbols.d.mts +8 -2
- package/site/materialSymbols.mjs +27 -11
- package/site/materialSymbols.test.mjs +44 -0
- package/site/theme.mjs +4 -1
- package/src/materialIcons.ts +5 -7
- package/src/virtual.d.ts +5 -0
- package/starter/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/lib/licenses.mjs
CHANGED
|
@@ -428,7 +428,7 @@ const HELPERS = [
|
|
|
428
428
|
[/^\0vite\//, 'vite'],
|
|
429
429
|
[/^\0rolldown\//, 'rolldown'],
|
|
430
430
|
];
|
|
431
|
-
const OWN_VIRTUAL = [/^\0virtual:(app-folders|all-icons)$/, /^\0site-theme-icons?(:|$)/];
|
|
431
|
+
const OWN_VIRTUAL = [/^\0virtual:(app-folders|all-icons|material-symbols)$/, /^\0site-theme-icons?(:|$)/];
|
|
432
432
|
|
|
433
433
|
/** An app or a theme as licensesIntegration takes it: its kind and id, its name, version and who made it, its manifest
|
|
434
434
|
* (its defineApp or its theme.json, with `license` and `thirdParty`), its folder, and whether the site is built with it
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morphemecms/cms",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Morpheme CMS: the editor for a site built with Astro, its screens, its blocks and the rules a site gives it. See README.md.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Lars Adolfsen",
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* import.meta.glob
|
|
1
|
+
/** All Outlined files as text, read one at a time: `{ '/node_modules/@material-symbols/svg-400/outlined/<name>.svg': '<svg …>' }`,
|
|
2
|
+
* the keys as import.meta.glob named them. `dir` is the URL or the path of the outlined/ folder. */
|
|
3
|
+
export function materialFiles(dir: any): {};
|
|
4
|
+
/** The module's source: `export default` of all the files (materialFiles). */
|
|
5
|
+
export function materialModule(): string;
|
|
6
|
+
/** The SSR module's source: the same as materialModule. With `ssr` false: an empty object. */
|
|
3
7
|
export function materialSsrModule(ssr: any): string;
|
|
8
|
+
/** The virtual module's id as imported (src/materialIcons.ts). */
|
|
9
|
+
export const MATERIAL_ALL: "virtual:material-symbols";
|
|
4
10
|
/** The virtual module's id as imported (packages/editor/src/icon.tsx). */
|
|
5
11
|
export const MATERIAL_SSR: "virtual:material-symbols-ssr";
|
package/site/materialSymbols.mjs
CHANGED
|
@@ -1,19 +1,35 @@
|
|
|
1
|
-
// The Material Symbols (Outlined) files as
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// The Material Symbols (Outlined) files as two modules answered by themePlugin (theme.mjs): `virtual:material-symbols` (all of them
|
|
2
|
+
// as text, for the one lazy chunk of src/materialIcons.ts) and `virtual:material-symbols-ssr` (all of them on the server render, so
|
|
3
|
+
// a backup icon, icon.tsx, is in the built page's HTML at once; `{}` in the browser). Files are read one at a time, never globbed
|
|
4
|
+
// (7,874 open files at once stops Cloudflare's build with EMFILE). Exposes MATERIAL_ALL, MATERIAL_SSR, materialFiles, materialModule,
|
|
5
|
+
// materialSsrModule. Reads @material-symbols/svg-400.
|
|
4
6
|
import { readdirSync, readFileSync } from 'node:fs';
|
|
5
7
|
import { pathToFileURL } from 'node:url';
|
|
6
8
|
|
|
9
|
+
/** The virtual module's id as imported (src/materialIcons.ts). */
|
|
10
|
+
export const MATERIAL_ALL = 'virtual:material-symbols';
|
|
7
11
|
/** The virtual module's id as imported (packages/editor/src/icon.tsx). */
|
|
8
12
|
export const MATERIAL_SSR = 'virtual:material-symbols-ssr';
|
|
9
13
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
const PREFIX = '/node_modules/@material-symbols/svg-400/outlined/';
|
|
15
|
+
|
|
16
|
+
/** All Outlined files as text, read one at a time: `{ '/node_modules/@material-symbols/svg-400/outlined/<name>.svg': '<svg …>' }`,
|
|
17
|
+
* the keys as import.meta.glob named them. `dir` is the URL or the path of the outlined/ folder. */
|
|
18
|
+
export function materialFiles(dir) {
|
|
19
|
+
const base = dir instanceof URL ? dir : pathToFileURL(`${String(dir).replace(/[\/]+$/, '')}/`);
|
|
15
20
|
const files = {};
|
|
16
|
-
for (const name of readdirSync(
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
for (const name of readdirSync(base).sort()) if (name.endsWith('.svg')) files[PREFIX + name] = readFileSync(new URL(name, base), 'utf8');
|
|
22
|
+
return files;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const outlined = () => new URL(`node_modules/@material-symbols/svg-400/outlined/`, pathToFileURL(`${process.cwd()}/`));
|
|
26
|
+
|
|
27
|
+
/** The module's source: `export default` of all the files (materialFiles). */
|
|
28
|
+
export function materialModule() {
|
|
29
|
+
return `export default ${JSON.stringify(materialFiles(outlined()))};`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** The SSR module's source: the same as materialModule. With `ssr` false: an empty object. */
|
|
33
|
+
export function materialSsrModule(ssr) {
|
|
34
|
+
return ssr ? materialModule() : 'export default {};';
|
|
19
35
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Tests of materialFiles, materialModule and materialSsrModule (site/materialSymbols.mjs): the Material Symbols files as one module.
|
|
2
|
+
// Run with `node --test site/materialSymbols.test.mjs`.
|
|
3
|
+
import { strict as assert } from 'node:assert';
|
|
4
|
+
import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { test } from 'node:test';
|
|
8
|
+
import { materialFiles, materialModule, materialSsrModule } from './materialSymbols.mjs';
|
|
9
|
+
|
|
10
|
+
const PREFIX = '/node_modules/@material-symbols/svg-400/outlined/';
|
|
11
|
+
const A = '<svg viewBox="0 0 1 1"><path d="A"/></svg>';
|
|
12
|
+
const B = '<svg viewBox="0 0 2 2"><path d="B"/></svg>';
|
|
13
|
+
|
|
14
|
+
const folder = mkdtempSync(join(tmpdir(), 'material-'));
|
|
15
|
+
const dir = join(folder, 'node_modules/@material-symbols/svg-400/outlined');
|
|
16
|
+
mkdirSync(dir, { recursive: true });
|
|
17
|
+
writeFileSync(join(dir, 'b.svg'), B);
|
|
18
|
+
writeFileSync(join(dir, 'a.svg'), A);
|
|
19
|
+
writeFileSync(join(dir, 'c.txt'), 'not an icon');
|
|
20
|
+
|
|
21
|
+
test('one key per svg file, sorted, with the file text', () => {
|
|
22
|
+
assert.deepEqual(materialFiles(dir), { [`${PREFIX}a.svg`]: A, [`${PREFIX}b.svg`]: B });
|
|
23
|
+
assert.deepEqual(Object.keys(materialFiles(dir)), [`${PREFIX}a.svg`, `${PREFIX}b.svg`]);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('a file that is not an svg has no key', () => {
|
|
27
|
+
assert.ok(!Object.keys(materialFiles(dir)).some((k) => k.endsWith('c.txt')));
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('the module source parses to the same object as materialFiles', () => {
|
|
31
|
+
const cwd = process.cwd();
|
|
32
|
+
process.chdir(folder);
|
|
33
|
+
try {
|
|
34
|
+
const code = materialModule();
|
|
35
|
+
assert.ok(code.startsWith('export default '));
|
|
36
|
+
assert.deepEqual(JSON.parse(code.slice('export default '.length, -1)), materialFiles(dir));
|
|
37
|
+
} finally {
|
|
38
|
+
process.chdir(cwd);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('without ssr the SSR module is an empty object', () => {
|
|
43
|
+
assert.equal(materialSsrModule(false), 'export default {};');
|
|
44
|
+
});
|
package/site/theme.mjs
CHANGED
|
@@ -11,7 +11,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
11
11
|
import { svgParts } from '@morphemecms/cms/lib/svg.mjs';
|
|
12
12
|
import { declarationProblems, ownerId } from '@morphemecms/cms/lib/licenses.mjs';
|
|
13
13
|
import { installedPacks, isIconName, packFolder, packProblems, phosphorFile, svgProblems, usedIcons } from './icons.mjs';
|
|
14
|
-
import { MATERIAL_SSR, materialSsrModule } from './materialSymbols.mjs';
|
|
14
|
+
import { MATERIAL_ALL, MATERIAL_SSR, materialModule, materialSsrModule } from './materialSymbols.mjs';
|
|
15
15
|
import { ICON_PACK_FILE, ICON_PACK_LICENSE, SYSTEM_PACKS, THEME_PACKS_FOLDER, packInUse, packTheme, themePackId } from './iconPacks.mjs';
|
|
16
16
|
import { MOTION_SCHEMES } from '@morphemecms/cms/lib/motion-schemes.mjs';
|
|
17
17
|
import { storeImportProblems } from './storeTheme.mjs';
|
|
@@ -227,6 +227,7 @@ const PHOSPHOR_REACT = '@phosphor-icons/react';
|
|
|
227
227
|
const PHOSPHOR_FILE = /@phosphor-icons\/core\/assets\/(?:regular|fill)\/([a-z0-9-]+)\.svg\?raw$/;
|
|
228
228
|
const REACT_ICONS = '\0site-theme-icons';
|
|
229
229
|
const FILE_ICON = '\0site-theme-icon:';
|
|
230
|
+
const MATERIAL_ALL_ID = `\0${MATERIAL_ALL}`;
|
|
230
231
|
const MATERIAL_SSR_ID = `\0${MATERIAL_SSR}`;
|
|
231
232
|
|
|
232
233
|
/** The React component's name of a Phosphor icon by its file's name (`caret-right` → CaretRight), when Phosphor has it. */
|
|
@@ -471,6 +472,7 @@ export function themePlugin() {
|
|
|
471
472
|
// The theme's icons import Phosphor's own.
|
|
472
473
|
if (source === PHOSPHOR_REACT) return own && importer !== REACT_ICONS ? REACT_ICONS : null;
|
|
473
474
|
if (source === ALL_ICONS) return '\0' + ALL_ICONS;
|
|
475
|
+
if (source === MATERIAL_ALL) return MATERIAL_ALL_ID;
|
|
474
476
|
if (source === MATERIAL_SSR) return MATERIAL_SSR_ID;
|
|
475
477
|
const icon = source.match(PHOSPHOR_FILE)?.[1];
|
|
476
478
|
if (icon) return svgParts(icons[icon]) ? FILE_ICON + icon : null;
|
|
@@ -485,6 +487,7 @@ export function themePlugin() {
|
|
|
485
487
|
return null;
|
|
486
488
|
},
|
|
487
489
|
load(id, options) {
|
|
490
|
+
if (id === MATERIAL_ALL_ID) return materialModule();
|
|
488
491
|
if (id === MATERIAL_SSR_ID) return materialSsrModule(options?.ssr);
|
|
489
492
|
if (id === REACT_ICONS) return reactIcons(icons);
|
|
490
493
|
if (id === '\0' + ALL_ICONS)
|
package/src/materialIcons.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// All of Material Symbols (Outlined, regular and filled) as text, by their file, for the icons icon.tsx draws that are not on
|
|
2
|
-
// its list: one lazy chunk, loaded in the browser the first time one is drawn
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
eager: true,
|
|
8
|
-
});
|
|
2
|
+
// its list: one lazy chunk, loaded in the browser the first time one is drawn. The set comes from virtual:material-symbols
|
|
3
|
+
// (packages/editor/site/materialSymbols.mjs), one module read file by file. Imported by icon.tsx only dynamically.
|
|
4
|
+
import all from 'virtual:material-symbols';
|
|
5
|
+
|
|
6
|
+
export const materialIcons: Record<string, string> = all;
|
package/src/virtual.d.ts
CHANGED
package/starter/package.json
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"@material-symbols/svg-400": "0.48.2",
|
|
33
33
|
"@material/material-color-utilities": "^0.3.0",
|
|
34
34
|
"@milkdown/kit": "^7.22.3",
|
|
35
|
-
"@morphemecms/cms": "0.7.
|
|
35
|
+
"@morphemecms/cms": "0.7.1",
|
|
36
36
|
"@phosphor-icons/core": "^2.1.1",
|
|
37
37
|
"@phosphor-icons/react": "^2.1.10",
|
|
38
38
|
"@tailwindcss/typography": "^0.5.20",
|