From 728704d15d0077e5c527ff03abffd078e2e7ca7c Mon Sep 17 00:00:00 2001 From: Wouter van Wageningen Date: Fri, 3 Mar 2023 22:02:57 +0000 Subject: [PATCH] Tweaks --- designs/albert/src/front.mjs | 6 +- designs/albert/src/strap.mjs | 4 +- plugins/plugin-annotations/src/crossbox.mjs | 2 +- plugins/plugin-annotations/src/index.mjs | 8 + plugins/plugin-annotations/src/miniscale.mjs | 104 ++++++ plugins/plugin-annotations/src/pleat.mjs | 2 +- plugins/plugin-annotations/src/scalebox.mjs | 298 ++++++++++++++++++ .../plugin-annotations/src/sewtogether.mjs | 2 +- plugins/plugin-bundle/src/index.mjs | 10 +- 9 files changed, 423 insertions(+), 13 deletions(-) create mode 100644 plugins/plugin-annotations/src/miniscale.mjs create mode 100644 plugins/plugin-annotations/src/scalebox.mjs diff --git a/designs/albert/src/front.mjs b/designs/albert/src/front.mjs index 4be8cede453..c3bf865945a 100644 --- a/designs/albert/src/front.mjs +++ b/designs/albert/src/front.mjs @@ -68,7 +68,7 @@ export const front = { bibLength: { pct: 75, min: 0, max: 90, menu: 'style' }, lengthBonus: { pct: 0, min: -20, max: 25, menu: 'style' }, }, - plugins: [pluginBundle, crossBox], + plugins: pluginBundle, draft: ({ options, measurements, @@ -191,11 +191,11 @@ export const front = { points.scaleboxAnchor = points.pocketLeftBottom.shiftFractionTowards(points.bottomRight, 0.5) macro('scalebox', { at: points.scaleboxAnchor }) - macro('crossBox', { + macro('crossbox', { from: points.topRightHem, to: points.crossBoxTo1, }) - macro('crossBox', { + macro('crossbox', { from: points.topRightBack, to: points.crossBoxTo2, text: 'attachment', diff --git a/designs/albert/src/strap.mjs b/designs/albert/src/strap.mjs index f2dc9b3107e..c4544aa3ef8 100644 --- a/designs/albert/src/strap.mjs +++ b/designs/albert/src/strap.mjs @@ -99,8 +99,8 @@ export const strap = { at: points.title, title: 'Strap', }) - macro('crossBox', { from: points.topLeft, to: points.topMiddleHem }) - macro('crossBox', { from: points.bottomLeftHem, to: points.bottomMiddle }) + macro('crossbox', { from: points.topLeft, to: points.topMiddleHem }) + macro('crossbox', { from: points.bottomLeftHem, to: points.bottomMiddle }) if (sa) { paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa') } diff --git a/plugins/plugin-annotations/src/crossbox.mjs b/plugins/plugin-annotations/src/crossbox.mjs index ddbc7a7e897..a5c8581647d 100644 --- a/plugins/plugin-annotations/src/crossbox.mjs +++ b/plugins/plugin-annotations/src/crossbox.mjs @@ -4,7 +4,7 @@ export const crossbox = { name: 'crossbox', version, macros: { - crossBox: function (so, { points, Point, paths, Path, getId }) { + crossbox: function (so, { points, Point, paths, Path, getId }) { let id = getId() let shiftFraction = 0.1 points[id + '_boxTopLeft'] = so.from.copy() diff --git a/plugins/plugin-annotations/src/index.mjs b/plugins/plugin-annotations/src/index.mjs index 961cb2c3069..f22f0569141 100644 --- a/plugins/plugin-annotations/src/index.mjs +++ b/plugins/plugin-annotations/src/index.mjs @@ -4,6 +4,9 @@ import { crossbox } from './crossbox.mjs' import { cutonfold } from './cutonfold.mjs' import { grainline } from './grainline.mjs' import { logo } from './logo.mjs' +import { scalebox } from './scalebox.mjs' +import { miniscale } from './scalebox.mjs' +// import { miniscale } from './miniscale.mjs' import { notches } from './notches.mjs' import { pleat } from './pleat.mjs' import { sewtogether } from './sewtogether.mjs' @@ -22,6 +25,11 @@ export const pluginCutonfold = cutonfold export const pleatPlugin = pleat export const pluginPleat = pleat +export const scaleboxPlugin = scalebox +export const pluginScalebox = scalebox +export const miniscalePlugin = miniscale +export const pluginMiniscale = miniscale + export const sewtogetherPlugin = sewtogether export const pluginSewtogether = sewtogether diff --git a/plugins/plugin-annotations/src/miniscale.mjs b/plugins/plugin-annotations/src/miniscale.mjs new file mode 100644 index 00000000000..18d1a411c31 --- /dev/null +++ b/plugins/plugin-annotations/src/miniscale.mjs @@ -0,0 +1,104 @@ +import { name, version } from '../data.mjs' + +export const miniscale = { + name: 'miniscale', + version, + macros: { + miniscale(so, { store, points, paths, scale, Point, Path }) { + // Passing `false` will remove the miniscale + if (so === false) { + for (const id of [ + '__miniscaleMetricTopLeft', + '__miniscaleMetricTopRight', + '__miniscaleMetricBottomRight', + '__miniscaleMetricBottomLeft', + '__miniscaleImperialTopLeft', + '__miniscaleImperialTopRight', + '__miniscaleImperialBottomRight', + '__miniscaleImperialBottomLeft', + '__miniscaleMetric', + '__miniscaleImperial', + ]) + delete points[id] + for (const id of ['__miniscaleMetric', '__miniscaleImperial']) delete paths[id] + return true + } + + // Convert scale to a value between 0 and 5, inclusive. + const scaleIndex = Math.ceil(6 * Math.max(0.1, Math.min(1, scale))) - 1 + + console.log({ MSat: so.at }) + + // Metric size in mm / display value and imperial size in mm / display value for each scale index. + const sizes = [ + [10, '1cm', 25.4 * 0.375, '⅜″'], + [13, '1.3cm', 25.4 * 0.5, '½″'], + [16, '1.6cm', 25.4 * 0.625, '⅝″'], + [19, '1.9cm', 25.4 * 0.75, '¾″'], + [22, '2.2cm', 25.4 * 0.875, '⅞″'], + [25, '2.5cm', 25.4 * 1, '1″'], + ] + const m = sizes[scaleIndex][0] / 2 + const i = sizes[scaleIndex][2] / 2 + const metricDisplaySize = sizes[scaleIndex][1] + const imperialDisplaySize = sizes[scaleIndex][3] + // Box points + points.__miniscaleMetricTopLeft = new Point(so.at.x - m, so.at.y - m) + points.__miniscaleMetricTopRight = new Point(so.at.x + m, so.at.y - m) + points.__miniscaleMetricBottomLeft = new Point(so.at.x - m, so.at.y + m) + points.__miniscaleMetricBottomRight = new Point(so.at.x + m, so.at.y + m) + points.__miniscaleImperialTopLeft = new Point(so.at.x - i, so.at.y - i) + points.__miniscaleImperialTopRight = new Point(so.at.x + i, so.at.y - i) + points.__miniscaleImperialBottomLeft = new Point(so.at.x - i, so.at.y + i) + points.__miniscaleImperialBottomRight = new Point(so.at.x + i, so.at.y + i) + // Text anchor points + points.__miniscaleMetric = new Point(so.at.x, so.at.y - 2 * scale) + points.__miniscaleImperial = new Point(so.at.x, so.at.y + 8 * scale) + // Rotation + if (so.rotate) { + so.rotate = Number(so.rotate) + let toRotate = [ + '__miniscaleMetricTopLeft', + '__miniscaleMetricTopRight', + '__miniscaleMetricBottomLeft', + '__miniscaleMetricBottomRight', + '__miniscaleImperialTopLeft', + '__miniscaleImperialTopRight', + '__miniscaleImperialBottomLeft', + '__miniscaleImperialBottomRight', + '__miniscaleMetric', + '__miniscaleImperial', + ] + for (const pid of toRotate) points[pid] = points[pid].rotate(so.rotate, so.at) + for (const pid of toRotate.slice(8)) { + points[pid].attributes.set( + 'data-text-transform', + `rotate(${so.rotate * -1}, ${points[pid].x}, ${points[pid].y})` + ) + } + } + // Paths + paths.__miniscaleImperial = new Path() + .attr('class', 'scalebox imperial fill-current') + .move(points.__miniscaleImperialTopLeft) + .line(points.__miniscaleImperialBottomLeft) + .line(points.__miniscaleImperialBottomRight) + .line(points.__miniscaleImperialTopRight) + .close() + paths.__miniscaleMetric = new Path() + .attr('class', 'scalebox metric fill-bg') + .move(points.__miniscaleMetricTopLeft) + .line(points.__miniscaleMetricBottomLeft) + .line(points.__miniscaleMetricBottomRight) + .line(points.__miniscaleMetricTopRight) + .close() + // Text + points.__miniscaleMetric = points.__miniscaleMetric + .attr('data-text', `${metricDisplaySize} x ${metricDisplaySize}`) + .attr('data-text-class', 'text-xs center') + points.__miniscaleImperial = points.__miniscaleImperial + .attr('data-text', `${imperialDisplaySize} x ${imperialDisplaySize}`) + .attr('data-text-class', 'text-xs center ') + }, + }, +} diff --git a/plugins/plugin-annotations/src/pleat.mjs b/plugins/plugin-annotations/src/pleat.mjs index b96662fbd15..896f7112990 100644 --- a/plugins/plugin-annotations/src/pleat.mjs +++ b/plugins/plugin-annotations/src/pleat.mjs @@ -6,7 +6,7 @@ const markers = ` ` -export const plugin = { +export const pleat = { name, version, hooks: { diff --git a/plugins/plugin-annotations/src/scalebox.mjs b/plugins/plugin-annotations/src/scalebox.mjs new file mode 100644 index 00000000000..0463e72b6b8 --- /dev/null +++ b/plugins/plugin-annotations/src/scalebox.mjs @@ -0,0 +1,298 @@ +import { name, version } from '../data.mjs' + +export const scalebox = { + name: 'scalebox', + version, + macros: { + scalebox(so, { store, points, paths, scale, Point, Path }) { + // Passing `false` will remove the scalebox + if (so === false) { + for (let id of [ + '__scaleboxMetricTopLeft', + '__scaleboxMetricTopRight', + '__scaleboxMetricBottomRight', + '__scaleboxMetricBottomLeft', + '__scaleboxImperialTopLeft', + '__scaleboxImperialTopRight', + '__scaleboxImperialBottomRight', + '__scaleboxImperialBottomLeft', + '__scaleboxLead', + '__scaleboxTitle', + '__scaleboxText', + '__scaleboxLink', + '__scaleboxMetric', + '__scaleboxImperial', + ]) + delete points[id] + for (let id of ['__scaleboxMetric', '__scaleboxImperial']) delete paths[id] + return true + } + + // Convert scale to a value between 0 and 9, inclusive. + const scaleIndex = Math.round(10 * Math.max(0.1, Math.min(1, scale))) - 1 + + // Metric width and height in mm and display width and height for each scale index. + const metricSizes = [ + [10, 5, '1cm', '0.5cm'], + [20, 10, '2cm', '1cm'], + [30, 15, '3cm', '1.5cm'], + [40, 20, '4cm', '2cm'], + [50, 25, '5cm', '2.5cm'], + [60, 30, '6cm', '3cm'], + [70, 35, '7cm', '3.5cm'], + [80, 40, '8cm', '4cm'], + [90, 45, '9cm', '4.5cm'], + [100, 50, '10cm', '5cm'], + ] + + const metricWidth = metricSizes[scaleIndex][0] + const metricHeight = metricSizes[scaleIndex][1] + const metricDisplayWidth = metricSizes[scaleIndex][2] + const metricDisplayHeight = metricSizes[scaleIndex][3] + + console.log({ SBat: so.at }) + + // Imperial width and height in mm and display width and heigth for each scale index. + const imperialSizes = [ + [25.4 * 0.5, 25.4 * 0.25, '½″', '¼″'], + [25.4 * 0.875, 25.4 * 0.5, '⅞″', '½″'], + [25.4 * 1.25, 25.4 * 0.625, '1 ¼″', '⅝″'], + [25.4 * 1.625, 25.4 * 0.875, '1 ⅝″', '⅞″'], + [25.4 * 2, 25.4 * 1, '2″', '1″'], + [25.4 * 2.375, 25.4 * 1.25, '2 ⅜″', '1 ¼″'], + [25.4 * 2.875, 25.4 * 1.5, '2 ⅞″', '1 ½″'], + [25.4 * 3.25, 25.4 * 1.625, '3 ¼″', '1 ⅝″'], + [25.4 * 3.625, 25.4 * 1.875, '3 ⅝″', '1 ⅞″'], + [25.4 * 4, 25.4 * 2, '4″', '2″'], + ] + + const imperialWidth = imperialSizes[scaleIndex][0] + const imperialHeight = imperialSizes[scaleIndex][1] + const imperialDisplayWidth = imperialSizes[scaleIndex][2] + const imperialDisplayHeight = imperialSizes[scaleIndex][3] + + // Box points + points.__scaleboxMetricTopLeft = new Point( + so.at.x - metricWidth / 2, + so.at.y - metricHeight / 2 + ) + points.__scaleboxMetricTopRight = new Point( + so.at.x + metricWidth / 2, + so.at.y - metricHeight / 2 + ) + points.__scaleboxMetricBottomLeft = new Point( + so.at.x - metricWidth / 2, + so.at.y + metricHeight / 2 + ) + points.__scaleboxMetricBottomRight = new Point( + so.at.x + metricWidth / 2, + so.at.y + metricHeight / 2 + ) + points.__scaleboxImperialTopLeft = new Point( + so.at.x - imperialWidth / 2, + so.at.y - imperialHeight / 2 + ) + points.__scaleboxImperialTopRight = new Point( + so.at.x + imperialWidth / 2, + so.at.y - imperialHeight / 2 + ) + points.__scaleboxImperialBottomLeft = new Point( + so.at.x - imperialWidth / 2, + so.at.y + imperialHeight / 2 + ) + points.__scaleboxImperialBottomRight = new Point( + so.at.x + imperialWidth / 2, + so.at.y + imperialHeight / 2 + ) + // Text anchor points + points.__scaleboxLead = new Point(so.at.x - 45 * scale, so.at.y - 15 * scale) + points.__scaleboxTitle = points.__scaleboxLead.shift(-90, 10 * scale) + points.__scaleboxText = points.__scaleboxTitle.shift(-90, 12 * scale) + points.__scaleboxLink = points.__scaleboxText.shift(-90, 5 * scale) + points.__scaleboxMetric = new Point(so.at.x, so.at.y + 20 * scale) + points.__scaleboxImperial = new Point(so.at.x, so.at.y + 24 * scale) + // Rotation + if (so.rotate) { + so.rotate = Number(so.rotate) + let toRotate = [ + '__scaleboxMetricTopLeft', + '__scaleboxMetricTopRight', + '__scaleboxMetricBottomLeft', + '__scaleboxMetricBottomRight', + '__scaleboxImperialTopLeft', + '__scaleboxImperialTopRight', + '__scaleboxImperialBottomLeft', + '__scaleboxImperialBottomRight', + '__scaleboxLead', + '__scaleboxTitle', + '__scaleboxText', + '__scaleboxLink', + '__scaleboxMetric', + '__scaleboxImperial', + ] + for (let pid of toRotate) points[pid] = points[pid].rotate(so.rotate, so.at) + for (let pid of toRotate.slice(8)) { + points[pid].attributes.set( + 'data-text-transform', + `rotate(${so.rotate * -1}, ${points[pid].x}, ${points[pid].y})` + ) + } + } + // Paths + paths.__scaleboxImperial = new Path() + .attr('class', 'scalebox imperial fill-current') + .move(points.__scaleboxImperialTopLeft) + .line(points.__scaleboxImperialBottomLeft) + .line(points.__scaleboxImperialBottomRight) + .line(points.__scaleboxImperialTopRight) + .close() + paths.__scaleboxMetric = new Path() + .attr('class', 'scalebox metric fill-bg') + .move(points.__scaleboxMetricTopLeft) + .line(points.__scaleboxMetricBottomLeft) + .line(points.__scaleboxMetricBottomRight) + .line(points.__scaleboxMetricTopRight) + .close() + // Lead + points.__scaleboxLead = points.__scaleboxLead + .attr('data-text', so.lead || 'FreeSewing') + .attr('data-text-class', 'text-sm') + // Title + if (so.title) points.__scaleboxTitle.attributes.set('data-text', so.title) + else { + let name = store.data?.name || 'No Name' + if (name.indexOf('@freesewing/') !== -1) name = name.replace('@freesewing/', '') + points.__scaleboxTitle = points.__scaleboxTitle + .attr('data-text', name) + .attr('data-text', 'v' + (store.data?.version || 'No Version')) + } + points.__scaleboxTitle.attributes.add('data-text-class', 'text-lg') + // Text + if (typeof so.text === 'string') { + points.__scaleboxText.attr('data-text', so.text) + } else { + points.__scaleboxText.attr('data-text', 'supportFreesewingBecomeAPatron') + points.__scaleboxLink = points.__scaleboxLink + .attr('data-text', 'freesewing.org/patrons/join') + .attr('data-text-class', 'text-sm fill-note') + } + points.__scaleboxText.attr('data-text-class', 'text-xs').attr('data-text-lineheight', 4) + // Instructions + points.__scaleboxMetric = points.__scaleboxMetric + .attr('data-text', 'theWhiteInsideOfThisBoxShouldMeasure') + .attr('data-text', `${metricDisplayWidth}`) + .attr('data-text', 'x') + .attr('data-text', `${metricDisplayHeight}`) + .attr('data-text-class', 'text-xs center') + points.__scaleboxImperial = points.__scaleboxImperial + .attr('data-text', 'theBlackOutsideOfThisBoxShouldMeasure') + .attr('data-text', `${imperialDisplayWidth}`) + .attr('data-text', 'x') + .attr('data-text', `${imperialDisplayHeight}`) + .attr('data-text-class', 'text-xs center ') + }, + }, +} + +export const miniscale = { + name: 'miniscale', + version, + macros: { + miniscale(so, { store, points, paths, scale, Point, Path }) { + // Passing `false` will remove the miniscale + if (so === false) { + for (const id of [ + '__miniscaleMetricTopLeft', + '__miniscaleMetricTopRight', + '__miniscaleMetricBottomRight', + '__miniscaleMetricBottomLeft', + '__miniscaleImperialTopLeft', + '__miniscaleImperialTopRight', + '__miniscaleImperialBottomRight', + '__miniscaleImperialBottomLeft', + '__miniscaleMetric', + '__miniscaleImperial', + ]) + delete points[id] + for (const id of ['__miniscaleMetric', '__miniscaleImperial']) delete paths[id] + return true + } + + // Convert scale to a value between 0 and 5, inclusive. + const scaleIndex = Math.ceil(6 * Math.max(0.1, Math.min(1, scale))) - 1 + + console.log({ MSat: so.at }) + + // Metric size in mm / display value and imperial size in mm / display value for each scale index. + const sizes = [ + [10, '1cm', 25.4 * 0.375, '⅜″'], + [13, '1.3cm', 25.4 * 0.5, '½″'], + [16, '1.6cm', 25.4 * 0.625, '⅝″'], + [19, '1.9cm', 25.4 * 0.75, '¾″'], + [22, '2.2cm', 25.4 * 0.875, '⅞″'], + [25, '2.5cm', 25.4 * 1, '1″'], + ] + const m = sizes[scaleIndex][0] / 2 + const i = sizes[scaleIndex][2] / 2 + const metricDisplaySize = sizes[scaleIndex][1] + const imperialDisplaySize = sizes[scaleIndex][3] + // Box points + points.__miniscaleMetricTopLeft = new Point(so.at.x - m, so.at.y - m) + points.__miniscaleMetricTopRight = new Point(so.at.x + m, so.at.y - m) + points.__miniscaleMetricBottomLeft = new Point(so.at.x - m, so.at.y + m) + points.__miniscaleMetricBottomRight = new Point(so.at.x + m, so.at.y + m) + points.__miniscaleImperialTopLeft = new Point(so.at.x - i, so.at.y - i) + points.__miniscaleImperialTopRight = new Point(so.at.x + i, so.at.y - i) + points.__miniscaleImperialBottomLeft = new Point(so.at.x - i, so.at.y + i) + points.__miniscaleImperialBottomRight = new Point(so.at.x + i, so.at.y + i) + // Text anchor points + points.__miniscaleMetric = new Point(so.at.x, so.at.y - 2 * scale) + points.__miniscaleImperial = new Point(so.at.x, so.at.y + 8 * scale) + // Rotation + if (so.rotate) { + so.rotate = Number(so.rotate) + let toRotate = [ + '__miniscaleMetricTopLeft', + '__miniscaleMetricTopRight', + '__miniscaleMetricBottomLeft', + '__miniscaleMetricBottomRight', + '__miniscaleImperialTopLeft', + '__miniscaleImperialTopRight', + '__miniscaleImperialBottomLeft', + '__miniscaleImperialBottomRight', + '__miniscaleMetric', + '__miniscaleImperial', + ] + for (const pid of toRotate) points[pid] = points[pid].rotate(so.rotate, so.at) + for (const pid of toRotate.slice(8)) { + points[pid].attributes.set( + 'data-text-transform', + `rotate(${so.rotate * -1}, ${points[pid].x}, ${points[pid].y})` + ) + } + } + // Paths + paths.__miniscaleImperial = new Path() + .attr('class', 'scalebox imperial fill-current') + .move(points.__miniscaleImperialTopLeft) + .line(points.__miniscaleImperialBottomLeft) + .line(points.__miniscaleImperialBottomRight) + .line(points.__miniscaleImperialTopRight) + .close() + paths.__miniscaleMetric = new Path() + .attr('class', 'scalebox metric fill-bg') + .move(points.__miniscaleMetricTopLeft) + .line(points.__miniscaleMetricBottomLeft) + .line(points.__miniscaleMetricBottomRight) + .line(points.__miniscaleMetricTopRight) + .close() + // Text + points.__miniscaleMetric = points.__miniscaleMetric + .attr('data-text', `${metricDisplaySize} x ${metricDisplaySize}`) + .attr('data-text-class', 'text-xs center') + points.__miniscaleImperial = points.__miniscaleImperial + .attr('data-text', `${imperialDisplaySize} x ${imperialDisplaySize}`) + .attr('data-text-class', 'text-xs center ') + }, + }, +} diff --git a/plugins/plugin-annotations/src/sewtogether.mjs b/plugins/plugin-annotations/src/sewtogether.mjs index 21c618e5580..f695cbaf7ff 100644 --- a/plugins/plugin-annotations/src/sewtogether.mjs +++ b/plugins/plugin-annotations/src/sewtogether.mjs @@ -12,7 +12,7 @@ const markers = ` ` -export const plugin = { +export const sewtogether = { name, version, hooks: { diff --git a/plugins/plugin-bundle/src/index.mjs b/plugins/plugin-bundle/src/index.mjs index e2524a659ea..4d1097d9641 100644 --- a/plugins/plugin-bundle/src/index.mjs +++ b/plugins/plugin-bundle/src/index.mjs @@ -3,17 +3,17 @@ import { crossboxPlugin } from '../../plugin-annotations/src/index.mjs' import { cutonfoldPlugin } from '../../plugin-annotations/src/index.mjs' import { pleatPlugin } from '../../plugin-annotations/src/index.mjs' import { sewtogetherPlugin } from '../../plugin-annotations/src/index.mjs' +import { logoPlugin } from '../../plugin-annotations/src/index.mjs' +import { buttonsPlugin } from '../../plugin-annotations/src/index.mjs' +import { grainlinePlugin } from '../../plugin-annotations/src/index.mjs' +import { notchesPlugin } from '../../plugin-annotations/src/index.mjs' +import { scaleboxPlugin } from '../../plugin-annotations/src/index.mjs' import { bannerPlugin } from '../../plugin-banner/src/index.mjs' -import { buttonsPlugin } from '../../plugin-buttons/src/index.mjs' import { dimensionPlugin } from '../../plugin-dimension/src/index.mjs' -import { grainlinePlugin } from '../../plugin-grainline/src/index.mjs' -import { logoPlugin } from '../../plugin-logo/src/index.mjs' import { measurementsPlugin } from '../../plugin-measurements/src/index.mjs' import { mirrorPlugin } from '../../plugin-mirror/src/index.mjs' -import { notchesPlugin } from '../../plugin-notches/src/index.mjs' import { roundPlugin } from '../../plugin-round/src/index.mjs' -import { scaleboxPlugin } from '../../plugin-scalebox/src/index.mjs' import { sprinklePlugin } from '../../plugin-sprinkle/src/index.mjs' import { titlePlugin } from '../../plugin-title/src/index.mjs' import { name, version } from '../data.mjs'