diff --git a/package-lock.json b/package-lock.json index 37bd7287e5b..475bf8328f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.5.2.tgz", @@ -25496,12 +25490,6 @@ "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": { "version": "3.7.0", "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": { "version": "11.0.5", "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": { "version": "3.5.2", "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": { "version": "3.5.2", "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": { "version": "3.5.2", "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": { "version": "3.5.2", "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" } }, - "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": { "version": "3.5.2", "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" } }, - "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": { "version": "3.5.2", "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" } }, - "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": { "version": "3.5.2", "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": { "version": "3.5.2", "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": { "version": "3.5.2", "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": { "version": "3.5.2", "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" } }, - "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": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.5.2.tgz", @@ -27130,12 +27046,6 @@ "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": { "version": "3.7.0", "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": { "version": "3.5.2", "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": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.7.0.tgz", @@ -36290,12 +36188,6 @@ "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": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -39108,12 +39000,6 @@ "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": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", @@ -47457,12 +47343,6 @@ "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": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", @@ -50231,12 +50111,6 @@ "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": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.1.3.tgz", @@ -51578,12 +51452,6 @@ "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": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -51763,12 +51631,6 @@ "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": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", @@ -57127,12 +56989,6 @@ "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": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -58882,9 +58738,9 @@ } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/tuf-js": { @@ -62217,6 +62073,7 @@ "html-react-parser": "^5.0.7", "luxon": "^3.5.0", "nuqs": "^1.17.6", + "pdfkit": "^0.16.0", "react-markdown": "^9.0.1", "tlds": "^1.255.0", "use-local-storage-state": "19.1.0", @@ -62234,6 +62091,15 @@ "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": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", @@ -62245,6 +62111,15 @@ "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": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", @@ -62256,6 +62131,23 @@ "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": { "version": "2.3.0", "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": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.1.tgz", @@ -62330,6 +62235,12 @@ "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": { "version": "1.255.0", "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.255.0.tgz", diff --git a/packages/react/components/CopyToClipboard/index.mjs b/packages/react/components/CopyToClipboard/index.mjs index 7e06d1b98f5..0c55084251e 100644 --- a/packages/react/components/CopyToClipboard/index.mjs +++ b/packages/react/components/CopyToClipboard/index.mjs @@ -27,7 +27,7 @@ export const CopyToClipboard = ({ content, label = false, sup = false }) => { const text = 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 ( handleCopied(setCopied, setLoadingStatus, label)}> diff --git a/packages/react/components/Editor/components/CopyToClipboard.mjs b/packages/react/components/Editor/components/CopyToClipboard.mjs new file mode 100644 index 00000000000..9a447333afa --- /dev/null +++ b/packages/react/components/Editor/components/CopyToClipboard.mjs @@ -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 ( + handleCopied(setCopied, label, update)}> + + + ) +} + +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 ( + handleCopied(setCopied, label, update)}> + + + ) +} diff --git a/packages/react/components/Editor/components/views/ExportView.mjs b/packages/react/components/Editor/components/views/ExportView.mjs new file mode 100644 index 00000000000..ae789a89dff --- /dev/null +++ b/packages/react/components/Editor/components/views/ExportView.mjs @@ -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 ( + <> + +
+

Export Pattern

+

Share your pattern

+

If you merely want to share your pattern with others, you can copy these URLs:

+
+ + Pattern and Measurements + + + Pattern only + +
+
+ + Explain these buttons + +
+
Pattern and Measurements
+

+ Use the Pattern and Measurements URL to share this pattern exactly as-is, + including the measurements used to generate it: +

+ + {urls.a} + +
+ + Use this to allow others to troubleshoot your pattern. +
+
Pattern only
+

+ Use the Pattern only to share this pattern as-is, but without measurements: +

+ + {urls.b} + +
+ + Use this to allow others to recreate this pattern for themselves. +
+
+
+

Export for printing

+

You can export your pattern in a variety of page formats for printing:

+
+
+

ISO paper sizes

+ {['a4', 'a3', 'a2', 'a1', 'a0'].map((format) => ( + + ))} +
+
+

Other paper sizes

+ {['letter', 'legal', 'tabloid'].map((format) => ( + + ))} +
+
+

Export for editing

+

+ We recommend SVG for editing, but we also provide a full-sized PDF if you prefer that. +

+
+ {['svg', 'pdf'].map((format) => ( + + ))} +
+

Export as code

+

This is all you need to reconstruct this pattern using FreeSewing' software:

+
+ {['json', 'yaml'].map((format) => ( + + ))} +
+
+ + ) +} + +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), + }) +} diff --git a/packages/react/components/Editor/components/views/index.mjs b/packages/react/components/Editor/components/views/index.mjs index 2e7f801ea87..dea155d0300 100644 --- a/packages/react/components/Editor/components/views/index.mjs +++ b/packages/react/components/Editor/components/views/index.mjs @@ -4,6 +4,7 @@ import { DesignsView } from './DesignsView.mjs' import { MeasurementsView } from './MeasurementsView.mjs' import { DraftView } from './DraftView.mjs' import { SaveView } from './SaveView.mjs' +import { ExportView } from './ExportView.mjs' import { ErrorIcon } from '@freesewing/react/components/Icon' import { OptionsIcon, @@ -53,6 +54,7 @@ export const View = (props) => { if (view === 'measurements') return if (view === 'draft') return if (view === 'save') return + if (view === 'export') return /* viewComponents: { draft: 'DraftView', diff --git a/packages/react/components/Highlight/index.mjs b/packages/react/components/Highlight/index.mjs index 8085256e337..ef1362cc4f3 100644 --- a/packages/react/components/Highlight/index.mjs +++ b/packages/react/components/Highlight/index.mjs @@ -18,6 +18,7 @@ const defaultTitles = { * @params {bool} raw - Set this to true to not escape tags * @params {string} title - Title for the highlight * @params {string} copy - Content to copy to clipboard + * @params {bool} noCopy - Do not add copy to clipboard */ export const Highlight = ({ language = 'txt', @@ -25,6 +26,7 @@ export const Highlight = ({ raw = false, title = false, copy = false, + noCopy = false, }) => { if (children?.props?.className) { language = children.props.className.split('-').pop() @@ -46,7 +48,7 @@ export const Highlight = ({ `} > {label} - + {noCopy ? null : }
{children}
diff --git a/packages/react/components/Icon/index.mjs b/packages/react/components/Icon/index.mjs index c22a00f997f..c15e838b676 100644 --- a/packages/react/components/Icon/index.mjs +++ b/packages/react/components/Icon/index.mjs @@ -125,6 +125,13 @@ export const CloseIcon = (props) => ( ) +// Looks like coding brackets +export const CodeIcon = (props) => ( + + + +) + // FIXME export const CompareIcon = (props) => ( diff --git a/packages/react/package.json b/packages/react/package.json index ece5ad49b58..b6437391267 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -86,12 +86,12 @@ "html-react-parser": "^5.0.7", "luxon": "^3.5.0", "nuqs": "^1.17.6", + "pdfkit": "^0.16.0", "react-markdown": "^9.0.1", "tlds": "^1.255.0", "use-local-storage-state": "19.1.0", "use-session-storage-state": "^19.0.0" }, - "devDependencies": {}, "files": [ "components/**", "hooks/**", diff --git a/packages/utils/src/index.mjs b/packages/utils/src/index.mjs index 54ed7c13579..9cb7c6f5e81 100644 --- a/packages/utils/src/index.mjs +++ b/packages/utils/src/index.mjs @@ -1,5 +1,6 @@ import tlds from 'tlds/index.json' with { type: 'json' } import { cloudflare as cloudflareConfig } from '@freesewing/config' +import _get from 'lodash/get.js' import _set from 'lodash/set.js' import _unset from 'lodash/unset.js' import _orderBy from 'lodash/orderBy.js' @@ -8,6 +9,7 @@ import { loadingMessages } from './loading-messages.mjs' /* * Re-export lodash utils */ +export const get = _get export const set = _set export const unset = _unset export const orderBy = _orderBy @@ -31,8 +33,7 @@ export const horFlexClassesNoSm = /* * These classes are what makes a link a link */ -export const linkClasses = - 'tw-underline tw-decoration-2 hover:tw-decoration-4 tw-text-secondary hover:tw-text-secondary-focus tw-font-medium' +export const linkClasses = 'tw-text-secondary hover:tw-underline hover:tw-cursor-pointer' /* * FUNCTIONS @@ -48,6 +49,18 @@ export function capitalize(string) { 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 * 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 * @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 */ -export const newPatternUrl = ({ design, settings = {}, view = 'draft' }) => - `/-/#settings=${encodeURIComponent( - JSON.stringify(settings) - )}&view=${encodeURIComponent('"' + view + '"')}` +export const patternUrlFromState = (state = {}, includeMeasurements = false, view = 'draft') => { + // Avoid changing state by accident + const newState = clone(state) + 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 diff --git a/sites/org/tailwind.config.mjs b/sites/org/tailwind.config.mjs index 3c5021d872e..0e0abdb6b59 100644 --- a/sites/org/tailwind.config.mjs +++ b/sites/org/tailwind.config.mjs @@ -10,6 +10,7 @@ export default { '../../packages/react/context/**/*.mjs', '../../packages/react/hooks/**/*.mjs', '../../packages/react/lib/tailwind-force.mjs', + '../../packages/utils/src/*.mjs', './tailwind-force.html', ], plugins: [daisyui],