feat: Wrapped up work on measurements sets
This commit is contained in:
parent
770b608090
commit
dbe1a04552
23 changed files with 1292 additions and 359 deletions
205
CHANGELOG.md
205
CHANGELOG.md
|
@ -1086,6 +1086,16 @@
|
|||
- Migrated from Rollup to Esbuild for all builds
|
||||
- The `pctBasedOn()` helper method for pattern config was moved to config-helpers We did not make this a breaking change since it's only used internally.
|
||||
|
||||
### i18n
|
||||
|
||||
#### Changed
|
||||
|
||||
- Migrated from Rollup to Esbuild for all builds
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Added missing lab namespace for English
|
||||
|
||||
### models
|
||||
|
||||
#### Changed
|
||||
|
@ -1225,6 +1235,12 @@
|
|||
|
||||
## 2.20.2 (2022-01-27)
|
||||
|
||||
### i18n
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Patterns options were always in English due to symlinks being used
|
||||
|
||||
|
||||
## 2.20.1 (2022-01-27)
|
||||
|
||||
|
@ -1553,6 +1569,12 @@
|
|||
|
||||
- Added support for `settings.scale`
|
||||
|
||||
### i18n
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fixed issue that was causing plugin translations to always be in English
|
||||
|
||||
|
||||
## 2.19.9 (2022-01-09)
|
||||
|
||||
|
@ -1985,6 +2007,13 @@
|
|||
|
||||
- Pattern.on() is now chainable as it returns the Pattern object
|
||||
|
||||
### i18n
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fixed bug in resolving of shared pattern options
|
||||
- Removed optional chaining which broke node v12 support
|
||||
|
||||
### snapseries
|
||||
|
||||
#### Added
|
||||
|
@ -2031,6 +2060,16 @@
|
|||
|
||||
- Handle path.offset() of very short curves with control points on the start or end point Closes [#1257](https://github.com/freesewing/freesewing/issues/1257)
|
||||
|
||||
### i18n
|
||||
|
||||
#### Added
|
||||
|
||||
- Added translations for Yuri
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Added optional chaining so missing options always lead to clear error message
|
||||
|
||||
|
||||
## 2.17.4 (2021-08-20)
|
||||
|
||||
|
@ -2043,6 +2082,12 @@
|
|||
|
||||
## 2.17.3 (2021-08-16)
|
||||
|
||||
### i18n
|
||||
|
||||
#### Added
|
||||
|
||||
- New translations
|
||||
|
||||
### utils
|
||||
|
||||
#### Fixed
|
||||
|
@ -2064,6 +2109,12 @@
|
|||
|
||||
- Added new ffsa option to let the user control the extra SA for flat-felled seams Closes [#1251](https://github.com/freesewing/freesewing/issues/1251)
|
||||
|
||||
### i18n
|
||||
|
||||
#### Added
|
||||
|
||||
- Added new ffsa option for simon & simone
|
||||
|
||||
### models
|
||||
|
||||
#### Added
|
||||
|
@ -2185,9 +2236,21 @@
|
|||
|
||||
- Fix a bug in `path.shiftAlong` where no point is returned if the distance to shift is a fraction of one step (1/25mm) into a new path segment See [#1140](https://github.com/freesewing/freesewing/issues/1140)
|
||||
|
||||
### i18n
|
||||
|
||||
#### Changed
|
||||
|
||||
- Changed antman references to antperson
|
||||
|
||||
|
||||
## 2.16.2 (2021-05-05)
|
||||
|
||||
### i18n
|
||||
|
||||
#### Changed
|
||||
|
||||
- String updates
|
||||
|
||||
|
||||
## 2.16.1 (2021-05-30)
|
||||
|
||||
|
@ -2395,6 +2458,12 @@
|
|||
|
||||
- Changed `department` setting in config in line with new grouping
|
||||
|
||||
### i18n
|
||||
|
||||
#### Added
|
||||
|
||||
- New translations for pattern filter
|
||||
|
||||
### utils
|
||||
|
||||
#### Changed
|
||||
|
@ -2430,6 +2499,12 @@
|
|||
|
||||
- Fixed third button not showing up See [#973](https://github.com/freesewing/freesewing/issues/973)
|
||||
|
||||
### i18n
|
||||
|
||||
#### Changed
|
||||
|
||||
- Changes to cfp strings
|
||||
|
||||
|
||||
## 2.15.4 (2021-05-08)
|
||||
|
||||
|
@ -2561,6 +2636,13 @@
|
|||
|
||||
- Don't round coordinates internally to avoid path.split misses
|
||||
|
||||
### i18n
|
||||
|
||||
#### Added
|
||||
|
||||
- Added translation for new Titan options
|
||||
- Added translations for Charlie
|
||||
|
||||
|
||||
## 2.14.0 (2021-03-07)
|
||||
|
||||
|
@ -2576,6 +2658,12 @@
|
|||
|
||||
- Replaced grainline indicator on pocket with cut-on-fold indicator
|
||||
|
||||
### i18n
|
||||
|
||||
#### Added
|
||||
|
||||
- Added translations for Cornelius
|
||||
|
||||
|
||||
## 2.13.2 (2021-02-21)
|
||||
|
||||
|
@ -2683,6 +2771,12 @@
|
|||
|
||||
- Make sure roudEnd and roundStart points are always available
|
||||
|
||||
### i18n
|
||||
|
||||
#### Added
|
||||
|
||||
- Translation for Hortensia
|
||||
|
||||
|
||||
## 2.12.1 (2021-01-27)
|
||||
|
||||
|
@ -2807,6 +2901,16 @@
|
|||
|
||||
- Removed unused lengthBonus option
|
||||
|
||||
### i18n
|
||||
|
||||
#### Changed
|
||||
|
||||
- New strings for new features
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Type in Simon title
|
||||
|
||||
|
||||
## 2.10.7 (2020-11-18)
|
||||
|
||||
|
@ -2822,6 +2926,12 @@
|
|||
|
||||
## 2.10.5 (2020-11-14)
|
||||
|
||||
### i18n
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Added missing `cty.` translations to non-English language files
|
||||
|
||||
|
||||
## 2.10.4 (2020-11-13)
|
||||
|
||||
|
@ -2884,6 +2994,18 @@
|
|||
- Added the `info` type to raised events
|
||||
- Added support for conditional loading of plugins
|
||||
|
||||
### i18n
|
||||
|
||||
#### Added
|
||||
|
||||
- Added translations for plugin-title
|
||||
- Added translations for teagan
|
||||
- Added some translations for the UI
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Replaced a few identical files with symlinks
|
||||
|
||||
|
||||
## 2.8.1 (2020-08-16)
|
||||
|
||||
|
@ -3277,6 +3399,13 @@
|
|||
|
||||
- [Properly escape quotes in imperial units](https://github.com/freesewing/freesewing/issues/437)
|
||||
|
||||
### i18n
|
||||
|
||||
#### Changed
|
||||
|
||||
- Added translations for Titan
|
||||
- Removed `Circumference` suffix from measurement names
|
||||
|
||||
### models
|
||||
|
||||
#### Changed
|
||||
|
@ -3344,6 +3473,12 @@
|
|||
- utils now includes `Bezier` which holds the bezier-js library so you don't need to re-import it
|
||||
- We no longer set the plugin configuration/data object to fall in `pattern.use()`
|
||||
|
||||
### i18n
|
||||
|
||||
#### Changed
|
||||
|
||||
- Changes to support the renaming of @freesewing/fu to @freesewing/florence
|
||||
|
||||
|
||||
## 2.5.0 (2020-04-05)
|
||||
|
||||
|
@ -3353,9 +3488,21 @@
|
|||
|
||||
- Diana is a top with a draped neck
|
||||
|
||||
### i18n
|
||||
|
||||
#### Added
|
||||
|
||||
- title, description, and options for Dianna
|
||||
|
||||
|
||||
## 2.4.6 (2020-03-23)
|
||||
|
||||
### i18n
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fixed an bug in the i18n package
|
||||
|
||||
|
||||
## 2.4.5 (2020-03-19)
|
||||
|
||||
|
@ -3413,9 +3560,21 @@
|
|||
|
||||
## 2.4.3 (2020-03-12)
|
||||
|
||||
### i18n
|
||||
|
||||
#### Added
|
||||
|
||||
- Added more translations
|
||||
|
||||
|
||||
## 2.4.2 (2020-03-08)
|
||||
|
||||
### i18n
|
||||
|
||||
#### Added
|
||||
|
||||
- Added more strings
|
||||
|
||||
|
||||
## 2.4.1 (2020-03-04)
|
||||
|
||||
|
@ -3588,6 +3747,22 @@
|
|||
- Added the `Path.noop()` method
|
||||
- Added the `Path.insop()` methods
|
||||
|
||||
### i18n
|
||||
|
||||
#### Added
|
||||
|
||||
- Added translations for Breanna
|
||||
|
||||
#### Changed
|
||||
|
||||
- Added/Updated strings for the 2.2 frontend changes
|
||||
- Changed `Joost De Cock` to `Joost` because spam filters don't like cock
|
||||
|
||||
#### Removed
|
||||
|
||||
- Removed the files for homepage translation, and moved that content to markdown
|
||||
- Removed the files for editor translation, as it is no longer used
|
||||
|
||||
### models
|
||||
|
||||
#### Changed
|
||||
|
@ -3652,6 +3827,12 @@
|
|||
|
||||
## 2.1.3 (2019-10-18)
|
||||
|
||||
### i18n
|
||||
|
||||
#### Added
|
||||
|
||||
- More translated strings
|
||||
|
||||
### utils
|
||||
|
||||
#### Changed
|
||||
|
@ -3665,6 +3846,12 @@
|
|||
|
||||
## 2.1.2 (2019-10-14)
|
||||
|
||||
### i18n
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Fixed issue where symlinks were causing all languages to export English strings
|
||||
|
||||
|
||||
## 2.1.1 (2019-10-13)
|
||||
|
||||
|
@ -3719,6 +3906,12 @@
|
|||
|
||||
- The pattern super constructor now sets a `config` property that holds the pattern configuration. This means that unlike before, there is no need to instantiate a pattern to access its config. You can just import the pattern, and it's config property will contain the pattern config.
|
||||
|
||||
### i18n
|
||||
|
||||
#### Added
|
||||
|
||||
- Added translations for Penelope, Waralee, and Simone
|
||||
|
||||
### utils
|
||||
|
||||
#### Added
|
||||
|
@ -3777,6 +3970,12 @@
|
|||
- [#102](https://github.com/freesewing/freesewing.org/issues/102): Fixed 'Snippets not defined' error when drafting a seperate button placket
|
||||
- [#103](https://github.com/freesewing/freesewing.org/issues/103): Fixed 'hemSa not defined' when drafting paperless Simon without seam allowance
|
||||
|
||||
### i18n
|
||||
|
||||
#### Added
|
||||
|
||||
- [#90](https://github.com/freesewing/freesewing/issues/90): Added missing option translations for Benjamin, Florent, Sandy, Shin, and Theo
|
||||
|
||||
### utils
|
||||
|
||||
#### Fixed
|
||||
|
@ -3980,6 +4179,12 @@
|
|||
|
||||
### core
|
||||
|
||||
#### Added
|
||||
|
||||
- Initial release
|
||||
|
||||
### i18n
|
||||
|
||||
#### Added
|
||||
|
||||
- Initial release
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"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",
|
||||
"new-design": "Initializer package for a new FreeSewing design: npx @freesewing/new-design",
|
||||
"prettier-config": "FreeSewing's shared configuration for prettier",
|
||||
|
|
|
@ -119,3 +119,16 @@ export const designs = {
|
|||
}
|
||||
|
||||
export const collection = Object.keys(designs)
|
||||
|
||||
export const requiredMeasurements = {}
|
||||
export const optionalMeasurements = {}
|
||||
export const measurements = {}
|
||||
|
||||
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,
|
||||
]
|
||||
}
|
||||
|
|
222
packages/i18n/CHANGELOG.md
Normal file
222
packages/i18n/CHANGELOG.md
Normal file
|
@ -0,0 +1,222 @@
|
|||
# Change log for: @freesewing/i18n
|
||||
|
||||
|
||||
## 3.0.0 (2023-09-30)
|
||||
|
||||
### Changed
|
||||
|
||||
- All FreeSewing packages are now ESM only.
|
||||
- All FreeSewing packages now use named exports.
|
||||
- Dropped support for NodeJS 14. NodeJS 18 (LTS/hydrogen) or more recent is now required.
|
||||
|
||||
## 2.21.0 (2022-06-27)
|
||||
|
||||
### Changed
|
||||
|
||||
- Migrated from Rollup to Esbuild for all builds
|
||||
|
||||
### Fixed
|
||||
|
||||
- Added missing lab namespace for English
|
||||
|
||||
## 2.20.2 (2022-01-27)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Patterns options were always in English due to symlinks being used
|
||||
|
||||
## 2.20.0 (2022-01-24)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed issue that was causing plugin translations to always be in English
|
||||
|
||||
## 2.19.0 (2021-10-17)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed bug in resolving of shared pattern options
|
||||
- Removed optional chaining which broke node v12 support
|
||||
|
||||
## 2.18.0 (2021-09-09)
|
||||
|
||||
### Added
|
||||
|
||||
- Added translations for Yuri
|
||||
|
||||
### Fixed
|
||||
|
||||
- Added optional chaining so missing options always lead to clear error message
|
||||
|
||||
## 2.17.3 (2021-08-16)
|
||||
|
||||
### Added
|
||||
|
||||
- New translations
|
||||
|
||||
## 2.17.2 (2021-08-15)
|
||||
|
||||
### Added
|
||||
|
||||
- Added new ffsa option for simon & simone
|
||||
|
||||
## 2.17.0 (2021-07-01)
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed antman references to antperson
|
||||
|
||||
## 2.16.2 (2021-05-05)
|
||||
|
||||
### Changed
|
||||
|
||||
- String updates
|
||||
|
||||
## 2.16.1 (2021-05-30)
|
||||
|
||||
### Added
|
||||
|
||||
- New translations for pattern filter
|
||||
|
||||
## 2.16.0 (2021-05-24)
|
||||
|
||||
### Changed
|
||||
|
||||
- Changes to cfp strings
|
||||
|
||||
## 2.15.0 (2021-04-15)
|
||||
|
||||
### Added
|
||||
|
||||
- Added translation for new Titan options
|
||||
- Added translations for Charlie
|
||||
|
||||
## 2.14.0 (2021-03-07)
|
||||
|
||||
### Added
|
||||
|
||||
- Added translations for Cornelius
|
||||
|
||||
## 2.13.0 (2021-02-13)
|
||||
|
||||
### Added
|
||||
|
||||
- Translation for Hortensia
|
||||
|
||||
## 2.11.0 (2021-01-10)
|
||||
|
||||
### Changed
|
||||
|
||||
- New strings for new features
|
||||
|
||||
### Fixed
|
||||
|
||||
- Type in Simon title
|
||||
|
||||
## 2.10.5 (2020-11-14)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Added missing `cty.` translations to non-English language files
|
||||
|
||||
## 2.9.0 (2020-10-02)
|
||||
|
||||
### Added
|
||||
|
||||
- Added translations for plugin-title
|
||||
- Added translations for teagan
|
||||
- Added some translations for the UI
|
||||
|
||||
### Fixed
|
||||
|
||||
- Replaced a few identical files with symlinks
|
||||
|
||||
## 2.7.0 (2020-07-12)
|
||||
|
||||
### Changed
|
||||
|
||||
- Added translations for Titan
|
||||
- Removed `Circumference` suffix from measurement names
|
||||
|
||||
## 2.6.0 (2020-05-01)
|
||||
|
||||
### Changed
|
||||
|
||||
- Changes to support the renaming of @freesewing/fu to @freesewing/florence
|
||||
|
||||
## 2.5.0 (2020-04-05)
|
||||
|
||||
### Added
|
||||
|
||||
- title, description, and options for Dianna
|
||||
|
||||
## 2.4.6 (2020-03-23)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed an bug in the i18n package
|
||||
|
||||
## 2.4.3 (2020-03-12)
|
||||
|
||||
### Added
|
||||
|
||||
- Added more translations
|
||||
|
||||
## 2.4.2 (2020-03-08)
|
||||
|
||||
### Added
|
||||
|
||||
- Added more strings
|
||||
|
||||
## 2.2.0 (2020-02-22)
|
||||
|
||||
### Added
|
||||
|
||||
- Added translations for Breanna
|
||||
|
||||
### Changed
|
||||
|
||||
- Added/Updated strings for the 2.2 frontend changes
|
||||
- Changed `Joost De Cock` to `Joost` because spam filters don't like cock
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed the files for homepage translation, and moved that content to markdown
|
||||
- Removed the files for editor translation, as it is no longer used
|
||||
|
||||
## 2.1.3 (2019-10-18)
|
||||
|
||||
### Added
|
||||
|
||||
- More translated strings
|
||||
|
||||
## 2.1.2 (2019-10-14)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed issue where symlinks were causing all languages to export English strings
|
||||
|
||||
## 2.1.0 (2019-10-06)
|
||||
|
||||
### Added
|
||||
|
||||
- Added translations for Penelope, Waralee, and Simone
|
||||
|
||||
## 2.0.2 (2019-09-06)
|
||||
|
||||
### Added
|
||||
|
||||
- [#90](https://github.com/freesewing/freesewing/issues/90): Added missing option translations for Benjamin, Florent, Sandy, Shin, and Theo
|
||||
|
||||
## 2.0.0 (2019-08-25)
|
||||
|
||||
### Added
|
||||
|
||||
- Initial release
|
||||
|
||||
|
||||
This is the **initial release**, and the start of this change log.
|
||||
|
||||
> Prior to version 2, FreeSewing was not a JavaScript project.
|
||||
> As such, that history is out of scope for this change log.
|
||||
|
162
packages/i18n/README.md
Normal file
162
packages/i18n/README.md
Normal file
|
@ -0,0 +1,162 @@
|
|||
<p align='center'><a
|
||||
href="https://www.npmjs.com/package/@freesewing/i18n"
|
||||
title="@freesewing/i18n on NPM"
|
||||
><img src="https://img.shields.io/npm/v/@freesewing/i18n.svg"
|
||||
alt="@freesewing/i18n on NPM"/>
|
||||
</a><a
|
||||
href="https://opensource.org/licenses/MIT"
|
||||
title="License: MIT"
|
||||
><img src="https://img.shields.io/npm/l/@freesewing/i18n.svg?label=License"
|
||||
alt="License: MIT"/>
|
||||
</a><a
|
||||
href="https://deepscan.io/dashboard#view=project&tid=2114&pid=2993&bid=23256"
|
||||
title="Code quality on DeepScan"
|
||||
><img src="https://deepscan.io/api/teams/2114/projects/2993/branches/23256/badge/grade.svg"
|
||||
alt="Code quality on DeepScan"/>
|
||||
</a><a
|
||||
href="https://github.com/freesewing/freesewing/issues?q=is%3Aissue+is%3Aopen+label%3Apkg%3Ai18n"
|
||||
title="Open issues tagged pkg:i18n"
|
||||
><img src="https://img.shields.io/github/issues/freesewing/freesewing/pkg:i18n.svg?label=Issues"
|
||||
alt="Open issues tagged pkg:i18n"/>
|
||||
</a><a
|
||||
href="#contributors-"
|
||||
title="All Contributors"
|
||||
><img src="https://img.shields.io/badge/all_contributors-131-pink.svg"
|
||||
alt="All Contributors"/>
|
||||
</a></p><p align='center'><a
|
||||
href="https://twitter.com/freesewing_org"
|
||||
title="Follow @freesewing_org on Twitter"
|
||||
><img src="https://img.shields.io/badge/%F3%A0%80%A0-Follow%20us-blue.svg?logo=twitter&logoColor=white&logoWidth=15"
|
||||
alt="Follow @freesewing_org on Twitter"/>
|
||||
</a><a
|
||||
href="https://chat.freesewing.org"
|
||||
title="Chat with us on Discord"
|
||||
><img src="https://img.shields.io/discord/698854858052075530?label=Chat%20on%20Discord"
|
||||
alt="Chat with us on Discord"/>
|
||||
</a><a
|
||||
href="https://freesewing.org/patrons/join"
|
||||
title="Become a FreeSewing Patron"
|
||||
><img src="https://img.shields.io/badge/%F3%A0%80%A0-Support%20us-blueviolet.svg?logo=cash-app&logoColor=white&logoWidth=15"
|
||||
alt="Become a FreeSewing Patron"/>
|
||||
</a><a
|
||||
href="https://instagram.com/freesewing_org"
|
||||
title="Follow @freesewing_org on Twitter"
|
||||
><img src="https://img.shields.io/badge/%F3%A0%80%A0-Follow%20us-E4405F.svg?logo=instagram&logoColor=white&logoWidth=15"
|
||||
alt="Follow @freesewing_org on Twitter"/>
|
||||
</a></p>
|
||||
|
||||
# @freesewing/i18n
|
||||
|
||||
Translation for the FreeSewing project
|
||||
|
||||
|
||||
|
||||
# FreeSewing
|
||||
|
||||
> [!TIP]
|
||||
>#### Support FreeSewing: Become a patron, or make a one-time donation 🥰
|
||||
>
|
||||
> FreeSewing is an open source project maintained by Joost De Cock and financially supported by the FreeSewing patrons.
|
||||
>
|
||||
> If you feel FreeSewing is worthwhile, and you can spend a few coins without
|
||||
hardship, then you should [join us and become a patron](https://freesewing.org/community/join).
|
||||
|
||||
## What am I looking at? 🤔
|
||||
|
||||
This repository is the FreeSewing *monorepo* holding all FreeSewing's websites, documentation, designs, plugins, and other NPM packages.
|
||||
|
||||
This folder holds: @freesewing/i18n
|
||||
|
||||
If you're not entirely sure what to do or how to start, type this command:
|
||||
|
||||
```
|
||||
npm run tips
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> If you don't want to set up a dev environment, you can run it in your browser:
|
||||
>
|
||||
> [](https://gitpod.io/#https://github.com/freesewing/freesewing)
|
||||
>
|
||||
> We recommend that you fork our repository and then
|
||||
> put `gitpod.io/#<entire-url-of-your-fork` into a browser
|
||||
> to start up a browser-based dev environment of your own.
|
||||
|
||||
## About FreeSewing 💀
|
||||
|
||||
Where the world of makers and developers collide, that's where you'll find FreeSewing.
|
||||
|
||||
If you're a maker, checkout [freesewing.org](https://freesewing.org/) where you can generate
|
||||
sewing patterns adapted to your measurements.
|
||||
|
||||
If you're a developer, the FreeSewing documentation lives at [freesewing.dev](https://freesewing.dev/).
|
||||
The FreeSewing [core library](https://freesewing.dev/reference/api/) is a *batteries-included* toolbox
|
||||
for parametric design of sewing patterns. But FreeSewing also provides a range
|
||||
of [plugins](https://freesewing.dev/reference/plugins/) that further extend the
|
||||
functionality of the platform.
|
||||
|
||||
If you have NodeJS installed, you can try it right now by running:
|
||||
|
||||
```bash
|
||||
npx @freesewing/new-design
|
||||
```
|
||||
|
||||
Getting started guides are available for:
|
||||
- [Linux](https://freesewing.dev/tutorials/getting-started-linux/)
|
||||
- [MacOS](https://freesewing.dev/tutorials/getting-started-mac/)
|
||||
- [Windows](https://freesewing.dev/tutorials/getting-started-windows/)
|
||||
|
||||
The [pattern design tutorial](https://freesewing.dev/tutorials/pattern-design/) will
|
||||
show you how to create your first parametric design.
|
||||
|
||||
## Getting started ⚡
|
||||
|
||||
To get started with FreeSewing, you can spin up our development environment with:
|
||||
|
||||
```bash
|
||||
npx @freesewing/new-design
|
||||
```
|
||||
|
||||
To work with FreeSewing's monorepo, you'll need [NodeJS v20](https://nodejs.org) on your system.
|
||||
Once you have that, clone (or fork) this repo and run `npm run kickstart`:
|
||||
|
||||
```bash
|
||||
git clone git@github.com:freesewing/freesewing.git
|
||||
cd freesewing
|
||||
npm run kickstart
|
||||
```
|
||||
|
||||
## Links 👩💻
|
||||
|
||||
**Official channels**
|
||||
|
||||
- 💻 Makers website: [FreeSewing.org](https://freesewing.org)
|
||||
- 💻 Developers website: [FreeSewing.dev](https://freesewing.dev)
|
||||
- ✅ [Support](https://github.com/freesewing/freesewing/issues/new/choose),
|
||||
[Issues](https://github.com/freesewing/freesewing/issues) &
|
||||
[Discussions](https://github.com/freesewing/freesewing/discussions) on
|
||||
[GitHub](https://github.com/freesewing/freesewing)
|
||||
|
||||
**Social media**
|
||||
|
||||
- 🐦 Twitter: [@freesewing_org](https://twitter.com/freesewing_org)
|
||||
- 📷 Instagram: [@freesewing_org](https://instagram.com/freesewing_org)
|
||||
|
||||
**Places the FreeSewing community hangs out**
|
||||
|
||||
- 💬 [Discord](https://discord.freesewing.org/)
|
||||
- 💬 [Facebook](https://www.facebook.com/groups/627769821272714/)
|
||||
- 💬 [Reddit](https://www.reddit.com/r/freesewing/)
|
||||
|
||||
## License: MIT 🤓
|
||||
|
||||
© [Joost De Cock](https://github.com/joostdecock).
|
||||
See [the license file](https://github.com/freesewing/freesewing/blob/develop/LICENSE) for details.
|
||||
|
||||
## Where to get help 🤯
|
||||
|
||||
For [Support](https://github.com/freesewing/freesewing/issues/new/choose),
|
||||
please use the [Issues](https://github.com/freesewing/freesewing/issues) &
|
||||
[Discussions](https://github.com/freesewing/freesewing/discussions) on
|
||||
[GitHub](https://github.com/freesewing/freesewing).
|
||||
|
4
packages/i18n/data.mjs
Normal file
4
packages/i18n/data.mjs
Normal file
|
@ -0,0 +1,4 @@
|
|||
// This file is auto-generated | All changes you make will be overwritten.
|
||||
export const name = '@freesewing/i18n'
|
||||
export const version = '3.3.0-rc.1'
|
||||
export const data = { name, version }
|
50
packages/i18n/package.json
Normal file
50
packages/i18n/package.json
Normal file
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"name": "@freesewing/i18n",
|
||||
"version": "3.3.0-rc.1",
|
||||
"description": "Translation for the FreeSewing project",
|
||||
"author": "Joost De Cock <joost@joost.at> (https://github.com/joostdecock)",
|
||||
"homepage": "https://freesewing.org/",
|
||||
"repository": "github:freesewing/freesewing",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/freesewing/freesewing/issues"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://freesewing.org/patrons/join"
|
||||
},
|
||||
"keywords": [
|
||||
"freesewing",
|
||||
"i18n",
|
||||
"internationalisation",
|
||||
"languages",
|
||||
"localisation",
|
||||
"translation"
|
||||
],
|
||||
"type": "module",
|
||||
"module": "src/index.mjs",
|
||||
"exports": {
|
||||
".": "./src/index.mjs"
|
||||
},
|
||||
"scripts": {
|
||||
"symlink": "mkdir -p ./node_modules/@freesewing && cd ./node_modules/@freesewing && ln -s -f ../../../* . && cd -",
|
||||
"test": "echo \"i18n: No tests configured. Perhaps you could write some?\" && exit 0",
|
||||
"tips": "node ../../scripts/help.mjs",
|
||||
"lint": "npx eslint 'src/**' 'tests/*.mjs'"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"dependencies": {},
|
||||
"devDependencies": {},
|
||||
"files": [
|
||||
"src/**",
|
||||
"README.md"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"tag": "next"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
},
|
||||
"private": true
|
||||
}
|
3
packages/i18n/src/index.mjs
Normal file
3
packages/i18n/src/index.mjs
Normal file
|
@ -0,0 +1,3 @@
|
|||
import { measurements } from './measurements.mjs'
|
||||
|
||||
export { measurements }
|
40
packages/i18n/src/measurements.mjs
Normal file
40
packages/i18n/src/measurements.mjs
Normal file
|
@ -0,0 +1,40 @@
|
|||
export const measurements = {
|
||||
ankle: 'Ankle circumference',
|
||||
biceps: 'Biceps circumference',
|
||||
bustFront: 'Bust front',
|
||||
bustPointToUnderbust: 'Bust point to underbust',
|
||||
bustSpan: 'Bust span',
|
||||
chest: 'Chest circumference',
|
||||
crossSeam: 'Cross seam',
|
||||
crossSeamFront: 'Cross seam front',
|
||||
head: 'Head circumference',
|
||||
heel: 'Heel circumference',
|
||||
highBustFront: 'High bust front',
|
||||
highBust: 'High bust',
|
||||
hips: 'Hips circumference',
|
||||
hpsToBust: 'HPS to bust',
|
||||
hpsToWaistBack: 'HPS to waist back',
|
||||
hpsToWaistFront: 'HPS to waist front',
|
||||
inseam: 'Inseam',
|
||||
knee: 'Knee circumference',
|
||||
neck: 'Neck circumference',
|
||||
seat: 'Seat circumference',
|
||||
seatBack: 'Seat back',
|
||||
crotchDepth: 'Crotch depth',
|
||||
shoulderSlope: 'Shoulder slope',
|
||||
shoulderToElbow: 'Shoulder to elbow',
|
||||
shoulderToShoulder: 'Shoulder to shoulder',
|
||||
shoulderToWrist: 'Shoulder to wrist',
|
||||
underbust: 'Underbust',
|
||||
upperLeg: 'Upper leg circumference',
|
||||
waist: 'Waist circumference',
|
||||
waistBack: 'Waist back',
|
||||
waistToArmpit: 'Waist to armpit',
|
||||
waistToFloor: 'Waist to floor',
|
||||
waistToHips: 'Waist to hips',
|
||||
waistToKnee: 'Waist to knee',
|
||||
waistToSeat: 'Waist to seat',
|
||||
waistToUnderbust: 'Waist to underbust',
|
||||
waistToUpperLeg: 'Waist to upper leg',
|
||||
wrist: 'Wrist circumference',
|
||||
}
|
|
@ -1,11 +1,19 @@
|
|||
// Dependencies
|
||||
import { measurements, isDegreeMeasurement, control as controlConfig } from '@freesewing/config'
|
||||
import {
|
||||
measurements,
|
||||
isDegreeMeasurement,
|
||||
control as controlConfig,
|
||||
urls,
|
||||
} from '@freesewing/config'
|
||||
import { measurements as measurementTranslations } from '@freesewing/i18n'
|
||||
import { measurements as designMeasurements } from '@freesewing/collection'
|
||||
import {
|
||||
cloudflareImageUrl,
|
||||
capitalize,
|
||||
formatMm,
|
||||
horFlexClasses,
|
||||
linkClasses,
|
||||
notEmpty,
|
||||
roundDistance,
|
||||
shortDate,
|
||||
timeAgo,
|
||||
|
@ -18,8 +26,10 @@ import React, { useState, useEffect, Fragment, useContext } from 'react'
|
|||
import { useAccount } from '@freesewing/react/hooks/useAccount'
|
||||
import { useBackend } from '@freesewing/react/hooks/useBackend'
|
||||
// Components
|
||||
import { Link as WebLink } from '@freesewing/react/components/Link'
|
||||
import { Link as WebLink, AnchorLink } from '@freesewing/react/components/Link'
|
||||
import {
|
||||
BoolNoIcon,
|
||||
BoolYesIcon,
|
||||
CloneIcon,
|
||||
CuratedMeasurementsSetIcon,
|
||||
EditIcon,
|
||||
|
@ -36,54 +46,26 @@ import {
|
|||
// BoolNoIcon,
|
||||
} from '@freesewing/react/components/Icon'
|
||||
import { BookmarkButton, MsetCard } from '@freesewing/react/components/Account'
|
||||
import { ToggleInput } from '@freesewing/react/components/Input'
|
||||
import {
|
||||
DesignInput,
|
||||
MarkdownInput,
|
||||
ListInput,
|
||||
MeasieInput,
|
||||
PassiveImageInput,
|
||||
StringInput,
|
||||
ToggleInput,
|
||||
} from '@freesewing/react/components/Input'
|
||||
import { DisplayRow } from './shared.mjs'
|
||||
import Markdown from 'react-markdown'
|
||||
import { ModalWrapper } from '@freesewing/react/components/Modal'
|
||||
import { Json } from '@freesewing/react/components/Json'
|
||||
import { Yaml } from '@freesewing/react/components/Yaml'
|
||||
import { Popout } from '@freesewing/react/components/Popout'
|
||||
|
||||
//import { measurements as designMeasurements } from 'shared/prebuild/data/design-measurements.mjs'
|
||||
//import { freeSewingConfig as conf, controlLevels } from 'shared/config/freesewing.config.mjs'
|
||||
//import { isDegreeMeasurement } from 'config/measurements.mjs'
|
||||
//import {
|
||||
// shortDate,
|
||||
// cloudflareImageUrl,
|
||||
// formatMm,
|
||||
// hasRequiredMeasurements,
|
||||
// capitalize,
|
||||
// horFlexClasses,
|
||||
//} from 'shared/utils.mjs'
|
||||
//// Hooks
|
||||
//import { useState, useEffect, useContext } from 'react'
|
||||
//import { useTranslation } from 'next-i18next'
|
||||
//import { useAccount } from 'shared/hooks/use-account.mjs'
|
||||
//import { useBackend } from 'shared/hooks/use-backend.mjs'
|
||||
//import { useRouter } from 'next/router'
|
||||
//// Context
|
||||
//import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
|
||||
//import { ModalContext } from 'shared/context/modal-context.mjs'
|
||||
//// Components
|
||||
//import { Popout } from 'shared/components/popout/index.mjs'
|
||||
//import { BackToAccountButton } from './shared.mjs'
|
||||
//import { AnchorLink, PageLink, Link } from 'shared/components/link.mjs'
|
||||
//import { Json } from 'shared/components/json.mjs'
|
||||
//import { Yaml } from 'shared/components/yaml.mjs'
|
||||
//import { ModalWrapper } from 'shared/components/wrappers/modal.mjs'
|
||||
//import { Mdx } from 'shared/components/mdx/dynamic.mjs'
|
||||
//import Timeago from 'react-timeago'
|
||||
//import {
|
||||
// StringInput,
|
||||
// ToggleInput,
|
||||
// PassiveImageInput,
|
||||
// ListInput,
|
||||
// MarkdownInput,
|
||||
// MeasieInput,
|
||||
// DesignDropdown,
|
||||
// ns as inputNs,
|
||||
//} from 'shared/components/inputs.mjs'
|
||||
//import { BookmarkButton } from 'shared/components/bookmarks.mjs'
|
||||
//import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
|
||||
const t = (input) => {
|
||||
console.log('t called', input)
|
||||
return input
|
||||
}
|
||||
|
||||
/*
|
||||
* Component to show an individual measurements set
|
||||
|
@ -163,10 +145,8 @@ export const Set = ({ id, publicOnly = false, Link = false }) => {
|
|||
}
|
||||
}, [id, publicOnly])
|
||||
|
||||
const filterMeasurements = () => {
|
||||
if (!filter) return measurements.map((m) => `measurements:${m}` + `|${m}`).sort()
|
||||
else return designMeasurements[filter].map((m) => `measurements:${m}` + `|${m}`).sort()
|
||||
}
|
||||
const filterMeasurements = () =>
|
||||
filter ? designMeasurements[filter].sort() : measurements.sort()
|
||||
|
||||
if (!id || !mset) return null
|
||||
|
||||
|
@ -192,7 +172,7 @@ export const Set = ({ id, publicOnly = false, Link = false }) => {
|
|||
setLoadingStatus([true, 'Saving measurements set'])
|
||||
const [status, body] = await backend.updateSet(mset.id, data)
|
||||
if (status === 200 && body.result === 'success') {
|
||||
setMset(body.data.set)
|
||||
setMset(body.set)
|
||||
setEdit(false)
|
||||
setLoadingStatus([true, 'Nailed it', true, true])
|
||||
} else
|
||||
|
@ -218,10 +198,9 @@ export const Set = ({ id, publicOnly = false, Link = false }) => {
|
|||
}
|
||||
delete data.img
|
||||
const [status, body] = await backend.createSet(data)
|
||||
if (status === 200 && body.result === 'success') {
|
||||
setMset(body.data.set)
|
||||
setEdit(false)
|
||||
setLoadingStatus([true, 'Nailed it', true, true])
|
||||
if (status === 201 && body.result === 'created') {
|
||||
setLoadingStatus([true, 'Loading newly created set', true, true])
|
||||
window.location = `/account/set/?id=${body.set.id}`
|
||||
} else setLoadingStatus([true, 'We failed to create this measurements set', true, false])
|
||||
}
|
||||
|
||||
|
@ -235,14 +214,14 @@ export const Set = ({ id, publicOnly = false, Link = false }) => {
|
|||
{account.control > 2 && mset.public && mset.userId !== account.id ? (
|
||||
<div className="flex flex-row gap-2 items-center">
|
||||
<a
|
||||
className="badge badge-secondary font-bold badge-lg"
|
||||
href={`${conf.backend}/sets/${mset.id}.json`}
|
||||
className="daisy-badge daisy-badge-secondary font-bold daisy-badge-lg"
|
||||
href={`${urls.backend}/sets/${mset.id}.json`}
|
||||
>
|
||||
JSON
|
||||
</a>
|
||||
<a
|
||||
className="badge badge-success font-bold badge-lg"
|
||||
href={`${conf.backend}/sets/${mset.id}.yaml`}
|
||||
className="daisy-badge daisy-badge-success font-bold daisy-badge-lg"
|
||||
href={`${urls.backend}/sets/${mset.id}.yaml`}
|
||||
>
|
||||
YAML
|
||||
</a>
|
||||
|
@ -253,7 +232,7 @@ export const Set = ({ id, publicOnly = false, Link = false }) => {
|
|||
{account.control > 3 && mset.userId === account.id ? (
|
||||
<div className="flex flex-row gap-2 items-center">
|
||||
<button
|
||||
className="badge badge-secondary font-bold badge-lg"
|
||||
className="daisy-badge daisy-badge-secondary font-bold daisy-badge-lg"
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<ModalWrapper keepOpenOnClick>
|
||||
|
@ -265,7 +244,7 @@ export const Set = ({ id, publicOnly = false, Link = false }) => {
|
|||
JSON
|
||||
</button>
|
||||
<button
|
||||
className="badge badge-success font-bold badge-lg"
|
||||
className="daisy-badge daisy-badge-success font-bold daisy-badge-lg text-neutral-content"
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<ModalWrapper keepOpenOnClick>
|
||||
|
@ -283,12 +262,12 @@ export const Set = ({ id, publicOnly = false, Link = false }) => {
|
|||
{account.id && account.control > 2 && mset.public && mset.userId !== account.id ? (
|
||||
<button
|
||||
className="daisy-btn daisy-btn-primary"
|
||||
title={t('account:importSet')}
|
||||
title="Import measurements set"
|
||||
onClick={importSet}
|
||||
>
|
||||
<div className="flex flex-row gap-4 justify-between items-center w-full">
|
||||
<UploadIcon />
|
||||
{t('account:importSet')}
|
||||
Import measurements set
|
||||
</div>
|
||||
</button>
|
||||
) : null}
|
||||
|
@ -379,7 +358,7 @@ export const Set = ({ id, publicOnly = false, Link = false }) => {
|
|||
return (
|
||||
<div className="max-w-2xl">
|
||||
{heading}
|
||||
<SuggestCset {...{ mset, setLoadingStatus, backend, t }} />
|
||||
<SuggestCset {...{ mset, setLoadingStatus, backend, Link }} />
|
||||
</div>
|
||||
)
|
||||
|
||||
|
@ -466,56 +445,27 @@ export const Set = ({ id, publicOnly = false, Link = false }) => {
|
|||
return (
|
||||
<div className="max-w-2xl">
|
||||
{heading}
|
||||
<ul className="list list-disc list-inside ml-4">
|
||||
{['measies', 'data'].map((s) => (
|
||||
<li key={s}>
|
||||
<AnchorLink id={s}>{s}</AnchorLink>
|
||||
</li>
|
||||
))}
|
||||
<ul className="list list-disc list-inside ml-4">
|
||||
<li>
|
||||
<AnchorLink id="name">Name</AnchorLink>
|
||||
</li>
|
||||
{account.control >= conf.account.sets.img ? (
|
||||
<li>
|
||||
<AnchorLink id="image">Image</AnchorLink>
|
||||
</li>
|
||||
) : null}
|
||||
{['public', 'units', 'notes'].map((id) =>
|
||||
account.control >= conf.account.sets[id] ? (
|
||||
<li key={id}>
|
||||
<AnchorLink id="units">{id}</AnchorLink>
|
||||
</li>
|
||||
) : null
|
||||
)}
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
<h2 id="measies">{t('measies')}</h2>
|
||||
<h2 id="measies">Measurements</h2>
|
||||
<div className="bg-secondary px-4 pt-1 pb-4 rounded-lg shadow bg-opacity-10">
|
||||
<DesignDropdown
|
||||
<DesignInput
|
||||
update={setFilter}
|
||||
label="Filter by design"
|
||||
current={filter}
|
||||
firstOption={<option value="">Clear filter</option>}
|
||||
/>
|
||||
</div>
|
||||
{filterMeasurements().map((mplus) => {
|
||||
const [translated, m] = mplus.split('|')
|
||||
|
||||
return (
|
||||
{filterMeasurements().map((m) => (
|
||||
<MeasieInput
|
||||
id={`measie-${m}`}
|
||||
key={m}
|
||||
m={m}
|
||||
imperial={mset.imperial}
|
||||
label={translated}
|
||||
label={measurementTranslations[m]}
|
||||
current={mset.measies[m]}
|
||||
original={mset.measies[m]}
|
||||
update={updateMeasies}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
))}
|
||||
|
||||
<h2 id="data">Data</h2>
|
||||
|
||||
|
@ -533,7 +483,7 @@ export const Set = ({ id, publicOnly = false, Link = false }) => {
|
|||
|
||||
{/* img: Control level determines whether or not to show this */}
|
||||
<span id="image"></span>
|
||||
{account.control >= conf.account.sets.img ? (
|
||||
{account.control >= controlConfig.account.sets.img ? (
|
||||
<PassiveImageInput
|
||||
id="set-img"
|
||||
label="Image"
|
||||
|
@ -545,7 +495,7 @@ export const Set = ({ id, publicOnly = false, Link = false }) => {
|
|||
|
||||
{/* public: Control level determines whether or not to show this */}
|
||||
<span id="public"></span>
|
||||
{account.control >= conf.account.sets.public ? (
|
||||
{account.control >= controlConfig.account.sets.public ? (
|
||||
<ListInput
|
||||
id="set-public"
|
||||
label="Public"
|
||||
|
@ -581,7 +531,7 @@ export const Set = ({ id, publicOnly = false, Link = false }) => {
|
|||
|
||||
{/* units: Control level determines whether or not to show this */}
|
||||
<span id="units"></span>
|
||||
{account.control >= conf.account.sets.units ? (
|
||||
{account.control >= controlConfig.account.sets.units ? (
|
||||
<>
|
||||
<ListInput
|
||||
id="set-units"
|
||||
|
@ -611,13 +561,15 @@ export const Set = ({ id, publicOnly = false, Link = false }) => {
|
|||
]}
|
||||
current={imperial}
|
||||
/>
|
||||
<span className="text-large text-warning">{t('unitsMustSave')}</span>
|
||||
<span className="text-large text-warning">
|
||||
Note: You must save after changing Units to have the change take effect on this page.
|
||||
</span>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{/* notes: Control level determines whether or not to show this */}
|
||||
<span id="notes"></span>
|
||||
{account.control >= conf.account.sets.notes ? (
|
||||
{account.control >= controlConfig.account.sets.notes ? (
|
||||
<MarkdownInput
|
||||
id="set-notes"
|
||||
label="Notes"
|
||||
|
@ -652,14 +604,137 @@ export const MeasurementValue = ({ val, m, imperial = false }) =>
|
|||
<span dangerouslySetInnerHTML={{ __html: formatMm(val, imperial) }}></span>
|
||||
)
|
||||
|
||||
/*
|
||||
/**
|
||||
* React component to suggest a measurements set for curation
|
||||
*
|
||||
* @param {object} props - All React props
|
||||
* @param {string} mset - The measurements set
|
||||
*/
|
||||
export const SuggestCset = ({ mset, Link }) => {
|
||||
// State
|
||||
const [height, setHeight] = useState('')
|
||||
const [img, setImg] = useState('')
|
||||
const [name, setName] = useState('')
|
||||
const [notes, setNotes] = useState('')
|
||||
const [submission, setSubmission] = useState(false)
|
||||
|
||||
console.log(mset)
|
||||
|
||||
// Hooks
|
||||
const backend = useBackend()
|
||||
|
||||
// Method to submit the form
|
||||
const suggestSet = async () => {
|
||||
setLoadingStatus([true, 'Contacting backend'])
|
||||
const result = await backend.suggestCset({ set: mset.id, height, img, name, notes })
|
||||
if (result.success && result.data.submission) {
|
||||
setSubmission(result.data.submission)
|
||||
setLoadingStatus([true, 'Nailed it', true, true])
|
||||
} else setLoadingStatus([true, 'An unexpected error occured. Please report this.', true, false])
|
||||
}
|
||||
|
||||
const missing = []
|
||||
for (const m of measurements) {
|
||||
if (typeof mset.measies[m] === 'undefined') missing.push(m)
|
||||
}
|
||||
|
||||
if (submission) {
|
||||
const url = `/curate/sets/suggested/${submission.id}`
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2>Thank you</h2>
|
||||
<p>Your submission has been registered and will be processed by one of our curators.</p>
|
||||
<p>
|
||||
It is available at: <Link href={url}>{url}</Link>
|
||||
</p>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2>Suggest a measurements set for curation</h2>
|
||||
<h4 className="flex flex-row items-center gap-2">
|
||||
{missing.length > 0 ? <BoolNoIcon /> : <BoolYesIcon />}
|
||||
Measurements
|
||||
</h4>
|
||||
{missing.length > 0 ? (
|
||||
<>
|
||||
<p>
|
||||
To ensure curated measurements sets work for all designs, you need to provide a full set
|
||||
of measurements.
|
||||
</p>
|
||||
<p>Your measurements set is missing the following measurements:</p>
|
||||
<ul className="list list-inside list-disc ml-4">
|
||||
{missing.map((m) => (
|
||||
<li key={m}>{m}</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
) : (
|
||||
<p>All measurements are available.</p>
|
||||
)}
|
||||
<h4 className="flex flex-row items-center gap-2">
|
||||
{name.length > 1 ? <BoolYesIcon /> : <BoolNoIcon />}
|
||||
Name
|
||||
</h4>
|
||||
<p>Each curated set has a name. You can suggest your own name or a pseudonym.</p>
|
||||
<StringInput label="Name" current={name} update={setName} valid={(val) => val.length > 1} />
|
||||
<h4 className="flex flex-row items-center gap-2">
|
||||
{height.length > 1 ? <BoolYesIcon /> : <BoolNoIcon />}
|
||||
Height
|
||||
</h4>
|
||||
<p>
|
||||
To allow organizing and presenting our curated sets in a structured way, we organize them by
|
||||
height.
|
||||
</p>
|
||||
<StringInput
|
||||
label="height"
|
||||
current={height}
|
||||
update={setHeight}
|
||||
valid={(val) => val.length > 1}
|
||||
/>
|
||||
<h4 className="flex flex-row items-center gap-2 mt-4">
|
||||
{img.length > 0 ? <BoolYesIcon /> : <BoolNoIcon />}
|
||||
Image
|
||||
</h4>
|
||||
<p>
|
||||
Finally, we need a picture. Please refer to the documentation to see what makes a good
|
||||
picture for a curated measurements set.
|
||||
<Link href="/docs/about/site/csets">Documentation</Link>
|
||||
</p>
|
||||
<PassiveImageInput
|
||||
label="Image"
|
||||
current={img}
|
||||
update={setImg}
|
||||
valid={(val) => val.length > 1}
|
||||
/>
|
||||
<h4 className="flex flex-row items-center gap-2 mt-4">
|
||||
<BoolYesIcon />
|
||||
Notes
|
||||
</h4>
|
||||
<p>If you would like to add any notes, you can do so here.</p>
|
||||
<Popout tip compact>
|
||||
This field supports markdown
|
||||
</Popout>
|
||||
<MarkdownInput label="Notes" current={notes} update={setNotes} valid={() => true} />
|
||||
<button
|
||||
className="daisy-btn daisy-btn-primary w-full mt-4"
|
||||
disabled={!(missing.length === 0 && height.length > 1 && img.length > 0)}
|
||||
onClick={suggestSet}
|
||||
>
|
||||
Suggest for curation
|
||||
</button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const NewSet = () => {
|
||||
// Hooks
|
||||
const { setLoadingStatus } = useContext(LoadingStatusContext)
|
||||
const backend = useBackend()
|
||||
const { t } = useTranslation(ns)
|
||||
const router = useRouter()
|
||||
const { account } = useAccount()
|
||||
const { setLoadingStatus, LoadingProgress } = useContext(LoadingStatusContext)
|
||||
|
||||
// State
|
||||
const [name, setName] = useState('')
|
||||
|
@ -669,39 +744,46 @@ export const NewSet = () => {
|
|||
|
||||
// Helper method to create a new set
|
||||
const createSet = async () => {
|
||||
setLoadingStatus([true, 'processingUpdate'])
|
||||
const result = await backend.createSet({ name, imperial })
|
||||
if (result.success) {
|
||||
setLoadingStatus([true, t('nailedIt'), true, true])
|
||||
router.push(`/account/set?id=${result.data.set.id}`)
|
||||
} else setLoadingStatus([true, 'backendError', true, false])
|
||||
setLoadingStatus([true, 'Storing new measurements set'])
|
||||
const [status, body] = await backend.createSet({ name, imperial })
|
||||
if (status === 201 && body.result === 'created') {
|
||||
setLoadingStatus([true, 'Nailed it', true, true])
|
||||
window.location = `/account/set?id=${body.set.id}`
|
||||
} else
|
||||
setLoadingStatus([
|
||||
true,
|
||||
'Failed to save the measurments set. Please report this.',
|
||||
true,
|
||||
false,
|
||||
])
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-xl">
|
||||
<h5>{t('name')}</h5>
|
||||
<p>{t('setNameDesc')}</p>
|
||||
<input
|
||||
autoFocus
|
||||
value={name}
|
||||
onChange={(evt) => setName(evt.target.value)}
|
||||
className="input w-full input-bordered flex flex-row"
|
||||
type="text"
|
||||
<h5>Name</h5>
|
||||
<p>Give this set of measurements a name. That will help tell them apart.</p>
|
||||
<StringInput
|
||||
id="new-set"
|
||||
label="Name"
|
||||
update={setName}
|
||||
current={name}
|
||||
valid={(val) => val && val.length > 0}
|
||||
placeholder={'Georg Cantor'}
|
||||
/>
|
||||
<div className="flex flex-row gap-2 items-center w-full mt-8 mb-2">
|
||||
<button
|
||||
className="btn btn-primary grow capitalize"
|
||||
className="daisy-btn daisy-btn-primary grow capitalize"
|
||||
disabled={name.length < 1}
|
||||
onClick={createSet}
|
||||
>
|
||||
{t('newSet')}
|
||||
New Measurements Set
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
export const SetCard = ({
|
||||
set,
|
||||
|
@ -950,122 +1032,5 @@ export const BookmarkedSetPicker = ({ design, clickHandler, t, size, href }) =>
|
|||
)
|
||||
}
|
||||
|
||||
const SuggestCset = ({ mset, backend, setLoadingStatus, t }) => {
|
||||
// State
|
||||
const [height, setHeight] = useState('')
|
||||
const [img, setImg] = useState('')
|
||||
const [name, setName] = useState('')
|
||||
const [notes, setNotes] = useState('')
|
||||
const [submission, setSubmission] = useState(false)
|
||||
|
||||
// Method to submit the form
|
||||
const suggestSet = async () => {
|
||||
setLoadingStatus([true, 'status:contactingBackend'])
|
||||
const result = await backend.suggestCset({ set: mset.id, height, img, name, notes })
|
||||
if (result.success && result.data.submission) {
|
||||
setSubmission(result.data.submission)
|
||||
setLoadingStatus([true, 'status:nailedIt', true, true])
|
||||
} else setLoadingStatus([true, 'backendError', true, false])
|
||||
}
|
||||
|
||||
const missing = []
|
||||
for (const m of measurements) {
|
||||
if (typeof mset.measies[m] === 'undefined') missing.push(m)
|
||||
}
|
||||
|
||||
if (submission) {
|
||||
const url = `/curate/sets/suggested/${submission.id}`
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2>{t('account:thankYouVeryMuch')}</h2>
|
||||
<p>{t('account:csetSuggestedMsg')}</p>
|
||||
<p>
|
||||
{t('account:itIsAvailableAt')}: <PageLink href={url} txt={url} />
|
||||
</p>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2>{t('account:suggestCset')}</h2>
|
||||
<h4 className="flex flex-row items-center gap-2">
|
||||
{missing.length > 0 ? <BoolNoIcon /> : <BoolYesIcon />}
|
||||
{t('account:measurements')}
|
||||
</h4>
|
||||
{missing.length > 0 ? (
|
||||
<>
|
||||
<p>{t('account:csetAllMeasies')}</p>
|
||||
<p>{t('account:csetMissing')}:</p>
|
||||
<ul className="list list-inside list-disc ml-4">
|
||||
{missing.map((m) => (
|
||||
<li key={m}>{t(`measurements:${m}`)}</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
) : (
|
||||
<p>{t('account:allMeasiesAvailable')}</p>
|
||||
)}
|
||||
<h4 className="flex flex-row items-center gap-2">
|
||||
{name.length > 1 ? <BoolYesIcon /> : <BoolNoIcon />}
|
||||
{t('account:name')}
|
||||
</h4>
|
||||
<p>{t('account:csetNameMsg')}</p>
|
||||
<StringInput
|
||||
label={t('account:name')}
|
||||
current={name}
|
||||
update={setName}
|
||||
valid={(val) => val.length > 1}
|
||||
/>
|
||||
<h4 className="flex flex-row items-center gap-2">
|
||||
{height.length > 1 ? <BoolYesIcon /> : <BoolNoIcon />}
|
||||
{t('measurements:height')}
|
||||
</h4>
|
||||
<p>{t('account:csetHeightMsg1')}</p>
|
||||
<StringInput
|
||||
label={t('measurements:height')}
|
||||
current={height}
|
||||
update={setHeight}
|
||||
valid={(val) => val.length > 1}
|
||||
/>
|
||||
<h4 className="flex flex-row items-center gap-2 mt-4">
|
||||
{img.length > 0 ? <BoolYesIcon /> : <BoolNoIcon />}
|
||||
{t('account:img')}
|
||||
</h4>
|
||||
<p>
|
||||
{t('account:csetImgMsg')}:{' '}
|
||||
<PageLink href="/docs/about/site/csets">{t('account:docs')}</PageLink>
|
||||
</p>
|
||||
<PassiveImageInput
|
||||
label={t('account:img')}
|
||||
current={img}
|
||||
update={setImg}
|
||||
valid={(val) => val.length > 1}
|
||||
/>
|
||||
<h4 className="flex flex-row items-center gap-2 mt-4">
|
||||
<BoolYesIcon />
|
||||
{t('account:notes')}
|
||||
</h4>
|
||||
<p>{t('account:csetNotesMsg')}</p>
|
||||
<Popout tip compact>
|
||||
{t('account:mdSupport')}
|
||||
</Popout>
|
||||
<MarkdownInput
|
||||
label={t('account:notes')}
|
||||
current={notes}
|
||||
update={setNotes}
|
||||
valid={() => true}
|
||||
/>
|
||||
<button
|
||||
className="btn btn-primary w-full mt-4"
|
||||
disabled={!(missing.length === 0 && height.length > 1 && img.length > 0)}
|
||||
onClick={suggestSet}
|
||||
>
|
||||
{t('account:suggestForCuration')}
|
||||
</button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
*/
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||
|
||||
import { Bookmarks, BookmarkButton } from './Bookmarks.mjs'
|
||||
import { Links } from './Links.mjs'
|
||||
import { Set } from './Set.mjs'
|
||||
import { Set, NewSet } from './Set.mjs'
|
||||
import { Sets, MsetCard } from './Sets.mjs'
|
||||
|
||||
export { Bookmarks, BookmarkButton, Links, Set, Sets, MsetCard }
|
||||
export { Bookmarks, BookmarkButton, Links, Set, NewSet, Sets, MsetCard }
|
||||
|
|
|
@ -1,26 +1,34 @@
|
|||
import React, { useState } from 'react'
|
||||
import React, { useContext, useState } from 'react'
|
||||
import ReactDOMServer from 'react-dom/server'
|
||||
import { CopyIcon, OkIcon } from '@freesewing/react/components/Icon'
|
||||
import { CopyToClipboard as Copy } from 'react-copy-to-clipboard'
|
||||
import { LoadingStatusContext } from '@freesewing/react/context/LoadingStatus'
|
||||
|
||||
const strip = (html) =>
|
||||
typeof DOMParser === 'undefined'
|
||||
? html
|
||||
: new DOMParser().parseFromString(html, 'text/html').body.textContent || ''
|
||||
|
||||
const handleCopied = (setCopied) => {
|
||||
const handleCopied = (setCopied, setLoadingStatus, label) => {
|
||||
setCopied(true)
|
||||
setLoadingStatus([
|
||||
true,
|
||||
label ? `${label} copied to clipboard` : 'Copied to clipboard',
|
||||
true,
|
||||
true,
|
||||
])
|
||||
setTimeout(() => setCopied(false), 1000)
|
||||
}
|
||||
|
||||
export const CopyToClipboard = ({ content }) => {
|
||||
export const CopyToClipboard = ({ content, label = false }) => {
|
||||
const [copied, setCopied] = useState(false)
|
||||
const { setLoadingStatus } = useContext(LoadingStatusContext)
|
||||
|
||||
const text =
|
||||
typeof content === 'string' ? content : strip(ReactDOMServer.renderToStaticMarkup(content))
|
||||
|
||||
return (
|
||||
<Copy text={text} onCopy={() => handleCopied(setCopied)}>
|
||||
<Copy text={text} onCopy={() => handleCopied(setCopied, setLoadingStatus, label)}>
|
||||
<button className={copied ? 'text-success' : ''}>
|
||||
{copied ? (
|
||||
<OkIcon className="w-5 h-5 text-success-content bg-success rounded-full p-1" stroke={4} />
|
||||
|
|
|
@ -1,25 +1,41 @@
|
|||
import React from 'react'
|
||||
import { CopyToClipboard } from '@freesewing/react/components/CopyToClipboard'
|
||||
|
||||
const names = {
|
||||
const defaultTitles = {
|
||||
js: 'Javascript',
|
||||
bash: 'Bash prompt',
|
||||
sh: 'Shell prompt',
|
||||
bash: 'Bash commands',
|
||||
sh: 'Shell commands',
|
||||
json: 'JSON',
|
||||
yaml: 'file.yaml',
|
||||
yaml: 'YAML',
|
||||
}
|
||||
|
||||
export const Highlight = (props) => {
|
||||
let language = 'txt'
|
||||
if (props.language) language = props.language
|
||||
if (props.children?.props?.className) {
|
||||
language = props.children.props.className.split('-').pop()
|
||||
/**
|
||||
* A React component to highlight code
|
||||
*
|
||||
* @params {object} props - All React props
|
||||
* @params {string} language - The language to highlight
|
||||
* @params {object} children - The React children
|
||||
* @params {bool} raw - Set this to true to not escape tags
|
||||
* @params {string} title - Title for the highlight
|
||||
* @params {string} copy - Content to copy to clipboard
|
||||
*/
|
||||
export const Highlight = ({
|
||||
language = 'txt',
|
||||
children,
|
||||
raw = false,
|
||||
title = false,
|
||||
copy = false,
|
||||
}) => {
|
||||
if (children?.props?.className) {
|
||||
language = children.props.className.split('-').pop()
|
||||
}
|
||||
|
||||
const preProps = {
|
||||
className: `language-${language} hljs text-base lg:text-lg whitespace-break-spaces overflow-scroll pr-4`,
|
||||
}
|
||||
if (props.raw) preProps.dangerouslySetInnerHTML = { __html: props.raw }
|
||||
if (raw) preProps.dangerouslySetInnerHTML = { __html: raw }
|
||||
|
||||
const label = title ? title : defaultTitles[language] ? defaultTitles[language] : language
|
||||
|
||||
return (
|
||||
<div className="hljs my-4">
|
||||
|
@ -31,10 +47,10 @@ export const Highlight = (props) => {
|
|||
px-4 py-1 mb-2 lg:text-sm
|
||||
`}
|
||||
>
|
||||
<span>{props.title ? props.title : names[language] ? names[language] : language}</span>
|
||||
<CopyToClipboard content={props.children} />
|
||||
<span>{label}</span>
|
||||
<CopyToClipboard content={copy ? copy : children} label={label} />
|
||||
</div>
|
||||
<pre {...preProps}>{props.children}</pre>
|
||||
<pre {...preProps}>{children}</pre>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -14,13 +14,11 @@ import React, { useState, useCallback, useContext } from 'react'
|
|||
import { useDropzone } from 'react-dropzone'
|
||||
import { useBackend } from '@freesewing/react/hooks/useBackend'
|
||||
// Components
|
||||
//import { Mdx } from 'shared/components/mdx/dynamic.mjs'
|
||||
import { ResetIcon, DocsIcon, UploadIcon } from '@freesewing/react/components/Icon'
|
||||
import { ResetIcon, UploadIcon } from '@freesewing/react/components/Icon'
|
||||
import { ModalWrapper } from '@freesewing/react/components/Modal'
|
||||
import { isDegreeMeasurement } from '@freesewing/config'
|
||||
import { Tabs, Tab } from '@freesewing/react/components/Tab'
|
||||
|
||||
export const ns = ['account', 'measurements', 'designs']
|
||||
import Markdown from 'react-markdown'
|
||||
|
||||
/*
|
||||
* Helper component to display a tab heading
|
||||
|
@ -32,8 +30,8 @@ export const _Tab = ({
|
|||
setActiveTab, // Method to set the active tab
|
||||
}) => (
|
||||
<button
|
||||
className={`text-lg font-bold capitalize tab tab-bordered grow
|
||||
${activeTab === id ? 'tab-active' : ''}`}
|
||||
className={`text-lg font-bold capitalize daisy-tab daisy-tab-bordered grow
|
||||
${activeTab === id ? 'daisy-tab-active' : ''}`}
|
||||
onClick={() => setActiveTab(id)}
|
||||
>
|
||||
{label ? label : id}
|
||||
|
@ -46,42 +44,16 @@ export const _Tab = ({
|
|||
export const FormControl = ({
|
||||
label, // the (top-left) label
|
||||
children, // Children to go inside the form control
|
||||
docs = false, // Optional top-right label
|
||||
labelBL = false, // Optional bottom-left label
|
||||
labelBR = false, // Optional bottom-right label
|
||||
forId = false, // ID of the for element we are wrapping
|
||||
}) => {
|
||||
const { setModal } = useContext(ModalContext)
|
||||
|
||||
if (labelBR && !labelBL) labelBL = <span></span>
|
||||
|
||||
const topLabelChildren = (
|
||||
<>
|
||||
<span className="daisy-label-text text-sm lg:text-base font-bold mb-1 text-inherit">
|
||||
{label}
|
||||
</span>
|
||||
{docs ? (
|
||||
<span className="daisy-label-text-alt">
|
||||
<button
|
||||
className="daisy-btn daisy-btn-ghost daisy-btn-sm daisy-btn-circle hover:daisy-btn-secondary"
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<ModalWrapper
|
||||
flex="col"
|
||||
justify="top lg:justify-center"
|
||||
slideFrom="right"
|
||||
keepOpenOnClick
|
||||
>
|
||||
<div className="markdown max-w-prose">{docs}</div>
|
||||
</ModalWrapper>
|
||||
)
|
||||
}
|
||||
>
|
||||
<DocsIcon />
|
||||
</button>
|
||||
</span>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
const bottomLabelChildren = (
|
||||
<>
|
||||
|
@ -149,7 +121,6 @@ export const NumberInput = ({
|
|||
current, // The current value
|
||||
original, // The original value
|
||||
placeholder, // The placeholder text
|
||||
docs = false, // Docs to load, if any
|
||||
id = '', // An id to tie the input to the label
|
||||
labelBL = false, // Bottom-Left label
|
||||
labelBR = false, // Bottom-Right label
|
||||
|
@ -157,7 +128,7 @@ export const NumberInput = ({
|
|||
min = 220,
|
||||
step = 1,
|
||||
}) => (
|
||||
<FormControl {...{ label, labelBL, labelBR, docs }} forId={id}>
|
||||
<FormControl {...{ label, labelBL, labelBR }} forId={id}>
|
||||
<input
|
||||
id={id}
|
||||
type="text"
|
||||
|
@ -183,12 +154,11 @@ export const StringInput = ({
|
|||
current, // The current value
|
||||
original, // The original value
|
||||
placeholder, // The placeholder text
|
||||
docs = false, // Docs to load, if any
|
||||
id = '', // An id to tie the input to the label
|
||||
labelBL = false, // Bottom-Left label
|
||||
labelBR = false, // Bottom-Right label
|
||||
}) => (
|
||||
<FormControl {...{ label, labelBL, labelBR, docs }} forId={id}>
|
||||
<FormControl {...{ label, labelBL, labelBR }} forId={id}>
|
||||
<input
|
||||
id={id}
|
||||
type="text"
|
||||
|
@ -220,7 +190,6 @@ export const MfaInput = ({
|
|||
valid={(val) => val.length > 4}
|
||||
{...{ update, current, id }}
|
||||
placeholder="MFA Code"
|
||||
docs={false}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -234,7 +203,6 @@ export const PasswordInput = ({
|
|||
valid, // Method that should return whether the value is valid or not
|
||||
current, // The current value
|
||||
placeholder = '¯\\_(ツ)_/¯', // The placeholder text
|
||||
docs = false, // Docs to load, if any
|
||||
id = '', // An id to tie the input to the label
|
||||
onKeyDown = false, // Optionall capture certain keys (like enter)
|
||||
}) => {
|
||||
|
@ -245,7 +213,6 @@ export const PasswordInput = ({
|
|||
return (
|
||||
<FormControl
|
||||
label={label}
|
||||
docs={docs}
|
||||
forId={id}
|
||||
labelBR={
|
||||
<button
|
||||
|
@ -281,12 +248,11 @@ export const EmailInput = ({
|
|||
current, // The current value
|
||||
original, // The original value
|
||||
placeholder, // The placeholder text
|
||||
docs = false, // Docs to load, if any
|
||||
id = '', // An id to tie the input to the label
|
||||
labelBL = false, // Bottom-Left label
|
||||
labelBR = false, // Bottom-Right label
|
||||
}) => (
|
||||
<FormControl {...{ label, docs, labelBL, labelBR }} forId={id}>
|
||||
<FormControl {...{ label, labelBL, labelBR }} forId={id}>
|
||||
<input
|
||||
id={id}
|
||||
type="email"
|
||||
|
@ -301,21 +267,20 @@ export const EmailInput = ({
|
|||
)
|
||||
|
||||
/*
|
||||
* Dropdown for designs
|
||||
* Input for designs
|
||||
*/
|
||||
export const DesignDropdown = ({
|
||||
export const DesignInput = ({
|
||||
label, // Label to use
|
||||
update, // onChange handler
|
||||
current, // The current value
|
||||
docs = false, // Docs to load, if any
|
||||
firstOption = null, // Any first option to add in addition to designs
|
||||
id = '', // An id to tie the input to the label
|
||||
}) => {
|
||||
return (
|
||||
<FormControl label={label} docs={docs} forId={id}>
|
||||
<FormControl label={label} forId={id}>
|
||||
<select
|
||||
id={id}
|
||||
className="select select-bordered w-full"
|
||||
className="daisy-select daisy-select-bordered w-full"
|
||||
onChange={(evt) => update(evt.target.value)}
|
||||
value={current}
|
||||
>
|
||||
|
@ -338,7 +303,6 @@ export const ImageInput = ({
|
|||
update, // The onChange handler
|
||||
current, // The current value
|
||||
original, // The original value
|
||||
docs = false, // Docs to load, if any
|
||||
active = false, // Whether or not to upload images
|
||||
imgType = 'showcase', // The image type
|
||||
imgSubid, // The image sub-id
|
||||
|
@ -383,7 +347,7 @@ export const ImageInput = ({
|
|||
|
||||
if (current)
|
||||
return (
|
||||
<FormControl label={label} docs={docs}>
|
||||
<FormControl label={label}>
|
||||
<div
|
||||
className="bg-base-100 w-full h-36 mb-2 mx-auto flex flex-col items-center text-center justify-center"
|
||||
style={{
|
||||
|
@ -396,7 +360,7 @@ export const ImageInput = ({
|
|||
}}
|
||||
>
|
||||
<button
|
||||
className="btn btn-neutral btn-circle opacity-50 hover:opacity-100"
|
||||
className="daisy-btn daisy-btn-neutral daisy-btn-circle opacity-50 hover:opacity-100"
|
||||
onClick={() => update(original)}
|
||||
>
|
||||
<ResetIcon />
|
||||
|
@ -406,7 +370,7 @@ export const ImageInput = ({
|
|||
)
|
||||
|
||||
return (
|
||||
<FormControl label={label} docs={docs} forId={id}>
|
||||
<FormControl label={label} forId={id}>
|
||||
<div
|
||||
{...getRootProps()}
|
||||
className={`
|
||||
|
@ -417,7 +381,7 @@ export const ImageInput = ({
|
|||
<input {...getInputProps()} />
|
||||
<p className="hidden lg:block p-0 m-0">Drag and drop and image here</p>
|
||||
<p className="hidden lg:block p-0 my-2">or</p>
|
||||
<button className={`btn btn-secondary btn-outline mt-4 px-8`}>
|
||||
<button className={`daisy-btn daisy-btn-secondary daisy-btn-outline mt-4 px-8`}>
|
||||
Select an image to use
|
||||
</button>
|
||||
</div>
|
||||
|
@ -433,7 +397,7 @@ export const ImageInput = ({
|
|||
/>
|
||||
{active && (
|
||||
<button
|
||||
className="btn btn-secondary ml-2 capitalize"
|
||||
className="daisy-btn daisy-btn-secondary ml-2 capitalize"
|
||||
disabled={!url || url.length < 1}
|
||||
onClick={() => upload(url, true)}
|
||||
>
|
||||
|
@ -463,9 +427,8 @@ export const ListInput = ({
|
|||
label, // The label
|
||||
list, // The list of items to present { val, label, desc }
|
||||
current, // The (value of the) current item
|
||||
docs = false, // Docs to load, if any
|
||||
}) => (
|
||||
<FormControl label={label} docs={docs}>
|
||||
<FormControl label={label}>
|
||||
{list.map((item, i) => (
|
||||
<ButtonFrame key={i} active={item.val === current} onClick={() => update(item.val)}>
|
||||
<div className="w-full flex flex-col gap-2">
|
||||
|
@ -489,15 +452,18 @@ export const MarkdownInput = ({
|
|||
current, // The current value (markdown)
|
||||
update, // The onChange handler
|
||||
placeholder, // The placeholder content
|
||||
docs = false, // Docs to load, if any
|
||||
id = '', // An id to tie the input to the label
|
||||
labelBL = false, // Bottom-Left label
|
||||
labelBR = false, // Bottom-Right label
|
||||
}) => (
|
||||
<FormControl {...{ label, labelBL, labelBR, docs }} forId={id}>
|
||||
<FormControl
|
||||
{...{ label, labelBR }}
|
||||
forId={id}
|
||||
labelBL={labelBL ? labelBL : 'This field supports markdown'}
|
||||
>
|
||||
<Tabs tabs={['edit', 'preview']}>
|
||||
<Tab key="edit">
|
||||
<div className="flex flex-row items-center mt-4">
|
||||
<div className="flex flex-row items-center">
|
||||
<textarea
|
||||
id={id}
|
||||
rows="5"
|
||||
|
@ -509,8 +475,8 @@ export const MarkdownInput = ({
|
|||
</div>
|
||||
</Tab>
|
||||
<Tab key="preview">
|
||||
<div className="flex flex-row items-center mt-4">
|
||||
<Mdx md={current} />
|
||||
<div className="flex flex-row items-center">
|
||||
<Markdown>{current}</Markdown>
|
||||
</div>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
@ -523,7 +489,6 @@ export const MeasieInput = ({
|
|||
original, // The original value
|
||||
update, // The onChange handler
|
||||
placeholder, // The placeholder content
|
||||
docs = false, // Docs to load, if any
|
||||
id = '', // An id to tie the input to the label
|
||||
}) => {
|
||||
const isDegree = isDegreeMeasurement(m)
|
||||
|
@ -553,14 +518,14 @@ export const MeasieInput = ({
|
|||
if (!m) return null
|
||||
|
||||
// Various visual indicators for validating the input
|
||||
let inputClasses = 'input-secondary'
|
||||
let inputClasses = 'daisy-input-secondary'
|
||||
let bottomLeftLabel = null
|
||||
if (valid === true) {
|
||||
inputClasses = 'input-success'
|
||||
inputClasses = 'daisy-input-success'
|
||||
const val = `${validatedVal}${isDegree ? '°' : imperial ? '"' : 'cm'}`
|
||||
bottomLeftLabel = <span className="font-medium text-base text-success -mt-2 block">{val}</span>
|
||||
} else if (valid === false) {
|
||||
inputClasses = 'input-error'
|
||||
inputClasses = 'daisy-input-error'
|
||||
bottomLeftLabel = (
|
||||
<span className="font-medium text-error text-base -mt-2 block">¯\_(ツ)_/¯</span>
|
||||
)
|
||||
|
@ -574,12 +539,7 @@ export const MeasieInput = ({
|
|||
* See: https://github.com/facebook/react/issues/16554
|
||||
*/
|
||||
return (
|
||||
<FormControl
|
||||
label={t(m) + (isDegree ? ' (°)' : '')}
|
||||
docs={docs}
|
||||
forId={id}
|
||||
labelBL={bottomLeftLabel}
|
||||
>
|
||||
<FormControl label={m + (isDegree ? ' (°)' : '')} forId={id} labelBL={bottomLeftLabel}>
|
||||
<input
|
||||
id={id}
|
||||
type="text"
|
||||
|
@ -588,7 +548,7 @@ export const MeasieInput = ({
|
|||
placeholder={placeholder}
|
||||
value={localVal}
|
||||
onChange={(evt) => localUpdate(evt.target.value)}
|
||||
className={`input w-full input-bordered ${inputClasses}`}
|
||||
className={`daisy-input w-full daisy-input-bordered ${inputClasses}`}
|
||||
/>
|
||||
</FormControl>
|
||||
)
|
||||
|
@ -628,7 +588,7 @@ export const FileInput = ({
|
|||
<FormControl label={label} isValid={valid(current)}>
|
||||
<div className="bg-base-100 w-full h-36 mb-2 mx-auto flex flex-col items-center text-center justify-center">
|
||||
<button
|
||||
className="btn btn-neutral btn-circle opacity-50 hover:opacity-100"
|
||||
className="daisy-btn daisy-btn-neutral daisy-btn-circle opacity-50 hover:opacity-100"
|
||||
onClick={() => update(original)}
|
||||
>
|
||||
<ResetIcon />
|
||||
|
@ -651,7 +611,9 @@ export const FileInput = ({
|
|||
>
|
||||
<input {...getInputProps()} />
|
||||
<p className="hidden lg:block p-0 m-0">Drag and drop your file here</p>
|
||||
<button className={`btn btn-secondary btn-outline mt-4 px-8`}>Browse...</button>
|
||||
<button className={`daisy-btn daisy-btn-secondary daisy-btn-outline mt-4 px-8`}>
|
||||
Browse...
|
||||
</button>
|
||||
</div>
|
||||
</FormControl>
|
||||
)
|
||||
|
|
|
@ -5,5 +5,7 @@ import hljs from 'highlight.js/lib/common'
|
|||
export const Json = (props) => {
|
||||
const code = props.js ? JSON.stringify(props.js, null, 2) : props.children
|
||||
|
||||
return <Highlight language="json" raw={hljs.highlight(code, { language: 'json' }).value} />
|
||||
return (
|
||||
<Highlight language="json" raw={hljs.highlight(code, { language: 'json' }).value} copy={code} />
|
||||
)
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@ export const ModalWrapper = ({
|
|||
flex = 'row',
|
||||
justify = 'center',
|
||||
items = 'center',
|
||||
bg = 'base-100 lg:bg-base-300',
|
||||
bgOpacity = '100 lg:bg-opacity-95',
|
||||
bg = 'neutral lg:neutral',
|
||||
bgOpacity = '100 lg:bg-opacity-70',
|
||||
bare = false,
|
||||
keepOpenOnClick = false,
|
||||
slideFrom = 'left',
|
||||
|
@ -68,9 +68,10 @@ export const ModalWrapper = ({
|
|||
<div
|
||||
className={`fixed top-0 left-0 m-0 p-0 shadow w-full h-screen
|
||||
transform-all duration-150 ${animation}
|
||||
bg-${bg} bg-opacity-${bgOpacity} z-40 hover:cursor-pointer
|
||||
flex flex-${flex} justify-${justify} items-${items} lg:p-12`}
|
||||
bg-${bg} bg-opacity-${bgOpacity} hover:cursor-pointer
|
||||
flex flex-${flex} justify-${justify} items-${items} lg:p-12 backdrop-blur-md`}
|
||||
onClick={close}
|
||||
style={{ zIndex: 250 }}
|
||||
>
|
||||
{bare ? (
|
||||
children
|
||||
|
|
|
@ -1,8 +1,104 @@
|
|||
import React from 'react'
|
||||
import { mergeProps } from './utils.mjs'
|
||||
import { Popout as SwizzledPopout } from './editor/swizzle/components/popout.mjs'
|
||||
import { CloseIcon } from './editor/swizzle/components/icons.mjs'
|
||||
import React, { useState } from 'react'
|
||||
import { CloseIcon } from '@freesewing/react/components/Icon'
|
||||
|
||||
const t = (id) => id
|
||||
const colors = {
|
||||
comment: 'secondary',
|
||||
error: 'error',
|
||||
fixme: 'warning',
|
||||
link: 'secondary',
|
||||
none: '',
|
||||
note: 'primary',
|
||||
related: 'info',
|
||||
tip: 'accent',
|
||||
tldr: 'info',
|
||||
warning: 'error',
|
||||
}
|
||||
|
||||
export const Popout = (props) => <SwizzledPopout {...mergeProps(props, { CloseIcon }, { t })} />
|
||||
/**
|
||||
* This popout component is a way to make some content stand out
|
||||
*
|
||||
* @param {object} props - All React props
|
||||
* @param {object} props.comment - Set this to make it a comment popout
|
||||
* @param {object} props.error - Set this to make it a error popout
|
||||
* @param {object} props.fixme - Set this to make it a fixme popout
|
||||
* @param {object} props.link - Set this to make it a link popout
|
||||
* @param {object} props.note - Set this to make it a note popout
|
||||
* @param {object} props.related - Set this to make it a related popout
|
||||
* @param {object} props.tip - Set this to make it a tip popout
|
||||
* @param {object} props.tldr - Set this to make it a tldr popout
|
||||
* @param {object} props.warning - Set this to make it a warning popout
|
||||
* @param {string} props.title - The popout title
|
||||
* @param {string} noP - Do not wrap the content in a p tag
|
||||
*/
|
||||
export const Popout = (props) => {
|
||||
// Make this hideable/dismissable
|
||||
const [hide, setHide] = useState(false)
|
||||
if (hide) return null
|
||||
|
||||
let type = 'none'
|
||||
for (const c in colors) {
|
||||
if (props[c]) type = c
|
||||
}
|
||||
const color = colors[type]
|
||||
const { className = '' } = props
|
||||
|
||||
return props.compact ? (
|
||||
<div
|
||||
className={`relative ${
|
||||
props.dense ? 'my-1' : 'my-8'
|
||||
} bg-${color} bg-opacity-5 -ml-4 -mr-4 sm:ml-0 sm:mr-0 ${className}`}
|
||||
>
|
||||
<div
|
||||
className={`
|
||||
border-y-4 sm:border-0 sm:border-l-4 px-4
|
||||
shadow text-base border-${color}
|
||||
flex flex-row items-center
|
||||
`}
|
||||
>
|
||||
<div className={`font-bold uppercase text-${color}`}>
|
||||
{props.title || (
|
||||
<>
|
||||
<span>{type.toUpperCase()}</span>
|
||||
<span className="px-3">|</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="popout-content">{props.noP ? props.children : <p>{props.children}</p>}</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className={`relative my-8 bg-${color} bg-opacity-5 -ml-4 -mr-4 sm:ml-0 sm:mr-0 ${className}`}
|
||||
>
|
||||
<div
|
||||
className={`
|
||||
border-y-4 sm:border-0 sm:border-l-4 px-6 sm:px-8 py-4 sm:py-2
|
||||
shadow text-base border-${color}
|
||||
`}
|
||||
>
|
||||
<div className={`font-bold flex flex-row gap-1 items-end justify-between`}>
|
||||
<div>
|
||||
<span className={`font-bold uppercase text-${color}`}>
|
||||
{type === 'tldr' ? 'TL;DR' : type.toUpperCase()}
|
||||
</span>
|
||||
<span className={`font-normal text-base text-${color}`}>
|
||||
{type === 'comment' && (
|
||||
<>
|
||||
{' '}
|
||||
by <b>{props.by}</b>
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
{props.hideable && (
|
||||
<button onClick={() => setHide(true)} className="hover:text-secondary" title="Close">
|
||||
<CloseIcon />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="py-1 first:mt-0 popout-content">{props.children}</div>
|
||||
{type === 'comment' && <div className={`font-bold italic text-${color}`}>{props.by}</div>}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -31,16 +31,17 @@ export const Tabs = ({ tabs = '', active = 0, children, withModal = false }) =>
|
|||
)
|
||||
|
||||
return (
|
||||
<div className="my-4">
|
||||
<div className="tabs">
|
||||
<div className="">
|
||||
<div className="daisy-tabs daisy-tabs-bordered" role="tablist">
|
||||
{tablist.map((title, tabId) => {
|
||||
const btnClasses = `text-lg font-bold capitalize tab h-auto tab-bordered grow py-2 ${
|
||||
activeTab === tabId ? 'tab-active' : ''
|
||||
const btnClasses = `text-lg font-bold capitalize daisy-tab h-auto daisy-tabs-bordered grow py-1 ${
|
||||
activeTab === tabId ? 'daisy-tab-active' : ''
|
||||
}`
|
||||
|
||||
return withModal && activeTab === tabId ? (
|
||||
<button
|
||||
key={tabId}
|
||||
role="tab"
|
||||
className={btnClasses}
|
||||
onClick={() =>
|
||||
setModal(
|
||||
|
|
|
@ -10,6 +10,11 @@ export const Yaml = (props) => {
|
|||
else code = props.children
|
||||
|
||||
return (
|
||||
<Highlight {...props} language="yaml" raw={hljs.highlight(code, { language: 'yaml' }).value} />
|
||||
<Highlight
|
||||
{...props}
|
||||
language="yaml"
|
||||
raw={hljs.highlight(code, { language: 'yaml' }).value}
|
||||
copy={code}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -47,7 +47,10 @@ const LoadingStatus = ({ loadingStatus }) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="fixed bottom-14 md:top-28 left-0 w-full z-50 md:px-4 md:mx-auto">
|
||||
<div
|
||||
className="fixed bottom-14 md:top-28 left-0 w-full z-50 md:px-4 md:mx-auto"
|
||||
style={{ zIndex: 500 }}
|
||||
>
|
||||
<div
|
||||
className={`w-full md:max-w-2xl m-auto bg-${color} flex flex-row items-center gap-4 p-4 px-4 ${fade}
|
||||
transition-opacity delay-[${timeout * 1000 - 400}ms] duration-300
|
||||
|
|
|
@ -3,4 +3,12 @@ title: Create a new measurement set
|
|||
sidebar_position: 2
|
||||
---
|
||||
|
||||
FIXME
|
||||
import { DocusaurusDoc } from '@freesewing/react/components/Docusaurus'
|
||||
import { RoleBlock } from '@freesewing/react/components/Role'
|
||||
import { NewSet } from '@freesewing/react/components/Account'
|
||||
|
||||
<DocusaurusDoc>
|
||||
<RoleBlock user>
|
||||
<NewSet />
|
||||
</RoleBlock>
|
||||
</DocusaurusDoc>
|
||||
|
|
161
sites/org/src/css/code.css
Normal file
161
sites/org/src/css/code.css
Normal file
|
@ -0,0 +1,161 @@
|
|||
/* __SDEFILE__ - This file is a dependency for the stand-alone environment */
|
||||
|
||||
/*
|
||||
* CSS file for highlightjs, with support for (DaisyUI) themes
|
||||
*
|
||||
* Do not edit this file, edit the theme configuration instead
|
||||
*/
|
||||
|
||||
/* The div wrapping the code block */
|
||||
div.hljs {
|
||||
background: var(--code-background-color);
|
||||
border-color: var(--code-border-color);
|
||||
border-width: var(--code-border-width);
|
||||
border-style: var(--code-border-style);
|
||||
padding: 0;
|
||||
color: var(--code-color);
|
||||
border-radius: var(--code-border-radius);
|
||||
}
|
||||
|
||||
/* The code block inside the wrapping div */
|
||||
div.hljs > pre {
|
||||
background: var(--code-bg);
|
||||
color: var(--code-color);
|
||||
padding: var(--code-inner-padding);
|
||||
font-family: var(--code-font-family);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix for the tailwind typography plugin (aka prose) that
|
||||
* adds padding to code that makes it look like there's a
|
||||
* extra space on the first line
|
||||
*/
|
||||
div.hljs > pre > code {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Higlight lines within a highlighted code block
|
||||
*/
|
||||
div.hljs > pre > code section {
|
||||
margin: 0 -1rem;
|
||||
padding: 0 1rem 0 calc(1rem - 4px);
|
||||
border-left: 0.35rem solid transparent;
|
||||
border-color: rgb(130, 203, 21);
|
||||
background-color: var(--code-background-highlight-color);
|
||||
}
|
||||
div.hljs > pre > code section > div.code-section-inner {
|
||||
display: inline-block;
|
||||
padding: 0.25rem 0.25rem 0.25rem 0;
|
||||
background-color: var(--code-background-highlight-color);
|
||||
}
|
||||
div.hljs > pre > code section.strikeout-lines {
|
||||
border-color: rgb(255, 75, 57);
|
||||
}
|
||||
div.hljs > pre > code section > span.code-line-break:last-child {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* CSS for highlighted code: keyword
|
||||
*/
|
||||
.hljs-doctag,
|
||||
.hljs-keyword,
|
||||
.hljs-meta .hljs-keyword,
|
||||
.hljs-template-tag,
|
||||
.hljs-template-variable,
|
||||
.hljs-type,
|
||||
.hljs-variable.language_ {
|
||||
color: var(--code-color-keyword);
|
||||
font-weight: var(--code-font-weight-keyword);
|
||||
}
|
||||
|
||||
/*
|
||||
* CSS for highlighted code: entity
|
||||
*/
|
||||
.hljs-title,
|
||||
.hljs-title.class_,
|
||||
.hljs-title.class_.inherited__,
|
||||
.hljs-title.function_ {
|
||||
color: var(--code-color-entity);
|
||||
font-weight: var(--code-font-weight-entity);
|
||||
}
|
||||
|
||||
/*
|
||||
* CSS for highlighted code: constant
|
||||
*/
|
||||
.hljs-attr,
|
||||
.hljs-attribute,
|
||||
.hljs-literal,
|
||||
.hljs-meta,
|
||||
.hljs-number,
|
||||
.hljs-operator,
|
||||
.hljs-variable,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-class,
|
||||
.hljs-selector-id {
|
||||
color: var(--code-color-constant);
|
||||
}
|
||||
|
||||
/*
|
||||
* CSS for highlighted code: string
|
||||
*/
|
||||
.hljs-regexp,
|
||||
.hljs-string,
|
||||
.hljs-meta .hljs-string {
|
||||
color: var(--code-color-string);
|
||||
font-style: var(--code-font-style-string);
|
||||
}
|
||||
|
||||
/*
|
||||
* CSS for highlighted code: variable
|
||||
*/
|
||||
.hljs-built_in,
|
||||
.hljs-symbol {
|
||||
color: var(--code-color-variable);
|
||||
}
|
||||
|
||||
/*
|
||||
* CSS for highlighted code: comment
|
||||
*/
|
||||
.hljs-comment,
|
||||
.hljs-code,
|
||||
.hljs-formula {
|
||||
color: var(--code-color-comment);
|
||||
}
|
||||
|
||||
/*
|
||||
* CSS for highlighted code: tag
|
||||
*/
|
||||
.hljs-name,
|
||||
.hljs-quote,
|
||||
.hljs-selector-tag,
|
||||
.hljs-selector-pseudo {
|
||||
color: var(--code-color-tag);
|
||||
}
|
||||
|
||||
/*
|
||||
* CSS for highlighted code: property
|
||||
*/
|
||||
.hljs-property {
|
||||
color: var(--code-color-property);
|
||||
font-weight: var(--code-font-weight-property);
|
||||
}
|
||||
|
||||
/*
|
||||
* CSS for highlighted code: other
|
||||
*/
|
||||
.hljs-addition,
|
||||
.hljs-bullet,
|
||||
.hljs-char.escape_,
|
||||
.hljs-deletion,
|
||||
.hljs-emphasis,
|
||||
.hljs-link,
|
||||
.hljs-params,
|
||||
.hljs-punctuation,
|
||||
.hljs-section,
|
||||
.hljs-strong,
|
||||
.hljs-subst,
|
||||
.hljs-tag {
|
||||
/* Currently not using these */
|
||||
}
|
|
@ -12,6 +12,11 @@
|
|||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/*
|
||||
* Add CSS for code
|
||||
*/
|
||||
@import './code.css';
|
||||
|
||||
@layer components {
|
||||
/* Applied styles for common HTML tags */
|
||||
h1 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue