1
0
Fork 0

feat: Added studio to monorepo

This commit is contained in:
joostdecock 2025-04-21 18:20:52 +02:00 committed by Joost De Cock
parent c17b58f141
commit 02f841c570
177 changed files with 2467 additions and 2118 deletions

11
.gitignore vendored
View file

@ -35,6 +35,17 @@ sites/*/yarn.lock
# Docusaurus cache
.docusaurus
# Sites get some files from org via the reconfigure script
sites/studio/postcss.config.js
sites/studio/babel.config.mjs
sites/studio/plugins
sites/studio/src/css
sites/studio/designs
sites/studio/docs
sites/studio/src
sites/studio/scripts
sites/studio/static
# Sites prebuild artifacts
sites/*/public/locales/*/*.json
!sites/sde/public/locales/*/*.json

View file

@ -211,18 +211,18 @@
- The `@freesewing/i18n` package holds translations in English for where they are needed
### studio
#### Added
- Added `@freesewing/studio`, our new development environment
### react
#### Added
- The `@freesewing/react` package holds shared components, hooks, and context for our React-based frontends
### studio
#### Added
- Added `@freesewing/studio`, our new development environment
### utils
#### Added

View file

@ -1,5 +1,5 @@
_types:
design:
designs:
peer:
'@freesewing/core': &freesewing '{{version}}'
dev:
@ -7,7 +7,7 @@ _types:
'chai': &chai '5.1.1'
'@freesewing/models': *freesewing
'@freesewing/plugin-timing': *freesewing
plugin:
plugins:
peer:
'@freesewing/core': *freesewing
dev:

View file

@ -4,11 +4,11 @@ _:
tips: 'node ../../scripts/help.mjs'
lint: "npx eslint 'src/**' 'tests/*.mjs'"
_types:
design:
designs:
prettier: "npx prettier --write 'src/*.mjs' 'tests/*.mjs'"
test: &test 'npx mocha tests/*.test.mjs'
testci: &testci 'NODE_OPTIONS="--conditions=internal" npx mocha tests/*.test.mjs --reporter ../../tests/reporters/terse.js'
plugin:
plugins:
prettier: "npx prettier --write 'src/*.mjs' 'tests/*.mjs'"
test: *test
testci: *testci

View file

@ -1,936 +0,0 @@
{
"aaron": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a A-shirt or tank top",
"design": "Joost De Cock",
"difficulty": 2,
"tags": [
"tops",
"underwear"
],
"techniques": [
"hem",
"stretch",
"knit-binding",
"curved-seam"
]
},
"albert": {
"code": "Wouter Van Wageningen",
"description": "A FreeSewing pattern for an apron",
"design": "Wouter Van Wageningen",
"difficulty": 2,
"tags": [
"accessories"
],
"techniques": [
"hem",
"knit-binding",
"curved-seam",
"pocket"
]
},
"bee": {
"code": "bobgeorgethe3rd",
"description": "A FreeSewing pattern for a bikini top",
"design": "PrudenceRabbit",
"difficulty": 3,
"tags": [
"tops",
"swimwear"
],
"techniques": [
"hem",
"stretch",
"curved-seam",
"precision"
]
},
"bella": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a womenswear bodice block",
"design": [
"Bella Incognito",
"Joost De Cock"
],
"difficulty": 3,
"tags": [
"blocks",
"tops"
],
"techniques": [
"dart",
"block"
]
},
"benjamin": {
"code": "Wouter Van Wageningen",
"description": "A FreeSewing pattern for a bow tie",
"design": "Wouter Van Wageningen",
"difficulty": 3,
"tags": [
"accessories"
],
"techniques": [
"precision",
"interfacing"
]
},
"bent": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a menswear body block with a two-part sleeve",
"design": "Joost De Cock",
"difficulty": 3,
"tags": [
"blocks",
"tops"
],
"techniques": [
"hem",
"curved-seam",
"set-sleeve"
]
},
"bibi": {
"code": "Jonathan Haas",
"description": "A FreeSewing pattern for a knit top body block",
"design": "Jonathan Haas",
"difficulty": 2,
"tags": [
"blocks",
"tops"
],
"techniques": [
"curved-seam",
"hem",
"flat-sleeve"
]
},
"bob": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a bib",
"design": "Joost De Cock",
"difficulty": 3,
"tags": [
"accessories",
"infants"
],
"techniques": [
"bias-tape",
"curved-seam",
"snap"
]
},
"bonny": {
"code": "Jonathan Haas",
"description": "A FreeSewing pattern that turns measurements into a body outline",
"design": "Jonathan Haas",
"difficulty": 1,
"tags": [],
"techniques": []
},
"breanna": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a basic body block for womenswear",
"design": "Joost De Cock",
"difficulty": 3,
"tags": [
"blocks",
"tops"
],
"techniques": [
"block",
"dart"
]
},
"brian": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a basic body block for menswear",
"design": "Joost De Cock",
"difficulty": 3,
"tags": [
"blocks",
"tops"
],
"techniques": [
"block",
"flat-sleeve"
]
},
"bruce": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for boxer briefs",
"design": "Joost De Cock",
"difficulty": 3,
"tags": [
"bottoms",
"underwear"
],
"techniques": [
"stretch",
"hem",
"curved-seam",
"elastic"
]
},
"carlita": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for Sherlock Holmes cosplay; Or just a nice long coat",
"design": [
"Anneke Caramin",
"Joost De Cock"
],
"difficulty": 5,
"tags": [
"tops",
"coats"
],
"techniques": [
"hem",
"pocket",
"curved-seam",
"precision",
"set-sleeve",
"welt-pocket",
"lining",
"princess-seam",
"interfacing",
"button"
]
},
"carlton": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for Sherlock Holmes cosplay; Or just a nice long coat",
"design": [
"Anneke Caramin",
"Joost De Cock"
],
"difficulty": 5,
"tags": [
"tops",
"coats"
],
"techniques": [
"hem",
"pocket",
"curved-seam",
"precision",
"set-sleeve",
"welt-pocket",
"lining",
"interfacing",
"button"
]
},
"cathrin": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a underbust corset / waist trainer",
"design": [
"Cathrin Åhlén",
"Joost De Cock"
],
"difficulty": 4,
"tags": [
"tops",
"underwear"
],
"techniques": [
"boning",
"precision",
"curved-seam",
"interfacing"
]
},
"charlie": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for chino trousers",
"design": "Joost De Cock",
"difficulty": 3,
"tags": [
"bottoms",
"trousers"
],
"techniques": [
"welt-pocket",
"curved-seam",
"interfacing",
"fly",
"zipper",
"button",
"dart",
"hem",
"seam-pocket"
]
},
"cornelius": {
"code": "Wouter Van Wageningen",
"description": "A FreeSewing pattern for cycling breeches, based on the Keystone drafting system",
"design": "Wouter Van Wageningen",
"difficulty": 3,
"tags": [
"bottoms",
"trousers"
],
"techniques": [
"curved-seam",
"fly",
"zipper",
"button",
"pocket"
]
},
"diana": {
"code": "Erica Alcusa Sáez",
"description": "A FreeSewing pattern for a top with a draped neck",
"design": "Erica Alcusa Sáez",
"difficulty": 2,
"tags": [
"tops"
],
"techniques": [
"curved-seam",
"flat-sleeve",
"hem"
]
},
"examples": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern holding examples for our documentation"
},
"florence": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a face mask",
"design": "Joost De Cock",
"difficulty": 1,
"tags": [
"accessories"
],
"techniques": [
"curved-seam"
]
},
"florent": {
"code": [
"Quentin Felix",
"Joost De Cock"
],
"description": "A FreeSewing pattern for a flat cap",
"design": "Quentin Felix",
"difficulty": 3,
"tags": [
"accessories",
"hats"
],
"techniques": [
"curved-seam"
]
},
"gozer": {
"code": "Wouter Van Wageningen",
"description": "A FreeSewing pattern for a ghost costume",
"design": "Wouter Van Wageningen",
"difficulty": 1,
"tags": [
"costumes"
],
"techniques": [
"hem"
]
},
"hi": {
"code": "Wouter Van Wageningen",
"description": "A FreeSewing pattern for a shark plush toy",
"design": "Wouter Van Wageningen",
"difficulty": 4,
"tags": [
"accessories",
"toys"
],
"techniques": [
"curved-seam",
"dart"
]
},
"holmes": {
"code": [
"Erica Alcusa Sáez",
"bobgeorgethe3rd"
],
"description": "A FreeSewing pattern for a Sherlock Holmes hat",
"design": "Erica Alcusa Sáez",
"difficulty": 3,
"tags": [
"accessories",
"hats"
],
"techniques": [
"curved-seam",
"lining"
]
},
"hortensia": {
"code": "Wouter Van Wageningen",
"description": "A FreeSewing pattern for a handbag",
"design": [
"Stoffsuchti",
"Wouter Van Wageningen"
],
"difficulty": 3,
"tags": [
"accessories",
"bags"
],
"techniques": [
"curved-seam",
"precision",
"lining",
"zipper"
]
},
"huey": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a zip-up hoodie",
"design": "Joost De Cock",
"difficulty": 3,
"tags": [
"tops"
],
"techniques": [
"curved-seam",
"pocket",
"zipper",
"ribbing",
"flat-sleeve"
]
},
"hugo": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a hooded jumper with raglan sleeves",
"design": "Joost De Cock",
"difficulty": 3,
"tags": [
"tops"
],
"techniques": [
"curved-seam",
"pocket",
"ribbing",
"raglan-sleeve"
]
},
"jaeger": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a sport coat style jacket",
"design": "Joost De Cock",
"difficulty": 5,
"tags": [
"tops",
"coats"
],
"techniques": [
"hem",
"pocket",
"curved-seam",
"precision",
"set-sleeve",
"welt-pocket",
"lining",
"interfacing",
"button"
]
},
"jane": {
"code": "SeaZeeZee",
"description": "A FreeSewing pattern for a 1790s shift",
"design": "SeaZeeZee",
"difficulty": 2,
"tags": [
"tops",
"historical",
"underwear"
],
"techniques": [
"hem"
]
},
"legend": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern to document pattern notation"
},
"lucy": {
"code": "SeaZeeZee",
"description": "A FreeSewing pattern for a historical tie-on pocket",
"design": "SeaZeeZee",
"difficulty": 2,
"tags": [
"accessories",
"historical",
"bags"
],
"techniques": [
"curved-seam"
]
},
"lumina": {
"code": "Wouter Van Wageningen",
"description": "A FreeSewing pattern for leggings",
"design": "Wouter Van Wageningen",
"difficulty": 3,
"tags": [
"bottoms",
"trousers"
],
"techniques": [
"stretch",
"curved-seam",
"elastic"
]
},
"lumira": {
"code": "Wouter Van Wageningen",
"description": "A FreeSewing pattern for leggings",
"design": "Wouter Van Wageningen",
"difficulty": 3,
"tags": [
"bottoms",
"trousers"
],
"techniques": [
"stretch",
"curved-seam",
"elastic"
]
},
"lunetius": {
"code": "Rika Tamaike",
"description": "A FreeSewing pattern for a lacerna, a historical Roman cloak",
"design": "Rika Tamaike",
"difficulty": 1,
"tags": [
"tops",
"coats",
"historical"
],
"techniques": [
"hem"
]
},
"magde": {
"code": "clegganator259",
"description": "A FreeSewing pattern for a bike messenger bag",
"design": "clegganator259",
"difficulty": 3,
"tags": [
"accessories",
"bags"
],
"techniques": []
},
"noble": {
"code": "Wouter Van Wageningen",
"description": "A FreeSewing pattern for a princess seam bodice block",
"design": "Wouter Van Wageningen",
"difficulty": 3,
"tags": [
"blocks",
"tops"
],
"techniques": [
"block",
"curved-seam",
"precision",
"princess-seam"
]
},
"octoplushy": {
"code": "Wouter Van Wageningen",
"description": "A FreeSewing pattern for an octopus plushy toy",
"design": "Wouter Van Wageningen",
"difficulty": 4,
"tags": [
"accessories",
"toys"
],
"techniques": [
"curved-seam",
"precision"
]
},
"onyx": {
"code": "Thrunic",
"description": "A FreeSewing pattern for one-piece garments",
"design": "Thrunic",
"difficulty": 4,
"tags": [
"swimwear",
"pajamas",
"onePiece"
],
"techniques": [
"hem",
"curved-seam",
"stretch",
"lining",
"zipper",
"ribbing"
]
},
"opal": {
"code": "Thrunic",
"description": "A FreeSewing pattern for overalls",
"design": "Thrunic",
"difficulty": 3,
"tags": [
"overalls",
"onePiece"
],
"techniques": [
"flat-felled-seam",
"hem",
"curved-seam",
"button",
"pocket"
]
},
"otis": {
"code": "Wouter Van Wageningen",
"description": "A FreeSewing pattern for a baby romper",
"design": "Wouter Van Wageningen",
"difficulty": 2,
"tags": [],
"techniques": []
},
"paco": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for summer pants",
"design": "Joost De Cock",
"difficulty": 3,
"tags": [
"bottoms",
"trousers"
],
"techniques": [
"elastic",
"curved-seam",
"pocket",
"welt-pocket",
"hem"
]
},
"penelope": {
"code": "Wouter Van Wageningen",
"description": "A FreeSewing pattern for a pencil skirt",
"design": "Wouter Van Wageningen",
"difficulty": 3,
"tags": [
"bottoms",
"skirts"
],
"techniques": [
"hem",
"curved-seam",
"precision",
"zipper"
]
},
"plugintest": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern to test (y)our plugins"
},
"rendertest": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern to test (y)our render engine our CSS"
},
"sandy": {
"code": [
"Erica Alcusa Sáez",
"Joost De Cock"
],
"description": "A FreeSewing pattern for a circle skirt",
"design": "Erica Alcusa Sáez",
"difficulty": 3,
"tags": [
"bottoms",
"skirts"
],
"techniques": [
"curved-seam",
"button",
"hem"
]
},
"shelly": {
"code": "Thrunic",
"description": "A FreeSewing pattern for a raglan shirt, perfect for swimshirts",
"design": "Thrunic",
"difficulty": 2,
"tags": [
"tops",
"swimwear"
],
"techniques": [
"hem",
"stretch",
"curved-seam",
"raglan-sleeve"
]
},
"shin": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for swim trunks",
"design": "Joost De Cock",
"difficulty": 2,
"tags": [
"bottoms",
"swimwear"
],
"techniques": [
"hem",
"stretch",
"curved-seam",
"elastic"
]
},
"simon": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a button down shirt",
"design": "Joost De Cock",
"difficulty": 4,
"tags": [
"tops"
],
"techniques": [
"hem",
"button",
"interfacing",
"curved-seam",
"flat-felled-seam",
"flat-sleeve"
]
},
"simone": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a button down shirt (Simone = Simon for people with breasts)",
"design": "Joost De Cock",
"difficulty": 4,
"tags": [
"tops"
],
"techniques": [
"hem",
"button",
"interfacing",
"curved-seam",
"flat-felled-seam",
"flat-sleeve"
]
},
"skully": {
"code": "Wouter Van Wageningen",
"description": "A FreeSewing pattern for skully, our logo, a plushy toy",
"design": "Wouter Van Wageningen",
"difficulty": 4,
"tags": [
"accessories",
"toys"
],
"techniques": [
"curved-seam",
"precision"
]
},
"sven": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a straightforward sweater",
"design": "Joost De Cock",
"difficulty": 3,
"tags": [
"tops"
],
"techniques": [
"curved-seam",
"flat-sleeve",
"ribbing"
]
},
"tamiko": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a zero-waste top",
"design": "Joost De Cock",
"difficulty": 1,
"tags": [
"tops"
],
"techniques": [
"curved-seam"
]
},
"teagan": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a T-shirt",
"design": "Joost De Cock",
"difficulty": 2,
"tags": [
"tops"
],
"techniques": [
"curved-seam",
"hem",
"flat-sleeve",
"knit-band"
]
},
"tiberius": {
"code": "Rika Tamaike",
"description": "A FreeSewing pattern for a tunica, a historical Roman tunic",
"design": "Rika Tamaike",
"difficulty": 1,
"tags": [
"tops",
"historical"
],
"techniques": []
},
"titan": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a unisex trouser block",
"design": [
"Debra Bean",
"Joost De Cock"
],
"difficulty": 3,
"tags": [
"blocks",
"bottoms"
],
"techniques": []
},
"trayvon": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a tie",
"design": "Joost De Cock",
"difficulty": 2,
"tags": [
"accessories"
],
"techniques": [
"precision",
"lining"
]
},
"tristan": {
"code": "Wouter van Wageningen",
"description": "A FreeSewing pattern for a fitted top with prince(ss) seams",
"design": "Natalia Sayang",
"difficulty": 3,
"tags": [
"tops"
],
"techniques": [
"curved-seam",
"precision"
]
},
"uma": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a basic, highly-customizable underwear pattern",
"design": "Joost De Cock",
"difficulty": 2,
"tags": [
"bottoms",
"underwear"
],
"techniques": [
"elastic",
"curved-seam"
]
},
"umbra": {
"code": ["Joost De Cock", "Jonathan Haas"],
"description": "A FreeSewing pattern for a basic, highly-customizable underwear pattern",
"design": ["Joost De Cock", "Jonathan Haas"],
"difficulty": 2,
"tags": [
"bottoms",
"underwear"
],
"techniques": [
"elastic",
"curved-seam"
]
},
"wahid": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a classic fitted waistcoat",
"design": "Joost De Cock",
"difficulty": 4,
"tags": [
"tops"
],
"techniques": [
"curved-seam",
"hem",
"interfacing",
"lining",
"welt-pocket",
"button"
]
},
"walburga": {
"code": "Rika Tamaike",
"description": "A FreeSewing pattern for a wappenrock (tabard/surcoat), a historical European/medieval (ish) garment",
"design": "Rika Tamaike",
"difficulty": 1,
"tags": [
"bottoms",
"historical"
],
"techniques": [
"hem"
]
},
"waralee": {
"code": "Wouter Van Wageningen",
"description": "A FreeSewing pattern for wrap pants",
"design": "Wouter Van Wageningen",
"difficulty": 2,
"tags": [
"bottoms",
"trousers"
],
"techniques": [
"curved-seam",
"hem",
"welt-pocket"
]
},
"yuri": {
"code": "Hellgy",
"description": "A FreeSewing pattern for a fancy zipless sweater based on the Huey hoodie",
"design": "Biou",
"difficulty": 3,
"tags": [
"tops"
],
"techniques": [
"curved-seam",
"flat-sleeve",
"hem",
"button"
]
},
"lily": {
"code": ["Anna Puk", "Joost De Cock"],
"description": "A FreeSewing pattern for basic leggings",
"design": "Anna Puk",
"difficulty": 2,
"tags": [
"bottoms"
],
"techniques": [
"elastic",
"curved-seam",
"hem"
]
}
}

