1
0
Fork 0

wip: Implemented editor export

This commit is contained in:
joostdecock 2025-02-02 15:02:35 +01:00
parent 77ee973355
commit 3ec1cbd01b
10 changed files with 332 additions and 157 deletions

205
package-lock.json generated
View file

@ -25475,12 +25475,6 @@
} }
} }
}, },
"node_modules/@docusaurus/core/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/@docusaurus/cssnano-preset": { "node_modules/@docusaurus/cssnano-preset": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.5.2.tgz", "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.5.2.tgz",
@ -25496,12 +25490,6 @@
"node": ">=18.0" "node": ">=18.0"
} }
}, },
"node_modules/@docusaurus/cssnano-preset/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/@docusaurus/faster": { "node_modules/@docusaurus/faster": {
"version": "3.7.0", "version": "3.7.0",
"resolved": "https://registry.npmjs.org/@docusaurus/faster/-/faster-3.7.0.tgz", "resolved": "https://registry.npmjs.org/@docusaurus/faster/-/faster-3.7.0.tgz",
@ -25825,12 +25813,6 @@
} }
} }
}, },
"node_modules/@docusaurus/mdx-loader/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/@docusaurus/mdx-loader/node_modules/unified": { "node_modules/@docusaurus/mdx-loader/node_modules/unified": {
"version": "11.0.5", "version": "11.0.5",
"resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
@ -26042,12 +26024,6 @@
} }
} }
}, },
"node_modules/@docusaurus/plugin-content-blog/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/@docusaurus/plugin-content-docs": { "node_modules/@docusaurus/plugin-content-docs": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.5.2.tgz", "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.5.2.tgz",
@ -26153,12 +26129,6 @@
} }
} }
}, },
"node_modules/@docusaurus/plugin-content-docs/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/@docusaurus/plugin-content-pages": { "node_modules/@docusaurus/plugin-content-pages": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.5.2.tgz", "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.5.2.tgz",
@ -26255,12 +26225,6 @@
} }
} }
}, },
"node_modules/@docusaurus/plugin-content-pages/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/@docusaurus/plugin-debug": { "node_modules/@docusaurus/plugin-debug": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.5.2.tgz", "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.5.2.tgz",
@ -26355,12 +26319,6 @@
} }
} }
}, },
"node_modules/@docusaurus/plugin-debug/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/@docusaurus/plugin-google-analytics": { "node_modules/@docusaurus/plugin-google-analytics": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.5.2.tgz", "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.5.2.tgz",
@ -26401,12 +26359,6 @@
"react-dom": "^18.0.0" "react-dom": "^18.0.0"
} }
}, },
"node_modules/@docusaurus/plugin-google-analytics/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/@docusaurus/plugin-google-gtag": { "node_modules/@docusaurus/plugin-google-gtag": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.5.2.tgz", "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.5.2.tgz",
@ -26448,12 +26400,6 @@
"react-dom": "^18.0.0" "react-dom": "^18.0.0"
} }
}, },
"node_modules/@docusaurus/plugin-google-gtag/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/@docusaurus/plugin-google-tag-manager": { "node_modules/@docusaurus/plugin-google-tag-manager": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.5.2.tgz", "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.5.2.tgz",
@ -26494,12 +26440,6 @@
"react-dom": "^18.0.0" "react-dom": "^18.0.0"
} }
}, },
"node_modules/@docusaurus/plugin-google-tag-manager/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/@docusaurus/plugin-sitemap": { "node_modules/@docusaurus/plugin-sitemap": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.5.2.tgz", "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.5.2.tgz",
@ -26597,12 +26537,6 @@
} }
} }
}, },
"node_modules/@docusaurus/plugin-sitemap/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/@docusaurus/preset-classic": { "node_modules/@docusaurus/preset-classic": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.5.2.tgz", "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.5.2.tgz",
@ -26765,12 +26699,6 @@
} }
} }
}, },
"node_modules/@docusaurus/theme-classic/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/@docusaurus/theme-common": { "node_modules/@docusaurus/theme-common": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.5.2.tgz", "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.5.2.tgz",
@ -26851,12 +26779,6 @@
} }
} }
}, },
"node_modules/@docusaurus/theme-common/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/@docusaurus/theme-search-algolia": { "node_modules/@docusaurus/theme-search-algolia": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.5.2.tgz", "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.5.2.tgz",
@ -27111,12 +27033,6 @@
"@algolia/transporter": "4.24.0" "@algolia/transporter": "4.24.0"
} }
}, },
"node_modules/@docusaurus/theme-search-algolia/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/@docusaurus/theme-translations": { "node_modules/@docusaurus/theme-translations": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.5.2.tgz", "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.5.2.tgz",
@ -27130,12 +27046,6 @@
"node": ">=18.0" "node": ">=18.0"
} }
}, },
"node_modules/@docusaurus/theme-translations/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/@docusaurus/types": { "node_modules/@docusaurus/types": {
"version": "3.7.0", "version": "3.7.0",
"resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.7.0.tgz", "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.7.0.tgz",
@ -27430,12 +27340,6 @@
} }
} }
}, },
"node_modules/@docusaurus/utils-common/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/@docusaurus/utils-validation": { "node_modules/@docusaurus/utils-validation": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.5.2.tgz", "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.5.2.tgz",
@ -27507,12 +27411,6 @@
} }
} }
}, },
"node_modules/@docusaurus/utils-validation/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/@docusaurus/utils/node_modules/@docusaurus/utils-common": { "node_modules/@docusaurus/utils/node_modules/@docusaurus/utils-common": {
"version": "3.7.0", "version": "3.7.0",
"resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.7.0.tgz", "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.7.0.tgz",
@ -36290,12 +36188,6 @@
"tslib": "^2.0.3" "tslib": "^2.0.3"
} }
}, },
"node_modules/camel-case/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/camelcase": { "node_modules/camelcase": {
"version": "5.3.1", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
@ -39108,12 +39000,6 @@
"tslib": "^2.0.3" "tslib": "^2.0.3"
} }
}, },
"node_modules/dot-case/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/dot-prop": { "node_modules/dot-prop": {
"version": "5.3.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
@ -47457,12 +47343,6 @@
"tslib": "^2.0.3" "tslib": "^2.0.3"
} }
}, },
"node_modules/lower-case/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/lowercase-keys": { "node_modules/lowercase-keys": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz",
@ -50231,12 +50111,6 @@
"tslib": "^2.0.3" "tslib": "^2.0.3"
} }
}, },
"node_modules/no-case/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/node-emoji": { "node_modules/node-emoji": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.1.3.tgz", "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.1.3.tgz",
@ -51578,12 +51452,6 @@
"tslib": "^2.0.3" "tslib": "^2.0.3"
} }
}, },
"node_modules/param-case/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/parent-module": { "node_modules/parent-module": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@ -51763,12 +51631,6 @@
"tslib": "^2.0.3" "tslib": "^2.0.3"
} }
}, },
"node_modules/pascal-case/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/passport": { "node_modules/passport": {
"version": "0.7.0", "version": "0.7.0",
"resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz",
@ -57127,12 +56989,6 @@
"tslib": "^2.0.3" "tslib": "^2.0.3"
} }
}, },
"node_modules/snake-case/node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
"license": "0BSD"
},
"node_modules/sockjs": { "node_modules/sockjs": {
"version": "0.3.24", "version": "0.3.24",
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
@ -58882,9 +58738,9 @@
} }
}, },
"node_modules/tslib": { "node_modules/tslib": {
"version": "2.6.2", "version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD" "license": "0BSD"
}, },
"node_modules/tuf-js": { "node_modules/tuf-js": {
@ -62217,6 +62073,7 @@
"html-react-parser": "^5.0.7", "html-react-parser": "^5.0.7",
"luxon": "^3.5.0", "luxon": "^3.5.0",
"nuqs": "^1.17.6", "nuqs": "^1.17.6",
"pdfkit": "^0.16.0",
"react-markdown": "^9.0.1", "react-markdown": "^9.0.1",
"tlds": "^1.255.0", "tlds": "^1.255.0",
"use-local-storage-state": "19.1.0", "use-local-storage-state": "19.1.0",
@ -62234,6 +62091,15 @@
"react": "^18.2.0" "react": "^18.2.0"
} }
}, },
"packages/react/node_modules/@swc/helpers": {
"version": "0.5.15",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
"integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.8.0"
}
},
"packages/react/node_modules/axios": { "packages/react/node_modules/axios": {
"version": "1.7.2", "version": "1.7.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz",
@ -62245,6 +62111,15 @@
"proxy-from-env": "^1.1.0" "proxy-from-env": "^1.1.0"
} }
}, },
"packages/react/node_modules/clone": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
"license": "MIT",
"engines": {
"node": ">=0.8"
}
},
"packages/react/node_modules/cookie": { "packages/react/node_modules/cookie": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
@ -62256,6 +62131,23 @@
"node": ">=18" "node": ">=18"
} }
}, },
"packages/react/node_modules/fontkit": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz",
"integrity": "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==",
"license": "MIT",
"dependencies": {
"@swc/helpers": "^0.5.12",
"brotli": "^1.3.2",
"clone": "^2.1.2",
"dfa": "^1.2.0",
"fast-deep-equal": "^3.1.3",
"restructure": "^3.0.0",
"tiny-inflate": "^1.0.3",
"unicode-properties": "^1.4.0",
"unicode-trie": "^2.0.0"
}
},
"packages/react/node_modules/nuqs": { "packages/react/node_modules/nuqs": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/nuqs/-/nuqs-2.3.0.tgz", "resolved": "https://registry.npmjs.org/nuqs/-/nuqs-2.3.0.tgz",
@ -62286,6 +62178,19 @@
} }
} }
}, },
"packages/react/node_modules/pdfkit": {
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/pdfkit/-/pdfkit-0.16.0.tgz",
"integrity": "sha512-oXMxkIqXH4uTAtohWdYA41i/f6i2ReB78uhgizN8H4hJEpgR3/Xjy3iu2InNAuwCIabN3PVs8P1D6G4+W2NH0A==",
"license": "MIT",
"dependencies": {
"crypto-js": "^4.2.0",
"fontkit": "^2.0.4",
"jpeg-exif": "^1.1.4",
"linebreak": "^1.1.0",
"png-js": "^1.0.0"
}
},
"packages/react/node_modules/react-router": { "packages/react/node_modules/react-router": {
"version": "7.1.1", "version": "7.1.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.1.tgz", "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.1.tgz",
@ -62330,6 +62235,12 @@
"react-dom": ">=18" "react-dom": ">=18"
} }
}, },
"packages/react/node_modules/restructure": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.2.tgz",
"integrity": "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==",
"license": "MIT"
},
"packages/react/node_modules/tlds": { "packages/react/node_modules/tlds": {
"version": "1.255.0", "version": "1.255.0",
"resolved": "https://registry.npmjs.org/tlds/-/tlds-1.255.0.tgz", "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.255.0.tgz",

View file

@ -27,7 +27,7 @@ export const CopyToClipboard = ({ content, label = false, sup = false }) => {
const text = const text =
typeof content === 'string' ? content : strip(ReactDOMServer.renderToStaticMarkup(content)) typeof content === 'string' ? content : strip(ReactDOMServer.renderToStaticMarkup(content))
const style = sup ? 'w-4 h-4 -mt-4' : 'w-5 h-5' const style = sup ? 'tw-w-4 tw-h-4 tw--mt-4' : 'tw-w-5 tw-h-5'
return ( return (
<Copy text={text} onCopy={() => handleCopied(setCopied, setLoadingStatus, label)}> <Copy text={text} onCopy={() => handleCopied(setCopied, setLoadingStatus, label)}>

View file

@ -0,0 +1,67 @@
import React, { useContext, useState } from 'react'
import ReactDOMServer from 'react-dom/server'
import { horFlexClasses } from '@freesewing/utils'
import { CopyIcon, OkIcon } from '@freesewing/react/components/Icon'
import { CopyToClipboard as Copy } from 'react-copy-to-clipboard'
const strip = (html) =>
typeof DOMParser === 'undefined'
? html
: new DOMParser().parseFromString(html, 'text/html').body.textContent || ''
const handleCopied = (setCopied, label, update) => {
setCopied(true)
update.notifySuccess(label ? `${label} c` : 'C' + 'opied to clipboard')
setTimeout(() => setCopied(false), 1000)
}
export const CopyToClipboard = ({ content, label = false, sup = false, update }) => {
const [copied, setCopied] = useState(false)
const text =
typeof content === 'string' ? content : strip(ReactDOMServer.renderToStaticMarkup(content))
const style = sup ? 'tw-w-4 tw-h-4 tw--mt-4' : 'tw-w-5 tw-h-5'
return (
<Copy text={text} onCopy={() => handleCopied(setCopied, label, update)}>
<button className={copied ? 'tw-text-success' : ''}>
{copied ? (
<OkIcon
className={`${style} tw-text-success-content tw-bg-success tw-rounded-full tw-p-1`}
stroke={4}
/>
) : (
<CopyIcon className={`${style} tw-text-inherit`} />
)}
</button>
</Copy>
)
}
export const CopyToClipboardButton = ({ content, label = false, update, children }) => {
const [copied, setCopied] = useState(false)
const text =
typeof content === 'string' ? content : strip(ReactDOMServer.renderToStaticMarkup(content))
const style = 'tw-w-6 tw-h-6'
return (
<Copy text={text} onCopy={() => handleCopied(setCopied, label, update)}>
<button
className={`${horFlexClasses} tw-daisy-btn ${copied ? 'tw-daisy-btn-success' : 'tw-daisy-btn-primary'}`}
>
{copied ? (
<OkIcon
className={`${style} tw-text-success-content tw-bg-success tw-rounded-full tw-p-1`}
stroke={4}
/>
) : (
<CopyIcon className={`${style} tw-text-inherit`} />
)}
<div>{children}</div>
</button>
</Copy>
)
}

View file

@ -0,0 +1,162 @@
// Dependencies
import { linkClasses, horFlexClasses, patternUrlFromState } from '@freesewing/utils'
import { exportTypes, handleExport } from '../../lib/export/index.mjs'
// Hooks
import React, { useState } from 'react'
// Components
import { H1, H2, H3, H5 } from '@freesewing/react/components/Heading'
import { Popout } from '@freesewing/react/components/Popout'
import { HeaderMenu } from '../HeaderMenu.mjs'
import { CopyToClipboardButton } from '../CopyToClipboard.mjs'
import { Highlight } from '@freesewing/react/components/Highlight'
import { EditIcon, CodeIcon, TipIcon, PrintIcon } from '@freesewing/react/components/Icon'
/**
* This is the export view, it allows you to export your pattern in a variety of formats
*
* @param {Object} props - All the props
* @param {Function} props.config - The editor configuration
* @param {Object} props.state - The editor state object
* @param {Object} props.update - Helper object for updating the editor state
*/
export const ExportView = (props) => {
const { config, state, update } = props
const [link, setLink] = useState(false)
const [format, setFormat] = useState(false)
const { protocol, hostname, port } = window.location
const site =
(protocol === 'https:' && port === 443) || (protocol === 'http:' && port === 80)
? `${window.location.protocol}//${window.location.hostname}`
: `${window.location.protocol}//${window.location.hostname}:${window.location.port}`
const urls = {
a: `${site}${patternUrlFromState(state, true)}`,
b: `${site}${patternUrlFromState(state, false)}`,
}
const exportProps = {
design: props.design,
Design: props.Design,
ui: props.state.ui,
settings: props.state.settings,
setLink,
setFormat,
startLoading: update.startLoading,
stopLoading: update.stopLoading,
}
return (
<>
<HeaderMenu state={state} {...{ config, update }} />
<div className="tw-m-auto tw-mt-8 tw-max-w-2xl tw-px-4 tw-mb-8">
<H1>Export Pattern</H1>
<H2>Share your pattern</H2>
<p>If you merely want to share your pattern with others, you can copy these URLs:</p>
<div className="tw-grid tw-grid-cols-1 lg:tw-grid-cols-2 tw-gap-2 tw-mt-2 ">
<CopyToClipboardButton content={urls.a} update={update}>
Pattern and Measurements
</CopyToClipboardButton>
<CopyToClipboardButton content={urls.b} update={update}>
Pattern only
</CopyToClipboardButton>
</div>
<details className="tw-pt-2">
<summary>
<span className={linkClasses}>Explain these buttons</span>
</summary>
<div className="tw-ml-4 tw-border-l-2 tw-pl-4">
<H5>Pattern and Measurements</H5>
<p>
Use the <b>Pattern and Measurements</b> URL to share this pattern exactly as-is,
including the measurements used to generate it:
</p>
<Highlight noCopy title="URL" language="URL">
{urls.a}
</Highlight>
<div className="tw-text-sm tw--mt-3 tw-flex tw-flex-row tw-gap-2 tw-items-center tw-pl-4 tw-mb-4">
<TipIcon className="tw-w-5 tw-h-5 tw-text-success" />
Use this to allow others to troubleshoot your pattern.
</div>
<H5>Pattern only</H5>
<p>
Use the <b>Pattern only</b> to share this pattern as-is, but without measurements:
</p>
<Highlight noCopy title="URL" language="URL">
{urls.b}
</Highlight>
<div className="tw-text-sm tw--mt-3 tw-flex tw-flex-row tw-gap-2 tw-items-center tw-pl-4">
<TipIcon className="tw-w-5 tw-h-5 tw-text-success" />
Use this to allow others to recreate this pattern for themselves.
</div>
</div>
</details>
<H2>Export for printing</H2>
<p>You can export your pattern in a variety of page formats for printing:</p>
<div className="tw-grid tw-grid-cols-1 lg:tw-grid-cols-2 tw-gap-2">
<div className="tw-flex tw-flex-col tw-gap-2 tw-max-w-md">
<H3>ISO paper sizes</H3>
{['a4', 'a3', 'a2', 'a1', 'a0'].map((format) => (
<button
className={`${horFlexClasses} tw-daisy-btn tw-daisy-btn-primary tw-uppercase`}
onClick={() => exportPattern({ ...exportProps, format })}
>
<PrintIcon />
{format} PDF
</button>
))}
</div>
<div className="tw-flex tw-flex-col tw-gap-2 tw-max-w-md">
<H3>Other paper sizes</H3>
{['letter', 'legal', 'tabloid'].map((format) => (
<button
className={`${horFlexClasses} tw-daisy-btn tw-daisy-btn-primary tw-uppercase`}
onClick={() => exportPattern({ ...exportProps, format })}
>
<PrintIcon />
{format} PDF
</button>
))}
</div>
</div>
<H2>Export for editing</H2>
<p>
We recommend SVG for editing, but we also provide a full-sized PDF if you prefer that.
</p>
<div className="tw-grid tw-grid-cols-1 lg:tw-grid-cols-2 tw-gap-2 tw-mt-2">
{['svg', 'pdf'].map((format) => (
<button
className={`${horFlexClasses} tw-daisy-btn tw-daisy-btn-primary tw-uppercase`}
onClick={() => exportPattern({ ...exportProps, format })}
>
<EditIcon />
{format}
</button>
))}
</div>
<H2>Export as code</H2>
<p>This is all you need to reconstruct this pattern using FreeSewing&apos; software:</p>
<div className="tw-grid tw-grid-cols-1 lg:tw-grid-cols-2 tw-gap-2 tw-mt-2">
{['json', 'yaml'].map((format) => (
<button
className={`${horFlexClasses} tw-daisy-btn tw-daisy-btn-primary tw-uppercase`}
onClick={() => exportPattern({ ...exportProps, format })}
>
<CodeIcon />
{format}
</button>
))}
</div>
</div>
</>
)
}
function exportPattern(props) {
props.setLink(false)
props.setFormat(props.format)
handleExport({
...props,
onComplete: (e) => (e.data?.link ? props.setLink(e.data.link) : null),
onError: (e) => (e.data?.error ? props.stopLoading('export', e.data.error.message) : null),
})
}

View file

@ -4,6 +4,7 @@ import { DesignsView } from './DesignsView.mjs'
import { MeasurementsView } from './MeasurementsView.mjs' import { MeasurementsView } from './MeasurementsView.mjs'
import { DraftView } from './DraftView.mjs' import { DraftView } from './DraftView.mjs'
import { SaveView } from './SaveView.mjs' import { SaveView } from './SaveView.mjs'
import { ExportView } from './ExportView.mjs'
import { ErrorIcon } from '@freesewing/react/components/Icon' import { ErrorIcon } from '@freesewing/react/components/Icon'
import { import {
OptionsIcon, OptionsIcon,
@ -53,6 +54,7 @@ export const View = (props) => {
if (view === 'measurements') return <MeasurementsView {...props} /> if (view === 'measurements') return <MeasurementsView {...props} />
if (view === 'draft') return <DraftView {...props} /> if (view === 'draft') return <DraftView {...props} />
if (view === 'save') return <SaveView {...props} /> if (view === 'save') return <SaveView {...props} />
if (view === 'export') return <ExportView {...props} />
/* /*
viewComponents: { viewComponents: {
draft: 'DraftView', draft: 'DraftView',

View file

@ -18,6 +18,7 @@ const defaultTitles = {
* @params {bool} raw - Set this to true to not escape tags * @params {bool} raw - Set this to true to not escape tags
* @params {string} title - Title for the highlight * @params {string} title - Title for the highlight
* @params {string} copy - Content to copy to clipboard * @params {string} copy - Content to copy to clipboard
* @params {bool} noCopy - Do not add copy to clipboard
*/ */
export const Highlight = ({ export const Highlight = ({
language = 'txt', language = 'txt',
@ -25,6 +26,7 @@ export const Highlight = ({
raw = false, raw = false,
title = false, title = false,
copy = false, copy = false,
noCopy = false,
}) => { }) => {
if (children?.props?.className) { if (children?.props?.className) {
language = children.props.className.split('-').pop() language = children.props.className.split('-').pop()
@ -46,7 +48,7 @@ export const Highlight = ({
`} `}
> >
<span>{label}</span> <span>{label}</span>
<CopyToClipboard content={copy ? copy : children} label={label} /> {noCopy ? null : <CopyToClipboard content={copy ? copy : children} label={label} />}
</div> </div>
<pre {...preProps}>{children}</pre> <pre {...preProps}>{children}</pre>
</div> </div>

View file

@ -125,6 +125,13 @@ export const CloseIcon = (props) => (
</IconWrapper> </IconWrapper>
) )
// Looks like coding brackets
export const CodeIcon = (props) => (
<IconWrapper {...props}>
<path d="M17.25 6.75 22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3-4.5 16.5" />
</IconWrapper>
)
// FIXME // FIXME
export const CompareIcon = (props) => ( export const CompareIcon = (props) => (
<IconWrapper {...props}> <IconWrapper {...props}>

View file

@ -86,12 +86,12 @@
"html-react-parser": "^5.0.7", "html-react-parser": "^5.0.7",
"luxon": "^3.5.0", "luxon": "^3.5.0",
"nuqs": "^1.17.6", "nuqs": "^1.17.6",
"pdfkit": "^0.16.0",
"react-markdown": "^9.0.1", "react-markdown": "^9.0.1",
"tlds": "^1.255.0", "tlds": "^1.255.0",
"use-local-storage-state": "19.1.0", "use-local-storage-state": "19.1.0",
"use-session-storage-state": "^19.0.0" "use-session-storage-state": "^19.0.0"
}, },
"devDependencies": {},
"files": [ "files": [
"components/**", "components/**",
"hooks/**", "hooks/**",

View file

@ -1,5 +1,6 @@
import tlds from 'tlds/index.json' with { type: 'json' } import tlds from 'tlds/index.json' with { type: 'json' }
import { cloudflare as cloudflareConfig } from '@freesewing/config' import { cloudflare as cloudflareConfig } from '@freesewing/config'
import _get from 'lodash/get.js'
import _set from 'lodash/set.js' import _set from 'lodash/set.js'
import _unset from 'lodash/unset.js' import _unset from 'lodash/unset.js'
import _orderBy from 'lodash/orderBy.js' import _orderBy from 'lodash/orderBy.js'
@ -8,6 +9,7 @@ import { loadingMessages } from './loading-messages.mjs'
/* /*
* Re-export lodash utils * Re-export lodash utils
*/ */
export const get = _get
export const set = _set export const set = _set
export const unset = _unset export const unset = _unset
export const orderBy = _orderBy export const orderBy = _orderBy
@ -31,8 +33,7 @@ export const horFlexClassesNoSm =
/* /*
* These classes are what makes a link a link * These classes are what makes a link a link
*/ */
export const linkClasses = export const linkClasses = 'tw-text-secondary hover:tw-underline hover:tw-cursor-pointer'
'tw-underline tw-decoration-2 hover:tw-decoration-4 tw-text-secondary hover:tw-text-secondary-focus tw-font-medium'
/* /*
* FUNCTIONS * FUNCTIONS
@ -48,6 +49,18 @@ export function capitalize(string) {
return typeof string === 'string' ? string.charAt(0).toUpperCase() + string.slice(1) : '' return typeof string === 'string' ? string.charAt(0).toUpperCase() + string.slice(1) : ''
} }
/**
* A method to clone objects
*
* Note that as this uses JSON, this can only clone what can be serialized.
*
* @param {object} obj - The object to clone
* @return {object} clone - The cloned object
*/
export function clone(obj) {
return JSON.parse(JSON.stringify(obj))
}
/* /*
* Returns the URL of a cloudflare image * Returns the URL of a cloudflare image
* based on the ID and Variant * based on the ID and Variant
@ -72,7 +85,7 @@ export function cloudflareImageUrl({ id = 'default-avatar', variant = 'public' }
} }
/** /**
* Determines the design optino type based on the option's config * Determines the design option type based on the option's config
* *
* @param {object} option - The option config * @param {object} option - The option config
* @return {string} type - The option type * @return {string} type - The option type
@ -339,10 +352,20 @@ export const mutateObject = (obj = {}, path, val = 'unset') => {
} }
/** Generate a URL to create a new pattern with a given design, settings, and view */ /** Generate a URL to create a new pattern with a given design, settings, and view */
export const newPatternUrl = ({ design, settings = {}, view = 'draft' }) => export const patternUrlFromState = (state = {}, includeMeasurements = false, view = 'draft') => {
`/-/#settings=${encodeURIComponent( // Avoid changing state by accident
JSON.stringify(settings) const newState = clone(state)
)}&view=${encodeURIComponent('"' + view + '"')}` const measurements = includeMeasurements ? { ...(newState.settings?.measurements || {}) } : {}
const settings = { ...(newState.settings || {}) }
settings.measurements = measurements
const obj = {
design: newState.design,
settings,
view,
}
return `/editor/#s=${encodeURIComponent(JSON.stringify(obj))}`
}
/* /*
* A method to ensure input is not empty * A method to ensure input is not empty

View file

@ -10,6 +10,7 @@ export default {
'../../packages/react/context/**/*.mjs', '../../packages/react/context/**/*.mjs',
'../../packages/react/hooks/**/*.mjs', '../../packages/react/hooks/**/*.mjs',
'../../packages/react/lib/tailwind-force.mjs', '../../packages/react/lib/tailwind-force.mjs',
'../../packages/utils/src/*.mjs',
'./tailwind-force.html', './tailwind-force.html',
], ],
plugins: [daisyui], plugins: [daisyui],