diff --git a/packages/core/src/svg.js b/packages/core/src/svg.js index b62c650343d..69f07f0b1d1 100644 --- a/packages/core/src/svg.js +++ b/packages/core/src/svg.js @@ -50,6 +50,7 @@ Svg.prototype.insertText = function (text) { Svg.prototype.render = function (pattern) { this.idPrefix = pattern.settings.idPrefix this.runHooks('preRender') + pattern.runHooks('postLayout') if (!pattern.settings.embed) { this.attributes.add('width', round(pattern.width) + 'mm') this.attributes.add('height', round(pattern.height) + 'mm') diff --git a/plugins/plugin-buttons/src/button.js b/plugins/plugin-buttons/src/button.js index 20adc762cf9..5170f7fd583 100644 --- a/plugins/plugin-buttons/src/button.js +++ b/plugins/plugin-buttons/src/button.js @@ -2,10 +2,10 @@ export default ` - - - - + + + + ` diff --git a/plugins/plugin-buttons/src/buttonhole.js b/plugins/plugin-buttons/src/buttonhole.js index c141dd9e0ee..221214df981 100644 --- a/plugins/plugin-buttons/src/buttonhole.js +++ b/plugins/plugin-buttons/src/buttonhole.js @@ -1,19 +1,19 @@ export default ` ` diff --git a/plugins/plugin-cutonfold/src/lib/markers.js b/plugins/plugin-cutonfold/src/lib/markers.js index 2cda96a8676..b60f1aed59f 100644 --- a/plugins/plugin-cutonfold/src/lib/markers.js +++ b/plugins/plugin-cutonfold/src/lib/markers.js @@ -1,8 +1,9 @@ +// FIXME identical arrow paths for dimensions, cutonfold, and grainline export default ` - - + + - - + + `; diff --git a/plugins/plugin-dimension/src/lib/markers.js b/plugins/plugin-dimension/src/lib/markers.js index c445f7f085f..d04ddc42dd9 100644 --- a/plugins/plugin-dimension/src/lib/markers.js +++ b/plugins/plugin-dimension/src/lib/markers.js @@ -1,4 +1,9 @@ +// FIXME identical arrow paths for dimensions, cutonfold, and grainline export default ` - - + + + + + + `; diff --git a/plugins/plugin-grainline/src/markers.js b/plugins/plugin-grainline/src/markers.js index 28b09edb603..2dc576b2e84 100644 --- a/plugins/plugin-grainline/src/markers.js +++ b/plugins/plugin-grainline/src/markers.js @@ -1,8 +1,9 @@ +// FIXME identical arrow paths for dimensions, cutonfold, and grainline export default ` - - + + - - + + ` diff --git a/plugins/plugin-theme/src/index.js b/plugins/plugin-theme/src/index.js index 36a7a534048..00be62a346a 100644 --- a/plugins/plugin-theme/src/index.js +++ b/plugins/plugin-theme/src/index.js @@ -9,12 +9,12 @@ export default { name: pkg.name, version: pkg.version, hooks: { - preRender: function (svg) { + preRender: function (svg, data = {}) { if (svg.attributes.get('freesewing:plugin-theme') === false) { svg.attributes.set('class', 'freesewing') svg.style += sample svg.style += paperless - svg.style += draft(svg.pattern.settings.scale) + svg.style += draft(svg.pattern.settings.scale, data.stripped) if (svg.pattern.settings.paperless) { svg.pattern.settings.units === 'imperial' ? (svg.defs += gridImperial) diff --git a/plugins/plugin-theme/src/lib/draft.js b/plugins/plugin-theme/src/lib/draft.js index b96d7b6d8c4..5975a98cfd2 100644 --- a/plugins/plugin-theme/src/lib/draft.js +++ b/plugins/plugin-theme/src/lib/draft.js @@ -1,17 +1,30 @@ +// FIXME surely this can be extracted from the theme in some way so as to keep things consistent? + const round = value => Math.round(value * 1e2) / 1e2 -export default (scale) => ` - /* Reset */ - svg.freesewing path, - svg.freesewing circle, - svg.freesewing rect { +const colors = { + fabric: '#212121', + lining: '#10b981', + interfacing: '#a3a3a3', + canvas: '#d97706', + various: '#ef4444', + note: '#8b5cf6', + mark: '#3b82f6', + contrast: '#ec4899' +} + +export default (scale, stripped) => ` + ${!stripped ? '/* Reset */' : ''} + ${!stripped ? 'svg.freesewing ' : ''}path, + ${!stripped ? 'svg.freesewing ' : ''}circle, + ${!stripped ? 'svg.freesewing ' : ''}rect { fill: none; stroke: none; } - /* Defaults */ - svg.freesewing path, - svg.freesewing circle { + ${!stripped ? '/* Defaults */' : ''} + ${!stripped ? 'svg.freesewing ' : ''}path, + ${!stripped ? 'svg.freesewing ' : ''}circle { stroke: #000; stroke-opacity: 1; stroke-width: ${round(0.3*scale)}; @@ -19,111 +32,118 @@ export default (scale) => ` stroke-linejoin: round; } - /* Stroke classes */ - svg.freesewing .fabric { + ${!stripped ? '/* Stroke classes */' : ''} + ${!stripped ? 'svg.freesewing ' : ''}.fabric { stroke-width: ${round(0.6*scale)}; - stroke: #212121; + stroke: ${colors.fabric}; } - svg.freesewing .lining { + ${!stripped ? 'svg.freesewing ' : ''}.lining { stroke-width: ${round(0.6*scale)}; - stroke: #ff5b77; + stroke: ${colors.lining}; } - svg.freesewing .interfacing { + ${!stripped ? 'svg.freesewing ' : ''}.interfacing { stroke-width: ${round(0.6*scale)}; - stroke: #64b5f6; + stroke: ${colors.interfacing}; } - svg.freesewing .canvas { + ${!stripped ? 'svg.freesewing ' : ''}.canvas { stroke-width: ${round(0.6*scale)}; - stroke: #ff9000; + stroke: ${colors.canvas}; } - svg.freesewing .various { + ${!stripped ? 'svg.freesewing ' : ''}.various { stroke-width: ${round(0.6*scale)}; - stroke: #4caf50; + stroke: ${colors.various}; } - svg.freesewing .note { + ${!stripped ? 'svg.freesewing ' : ''}.note { stroke-width: ${round(0.4*scale)}; - stroke: #dd60dd; + stroke: ${colors.note}; } - svg.freesewing .mark { + ${!stripped ? 'svg.freesewing ' : ''}.mark { stroke-width: ${round(0.4*scale)}; - stroke: blue; + stroke: ${colors.mark}; } - svg.freesewing .contrast { + ${!stripped ? 'svg.freesewing ' : ''}.contrast { stroke-width: ${round(0.8*scale)}; - stroke: red; + stroke: ${colors.contrast}; } - svg.freesewing .stroke-xs { + + ${!stripped ? 'svg.freesewing ' : ''}.stroke-xs { stroke-width: ${round(0.1*scale)}; } - svg.freesewing .stroke-sm { + ${!stripped ? 'svg.freesewing ' : ''}.stroke-sm { stroke-width: ${round(0.2*scale)}; } - svg.freesewing .stroke-lg { + ${!stripped ? 'svg.freesewing ' : ''}.stroke-lg { stroke-width: ${round(0.6*scale)}; } - svg.freesewing .stroke-xl { + ${!stripped ? 'svg.freesewing ' : ''}.stroke-xl { stroke-width: ${round(1*scale)}; } - svg.freesewing .stroke-xxl, - svg.freesewing .stroke-2xl { + ${!stripped ? 'svg.freesewing ' : ''}.stroke-xxl, + ${!stripped ? 'svg.freesewing ' : ''}.stroke-2xl { stroke-width: ${round(2*scale)}; } - svg.freesewing .stroke-3xl { + ${!stripped ? 'svg.freesewing ' : ''}.stroke-3xl { stroke-width: ${round(3*scale)}; } - svg.freesewing .stroke-4xl { + ${!stripped ? 'svg.freesewing ' : ''}.stroke-4xl { stroke-width: ${round(4*scale)}; } - svg.freesewing .sa { + ${!stripped ? 'svg.freesewing ' : ''}.sa { stroke-dasharray: 0.4, 0.8; } - svg.freesewing .help { + ${!stripped ? 'svg.freesewing ' : ''}.help { stroke-width: ${round(0.2*scale)}; stroke-dasharray: 15, 1.5, 1, 1.5; } - svg.freesewing .dotted { + ${!stripped ? 'svg.freesewing ' : ''}.dotted { stroke-dasharray: 0.4, 0.8; } - svg.freesewing .dashed { + ${!stripped ? 'svg.freesewing ' : ''}.dashed { stroke-dasharray: 1, 1.5; } - svg.freesewing .lashed { + ${!stripped ? 'svg.freesewing ' : ''}.lashed { stroke-dasharray: 6, 6; } - svg.freesewing .hidden { + ${!stripped ? 'svg.freesewing ' : ''}.hidden { stroke: none; fill: none; } - - /* Fill classes */ - svg.freesewing .fill-fabric { - fill: #212121; - } - svg.freesewing .fill-lining { - fill: #ff5b77; - } - svg.freesewing .fill-interfacing { - fill: #64b5f6; - } - svg.freesewing .fill-canvas { - fill: #ff9000; - } - svg.freesewing .fill-various { - fill: #4caf50; - } - svg.freesewing .fill-note { - fill: #dd69dd; - } - svg.freesewing .fill-mark { - fill: blue; - } - svg.freesewing .fill-contrast { - fill: red; + ${!stripped ? 'svg.freesewing ' : ''}.no-stroke { stroke: none !important; } + ${!stripped ? 'svg.freesewing ' : ''}.no-fill { fill: none !important; } + ${!stripped ? 'svg.freesewing ' : ''}.muted { + stroke-opacity: 0.15; + fill-opacity: 0.15; } - /* Text */ - svg.freesewing text { + ${!stripped ? '/* Fill classes */' : ''} + ${!stripped ? 'svg.freesewing ' : ''}.fill-fabric { + fill: ${colors.fabric}; + } + ${!stripped ? 'svg.freesewing ' : ''}.fill-lining { + fill: ${colors.lining}; + } + ${!stripped ? 'svg.freesewing ' : ''}.fill-interfacing { + fill: ${colors.interfacing}; + } + ${!stripped ? 'svg.freesewing ' : ''}.fill-canvas { + fill: ${colors.canvas}; + } + ${!stripped ? 'svg.freesewing ' : ''}.fill-various { + fill: ${colors.various}; + } + ${!stripped ? 'svg.freesewing ' : ''}.fill-note { + fill: ${colors.note}; + } + ${!stripped ? 'svg.freesewing ' : ''}.fill-mark { + fill: ${colors.mark}; + } + ${!stripped ? 'svg.freesewing ' : ''}.fill-contrast { + fill: ${colors.contrast}; + } + + ${!stripped ? '/* Text */' : ''} + ${!stripped ? 'svg.freesewing ' : ''}text { font-size: ${round(5*scale)}px; font-family: -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; @@ -132,31 +152,39 @@ export default (scale) => ` font-weight: 200; dominant-baseline: ideographic; } - svg.freesewing .text-xs { + ${!stripped ? 'svg.freesewing ' : ''}.text-xs { font-size: ${round(3*scale)}px; } - svg.freesewing .text-sm { + ${!stripped ? 'svg.freesewing ' : ''}.text-sm { font-size: ${round(4*scale)}px; } - svg.freesewing .text-lg { + ${!stripped ? 'svg.freesewing ' : ''}.text-lg { font-size: ${round(7*scale)}px; } - svg.freesewing .text-xl { + ${!stripped ? 'svg.freesewing ' : ''}.text-xl { font-size: ${round(9*scale)}px; } - svg.freesewing .text-xxl { + ${!stripped ? 'svg.freesewing ' : ''}.text-xxl { font-size: ${round(12*scale)}px; } + ${!stripped ? 'svg.freesewing ' : ''}.text-4xl { + font-size: ${round(36*scale)}px; + } - svg.freesewing .center { + ${!stripped ? 'svg.freesewing ' : ''}.center { text-anchor: middle; } - svg.freesewing .right { + ${!stripped ? 'svg.freesewing ' : ''}.baseline-center { + alignment-baseline: central; + dominant-baseline: central; + } + + ${!stripped ? 'svg.freesewing ' : ''}.right { text-anchor: end; } - /* Bartack */ - svg.freesewing path.bartack { + ${!stripped ? '/* Bartack */' : ''} + ${!stripped ? 'svg.freesewing ' : ''}path.bartack { stroke-width: ${round(2*scale)}; stroke: #fd7e14; stroke-linecap: butt; diff --git a/plugins/plugin-title/src/index.js b/plugins/plugin-title/src/index.js index 0c73810edea..38e01fbc541 100644 --- a/plugins/plugin-title/src/index.js +++ b/plugins/plugin-title/src/index.js @@ -92,14 +92,6 @@ export default { .attr('data-text-class', 'fill-current font-bold') .attr('data-text-transform', transform(so.at.shift(-90 - so.rotation, shift * so.scale))) } - shift += 6 - const dateformat = require('dateformat') - const now = new Date() - this.points[`_${prefix}_exportDate`] = so.at - .shift(-90 - so.rotation, shift * so.scale) - .attr('data-text', dateformat(now, 'yyyymmdd"T"HHMMo')) - .attr('data-text-class', 'text-sm') - .attr('data-text-transform', transform(so.at.shift(-90 - so.rotation, shift * so.scale))) }, }, } diff --git a/sites/shared/components/workbench/exporting/exporter.js b/sites/shared/components/workbench/exporting/exporter.js new file mode 100644 index 00000000000..94dc32796e8 --- /dev/null +++ b/sites/shared/components/workbench/exporting/exporter.js @@ -0,0 +1,122 @@ +import {sizes} from '../layout/print/plugin' +import PDFDocument from 'pdfkit/js/pdfkit.standalone' +import SVGtoPDF from 'svg-to-pdfkit' +import fileSaver from 'file-saver' + +const pointsPerPx = (72/96); +const pxPerMm = 3.77953 +const pointsPerMm = pxPerMm * pointsPerPx + +export default class Exporter { + designName + svg + settings + + pdf + pageWidth + pageHeight + margin + wPages + hPages + svgWidth + svgHeight + + + constructor(designName, pattern, svg, settings) { + this.designName = designName || 'freesewing' + this.settings = settings + this.createPdf() + + this.pageHeight = this.pdf.page.height + this.pageWidth = this.pdf.page.width + this.margin = this.settings.margin * pointsPerMm + + let marginInMm = this.settings.margin + let pageWidthInPx = this.pageWidth / pointsPerMm - marginInMm + let pageHeightInPx = this.pageHeight / pointsPerMm - marginInMm + + const divElem = document.createElement('div'); + divElem.innerHTML = svg; + this.svg = divElem.firstElementChild; + + this.svgWidth = this.svg.width.baseVal.valueInSpecifiedUnits + this.svgHeight = this.svg.height.baseVal.valueInSpecifiedUnits + + this.wPages = Math.ceil(this.svgWidth/pageWidthInPx) + this.hPages = Math.ceil(this.svgHeight/pageHeightInPx) + + this.svgWidth = this.wPages * (this.pageWidth - this.margin) + this.svgHeight = this.hPages * (this.pageHeight - this.margin) + + this.svg.setAttribute('height', this.svgWidth + 'pt') + this.svg.setAttribute('width', this.svgHeight + 'pt') + this.svg.setAttribute('viewBox', `0 0 ${this.wPages * pageWidthInPx} ${this.hPages * pageHeightInPx}`) + } + + createPdf() { + this.pdf = new PDFDocument({ + size: this.settings.format, + layout: this.settings.orientation + }) + + const buffers = []; + this.pdf.on('data', buffers.push.bind(buffers)); + this.pdf.on('end', () => { + const blob = new Blob(buffers, { + type: 'application/pdf' + }) + fileSaver.saveAs(blob, `freesewing-${this.designName}.pdf`) + }); + } + + async export() { + await this.generateCoverPage() + await this.generatePages(); + this.save() + } + + async generateCoverPage() { + if (!this.settings.coverPage) { + return + } + + let coverMargin = 100 + + let coverHeight = this.pageHeight - coverMargin * 2 + let coverWidth = this.pageWidth - coverMargin * 2 + + await SVGtoPDF(this.pdf, this.svg.outerHTML, coverMargin, coverMargin, { + width: coverWidth, + height: coverHeight, + assumePt: true, + preserveAspectRatio: 'xMidYMid meet' + }); + } + + async generatePages() { + const options = { + assumePt: true, + width: this.svgWidth, + height: this.svgHeight, + preserveAspectRatio: 'xMinYMin slice' + } + + for (var h = 0; h < this.hPages; h++) { + for (var w = 0; w < this.wPages; w++) { + // if there was no cover page, the first page already exists + if (this.settings.coverPage || h+w > 0) { + this.pdf.addPage() + } + + let x = -w * this.pageWidth + (0.5 + w) * this.margin + let y = -h * this.pageHeight + (0.5 + h) * this.margin + + await SVGtoPDF(this.pdf, this.svg.outerHTML, x, y, options) + } + } + } + + save() { + this.pdf.end(); + } +} diff --git a/sites/shared/components/workbench/exporting/index.js b/sites/shared/components/workbench/exporting/index.js new file mode 100644 index 00000000000..79030796b56 --- /dev/null +++ b/sites/shared/components/workbench/exporting/index.js @@ -0,0 +1,141 @@ +import { useState} from 'react' +import { useTranslation } from 'next-i18next' +import fileSaver from 'file-saver' +import yaml from 'js-yaml' +import axios from 'axios' +import Popout from 'shared/components/popout' +import WebLink from 'shared/components/web-link' +import theme from '@freesewing/plugin-theme' +import {pagesPlugin} from '../layout/print/plugin' +import PdfExporter from './exporter' + +export const exports = { + exportForPrinting: ['a4', 'a3', 'a2', 'a1', 'a0', 'letter', 'tabloid'], + exportForEditing: ['svg', 'pdf'], + exportAsData: ['json', 'yaml', 'github gist'], +} + +export const defaultPdfSettings = { + format: 'a4', + orientation: 'portrait', + margin: 10, + coverPage: true +} + +export const handleExport = (format, gist, design, t, app, setLink, setFormat) => { + + setLink && setLink(false) + setFormat && setFormat(format) + if (exports.exportAsData.indexOf(format) !== -1) { + if (format === 'json') exportJson(gist) + else if (format === 'yaml') exportYaml(gist) + else if (format === 'github gist') exportGithubGist(gist, app, setLink) + + return + } + + gist.embed=false + let svg = '' + const layout = gist.layouts?.printingLayout || gist.layout || true + let pattern = new design({...gist, layout}) + pattern.use(theme, {stripped: format !== 'svg'}) + pattern.use({ + hooks: { + insertText: (locale, text, {t}) => t(text) + } + },{t}) + + const settings = { + ...defaultPdfSettings, + ...(gist._state.layout?.forPrinting?.page || {}) + } + + if (format !== 'pdf') { + settings.format = format + } + + try { + if (format !== 'svg') { + pattern.use(pagesPlugin(settings.format, settings.orientation, settings.margin, true)) + } + + pattern.draft(); + svg = pattern.render() + + } catch(err) { + console.log(err) + } + + if (format === 'svg') return exportSvg(gist, svg) + + return new PdfExporter(gist.design, pattern, svg, settings).export(); +} + +const exportJson = gist => { + const blob = new Blob([JSON.stringify(gist, null, 2)], { + type: 'application/json;charset=utf-8' + }) + fileSaver.saveAs(blob, `freesewing-${gist.design || 'gist'}.json`) +} +const exportYaml = gist => { + const blob = new Blob([yaml.dump(gist)], { + type: 'application/x-yaml;charset=utf-8' + }) + fileSaver.saveAs(blob, `freesewing-${gist.design || 'gist'}.yaml`) +} +const exportSvg = (gist, svg) => { + const blob = new Blob([svg], { + type: 'image/svg+xml;charset=utf-8' + }) + fileSaver.saveAs(blob, `freesewing-${gist.design || 'pattern'}.svg`) +} +const exportGithubGist = (data, app, setLink) => { + app.setLoading(true) + axios.post('https://backend.freesewing.org/github/gist', { + design: data.design, + data: yaml.dump(data) + }) + .then(res => setLink('https://gist.github.com/' + res.data.id)) + .catch(err => console.log(err)) + .finally(() => app.stopLoading()) +} + +const ExportDraft = ({ gist, design, app }) => { + + const [link, setLink] = useState(false) + const [format, setFormat] = useState(false) + + const { t } = useTranslation(['app']) + + return ( +
+

{t('export')}

+

{t('exportPattern-txt')}

+ {link && ( + + + {format}: + + + + )} +
+ {Object.keys(exports).map(type => ( +
+

{t(type)}

+ {exports[type].map(format => ( + + ))} +
+ ))} +
+
+ ) +} + +export default ExportDraft diff --git a/sites/shared/components/workbench/layout/print/index.js b/sites/shared/components/workbench/layout/print/index.js index 1fff481809e..a33fa7f9cb8 100644 --- a/sites/shared/components/workbench/layout/print/index.js +++ b/sites/shared/components/workbench/layout/print/index.js @@ -2,7 +2,8 @@ import { useEffect } from 'react' import { useTranslation } from 'next-i18next' import Settings from './settings' import Draft from '../draft/index' -import pluginBuilder from './plugin' +import {pagesPlugin} from './plugin' +import {handleExport, defaultPdfSettings} from 'shared/components/workbench/exporting' const PrintLayout = props => { // disable xray @@ -15,11 +16,14 @@ const PrintLayout = props => { const { t } = useTranslation(['workbench']) + const layoutSettings = props.gist?._state?.layout?.forPrinting?.page || defaultPdfSettings + const draft = props.draft // add the pages plugin to the draft - draft.use(pluginBuilder( - props.gist?._state?.layout?.forPrinting?.page?.size, - props.gist?._state?.layout?.forPrinting?.page?.orientation, + draft.use(pagesPlugin( + layoutSettings.size, + layoutSettings.orientation, + layoutSettings.margin )) let patternProps @@ -32,6 +36,10 @@ const PrintLayout = props => { } const bgProps = { fill: "url(#page)" } + const exportIt = () => { + handleExport('pdf', props.gist, props.design, t) + } + return (

@@ -42,7 +50,7 @@ const PrintLayout = props => { }

- +
({ +export const pagesPlugin = (size='a4', orientation='portrait', margin =10, outlineStyle = true ) => { + let [sheetWidth, sheetHeight] = sizes[size]; + sheetWidth -= margin + sheetHeight -= margin + return basePlugin({sheetWidth, sheetHeight, orientation, outlineStyle}) +} + +export const cutFabricPlugin = (sheetWidth, sheetHeight) => basePlugin({sheetWidth, sheetHeight, boundary: true, partName: "cutFabric", responsiveWidth: false}) + +const basePlugin = ({sheetWidth, sheetHeight, orientation='portrait', boundary=false, partName="pages", responsiveWidth=true, outlineStyle=false}) => ({ name, version, hooks: { postLayout: function(pattern) { // Add part - pattern.parts.pages = pattern.Part('pages') + pattern.parts[partName] = pattern.Part(partName) // Keep part out of layout - pattern.parts.pages.layout = false + pattern.parts[partName].layout = false // But add the part to the autoLayout property - pattern.autoLayout.parts.pages = { + pattern.autoLayout.parts[partName] = { move: { x: 0, y: 0 } } // Add pages - const { macro } = pattern.parts.pages.shorthand() - const { height, width } = pattern - macro('addPages', { size, orientation, height, width }) + const { macro } = pattern.parts[partName].shorthand() + let { height, width } = pattern + if (!responsiveWidth) width = sheetWidth; + macro('addPages', { size: [sheetWidth, sheetHeight], orientation, height, width }) + + if (boundary) pattern.parts[partName].boundary(); } }, macros: { addPages: function(so) { const ls = so.orientation === 'landscape' - const w = sizes[so.size][ls ? 1 : 0] - const h = sizes[so.size][ls ? 0 : 1] + const w = so.size[ls ? 1 : 0] + const h = so.size[ls ? 0 : 1] const cols = Math.ceil(so.width / w) const rows = Math.ceil(so.height / h) - const { points, Point, paths, Path } = this.shorthand() + const { points, Point, paths, Path, macro } = this.shorthand() let x = 0 let y = 0 let count = 0 @@ -44,25 +56,38 @@ const pagesPlugin = (size='a4', orientation='portrait') => ({ x=0 for (let col=0;col ({ // Store page count in part this.pages = { cols, rows, count: cols*rows } + }, + addRuler({xAxis, pageName}) { + const { points, Point, paths, Path } = this.shorthand() + const rulerLength = 2 + const isMetric = this.context.settings.units === 'metric' + const endPointDist = [(isMetric ? 10 : 25.4) * rulerLength, 0] + + const axisName = xAxis ? 'x' : 'y' + const endPoint = [endPointDist[xAxis ? 0 : 1], endPointDist[xAxis ? 1 : 0]] + points[`${pageName}-${axisName}-ruler-start`] = points[`${pageName}-tl`].translate(endPoint[0], endPoint[1]) + points[`${pageName}-${axisName}-ruler-end`] = points[`${pageName}-${axisName}-ruler-start`].translate(xAxis ? 0 : 3, xAxis ? 3 : 0) + .attr('data-text', rulerLength + (isMetric ? 'cm' : 'in')) + .attr('data-text-class', xAxis ? 'center baseline-center' : 'baseline-center') + .attr(`data-text-d${xAxis ? 'y' : 'x'}`, xAxis ? 5 : 3) + paths[`${pageName}-${axisName}-ruler`] = new Path() + .move(points[`${pageName}-tl`]) + + const division = (isMetric ? 0.1 : 0.125) / rulerLength + for (var d = division; d < 1; d+= division) { + points[`${pageName}-${axisName}-ruler-${d}-start`] = points[`${pageName}-tl`].shiftFractionTowards(points[`${pageName}-${axisName}-ruler-start`], d) + + let tick = 1; + if (d.toFixed(3) % (1/rulerLength) === 0) tick = 3 + else if (d.toFixed(3) % (0.5/rulerLength) === 0) tick = 2 + + points[`${pageName}-${axisName}-ruler-${d}-end`] = points[`${pageName}-${axisName}-ruler-${d}-start`].translate(xAxis ? 0 : tick, xAxis ? tick : 0) + + paths[`${pageName}-${axisName}-ruler`] + .line(points[`${pageName}-${axisName}-ruler-${d}-start`]) + .line(points[`${pageName}-${axisName}-ruler-${d}-end`]) + .line(points[`${pageName}-${axisName}-ruler-${d}-start`]) + } + + paths[`${pageName}-${axisName}-ruler`] + .line(points[`${pageName}-${axisName}-ruler-start`]) + .line(points[`${pageName}-${axisName}-ruler-end`]) + .attr('class', 'interfacing stroke-xs') + }, + addPageMarkers({row, col, pageName}) { + const {macro, points} = this.shorthand() + if (row !== 0) macro('addPageMarker', { + along: [points[`${pageName}-tl`], points[`${pageName}-tr`]], + label: '' + row, + isRow: true, + pageName + }) + if (col !== 0) macro('addPageMarker', { + along: [points[`${pageName}-tl`], points[`${pageName}-bl`]], + label: String.fromCharCode('A'.charCodeAt(0) + col - 1), + isRow: false, + pageName + }) + }, + addPageMarker({along, label, isRow, pageName}) { + const {points, paths, Point, Path} = this.shorthand() + const markerName = `${pageName}-${isRow ? 'row' : 'col'}-marker` + points[`${markerName}-center`] = along[0].shiftFractionTowards(along[1], 0.5) + .attr('data-text', label) + .attr('data-text-class', 'text-sm center baseline-center bold') + points[`${markerName}-r`] = points[`${markerName}-center`].translate(-5, 0) + points[`${markerName}-l`] = points[`${markerName}-center`].translate(5, 0) + points[`${markerName}-t`] = points[`${markerName}-center`].translate(0, -5) + points[`${markerName}-b`] = points[`${markerName}-center`].translate(0, 5) + + paths[markerName] = new Path() + .move(points[`${markerName}-r`]) + .line(points[`${markerName}-t`]) + .line(points[`${markerName}-l`]) + .line(points[`${markerName}-b`]) + .close() + .attr('class', 'fill-interfacing interfacing') } } }) - -export default pagesPlugin diff --git a/sites/shared/components/workbench/layout/print/settings.js b/sites/shared/components/workbench/layout/print/settings.js index 9fe7a6cc7a4..d2db3307218 100644 --- a/sites/shared/components/workbench/layout/print/settings.js +++ b/sites/shared/components/workbench/layout/print/settings.js @@ -3,6 +3,7 @@ import OrientationPicker from './orientation-picker' import PrintIcon from 'shared/components/icons/print' import RightIcon from 'shared/components/icons/right' import ClearIcon from 'shared/components/icons/clear' +import ExportIcon from 'shared/components/icons/export' import { useTranslation } from 'next-i18next' const PrintLayoutSettings = props => { @@ -10,28 +11,68 @@ const PrintLayoutSettings = props => { const { cols, rows, count } = props.draft.parts.pages.pages const { t } = useTranslation(['workbench']) + const setMargin = (evt) => { + props.updateGist(['_state', 'layout', 'forPrinting', 'page', 'margin'], parseInt(evt.target.value)) + } + + const margin = props.gist._state?.layout?.forPrinting?.page?.margin || 10 + + return ( -
- - -
- - {count} - | - - {cols} - | -
- {rows} +
+
+
+ + +
+
+ + +
+
+
+ +
+ + {count} + | + + {cols} + | +
+ {rows} +
-
) } diff --git a/sites/shared/components/wrappers/workbench.js b/sites/shared/components/wrappers/workbench.js index 09b99220c68..16382e9e2be 100644 --- a/sites/shared/components/wrappers/workbench.js +++ b/sites/shared/components/wrappers/workbench.js @@ -11,7 +11,7 @@ import Modal from 'shared/components/modal' import Measurements from 'shared/components/workbench/measurements/index.js' import LabDraft from 'shared/components/workbench/draft/index.js' import LabSample from 'shared/components/workbench/sample.js' -import ExportDraft from 'shared/components/workbench/export.js' +import ExportDraft from 'shared/components/workbench/exporting/index.js' import GistAsJson from 'shared/components/workbench/json.js' import GistAsYaml from 'shared/components/workbench/yaml.js' import DraftEvents from 'shared/components/workbench/events.js' diff --git a/sites/shared/package.json b/sites/shared/package.json index 9d998732d34..5d49d444bc2 100644 --- a/sites/shared/package.json +++ b/sites/shared/package.json @@ -27,6 +27,7 @@ "lodash.orderby": "^4.6.0", "lodash.unset": "^4.5.2", "mdast-util-toc": "^6.1.0", + "pdfkit": "^0.13.0", "react-markdown": "^8.0.0", "react-sizeme": "^3.0.2", "react-timeago": "^7.1.0", @@ -36,6 +37,7 @@ "remark-extract-frontmatter": "^3.2.0", "remark-frontmatter": "^4.0.1", "remark-smartypants": "^2.0.0", + "svg-to-pdfkit": "^0.1.8", "to-vfile": "^7.2.2", "unist-util-visit": "^4.1.0" }, diff --git a/yarn.lock b/yarn.lock index 455eec087cb..7126618a43a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3828,6 +3828,13 @@ dependencies: tslib "^2.4.0" +"@swc/helpers@^0.3.13": + version "0.3.17" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.3.17.tgz#7c1b91f43c77e2bba99492162a498d465ef253d5" + integrity sha512-tb7Iu+oZ+zWJZ3HJqwx8oNwSDIU440hmVMDPhpACWQWnrZHK99Bxs70gT1L2dnr5Hg50ZRWEFkQCAnOVVV0z1Q== + dependencies: + tslib "^2.4.0" + "@szmarczak/http-timer@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" @@ -5447,6 +5454,11 @@ ava@^4.0.1: write-file-atomic "^4.0.1" yargs "^17.5.1" +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -5618,7 +5630,12 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base64-js@^1.0.2, base64-js@^1.3.1: +base64-js@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978" + integrity sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw== + +base64-js@^1.0.2, base64-js@^1.1.2, base64-js@^1.3.0, base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -5933,6 +5950,13 @@ brorand@^1.0.1, brorand@^1.1.0: resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== +brotli@^1.3.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/brotli/-/brotli-1.3.3.tgz#7365d8cc00f12cf765d2b2c898716bcf4b604d48" + integrity sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg== + dependencies: + base64-js "^1.1.2" + browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" @@ -6892,6 +6916,11 @@ clone@^1.0.2: resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== +clone@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== + cls-bluebird@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cls-bluebird/-/cls-bluebird-2.1.0.tgz#37ef1e080a8ffb55c2f4164f536f1919e7968aee" @@ -7707,6 +7736,11 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" +crypto-js@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.1.1.tgz#9e485bcf03521041bd85844786b83fb7619736cf" + integrity sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw== + crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" @@ -8101,6 +8135,27 @@ deep-equal@^1.0.1, deep-equal@^1.1.1: object-keys "^1.1.1" regexp.prototype.flags "^1.2.0" +deep-equal@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.0.5.tgz#55cd2fe326d83f9cbf7261ef0e060b3f724c5cb9" + integrity sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw== + dependencies: + call-bind "^1.0.0" + es-get-iterator "^1.1.1" + get-intrinsic "^1.0.1" + is-arguments "^1.0.4" + is-date-object "^1.0.2" + is-regex "^1.1.1" + isarray "^2.0.5" + object-is "^1.1.4" + object-keys "^1.1.1" + object.assign "^4.1.2" + regexp.prototype.flags "^1.3.0" + side-channel "^1.0.3" + which-boxed-primitive "^1.0.1" + which-collection "^1.0.1" + which-typed-array "^1.1.2" + deep-equal@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" @@ -8419,6 +8474,11 @@ dezalgo@^1.0.0: asap "^2.0.0" wrappy "1" +dfa@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/dfa/-/dfa-1.2.0.tgz#96ac3204e2d29c49ea5b57af8d92c2ae12790657" + integrity sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q== + didyoumean@^1.2.1, didyoumean@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" @@ -8909,7 +8969,7 @@ error-stack-parser@^2.0.0, error-stack-parser@^2.0.2, error-stack-parser@^2.0.3: dependencies: stackframe "^1.3.4" -es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.4, es-abstract@^1.19.5, es-abstract@^1.20.1: +es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.4, es-abstract@^1.19.5, es-abstract@^1.20.0, es-abstract@^1.20.1: version "1.20.1" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814" integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA== @@ -8943,6 +9003,20 @@ es-array-method-boxes-properly@^1.0.0: resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== +es-get-iterator@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.2.tgz#9234c54aba713486d7ebde0220864af5e2b283f7" + integrity sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.0" + has-symbols "^1.0.1" + is-arguments "^1.1.0" + is-map "^2.0.2" + is-set "^2.0.2" + is-string "^1.0.5" + isarray "^2.0.5" + es-module-lexer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.0.1.tgz#8dcd50a141274b31cccfe8501840182a6dced7ac" @@ -10200,6 +10274,28 @@ font-awesome@^4.7.0: resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133" integrity sha512-U6kGnykA/6bFmg1M/oT9EkFeIYv7JlX3bozwQJWiiLz6L0w3F5vBVPxHlwyX/vtNq1ckcpRKOB9f2Qal/VtFpg== +fontkit@^1.8.1: + version "1.9.0" + resolved "https://registry.yarnpkg.com/fontkit/-/fontkit-1.9.0.tgz#95729cc9f24995fb068ea53aea2f1f193e323f2b" + integrity sha512-HkW/8Lrk8jl18kzQHvAw9aTHe1cqsyx5sDnxncx652+CIfhawokEPkeM3BoIC+z/Xv7a0yMr0f3pRRwhGH455g== + dependencies: + "@swc/helpers" "^0.3.13" + brotli "^1.3.2" + clone "^2.1.2" + deep-equal "^2.0.5" + dfa "^1.2.0" + restructure "^2.0.1" + tiny-inflate "^1.0.3" + unicode-properties "^1.3.1" + unicode-trie "^2.0.0" + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -10519,7 +10615,7 @@ get-func-name@^2.0.0: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: +get-intrinsic@^1.0.1, get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598" integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA== @@ -12272,7 +12368,7 @@ is-alphanumerical@^2.0.0: is-alphabetical "^2.0.0" is-decimal "^2.0.0" -is-arguments@^1.0.4: +is-arguments@^1.0.4, is-arguments@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== @@ -12341,7 +12437,7 @@ is-builtin-module@^3.1.0: dependencies: builtin-modules "^3.0.0" -is-callable@^1.1.4, is-callable@^1.2.4: +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== @@ -12386,7 +12482,7 @@ is-data-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" -is-date-object@^1.0.1: +is-date-object@^1.0.1, is-date-object@^1.0.2: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== @@ -12549,6 +12645,11 @@ is-lambda@^1.0.1: resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== +is-map@^2.0.1, is-map@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" + integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== + is-nan@^1.3.0: version "1.3.2" resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" @@ -12710,7 +12811,7 @@ is-reference@^3.0.0: dependencies: "@types/estree" "*" -is-regex@^1.0.4, is-regex@^1.1.0, is-regex@^1.1.4: +is-regex@^1.0.4, is-regex@^1.1.0, is-regex@^1.1.1, is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== @@ -12730,6 +12831,11 @@ is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== +is-set@^2.0.1, is-set@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" + integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== + is-shared-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" @@ -12794,6 +12900,17 @@ is-type-of@^1.0.0: is-class-hotfix "~0.0.6" isstream "~0.1.2" +is-typed-array@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.9.tgz#246d77d2871e7d9f5aeb1d54b9f52c71329ece67" + integrity sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-abstract "^1.20.0" + for-each "^0.3.3" + has-tostringtag "^1.0.0" + is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -12824,6 +12941,11 @@ is-valid-domain@0.0.17: resolved "https://registry.yarnpkg.com/is-valid-domain/-/is-valid-domain-0.0.17.tgz#2cc19d576b4feebcf4ce5edd99dc8f0280e9d058" integrity sha512-w0UWEXyrgPeWWwj9FVT14y4/dSIqWgjDkzxbsGDFpT+QRbyS9HTwwNvGus2IOR/03GzCpeChzSWK9Bo9WlStDA== +is-weakmap@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" + integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== + is-weakref@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" @@ -12831,6 +12953,14 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" +is-weakset@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" + integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -12868,6 +12998,11 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + iserror@0.0.2, iserror@^0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/iserror/-/iserror-0.0.2.tgz#bd53451fe2f668b9f2402c1966787aaa2c7c0bf5" @@ -13786,6 +13921,14 @@ lilconfig@^2.0.5, lilconfig@^2.0.6: resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4" integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg== +linebreak@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/linebreak/-/linebreak-1.1.0.tgz#831cf378d98bced381d8ab118f852bd50d81e46b" + integrity sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ== + dependencies: + base64-js "0.0.8" + unicode-trie "^2.0.0" + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" @@ -17050,7 +17193,7 @@ object-inspect@^1.12.0, object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== -object-is@^1.0.1, object-is@^1.1.2: +object-is@^1.0.1, object-is@^1.1.2, object-is@^1.1.4: version "1.1.5" resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== @@ -17614,6 +17757,11 @@ pacote@^13.0.3, pacote@^13.6.1: ssri "^9.0.0" tar "^6.1.11" +pako@^0.2.5: + version "0.2.9" + resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" + integrity sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA== + pako@~1.0.2, pako@~1.0.5: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" @@ -17959,6 +18107,16 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" +pdfkit@>=0.8.1, pdfkit@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/pdfkit/-/pdfkit-0.13.0.tgz#da4c2becd63a129e3aae448fdaed4ee7be790f8f" + integrity sha512-AW79eHU5eLd2vgRDS9z3bSoi0FA+gYm+100LLosrQQMLUzOBGVOhG7ABcMFpJu7Bpg+MT74XYHi4k9EuU/9EZw== + dependencies: + crypto-js "^4.0.0" + fontkit "^1.8.1" + linebreak "^1.0.2" + png-js "^1.0.0" + pegjs@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/pegjs/-/pegjs-0.10.0.tgz#cf8bafae6eddff4b5a7efb185269eaaf4610ddbd" @@ -18105,6 +18263,11 @@ pluralize@8.0.0, pluralize@^8.0.0: resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== +png-js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/png-js/-/png-js-1.0.0.tgz#e5484f1e8156996e383aceebb3789fd75df1874d" + integrity sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g== + points-on-curve@0.2.0, points-on-curve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/points-on-curve/-/points-on-curve-0.2.0.tgz#7dbb98c43791859434284761330fa893cb81b4d1" @@ -19602,7 +19765,7 @@ regexp-clone@1.0.0, regexp-clone@^1.0.0: resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-1.0.0.tgz#222db967623277056260b992626354a04ce9bf63" integrity sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw== -regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.4.3: +regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.0, regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== @@ -20592,6 +20755,11 @@ restore-cursor@^4.0.0: onetime "^5.1.0" signal-exit "^3.0.2" +restructure@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/restructure/-/restructure-2.0.1.tgz#4199745466cfc9bb9e1647746a4c902b7b0049d1" + integrity sha512-e0dOpjm5DseomnXx2M5lpdZ5zoHqF1+bqdMJUohoYVVQa7cBdnk7fdmeI6byNWP/kiME72EeTiSypTCVnpLiDg== + ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" @@ -21171,7 +21339,7 @@ shimmer@^1.1.0: resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== -side-channel@^1.0.4: +side-channel@^1.0.3, side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== @@ -22615,6 +22783,13 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +svg-to-pdfkit@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/svg-to-pdfkit/-/svg-to-pdfkit-0.1.8.tgz#5921765922044843f0c1a5b25ec1ef8a4a33b8af" + integrity sha512-QItiGZBy5TstGy+q8mjQTMGRlDDOARXLxH+sgVm1n/LYeo0zFcQlcCh8m4zi8QxctrxB9Kue/lStc/RD5iLadQ== + dependencies: + pdfkit ">=0.8.1" + switchback@^2.0.1: version "2.0.5" resolved "https://registry.yarnpkg.com/switchback/-/switchback-2.0.5.tgz#2f50c91118f659c42e03c0f2bdb094f868c45336" @@ -22912,6 +23087,11 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" +tiny-inflate@^1.0.0, tiny-inflate@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-inflate/-/tiny-inflate-1.0.3.tgz#122715494913a1805166aaf7c93467933eea26c4" + integrity sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw== + tiny-invariant@^1.0.2: version "1.2.0" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9" @@ -23394,11 +23574,27 @@ unicode-match-property-value-ecmascript@^2.0.0: resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== +unicode-properties@^1.3.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/unicode-properties/-/unicode-properties-1.4.1.tgz#96a9cffb7e619a0dc7368c28da27e05fc8f9be5f" + integrity sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg== + dependencies: + base64-js "^1.3.0" + unicode-trie "^2.0.0" + unicode-property-aliases-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== +unicode-trie@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-trie/-/unicode-trie-2.0.0.tgz#8fd8845696e2e14a8b67d78fa9e0dd2cad62fec8" + integrity sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ== + dependencies: + pako "^0.2.5" + tiny-inflate "^1.0.0" + unified-args@^10.0.0: version "10.0.0" resolved "https://registry.yarnpkg.com/unified-args/-/unified-args-10.0.0.tgz#95994c5558fea83ff07006cb560fd88cdcf31134" @@ -24377,7 +24573,7 @@ whatwg-url@^8.4.0: tr46 "^2.1.0" webidl-conversions "^6.1.0" -which-boxed-primitive@^1.0.2: +which-boxed-primitive@^1.0.1, which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== @@ -24388,11 +24584,33 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" +which-collection@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" + integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== + dependencies: + is-map "^2.0.1" + is-set "^2.0.1" + is-weakmap "^2.0.1" + is-weakset "^2.0.1" + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== +which-typed-array@^1.1.2: + version "1.1.8" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.8.tgz#0cfd53401a6f334d90ed1125754a42ed663eb01f" + integrity sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-abstract "^1.20.0" + for-each "^0.3.3" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.9" + which@2.0.2, which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"