View file

@ -1,41 +0,0 @@
import designs from './designs.json' assert { type: 'json' }
import packages from './packages.json' assert { type: 'json' }
import plugins from './plugins.json' assert { type: 'json' }
// Helper method to construct summary objects
const unpack = (obj, folder) =>
Object.fromEntries(
Object.keys(obj).map((name) => [
name,
{ name, folder, type: folder.slice(0, -1), description: obj[name] },
])
)
// Helper method to construct summary objects for designs
const unpackDesigns = (obj, folder) =>
Object.fromEntries(
Object.keys(obj).map((name) => [
name,
{ name, folder, type: folder.slice(0, -1), ...obj[name] },
])
)
// Re-Export imported JSON
export { designs, packages, plugins }
// All software
export const software = {
...unpackDesigns(designs, 'designs'),
...unpack(plugins, 'plugins'),
...unpack(packages, 'packages'),
}
// All software published on NPM
export const publishedSoftware = {
...unpackDesigns(designs, 'designs'),
...unpack(plugins, 'plugins'),
...unpack(packages, 'packages'),
}
export const publishedTypes = ['designs', 'packages', 'plugins']
export const types = publishedTypes

View file

@ -1,12 +0,0 @@
{
"collection": "All FreeSewing designs bundles into one pacakge, our collection",
"config": "Various configurations for FreeSewing",
"core": "A library for creating made-to-measure sewing patterns",
"i18n": "Translation for the FreeSewing project",
"models": "Body measurements data for a range of default sizes",
"studio": "Initializer package for a the FreeSewing design studio: npx @freesewing/studio",
"prettier-config": "FreeSewing's shared configuration for prettier",
"react": "React components, hooks and context by/for FreeSewing",
"snapseries": "A series of common sizes for elastics and other series to be used with snapped percentage options",
"utils": "A number of utilities, typically used by FreeSewing frontend code"
}

View file

@ -1,19 +0,0 @@
{
"core-plugins": "An umbrella package of essential plugins that are bundled with FreeSewing's core library",
"plugin-annotations": "A FreeSewing plugin that provides pattern annotations",
"plugin-bin-pack": "A FreeSewing plugin that adds a bin-pack algorithm to the core library",
"plugin-bust": "A FreeSewing plugin that helps with bust-adjusting menswear patterns",
"plugin-flip": "A FreeSewing plugin to flip parts horizontally",
"plugin-gore": "A FreeSewing plugin to generate gores for a semi-sphere or dome",
"plugin-i18n": "A FreeSewing plugin for pattern translation",
"plugin-measurements": "A FreeSewing plugin that adds additional measurements that can be calculated from existing ones",
"plugin-mirror": "A FreeSewing plugin to mirror points or paths",
"plugin-ringsector": "A FreeSewing plugin to draft a ring sector (think part of a donut)",
"plugin-round": "A FreeSewing plugin to round corners",
"plugin-path-utils": "A FreeSewing plugin that adds various path helper macros",
"plugin-sprinkle": "A FreeSewing plugin to bulk-add snippets to your pattern",
"plugin-svgattr": "A FreeSewing plugin to set SVG attributes",
"plugin-theme": "A FreeSewing plugin that provides a default theme",
"plugin-timing": "A FreeSewing plugin to record the time it takes to draft your pattern parts",
"plugin-versionfree-svg": "A FreeSewing plugin to keep version info out of your SVG to allow easy diffs across versions"
}

View file

@ -0,0 +1,9 @@
{{{ designImports }}}
export const designs = {
{{ designList }}
}
export const useDesign = (design) => (designs[design] ? designs[design] : false)
export const collection = Object.keys(designs)

View file

@ -0,0 +1,72 @@
// Designs
{{{ designImports }}}
// Translations
import { i18n as translations } from './i18n.mjs'
// Examples
import { designExampleIds, designExampleHrefs } from './examples.mjs'
/*
* Export the designs themselves
*/
export const designs = {
{{ designList }}
}
/*
* Export a list of names that make up the FreeSewing collection
*/
export const collection = Object.keys(designs)
/*
* Create various helper exports to get info about the collection
*/
export const requiredMeasurements = {}
export const optionalMeasurements = {}
export const measurements = {}
export const about = {}
const _tags = new Set()
const _techniques = new Set()
const _devs = new Set()
const _dess = new Set()
for (const design in designs) {
requiredMeasurements[design] = designs[design].patternConfig.measurements
optionalMeasurements[design] = designs[design].patternConfig.optionalMeasurements
measurements[design] = [
...designs[design].patternConfig.measurements,
...designs[design].patternConfig.optionalMeasurements,
]
about[design] = { ...designs[design].designConfig.data }
if (about[design].tags) _tags.add(...about[design].tags)
if (about[design].techniques) _techniques.add(...about[design].techniques)
if (Array.isArray(about[design].code)) _devs.add(...about[design].code)
else _devs.add(about[design].code)
if (Array.isArray(about[design].design)) _dess.add(...about[design].design)
else _dess.add(about[design].design)
}
export const tags = Array.from(_tags)
.filter((t) => (t ? true : false))
.sort()
export const techniques = Array.from(_techniques)
.filter((t) => (t ? true : false))
.sort()
export const developers = Array.from(_devs)
.filter((t) => (t ? true : false))
.sort()
export const designers = Array.from(_dess)
.filter((t) => (t ? true : false))
.sort()
/*
* Export the translations
*/
export const i18n = translations
/*
* These are examples
*/
export const examples = {
id: designExampleIds,
href: designExampleHrefs,
}

View file

@ -1,4 +0,0 @@
// This file is auto-generated | All changes you make will be overwritten.
export const name = '{{{ name }}}'
export const version = '{{ version }}'
export const data = { name, version }

View file

@ -17,7 +17,7 @@
".": "./src/index.mjs"
},
"scripts": {
"testonly": "BABEL_ENV=production ../../node_modules/.bin/_mocha tests/*.test.js --require @babel/register",
"test": "npx mocha tests/*.test.mjs",
"publish": "npm publish --access public"
},
"peerDependencies": {},

View file

@ -0,0 +1,6 @@
{
"id": "plugin-{{ name }}",
"description": "A FreeSewing plugin that lacks a description",
"version": "4.0.0-rc.8"
}

View file

@ -1,21 +1,23 @@
import { name, version } from '../data.mjs'
import about from '../about.json' with { type: 'json' }
/*
* This is plugin-{{ name }}
*
* This skeleton file was auto-generated.
* For help on writing plugins, see the plugin guide at:
* https://freesewing.dev/guides/plugins/
*/
export const plugin = {
name,
version,
macros: {
{{name}}: function (so, {points, paths, Path}) { //Example shorthand, you may wish to add other elements like utils
const defaults = {
//note these are common examples and can be removed
scale: 1,
rotation: 0,
}
so = { ...defaults, ...so }
//write plugin here
},
},
name: about.id,
version: about.version,
hooks: { },
macros: { },
store: [ ],
}
// More specifically named exports
/*
* More specifically named exports
*/
export const {{name}}Plugin = plugin
export const plugin{{capitalized_name}} = plugin

View file

@ -0,0 +1,5 @@
{
"id": "examples",
"version": "4.0.0",
"description": "A FreeSewing pattern holding examples for our documentation"
}

View file

@ -0,0 +1,5 @@
{
"id": "legend",
"description": "A FreeSewing pattern to document pattern notation",
"version": "4.0.0"
}

View file

@ -9,5 +9,6 @@
"accessories",
"bags"
],
"techniques": []
"techniques": [],
"version": "4.0.0"
}

View file

@ -0,0 +1,5 @@
{
"id": "plugintest",
"description": "A FreeSewing pattern to test (y)our plugins",
"version": "4.0.0"
}

View file

@ -0,0 +1,5 @@
{
"id": "rendertest",
"description": "A FreeSewing pattern to test (y)our render engine our CSS",
"version": "4.0.0"
}

382
package-lock.json generated
View file

@ -59607,6 +59607,10 @@
"node": ">=4"
}
},
"node_modules/studio": {
"resolved": "sites/studio",
"link": true
},
"node_modules/style-mod": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
@ -70585,6 +70589,384 @@
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"sites/studio": {
"version": "0.0.0",
"dependencies": {
"@docusaurus/core": "^3.7.0",
"@docusaurus/faster": "^3.7.0",
"@docusaurus/preset-classic": "^3.7.0",
"@freesewing/collection": "latest",
"@freesewing/config": "latest",
"@freesewing/core": "latest",
"@freesewing/i18n": "latest",
"@freesewing/plugin-i18n": "latest",
"@freesewing/plugin-theme": "latest",
"@freesewing/plugin-timing": "latest",
"@freesewing/react": "latest",
"@freesewing/snapseries": "latest",
"@freesewing/utils": "latest",
"@mdx-js/react": "^3.0.0",
"lodash": "^4.17.21",
"postcss": "^8.4.47",
"prism-react-renderer": "^2.3.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-markdown": "^9.0.1",
"remark-smartypants": "^3.0.2"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.7.0",
"@docusaurus/types": "^3.7.0",
"@tailwindcss/postcss": "^4.1.3",
"autoprefixer": "^10.4.20",
"daisyui": "^5.0.19",
"glob": "^11.0.0",
"gray-matter": "^4.0.3",
"postcss": "^8.4.47",
"tailwindcss": "^4.1.3",
"yaml-loader": "^0.8.1"
},
"engines": {
"node": ">=20.0"
}
},
"sites/studio/node_modules/@freesewing/collection": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@freesewing/collection/-/collection-4.0.0.tgz",
"integrity": "sha512-ozBv1MdcZ3VyJiBxsevK/dIOHTa+Di7m2qfvYPdCa1Io+zMT6RfCdS46gYOp79M9Hf1lLEsKaXV6IPa5P6eCIQ==",
"license": "MIT",
"dependencies": {
"@freesewing/aaron": "4.0.0",
"@freesewing/albert": "4.0.0",
"@freesewing/bee": "4.0.0",
"@freesewing/bella": "4.0.0",
"@freesewing/benjamin": "4.0.0",
"@freesewing/bent": "4.0.0",
"@freesewing/bibi": "4.0.0",
"@freesewing/bob": "4.0.0",
"@freesewing/bonny": "4.0.0",
"@freesewing/breanna": "4.0.0",
"@freesewing/brian": "4.0.0",
"@freesewing/bruce": "4.0.0",
"@freesewing/carlita": "4.0.0",
"@freesewing/carlton": "4.0.0",
"@freesewing/cathrin": "4.0.0",
"@freesewing/charlie": "4.0.0",
"@freesewing/core": "4.0.0",
"@freesewing/core-plugins": "4.0.0",
"@freesewing/cornelius": "4.0.0",
"@freesewing/diana": "4.0.0",
"@freesewing/florence": "4.0.0",
"@freesewing/florent": "4.0.0",
"@freesewing/gozer": "4.0.0",
"@freesewing/hi": "4.0.0",
"@freesewing/holmes": "4.0.0",
"@freesewing/hortensia": "4.0.0",
"@freesewing/huey": "4.0.0",
"@freesewing/hugo": "4.0.0",
"@freesewing/jaeger": "4.0.0",
"@freesewing/jane": "4.0.0",
"@freesewing/lily": "4.0.0",
"@freesewing/lucy": "4.0.0",
"@freesewing/lumina": "4.0.0",
"@freesewing/lumira": "4.0.0",
"@freesewing/lunetius": "4.0.0",
"@freesewing/noble": "4.0.0",
"@freesewing/octoplushy": "4.0.0",
"@freesewing/onyx": "4.0.0",
"@freesewing/opal": "4.0.0",
"@freesewing/otis": "4.0.0",
"@freesewing/paco": "4.0.0",
"@freesewing/penelope": "4.0.0",
"@freesewing/plugin-bust": "4.0.0",
"@freesewing/plugin-flip": "4.0.0",
"@freesewing/sandy": "4.0.0",
"@freesewing/shelly": "4.0.0",
"@freesewing/shin": "4.0.0",
"@freesewing/simon": "4.0.0",
"@freesewing/simone": "4.0.0",
"@freesewing/skully": "4.0.0",
"@freesewing/snapseries": "4.0.0",
"@freesewing/sven": "4.0.0",
"@freesewing/tamiko": "4.0.0",
"@freesewing/teagan": "4.0.0",
"@freesewing/tiberius": "4.0.0",
"@freesewing/titan": "4.0.0",
"@freesewing/trayvon": "4.0.0",
"@freesewing/tristan": "4.0.0",
"@freesewing/uma": "4.0.0",
"@freesewing/umbra": "4.0.0",
"@freesewing/wahid": "4.0.0",
"@freesewing/walburga": "4.0.0",
"@freesewing/waralee": "4.0.0",
"@freesewing/yuri": "4.0.0"
},
"engines": {
"node": ">= 20"
},
"funding": {
"type": "individual",
"url": "https://freesewing.org/patrons/join"
}
},
"sites/studio/node_modules/@freesewing/config": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@freesewing/config/-/config-4.0.0.tgz",
"integrity": "sha512-VNGs+22BsNyY4grbbca2ml/prMweqNmmO2SO8uwY+8GLPnvVs+0pRgSEciWkGmTTprWsFtLHIz8jCf2u+spZ7g==",
"license": "MIT",
"engines": {
"node": ">= 20"
},
"funding": {
"type": "individual",
"url": "https://freesewing.org/patrons/join"
}
},
"sites/studio/node_modules/@freesewing/core": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@freesewing/core/-/core-4.0.0.tgz",
"integrity": "sha512-o1CTkyND0ytU7wj9h29G/AuG9pkxZlQ+7hbZx51u9l1UA0Qbvfm627+VEMThdDQalrNam4WN+9mW6OdTZyXr8Q==",
"license": "MIT",
"dependencies": {
"@freesewing/core-plugins": "4.0.0",
"bezier-js": "6.1.4",
"hooks": "0.3.2",
"lodash.clonedeep": "^4.5.0",
"lodash.get": "4.4.2",
"lodash.set": "4.3.2",
"lodash.unset": "4.5.2"
},
"engines": {
"node": ">= 20"
},
"funding": {
"type": "individual",
"url": "https://freesewing.org/patrons/join"
}
},
"sites/studio/node_modules/@freesewing/i18n": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@freesewing/i18n/-/i18n-4.0.0.tgz",
"integrity": "sha512-jd0LLuSiiGfM5P1EQKW/5tS/nFMpAbXgg22OP9lYTDiHNdPdZ3QFoDGGb1p8dnbI3RBJfkn+ciLTt7R45YOPBg==",
"license": "MIT",
"engines": {
"node": ">= 20"
},
"funding": {
"type": "individual",
"url": "https://freesewing.org/patrons/join"
}
},
"sites/studio/node_modules/@freesewing/plugin-i18n": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@freesewing/plugin-i18n/-/plugin-i18n-4.0.0.tgz",
"integrity": "sha512-v4DoroyWpkoJNCccQ2saepphySKv91On31eWCW9aj8E3Ps8smcwUd+4kOz+MXZkUpPXOOD7oFhdYhrT4hlGcFg==",
"license": "MIT",
"engines": {
"node": ">= 20"
},
"funding": {
"type": "individual",
"url": "https://freesewing.org/patrons/join"
},
"peerDependencies": {
"@freesewing/core": "4.0.0"
}
},
"sites/studio/node_modules/@freesewing/plugin-theme": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@freesewing/plugin-theme/-/plugin-theme-4.0.0.tgz",
"integrity": "sha512-USB0sKJphpoicXvFDb/I5K5m8KSSOb8l0wZGbb+KnKkj9zrUSEyJB4EHtGgv1fstelNyjfA8naq0Nq5qgHPJFA==",
"license": "MIT",
"engines": {
"node": ">= 20"
},
"funding": {
"type": "individual",
"url": "https://freesewing.org/patrons/join"
},
"peerDependencies": {
"@freesewing/core": "4.0.0"
}
},
"sites/studio/node_modules/@freesewing/plugin-timing": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@freesewing/plugin-timing/-/plugin-timing-4.0.0.tgz",
"integrity": "sha512-m4n3Ley+aoScI8vW1uVW/YBjeTZmWCyuixhFC88LU2TjUH/Lm11P6gCTWdbE9IBpA2Zkn65arpRLZrI08GQlnw==",
"license": "MIT",
"engines": {
"node": ">= 20"
},
"funding": {
"type": "individual",
"url": "https://freesewing.org/patrons/join"
},
"peerDependencies": {
"@freesewing/core": "4.0.0"
}
},
"sites/studio/node_modules/@freesewing/react": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@freesewing/react/-/react-4.0.0.tgz",
"integrity": "sha512-h53FTzj11T9JewkcLm+4B+lN85JqdFMv3HEvbe7l2+C17KYSFQEky9P8Xv613Gq/WzNjzfpOWbr7YIrGdSExSA==",
"license": "MIT",
"dependencies": {
"@codemirror/lang-yaml": "^6.1.2",
"@uiw/react-codemirror": "^4.23.8",
"d3-drag": "3.0.0",
"d3-selection": "3.0.0",
"diff": "^7.0.0",
"echarts": "^5.6.0",
"echarts-for-react": "^3.0.2",
"file-saver": "^2.0.5",
"highlight.js": "^11.11.1",
"html-react-parser": "^5.2.2",
"jotai": "^2.12.1",
"jotai-location": "^0.5.5",
"luxon": "^3.5.0",
"mustache": "^4.2.0",
"pdfkit": "^0.16.0",
"react-diff-viewer-continued": "^4.0.5",
"react-dropzone": "^14.3.5",
"react-zoom-pan-pinch": "^3.7.0",
"svg-to-pdfkit": "^0.1.8",
"use-local-storage-state": "^19.5.0",
"web-worker": "^1.5.0",
"yaml": "^2.7.0"
},
"engines": {
"node": ">= 20"
},
"funding": {
"type": "individual",
"url": "https://freesewing.org/patrons/join"
},
"peerDependencies": {
"react": "^19.0.0"
}
},
"sites/studio/node_modules/@freesewing/snapseries": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@freesewing/snapseries/-/snapseries-4.0.0.tgz",
"integrity": "sha512-Fqh+Mz22xccDZGqQMpYBgKHnARSe/T1s4JCXUhKPvk0fgMg+5jNFfFUj+qTo9gaJ6qDFZYv1Wts/Smqr5nYIpQ==",
"license": "MIT",
"engines": {
"node": ">= 20"
},
"funding": {
"type": "individual",
"url": "https://freesewing.org/patrons/join"
}
},
"sites/studio/node_modules/@freesewing/utils": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@freesewing/utils/-/utils-4.0.0.tgz",
"integrity": "sha512-CUqdmCWWoMj/UkONtKAq3rtFbWt8jFZS/DhqjmryJ1m8I4UjPpzXNEekr9gSiiP2RV/AbRHMAFS4sFBPmxia0w==",
"license": "MIT",
"dependencies": {
"lodash": "^4.17.21",
"tlds": "^1.255.0"
},
"engines": {
"node": ">= 20"
},
"funding": {
"type": "individual",
"url": "https://freesewing.org/patrons/join"
}
},
"sites/studio/node_modules/diff": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz",
"integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
}
},
"sites/studio/node_modules/glob": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz",
"integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==",
"dev": true,
"license": "ISC",
"dependencies": {
"foreground-child": "^3.1.0",
"jackspeak": "^4.0.1",
"minimatch": "^10.0.0",
"minipass": "^7.1.2",
"package-json-from-dist": "^1.0.0",
"path-scurry": "^2.0.0"
},
"bin": {
"glob": "dist/esm/bin.mjs"
},
"engines": {
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"sites/studio/node_modules/jackspeak": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.0.tgz",
"integrity": "sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/cliui": "^8.0.2"
},
"engines": {
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"sites/studio/node_modules/lru-cache": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz",
"integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==",
"dev": true,
"license": "ISC",
"engines": {
"node": "20 || >=22"
}
},
"sites/studio/node_modules/minimatch": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz",
"integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"sites/studio/node_modules/path-scurry": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz",
"integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"lru-cache": "^11.0.0",
"minipass": "^7.1.2"
},
"engines": {
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
}
}
}

