diff --git a/markdown/dev/reference/api/defs/asrenderprops/en.md b/markdown/dev/reference/api/defs/asrenderprops/en.md
new file mode 100644
index 00000000000..f8f37a9e3c3
--- /dev/null
+++ b/markdown/dev/reference/api/defs/asrenderprops/en.md
@@ -0,0 +1,44 @@
+---
+title: Defs.asRenderProps()
+---
+
+Returns the Defs as render props, suitable for front-end rendering.
+
+## Signature
+
+```js
+Object defs.asRenderProps()
+```
+
+The object returned by this method will have a `list` property that
+holds all the defs, as well as a `asSvg` property that holds the result
+of [Defs.render()](/reference/api/defs/render):
+
+```js
+{
+ list: {
+ button: `
+
+
+
+
+
+`,
+ buttonhole: `
+
+`,
+ },
+ forSvg: `
+
+
+
+
+
+
+
+
+
+
+`
+}
+```
diff --git a/markdown/dev/reference/api/defs/clone/en.md b/markdown/dev/reference/api/defs/clone/en.md
new file mode 100644
index 00000000000..d2aa6f2592f
--- /dev/null
+++ b/markdown/dev/reference/api/defs/clone/en.md
@@ -0,0 +1,11 @@
+---
+title: Defs.clone()
+---
+
+Returns a Defs object that is a deep copy of this one.
+
+## Signature
+
+```js
+Defs defs.clone()
+```
diff --git a/markdown/dev/reference/api/defs/en.md b/markdown/dev/reference/api/defs/en.md
new file mode 100644
index 00000000000..b3d6c3d2da4
--- /dev/null
+++ b/markdown/dev/reference/api/defs/en.md
@@ -0,0 +1,16 @@
+---
+title: Defs
+---
+
+The `Defs` object in FreeSewing's core library represents an SVG document's
+[`defs` element](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs).
+It is not directly exposed, but it is available as the `defs` attribute
+of an [Svg object](/reference/api/svg/defs).
+
+While the methods exposed by this object are typically only used internally,
+they are documented here to facilitate development of plugins.
+
+## Defs methods
+
+
+
diff --git a/markdown/dev/reference/api/defs/get/en.md b/markdown/dev/reference/api/defs/get/en.md
new file mode 100644
index 00000000000..26bb90da568
--- /dev/null
+++ b/markdown/dev/reference/api/defs/get/en.md
@@ -0,0 +1,12 @@
+---
+title: Defs.get()
+---
+
+Returns the value of a defs entry stored under _name_.
+
+## Signature
+
+```js
+String defs.get(string name)
+```
+
diff --git a/markdown/dev/reference/api/defs/remove/en.md b/markdown/dev/reference/api/defs/remove/en.md
new file mode 100644
index 00000000000..65e32776a2d
--- /dev/null
+++ b/markdown/dev/reference/api/defs/remove/en.md
@@ -0,0 +1,15 @@
+---
+title: Defs.remove()
+---
+
+Removes the defs entry stored under _name_.
+
+
+## Signature
+
+```js
+Defs defs.remove(string name)
+```
+
+This object is chainable as it returns the `Defs` object.
+
diff --git a/markdown/dev/reference/api/defs/render/en.md b/markdown/dev/reference/api/defs/render/en.md
new file mode 100644
index 00000000000..e62e4a2a473
--- /dev/null
+++ b/markdown/dev/reference/api/defs/render/en.md
@@ -0,0 +1,27 @@
+---
+title: Defs.render()
+---
+
+Renders the added Defs as a string suitable for inclusion in an SVG document `defs` element.
+
+## Signature
+
+```js
+String defs.render()
+```
+
+This function is called by [svg.render()](/reference/api/svg/render) internally.
+Its output will look something like this:
+
+```()
+
+
+
+
+
+
+
+
+
+
+```
diff --git a/markdown/dev/reference/api/defs/set/en.md b/markdown/dev/reference/api/defs/set/en.md
new file mode 100644
index 00000000000..730dd90bf93
--- /dev/null
+++ b/markdown/dev/reference/api/defs/set/en.md
@@ -0,0 +1,17 @@
+---
+title: Defs.set()
+---
+
+Sets the defs entry stored under _name_ to _value_.
+
+## Signature
+
+```js
+Defs defs.set(
+ String name,
+ String value
+)
+```
+
+This object is chainable as it returns the `Defs` object.
+
diff --git a/markdown/dev/reference/api/defs/setifunset/en.md b/markdown/dev/reference/api/defs/setifunset/en.md
new file mode 100644
index 00000000000..e36f248fac1
--- /dev/null
+++ b/markdown/dev/reference/api/defs/setifunset/en.md
@@ -0,0 +1,17 @@
+---
+title: Defs.setIfUnset()
+---
+
+Sets the defs entry stored under _name_ to _value_, but only if it
+is not currently set to any value (if it is undefined).
+
+## Signature
+
+```js
+Defs defs.setIfUnset(
+ String name,
+ String value
+)
+```
+
+This object is chainable as it returns the `Defs` object.
diff --git a/markdown/dev/reference/api/svg/defs/en.md b/markdown/dev/reference/api/svg/defs/en.md
index 8d0a49e0241..87a33ed4bde 100644
--- a/markdown/dev/reference/api/svg/defs/en.md
+++ b/markdown/dev/reference/api/svg/defs/en.md
@@ -2,7 +2,8 @@
title: Svg.defs
---
-The `Svg.defs` property holds a string that will be rendered as [the defs
+The `Svg.defs` property holds a [Defs object](/reference/api/defs) that holds
+the contents of [the defs
section](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs) of the
SVG document.
@@ -13,22 +14,3 @@ SVG document.
/* svg.defs will be inserted */
```
-
-## Notes
-
-The defs attribute is where plugins will add additional snippets.
-
-When adding your own defs, it's important not to
-overwrite this property, but rather add your own.
-
-In other words, do this:
-
-```js
-svg.defs += myDefs
-```
-
-and don't do this:
-
-```js
-svg.defs = myDefs
-```
diff --git a/markdown/dev/reference/api/svg/en.md b/markdown/dev/reference/api/svg/en.md
index 18230d028c4..d9943170751 100644
--- a/markdown/dev/reference/api/svg/en.md
+++ b/markdown/dev/reference/api/svg/en.md
@@ -10,6 +10,6 @@ While the methods exposed by this object are only used internally,
its attributes are useful for situations where you
want to develop a plugin, or use a custom layout.
-## Svg properties
+## Svg methods & properties
diff --git a/markdown/dev/reference/css/en.md b/markdown/dev/reference/css/en.md
index 758a4738875..13fd809b9a7 100644
--- a/markdown/dev/reference/css/en.md
+++ b/markdown/dev/reference/css/en.md
@@ -2,17 +2,76 @@
title: CSS Classes
---
-We recommend using these classes to style your designs. Not only are these
+We recommend using these classes to style your designs. Not only are these
classes implemented in the `@freesewing/plugin-theme` plugin, they are also
-properly styled in our own frontends.
+properly styled in our own frontends. Furthermore, by using a common set
+of class names, anyone can adapt the styling to suit their own needs.
It is this styling that you will see below. What the various classes exactly
-look like will depend on the environment where you use FreeSewing. But what
+look like will depend on the environment where you use FreeSewing, because
+in-browser styling or SVG/PDF styling is slightly different. But what
doesn't change is the names of the classes and their purpose.
-## Stoke colors
+## Contextual colors
-These classes set the `stroke` property.
+These are the main classes that you typically want to use.
+The will set either the `stroke` or `fill` property, depending on the element you set them on.
+
+For example, when you use these classes on a path, they will set the `stroke` property.
+But if you use them on text, they will set the `fill` property.
+Which is typically what you want.
+
+
+```mjs
+({
+ Point,
+ Path,
+ points,
+ paths,
+ store,
+ options,
+ part
+}) => {
+ const colors = [
+ 'fabric',
+ 'lining',
+ 'interfacing',
+ 'canvas',
+ 'various',
+ 'mark',
+ 'contrast',
+ 'note',
+ ]
+ const w = 120
+ let y = 0
+
+ for (const color of colors) {
+ y += 12
+ paths[color] = new Path()
+ .move(new Point(0, y))
+ .line(new Point(w, y))
+ .setClass(color)
+ .addText(`path.${color}`, `left text-sm`)
+ paths[`${color}Text`] = new Path()
+ .move(new Point(0, y))
+ .line(new Point(w, y))
+ .setClass('hidden')
+ .addText(`text.${color}`, `${color} right text-sm`)
+ }
+
+ paths.noClip = new Path()
+ .move(new Point(0, -1))
+ .move(new Point(10, -1))
+
+ return part
+}
+```
+
+
+
+## Stroke colors
+
+These classes set the `stroke` property explicitly.
```mjs
@@ -44,7 +103,12 @@ These classes set the `stroke` property.
.move(new Point(0, y))
.line(new Point(w, y))
.setClass(color)
- .addText(`.${color}`, 'center')
+ .addText(`path.stroke-${color}`, `left text-sm`)
+ paths[`${color}Text`] = new Path()
+ .move(new Point(0, y))
+ .line(new Point(w, y))
+ .setClass('hidden')
+ .addText(`text.stroke-${color}`, `stroke-${color} right text-sm`)
}
paths.noClip = new Path()
@@ -58,7 +122,8 @@ These classes set the `stroke` property.
## Fill colors
-These classes set the `stroke-fill` property.
+These classes set the `stroke-fill` property. Note that we've applied a background
+to ensure the text remains readable.
```mjs
@@ -81,28 +146,31 @@ These classes set the `stroke-fill` property.
'contrast',
'note',
]
- const w = 55
+ const w = 120
let row = 1
let i = 0
- let y = 20
+ let y = 15
for (const color of colors) {
- const d = (i%2) ? 0 : 60
- points[color] = new Point(w/2+d, y*row-6).addText(`.${color}`, 'center')
+ const h = 10
+ points[`${color}PathBg`] = new Point(2, y*row+8).addText(`path.fill-${color}`, 'stroke-interfacing left text-sm')
+ points[`${color}Path`] = new Point(2, y*row+8).addText(`path.fill-${color}`, 'left text-sm')
+ points[`${color}TextBg`] = new Point(w-2, y*row+8).addText(`text.fill-${color}`, 'stroke-interfacing right text-sm')
+ points[`${color}Text`] = new Point(w-2, y*row+8).addText(`text.fill-${color}`, 'right text-sm')
paths[color] = new Path()
- .move(new Point(d, y*row))
- .line(new Point(w+d, y*row-10))
- .line(new Point(w+d, y*row))
- .line(new Point(d, y*row-10))
+ .move(new Point(0, y*row))
+ .line(new Point(w, y*row))
+ .line(new Point(w, y*row+h))
+ .line(new Point(0, y*row+h))
.close()
.setClass(`fill-${color} no-stroke`)
- if (i%2) row++
+ row++
i++
}
paths.noClip = new Path()
- .move(new Point(0, -10))
- .move(new Point(10, -1))
+ .move(new Point(0, 20))
+ .move(new Point(10, 21))
return part
}
diff --git a/scripts/addpatterndocs.js b/scripts/addpatterndocs.js
deleted file mode 100644
index 3f61ad14bc9..00000000000
--- a/scripts/addpatterndocs.js
+++ /dev/null
@@ -1,138 +0,0 @@
-const fs = require('fs')
-const path = require('path')
-const core = require('../packages/core/dist')
-const theme = require('../plugins/plugin-theme/dist')
-const pi = require('../packages/pattern-info/dist')
-const models = require('../packages/models/dist')
-const wb32 = models.withBreasts.size32
-const i18n = require('../packages/i18n/dist')
-let { capitalize } = require('../packages/core/src/utils.mjs')
-
-const missing = []
-const lacking = []
-const extra = []
-const file = 'en.md'
-const subpages = ['cutting', 'fabric', 'instructions', 'options', 'measurements', 'needs']
-
-const patternDocsPage = (pattern) => `---
-title: "Fixme"
----
-
-
-
-`
-const fixme = `---
-title: "Fixme"
----
-
-
-
-This documentation page is yet to be written.
-
-Sorry for the inconvenience.
-
-
-`
-
-const component = (comp, pattern) => `---
-title: "Fixme"
----
-
-
-
-`
-
-const patternDocsSubPage = (pattern, sub) => {
- switch (sub) {
- case 'measurements':
- case 'options':
- return component(sub, pattern)
- break
- default:
- return fixme
- }
-}
-
-const optionDocsPage = (pattern, option) =>
- `---
-title: ` +
- i18n.strings.en[`options.${pattern}.${option}.title`] +
- '\n---\n\n' +
- i18n.strings.en[`options.${pattern}.${option}.description`] +
- '\n'
-
-const present = (folder) => {
- try {
- if (fs.readFileSync(path.join(folder, file))) return true
- } catch (err) {
- return false
- }
-
- return false
-}
-
-const getSubFolders = (folder) =>
- fs
- .readdirSync(folder, { withFileTypes: true })
- .filter((dirent) => dirent.isDirectory())
- .map((dirent) => dirent.name)
-
-const checkOptionDocs = () => {
- const steps = ['markdown', 'org', 'docs', 'patterns']
- for (const pattern of pi.list) {
- // Index page
- const folder = path.join(...steps, pattern)
- const subFolders = getSubFolders(folder)
- for (const page of subpages) {
- if (subFolders.indexOf(page) === -1) lacking.push(path.join(folder, page))
- }
- for (const sub of subFolders) {
- if (subpages.indexOf(sub) === -1) extra.push(path.join(folder, sub))
- }
- if (!present(folder)) {
- fs.mkdirSync(folder, { recursive: true })
- fs.writeFileSync(path.join(folder, file), patternDocsPage(pattern))
- }
- // Sub pages
- for (const sub of subpages) {
- const folder = path.join(...steps, pattern, sub)
- if (!present(folder)) {
- fs.mkdirSync(folder, { recursive: true })
- fs.writeFileSync(path.join(folder, file), patternDocsSubPage(pattern, sub))
- }
- }
-
- // Options
- let optionFolders = getSubFolders(path.join(...steps, pattern, 'options'))
- for (const option of pi.options[pattern]) {
- // Remove this from the folder list
- const i = optionFolders.indexOf(option.toLowerCase())
- optionFolders.splice(i, 1)
- const folder = path.join(...steps, pattern, 'options', option.toLowerCase())
- if (!present(folder)) {
- missing.push(path.join(folder, file))
- fs.mkdirSync(folder, { recursive: true })
- fs.writeFileSync(path.join(folder, file), optionDocsPage(pattern, option))
- }
- }
- // Now check for extra folders
- for (const subfolder of optionFolders) {
- extra.push(path.join(...steps, pattern, 'options', subfolder))
- }
- }
-
- if (missing.length < 1 && extra.length < 1 && lacking.length < 1) {
- console.log('\n 🎉 Everything looks fine 😀\n')
- } else {
- if (missing.length > 0) {
- console.log('\n', 'Added documenation pages for the following options:', '\n\n')
- for (const line of missing) console.log(line)
- }
- if (extra.length > 0) {
- console.log('\n', 'Found extra folders that should not be there:', '\n\n')
- for (const line of extra) console.log(line)
- }
- }
-}
-
-checkOptionDocs()
diff --git a/sites/shared/styles/globals.css b/sites/shared/styles/globals.css
index fc391afe50b..3abe3b735fd 100644
--- a/sites/shared/styles/globals.css
+++ b/sites/shared/styles/globals.css
@@ -157,6 +157,8 @@
svg.freesewing.pattern rect.stroke-fabric,
svg.freesewing.pattern path.fabric,
svg.freesewing.pattern path.stroke-fabric,
+ svg.freesewing.pattern tspan.stroke-fabric,
+ svg.freesewing.pattern text.stroke-fabric,
svg.freesewing.pattern circle.fabric,
svg.freesewing.pattern circle.stroke-fabric {
@apply fs-stroke-fabric;
@@ -165,6 +167,8 @@
svg.freesewing.pattern rect.stroke-lining,
svg.freesewing.pattern path.lining,
svg.freesewing.pattern path.stroke-lining,
+ svg.freesewing.pattern tspan.stroke-lining,
+ svg.freesewing.pattern text.stroke-lining,
svg.freesewing.pattern circle.lining,
svg.freesewing.pattern circle.stroke-lining {
@apply fs-stroke-lining;
@@ -173,6 +177,8 @@
svg.freesewing.pattern rect.stroke-interfacing,
svg.freesewing.pattern path.interfacing,
svg.freesewing.pattern path.stroke-interfacing,
+ svg.freesewing.pattern text.stroke-interfacing,
+ svg.freesewing.pattern tspan.stroke-interfacing,
svg.freesewing.pattern circle.interfacing,
svg.freesewing.pattern circle.stroke-interfacing {
@apply fs-stroke-interfacing;
@@ -181,6 +187,8 @@
svg.freesewing.pattern rect.stroke-canvas,
svg.freesewing.pattern path.canvas,
svg.freesewing.pattern path.stroke-canvas,
+ svg.freesewing.pattern text.stroke-canvas,
+ svg.freesewing.pattern tspan.stroke-canvas,
svg.freesewing.pattern circle.canvas,
svg.freesewing.pattern circle.stroke-canvas {
@apply fs-stroke-canvas;
@@ -189,6 +197,8 @@
svg.freesewing.pattern rect.stroke-various,
svg.freesewing.pattern path.various,
svg.freesewing.pattern path.stroke-various,
+ svg.freesewing.pattern text.stroke-various,
+ svg.freesewing.pattern tspan.stroke-various,
svg.freesewing.pattern circle.various,
svg.freesewing.pattern circle.stroke-various {
@apply fs-stroke-various;
@@ -197,6 +207,8 @@
svg.freesewing.pattern rect.stroke-mark,
svg.freesewing.pattern path.mark,
svg.freesewing.pattern path.stroke-mark,
+ svg.freesewing.pattern text.stroke-mark,
+ svg.freesewing.pattern tspan.stroke-mark,
svg.freesewing.pattern circle.mark,
svg.freesewing.pattern circle.stroke-mark {
@apply fs-stroke-mark;
@@ -205,6 +217,8 @@
svg.freesewing.pattern rect.stroke-contrast,
svg.freesewing.pattern path.contrast,
svg.freesewing.pattern path.stroke-contrast,
+ svg.freesewing.pattern text.stroke-contrast,
+ svg.freesewing.pattern tspan.stroke-contrast,
svg.freesewing.pattern circle.contrast,
svg.freesewing.pattern circle.stroke-contrast {
@apply fs-stroke-contrast;
@@ -213,6 +227,8 @@
svg.freesewing.pattern rect.stroke-note,
svg.freesewing.pattern path.note,
svg.freesewing.pattern path.stroke-note,
+ svg.freesewing.pattern text.stroke-note,
+ svg.freesewing.pattern tspan.stroke-note,
svg.freesewing.pattern circle.note,
svg.freesewing.pattern circle.stroke-note {
@apply fs-stroke-note;
@@ -245,12 +261,16 @@
svg.freesewing.pattern path.fill-fabric,
svg.freesewing.pattern text.fill-fabric,
svg.freesewing.pattern tspan.fill-fabric,
+ svg.freesewing.pattern text.fabric,
+ svg.freesewing.pattern tspan.fabric,
svg.freesewing.pattern circle.fill-fabric {
@apply fs-fill-fabric;
}
svg.freesewing.pattern rect.fill-lining,
svg.freesewing.pattern text.fill-lining,
svg.freesewing.pattern tspan.fill-lining,
+ svg.freesewing.pattern text.lining,
+ svg.freesewing.pattern tspan.lining,
svg.freesewing.pattern path.fill-lining,
svg.freesewing.pattern circle.fill-lining {
@apply fs-fill-lining;
@@ -258,6 +278,8 @@
svg.freesewing.pattern rect.fill-interfacing,
svg.freesewing.pattern text.fill-interfacing,
svg.freesewing.pattern tspan.fill-interfacing,
+ svg.freesewing.pattern text.interfacing,
+ svg.freesewing.pattern tspan.interfacing,
svg.freesewing.pattern path.fill-interfacing,
svg.freesewing.pattern circle.fill-interfacing {
@apply fs-fill-interfacing;
@@ -265,6 +287,8 @@
svg.freesewing.pattern rect.fill-canvas,
svg.freesewing.pattern text.fill-canvas,
svg.freesewing.pattern tspan.fill-canvas,
+ svg.freesewing.pattern text.canvas,
+ svg.freesewing.pattern tspan.canvas,
svg.freesewing.pattern path.fill-canvas,
svg.freesewing.pattern circle.fill-canvas {
@apply fs-fill-canvas;
@@ -272,6 +296,8 @@
svg.freesewing.pattern rect.fill-various,
svg.freesewing.pattern text.fill-various,
svg.freesewing.pattern tspan.fill-various,
+ svg.freesewing.pattern text.various,
+ svg.freesewing.pattern tspan.various,
svg.freesewing.pattern path.fill-various,
svg.freesewing.pattern circle.fill-various {
@apply fs-fill-various;
@@ -280,12 +306,16 @@
svg.freesewing.pattern path.fill-mark,
svg.freesewing.pattern text.fill-mark,
svg.freesewing.pattern tspan.fill-mark,
+ svg.freesewing.pattern text.mark,
+ svg.freesewing.pattern tspan.mark,
svg.freesewing.pattern circle.fill-mark {
@apply fs-fill-mark;
}
svg.freesewing.pattern rect.fill-contrast,
svg.freesewing.pattern text.fill-contrast,
svg.freesewing.pattern tspan.fill-contrast,
+ svg.freesewing.pattern text.contrast,
+ svg.freesewing.pattern tspan.contrast,
svg.freesewing.pattern path.fill-contrast,
svg.freesewing.pattern circle.fill-contrast {
@apply fs-fill-contrast;
@@ -293,6 +323,8 @@
svg.freesewing.pattern rect.fill-note,
svg.freesewing.pattern text.fill-note,
svg.freesewing.pattern tspan.fill-note,
+ svg.freesewing.pattern text.note,
+ svg.freesewing.pattern tspan.note,
svg.freesewing.pattern path.fill-note,
svg.freesewing.pattern circle.fill-note {
@apply fs-fill-note;