View file

@ -11,12 +11,15 @@
"homepage": "https://freesewing.org/",
"license": "MIT",
"scripts": {
"add": "node --experimental-json-modules --no-warnings scripts/add-software.mjs",
"new": "node --experimental-json-modules --no-warnings scripts/add-software.mjs",
"build": "lerna run build:all",
"?": "node scripts/help.mjs",
"tips": "node scripts/help.mjs",
"org": "cd sites/org && npm run start",
"eu": "cd sites/org && npm run start",
"dev": "cd sites/dev && npm run start",
"studio": "cd sites/studio && npm run start",
"kickstart": "npm install && husky && npm run tips",
"cleanall": "npx nx run-many --target=clean",
"test": "npx nx run-many --target=test",

View file

@ -32,7 +32,7 @@
# @freesewing/collection
All FreeSewing designs bundles into one pacakge, our collection
All FreeSewing designs bundled into one package, our collection

View file

@ -0,0 +1,5 @@
{
"id": "collection",
"description": "All FreeSewing designs bundled into one package, our collection",
"version": "4.0.0"
}

View file

@ -1,7 +1,7 @@
{
"name": "@freesewing/collection",
"version": "4.0.0",
"description": "All FreeSewing designs bundles into one pacakge, our collection",
"description": "All FreeSewing designs bundled into one package, our collection",
"author": "Joost De Cock <joost@joost.at> (https://github.com/joostdecock)",
"homepage": "https://freesewing.org/",
"repository": "github:freesewing/freesewing",
@ -15,7 +15,12 @@
},
"keywords": [
"freesewing",
"freesewing"
"design",
"diy",
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -75,6 +75,7 @@ export const designs = {
bent,
bibi,
bob,
bonny,
breanna,
brian,
bruce,

View file

@ -0,0 +1,5 @@
{
"id": "config",
"description": "Various configurations for FreeSewing",
"version": "4.0.0"
}

View file

@ -15,7 +15,12 @@
},
"keywords": [
"freesewing",
"freesewing"
"design",
"diy",
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -1,20 +1,5 @@
{
"id": "aaron",
"code": "Joost De Cock",
"name": "Aaron A-shirt",
"description": "A FreeSewing pattern for a A-shirt or tank top",
"design": "Joost De Cock",
"difficulty": 2,
"tags": [
"tops",
"underwear"
],
"techniques": [
"hem",
"stretch",
"knit-binding",
"curved-seam"
],
"version": "4.0.0-rc.5",
"pkg": "@freesewing/aaron"
"id": "core",
"description": "A library for creating made-to-measure sewing patterns",
"version": "4.0.0"
}

View file

@ -32,7 +32,7 @@
# @freesewing/i18n
Translation for the FreeSewing project
English translation for the FreeSewing project

5
packages/i18n/about.json Normal file
View file

@ -0,0 +1,5 @@
{
"id": "i18n",
"description": "English translation for the FreeSewing project",
"version": "4.0.0"
}

View file

@ -1,7 +1,7 @@
{
"name": "@freesewing/i18n",
"version": "4.0.0",
"description": "Translation for the FreeSewing project",
"description": "English translation for the FreeSewing project",
"author": "Joost De Cock <joost@joost.at> (https://github.com/joostdecock)",
"homepage": "https://freesewing.org/",
"repository": "github:freesewing/freesewing",

View file

@ -32,7 +32,7 @@
# @freesewing/models
Body measurements data for a range of default sizes
Body measurements data used to test FreeSewing designs
## Usage

View file

@ -0,0 +1,5 @@
{
"id": "models",
"description": "Body measurements data used to test FreeSewing designs",
"version": "4.0.0"
}

View file

@ -1,7 +1,7 @@
{
"name": "@freesewing/models",
"version": "4.0.0",
"description": "Body measurements data for a range of default sizes",
"description": "Body measurements data used to test FreeSewing designs",
"author": "Joost De Cock <joost@joost.at> (https://github.com/joostdecock)",
"homepage": "https://freesewing.org/",
"repository": "github:freesewing/freesewing",

View file

@ -32,7 +32,7 @@
# @freesewing/prettier-config
FreeSewing&#39;s shared configuration for prettier
FreeSewing shared configuration for prettier

View file

@ -0,0 +1,5 @@
{
"id": "prettier-config",
"description": "FreeSewing shared configuration for prettier",
"version": "4.0.0"
}

View file

@ -1,7 +1,7 @@
{
"name": "@freesewing/prettier-config",
"version": "4.0.0",
"description": "FreeSewing's shared configuration for prettier",
"description": "FreeSewing shared configuration for prettier",
"author": "Joost De Cock <joost@joost.at> (https://github.com/joostdecock)",
"homepage": "https://freesewing.org/",
"repository": "github:freesewing/freesewing",

View file

@ -32,7 +32,7 @@
# @freesewing/react
React components, hooks and context by&#x2F;for FreeSewing
React components, hooks and context for FreeSewing frontends

View file

@ -0,0 +1,5 @@
{
"id": "react",
"description": "React components, hooks and context for FreeSewing frontends",
"version": "4.0.0"
}

View file

@ -6,6 +6,7 @@ import { Benjamin as benjamin } from '@freesewing/benjamin'
import { Bent as bent } from '@freesewing/bent'
import { Bibi as bibi } from '@freesewing/bibi'
import { Bob as bob } from '@freesewing/bob'
import { Bonny as bonny } from '@freesewing/bonny'
import { Breanna as breanna } from '@freesewing/breanna'
import { Brian as brian } from '@freesewing/brian'
import { Bruce as bruce } from '@freesewing/bruce'
@ -25,6 +26,7 @@ import { Huey as huey } from '@freesewing/huey'
import { Hugo as hugo } from '@freesewing/hugo'
import { Jaeger as jaeger } from '@freesewing/jaeger'
import { Jane as jane } from '@freesewing/jane'
import { Lily as lily } from '@freesewing/lily'
import { Lucy as lucy } from '@freesewing/lucy'
import { Lumina as lumina } from '@freesewing/lumina'
import { Lumira as lumira } from '@freesewing/lumira'
@ -55,8 +57,6 @@ import { Wahid as wahid } from '@freesewing/wahid'
import { Walburga as walburga } from '@freesewing/walburga'
import { Waralee as waralee } from '@freesewing/waralee'
import { Yuri as yuri } from '@freesewing/yuri'
import { Lily as lily } from '@freesewing/lily'
import { Bonny as bonny } from '@freesewing/bonny'
export const designs = {
aaron,
@ -67,6 +67,7 @@ export const designs = {
bent,
bibi,
bob,
bonny,
breanna,
brian,
bruce,
@ -86,6 +87,7 @@ export const designs = {
hugo,
jaeger,
jane,
lily,
lucy,
lumina,
lumira,
@ -116,8 +118,6 @@ export const designs = {
walburga,
waralee,
yuri,
lily,
bonny,
}
export const useDesign = (design) => (designs[design] ? designs[design] : false)

View file

@ -1,7 +1,7 @@
{
"name": "@freesewing/react",
"version": "4.0.0",
"description": "React components, hooks and context by/for FreeSewing",
"description": "React components, hooks and context for FreeSewing frontends",
"author": "Joost De Cock <joost@joost.at> (https://github.com/joostdecock)",
"homepage": "https://freesewing.org/",
"repository": "github:freesewing/freesewing",
@ -15,7 +15,12 @@
},
"keywords": [
"freesewing",
"freesewing"
"design",
"diy",
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -0,0 +1,5 @@
{
"id": "snapseries",
"description": "A series of common sizes for elastics and other series to be used with snapped percentage options",
"version": "4.0.0"
}

View file

@ -15,7 +15,12 @@
},
"keywords": [
"freesewing",
"freesewing"
"design",
"diy",
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -0,0 +1,5 @@
{
"id": "studio",
"description": "Initializer package for a the FreeSewing design studio: npx @freesewing/studio",
"version": "4.0.0"
}

View file

@ -15,7 +15,12 @@
},
"keywords": [
"freesewing",
"freesewing"
"design",
"diy",
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"scripts": {

View file

@ -1,6 +1,6 @@
---
title: Support
sidebar_class_name: tw-hidden
sidebar_class_name: tw:hidden
---
import { RoleBlock } from '@freesewing/react/components/Role'

View file

@ -1,8 +1,5 @@
import path from 'node:path'
import { themes as prismThemes } from 'prism-react-renderer'
//import designs from '../../config/software/designs.json'
import tailwindcss from 'tailwindcss'
import autoprefixer from 'autoprefixer'
import { docusaurusPlugins } from './plugins/index.mjs'
import smartypants from 'remark-smartypants'
const config = {
@ -22,51 +19,7 @@ const config = {
/*
* We need to make sure we can import from .mjs files
*/
plugins: [
() => ({
name: 'mjs-loader',
configureWebpack() {
return {
module: {
rules: [
{
test: /\.mjs$/,
include: /node_modules/,
type: 'javascript/auto',
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
},
},
},
{
test: /\.mjs$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-react'],
},
},
},
],
},
}
},
}),
async function myPlugin() {
return {
name: 'docusaurus-tailwindcss',
configurePostCss(postcssOptions) {
// Appends TailwindCSS and AutoPrefixer.
postcssOptions.plugins.push(tailwindcss)
postcssOptions.plugins.push(autoprefixer)
return postcssOptions
},
}
},
],
plugins: docusaurusPlugins,
i18n: { defaultLocale: 'en', locales: ['en'] },
presets: [
[
@ -84,6 +37,11 @@ const config = {
],
],
themeConfig: {
colorMode: {
// Do not be tempted to change these
disableSwitch: true,
respectPrefersColorScheme: true,
},
image: 'img/freesewing-social-card.png',
navbar: {
title: 'FreeSewing Studio',

View file

@ -29,24 +29,25 @@
"@freesewing/plugin-i18n": "latest",
"@freesewing/plugin-theme": "latest",
"@freesewing/plugin-timing": "latest",
"autoprefixer": "^10.4.20",
"clsx": "^2.0.0",
"daisyui": "^4.12.23",
"lodash": "^4.17.21",
"postcss": "^8.4.47",
"prism-react-renderer": "^2.3.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-markdown": "^9.0.1",
"remark-smartypants": "^3.0.2",
"tailwindcss": "^3.4.14"
"remark-smartypants": "^3.0.2"
},
"devDependencies": {
"@babel/plugin-syntax-import-attributes": "^7.25.6",
"@docusaurus/module-type-aliases": "^3.7.0",
"@docusaurus/types": "^3.7.0",
"@tailwindcss/postcss": "^4.1.3",
"autoprefixer": "^10.4.20",
"daisyui": "^5.0.19",
"glob": "^11.0.0",
"gray-matter": "^4.0.3",
"postcss": "^8.4.47",
"tailwindcss": "^4.1.3",
"yaml-loader": "^0.8.1"
},
"browserslist": {

View file

@ -0,0 +1,28 @@
export function esmPlugin() {
return {
name: 'esm-plugin',
configureWebpack() {
return {
module: {
rules: [
{
test: /\.mjs$/,
include: /node_modules/,
type: 'javascript/auto',
},
{
test: /\.mjs$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-react'],
},
},
},
],
},
}
},
}
}

View file

@ -0,0 +1,4 @@
import { esmPlugin } from './esm.mjs'
import { tailwindPlugin } from './tailwind.mjs'
export const docusaurusPlugins = [esmPlugin, tailwindPlugin]

View file

@ -0,0 +1,14 @@
import tailwindPostcss from '@tailwindcss/postcss'
import autoprefixer from 'autoprefixer'
export async function tailwindPlugin() {
return {
name: 'tailwind-plugin',
configurePostCss(postcssOptions) {
// Appends TailwindCSS and AutoPrefixer.
postcssOptions.plugins.push(tailwindPostcss)
postcssOptions.plugins.push(autoprefixer)
return postcssOptions
},
}
}

View file

@ -0,0 +1,6 @@
module.exports = {
plugins: {
'@tailwindcss/postcss': {},
autoprefixer: {},
},
}

View file

@ -24,7 +24,7 @@ export function BareLayout({
children = null,
footer = false,
noHeader = false,
className = 'tw-bg-transparent tw-p-0 tw-m-0',
className = 'tw:bg-transparent tw:p-0 tw:m-0',
title = 'FreeSewing.org',
description = 'Free bespoke sewing patterns',
}) {

View file

@ -1,154 +1,59 @@
/**
* Any CSS included here will be global. The classic template
* bundles Infima by default. Infima is a CSS framework designed to
* work well for content-centric websites.
*/
/* You can override the default Infima variables here. */
:root {
/* Colors from tailwind that we use here*/
--sky-300: #7dd3fc;
--sky-400: #38bdf8;
--sky-500: #0ea5e9;
--sky-600: #0284c7;
--sky-700: #0369a1;
--pink-300: #f9a8d4;
--pink-500: #ec4899;
--neutral-50: #fafafa;
--neutral-100: #f5f5f5;
--neutral-200: #e5e5e5;
--neutral-400: #a3a3a3;
--neutral-500: #737373;
--neutral-600: #525252;
--neutral-900: #0a0a0a;
--amber-600: #d97706;
--red-500: #ef4444;
--blue-500: #3b82f6;
--pink-500: #ec4899;
--violet-500: #8b5cf6;
/* Color Palette */
--ifm-color-primary: var(--sky-500);
--ifm-color-primary-dark: var(--sky-600);
--ifm-color-primary-light: var(--sky-400);
--ifm-color-secondary: var(--sky-300);
--ifm-color-tertiary: var(--pink-500);
/* Text Colors */
--ifm-font-color-base: var(--neutral-900);
--ifm-font-color-light: var(--neutral-50);
--ifm-font-color-secondary: var(--sky-500);
/* State colors */
--ifm-color-success: var(--sky-400);
/* Background Colors */
--ifm-background-color: #fcfcfc;
--ifm-background-color-secondary: var(--neutral-100);
/* Borders and Outlines */
--ifm-border-color: var(--neutral-200);
--ifm-outline-color: var(--pink-300);
/* Link colors */
--ifm-link-color: var(--sky-600);
--ifm-link-hover-color: var(--sky-700);
/* Button Colors */
--ifm-button-color: var(--neutral-50);
--ifm-button-background-color: var(--sky-500);
--ifm-button-background-hover-color: var(--sky-700);
--ifm-button-border-color: var(--sky-600);
/* Font Sizes and Spacing */
--ifm-font-size-base: 16px;
--ifm-line-height-base: 1.5;
--ifm-spacing-unit: 8px;
--ifm-spacing-base: 16px;
/* Sidebar/Navigation Customizations */
--ifm-sidebar-background-color: var(--neutral-50);
--ifm-sidebar-link-color: var(--neutral-500);
--ifm-sidebar-link-hover-color: var(--sky-600);
--ifm-sidebar-active-link-color: var(--sky-600);
--ifm-sidebar-item-spacing: 8px;
/* Navbar Customizations */
--ifm-navbar-background-color: var(--neutral-50);
--ifm-navbar-link-color: var(--neutral-900);
--ifm-navbar-link-hover-color: var(--sky-500);
/* Footer colors */
--ifm-footer-background-color: var(--neutral-100);
--ifm-footer-link-color: var(--sky-600);
/*
* FreeSewing pattern vars
*/
'--pattern-bg':var(--neutral-50);
'--pattern-fabric':var(--neutral-900);
'--pattern-lining':var(--emerald-500);
'--pattern-interfacing':var(--neutral-400);
,'--pattern-canvas': var(--amber-600);
'--pattern-various':var(--red-500);
'--pattern-mark':var(--blue-500);
'--pattern-contrast':var(--pink-500);
'--pattern-note':var(--violet-500);
}
/* For readability concerns, you should choose a lighter palette in dark mode. */
[data-theme='dark'] {
/* Text Colors */
--ifm-font-color-base: var(--neutral-200);
--ifm-font-color-light: var(--neutral-50);
/* Background Colors */
--ifm-background-color: var(--neutral-900);
--ifm-background-color-secondary: var(--neutral-100);
/* Borders and Outlines */
--ifm-border-color: var(--neutral-200);
/* Link colors */
--ifm-link-color: var(--sky-400);
--ifm-link-hover-color: var(--sky-500);
/* Button Colors */
--ifm-button-color: var(--neutral-600);
/* Navbar Customizations */
--ifm-navbar-background-color: var(--neutral-900);
--ifm-navbar-link-color: var(--neutral-50);
--ifm-navbar-link-hover-color: var(--sky-300);
/* Footer colors */
--ifm-footer-background-color: var(--neutral-900);
--ifm-footer-link-color: var(--sky-300);
/*
* FreeSewing pattern vars
*/
'--pattern-bg':var(--neutral-900);
'--pattern-fabric':var(--neutral-5);
'--pattern-lining':var(--emerald-500);
'--pattern-interfacing':var(--neutral-400);
,'--pattern-canvas': var(--amber-600);
'--pattern-various':var(--red-500);
'--pattern-mark':var(--blue-500);
'--pattern-contrast':var(--pink-500);
'--pattern-note':var(--violet-500);
@import 'tailwindcss' prefix(tw);
@plugin "daisyui" {
prefix: 'daisy-';
}
@import './light.css';
@import './dark.css';
/*
* Add CSS for code
*/
@import './code.css';
@import './code.css' layer(base);
/*
* Add styling for FreeSewing patterns
*/
@import './patterns.css';
@import './patterns.css' layer(base);
@source '../**/*.{js,mjs,mdx}';
@source '../../docs/**/*.mdx';
@source '../../node_modules/daisyui/**/*.{js,mjs,ts,tsx}';
@source '../../node_modules/@freesewing/react/components/**/*.mjs';
@source '../../node_modules/@freesewing/react/context/**/*.mjs';
@source '../../node_modules/@freesewing/react/hooks/**/*.mjs';
@source '../../node_modules/@freesewing/utils/src/*.mjs';
@custom-variant dark (&:where(data-theme="dark"], data-theme="dark"] *));
@theme {
--aspect-9\/16: 9 / 16;
}
/*
The default border color has changed to `currentcolor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentcolor);
}
}
@utility markdown {
& ul {
@apply tw:list-inside tw:list-disc tw:ml-4;
}
}
@layer base {
div.footer__copyright {
font-size: 0.8rem;
}
@ -193,10 +98,9 @@ figcaption.mdx {
padding: 0 0.5rem;
font-size: 90%;
}
/*
* fixes
*/
.mdx p {
margin: 0.75rem 0;
}
.avatar img {
width: var(--ifm-avatar-photo-size);
height: var(--ifm-avatar-photo-size);
@ -220,10 +124,6 @@ figcaption.mdx {
.markdown ul > li > p {
display: inline;
}
/*
* Make the 'edit this page' link look consistent
*/
a.theme-edit-this-page {
display: flex;
flex-direction: row;
@ -250,36 +150,56 @@ a.daisy-btn-neutral:hover {
color: #fff;
text-decoration: none;
}
}
/*
* fixes
*/
a.no-hover-decoration:hover {
text-decoration: none;
}
a.tw\:daisy-btn {
color: inherit;
}
a.tw\:daisy-btn-primary.tw\:daisy-btn-outline {
color: var(--color-primary);
}
a.tw\:daisy-btn-primary.tw\:daisy-btn-outline:hover {
color: var(--color-primary-content);
text-decoration: none;
}
.tw\:daisy-menu {
--daisy-menu-active-fg: currentColor;
--daisy-menu-active-bg: var(--bg-transparent);
}
/*
* Make the 'edit this page' link look consistent
*/
/*
* Add Tailwindcss
*/
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components {
/* Applied styles for common HTML tags */
h1 {
@apply tw-text-5xl tw-pt-5 tw-pb-4 tw-font-light tw-tracking-tight lg:tw-text-6xl;
@apply tw:text-5xl tw:pt-5 tw:pb-4 tw:font-light tw:tracking-tight tw:lg:text-6xl;
}
h2 {
@apply tw-text-3xl tw-pt-4 tw-pb-3 tw-font-black tw-m-0 tw-tracking-tight lg:tw-text-4xl;
@apply tw:text-3xl tw:pt-4 tw:pb-3 tw:font-black tw:m-0 tw:tracking-tight tw:lg:text-4xl;
}
h3 {
@apply tw-text-2xl tw-pt-3 tw-pb-2 tw-font-extrabold tw-tracking-tight tw-m-0 lg:tw-text-3xl;
@apply tw:text-2xl tw:pt-3 tw:pb-2 tw:font-extrabold tw:tracking-tight tw:m-0 tw:lg:text-3xl;
}
h4 {
@apply tw-text-xl tw-pt-2 tw-pb-1 tw-font-bold tw-m-0 tw-tracking-tight lg:tw-text-2xl;
@apply tw:text-xl tw:pt-2 tw:pb-1 tw:font-bold tw:m-0 tw:tracking-tight tw:lg:text-2xl;
}
h5 {
@apply tw-text-lg tw-py-1 tw-font-semibold tw-m-0 tw-tracking-tight lg:tw-text-xl;
@apply tw:text-lg tw:py-1 tw:font-semibold tw:m-0 tw:tracking-tight tw:lg:text-xl;
}
h6 {
@apply tw-text-base tw-py-1 tw-font-medium tw-italic tw-m-0 tw-tracking-tight lg:tw-text-lg;
}
.markdown ul {
@apply tw-list-inside tw-list-disc tw-ml-4;
@apply tw:text-base tw:py-1 tw:font-medium tw:italic tw:m-0 tw:tracking-tight tw:lg:text-lg;
}
}
nav.navbar {

View file

@ -0,0 +1,229 @@
[data-theme='dark']:root,
html[data-theme='dark'] {
/* Color Palette */
--ifm-color-primary: oklch(0.685 0.169 237.323);
--ifm-color-primary-dark: oklch(0.588 0.158 241.966);
--ifm-color-primary-light: oklch(0.746 0.16 232.661);
--ifm-color-secondary: oklch(0.828 0.111 230.318);
--ifm-color-tertiary: oklch(0.656 0.241 354.308);
/* Text Colors */
--ifm-font-color-base: oklch(0.97 0 0);
--ifm-font-color-light: oklch(0.985 0 0);
--ifm-font-color-secondary: oklch(0.685 0.169 237.323);
/* State colors */
--ifm-color-success: oklch(0.746 0.16 232.661);
/* Background Colors */
--ifm-background-color: oklch(0.269 0 0);
--ifm-background-color-secondary: oklch(0.97 0 0);
/* Borders and Outlines */
--ifm-border-color: oklch(0.922 0 0);
--ifm-outline-color: oklch(0.823 0.12 346.018);
/* Link colors */
--ifm-link-color: oklch(0.746 0.16 232.661);
--ifm-link-hover-color: oklch(0.828 0.111 230.318);
/* Button Colors */
--ifm-button-color: oklch(0.985 0 0);
--ifm-button-background-color: oklch(0.685 0.169 237.323);
--ifm-button-background-hover-color: oklch(0.5 0.134 242.749);
--ifm-button-border-color: oklch(0.588 0.158 241.966);
/* Font Sizes and Spacing */
--ifm-font-size-base: 16px;
--ifm-line-height-base: 1.5;
--ifm-spacing-unit: 8px;
--ifm-spacing-base: 16px;
/* Sidebar/Navigation Customizations */
--ifm-sidebar-background-color: oklch(0.985 0 0);
--ifm-sidebar-link-color: oklch(0.556 0 0);
--ifm-sidebar-link-hover-color: oklch(0.588 0.158 241.966);
--ifm-sidebar-active-link-color: oklch(0.588 0.158 241.966);
--ifm-sidebar-item-spacing: 8px;
/* Navbar Customizations */
--ifm-navbar-background-color: oklch(0.985 0 0);
--ifm-navbar-link-color: oklch(0.97 0 0);
--ifm-navbar-link-hover-color: oklch(0.685 0.169 237.323);
/* Footer colors */
--ifm-footer-background-color: oklch(0.205 0 0);
--ifm-footer-link-color: oklch(0.828 0.111 230.318);
/*
* These are variables to style FreeSewing SVG output (drafts, examples, and so on)
*/
--pattern-bg: oklch(0.985 0 0);
--pattern-fabric: oklch(0.985 0 0);
--pattern-lining: oklch(0.696 0.17 162.48);
--pattern-interfacing: oklch(0.708 0 0);
--pattern-canvas: oklch(0.666 0.179 58.318);
--pattern-various: oklch(0.637 0.237 25.331);
--pattern-mark: oklch(0.623 0.214 259.815);
--pattern-contrast: oklch(0.656 0.241 354.308);
--pattern-note: oklch(0.606 0.25 292.717);
--pattern-color-0: oklch(0.637 0.237 25.331);
--pattern-color-1: oklch(0.723 0.219 149.579);
--pattern-color-2: oklch(0.623 0.214 259.815);
--pattern-color-3: oklch(0.795 0.184 86.047);
--pattern-color-4: oklch(0.656 0.241 354.308);
--pattern-color-5: oklch(0.606 0.25 292.717);
--pattern-color-6: oklch(0.704 0.14 182.503);
--pattern-color-7: oklch(0.769 0.188 70.08);
--pattern-color-8: oklch(0.667 0.295 322.15);
--pattern-color-9: oklch(0.715 0.143 215.221);
--pattern-text-xs: 0.2rem;
--pattern-text-sm: 0.3rem;
--pattern-text: 0.4rem;
--pattern-text-lg: 0.6rem;
--pattern-text-xl: 0.8rem;
--pattern-text-2xl: 1.5rem;
--pattern-text-3xl: 2rem;
--pattern-text-4xl: 3rem;
--pattern-scale: 1;
--pattern-stroke-xs: 0.2px;
--pattern-stroke-sm: 0.4px;
--pattern-stroke: 0.7px;
--pattern-stroke-lg: 1.3px;
--pattern-stroke-xl: 2px;
--pattern-stroke-2xl: 4px;
--pattern-stroke-3xl: 6px;
--pattern-stroke-4xl: 8px;
--pattern-stroke-5xl: 12px;
--pattern-stroke-6xl: 16px;
--pattern-stroke-7xl: 20px;
--pattern-sample-1: oklch(0.637 0.237 25.331);
--pattern-sample-2: oklch(0.705 0.213 47.604);
--pattern-sample-3: oklch(0.795 0.184 86.047);
--pattern-sample-4: oklch(0.768 0.233 130.85);
--pattern-sample-5: oklch(0.696 0.17 162.48);
--pattern-sample-6: oklch(0.715 0.143 215.221);
--pattern-sample-7: oklch(0.623 0.214 259.815);
--pattern-sample-8: oklch(0.606 0.25 292.717);
--pattern-sample-9: oklch(0.667 0.295 322.15);
--pattern-sample-10: oklch(0.645 0.246 16.439);
}
@plugin "daisyui/theme" {
name: 'dark';
default: false;
prefersdark: true;
color-scheme: dark;
--color-base-100: oklch(0.205 0 0);
--color-base-200: oklch(0.371 0 0);
--color-base-300: oklch(0.439 0 0);
--color-base-content: oklch(0.97 0 0);
--color-primary: oklch(0.811 0.111 293.571);
--color-primary-content: oklch(0.145 0 0);
--color-secondary: oklch(0.828 0.111 230.318);
--color-secondary-content: oklch(0.145 0 0);
--color-accent: oklch(0.833 0.145 321.434);
--color-accent-content: oklch(0.145 0 0);
--color-neutral: oklch(0.87 0 0);
--color-neutral-content: oklch(0.145 0 0);
--color-info: oklch(0.945 0.129 101.54);
--color-info-content: oklch(0.145 0 0);
--color-success: oklch(0.792 0.209 151.711);
--color-success-content: oklch(0.145 0 0);
--color-warning: oklch(0.75 0.183 55.934);
--color-warning-content: oklch(0.145 0 0);
--color-error: oklch(0.704 0.191 22.216);
--color-error-content: oklch(0.145 0 0);
/*
* These are variables to style highlighted code blocks.
*/
--code-background-color: oklch(0.269 0 0);
--code-background-highlight-color: #313131;
--code-border-color: oklch(0.205 0 0);
--code-color: oklch(0.97 0 0);
--code-font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;
--code-border-radius: 0.5rem;
--code-border-style: solid;
--code-border-width: 1;
--code-outer-padding: 0 0.5rem;
--code-inner-padding: 1rem;
/*
* These variables are used to style the highlighted tokens themselves
*/
--code-color-keyword: oklch(0.795 0.184 86.047);
--code-font-weight-keyword: bold;
--code-color-entity: oklch(0.702 0.183 293.541);
--code-font-weight-entity: bold;
--code-color-constant: oklch(0.841 0.238 128.85);
--code-color-string: oklch(0.746 0.16 232.661);
--code-font-style-string: italic;
--code-color-variable: oklch(0.673 0.182 276.935);
--code-color-comment: oklch(0.708 0 0);
--code-color-tag: oklch(0.792 0.209 151.711);
--code-color-property: oklch(0.945 0.129 101.54);
--code-font-weight-property: bold;
/*
* These are variables to style FreeSewing SVG output (drafts, examples, and so on)
*/
--pattern-bg: oklch(0.985 0 0);
--pattern-fabric: oklch(0.985 0 0);
--pattern-lining: oklch(0.696 0.17 162.48);
--pattern-interfacing: oklch(0.708 0 0);
--pattern-canvas: oklch(0.666 0.179 58.318);
--pattern-various: oklch(0.637 0.237 25.331);
--pattern-mark: oklch(0.623 0.214 259.815);
--pattern-contrast: oklch(0.656 0.241 354.308);
--pattern-note: oklch(0.606 0.25 292.717);
--pattern-color-0: oklch(0.637 0.237 25.331);
--pattern-color-1: oklch(0.723 0.219 149.579);
--pattern-color-2: oklch(0.623 0.214 259.815);
--pattern-color-3: oklch(0.795 0.184 86.047);
--pattern-color-4: oklch(0.656 0.241 354.308);
--pattern-color-5: oklch(0.606 0.25 292.717);
--pattern-color-6: oklch(0.704 0.14 182.503);
--pattern-color-7: oklch(0.769 0.188 70.08);
--pattern-color-8: oklch(0.667 0.295 322.15);
--pattern-color-9: oklch(0.715 0.143 215.221);
--pattern-text-xs: 0.2rem;
--pattern-text-sm: 0.3rem;
--pattern-text: 0.4rem;
--pattern-text-lg: 0.6rem;
--pattern-text-xl: 0.8rem;
--pattern-text-2xl: 1.5rem;
--pattern-text-3xl: 2rem;
--pattern-text-4xl: 3rem;
--pattern-scale: 1;
--pattern-stroke-xs: 0.2px;
--pattern-stroke-sm: 0.4px;
--pattern-stroke: 0.7px;
--pattern-stroke-lg: 1.3px;
--pattern-stroke-xl: 2px;
--pattern-stroke-2xl: 4px;
--pattern-stroke-3xl: 6px;
--pattern-stroke-4xl: 8px;
--pattern-stroke-5xl: 12px;
--pattern-stroke-6xl: 16px;
--pattern-stroke-7xl: 20px;
--pattern-sample-1: oklch(0.637 0.237 25.331);
--pattern-sample-2: oklch(0.705 0.213 47.604);
--pattern-sample-3: oklch(0.795 0.184 86.047);
--pattern-sample-4: oklch(0.768 0.233 130.85);
--pattern-sample-5: oklch(0.696 0.17 162.48);
--pattern-sample-6: oklch(0.715 0.143 215.221);
--pattern-sample-7: oklch(0.623 0.214 259.815);
--pattern-sample-8: oklch(0.606 0.25 292.717);
--pattern-sample-9: oklch(0.667 0.295 322.15);
--pattern-sample-10: oklch(0.645 0.246 16.439);
}

View file

@ -0,0 +1,233 @@
/* Infima vars (for docusaurus native styles) */
:root {
/* Color Palette */
--ifm-color-primary: oklch(0.685 0.169 237.323);
--ifm-color-primary-dark: oklch(0.588 0.158 241.966);
--ifm-color-primary-light: oklch(0.746 0.16 232.661);
--ifm-color-secondary: oklch(0.828 0.111 230.318);
--ifm-color-tertiary: oklch(0.656 0.241 354.308);
/* Text Colors */
--ifm-font-color-base: oklch(0.205 0 0);
--ifm-font-color-light: oklch(0.985 0 0);
--ifm-font-color-secondary: oklch(0.685 0.169 237.323);
/* State colors */
--ifm-color-success: oklch(0.746 0.16 232.661);
/* Background Colors */
--ifm-background-color: oklch(0.985 0 0);
--ifm-background-color-secondary: oklch(0.97 0 0);
/* Borders and Outlines */
--ifm-border-color: oklch(0.922 0 0);
--ifm-outline-color: oklch(0.823 0.12 346.018);
/* Link colors */
--ifm-link-color: oklch(0.588 0.158 241.966);
--ifm-link-hover-color: oklch(0.5 0.134 242.749);
/* Button Colors */
--ifm-button-color: oklch(0.985 0 0);
--ifm-button-background-color: oklch(0.685 0.169 237.323);
--ifm-button-background-hover-color: oklch(0.5 0.134 242.749);
--ifm-button-border-color: oklch(0.588 0.158 241.966);
/* Font Sizes and Spacing */
--ifm-font-size-base: 16px;
--ifm-line-height-base: 1.5;
--ifm-spacing-unit: 8px;
--ifm-spacing-base: 16px;
/* Sidebar/Navigation Customizations */
--ifm-sidebar-background-color: oklch(0.985 0 0);
--ifm-sidebar-link-color: oklch(0.556 0 0);
--ifm-sidebar-link-hover-color: oklch(0.588 0.158 241.966);
--ifm-sidebar-active-link-color: oklch(0.588 0.158 241.966);
--ifm-sidebar-item-spacing: 8px;
/* Navbar Customizations */
--ifm-navbar-background-color: oklch(0.985 0 0);
--ifm-navbar-link-color: oklch(0.205 0 0);
--ifm-navbar-link-hover-color: oklch(0.685 0.169 237.323);
/* Footer colors */
--ifm-footer-background-color: oklch(0.922 0 0);
--ifm-footer-link-color: oklch(0.588 0.158 241.966);
/*
* These are variables to style FreeSewing SVG output (drafts, examples, and so on)
*/
--pattern-bg: oklch(0.985 0 0);
--pattern-fabric: oklch(0.205 0 0);
--pattern-lining: oklch(0.696 0.17 162.48);
--pattern-interfacing: oklch(0.708 0 0);
--pattern-canvas: oklch(0.666 0.179 58.318);
--pattern-various: oklch(0.637 0.237 25.331);
--pattern-mark: oklch(0.623 0.214 259.815);
--pattern-contrast: oklch(0.656 0.241 354.308);
--pattern-note: oklch(0.606 0.25 292.717);
--pattern-color-0: oklch(0.637 0.237 25.331);
--pattern-color-1: oklch(0.723 0.219 149.579);
--pattern-color-2: oklch(0.623 0.214 259.815);
--pattern-color-3: oklch(0.795 0.184 86.047);
--pattern-color-4: oklch(0.656 0.241 354.308);
--pattern-color-5: oklch(0.606 0.25 292.717);
--pattern-color-6: oklch(0.704 0.14 182.503);
--pattern-color-7: oklch(0.769 0.188 70.08);
--pattern-color-8: oklch(0.667 0.295 322.15);
--pattern-color-9: oklch(0.715 0.143 215.221);
--pattern-text-xs: 0.2rem;
--pattern-text-sm: 0.3rem;
--pattern-text: 0.4rem;
--pattern-text-lg: 0.6rem;
--pattern-text-xl: 0.8rem;
--pattern-text-2xl: 1.5rem;
--pattern-text-3xl: 2rem;
--pattern-text-4xl: 3rem;
--pattern-scale: 1;
--pattern-stroke-xs: 0.2px;
--pattern-stroke-sm: 0.4px;
--pattern-stroke: 0.7px;
--pattern-stroke-lg: 1.3px;
--pattern-stroke-xl: 2px;
--pattern-stroke-2xl: 4px;
--pattern-stroke-3xl: 6px;
--pattern-stroke-4xl: 8px;
--pattern-stroke-5xl: 12px;
--pattern-stroke-6xl: 16px;
--pattern-stroke-7xl: 20px;
--pattern-sample-1: oklch(0.637 0.237 25.331);
--pattern-sample-2: oklch(0.705 0.213 47.604);
--pattern-sample-3: oklch(0.795 0.184 86.047);
--pattern-sample-4: oklch(0.768 0.233 130.85);
--pattern-sample-5: oklch(0.696 0.17 162.48);
--pattern-sample-6: oklch(0.715 0.143 215.221);
--pattern-sample-7: oklch(0.623 0.214 259.815);
--pattern-sample-8: oklch(0.606 0.25 292.717);
--pattern-sample-9: oklch(0.667 0.295 322.15);
--pattern-sample-10: oklch(0.645 0.246 16.439);
}
@plugin "daisyui/theme" {
name: 'light';
default: true;
prefersdark: false;
color-scheme: light;
/*fontFamily: 'system-ui, sans-serif',*/
--ifm-link-hover-color: oklch(0.685 0.169 237.323);
--color-base-100: oklch(0.985 0 0);
--color-base-200: oklch(0.97 0 0);
--color-base-300: oklch(0.87 0 0);
--color-base-content: oklch(0.371 0 0);
--color-primary: oklch(0.541 0.281 293.009);
--color-primary-content: oklch(0.985 0 0);
--color-secondary: oklch(0.685 0.169 237.323);
--color-secondary-content: oklch(0.985 0 0);
--color-accent: oklch(0.667 0.295 322.15);
--color-accent-content: oklch(0.985 0 0);
--color-neutral: oklch(0.205 0 0);
--color-neutral-content: oklch(0.985 0 0);
--color-info: oklch(0.905 0.182 98.111);
--color-info-content: oklch(0.205 0 0);
--color-success: oklch(0.627 0.194 149.214);
--color-success-content: oklch(0.985 0 0);
--color-warning: oklch(0.646 0.222 41.116);
--color-warning-content: oklch(0.985 0 0);
--color-error: oklch(0.577 0.245 27.325);
--color-error-content: oklch(0.985 0 0);
/*
* These are variables to style highlighted code blocks.
*/
--code-background-color: oklch(0.269 0 0);
--code-background-highlight-color: #313131;
--code-border-color: oklch(0.205 0 0);
--code-color: oklch(0.97 0 0);
--code-font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;
--code-border-radius: 0.5rem;
--code-border-style: solid;
--code-border-width: 1;
--code-outer-padding: 0 0.5rem;
--code-inner-padding: 1rem;
/*
* These variables are used to style the highlighted tokens themselves
*/
--code-color-keyword: oklch(0.795 0.184 86.047);
--code-font-weight-keyword: bold;
--code-color-entity: oklch(0.702 0.183 293.541);
--code-font-weight-entity: bold;
--code-color-constant: oklch(0.841 0.238 128.85);
--code-color-string: oklch(0.746 0.16 232.661);
--code-font-style-string: italic;
--code-color-variable: oklch(0.673 0.182 276.935);
--code-color-comment: oklch(0.708 0 0);
--code-color-tag: oklch(0.792 0.209 151.711);
--code-color-property: oklch(0.945 0.129 101.54);
--code-font-weight-property: bold;
/*
* These are variables to style FreeSewing SVG output (drafts, examples, and so on)
*/
--pattern-bg: oklch(0.985 0 0);
--pattern-fabric: oklch(0.205 0 0);
--pattern-lining: oklch(0.696 0.17 162.48);
--pattern-interfacing: oklch(0.708 0 0);
--pattern-canvas: oklch(0.666 0.179 58.318);
--pattern-various: oklch(0.637 0.237 25.331);
--pattern-mark: oklch(0.623 0.214 259.815);
--pattern-contrast: oklch(0.656 0.241 354.308);
--pattern-note: oklch(0.606 0.25 292.717);
--pattern-color-0: oklch(0.637 0.237 25.331);
--pattern-color-1: oklch(0.723 0.219 149.579);
--pattern-color-2: oklch(0.623 0.214 259.815);
--pattern-color-3: oklch(0.795 0.184 86.047);
--pattern-color-4: oklch(0.656 0.241 354.308);
--pattern-color-5: oklch(0.606 0.25 292.717);
--pattern-color-6: oklch(0.704 0.14 182.503);
--pattern-color-7: oklch(0.769 0.188 70.08);
--pattern-color-8: oklch(0.667 0.295 322.15);
--pattern-color-9: oklch(0.715 0.143 215.221);
--pattern-text-xs: 0.2rem;
--pattern-text-sm: 0.3rem;
--pattern-text: 0.4rem;
--pattern-text-lg: 0.6rem;
--pattern-text-xl: 0.8rem;
--pattern-text-2xl: 1.5rem;
--pattern-text-3xl: 2rem;
--pattern-text-4xl: 3rem;
--pattern-scale: 1;
--pattern-stroke-xs: 0.2px;
--pattern-stroke-sm: 0.4px;
--pattern-stroke: 0.7px;
--pattern-stroke-lg: 1.3px;
--pattern-stroke-xl: 2px;
--pattern-stroke-2xl: 4px;
--pattern-stroke-3xl: 6px;
--pattern-stroke-4xl: 8px;
--pattern-stroke-5xl: 12px;
--pattern-stroke-6xl: 16px;
--pattern-stroke-7xl: 20px;
--pattern-sample-1: oklch(0.637 0.237 25.331);
--pattern-sample-2: oklch(0.705 0.213 47.604);
--pattern-sample-3: oklch(0.795 0.184 86.047);
--pattern-sample-4: oklch(0.768 0.233 130.85);
--pattern-sample-5: oklch(0.696 0.17 162.48);
--pattern-sample-6: oklch(0.715 0.143 215.221);
--pattern-sample-7: oklch(0.623 0.214 259.815);
--pattern-sample-8: oklch(0.606 0.25 292.717);
--pattern-sample-9: oklch(0.667 0.295 322.15);
--pattern-sample-10: oklch(0.645 0.246 16.439);
}

View file

@ -6,8 +6,8 @@ import { linkClasses } from '@freesewing/utils'
import Link from '@docusaurus/Link'
const Card = ({ title, children, icon }) => (
<div className={`tw-px-8 tw-bg-primary/5 tw-py-10 tw-rounded-lg tw-block tw-shadow-lg tw-grow`}>
<h2 className="tw-mb-4 tw-text-inherit tw-flex tw-flex-row tw-gap-4 tw-justify-between tw-items-center tw-font-medium">
<div className={`tw:px-8 tw:bg-primary/5 tw:py-10 tw:rounded-lg tw:block tw:shadow-lg tw:grow`}>
<h2 className="tw:mb-4 tw:text-inherit tw:flex tw:flex-row tw:gap-4 tw:justify-between tw:items-center tw:font-medium">
{title}
{icon}
</h2>
@ -25,44 +25,44 @@ const meta = {
export default function Home() {
return (
<DocusaurusPage DocusaurusLayout={Layout} {...meta} Layout={false}>
<div className="tw-max-w-7xl tw-mx-auto tw-my-12 tw-px-4">
<div className="tw-text-center">
<FreeSewingIcon className="tw-w-48 tw-h-48 tw-mx-auto tw-pr-3" />
<h1 className="tw-font-black tw-text-5xl lg:tw-text-7xl tw-tracking-tighter tw-mb-0 tw-pb-0">
<div className="tw:max-w-7xl tw:mx-auto tw:my-12 tw:px-4">
<div className="tw:text-center">
<FreeSewingIcon className="tw:w-48 tw:h-48 tw:mx-auto tw:pr-3" />
<h1 className="tw:font-black tw:text-5xl lg:tw:text-7xl tw:tracking-tighter tw:mb-0 tw:pb-0">
FreeSewing Studio
</h1>
<h2 className="tw-text-xl lg:tw-text-3xl tw-font-medium tw-tracking-tighter tw-mt-0 tw-pt-0">
<h2 className="tw:text-xl lg:tw:text-3xl tw:font-medium tw:tracking-tighter tw:mt-0 tw:pt-0">
Design your own bespoke sewing patterns
</h2>
</div>
<div className="tw-flex tw-flex-col tw-gap-8 md:tw-grid md:tw-grid-cols-2 md:tw-gap-4 tw-mt-12 md:tw-mt-20 md:tw-px-4">
<div className="tw:flex tw:flex-col tw:gap-8 md:tw:grid md:tw:grid-cols-2 md:tw:gap-4 tw:mt-12 md:tw:mt-20 md:tw:px-4">
<Card
title="Batteries Included"
icon={<OkIcon className="tw-w-12 tw-h-12 tw-text-success" stroke={4} />}
icon={<OkIcon className="tw:w-12 tw:h-12 tw:text-success" stroke={4} />}
>
<p className="tw-font-medium tw-text-lg tw-mb-4">
<p className="tw:font-medium tw:text-lg tw:mb-4">
The FreeSewing Studio ships with <b>all FreeSewing designs</b> on board. You can
utilize them as they are, or extend them for your own needs.
</p>
<p className="tw-font-medium tw-text-lg tw-mb-4">
<p className="tw:font-medium tw:text-lg tw:mb-4">
The studio is also integrated with the FreeSewing backend, so you can access all your
account data, and can store your patterns.
</p>
<p className="tw-font-medium tw-text-lg tw-text-center tw-mt-4">
<p className="tw:font-medium tw:text-lg tw:text-center tw:mt-4">
<Link
className="tw-daisy-btn tw-daisy-btn-primary hover:tw-no-underline hover:tw-text-primary-content"
className="tw:daisy-btn tw:daisy-btn-primary hover:tw:no-underline hover:tw:text-primary-content"
href="/collection"
>
Browse Collection
<span className="tw:text-primary-content">Browse Collection</span>
</Link>
</p>
</Card>
<Card
title="Add your own designs"
icon={<OkIcon className="tw-w-12 tw-h-12 tw-text-success" stroke={4} />}
icon={<OkIcon className="tw:w-12 tw:h-12 tw:text-success" stroke={4} />}
>
<p className="tw-font-medium tw-text-lg tw-mb-4">
<p className="tw:font-medium tw:text-lg tw:mb-4">
<Link href="/add" className={linkClasses}>
Adding your own custom design
</Link>{' '}
@ -72,16 +72,16 @@ export default function Home() {
</Link>
.
</p>
<p className="tw-font-medium tw-text-lg">
<p className="tw:font-medium tw:text-lg">
You can start a new design from scratch, or start from one of our blocks. Just pick
the option you want, and your new design will be added to the studio.
</p>
<p className="tw-font-medium tw-text-lg tw-text-center tw-mt-4">
<p className="tw:font-medium tw:text-lg tw:text-center tw:mt-4">
<Link
className="tw-daisy-btn tw-daisy-btn-primary hover:tw-no-underline hover:tw-text-primary-content"
className="tw:daisy-btn tw:daisy-btn-primary hover:tw:no-underline hover:tw:text-primary-content"
href="/add"
>
Add a new design
<span className="tw:text-primary-content">Add a new design</span>
</Link>
</p>
</Card>

View file

@ -1,66 +0,0 @@
<!--
Sometimes class names are added in a way that prevents TailwindCSS
from detecting them, which means they won't be included in the CSS
bundle. When you've got one of those, you can simply add them to
the class list below, as tailwind is configured to include this
file in it's scans.
-->
<!-- Loading status -->
<div className="fixed top-0 md:top-28 md:max-w-2xl md:px-4 md:mx-auto"></div>
<progress className="progress progress-secondary" />
<div className='bg-gradient-to-r from-accent from-0% to-0% to-primary'></div>
<div className='bg-gradient-to-r from-accent from-10% to-10% to-primary'></div>
<div className='bg-gradient-to-r from-accent from-20% to-20% to-primary'></div>
<div className='bg-gradient-to-r from-accent from-30% to-30% to-primary'></div>
<div className='bg-gradient-to-r from-accent from-40% to-40% to-primary'></div>
<div className='bg-gradient-to-r from-accent from-50% to-50% to-primary'></div>
<div className='bg-gradient-to-r from-accent from-60% to-60% to-primary'></div>
<div className='bg-gradient-to-r from-accent from-70% to-70% to-primary'></div>
<div className='bg-gradient-to-r from-accent from-80% to-80% to-primary'></div>
<div className='bg-gradient-to-r from-accent from-90% to-90% to-primary'></div>
<div className='bg-gradient-to-r from-accent from-100% to-100% to-primary'></div>
<!-- Classes for the Popout component -->
<p class="border-accent bg-accent text-accent" />
<p class="border-secondary bg-secondary text-secondary" />
<p class="border-error bg-error text-error" />
<p class="border-warning bg-warning text-warning" />
<p class="border-info bg-info text-info" />
<p class="border-success bg-success text-success" />
<p class="border-primary bg-primary text-primary" />
<!-- Background opacity for highlighted lines in code -->
<code class="bg-yellow-300 bg-opacity-5" />
<code class="bg-orange-300 bg-opacity-5 opacity-80 line-through decoration-orange-500" />
<!-- badges for tags -->
<badge class="badge badge-success hover:badge-success" />
<badge class="badge badge-warning hover:badge-warning" />
<badge class="badge badge-error hover:badge-error" />
<badge class="badge badge-info hover:badge-info" />
<badge class="badge badge-ghost hover:badge-ghost" />
<badge class="badge badge-outline hover:badge-outline" />
<badge class="badge badge-primary hover:badge-primary" />
<badge class="badge badge-secondary hover:badge-secondary" />
<badge class="badge badge-accent hover:badge-accent" />
<badge class="badge badge-neutral hover:badge-neutral" />
<!-- choice button colors -->
<div className="hover:bg-accent hover:bg-opacity-20 hover:border-accent"></div>
<div className="hover:bg-error hover:bg-opacity-20 hover:border-error"></div>
<div className="hover:bg-success hover:bg-opacity-20 hover:border-success"></div>
<!-- iFrame embed -->
<iframe className="w-full aspect-[16/9]"/>
<!-- toc list padding -->
<li className="pl-3"></li>
<!-- homepage -->
<a className="bg-accent text-accent-content"></a>
<!-- support -->
<div className="bg-gradient-to-tr from-secondary from-10% to-primary"></div>
<div className="bg-gradient-to-tr from-accent from-10% to-primary"></div>

View file

@ -1,30 +0,0 @@
// Handle themes
import { light, dark } from './themes/index.mjs'
import daisyui from 'daisyui'
export default {
content: [
'./src/**/*.{js,mjs,mdx}',
'./node_modules/daisyui/**/*.{js,mjs,ts,tsx}',
'./node_modules/@freesewing/react/components/**/*.mjs',
'./node_modules/@freesewing/react/context/**/*.mjs',
'./node_modules/@freesewing/react/hooks/**/*.mjs',
'./node_modules/@freesewing/react/lib/tailwind-force.mjs',
'./node_modules/@freesewing/utils/src/*.mjs',
'./tailwind-force.html',
],
plugins: [daisyui],
prefix: 'tw-',
daisyui: {
themes: [{ dark, light }],
logs: true,
prefix: 'daisy-',
},
theme: {
extend: {
aspectRatio: {
'9/16': '9 / 16',
},
},
},
}

View file

@ -0,0 +1,5 @@
{
"id": "utils",
"description": "A number of utilities, typically used by FreeSewing frontend code",
"version": "4.0.0"
}

View file

@ -15,7 +15,12 @@
},
"keywords": [
"freesewing",
"freesewing"
"design",
"diy",
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "./src/index.mjs",

View file

@ -32,7 +32,7 @@
# @freesewing/core-plugins
An umbrella package of essential plugins that are bundled with FreeSewing&#39;s core library
An umbrella package of essential plugins that are bundled with the FreeSewing core library
# Plugins

View file

@ -1,4 +1,5 @@
{
"version": "4.0.0-rc.8",
"name": "core-plugins"
"id": "core-plugins",
"description": "An umbrella package of essential plugins that are bundled with the FreeSewing core library",
"version": "4.0.0"
}

View file

@ -1,7 +1,7 @@
{
"name": "@freesewing/core-plugins",
"version": "4.0.0",
"description": "An umbrella package of essential plugins that are bundled with FreeSewing's core library",
"description": "An umbrella package of essential plugins that are bundled with the FreeSewing core library",
"author": "Joost De Cock <joost@joost.at> (https://github.com/joostdecock)",
"homepage": "https://freesewing.org/",
"repository": "github:freesewing/freesewing",

View file

@ -1,4 +1,5 @@
{
"version": "4.0.0-rc.8",
"name": "plugin-annotations"
"id": "plugin-annotations",
"description": "A FreeSewing plugin that provides pattern annotations",
"version": "4.0.0"
}

View file

@ -15,14 +15,12 @@
},
"keywords": [
"freesewing",
"plugin",
"sewing pattern",
"sewing",
"design",
"parametric design",
"made to measure",
"diy",
"fashion"
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -1,4 +1,5 @@
{
"version": "4.0.0-rc.8",
"name": "plugin-bin-pack"
"id": "plugin-bin-pack",
"description": "A FreeSewing plugin that adds a bin-pack algorithm to the core library",
"version": "4.0.0"
}

View file

@ -15,14 +15,12 @@
},
"keywords": [
"freesewing",
"plugin",
"sewing pattern",
"sewing",
"design",
"parametric design",
"made to measure",
"diy",
"fashion"
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -1,4 +1,5 @@
{
"version": "4.0.0-rc.8",
"name": "plugin-bust"
"id": "plugin-bust",
"description": "A FreeSewing plugin that helps with bust-adjusting menswear patterns",
"version": "4.0.0"
}

View file

@ -15,14 +15,12 @@
},
"keywords": [
"freesewing",
"plugin",
"sewing pattern",
"sewing",
"design",
"parametric design",
"made to measure",
"diy",
"fashion"
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -1,4 +1,5 @@
{
"version": "4.0.0-rc.8",
"name": "plugin-flip"
"id": "plugin-flip",
"description": "A FreeSewing plugin to flip parts horizontally",
"version": "4.0.0"
}

View file

@ -15,14 +15,12 @@
},
"keywords": [
"freesewing",
"plugin",
"sewing pattern",
"sewing",
"design",
"parametric design",
"made to measure",
"diy",
"fashion"
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -1,4 +1,6 @@
{
"version": "4.0.0-rc.8",
"name": "plugin-gore"
"name": "plugin-gore",
"description": "A FreeSewing plugin to generate gores for a semi-sphere or dome",
"id": "4.0.0",
"version": "4.0.0"
}

View file

@ -1,5 +1,5 @@
{
"name": "@freesewing/plugin-gore",
"name": "@freesewing/4.0.0",
"version": "4.0.0",
"description": "A FreeSewing plugin to generate gores for a semi-sphere or dome",
"author": "AlfaLyr (https://github.com/alfalyr)",
@ -15,14 +15,12 @@
},
"keywords": [
"freesewing",
"plugin",
"sewing pattern",
"sewing",
"design",
"parametric design",
"made to measure",
"diy",
"fashion"
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -1,4 +1,5 @@
{
"version": "4.0.0-rc.8",
"name": "plugin-i18n"
"id": "plugin-i18n",
"description": "A FreeSewing plugin for pattern translation",
"version": "4.0.0"
}

View file

@ -15,14 +15,12 @@
},
"keywords": [
"freesewing",
"plugin",
"sewing pattern",
"sewing",
"design",
"parametric design",
"made to measure",
"diy",
"fashion"
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -1,4 +1,5 @@
{
"version": "4.0.0-rc.8",
"name": "plugin-measurements"
"id": "plugin-measurements",
"description": "A FreeSewing plugin that adds additional measurements that can be calculated from existing ones",
"version": "4.0.0"
}

View file

@ -15,14 +15,12 @@
},
"keywords": [
"freesewing",
"plugin",
"sewing pattern",
"sewing",
"design",
"parametric design",
"made to measure",
"diy",
"fashion"
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -1,4 +1,5 @@
{
"version": "4.0.0-rc.8",
"name": "plugin-mirror"
"id": "plugin-mirror",
"description": "A FreeSewing plugin to mirror points or paths",
"version": "4.0.0"
}

View file

@ -15,14 +15,12 @@
},
"keywords": [
"freesewing",
"plugin",
"sewing pattern",
"sewing",
"design",
"parametric design",
"made to measure",
"diy",
"fashion"
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -1,4 +1,5 @@
{
"version": "4.0.0-rc.8",
"name": "plugin-path-utils"
"id": "plugin-path-utils",
"description": "A FreeSewing plugin that adds various path helper macros",
"version": "4.0.0"
}

View file

@ -15,14 +15,12 @@
},
"keywords": [
"freesewing",
"plugin",
"sewing pattern",
"sewing",
"design",
"parametric design",
"made to measure",
"diy",
"fashion"
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -1,4 +1,5 @@
{
"version": "4.0.0-rc.8",
"name": "plugin-ringsector"
"id": "plugin-ringsector",
"description": "A FreeSewing plugin to draft a ring sector (think part of a donut)",
"version": "4.0.0"
}

View file

@ -15,14 +15,12 @@
},
"keywords": [
"freesewing",
"plugin",
"sewing pattern",
"sewing",
"design",
"parametric design",
"made to measure",
"diy",
"fashion"
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -1,4 +1,5 @@
{
"version": "4.0.0-rc.8",
"name": "plugin-round"
"id": "plugin-round",
"description": "A FreeSewing plugin to round corners",
"version": "4.0.0"
}

View file

@ -15,14 +15,12 @@
},
"keywords": [
"freesewing",
"plugin",
"sewing pattern",
"sewing",
"design",
"parametric design",
"made to measure",
"diy",
"fashion"
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -1,4 +1,5 @@
{
"version": "4.0.0-rc.8",
"name": "plugin-sprinkle"
"id": "plugin-sprinkle",
"description": "A FreeSewing plugin to bulk-add snippets to your pattern",
"version": "4.0.0"
}

View file

@ -15,14 +15,12 @@
},
"keywords": [
"freesewing",
"plugin",
"sewing pattern",
"sewing",
"design",
"parametric design",
"made to measure",
"diy",
"fashion"
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -1,4 +1,5 @@
{
"version": "4.0.0-rc.8",
"name": "plugin-svgattr"
"id": "plugin-svgattr",
"description": "A FreeSewing plugin to set SVG attributes",
"version": "4.0.0"
}

View file

@ -15,14 +15,12 @@
},
"keywords": [
"freesewing",
"plugin",
"sewing pattern",
"sewing",
"design",
"parametric design",
"made to measure",
"diy",
"fashion"
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -32,7 +32,7 @@
# @freesewing/plugin-theme
A FreeSewing plugin that provides a default theme

View file

@ -1,4 +1,4 @@
{
"version": "4.0.0-rc.8",
"version": "4.0.0",
"name": "plugin-theme"
}

View file

@ -1,7 +1,6 @@
{
"name": "@freesewing/plugin-theme",
"name": "@freesewing/undefined",
"version": "4.0.0",
"description": "A FreeSewing plugin that provides a default theme",
"author": "Joost De Cock <joost@joost.at> (https://github.com/joostdecock)",
"homepage": "https://freesewing.org/",
"repository": "github:freesewing/freesewing",
@ -15,14 +14,12 @@
},
"keywords": [
"freesewing",
"plugin",
"sewing pattern",
"sewing",
"design",
"parametric design",
"made to measure",
"diy",
"fashion"
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -1,4 +1,5 @@
{
"version": "4.0.0-rc.8",
"name": "plugin-timing"
"id": "plugin-timing",
"description": "A FreeSewing plugin to record the time it takes to draft your pattern parts",
"version": "4.0.0"
}

View file

@ -15,14 +15,12 @@
},
"keywords": [
"freesewing",
"plugin",
"sewing pattern",
"sewing",
"design",
"parametric design",
"made to measure",
"diy",
"fashion"
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -1,4 +1,5 @@
{
"version": "4.0.0-rc.8",
"name": "plugin-versionfree-svg"
"id": "plugin-versionfree-svg",
"description": "A FreeSewing plugin to keep version info out of your SVG to allow easy diffs across versions",
"version": "4.0.0"
}

View file

@ -15,14 +15,12 @@
},
"keywords": [
"freesewing",
"plugin",
"sewing pattern",
"sewing",
"design",
"parametric design",
"made to measure",
"diy",
"fashion"
"fashion",
"made to measure",
"parametric design",
"sewing"
],
"type": "module",
"module": "src/index.mjs",

View file

@ -6,188 +6,163 @@ import { banner } from './banner.mjs'
import mustache from 'mustache'
import { execSync } from 'child_process'
import languages from '../config/languages.json' assert { type: 'json' }
// Software
import designs from '../config/software/designs.json' assert { type: 'json' }
import plugins from '../config/software/plugins.json' assert { type: 'json' }
import { getDesigns, getPlugins } from './software.mjs'
const type = process.argv[2]
const designs = await getDesigns()
const plugins = await getPlugins()
// Add new design
if (type === 'design') {
console.clear()
console.log(banner)
addDesign()
}
/*
* Ask input about what the user wants
*/
export const getInput = async () => {
let type = false
let template = false
let name = false
let finalName = false
const cwd = process.cwd()
// Add new plugin
else if (type === 'plugin') {
console.clear()
console.log(banner)
addPlugin()
} else
console.log(`
Usage:
// while we're not finalized on a name
while (finalName === false) {
// request type
type = (
await prompts({
type: 'select',
name: 'type',
message: ' Would you like to add a new design, or a new plugin?',
choices: [
{
title: 'Add a new FreeSewing Design',
value: 'design',
description: 'Add a new design',
},
{
title: 'Add a new FreeSewing Plugin',
value: 'plugin',
description: 'Add a new plugin',
},
],
})
).type
${chalk.bold.blue('npm run new design')} 👉 Adds a new design
${chalk.bold.blue('npm run new plugin')} 👉 Adds a new plugin
${chalk.bold.blue('npm run new')} ${chalk.yellow('[anything else]')} 👉 Shows this help
`)
// If they Ctrl-C'd out of the prompt, exit here
if (!type) process.exit()
async function addDesign() {
console.log(`
${chalk.bold.yellow('👕 Add a new design')}
${chalk.gray('≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡')}
We're going to add a new design to this repository. That's awesome 🎉
Let's start by picking a name. Naming things is hard 😬
We'd appreciate if you pick:
- a firstname like ${chalk.green('alex')}, ${chalk.green('jordan')}, ${chalk.green(
'ezra'
)}, or ${chalk.green('logan')}
- that is an aliteration with the kind of design, like ${chalk.green(
'wahid'
)} for a ${chalk.green('w')}aistcoat
Bonus points for picking a name that embraces diversity 🌈 🏾
`)
const { name } = await prompts({
// request a name
name = (
await prompts({
type: 'text',
name: 'name',
message: 'What name would you like the design to have? ([a-z0-9_] only)',
validate: validateDesignName,
message: ` Give a name for your new ${type}. Please stick to [a-z] only. 🏷️ `,
initial: type === 'plugin' ? 'coffee' : 'xiaomao',
})
).name
// check whether a folder with that name already exists
const dest = path.join(cwd, type + 's', type === 'plugin' ? `plugin-${name}` : name)
try {
const dir = await opendir(dest)
dir.close()
} catch {
// the folder didn't exist, so we're good to go
finalName = true
break
}
// the folder did exist, bail out
const { nextStep } = await prompts({
type: 'select',
name: 'nextStep',
message: 'It looks like that folder already exists. What should we do?',
choices: [
{ title: 'Go back', value: 'rename', description: 'Choose a different name' },
{
title: 'Exit',
value: 'exit',
description: 'Exit here so you can investigate',
},
],
})
if (name) {
console.log('\n' + ` Alright, let's add ${chalk.green(name)} 🪄`)
createDesign(name)
// if they said rename, we loop again. Otherwise, we exit
if (nextStep !== 'rename') process.exit()
}
// request a template
if (type === 'design')
template = (
await prompts({
type: 'select',
name: 'template',
message: ' What template would you like to start from?',
choices: [
{ title: 'Create a design from scratch', value: 'base' },
{ title: 'Extend the Brian block (flat-sleeve block for menswear)', value: 'brian' },
{ title: 'Extend the Bent block (two-part-sleeve block for menswear)', value: 'bent' },
{ title: 'Extend the Bella block (womenswear bodice block)', value: 'bella' },
{ title: 'Extend the Breanna block (womenswear bodice block)', value: 'breanna' },
{ title: 'Extend the Titan block (unisex trouser block)', value: 'titan' },
],
initial: 0,
})
).template
return { type, name: name.toLowerCase(), template }
}
async function addDesign({ name, template }) {
if (name && template) {
const valid = validateDesignName(name)
if (valid !== true) {
console.log(valid)
process.exit()
}
createDesign(name, template)
execSync('npm run reconfigure')
console.log(` Installing & linking dependencies...`)
execSync('npm install')
console.log(` All done 🎉`)
try {
console.log(`
${chalk.bold.yellow('✨ Summary')}
${chalk.gray('≡≡≡≡≡≡≡≡≡≡')}
👉 We've created your design skeleton at ${chalk.green('designs/' + name)}
👉 We've configured the packages via the ${chalk.green('package.json')} file
👉 We've added ${chalk.green('designs/' + name)} to the local repository
👉 We've added ${chalk.green(name)} to the FreeSewing collection
${chalk.bold.yellow('✏️ Make it your own')}
${chalk.gray('≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡')}
Hhere's a few other things you can configure:
👉 ${chalk.yellow('Author')}: Credit where credit is due; Add yourself as author in ${chalk.green(
'config/exceptions.yaml'
)}
👉 ${chalk.yellow('Description')}: We used placeholder metadata; Update it in ${chalk.green(
'config/software/designs.json'
)}
👉 ${chalk.yellow(
'Dependencies'
)}: If you need additional plugins or patterns to extend, update ${chalk.green(
🚧 We used placeholder metadata; Update it in ${chalk.green('designs/' + name + '/about.json')}
📦 If you need additional plugins or patterns to extend, update ${chalk.green(
'config/dependencies.yaml'
)}
If you change any of these, run ${chalk.blue('npm run reconfigure')} to update the package(s).
${chalk.bold.yellow('👷 Get to work')}
${chalk.gray('≡≡≡≡≡≡≡≡≡≡≡≡≡≡')}
🚀 You can now start the org development environment with ${chalk.blue('npm run org')}
🚀 You can now start the studio with ${chalk.blue('npm run studio')}
📖 Documentation is available at ${chalk.green('https://freesewing.dev/')}
🤓 Happy hacking
`)
} catch (err) {
console.log(err)
}
}
}
async function addPlugin() {
console.log(`
${chalk.bold.yellow('👕 Add a new plugin')}
${chalk.gray('≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡')}
We're going to add a new plugin to this repository. That's awesome 🎉
Let's start by picking the name for this plugin 🏷
Try to keep it to one word that explains what the plugin does e.g. ${chalk.green(
'flip'
)}, ${chalk.green('mirror')},
${chalk.green('round')}.
`)
const { name } = await prompts({
type: 'text',
name: 'name',
message: 'What name would you like the plugin to have? ([a-z] only)',
validate: validatePluginName,
})
async function addPlugin({ name }) {
if (name) {
console.log('\n' + ` Alright, let's add ${chalk.green(name)} to plugins 🪄`)
const valid = validatePluginName(name)
if (valid !== true) {
console.log(valid)
process.exit()
}
createPlugin(name)
execSync('npm run reconfigure')
console.log(` All done 🎉`)
try {
console.log(`
${chalk.bold.yellow('✨ Summary')}
${chalk.gray('≡≡≡≡≡≡≡≡≡≡')}
👉 We've created your plugin skeleton at ${chalk.green('plugins/plugin-' + name)}
👉 We've configured the packages via the ${chalk.green('package.json')} file
${chalk.bold.yellow('✏️ Make it your own')}
${chalk.gray('≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡')}
Hhere's a few other things you can configure:
👉 ${chalk.yellow('Author')}: Credit where credit is due; Add yourself as author in ${chalk.green(
'config/exceptions.yaml'
🚧 We used a placeholder description; Update it in ${chalk.green(
'plugins/plugin-' + name + '/about.json'
)}
👉 ${chalk.yellow('Description')}: We used a placeholder description; Update it in ${chalk.green(
'config/software/plugins.json'
)}
👉 ${chalk.yellow(
'Dependencies'
)}: If you need additional plugins or patterns to extend, update ${chalk.green(
'config/dependencies.yaml'
👷 To make your plugin do something awesome, edit ${chalk.green(
'plugins/plugin-' + name + '/src/index.mjs'
)}
If you change any of these, run ${chalk.blue('npm run reconfigure')} to update the package(s).
${chalk.bold.yellow('👷 Get to work')}
${chalk.gray('≡≡≡≡≡≡≡≡≡≡≡≡≡≡')}
🛠 You can now start the org development environment with ${chalk.blue('npm run org')}
📖 Documentation is available at ${chalk.green('https://freesewing.dev/')}
🤓 Happy hacking
`)
} catch (err) {
console.log(err)
}
}
}
function validateDesignName(name) {
if (Object.keys(designs).indexOf(name) !== -1)
if (Object.keys(designs).includes(name.toLowerCase()))
return `Sorry but ${name} is already taken so you'll need to pick something else`
if (/^([a-z][a-z0-9_]*)$/.test(name)) return true
@ -197,7 +172,7 @@ function validateDesignName(name) {
function validatePluginName(name) {
const pluginName = 'plugin-' + name
if ([...Object.keys(plugins)].indexOf(pluginName) !== -1)
if (Object.keys(plugins).includes(pluginName.toLowerCase()))
return `Sorry but ${pluginName} is already taken so you'll need to pick something else`
if (/^([a-z]+)$/.test(name)) return true
@ -221,7 +196,7 @@ function createDesign(name) {
tags: ['tagname'],
techniques: ['techname'],
}
write(['config', 'software', 'designs.json'], JSON.stringify(orderDesigns(designs), null, 2))
//write(['config', 'software', 'designs.json'], JSON.stringify(orderDesigns(designs), null, 2))
// Create folders
mkdir([...design, 'src'])
@ -275,8 +250,8 @@ function createPlugin(name) {
description,
})
plugins[pluginName] = description
write(['config', 'software', 'plugins.json'], JSON.stringify(orderPlugins(plugins), null, 2))
//Create about.json
templateOut([...template, 'about.json.mustache'], [...plugin, 'about.json'], { name })
// Create index.mjs
templateOut([...template, 'src', 'index.mjs.mustache'], [...plugin, 'src', 'index.mjs'], {
@ -349,3 +324,11 @@ function orderPlugins(plugins) {
return newPlugins
}
// Say hi, then prompt for input
console.log(banner, '\n\n')
const input = await getInput()
// Add new design
if (input.type === 'design') addDesign(input)
if (input.type === 'plugin') addPlugin(input)

253
scripts/fs.mjs Normal file
View file

@ -0,0 +1,253 @@
/*
* Various helper methods to handle file system access
*/
import fs from 'fs'
import path from 'path'
import { glob } from 'glob'
/**
* Re-export these
*/
export { fs, path, glob }
/**
* The monorepo root folder
*/
export const root = path.resolve(path.basename(import.meta.url), '..')
/**
* Copies a file
*
* @param {arrau} src - Source file
* @param {array} dst - Destination file
* @param {object} options - Options for the fs.cp call in NodeJS
*
*/
export async function cp(src, dst, options = {}) {
if (!Array.isArray(src)) src = [src]
if (!Array.isArray(dst)) dst = [dst]
try {
await fs.promises.cp(path.resolve(root, ...src), path.resolve(root, ...dst), options)
} catch (err) {
return false
}
return true
}
/**
* Removes a file
*
* @param {array} file - Path to the file to remove
* @param {object} options - Options for NodeJS' rm method
*
*/
export async function rm(file, options = { force: true }) {
if (!Array.isArray(file)) file = [file]
try {
await fs.promises.rm(path.resolve(root, ...file), options)
} catch (err) {
return false
}
return true
}
/**
* Reads a folder from disk with an optional glob pattern
*
* @param {string} (relative) path to the file to read
* @param {funtion} onError - a method to call on error
*
* @return {string} File contents, or false in case of trouble
*/
export async function globDir(
folderPath, // The (relative) path to the folder
pattern = '**/*' // Glob pattern to match
) {
if (!Array.isArray(folderPath)) folderPath = [folderPath]
let list = []
try {
list = await glob(path.resolve(root, ...folderPath) + '/' + pattern)
} catch (err) {
if (err) console.log(err)
return false
}
return list
}
/**
* Creates a directory/folder
*
* @param {string} dirPath - (relative) path to the folder to create
* @param {funtion} onError - a method to call on error
*
* @return {string} File contents, or false in case of trouble
*/
export async function mkdir(
dirPath, // The (relative) path to the folder to create
onError // Method to run on error
) {
if (!Array.isArray(dirPath)) dirPath = [dirPath]
let dir
try {
dir = path.resolve(root, ...dirPath)
await fs.promises.mkdir(dir, { recursive: true })
} catch (err) {
if (onError) onError(err)
return false
}
return true
}
/**
* Reads a file from disk
*
* @param {string} (relative) path to the file to read
* @param {funtion} onError - a method to call on error
*
* @return {string} File contents, or false in case of trouble
*/
export async function readFile(
filePath, // The (relative) path to the file
onError, // Method to run on error
binary = false
) {
if (!Array.isArray(filePath)) filePath = [filePath]
let content, file
try {
file = path.resolve(root, ...filePath)
content = await fs.promises.readFile(file, binary ? undefined : 'utf-8')
} catch (err) {
if (onError) onError(err)
return false
}
return content
}
/**
* Reads a JSON file from disk and parses it
*
* @param {string} path - (relative) path to the file to read
* @param {string} onError - a string to log on error rather than the default
*
* @return {string} File contents, or false in case of trouble
*/
export async function readJsonFile(
filePath, // The (relative) path to the file
onError // Method to run on error
) {
if (!Array.isArray(filePath)) filePath = [filePath]
let content
try {
content = await readFile(path.join(root, ...filePath), onError, true)
content = JSON.parse(content)
} catch (err) {
if (onError) onError(err)
return false
}
return content
}
/**
* Writes a file to disk
*
* @param {string} filePath - (relative) path to the file to write
* @param {string} data - the data to write to disk
* @param {function} log - a logger instance (or false)
* @param {octal} mode - a mode for chmod
*
* @return {bool} true of success, false in case of trouble
*/
export async function writeFile(
filePath, // The (relative) path to the file
data, // The data to write to disk
log = false,
mode = 0o666
) {
if (!Array.isArray(filePath)) filePath = [filePath]
let file
try {
file = path.resolve(root, ...filePath)
await fs.promises.mkdir(path.dirname(file), { recursive: true })
await fs.promises.writeFile(file, data)
await fs.promises.chmod(file, mode)
} catch (err) {
if (log) log.warn(err, `Failed to write file: ${file}`)
else console.log(`Failed to write file: ${file}`)
return false
}
return true
}
/**
* Writes a JSON file to disk
*
* @param {string} filePath - (relative) path to the file to write
* @param {string} data - the data to write to disk as a Javascript object
*
* @return {bool} true of success, false in case of trouble
*/
export async function writeJsonFile(filePath, data, log, mode) {
return await writeFile(filePath, JSON.stringify(data, null, 2), log, mode)
}
/**
* Reads the contents of a directory (non-recursive)
*
* @param {string} dirPath - (relative) path to the directory to read
* @param {funtion} onError - a method to call on error
*/
export async function readDirectory(dirPath, onError) {
if (!Array.isArray(dirPath)) dirPath = [dirPath]
let files
try {
const dir = path.resolve(root, ...dirPath)
files = await fs.promises.readdir(dir)
} catch (err) {
if (onError) onError(err)
return false
}
return files
}
/**
* Copies a folder recursively
*
* @param {string} srcDir - The source folder to copy
* @param {string} dstDir - The destination folder
*/
export async function copyFolderRecursively(srcDir, dstDir) {
/*
* Ensure target folder exists
*/
await mkdir(dstDir)
/*
* Glob all files to copy
* Generate relative from and to arrays
*/
const files = (await globDir(srcDir, '**/*'))
.sort()
.map((target) => target.split(root).pop().slice(1).split('/'))
.map((target) => ({
from: target,
to: [...dstDir, ...target.slice(srcDir.length)],
}))
/*
* Copy files, create folders
*/
for (const op of files) {
const stat = fs.statSync(path.join(root, ...op.from))
if (stat.isDirectory()) await mkdir(op.to)
else await cp(op.from, op.to)
}
}

View file

@ -1,18 +1,28 @@
import path from 'path'
import fs from 'fs'
import { glob } from 'glob'
//import path from 'path'
//import fs from 'fs'
import {
fs,
cp,
readFile,
writeFile,
path,
glob,
copyFolderRecursively,
root,
readJsonFile,
writeJsonFile,
} from './fs.mjs'
//import { glob } from 'glob'
import yaml from 'js-yaml'
import chalk from 'chalk'
import mustache from 'mustache'
import conf from '../lerna.json' assert { type: 'json' }
const { version } = conf
import { software, publishedTypes as types, plugins } from '../config/software/index.mjs'
import { getSoftware } from './software.mjs'
//import { software, publishedTypes as types, plugins } from '../config/software/index.mjs'
import { collection } from '@freesewing/collection'
import { capitalize } from '../packages/utils/src/index.mjs'
// Working directory
const cwd = process.cwd()
/*
* When we're building a site (on Netlify for example) SITEBUILD
* will be set and we'll do things differently to speed up the build.
@ -26,7 +36,7 @@ if (SITEBUILD) console.log('Site build | Configure monorepo accordingly')
* This object holds info about the repository
*/
const repo = {
path: cwd,
path: root,
defaults: readConfigFile('defaults.yaml'),
keywords: readConfigFile('keywords.yaml'),
badges: SITEBUILD ? null : readConfigFile('badges.yaml'),
@ -41,13 +51,17 @@ const repo = {
readme: SITEBUILD ? null : readTemplateFile('readme.dflt.md'),
pluginTests: SITEBUILD ? null : readTemplateFile('plugin.test.mjs'),
designTests: SITEBUILD ? null : readTemplateFile('design.test.mjs.mustache'),
data: SITEBUILD ? null : readTemplateFile('data.dflt.mjs.mustache'),
collection: {
pkg: readTemplateFile('collection-pkg.mustache'),
hook: readTemplateFile('collection-hook.mustache'),
},
dirs: foldersByType(),
contributors: SITEBUILD ? null : fs.readFileSync(path.join(cwd, 'CONTRIBUTORS.md'), 'utf-8'),
},
contributors: SITEBUILD ? null : fs.readFileSync(path.join(root, 'CONTRIBUTORS.md'), 'utf-8'),
ac: SITEBUILD
? null
: JSON.parse(fs.readFileSync(path.join(cwd, '.all-contributorsrc'), 'utf-8')),
: JSON.parse(fs.readFileSync(path.join(root, '.all-contributorsrc'), 'utf-8')),
software: await getSoftware(),
hiddenDesigns: ['examples', 'legend', 'plugintest', 'rendertest', 'magde'],
}
/*
@ -56,25 +70,64 @@ const repo = {
const log = process.stdout
// Step 0: Avoid symlink so Windows users don't complain
const copyThese = [
const cpFolders = [
{
from: ['scripts', 'banner.mjs'],
to: ['packages', 'new-design', 'lib', 'banner.mjs'],
from: ['sites', 'org', 'plugins'],
to: ['sites', 'studio', 'plugins'],
},
{
from: ['packages', 'studio', 'template', 'docs'],
to: ['sites', 'studio', 'docs'],
},
{
from: ['packages', 'studio', 'template', 'src'],
to: ['sites', 'studio', 'src'],
},
{
from: ['packages', 'studio', 'template', 'static'],
to: ['sites', 'studio', 'static'],
},
{
from: ['packages', 'studio', 'template', 'scripts'],
to: ['sites', 'studio', 'scripts'],
},
{
from: ['sites', 'org', 'src', 'css'],
to: ['sites', 'studio', 'src', 'css'],
},
]
for (const cp of copyThese) {
fs.copyFile(path.join(repo.path, ...cp.from), path.join(repo.path, ...cp.to), () => null)
}
const cpFiles = [
{
from: ['sites', 'org', 'babel.config.mjs'],
to: ['sites', 'studio', 'babel.config.mjs'],
},
{
from: ['sites', 'org', 'postcss.config.js'],
to: ['sites', 'studio', 'postcss.config.js'],
},
{
from: ['sites', 'org', 'plugins'],
to: ['sites', 'studio', 'plugins'],
},
{
from: ['sites', 'org', 'src', 'pages', 'style.mjs'],
to: ['sites', 'studio', 'src', 'pages', 'style.mjs'],
},
{
from: ['sites', 'studio', 'add.mdx'],
to: ['sites', 'studio', 'docs', 'add.mdx'],
},
]
for (const op of cpFolders) await copyFolderRecursively(op.from, op.to)
for (const op of cpFiles) await cp(op.from, op.to)
// Step 1: Generate main README file from template
if (!SITEBUILD) {
log.write(chalk.blueBright('Generating out main README file...'))
fs.writeFileSync(
path.join(repo.path, 'README.md'),
mustache.render(
fs.readFileSync(path.join(repo.path, 'config', 'templates', 'readme.main.md'), 'utf-8'),
{ allcontributors: repo.ac.contributors.length }
) + repo.contributors
log.write(chalk.blueBright('Templating out main README file...'))
const template = await readFile(['config', 'templates', 'readme.main.md'])
await writeFile(
'README.md',
mustache.render(template, { allcontributors: repo.ac.contributors.length }) + repo.contributors
)
log.write(chalk.green(' Done\n'))
}
@ -87,67 +140,67 @@ if (!SITEBUILD) {
// Step 3: Generate package.json, README, and CHANGELOG
log.write(chalk.blueBright('Generating package-specific files...'))
for (const pkg of Object.values(software)) {
fs.writeFileSync(
path.join(cwd, pkg.folder, pkg.name, 'package.json'),
JSON.stringify(packageJson(pkg), null, 2) + '\n'
)
for (const type of ['designs', 'packages', 'plugins']) {
for (const folder of Object.keys(repo.software[type])) {
const about = await readJsonFile([type, folder, 'about.json'])
await writeJsonFile([type, folder, 'package.json'], packageJson(folder, type, about))
if (!SITEBUILD) {
if (pkg.type !== 'site') {
fs.writeFileSync(path.join(cwd, pkg.folder, pkg.name, 'README.md'), readme(pkg))
fs.writeFileSync(path.join(cwd, pkg.folder, pkg.name, 'CHANGELOG.md'), changelog(pkg))
if ([...collection, 'bonny'].includes(pkg.name)) {
const aboutFile = path.join(cwd, 'designs', pkg.name, 'about.json')
const about = JSON.parse(fs.readFileSync(aboutFile, 'utf-8'))
about.version = version
about.pkg = `@freesewing/${about.id}`
fs.writeFileSync(aboutFile, JSON.stringify(about, null, 2))
}
await writeFile([type, folder, 'README.md'], readme(folder, type, about))
await writeFile([type, folder, 'CHANGELOG.md'], changelog(folder, type, about))
await writeJsonFile([type, folder, 'about.json'], { ...about, version })
}
}
}
log.write(chalk.green(' Done\n'))
// Step 4: Generate overall CHANGELOG.md
if (!SITEBUILD) fs.writeFileSync(path.join(repo.path, 'CHANGELOG.md'), changelog('global'))
if (!SITEBUILD) await writeFile('CHANGELOG.md', changelog('global'))
// Step 5: Generate tests for designs and plugins
if (!SITEBUILD) {
for (const design of collection) {
fs.writeFileSync(
path.join(repo.path, 'designs', design, 'tests', 'shared.test.mjs'),
for (const design in repo.software.designs) {
await writeFile(
['designs', design, 'tests', 'shared.test.mjs'],
mustache.render(repo.templates.designTests, { name: design, Name: capitalize(design) })
)
}
for (const plugin in plugins) {
fs.writeFileSync(
path.join(repo.path, 'plugins', plugin, 'tests', 'shared.test.mjs'),
repo.templates.pluginTests
for (const plugin in repo.software.plugins) {
await writeFile(['plugins', plugin, 'tests', 'shared.test.mjs'], repo.templates.pluginTests)
}
}
// Step 6: Generate collection package and hook dynamic files
const designList = Object.keys(repo.software.designs).filter(
(name) => !repo.hiddenDesigns.includes(name)
)
const designImports = designList
.map((name) => `import { ${capitalize(name)} as ${name} } from '@freesewing/${name}'`)
.join('\n')
await writeFile(
['packages', 'collection', 'src', 'index.mjs'],
mustache.render(repo.templates.collection.pkg, {
designImports,
designList: designList.join(',\n '),
})
)
await writeFile(
['packages', 'react', 'hooks', 'useDesign', 'index.mjs'],
mustache.render(repo.templates.collection.hook, {
designImports,
designList: designList.join(',\n '),
})
)
}
}
// All done
log.write(chalk.green(' All done\n'))
process.exit()
/*
* Generates a list of folders by type
*/
function foldersByType() {
const dirs = {}
for (const dir of types) {
dirs[dir] = glob.sync('*', { cwd: path.join(cwd, dir) })
}
return dirs
}
/**
* Reads a template file
*/
function readTemplateFile(file) {
return fs.readFileSync(path.join(cwd, 'config', 'templates', file), 'utf-8')
return fs.readFileSync(path.join(root, 'config', 'templates', file), 'utf-8')
}
/**
@ -156,19 +209,19 @@ function readTemplateFile(file) {
function readConfigFile(file, replace = false) {
if (replace)
return yaml.load(
mustache.render(fs.readFileSync(path.join(cwd, 'config', file), 'utf-8'), replace)
mustache.render(fs.readFileSync(path.join(root, 'config', file), 'utf-8'), replace)
)
return yaml.load(fs.readFileSync(path.join(cwd, 'config', file), 'utf-8'))
return yaml.load(fs.readFileSync(path.join(root, 'config', file), 'utf-8'))
}
/**
* Reads info.md from the package directory
* Returns its contents if it exists, or an empty string if not
*/
function readInfoFile(pkg) {
function readInfoFile(pkg, type) {
let markup = ''
try {
markup = fs.readFileSync(path.join(cwd, pkg.folder, pkg.name, 'info.md'), 'utf-8')
markup = fs.readFileSync(path.join(root, type, pkg, 'info.md'), 'utf-8')
} catch (err) {
return ''
}
@ -179,44 +232,36 @@ function readInfoFile(pkg) {
/**
* Returns an array of keywords for a package
*/
function keywords(pkg) {
if (pkg.type === 'site') return []
if (typeof repo.keywords[pkg.name] !== 'undefined') return repo.keywords[pkg.name]
if (typeof repo.keywords[pkg.type] !== 'undefined') return repo.keywords[pkg.type]
else {
console.log(
chalk.redBright.bold('Problem:'),
chalk.redBright(`No keywords for package ${pkg.name} which is of type ${pkg.type}`)
)
process.exit()
}
function keywords(pkg, type) {
if (typeof repo.keywords[pkg] !== 'undefined') return repo.keywords[pkg]
if (typeof repo.keywords[type] !== 'undefined') return repo.keywords[type]
if (Object.keys(repo.software.designs).includes(pkg)) return repo.keywords.design
else return repo.keywords.other
}
/**
* Returns an plain object of scripts for a package
*/
function scripts(pkg) {
function scripts(pkg, type) {
let runScripts = {}
if (pkg.type !== 'site') {
for (const key of Object.keys(repo.scripts._)) {
runScripts[key] = mustache.render(repo.scripts._[key], {
name: pkg.name,
name: pkg,
})
}
if (typeof repo.scripts._types[type] !== 'undefined') {
for (const key of Object.keys(repo.scripts._types[type])) {
runScripts[key] = mustache.render(repo.scripts._types[type][key], {
name: pkg,
})
}
}
if (typeof repo.scripts._types[pkg.type] !== 'undefined') {
for (const key of Object.keys(repo.scripts._types[pkg.type])) {
runScripts[key] = mustache.render(repo.scripts._types[pkg.type][key], {
name: pkg.name,
})
}
}
if (typeof repo.scripts[pkg.name] !== 'undefined') {
for (const key of Object.keys(repo.scripts[pkg.name])) {
if (repo.scripts[pkg.name][key] === '!') delete runScripts[key]
if (typeof repo.scripts[pkg] !== 'undefined') {
for (const key of Object.keys(repo.scripts[pkg])) {
if (repo.scripts[pkg][key] === '!') delete runScripts[key]
else
runScripts[key] = mustache.render(repo.scripts[pkg.name][key], {
name: pkg.name,
runScripts[key] = mustache.render(repo.scripts[pkg][key], {
name: pkg,
})
}
}
@ -233,16 +278,16 @@ function scripts(pkg) {
* - peer (for peerDependencies)
*
*/
function dependencies(section, pkg) {
function dependencies(section, pkg, type) {
let dependencies = {}
if (
typeof repo.dependencies._types[pkg.type] !== 'undefined' &&
typeof repo.dependencies._types[pkg.type][section] !== 'undefined'
typeof repo.dependencies._types[type] !== 'undefined' &&
typeof repo.dependencies._types[type][section] !== 'undefined'
)
dependencies = repo.dependencies._types[pkg.type][section]
if (typeof repo.dependencies[pkg.name] === 'undefined') return dependencies
if (typeof repo.dependencies[pkg.name][section] !== 'undefined')
return { ...dependencies, ...repo.dependencies[pkg.name][section] }
dependencies = repo.dependencies._types[type][section]
if (typeof repo.dependencies[pkg] === 'undefined') return dependencies
if (typeof repo.dependencies[pkg][section] !== 'undefined')
return { ...dependencies, ...repo.dependencies[pkg][section] }
return dependencies
}
@ -250,46 +295,36 @@ function dependencies(section, pkg) {
/**
* Creates a package.json file for a package
*/
function packageJson(pkg) {
function packageJson(pkg, type, about) {
let pkgConf = {}
// Let's keep these at the top
pkgConf.name = fullName(pkg.name)
pkgConf.name = fullName(about.id)
pkgConf.version = version
pkgConf.description = pkg.description
pkgConf.description = about.description
pkgConf = {
...pkgConf,
...JSON.parse(mustache.render(repo.templates.pkg, { name: pkg.name })),
...JSON.parse(mustache.render(repo.templates.pkg, { name: about.id })),
}
pkgConf.keywords = pkgConf.keywords.concat(keywords(pkg))
pkgConf.scripts = scripts(pkg)
pkgConf.keywords = pkgConf.keywords.concat(keywords(pkg, type))
pkgConf.scripts = scripts(pkg, type)
if (repo.exceptions.skipTests.indexOf(pkg.name) !== -1) {
pkgConf.scripts.test = `echo "skipping tests for ${pkg.name}"`
pkgConf.scripts.testci = `echo "skipping tests for ${pkg.name}"`
if (repo.exceptions.skipTests.includes(pkg)) {
pkgConf.scripts.test = `echo "skipping tests for ${about.id}"`
pkgConf.scripts.testci = `echo "skipping tests for ${about.id}"`
}
pkgConf.dependencies = dependencies('_', pkg)
pkgConf.devDependencies = dependencies('dev', pkg)
pkgConf.peerDependencies = dependencies('peer', pkg)
if (typeof repo.exceptions.packageJson[pkg.name] !== 'undefined') {
pkgConf.dependencies = dependencies('_', pkg, type)
pkgConf.devDependencies = dependencies('dev', pkg, type)
pkgConf.peerDependencies = dependencies('peer', pkg, type)
if (typeof repo.exceptions.packageJson[pkg] !== 'undefined') {
pkgConf = {
...pkgConf,
...repo.exceptions.packageJson[pkg.name],
...repo.exceptions.packageJson[pkg],
}
for (let key of Object.keys(repo.exceptions.packageJson[pkg.name])) {
if (repo.exceptions.packageJson[pkg.name][key] === '!') delete pkgConf[key]
for (let key of Object.keys(repo.exceptions.packageJson[pkg])) {
if (repo.exceptions.packageJson[pkg][key] === '!') delete pkgConf[key]
}
}
if (pkg.type === 'site') {
delete pkgConf.keywords
delete pkgConf.type
delete pkgConf.module
delete pkgConf.exports
delete pkgConf.files
delete pkgConf.publishConfig
pkgConf.private = true
}
return pkgConf
}
@ -325,19 +360,19 @@ function formatBadge(badge, name, fullname) {
* Returns the full (namespaced) name of a package
*/
function fullName(name) {
if (repo.exceptions.noNamespace.indexOf(name) !== -1) return name
if (repo.exceptions.noNamespace.includes(name)) return name
else return `@freesewing/${name}`
}
/**
* Creates a README.md file for a package
*/
function readme(pkg) {
function readme(pkg, type, about) {
let markup = mustache.render(repo.templates.readme, {
fullname: fullName(pkg.name),
description: pkg.description,
badges: badges(pkg.name),
info: readInfoFile(pkg),
fullname: fullName(pkg),
description: about.description,
badges: badges(pkg, type),
info: readInfoFile(pkg, type),
contributors: repo.contributors,
})
@ -349,8 +384,8 @@ function readme(pkg) {
*/
function changelog(pkg) {
let markup = mustache.render(repo.templates.changelog, {
fullname: pkg === 'global' ? 'FreeSewing (global)' : fullName(pkg.name),
changelog: pkg === 'global' ? globalChangelog() : packageChangelog(pkg.name),
fullname: pkg === 'global' ? 'FreeSewing (global)' : fullName(pkg),
changelog: pkg === 'global' ? globalChangelog() : packageChangelog(pkg),
})
return markup
@ -366,7 +401,12 @@ function globalChangelog() {
markup += '\n## ' + v
if (v !== 'Unreleased') markup += ' (' + formatDate(changes.date) + ')'
markup += '\n\n'
for (let pkg of ['global', ...Object.keys(software)]) {
for (let pkg of [
'global',
...Object.keys(repo.software.designs),
...Object.keys(repo.software.plugins),
...Object.keys(repo.software.packages),
]) {
let changed = false
for (let type of repo.changetypes) {
if (
@ -447,14 +487,7 @@ function formatDate(date) {
* Make sure we have (at least) a description for each package
*/
function validate() {
for (const type in repo.dirs) {
for (const dir of repo.dirs[type]) {
if (typeof software?.[dir]?.description !== 'string') {
log.write(chalk.redBright(` No description for package ${type}/${dir}` + '\n'))
return false
}
}
}
// Nothing to validate, perhaps we should change that
return true
}

Some files were not shown because too many files have changed in this diff Show more