Merge branch 'freesewing:develop' into develop
This commit is contained in:
commit
99adb6dd17
134 changed files with 2590 additions and 610 deletions
|
@ -5,7 +5,7 @@ title: "Tamiko top: Cutting Instructions"
|
|||
- **Tissu principal**
|
||||
- Couper **1 Tamiko dessus** sur le pli
|
||||
|
||||
Tamiko is a zero-waste pattern. It's a rectangle that's cut out on the fold. Not more than that. There's only one part to this top, we will simply refer to it at the **Tamiko top**. It needs to be cut on the fold along the bottom.
|
||||
Le Tamiko est un modèle zéro déchets. C'est un rectangle découpé sur la pliure. Rien de plus. C'est un modèle en une seule pièce, que nous appellerons simplement le **Tamiko top**. Elle doit être coupée sur la pliure, le long du bas.
|
||||
|
||||
<Note>
|
||||
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
title: "Tamiko top: Fabric Options"
|
||||
- - -
|
||||
|
||||
This pattern has a lot of unfinished edges, so you need something that does not ravel. And you want to go for something with a nice drape.
|
||||
This pattern has a lot of unfinished edges, so you need something that does not ravel. Et vous voulez quelque chose avec un joli drapé.
|
||||
|
||||
Long story short, go for a knitted fabric, or some light scuba or something. No wovens.
|
||||
Bref, choisissez un tissu à mailles, ou un scuba léger, quelque chose dans le genre. Pas de tissu tissé.
|
||||
|
|
|
@ -2,25 +2,25 @@
|
|||
title: "Tamiko top: Sewing Instructions"
|
||||
- - -
|
||||
|
||||
### Étape 1 : Terminer la couture des armoiries
|
||||
### Étape 1 : Terminer l'emmanchure
|
||||
|
||||

|
||||

|
||||
|
||||
- Finish the armhole seam with a narrow hem.
|
||||
- Terminez la couture de la manche avec un ourlet étroit.
|
||||
|
||||
### Étape 2 : Terminer le haut
|
||||
|
||||

|
||||

|
||||
|
||||
<Note>
|
||||
|
||||
Comme votre dessus est plié, c'est une bonne idée de relier les deux moitiés.
|
||||
De cette façon, votre top ne peut pas se déplacer pendant que nous le finissons.
|
||||
Comme votre top est plié, c'est une bonne idée d'épingler les deux moitiés ensemble.
|
||||
Comme ça, votre top ne va pas bouger pendant que nous le finissons.
|
||||
|
||||
</Note>
|
||||
|
||||
- Sew the three seamlines that are marked on your draft. F-H, C and I-J in the diagram, represented by lines and notches on the pattern.
|
||||
- Coudre les trois lignes de couture qui sont marquées sur votre patron. F-H, C et I-J dans le diagramme, représentés par des lignes et des encoches sur le modèle.
|
||||
|
||||
### Step 3: Enjoy!
|
||||
|
||||
Now enjoy your new top and it's zero waste properties!
|
||||
Vous pouvez maintenant enfiler votre nouveau top, qui a généré zéro déchets!
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
- - -
|
||||
title: "Tamiko top: Required Measurements"
|
||||
title: "top: Tamiko : Mensurations requises"
|
||||
- - -
|
||||
|
||||
<PatternMeasurements pattern='tamiko' />
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
- - -
|
||||
title: "Tamiko top: What You Need"
|
||||
title: "Top Tamiko : ce dont vous avez besoin"
|
||||
- - -
|
||||
|
||||
To make Tamiko, you will need the following:
|
||||
Pour faire Tamiko, vous aurez besoin des éléments suivants :
|
||||
|
||||
- Fourniture de base pour la couture
|
||||
- About 1 meter (1.1 yards) of a suitable fabric ([see Fabric options](/docs/patterns/tamiko/fabric))
|
||||
- Environ 1 mètre (1.1 yards) d'un tissu adapté ([voir Options de tissu](/docs/patterns/tamiko/fabric))
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
Contrôle la profondeur de votre armure, en tant que facteur de mesure de votre épaule à épaule.
|
||||
Contrôle la profondeur de votre manche, en fonction de la mensuration de votre épaule à épaule.
|
||||
|
||||
|
||||
## Effet de cette option sur le motif
|
||||
## Effet de cette option sur le patron
|
||||

|
|
@ -1,5 +1,5 @@
|
|||
|
||||
La quantité d'aisance à votre poitrine.
|
||||
L'aisance au niveau de la poitrine.
|
||||
|
||||
|
||||
## Effet de cette option sur le motif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
L'angle par lequel le vêtement sort de votre poitrine vers le bas.
|
||||
L'angle par lequel le vêtement s'évase de votre poitrine vers le bas.
|
||||
|
||||
|
||||
## Effet de cette option sur le motif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
La longueur de la couture d'épaule, en tant que facteur de la mesure d'épaule à épaule.
|
||||
La longueur de la couture d'épaule, en fonction de la mensuration d'épaule à épaule.
|
||||
|
||||
|
||||
## Effet de cette option sur le motif
|
||||
|
|
|
@ -24,7 +24,7 @@ const social = {
|
|||
|
||||
const Footer = ({ app }) => (
|
||||
<footer className="bg-neutral">
|
||||
<div className={`theme-gradient h-1 w-full relative ${app.loading ? 'loading' : ''}`}></div>
|
||||
<div className={`theme-gradient h-14 ${app.loading ? 'loading' : ''}`} />
|
||||
<div className="p-4 py-16 flex flex-row bg-neutral -mt-1 z-0 gap-8 flex-wrap justify-around text-neutral-content">
|
||||
<div className="w-64 mt-2">
|
||||
<div className="px-4 mb-4"><CreativeCommonsLogo /></div>
|
||||
|
@ -159,6 +159,7 @@ const Footer = ({ app }) => (
|
|||
</a>
|
||||
</div>
|
||||
|
||||
<div className={`theme-gradient h-14 ${app.loading ? 'loading' : ''}`} />
|
||||
</footer>
|
||||
)
|
||||
|
||||
|
|
|
@ -46,6 +46,8 @@ const Header = ({ app, setSearch }) => {
|
|||
z-30
|
||||
transition-transform
|
||||
${show ? '': 'fixed top-0 left-0 -translate-y-20'}
|
||||
drop-shadow-xl
|
||||
${app.loading ? "theme-gradient loading" : ""}
|
||||
`}>
|
||||
<div className="max-w-6xl m-auto">
|
||||
<div className="p-2 flex flex-row gap-2 justify-between text-neutral-content">
|
||||
|
@ -55,7 +57,7 @@ const Header = ({ app, setSearch }) => {
|
|||
text-neutral-content bg-transparent
|
||||
border border-transparent
|
||||
hover:bg-transparent hover:border-base-100
|
||||
sm:hidden
|
||||
md:hidden
|
||||
h-12
|
||||
`}
|
||||
onClick={app.togglePrimaryMenu}>
|
||||
|
@ -79,14 +81,14 @@ const Header = ({ app, setSearch }) => {
|
|||
)
|
||||
}
|
||||
</button>
|
||||
<div className="flex flex-row gap-2 sm:hidden">
|
||||
<div className="flex flex-row gap-2 md:hidden">
|
||||
<button className="btn btn-sm btn h-12 px-12" onClick={() => setSearch(true)}>
|
||||
<SearchIcon />
|
||||
</button>
|
||||
</div>
|
||||
<button className={`
|
||||
btn btn-sm h-12
|
||||
hidden sm:flex
|
||||
hidden md:flex
|
||||
flex-row gap-1 mr-4 w-64 px-2
|
||||
bg-base-100 text-base-content
|
||||
hover:bg-base-100 hover:text-base-content
|
||||
|
@ -110,15 +112,11 @@ const Header = ({ app, setSearch }) => {
|
|||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="hidden sm:flex flex-row items-center">
|
||||
<div className="hidden md:flex flex-row items-center">
|
||||
<ThemePicker app={app} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`
|
||||
theme-gradient h-1 w-full z-10 relative -mb-1
|
||||
${app.loading ? 'loading' : ''}
|
||||
`}></div>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
|
|
68
packages/freesewing.dev/components/layouts/bare.js
Normal file
68
packages/freesewing.dev/components/layouts/bare.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
import React from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import Link from 'next/link'
|
||||
// Shared components
|
||||
import Logo from 'shared/components/logos/freesewing.js'
|
||||
import Aside from 'shared/components/navigation/aside'
|
||||
import get from 'lodash.get'
|
||||
|
||||
const PageTitle = ({ app, slug, title }) => {
|
||||
if (title) return <h1>{title}</h1>
|
||||
if (slug) return <h1>{get(app.navigation, slug.split('/')).__title}</h1>
|
||||
|
||||
return <h1>FIXME: This page has no title</h1>
|
||||
}
|
||||
|
||||
const Breadcrumbs = ({ app, slug=false, title }) => {
|
||||
if (!slug) return null
|
||||
const crumbs = []
|
||||
const chunks = slug.split('/')
|
||||
for (const i in chunks) {
|
||||
const j = parseInt(i)+parseInt(1)
|
||||
const page = get(app.navigation, chunks.slice(0,j))
|
||||
if (page) crumbs.push([page.__linktitle, '/'+chunks.slice(0,j).join('/'), (j < chunks.length)])
|
||||
}
|
||||
|
||||
return (
|
||||
<ul className="flex flex-row flex-wrap gap-2 font-bold">
|
||||
<li>
|
||||
<Link href="/">
|
||||
<a title="To the homepage" className="text-base-content">
|
||||
<Logo size={24} fill="currentColor" stroke={false}/>
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
{crumbs.map(crumb => (
|
||||
<React.Fragment key={crumb[1]}>
|
||||
<li className="text-base-content">»</li>
|
||||
<li>
|
||||
{crumb[2]
|
||||
? (
|
||||
<Link href={crumb[1]}>
|
||||
<a title={crumb[0]} className="text-secondary hover:text-secondary-focus">
|
||||
{crumb[0]}
|
||||
</a>
|
||||
</Link>
|
||||
)
|
||||
: <span className="text-base-content">{crumb[0]}</span>
|
||||
}
|
||||
</li>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
const DefaultLayout = ({ app, title=false, children=[] }) => {
|
||||
const router = useRouter()
|
||||
const slug = router.asPath.slice(1)
|
||||
|
||||
return (
|
||||
<>
|
||||
<Aside app={app} slug={slug} mobileOnly />
|
||||
{children}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default DefaultLayout
|
78
packages/freesewing.dev/components/layouts/docs.js
Normal file
78
packages/freesewing.dev/components/layouts/docs.js
Normal file
|
@ -0,0 +1,78 @@
|
|||
import React from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import Link from 'next/link'
|
||||
// Shared components
|
||||
import Logo from 'shared/components/logos/freesewing.js'
|
||||
import Aside from 'shared/components/navigation/aside'
|
||||
import get from 'lodash.get'
|
||||
|
||||
const PageTitle = ({ app, slug, title }) => {
|
||||
if (title) return <h1>{title}</h1>
|
||||
if (slug) return <h1>{get(app.navigation, slug.split('/')).__title}</h1>
|
||||
|
||||
return <h1>FIXME: This page has no title</h1>
|
||||
}
|
||||
|
||||
const Breadcrumbs = ({ app, slug=false, title }) => {
|
||||
if (!slug) return null
|
||||
const crumbs = []
|
||||
const chunks = slug.split('/')
|
||||
for (const i in chunks) {
|
||||
const j = parseInt(i)+parseInt(1)
|
||||
const page = get(app.navigation, chunks.slice(0,j))
|
||||
if (page) crumbs.push([page.__linktitle, '/'+chunks.slice(0,j).join('/'), (j < chunks.length)])
|
||||
}
|
||||
|
||||
return (
|
||||
<ul className="flex flex-row flex-wrap gap-2 font-bold">
|
||||
<li>
|
||||
<Link href="/">
|
||||
<a title="To the homepage" className="text-base-content">
|
||||
<Logo size={24} fill="currentColor" stroke={false}/>
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
{crumbs.map(crumb => (
|
||||
<React.Fragment key={crumb[1]}>
|
||||
<li className="text-base-content">»</li>
|
||||
<li>
|
||||
{crumb[2]
|
||||
? (
|
||||
<Link href={crumb[1]}>
|
||||
<a title={crumb[0]} className="text-secondary hover:text-secondary-focus">
|
||||
{crumb[0]}
|
||||
</a>
|
||||
</Link>
|
||||
)
|
||||
: <span className="text-base-content">{crumb[0]}</span>
|
||||
}
|
||||
</li>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
const DefaultLayout = ({ app, title=false, children=[] }) => {
|
||||
const router = useRouter()
|
||||
const slug = router.asPath.slice(1)
|
||||
|
||||
return (
|
||||
<div className="m-auto flex flex-row justify-center">
|
||||
<Aside app={app} slug={slug} />
|
||||
<section className="py-28 md:py-36">
|
||||
<div>
|
||||
{title && (
|
||||
<div className="px-8 xl:pl-8 2xl:pl-16">
|
||||
<Breadcrumbs app={app} slug={slug} title={title} />
|
||||
<PageTitle app={app} slug={slug} title={title} />
|
||||
</div>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default DefaultLayout
|
115
packages/freesewing.dev/components/wrappers/layout.js
Normal file
115
packages/freesewing.dev/components/wrappers/layout.js
Normal file
|
@ -0,0 +1,115 @@
|
|||
import React from 'react'
|
||||
import { useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import Link from 'next/link'
|
||||
// Shared components
|
||||
import Logo from 'shared/components/logos/freesewing.js'
|
||||
import PrimaryNavigation from 'shared/components/navigation/primary'
|
||||
import get from 'lodash.get'
|
||||
import Right from 'shared/components/icons/right.js'
|
||||
import Left from 'shared/components/icons/left.js'
|
||||
// Site components
|
||||
import Header from 'site/components/header'
|
||||
import Footer from 'site/components/footer'
|
||||
import Search from 'site/components/search'
|
||||
|
||||
const PageTitle = ({ app, slug, title }) => {
|
||||
if (title) return <h1>{title}</h1>
|
||||
if (slug) return <h1>{get(app.navigation, slug.split('/')).__title}</h1>
|
||||
|
||||
return <h1>FIXME: This page has no title</h1>
|
||||
}
|
||||
|
||||
const Breadcrumbs = ({ app, slug=false, title }) => {
|
||||
if (!slug) return null
|
||||
const crumbs = []
|
||||
const chunks = slug.split('/')
|
||||
for (const i in chunks) {
|
||||
const j = parseInt(i)+parseInt(1)
|
||||
const page = get(app.navigation, chunks.slice(0,j))
|
||||
if (page) crumbs.push([page.__linktitle, '/'+chunks.slice(0,j).join('/'), (j < chunks.length)])
|
||||
}
|
||||
|
||||
return (
|
||||
<ul className="flex flex-row flex-wrap gap-2 font-bold">
|
||||
<li>
|
||||
<Link href="/">
|
||||
<a title="To the homepage" className="text-base-content">
|
||||
<Logo size={24} fill="currentColor" stroke={false}/>
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
{crumbs.map(crumb => (
|
||||
<React.Fragment key={crumb[1]}>
|
||||
<li className="text-base-content">»</li>
|
||||
<li>
|
||||
{crumb[2]
|
||||
? (
|
||||
<Link href={crumb[1]}>
|
||||
<a title={crumb[0]} className="text-secondary hover:text-secondary-focus">
|
||||
{crumb[0]}
|
||||
</a>
|
||||
</Link>
|
||||
)
|
||||
: <span className="text-base-content">{crumb[0]}</span>
|
||||
}
|
||||
</li>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
const LayoutWrapper = ({
|
||||
app,
|
||||
title=false,
|
||||
children=[],
|
||||
search,
|
||||
setSearch,
|
||||
noSearch=false,
|
||||
workbench=false,
|
||||
AltMenu=null,
|
||||
}) => {
|
||||
const startNavigation = () => {
|
||||
app.startLoading()
|
||||
// Force close of menu on mobile if it is open
|
||||
if (app.primaryNavigation) app.setPrimaryNavigation(false)
|
||||
// Force close of search modal if it is open
|
||||
if (search) setSearch(false)
|
||||
}
|
||||
|
||||
const router = useRouter()
|
||||
router.events?.on('routeChangeStart', startNavigation)
|
||||
router.events?.on('routeChangeComplete', () => app.stopLoading())
|
||||
const slug = router.asPath.slice(1)
|
||||
const [collapsePrimaryNav, setCollapsePrimaryNav] = useState(workbench || false)
|
||||
const [collapseAltMenu, setCollapseAltMenu] = useState(false)
|
||||
|
||||
return (
|
||||
<div className={`
|
||||
flex flex-col justify-between
|
||||
min-h-screen
|
||||
bg-base-100
|
||||
`}>
|
||||
<Header app={app} setSearch={setSearch} />
|
||||
<main className="grow">{children}</main>
|
||||
{!noSearch && search && (
|
||||
<>
|
||||
<div className={`
|
||||
fixed w-full max-h-screen bg-base-100 top-0 z-30 pt-0 pb-16 px-8
|
||||
md:rounded-lg md:top-24
|
||||
md:max-w-xl md:m-auto md:inset-x-12
|
||||
md:max-w-2xl
|
||||
lg:max-w-4xl
|
||||
`}>
|
||||
<Search app={app} search={search} setSearch={setSearch}/>
|
||||
</div>
|
||||
<div className="fixed top-0 left-0 w-full min-h-screen bg-neutral z-20 bg-opacity-70"></div>
|
||||
</>
|
||||
)}
|
||||
<Footer app={app} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutWrapper
|
68
packages/freesewing.dev/components/wrappers/page.js
Normal file
68
packages/freesewing.dev/components/wrappers/page.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
import { useSwipeable } from 'react-swipeable'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useHotkeys } from 'react-hotkeys-hook'
|
||||
// Layouts components
|
||||
import LayoutWrapper from 'site/components/wrappers/layout'
|
||||
import Docs from 'site/components/layouts/docs'
|
||||
|
||||
const layouts = {
|
||||
docs: Docs,
|
||||
}
|
||||
|
||||
/* This component should wrap all page content */
|
||||
const PageWrapper= ({
|
||||
title="FIXME: No title set",
|
||||
noSearch=false,
|
||||
app=false,
|
||||
layout=Docs,
|
||||
children=[]
|
||||
}) => {
|
||||
|
||||
const swipeHandlers = useSwipeable({
|
||||
onSwipedLeft: evt => (app.primaryMenu) ? app.setPrimaryMenu(false) : null,
|
||||
onSwipedRight: evt => (app.primaryMenu) ? null : app.setPrimaryMenu(true),
|
||||
trackMouse: true
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
const slug = router.asPath.slice(1)
|
||||
|
||||
useEffect(() => app.setSlug(slug), [slug])
|
||||
|
||||
// Trigger search with Ctrl+k
|
||||
useHotkeys('ctrl+k', (evt) => {
|
||||
evt.preventDefault()
|
||||
setSearch(true)
|
||||
})
|
||||
|
||||
const [search, setSearch] = useState(false)
|
||||
|
||||
const childProps = {
|
||||
app: app,
|
||||
title: title,
|
||||
search, setSearch, toggleSearch: () => setSearch(!search),
|
||||
noSearch: noSearch,
|
||||
}
|
||||
|
||||
const Layout = layout
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={swipeHandlers.ref}
|
||||
onMouseDown={swipeHandlers.onMouseDown}
|
||||
data-theme={app.theme}
|
||||
key={app.theme} // Thiis forces the data-theme update
|
||||
>
|
||||
<LayoutWrapper {...childProps}>
|
||||
{Layout
|
||||
? <Layout {...childProps}>{children}</Layout>
|
||||
: children
|
||||
}
|
||||
</LayoutWrapper>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PageWrapper
|
||||
|
|
@ -50,8 +50,5 @@
|
|||
"postcss": "^8.4.4",
|
||||
"tailwindcss": "^3.0.1",
|
||||
"yaml-loader": "^0.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.18.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import Page from 'shared/components/wrappers/page.js'
|
||||
import Page from 'site/components/wrappers/page.js'
|
||||
import useApp from 'site/hooks/useApp.js'
|
||||
import mdxMeta from 'site/prebuild/mdx.en.js'
|
||||
import mdxLoader from 'shared/mdx/loader'
|
||||
import MdxWrapper from 'shared/components/wrappers/mdx'
|
||||
import TocWrapper from 'shared/components/wrappers/toc'
|
||||
import Head from 'next/head'
|
||||
import HelpUs from 'site/components/help-us.js'
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||
|
@ -36,8 +37,17 @@ const MdxPage = props => {
|
|||
<meta property="og:locale" content="en_US" key='locale' />
|
||||
<meta property="og:site_name" content="freesewing.dev" key='site' />
|
||||
</Head>
|
||||
<MdxWrapper mdx={props.mdx} app={app}/>
|
||||
<HelpUs mdx slug={`/${props.page.slug}`} />
|
||||
<div className="flex flex-row-reverse flex-wrap xl:flex-nowrap justify-end px-8 xl:px-0">
|
||||
{props.toc && (
|
||||
<div className="mb-8 px-0 w-full xl:w-80 2xl:w-96 xl:pl-8 2xl:pl-16">
|
||||
<TocWrapper toc={props.toc} app={app}/>
|
||||
</div>
|
||||
)}
|
||||
<div className="px-0 xl:pl-8 2xl:pl-16">
|
||||
<MdxWrapper mdx={props.mdx} app={app}/>
|
||||
<HelpUs mdx slug={`/${props.page.slug}`} />
|
||||
</div>
|
||||
</div>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
@ -61,11 +71,12 @@ export default MdxPage
|
|||
*/
|
||||
export async function getStaticProps({ params, locale }) {
|
||||
|
||||
const { mdx, intro } = await mdxLoader('en', 'dev', params.mdxslug.join('/'))
|
||||
const { mdx, intro, toc } = await mdxLoader('en', 'dev', params.mdxslug.join('/'))
|
||||
|
||||
return {
|
||||
props: {
|
||||
mdx,
|
||||
toc,
|
||||
intro: intro.join(' '),
|
||||
page: {
|
||||
slug: params.mdxslug.join('/'),
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import Page from 'shared/components/wrappers/page.js'
|
||||
import Page from 'site/components/wrappers/page.js'
|
||||
import useApp from 'site/hooks/useApp.js'
|
||||
import Head from 'next/head'
|
||||
import HelpUs from 'site/components/help-us.js'
|
||||
import Link from 'next/link'
|
||||
import Script from 'next/script'
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||
import Layout from 'site/components/layouts/bare'
|
||||
import Navigation, { Icons } from 'shared/components/navigation/primary'
|
||||
|
||||
const HomePage = (props) => {
|
||||
const app = useApp()
|
||||
return (
|
||||
<Page app={app} title="Welcome to FreeSewing.dev">
|
||||
<Page app={app} title="Welcome to FreeSewing.dev" layout={Layout}>
|
||||
<Head>
|
||||
<meta property="og:title" content="FreeSewing.dev" key="title" />
|
||||
<meta property="og:type" content="article" key='type' />
|
||||
|
@ -23,85 +24,60 @@ const HomePage = (props) => {
|
|||
<meta property="og:locale" content="en_US" key='locale' />
|
||||
<meta property="og:site_name" content="freesewing.dev" key='site' />
|
||||
</Head>
|
||||
<Script src="/sw.js"></Script>
|
||||
<div className="max-w-screen-md">
|
||||
<p>
|
||||
FreeSewing.dev hosts documentation for contributors and developers alike.
|
||||
<br />
|
||||
For our maker site, and to try our platform, go
|
||||
to <a
|
||||
href="https://freesewing.org/"
|
||||
title="Go to FreeSewing.org"
|
||||
className="text-secondary font-bold"
|
||||
>freesewing.org</a>.
|
||||
</p>
|
||||
<h2 className="mt-8">What is FreeSewing?</h2>
|
||||
<div className="theme-gradient p-1 -mt-2 mb-2 "></div>
|
||||
<p className="text-2xl sm:text-3xl">
|
||||
FreeSewing is an open source platform for made-to-measure sewing patterns.
|
||||
</p>
|
||||
<p className="text-xl sm:text-2xl">
|
||||
<b>@freeSewing/core</b> is a Javascript library for 2D parametric design
|
||||
</p>
|
||||
<p>
|
||||
It has a primary focus is on sewing patterns,
|
||||
but can be utilized for a variety of similar 2D design tasks.
|
||||
</p>
|
||||
|
||||
<h2 className='mt-8'>How can I try it out?</h2>
|
||||
<div className="theme-gradient p-1 -mt-2 mb-2 "></div>
|
||||
<p className="text-2xl sm:text-3xl">
|
||||
You can try it <Link
|
||||
href="/howtos/environments/browser">
|
||||
<a className="text-secondary">in the browser</a>
|
||||
</Link>, <Link
|
||||
href="/howtos/environments/node">
|
||||
<a className="text-secondary">in NodeJS</a>
|
||||
</Link>,
|
||||
or on any Javascript runtime.
|
||||
</p>
|
||||
<p className="text-xl sm:text-2xl">
|
||||
The includes Deno, AWS Lamba, Cloudflare workers, Vercel Edge functions, Netlify functions, and so on.
|
||||
</p>
|
||||
<p>
|
||||
Or save yourself the trouble, and check <a
|
||||
href="https://freesewing.org/"
|
||||
title="Go to FreeSewing.org"
|
||||
className="text-secondary font-bold"
|
||||
>freesewing.org</a> for a showcase of our software.
|
||||
</p>
|
||||
|
||||
<h2 className='mt-8'>
|
||||
You son of a bitch, I'm in
|
||||
<sup>
|
||||
<a
|
||||
href="https://www.youtube.com/watch?v=nKxvDYHkfSY"
|
||||
className="text-secondary"
|
||||
>*</a>
|
||||
</sup>
|
||||
</h2>
|
||||
<div className="theme-gradient p-1 -mt-2 mb-2 "></div>
|
||||
<p className="text-2xl sm:text-3xl">
|
||||
We are an <a
|
||||
href="https://allcontributors.org/"
|
||||
className="text-secondary"
|
||||
>all-contributors</a> project
|
||||
and welcome all contributions.
|
||||
</p>
|
||||
<p className="text-xl sm:text-2xl">
|
||||
<a
|
||||
href="https://discord.freesewing.org/"
|
||||
className="text-secondary"
|
||||
>Come say hi on Discord</a>,
|
||||
or check out <Link
|
||||
href="/howtos/ways-to-contribute"><a
|
||||
className="text-secondary">ways to contribute</a>
|
||||
</Link> to get inspired.
|
||||
</p>
|
||||
<p>
|
||||
Last but certainly not least, you can also support FreeSewing financially:
|
||||
</p>
|
||||
|
||||
<section
|
||||
style={{
|
||||
backgroundImage: "url('/img/splash.jpg')",
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: '40% 50%',
|
||||
}}
|
||||
className="m-0 p-0 shadow drop-shadow-lg w-full mb-8"
|
||||
>
|
||||
<div className="mx-auto px-8 flex flex-col items-center justify-center min-h-screen lg:min-h-0 lg:py-96">
|
||||
<div className="flex flex-col items-end max-w-4xl">
|
||||
<h1
|
||||
className={`
|
||||
text-4xl font-black text-right px-4
|
||||
sm:text-6xl
|
||||
md:text-7xl px-6
|
||||
lg:px-8
|
||||
bg-secondary
|
||||
`}
|
||||
style={{ textShadow: '1px 1px 3px #000', color: 'white' }}
|
||||
>
|
||||
FreeSewing
|
||||
<span className="font-light">.dev</span>
|
||||
</h1>
|
||||
<h2
|
||||
className={`
|
||||
text-right text-2xl mr-0
|
||||
sm:text-3xl
|
||||
md:text-4xl
|
||||
lg:max-w-1/2 lg:text-4xl xl:pr-0 `}
|
||||
style={{ textShadow: '1px 1px 3px #000', color: 'white' }}
|
||||
>
|
||||
Documentation for FreeSewing contributors & developers
|
||||
</h2>
|
||||
</div>
|
||||
<Icons app={app} active='/'
|
||||
ulClasses="flex flex-row flex-wrap mt-8 justify-around w-full max-w-6xl"
|
||||
liClasses="text-neutral-content w-1/3 my-4 lg:mx-2 lg:w-24"
|
||||
linkClasses={`
|
||||
text-lg lg:text-xl py-1 text-secondary
|
||||
hover:text-secondary sm:hover:text-secondary-focus hover:cursor-pointer
|
||||
flex flex-col items-center capitalize`}
|
||||
/>
|
||||
<p className="text-neutral-content text-center mt-8">
|
||||
To learn more about FreeSewing and try our platform
|
||||
go to <a
|
||||
href="https://freesewing.org/"
|
||||
title="Go to FreeSewing.org"
|
||||
className="text-secondary font-bold"
|
||||
>freesewing.org</a>
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
<div>
|
||||
<div className="max-w-7xl m-auto my-32">
|
||||
<div className="bg-cover bg-neutral w-full bg-center rounded-lg shadow p-4 "
|
||||
style={{backgroundImage: "url(/support.jpg)"}}
|
||||
>
|
||||
|
@ -116,8 +92,25 @@ const HomePage = (props) => {
|
|||
</p>
|
||||
<a role="button" className="btn btn-accent btn-wide ml-4 mb-8" href="https://freesewing.org/patrons/join">Become a Patron</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="max-w-7xl m-auto my-32">
|
||||
<div className="px-8 text-base-content">
|
||||
<Icons app={app}
|
||||
active='/'
|
||||
ulClasses="flex flex-row flex-wrap mt-8 justify-around w-full max-w-6xl"
|
||||
liClasses="w-1/3 my-4 lg:mx-2 lg:w-24"
|
||||
linkClasses={`
|
||||
text-lg lg:text-xl py-1 text-base-content
|
||||
hover:text-secondary sm:hover:text-secondary-focus hover:cursor-pointer
|
||||
flex flex-col items-center capitalize`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="max-w-xl m-auto my-32">
|
||||
<HelpUs slug='/' />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
|
BIN
packages/freesewing.dev/public/img/splash.jpg
Normal file
BIN
packages/freesewing.dev/public/img/splash.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 118 KiB |
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* This is here to force-remove the cache of the old Gatsby site
|
||||
* See: https://github.com/gatsbyjs/gatsby/issues/15623
|
||||
*/
|
||||
self.addEventListener("activate", function (event) {
|
||||
event.waitUntil(
|
||||
caches.keys().then(function (cacheNames) {
|
||||
return Promise.all(
|
||||
cacheNames
|
||||
.map(function (cacheName) {
|
||||
return caches.delete(cacheName);
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
11
packages/freesewing.dev/skip_build.sh
Executable file
11
packages/freesewing.dev/skip_build.sh
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
if git diff HEAD^ HEAD --quiet ../freesewing.shared || git diff --quiet HEAD^ HEAD . ; then
|
||||
# We have local changes, go ahead and build
|
||||
echo "✅ - Changed detected; Let's build this thing"
|
||||
exit 1;
|
||||
else
|
||||
# No changes, do not waste time building this commit
|
||||
echo "🛑 - No changes detected; Let's just not"
|
||||
exit 0;
|
||||
fi
|
||||
|
771
packages/freesewing.lab/available-versions.json
Normal file
771
packages/freesewing.lab/available-versions.json
Normal file
|
@ -0,0 +1,771 @@
|
|||
{
|
||||
"2.20.7": [
|
||||
"aaron",
|
||||
"albert",
|
||||
"bee",
|
||||
"bella",
|
||||
"benjamin",
|
||||
"bent",
|
||||
"breanna",
|
||||
"brian",
|
||||
"bruce",
|
||||
"carlita",
|
||||
"carlton",
|
||||
"cathrin",
|
||||
"charlie",
|
||||
"cornelius",
|
||||
"diana",
|
||||
"examples",
|
||||
"florence",
|
||||
"florent",
|
||||
"holmes",
|
||||
"hortensia",
|
||||
"huey",
|
||||
"hugo",
|
||||
"jaeger",
|
||||
"legend",
|
||||
"lunetius",
|
||||
"paco",
|
||||
"penelope",
|
||||
"plugintest",
|
||||
"rendertest",
|
||||
"sandy",
|
||||
"shin",
|
||||
"simon",
|
||||
"simone",
|
||||
"sven",
|
||||
"tamiko",
|
||||
"teagan",
|
||||
"theo",
|
||||
"tiberius",
|
||||
"titan",
|
||||
"trayvon",
|
||||
"tutorial",
|
||||
"ursula",
|
||||
"wahid",
|
||||
"walburga",
|
||||
"waralee",
|
||||
"yuri"
|
||||
],
|
||||
"2.20.6": [
|
||||
"aaron",
|
||||
"albert",
|
||||
"bee",
|
||||
"bella",
|
||||
"benjamin",
|
||||
"bent",
|
||||
"breanna",
|
||||
"brian",
|
||||
"bruce",
|
||||
"carlita",
|
||||
"carlton",
|
||||
"cathrin",
|
||||
"charlie",
|
||||
"cornelius",
|
||||
"diana",
|
||||
"examples",
|
||||
"florence",
|
||||
"florent",
|
||||
"holmes",
|
||||
"hortensia",
|
||||
"huey",
|
||||
"hugo",
|
||||
"jaeger",
|
||||
"legend",
|
||||
"lunetius",
|
||||
"paco",
|
||||
"penelope",
|
||||
"plugintest",
|
||||
"rendertest",
|
||||
"sandy",
|
||||
"shin",
|
||||
"simon",
|
||||
"simone",
|
||||
"sven",
|
||||
"tamiko",
|
||||
"teagan",
|
||||
"theo",
|
||||
"tiberius",
|
||||
"titan",
|
||||
"trayvon",
|
||||
"tutorial",
|
||||
"ursula",
|
||||
"wahid",
|
||||
"walburga",
|
||||
"waralee",
|
||||
"yuri"
|
||||
],
|
||||
"2.20.5": [
|
||||
"aaron",
|
||||
"albert",
|
||||
"bee",
|
||||
"bella",
|
||||
"benjamin",
|
||||
"bent",
|
||||
"breanna",
|
||||
"brian",
|
||||
"bruce",
|
||||
"carlita",
|
||||
"carlton",
|
||||
"cathrin",
|
||||
"charlie",
|
||||
"cornelius",
|
||||
"diana",
|
||||
"examples",
|
||||
"florence",
|
||||
"florent",
|
||||
"holmes",
|
||||
"hortensia",
|
||||
"huey",
|
||||
"hugo",
|
||||
"jaeger",
|
||||
"legend",
|
||||
"lunetius",
|
||||
"paco",
|
||||
"penelope",
|
||||
"plugintest",
|
||||
"rendertest",
|
||||
"sandy",
|
||||
"shin",
|
||||
"simon",
|
||||
"simone",
|
||||
"sven",
|
||||
"tamiko",
|
||||
"teagan",
|
||||
"theo",
|
||||
"tiberius",
|
||||
"titan",
|
||||
"trayvon",
|
||||
"tutorial",
|
||||
"ursula",
|
||||
"wahid",
|
||||
"walburga",
|
||||
"waralee",
|
||||
"yuri"
|
||||
],
|
||||
"2.20.4": [
|
||||
"aaron",
|
||||
"albert",
|
||||
"bee",
|
||||
"bella",
|
||||
"benjamin",
|
||||
"bent",
|
||||
"breanna",
|
||||
"brian",
|
||||
"bruce",
|
||||
"carlita",
|
||||
"carlton",
|
||||
"cathrin",
|
||||
"charlie",
|
||||
"cornelius",
|
||||
"diana",
|
||||
"examples",
|
||||
"florence",
|
||||
"florent",
|
||||
"holmes",
|
||||
"hortensia",
|
||||
"huey",
|
||||
"hugo",
|
||||
"jaeger",
|
||||
"legend",
|
||||
"lunetius",
|
||||
"paco",
|
||||
"penelope",
|
||||
"plugintest",
|
||||
"rendertest",
|
||||
"sandy",
|
||||
"shin",
|
||||
"simon",
|
||||
"simone",
|
||||
"sven",
|
||||
"tamiko",
|
||||
"teagan",
|
||||
"theo",
|
||||
"tiberius",
|
||||
"titan",
|
||||
"trayvon",
|
||||
"tutorial",
|
||||
"ursula",
|
||||
"wahid",
|
||||
"walburga",
|
||||
"waralee",
|
||||
"yuri"
|
||||
],
|
||||
"2.20.3": [
|
||||
"aaron",
|
||||
"albert",
|
||||
"bee",
|
||||
"bella",
|
||||
"benjamin",
|
||||
"bent",
|
||||
"breanna",
|
||||
"brian",
|
||||
"bruce",
|
||||
"carlita",
|
||||
"carlton",
|
||||
"cathrin",
|
||||
"charlie",
|
||||
"cornelius",
|
||||
"diana",
|
||||
"examples",
|
||||
"florence",
|
||||
"florent",
|
||||
"holmes",
|
||||
"hortensia",
|
||||
"huey",
|
||||
"hugo",
|
||||
"jaeger",
|
||||
"legend",
|
||||
"lunetius",
|
||||
"paco",
|
||||
"penelope",
|
||||
"plugintest",
|
||||
"rendertest",
|
||||
"sandy",
|
||||
"shin",
|
||||
"simon",
|
||||
"simone",
|
||||
"sven",
|
||||
"tamiko",
|
||||
"teagan",
|
||||
"theo",
|
||||
"tiberius",
|
||||
"titan",
|
||||
"trayvon",
|
||||
"tutorial",
|
||||
"ursula",
|
||||
"wahid",
|
||||
"walburga",
|
||||
"waralee",
|
||||
"yuri"
|
||||
],
|
||||
"2.20.2": [
|
||||
"aaron",
|
||||
"albert",
|
||||
"bee",
|
||||
"bella",
|
||||
"benjamin",
|
||||
"bent",
|
||||
"breanna",
|
||||
"brian",
|
||||
"bruce",
|
||||
"carlita",
|
||||
"carlton",
|
||||
"cathrin",
|
||||
"charlie",
|
||||
"cornelius",
|
||||
"diana",
|
||||
"examples",
|
||||
"florence",
|
||||
"florent",
|
||||
"holmes",
|
||||
"hortensia",
|
||||
"huey",
|
||||
"hugo",
|
||||
"jaeger",
|
||||
"legend",
|
||||
"lunetius",
|
||||
"paco",
|
||||
"penelope",
|
||||
"plugintest",
|
||||
"rendertest",
|
||||
"sandy",
|
||||
"shin",
|
||||
"simon",
|
||||
"simone",
|
||||
"sven",
|
||||
"tamiko",
|
||||
"teagan",
|
||||
"theo",
|
||||
"tiberius",
|
||||
"titan",
|
||||
"trayvon",
|
||||
"tutorial",
|
||||
"ursula",
|
||||
"wahid",
|
||||
"walburga",
|
||||
"waralee",
|
||||
"yuri"
|
||||
],
|
||||
"2.20.1": [
|
||||
"aaron",
|
||||
"albert",
|
||||
"bee",
|
||||
"bella",
|
||||
"benjamin",
|
||||
"bent",
|
||||
"breanna",
|
||||
"brian",
|
||||
"bruce",
|
||||
"carlita",
|
||||
"carlton",
|
||||
"cathrin",
|
||||
"charlie",
|
||||
"cornelius",
|
||||
"diana",
|
||||
"examples",
|
||||
"florence",
|
||||
"florent",
|
||||
"holmes",
|
||||
"hortensia",
|
||||
"huey",
|
||||
"hugo",
|
||||
"jaeger",
|
||||
"legend",
|
||||
"lunetius",
|
||||
"paco",
|
||||
"penelope",
|
||||
"plugintest",
|
||||
"rendertest",
|
||||
"sandy",
|
||||
"shin",
|
||||
"simon",
|
||||
"simone",
|
||||
"sven",
|
||||
"tamiko",
|
||||
"teagan",
|
||||
"theo",
|
||||
"tiberius",
|
||||
"titan",
|
||||
"trayvon",
|
||||
"tutorial",
|
||||
"ursula",
|
||||
"wahid",
|
||||
"walburga",
|
||||
"waralee",
|
||||
"yuri"
|
||||
],
|
||||
"2.20.0": [
|
||||
"aaron",
|
||||
"albert",
|
||||
"bee",
|
||||
"bella",
|
||||
"benjamin",
|
||||
"bent",
|
||||
"breanna",
|
||||
"brian",
|
||||
"bruce",
|
||||
"carlita",
|
||||
"carlton",
|
||||
"cathrin",
|
||||
"charlie",
|
||||
"cornelius",
|
||||
"diana",
|
||||
"examples",
|
||||
"florence",
|
||||
"florent",
|
||||
"holmes",
|
||||
"hortensia",
|
||||
"huey",
|
||||
"hugo",
|
||||
"jaeger",
|
||||
"legend",
|
||||
"lunetius",
|
||||
"paco",
|
||||
"penelope",
|
||||
"plugintest",
|
||||
"rendertest",
|
||||
"sandy",
|
||||
"shin",
|
||||
"simon",
|
||||
"simone",
|
||||
"sven",
|
||||
"tamiko",
|
||||
"teagan",
|
||||
"theo",
|
||||
"tiberius",
|
||||
"titan",
|
||||
"trayvon",
|
||||
"tutorial",
|
||||
"ursula",
|
||||
"wahid",
|
||||
"walburga",
|
||||
"waralee",
|
||||
"yuri"
|
||||
],
|
||||
"2.19.9": [
|
||||
"aaron",
|
||||
"albert",
|
||||
"bee",
|
||||
"bella",
|
||||
"benjamin",
|
||||
"bent",
|
||||
"breanna",
|
||||
"brian",
|
||||
"bruce",
|
||||
"carlita",
|
||||
"carlton",
|
||||
"cathrin",
|
||||
"charlie",
|
||||
"cornelius",
|
||||
"diana",
|
||||
"examples",
|
||||
"florence",
|
||||
"florent",
|
||||
"holmes",
|
||||
"hortensia",
|
||||
"huey",
|
||||
"hugo",
|
||||
"jaeger",
|
||||
"legend",
|
||||
"lunetius",
|
||||
"paco",
|
||||
"penelope",
|
||||
"rendertest",
|
||||
"sandy",
|
||||
"shin",
|
||||
"simon",
|
||||
"simone",
|
||||
"sven",
|
||||
"tamiko",
|
||||
"teagan",
|
||||
"theo",
|
||||
"tiberius",
|
||||
"titan",
|
||||
"trayvon",
|
||||
"tutorial",
|
||||
"ursula",
|
||||
"wahid",
|
||||
"walburga",
|
||||
"waralee",
|
||||
"yuri"
|
||||
],
|
||||
"2.19.0": [
|
||||
"aaron",
|
||||
"albert",
|
||||
"bee",
|
||||
"bella",
|
||||
"benjamin",
|
||||
"bent",
|
||||
"breanna",
|
||||
"brian",
|
||||
"bruce",
|
||||
"carlita",
|
||||
"carlton",
|
||||
"cathrin",
|
||||
"charlie",
|
||||
"cornelius",
|
||||
"diana",
|
||||
"examples",
|
||||
"florence",
|
||||
"florent",
|
||||
"holmes",
|
||||
"hortensia",
|
||||
"huey",
|
||||
"hugo",
|
||||
"jaeger",
|
||||
"legend",
|
||||
"lunetius",
|
||||
"paco",
|
||||
"penelope",
|
||||
"rendertest",
|
||||
"sandy",
|
||||
"shin",
|
||||
"simon",
|
||||
"simone",
|
||||
"sven",
|
||||
"tamiko",
|
||||
"teagan",
|
||||
"theo",
|
||||
"tiberius",
|
||||
"titan",
|
||||
"trayvon",
|
||||
"tutorial",
|
||||
"ursula",
|
||||
"wahid",
|
||||
"walburga",
|
||||
"waralee",
|
||||
"yuri"
|
||||
],
|
||||
"2.18.0": [
|
||||
"aaron",
|
||||
"albert",
|
||||
"bella",
|
||||
"benjamin",
|
||||
"bent",
|
||||
"breanna",
|
||||
"brian",
|
||||
"bruce",
|
||||
"carlita",
|
||||
"carlton",
|
||||
"cathrin",
|
||||
"charlie",
|
||||
"cornelius",
|
||||
"diana",
|
||||
"examples",
|
||||
"florence",
|
||||
"florent",
|
||||
"holmes",
|
||||
"hortensia",
|
||||
"huey",
|
||||
"hugo",
|
||||
"jaeger",
|
||||
"legend",
|
||||
"paco",
|
||||
"penelope",
|
||||
"rendertest",
|
||||
"sandy",
|
||||
"shin",
|
||||
"simon",
|
||||
"simone",
|
||||
"sven",
|
||||
"tamiko",
|
||||
"teagan",
|
||||
"theo",
|
||||
"titan",
|
||||
"trayvon",
|
||||
"tutorial",
|
||||
"ursula",
|
||||
"wahid",
|
||||
"waralee",
|
||||
"yuri"
|
||||
],
|
||||
"2.17.1": [
|
||||
"aaron",
|
||||
"albert",
|
||||
"bella",
|
||||
"benjamin",
|
||||
"bent",
|
||||
"breanna",
|
||||
"brian",
|
||||
"bruce",
|
||||
"carlita",
|
||||
"carlton",
|
||||
"cathrin",
|
||||
"charlie",
|
||||
"cornelius",
|
||||
"diana",
|
||||
"examples",
|
||||
"florence",
|
||||
"florent",
|
||||
"holmes",
|
||||
"hortensia",
|
||||
"huey",
|
||||
"hugo",
|
||||
"jaeger",
|
||||
"legend",
|
||||
"paco",
|
||||
"penelope",
|
||||
"rendertest",
|
||||
"sandy",
|
||||
"shin",
|
||||
"simon",
|
||||
"simone",
|
||||
"sven",
|
||||
"tamiko",
|
||||
"teagan",
|
||||
"theo",
|
||||
"titan",
|
||||
"trayvon",
|
||||
"tutorial",
|
||||
"ursula",
|
||||
"wahid",
|
||||
"waralee"
|
||||
],
|
||||
"2.17.0": [
|
||||
"aaron",
|
||||
"albert",
|
||||
"bella",
|
||||
"benjamin",
|
||||
"bent",
|
||||
"breanna",
|
||||
"brian",
|
||||
"bruce",
|
||||
"carlita",
|
||||
"carlton",
|
||||
"cathrin",
|
||||
"charlie",
|
||||
"cornelius",
|
||||
"diana",
|
||||
"examples",
|
||||
"florence",
|
||||
"florent",
|
||||
"holmes",
|
||||
"hortensia",
|
||||
"huey",
|
||||
"hugo",
|
||||
"jaeger",
|
||||
"legend",
|
||||
"paco",
|
||||
"penelope",
|
||||
"rendertest",
|
||||
"sandy",
|
||||
"shin",
|
||||
"simon",
|
||||
"simone",
|
||||
"sven",
|
||||
"tamiko",
|
||||
"teagan",
|
||||
"theo",
|
||||
"titan",
|
||||
"trayvon",
|
||||
"tutorial",
|
||||
"ursula",
|
||||
"wahid",
|
||||
"waralee"
|
||||
],
|
||||
"2.16.2": [
|
||||
"aaron",
|
||||
"albert",
|
||||
"bella",
|
||||
"benjamin",
|
||||
"bent",
|
||||
"breanna",
|
||||
"brian",
|
||||
"bruce",
|
||||
"carlita",
|
||||
"carlton",
|
||||
"cathrin",
|
||||
"charlie",
|
||||
"cornelius",
|
||||
"diana",
|
||||
"examples",
|
||||
"florence",
|
||||
"florent",
|
||||
"holmes",
|
||||
"hortensia",
|
||||
"huey",
|
||||
"hugo",
|
||||
"jaeger",
|
||||
"legend",
|
||||
"paco",
|
||||
"penelope",
|
||||
"rendertest",
|
||||
"sandy",
|
||||
"shin",
|
||||
"simon",
|
||||
"simone",
|
||||
"sven",
|
||||
"tamiko",
|
||||
"teagan",
|
||||
"theo",
|
||||
"titan",
|
||||
"trayvon",
|
||||
"tutorial",
|
||||
"wahid",
|
||||
"waralee"
|
||||
],
|
||||
"2.16.0": [
|
||||
"aaron",
|
||||
"albert",
|
||||
"bella",
|
||||
"benjamin",
|
||||
"bent",
|
||||
"breanna",
|
||||
"brian",
|
||||
"bruce",
|
||||
"carlita",
|
||||
"carlton",
|
||||
"cathrin",
|
||||
"charlie",
|
||||
"cornelius",
|
||||
"diana",
|
||||
"examples",
|
||||
"florence",
|
||||
"florent",
|
||||
"holmes",
|
||||
"hortensia",
|
||||
"huey",
|
||||
"hugo",
|
||||
"jaeger",
|
||||
"legend",
|
||||
"paco",
|
||||
"penelope",
|
||||
"rendertest",
|
||||
"sandy",
|
||||
"shin",
|
||||
"simon",
|
||||
"simone",
|
||||
"sven",
|
||||
"tamiko",
|
||||
"teagan",
|
||||
"theo",
|
||||
"titan",
|
||||
"trayvon",
|
||||
"tutorial",
|
||||
"wahid",
|
||||
"waralee"
|
||||
],
|
||||
"2.15.4": [
|
||||
"aaron",
|
||||
"albert",
|
||||
"bella",
|
||||
"benjamin",
|
||||
"bent",
|
||||
"breanna",
|
||||
"brian",
|
||||
"bruce",
|
||||
"carlita",
|
||||
"carlton",
|
||||
"cathrin",
|
||||
"charlie",
|
||||
"cornelius",
|
||||
"diana",
|
||||
"examples",
|
||||
"florence",
|
||||
"florent",
|
||||
"holmes",
|
||||
"hortensia",
|
||||
"huey",
|
||||
"hugo",
|
||||
"jaeger",
|
||||
"legend",
|
||||
"paco",
|
||||
"penelope",
|
||||
"rendertest",
|
||||
"sandy",
|
||||
"shin",
|
||||
"simon",
|
||||
"simone",
|
||||
"sven",
|
||||
"tamiko",
|
||||
"teagan",
|
||||
"theo",
|
||||
"titan",
|
||||
"trayvon",
|
||||
"tutorial",
|
||||
"wahid",
|
||||
"waralee"
|
||||
],
|
||||
"2.15.0": [
|
||||
"aaron",
|
||||
"albert",
|
||||
"bella",
|
||||
"benjamin",
|
||||
"bent",
|
||||
"breanna",
|
||||
"brian",
|
||||
"bruce",
|
||||
"carlita",
|
||||
"carlton",
|
||||
"cathrin",
|
||||
"charlie",
|
||||
"cornelius",
|
||||
"diana",
|
||||
"examples",
|
||||
"florence",
|
||||
"florent",
|
||||
"holmes",
|
||||
"hortensia",
|
||||
"huey",
|
||||
"hugo",
|
||||
"jaeger",
|
||||
"legend",
|
||||
"paco",
|
||||
"penelope",
|
||||
"rendertest",
|
||||
"sandy",
|
||||
"shin",
|
||||
"simon",
|
||||
"simone",
|
||||
"sven",
|
||||
"tamiko",
|
||||
"teagan",
|
||||
"theo",
|
||||
"titan",
|
||||
"trayvon",
|
||||
"tutorial",
|
||||
"wahid",
|
||||
"waralee"
|
||||
]
|
||||
}
|
|
@ -28,7 +28,7 @@ const Footer = ({ app }) => {
|
|||
|
||||
return (
|
||||
<footer className="bg-neutral">
|
||||
<div className={`theme-gradient h-1 w-full relative ${app.loading ? 'loading' : ''}`}></div>
|
||||
<div className={`theme-gradient h-14 ${app.loading ? 'loading' : ''}`} />
|
||||
<div className="p-4 py-16 flex flex-row bg-neutral -mt-1 z-0 gap-8 flex-wrap justify-around text-neutral-content">
|
||||
<div className="w-64 mt-2">
|
||||
<div className="px-4 mb-4"><CreativeCommonsLogo /></div>
|
||||
|
@ -163,6 +163,7 @@ const Footer = ({ app }) => {
|
|||
</a>
|
||||
</div>
|
||||
|
||||
<div className={`theme-gradient h-14 ${app.loading ? 'loading' : ''}`} />
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -47,7 +47,9 @@ const Header = ({ app }) => {
|
|||
w-full
|
||||
z-30
|
||||
transition-transform
|
||||
drop-shadow-xl
|
||||
${show ? '': 'fixed top-0 left-0 -translate-y-20'}
|
||||
${app.loading ? "theme-gradient loading" : ""}
|
||||
`}>
|
||||
<div className="max-w-6xl m-auto">
|
||||
<div className="p-2 flex flex-row gap-2 justify-between text-neutral-content">
|
||||
|
@ -57,7 +59,7 @@ const Header = ({ app }) => {
|
|||
text-neutral-content bg-transparent
|
||||
border border-transparent
|
||||
hover:bg-transparent hover:border-base-100
|
||||
sm:hidden
|
||||
md:hidden
|
||||
h-12
|
||||
`}
|
||||
onClick={app.togglePrimaryMenu}>
|
||||
|
@ -66,29 +68,23 @@ const Header = ({ app }) => {
|
|||
: <><MenuIcon /><span className="opacity-50 pl-2 flex flex-row items-center gap-1"><Right />swipe</span></>
|
||||
}
|
||||
</button>
|
||||
<div className="hidden sm:flex flex-row items-center">
|
||||
<div className="hidden md:flex flex-row items-center">
|
||||
<PatternPicker app={app} />
|
||||
<VersionPicker app={app} />
|
||||
</div>
|
||||
<div className="hidden md:flex md:flex-row gap-2">
|
||||
<Link href="/">
|
||||
<a className="flex flex-column items-center">
|
||||
<Logo size={36} fill="currentColor" stroke={false} />
|
||||
</a>
|
||||
</Link>
|
||||
<Link href="/">
|
||||
<a role="button" className="btn btn-link btn-sm text-neutral-content h-12">
|
||||
lab.freesewing.dev
|
||||
<a role="button" className="btn btn-link btn-sm text-neutral-content h-12 font-normal lowercase text-2xl">
|
||||
lab.<span className="font-black px-1 normal-case">FreeSewing</span>.dev
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="hidden sm:flex flex-row items-center">
|
||||
<div className="hidden md:flex flex-row items-center">
|
||||
<ThemePicker app={app} />
|
||||
<LocalePicker app={app} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`theme-gradient h-1 w-full z-10 relative -mb-1 ${app.loading ? 'loading' : ''}`}></div>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
|
|
69
packages/freesewing.lab/components/layouts/bare.js
Normal file
69
packages/freesewing.lab/components/layouts/bare.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
import React from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import Link from 'next/link'
|
||||
// Shared components
|
||||
import Logo from 'shared/components/logos/freesewing.js'
|
||||
import Aside from 'shared/components/navigation/aside'
|
||||
import get from 'lodash.get'
|
||||
import { BeforeNav } from './lab'
|
||||
|
||||
const PageTitle = ({ app, slug, title }) => {
|
||||
if (title) return <h1>{title}</h1>
|
||||
if (slug) return <h1>{get(app.navigation, slug.split('/')).__title}</h1>
|
||||
|
||||
return <h1>FIXME: This page has no title</h1>
|
||||
}
|
||||
|
||||
const Breadcrumbs = ({ app, slug=false, title }) => {
|
||||
if (!slug) return null
|
||||
const crumbs = []
|
||||
const chunks = slug.split('/')
|
||||
for (const i in chunks) {
|
||||
const j = parseInt(i)+parseInt(1)
|
||||
const page = get(app.navigation, chunks.slice(0,j))
|
||||
if (page) crumbs.push([page.__linktitle, '/'+chunks.slice(0,j).join('/'), (j < chunks.length)])
|
||||
}
|
||||
|
||||
return (
|
||||
<ul className="flex flex-row flex-wrap gap-2 font-bold">
|
||||
<li>
|
||||
<Link href="/">
|
||||
<a title="To the homepage" className="text-base-content">
|
||||
<Logo size={24} fill="currentColor" stroke={false}/>
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
{crumbs.map(crumb => (
|
||||
<React.Fragment key={crumb[1]}>
|
||||
<li className="text-base-content">»</li>
|
||||
<li>
|
||||
{crumb[2]
|
||||
? (
|
||||
<Link href={crumb[1]}>
|
||||
<a title={crumb[0]} className="text-secondary hover:text-secondary-focus">
|
||||
{crumb[0]}
|
||||
</a>
|
||||
</Link>
|
||||
)
|
||||
: <span className="text-base-content">{crumb[0]}</span>
|
||||
}
|
||||
</li>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
const DefaultLayout = ({ app, title=false, children=[] }) => {
|
||||
const router = useRouter()
|
||||
const slug = router.asPath.slice(1)
|
||||
console.log(BeforeNav)
|
||||
return (
|
||||
<>
|
||||
<Aside app={app} slug={slug} before={<BeforeNav app={app}/>} mobileOnly />
|
||||
{children}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default DefaultLayout
|
51
packages/freesewing.lab/components/layouts/lab.js
Normal file
51
packages/freesewing.lab/components/layouts/lab.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
import ThemePicker from 'shared/components/theme-picker.js'
|
||||
import LocalePicker from 'shared/components/locale-picker.js'
|
||||
import PatternPicker from 'site/components/pattern-picker.js'
|
||||
import VersionPicker from 'site/components/version-picker.js'
|
||||
|
||||
export const BeforeNav = ({ app }) => (
|
||||
<>
|
||||
<div className="md:hidden flex flex-row flex-wrap sm:flex-nowrap gap-2 mb-2">
|
||||
<ThemePicker app={app} />
|
||||
<LocalePicker app={app} />
|
||||
</div>
|
||||
<div className="md:hidden flex flex-row flex-wrap sm:flex-nowrap gap-2 mb-2">
|
||||
<PatternPicker app={app} />
|
||||
<VersionPicker app={app} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
const LabLayout = ({ app, AltMenu, children=[] }) => (
|
||||
<div className="py-24 lg:py-36 flex flex-row">
|
||||
<div className="w-full px-8">
|
||||
{children}
|
||||
</div>
|
||||
<aside className={`
|
||||
fixed top-0 right-0
|
||||
pt-20 pb-8 px-8
|
||||
md:pt-0
|
||||
md:relative md:transform-none
|
||||
h-screen w-screen
|
||||
bg-base-100
|
||||
md:bg-base-50
|
||||
md:flex
|
||||
md:sticky
|
||||
overflow-y-scroll
|
||||
z-20
|
||||
bg-base-100 text-base-content
|
||||
transition-all
|
||||
xl:w-1/4
|
||||
${app.primaryMenu ? '' : 'translate-x-[-100%]'} transition-transform
|
||||
md:flex-row
|
||||
md:w-80
|
||||
lg:w-96
|
||||
shrink-0
|
||||
`}>
|
||||
<BeforeNav app={app}/>
|
||||
{AltMenu}
|
||||
</aside>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default LabLayout
|
|
@ -10,10 +10,10 @@ const PatternPicker = ({ app }) => {
|
|||
const version = useVersion()
|
||||
|
||||
return (
|
||||
<div className="dropdown">
|
||||
<div className="dropdown w-full md:w-auto">
|
||||
<div tabIndex="0" className={`
|
||||
m-0 btn btn-neutral flex flex-row gap-2
|
||||
sm:btn-ghost
|
||||
m-0 btn btn-neutral flex flex-row gap-2 btn-outline
|
||||
md:btn-ghost
|
||||
hover:bg-neutral hover:border-neutral-content
|
||||
`}>
|
||||
<DesignIcon />
|
||||
|
|
|
@ -24,10 +24,10 @@ const PatternPicker = ({ app }) => {
|
|||
const version = useVersion()
|
||||
|
||||
return (
|
||||
<div className="dropdown">
|
||||
<div className="dropdown w-full md:w-auto">
|
||||
<div tabIndex="0" className={`
|
||||
m-0 btn btn-neutral flex flex-row gap-2
|
||||
sm:btn-ghost
|
||||
m-0 btn btn-neutral flex flex-row gap-2 btn-outline
|
||||
md:btn-ghost
|
||||
hover:bg-neutral hover:border-neutral-content
|
||||
`}>
|
||||
<VersionsIcon />
|
||||
|
|
88
packages/freesewing.lab/components/wrappers/layout.js
Normal file
88
packages/freesewing.lab/components/wrappers/layout.js
Normal file
|
@ -0,0 +1,88 @@
|
|||
import React from 'react'
|
||||
import { useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import Link from 'next/link'
|
||||
// Shared components
|
||||
import Logo from 'shared/components/logos/freesewing.js'
|
||||
import PrimaryNavigation from 'shared/components/navigation/primary'
|
||||
import get from 'lodash.get'
|
||||
import Right from 'shared/components/icons/right.js'
|
||||
import Left from 'shared/components/icons/left.js'
|
||||
// Site components
|
||||
import Header from 'site/components/header'
|
||||
import Footer from 'site/components/footer'
|
||||
|
||||
export const PageTitle = ({ app, slug, title }) => {
|
||||
if (title) return <h1>{title}</h1>
|
||||
if (slug) return <h1>{get(app.navigation, slug.split('/')).__title}</h1>
|
||||
|
||||
return <h1>FIXME: This page has no title</h1>
|
||||
}
|
||||
|
||||
export const Breadcrumbs = ({ app, slug=false, title }) => {
|
||||
if (!slug) return null
|
||||
const crumbs = []
|
||||
const chunks = slug.split('/')
|
||||
for (const i in chunks) {
|
||||
const j = parseInt(i)+parseInt(1)
|
||||
const page = get(app.navigation, chunks.slice(0,j))
|
||||
if (page) crumbs.push([page.__linktitle, '/'+chunks.slice(0,j).join('/'), (j < chunks.length)])
|
||||
}
|
||||
|
||||
return (
|
||||
<ul className="flex flex-row flex-wrap gap-2 font-bold">
|
||||
<li>
|
||||
<Link href="/">
|
||||
<a title="To the homepage" className="text-base-content">
|
||||
<Logo size={24} fill="currentColor" stroke={false}/>
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
{crumbs.map(crumb => (
|
||||
<React.Fragment key={crumb[1]}>
|
||||
<li className="text-base-content">»</li>
|
||||
<li>
|
||||
{crumb[2]
|
||||
? (
|
||||
<Link href={crumb[1]}>
|
||||
<a title={crumb[0]} className="text-secondary hover:text-secondary-focus">
|
||||
{crumb[0]}
|
||||
</a>
|
||||
</Link>
|
||||
)
|
||||
: <span className="text-base-content">{crumb[0]}</span>
|
||||
}
|
||||
</li>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
const LayoutWrapper = ({ app, title=false, children=[] }) => {
|
||||
|
||||
const startNavigation = () => {
|
||||
app.startLoading()
|
||||
// Force close of menu on mobile if it is open
|
||||
if (app.primaryMenu) app.setPrimaryMenu(false)
|
||||
}
|
||||
|
||||
const router = useRouter()
|
||||
router.events?.on('routeChangeStart', startNavigation)
|
||||
router.events?.on('routeChangeComplete', app.stopLoading)
|
||||
const slug = router.asPath.slice(1)
|
||||
|
||||
return (
|
||||
<div className={`
|
||||
flex flex-col justify-between
|
||||
min-h-screen
|
||||
bg-base-100
|
||||
`}>
|
||||
<Header app={app}/>
|
||||
<main className="grow">{children}</main>
|
||||
<Footer app={app} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutWrapper
|
52
packages/freesewing.lab/components/wrappers/page.js
Normal file
52
packages/freesewing.lab/components/wrappers/page.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
import { useSwipeable } from 'react-swipeable'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useHotkeys } from 'react-hotkeys-hook'
|
||||
// Layouts components
|
||||
import LayoutWrapper from 'site/components/wrappers/layout'
|
||||
|
||||
/* This component should wrap all page content */
|
||||
const PageWrapper= ({
|
||||
title="FIXME: No title set",
|
||||
app=false,
|
||||
layout=false,
|
||||
children=[]
|
||||
}) => {
|
||||
|
||||
const swipeHandlers = useSwipeable({
|
||||
onSwipedLeft: evt => (app.primaryMenu) ? app.setPrimaryMenu(false) : null,
|
||||
onSwipedRight: evt => (app.primaryMenu) ? null : app.setPrimaryMenu(true),
|
||||
trackMouse: true
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
const slug = router.asPath.slice(1)
|
||||
|
||||
useEffect(() => app.setSlug(slug), [slug])
|
||||
|
||||
const childProps = {
|
||||
app: app,
|
||||
title: title,
|
||||
}
|
||||
|
||||
const Layout = layout
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={swipeHandlers.ref}
|
||||
onMouseDown={swipeHandlers.onMouseDown}
|
||||
data-theme={app.theme}
|
||||
key={app.theme} // Thiis forces the data-theme update
|
||||
>
|
||||
<LayoutWrapper {...childProps}>
|
||||
{Layout
|
||||
? <Layout {...childProps}>{children}</Layout>
|
||||
: children
|
||||
}
|
||||
</LayoutWrapper>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PageWrapper
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
"dev": "next dev -p 3002",
|
||||
"develop": "next dev -p 3002",
|
||||
"prebuild": "cd ../utils && npm run build && cd - && SITE=lab node ../freesewing.shared/prebuild/index.mjs",
|
||||
"cibuild": "yarn prebuild && next build",
|
||||
"build": "next build",
|
||||
"export": "yarn prebuild && next build && next export",
|
||||
"start": "next start -p 3002",
|
||||
|
@ -52,8 +53,5 @@
|
|||
"postcss": "^8.4.4",
|
||||
"tailwindcss": "^3.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.18.1"
|
||||
},
|
||||
"browserslist": [ "last 2 versions" ]
|
||||
}
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
import Page from 'shared/components/wrappers/page.js'
|
||||
import React from 'react'
|
||||
import Page from 'site/components/wrappers/page.js'
|
||||
import useApp from 'site/hooks/useApp.js'
|
||||
import Head from 'next/head'
|
||||
import Link from 'next/link'
|
||||
import About from 'site/components/about.js'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { defaultVersion, formatVersionTitle, formatVersionUri } from 'site/components/version-picker.js'
|
||||
import TutorialIcon from 'shared/components/icons/tutorial.js'
|
||||
import DesignIcon from 'shared/components/icons/design.js'
|
||||
import BoxIcon from 'shared/components/icons/box.js'
|
||||
import CogIcon from 'shared/components/icons/cog.js'
|
||||
import Layout from 'site/components/layouts/bare'
|
||||
import { PageTitle, Breadcrumbs } from 'site/components/wrappers/layout'
|
||||
|
||||
const links = (section, list, version) => list.map(design => (
|
||||
<li key={design} className="">
|
||||
|
@ -14,13 +20,49 @@ const links = (section, list, version) => list.map(design => (
|
|||
</li>
|
||||
))
|
||||
|
||||
const PatternListPageTemplate = ({ sections=false, version=false }) => {
|
||||
const icons = {
|
||||
accessories: (className='') => <TutorialIcon className={className}/>,
|
||||
blocks: (className='') => <BoxIcon className={className}/>,
|
||||
garments: (className='') => <DesignIcon className={className}/>,
|
||||
utilities: (className='') => <CogIcon className={className}/>,
|
||||
}
|
||||
|
||||
const Section = ({ section, version, patterns }) => {
|
||||
const { t } = useTranslation(['patterns'])
|
||||
return patterns.map(design => (
|
||||
<Link href={formatVersionUri(version, design)}>
|
||||
<a className={`
|
||||
text-secondary border rounded-lg
|
||||
flex flex-col gap-1 px-4 py-2 grow justify-between text-2xl
|
||||
md:text-4xl
|
||||
lg:text-4xl
|
||||
xl:text-6xl
|
||||
2xl:text-7xl
|
||||
hover:border hover:border-secondary hover:bg-secondary hover:bg-opacity-10
|
||||
shadow
|
||||
`}>
|
||||
<div className="flex flex-row items-center justify-items-start w-full">
|
||||
<span className="text-2xl md:text-3xl lg:text-4xl xl:text-4xl 2xl:text-5xl font-bold grow capitalize">
|
||||
{t(`patterns:${design}.t`)}
|
||||
</span>
|
||||
{icons[section]("w-12 h-12 md:h-20 md:w-20 xl:w-32 xl:h-32 shrink-0")}
|
||||
</div>
|
||||
<span className="text-xl md:text-2xl xl:text-3xl pb-2 xl:pb-4 2xl:text-4xl">{t(`patterns:${design}.d`)}</span>
|
||||
</a>
|
||||
</Link>
|
||||
))
|
||||
}
|
||||
|
||||
const PatternListPageTemplate = ({ section=false, version=false }) => {
|
||||
const app = useApp()
|
||||
const { t } = useTranslation(['app'])
|
||||
if (sections === false) sections = Object.keys(app.patterns)
|
||||
|
||||
const title = section
|
||||
? app.navigation[section].__title
|
||||
: t('designs')
|
||||
|
||||
return (
|
||||
<Page app={app} title={`FreeSewing Lab: ${formatVersionTitle(version)}`}>
|
||||
<Page app={app} title={`FreeSewing Lab: ${formatVersionTitle(version)}`} layout={Layout}>
|
||||
<Head>
|
||||
<meta property="og:title" content="lab.FreeSewing.dev" key="title" />
|
||||
<meta property="og:type" content="article" key='type' />
|
||||
|
@ -34,22 +76,30 @@ const PatternListPageTemplate = ({ sections=false, version=false }) => {
|
|||
<meta property="og:locale" content="en_US" key='locale' />
|
||||
<meta property="og:site_name" content="lab.freesewing.dev" key='site' />
|
||||
</Head>
|
||||
<div className="max-w-screen-md">
|
||||
{Object.keys(app.navigation).map(section => {
|
||||
if (sections.indexOf(section) !== -1) return (
|
||||
<div key={section}>
|
||||
<h2>{t(app.navigation[section].__title)}</h2>
|
||||
<ul className="flex flex-row flex-wrap gap-2">
|
||||
{links(section, app.patterns[section], version)}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
else return null
|
||||
})}
|
||||
<About />
|
||||
<div className="max-w-7xl m-auto py-20 md:py-36 min-h-screen">
|
||||
<section className="px-8">
|
||||
<PageTitle app={app} slug={'/'+section} title={title} />
|
||||
{section
|
||||
? (
|
||||
<div className="flex flex-row flex-wrap gap-4 items-center justify-center my-8">
|
||||
<Section section={section} version={version} patterns={app.patterns[section]} />
|
||||
</div>
|
||||
)
|
||||
: Object.keys(app.patterns).map(section => (
|
||||
<div key={section} className="mb-12">
|
||||
<h2 className="pb-0">{app.navigation[section].__title}</h2>
|
||||
<div className="flex flex-row flex-wrap gap-4 items-center justify-center my-8">
|
||||
<Section {...{section, version}} patterns={app.patterns[section]} />
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</section>
|
||||
</div>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
||||
export default PatternListPageTemplate
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import Page from 'shared/components/wrappers/page.js'
|
||||
import Page from 'site/components/wrappers/page.js'
|
||||
import useApp from 'site/hooks/useApp.js'
|
||||
import WorkbenchWrapper from 'shared/components/wrappers/workbench.js'
|
||||
import { useRouter } from 'next/router'
|
||||
import Layout from 'site/components/layouts/lab'
|
||||
|
||||
const WorkbenchPage = ({ pattern }) => {
|
||||
const app = useApp()
|
||||
|
@ -9,8 +10,8 @@ const WorkbenchPage = ({ pattern }) => {
|
|||
const { preload, from } = router.query
|
||||
|
||||
return (
|
||||
<Page app={app} noLayout>
|
||||
<WorkbenchWrapper {...{ app, pattern, preload, from }} />
|
||||
<Page app={app}>
|
||||
<WorkbenchWrapper {...{ app, pattern, preload, from }} layout={Layout} />
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
|
16
packages/freesewing.lab/pages/accessories/index.js
Normal file
16
packages/freesewing.lab/pages/accessories/index.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||
import PageTemplate from 'site/page-templates/pattern-list.js'
|
||||
|
||||
const Page = props => <PageTemplate section='accessories' />
|
||||
|
||||
export default Page
|
||||
|
||||
export async function getStaticProps({ locale }) {
|
||||
return {
|
||||
props: {
|
||||
...(await serverSideTranslations(locale)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
16
packages/freesewing.lab/pages/blocks/index.js
Normal file
16
packages/freesewing.lab/pages/blocks/index.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||
import PageTemplate from 'site/page-templates/pattern-list.js'
|
||||
|
||||
const Page = props => <PageTemplate section='blocks' />
|
||||
|
||||
export default Page
|
||||
|
||||
export async function getStaticProps({ locale }) {
|
||||
return {
|
||||
props: {
|
||||
...(await serverSideTranslations(locale)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
16
packages/freesewing.lab/pages/garments/index.js
Normal file
16
packages/freesewing.lab/pages/garments/index.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||
import PageTemplate from 'site/page-templates/pattern-list.js'
|
||||
|
||||
const Page = props => <PageTemplate section='garments' />
|
||||
|
||||
export default Page
|
||||
|
||||
export async function getStaticProps({ locale }) {
|
||||
return {
|
||||
props: {
|
||||
...(await serverSideTranslations(locale)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,7 +1,134 @@
|
|||
import Page from 'site/components/wrappers/page.js'
|
||||
import useApp from 'site/hooks/useApp.js'
|
||||
import Head from 'next/head'
|
||||
import Link from 'next/link'
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||
import Page from 'site/page-templates/pattern-list.js'
|
||||
import Layout from 'site/components/layouts/bare'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Navigation, { Icons } from 'shared/components/navigation/primary'
|
||||
|
||||
export default Page
|
||||
const HomePage = (props) => {
|
||||
const app = useApp()
|
||||
const { t } = useTranslation(['lab'])
|
||||
return (
|
||||
<Page app={app} title="Welcome to FreeSewing.dev" layout={Layout}>
|
||||
<Head>
|
||||
<meta property="og:title" content="FreeSewing.dev" key="title" />
|
||||
<meta property="og:type" content="article" key='type' />
|
||||
<meta property="og:description" content="Documentation and tutorials for FreeSewing developers and contributors. Plus our Developers Blog" key='description' />
|
||||
<meta property="og:article:author" content='Joost De Cock' key='author' />
|
||||
<meta property="og:image" content="https://canary.backend.freesewing.org/og-img/en/dev/" key='image' />
|
||||
<meta property="og:image:type" content="image/png" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:url" content="https://freesewing.dev/" key='url' />
|
||||
<meta property="og:locale" content="en_US" key='locale' />
|
||||
<meta property="og:site_name" content="freesewing.dev" key='site' />
|
||||
</Head>
|
||||
<section
|
||||
style={{
|
||||
backgroundImage: "url('/img/splash.jpg')",
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: '40% 50%',
|
||||
}}
|
||||
className="m-0 p-0 shadow drop-shadow-lg w-full mb-8"
|
||||
>
|
||||
<div className="mx-auto px-8 flex flex-col items-center justify-center min-h-screen py-24 lg:min-h-0 lg:py-96">
|
||||
<div className="flex flex-col items-end max-w-4xl">
|
||||
<h1
|
||||
className={`
|
||||
text-3xl font-black text-right px-4
|
||||
sm:text-6xl
|
||||
md:text-7xl px-6
|
||||
lg:px-8
|
||||
bg-accent
|
||||
`}
|
||||
style={{ textShadow: '1px 1px 3px #000', color: 'white' }}
|
||||
>
|
||||
<span className="font-light">lab.</span>
|
||||
FreeSewing
|
||||
<span className="font-light">.dev</span>
|
||||
</h1>
|
||||
|
||||
<h2
|
||||
className={`
|
||||
text-xl mr-0 mt-4 font-bold
|
||||
sm:text-3xl
|
||||
md:text-4xl
|
||||
lg:max-w-1/2 lg:text-4xl
|
||||
xl:pr-0 `}
|
||||
style={{ textShadow: '1px 1px 3px #000', color: 'white' }}
|
||||
>{t('slogan')}:</h2>
|
||||
<ul
|
||||
className={`
|
||||
text-xl mr-8 font-bold list list-inside list-disc
|
||||
sm:text-3xl
|
||||
md:text-4xl
|
||||
lg:max-w-1/2 lg:text-3xl
|
||||
xl:pr-0 `}
|
||||
style={{ textShadow: '1px 1px 3px #000', color: 'white' }}
|
||||
>
|
||||
<li>{t('slogan1')}</li>
|
||||
<li>{t('slogan2')}</li>
|
||||
<li>{t('slogan3')}</li>
|
||||
<li>{t('slogan4')}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<Icons app={app} active='/'
|
||||
ulClasses="flex flex-row flex-wrap mt-8 justify-around w-full max-w-6xl"
|
||||
liClasses="text-neutral-content w-1/2 my-4 lg:mx-2 lg:w-24"
|
||||
linkClasses={`
|
||||
text-lg lg:text-xl py-1 text-secondary text-center
|
||||
hover:text-secondary sm:hover:text-secondary-focus hover:cursor-pointer
|
||||
flex flex-col items-center capitalize`}
|
||||
/>
|
||||
<p className="text-neutral-content text-center mt-8">
|
||||
To learn more about FreeSewing and try our platform
|
||||
go to <a
|
||||
href="https://freesewing.org/"
|
||||
title="Go to FreeSewing.org"
|
||||
className="text-secondary font-bold"
|
||||
>freesewing.org</a>
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
<div>
|
||||
<div className="max-w-7xl m-auto my-32">
|
||||
<div className="bg-cover bg-neutral w-full bg-center rounded-lg shadow p-4 "
|
||||
style={{backgroundImage: "url(/support.jpg)"}}
|
||||
>
|
||||
<h2 className="text-neutral-content p-4 text-4xl font-bold sm:font-light sm:text-6xl drop-shadow">Support FreeSewing</h2>
|
||||
<p className="text-neutral-content p-4 font-bold max-w-md text-lg">
|
||||
FreeSewing is fuelled by a voluntary subscription model
|
||||
</p>
|
||||
<p className="text-neutral-content p-4 font-bold max-w-md text-lg">
|
||||
If you think what we do is worthwhile,
|
||||
and if you can spare a few coins each month without hardship,
|
||||
please support our work
|
||||
</p>
|
||||
<a role="button" className="btn btn-accent btn-wide ml-4 mb-8" href="https://freesewing.org/patrons/join">Become a Patron</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="max-w-7xl m-auto my-32">
|
||||
<div className="px-8 text-base-content">
|
||||
<Icons app={app}
|
||||
active='/'
|
||||
ulClasses="flex flex-row flex-wrap mt-8 justify-around w-full max-w-6xl"
|
||||
liClasses="w-1/3 my-4 lg:mx-2 lg:w-24"
|
||||
linkClasses={`
|
||||
text-lg lg:text-xl py-1 text-base-content text-center
|
||||
hover:text-secondary sm:hover:text-secondary-focus hover:cursor-pointer
|
||||
flex flex-col items-center capitalize`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
||||
export default HomePage
|
||||
|
||||
export async function getStaticProps({ locale }) {
|
||||
return {
|
||||
|
@ -12,3 +139,4 @@ export async function getStaticProps({ locale }) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
|
16
packages/freesewing.lab/pages/utilities/index.js
Normal file
16
packages/freesewing.lab/pages/utilities/index.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||
import PageTemplate from 'site/page-templates/pattern-list.js'
|
||||
|
||||
const Page = props => <PageTemplate section='utilities' />
|
||||
|
||||
export default Page
|
||||
|
||||
export async function getStaticProps({ locale }) {
|
||||
return {
|
||||
props: {
|
||||
...(await serverSideTranslations(locale)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
1
packages/freesewing.lab/public/img/splash.jpg
Symbolic link
1
packages/freesewing.lab/public/img/splash.jpg
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../../freesewing.dev/public/img/splash.jpg
|
|
@ -8,14 +8,13 @@
|
|||
"2.20.1",
|
||||
"2.20.0",
|
||||
"2.19.9",
|
||||
"2.19.8",
|
||||
"2.19.7",
|
||||
"2.19.6",
|
||||
"2.19.5",
|
||||
"2.19.4",
|
||||
"2.19.3",
|
||||
"2.19.2",
|
||||
"2.19.1",
|
||||
"2.19.0"
|
||||
"2.19.0",
|
||||
"2.18.0",
|
||||
"2.17.1",
|
||||
"2.17.0",
|
||||
"2.16.2",
|
||||
"2.16.0",
|
||||
"2.15.4",
|
||||
"2.15.0"
|
||||
]
|
||||
|
||||
|
|
7
packages/freesewing.shared/components/icons/box.js
Normal file
7
packages/freesewing.shared/components/icons/box.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
const BoxIcon = ({ className="m-6 h-6" }) => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default BoxIcon
|
8
packages/freesewing.shared/components/icons/cog.js
Normal file
8
packages/freesewing.shared/components/icons/cog.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
const CogIcon = ({ className='h-6 m-6' }) => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default CogIcon
|
|
@ -1,5 +1,5 @@
|
|||
const Design = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="currentColor" viewBox="0 0 24 24" stroke="currentColor">
|
||||
const Design = ({ className='h-6 w-6' }) => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="currentColor" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={0.75} d="m11.975 2.9104c-1.5285 0-2.7845 1.2563-2.7845 2.7848 0 0.7494 0.30048 1.4389 0.78637 1.9394a0.79437 0.79437 0 0 0 0.0084 0.00839c0.38087 0.38087 0.74541 0.62517 0.94538 0.82483 0.19998 0.19966 0.25013 0.2645 0.25013 0.51907v0.65964l-9.1217 5.2665c-0.28478 0.16442-0.83603 0.46612-1.3165 0.9611-0.48047 0.49498-0.92451 1.3399-0.66684 2.2585 0.22026 0.78524 0.7746 1.3486 1.3416 1.5878 0.56697 0.23928 1.0982 0.23415 1.4685 0.23415h18.041c0.37033 0 0.90158 0.0051 1.4686-0.23415 0.56697-0.23928 1.1215-0.80261 1.3418-1.5878 0.25767-0.91859-0.18662-1.7636-0.66709-2.2585-0.48046-0.49498-1.0315-0.79669-1.3162-0.9611l-8.9844-5.1873v-0.73889c0-0.70372-0.35623-1.2837-0.71653-1.6435-0.35778-0.3572-0.70316-0.58503-0.93768-0.81789-0.20864-0.21601-0.33607-0.50298-0.33607-0.83033 0-0.67 0.52595-1.1962 1.1959-1.1962 0.67001 0 1.1962 0.5262 1.1962 1.1962a0.79429 0.79429 0 0 0 0.79434 0.79427 0.79429 0.79429 0 0 0 0.79427-0.79427c0-1.5285-1.2563-2.7848-2.7848-2.7848zm-0.06859 8.2927 8.9919 5.1914c0.28947 0.16712 0.69347 0.41336 0.94393 0.67138 0.25046 0.25803 0.31301 0.3714 0.24754 0.60483-0.10289 0.36677-0.19003 0.40213-0.35969 0.47373-0.16967 0.07161-0.47013 0.09952-0.80336 0.09952h-18.041c-0.33323 0-0.6337-0.02792-0.80336-0.09952-0.16967-0.07161-0.25675-0.10696-0.35963-0.47373-0.06548-0.23342-0.00303-0.3468 0.24748-0.60483 0.25046-0.25803 0.65471-0.50426 0.94418-0.67138z" />
|
||||
</svg>
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* Sourced from heroicons.com - Thanks guys! */
|
||||
const Docs = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
const Docs = ({ className="h-6 w-6" }) => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
||||
</svg>
|
||||
)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const Guides = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
const Guides = ({ className="h-6 w-6" }) => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 3L3 10.53v.98l6.84 2.65L12.48 21h.98L21 3z" />
|
||||
</svg>
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* Sourced from heroicons.com - Thanks guys! */
|
||||
const Help = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
const Help = ({ className="w-6 h-6" }) => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* Sourced from heroicons.com - Thanks guys! */
|
||||
const Rss = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
const Rss = ({ className='h-6 w-6' }) => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 5c7.18 0 13 5.82 13 13M6 11a7 7 0 017 7m-6 0a1 1 0 11-2 0 1 1 0 012 0z" />
|
||||
</svg>
|
||||
)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const Tutorial = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
const Tutorial = ({ className="w-6 h-6" }) => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path d="M12 14l9-5-9-5-9 5 9 5z" />
|
||||
<path d="M12 14l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 14l9-5-9-5-9 5 9 5zm0 0l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14zm-4 6v-7.5l4-2.222" />
|
||||
|
|
|
@ -74,8 +74,9 @@ const asideClasses = `
|
|||
overflow-y-scroll
|
||||
z-20
|
||||
bg-base-100 text-base-content
|
||||
sm:bg-neutral sm:bg-opacity-95 sm:text-neutral-content
|
||||
transition-all `
|
||||
transition-all
|
||||
xl:w-1/4
|
||||
`
|
||||
|
||||
|
||||
const DefaultLayout = ({
|
||||
|
@ -110,53 +111,58 @@ const DefaultLayout = ({
|
|||
bg-base-100
|
||||
`}>
|
||||
<Header app={app} setSearch={setSearch} />
|
||||
<main className={`
|
||||
grow flex flex-row
|
||||
gap-2
|
||||
${!workbench ? 'lg:gap-8 xl:gap-16' : ''}
|
||||
`}>
|
||||
<aside className={`
|
||||
${asideClasses}
|
||||
${app.primaryMenu ? '' : 'translate-x-[-100%]'} transition-transform
|
||||
sm:flex-row-reverse
|
||||
${workbench && collapsePrimaryNav
|
||||
? 'sm:px-0 sm:w-16'
|
||||
: 'sm:px-1 md:px-4 lg:px-8 sm:w-[38.2%]'
|
||||
}
|
||||
`}>
|
||||
{workbench && (
|
||||
<div className={`hidden sm:flex`}>
|
||||
<button
|
||||
className="text-secondary-focus h-full px-2 pl-4 hover:animate-pulse"
|
||||
onClick={() => setCollapsePrimaryNav(!collapsePrimaryNav)}
|
||||
>
|
||||
{collapsePrimaryNav
|
||||
? <><Right /><Right /><Right /></>
|
||||
: <><Left /><Left /><Left /></>
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<PrimaryNavigation app={app} active={slug}/>
|
||||
</aside>
|
||||
<section className={`
|
||||
p-4 pt-24 sm:pt-28 w-full
|
||||
sm:px-1 md:px-4 lg:px-8
|
||||
${workbench && collapsePrimaryNav
|
||||
? ''
|
||||
: 'max-w-61.8%'
|
||||
}
|
||||
`}>
|
||||
<div className={workbench ? '' : "max-w-5xl"}>
|
||||
{title && (
|
||||
<>
|
||||
<Breadcrumbs app={app} slug={slug} title={title} />
|
||||
<PageTitle app={app} slug={slug} title={title} />
|
||||
</>
|
||||
<main className="grow bg-base-100">
|
||||
<div className="m-auto flex flex-row justify-center">
|
||||
|
||||
<aside className={`
|
||||
${asideClasses}
|
||||
${app.primaryMenu ? '' : 'translate-x-[-100%]'} transition-transform
|
||||
sm:flex-row-reverse
|
||||
${workbench && collapsePrimaryNav
|
||||
? 'sm:px-0 sm:w-16'
|
||||
: 'sm:px-1 md:px-4 lg:px-8'
|
||||
}
|
||||
w-96
|
||||
`}>
|
||||
{workbench && (
|
||||
<div className={`hidden sm:flex`}>
|
||||
<button
|
||||
className="text-secondary-focus h-full px-2 pl-4 hover:animate-pulse"
|
||||
onClick={() => setCollapsePrimaryNav(!collapsePrimaryNav)}
|
||||
>
|
||||
{collapsePrimaryNav
|
||||
? <><Right /><Right /><Right /></>
|
||||
: <><Left /><Left /><Left /></>
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{children}
|
||||
<PrimaryNavigation app={app} active={slug}/>
|
||||
</aside>
|
||||
|
||||
<div className="p-0 m-0 bg-base-100">
|
||||
<section className={`
|
||||
p-4 pt-24 sm:pt-28
|
||||
sm:px-1 md:px-4 lg:px-8
|
||||
${workbench && collapsePrimaryNav
|
||||
? ''
|
||||
: 'max-w-7xl'
|
||||
}
|
||||
`}>
|
||||
<div>
|
||||
{title && (
|
||||
<>
|
||||
<Breadcrumbs app={app} slug={slug} title={title} />
|
||||
<PageTitle app={app} slug={slug} title={title} />
|
||||
</>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
{workbench && AltMenu && (
|
||||
<aside className={`
|
||||
${asideClasses}
|
||||
|
|
|
@ -9,10 +9,10 @@ const LocalePicker = ({ app }) => {
|
|||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<div className="dropdown">
|
||||
<div className="dropdown w-full md:w-auto">
|
||||
<div tabIndex="0" className={`
|
||||
m-0 btn btn-neutral flex flex-row gap-2
|
||||
sm:btn-ghost
|
||||
m-0 btn btn-neutral flex flex-row gap-2 btn-outline
|
||||
md:btn-ghost
|
||||
hover:bg-neutral hover:border-neutral-content
|
||||
`}>
|
||||
<LocaleIcon />
|
||||
|
|
|
@ -17,7 +17,7 @@ const Highlight = (props) => {
|
|||
: 'txt'
|
||||
|
||||
const preProps = {
|
||||
className: `language-${language} hljs text-base lg:text-lg whitespace-pre-wrap break-words`
|
||||
className: `language-${language} hljs text-base lg:text-lg whitespace-pre-wrap break-all`
|
||||
}
|
||||
if (props.raw) preProps.dangerouslySetInnerHTML = { __html: props.raw }
|
||||
|
||||
|
|
26
packages/freesewing.shared/components/navigation/aside.js
Normal file
26
packages/freesewing.shared/components/navigation/aside.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
import PrimaryNavigation from './primary'
|
||||
|
||||
const Aside = ({ app, slug, mobileOnly=false, before=[], after=[]}) => (
|
||||
<aside className={`
|
||||
fixed top-0 right-0 h-screen w-screen
|
||||
overflow-y-auto z-20
|
||||
bg-base-100 text-base-content md:bg-base-50
|
||||
transition-all
|
||||
${app.primaryMenu ? '' : 'translate-x-[-100%]'} transition-transform
|
||||
md:flex md:sticky md:flex-row-reverse
|
||||
md:relative md:transform-none
|
||||
px-8 py-24
|
||||
shrink-0
|
||||
md:w-24 md:px-2 md:justify-center
|
||||
lg:w-max lg:pr-2 lg:border-r-2
|
||||
xl:w-max xl:border-0
|
||||
2xl:pr-8
|
||||
${mobileOnly ? 'block md:hidden' : ''}
|
||||
`}>
|
||||
{before}
|
||||
<PrimaryNavigation app={app} active={slug}/>
|
||||
{after}
|
||||
</aside>
|
||||
)
|
||||
|
||||
export default Aside
|
|
@ -1,11 +1,13 @@
|
|||
import Link from 'next/link'
|
||||
import orderBy from 'lodash.orderby'
|
||||
import ThemePicker from 'shared/components/theme-picker.js'
|
||||
import RssIcon from 'shared/components/icons/rss.js'
|
||||
import TutorialIcon from 'shared/components/icons/tutorial.js'
|
||||
import GuideIcon from 'shared/components/icons/guide.js'
|
||||
import HelpIcon from 'shared/components/icons/help.js'
|
||||
import DocsIcon from 'shared/components/icons/docs.js'
|
||||
import DesignIcon from 'shared/components/icons/design.js'
|
||||
import BoxIcon from 'shared/components/icons/box.js'
|
||||
import CogIcon from 'shared/components/icons/cog.js'
|
||||
|
||||
// Don't show children for blog and showcase posts
|
||||
const keepClosed = ['blog', 'showcase', ]
|
||||
|
@ -19,11 +21,15 @@ const force = [
|
|||
|
||||
// List of icons matched to top-level slug
|
||||
const icons = {
|
||||
blog: <RssIcon />,
|
||||
tutorials: <TutorialIcon />,
|
||||
guides: <GuideIcon />,
|
||||
howtos: <HelpIcon />,
|
||||
reference: <DocsIcon />
|
||||
blog: (className='') => <RssIcon className={className}/>,
|
||||
tutorials: (className='') => <TutorialIcon className={className}/>,
|
||||
guides: (className='') => <GuideIcon className={className}/>,
|
||||
howtos: (className='') => <HelpIcon className={className}/>,
|
||||
reference: (className='') => <DocsIcon className={className}/>,
|
||||
accessories: (className='') => <TutorialIcon className={className}/>,
|
||||
blocks: (className='') => <BoxIcon className={className}/>,
|
||||
garments: (className='') => <DesignIcon className={className}/>,
|
||||
utilities: (className='') => <CogIcon className={className}/>,
|
||||
}
|
||||
|
||||
/* helper method to order nav entries */
|
||||
|
@ -33,7 +39,7 @@ const order = obj => orderBy(obj, ['__order', '__title'], ['asc', 'asc'])
|
|||
// Exported for re-use
|
||||
export const Chevron = ({w=8, m=2}) => <svg className={`
|
||||
fill-current opacity-75 w-${w} h-${w} mr-${m}
|
||||
details-toggle hover:text-secondary sm:hover:text-secondary-focus
|
||||
details-toggle hover:text-secondary sm:hover:text-secondary
|
||||
`}
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
||||
<path d="M12.95 10.707l.707-.707L8 4.343 6.586 5.757 10.828 10l-4.242 4.243L8 15.657l4.95-4.95z"/>
|
||||
|
@ -47,9 +53,9 @@ const currentChildren = current => Object.values(order(current))
|
|||
// Exported for re-use
|
||||
export const linkClasses = `text-lg lg:text-xl
|
||||
py-1
|
||||
text-base-content sm:text-neutral-content
|
||||
text-base-content sm:text-base-content
|
||||
hover:text-secondary
|
||||
sm:hover:text-secondary-focus
|
||||
sm:hover:text-secondary
|
||||
`
|
||||
|
||||
// Figure out whether a page is on the path to the active page
|
||||
|
@ -76,7 +82,7 @@ const SubLevel = ({ nodes={}, active }) => (
|
|||
flex flex-row
|
||||
px-2
|
||||
text-base-content
|
||||
sm:text-neutral-content
|
||||
sm:text-base-content
|
||||
hover:cursor-row-resize
|
||||
items-center
|
||||
`}>
|
||||
|
@ -86,16 +92,16 @@ const SubLevel = ({ nodes={}, active }) => (
|
|||
${linkClasses}
|
||||
hover:cursor-pointer
|
||||
hover:border-secondary
|
||||
sm:hover:border-secondary-focus
|
||||
sm:hover:border-secondary
|
||||
${child.__slug === active
|
||||
? 'text-secondary border-secondary sm:text-secondary-focus sm:border-secondary-focus'
|
||||
: 'text-base-content sm:text-neutral-content'
|
||||
? 'text-secondary border-secondary sm:text-secondary sm:border-secondary'
|
||||
: 'text-base-content sm:text-base-content'
|
||||
}
|
||||
`}>
|
||||
<span className={`
|
||||
text-3xl mr-2 inline-block p-0 leading-3
|
||||
${child.__slug === active
|
||||
? 'text-secondary sm:text-secondary-focus translate-y-1'
|
||||
? 'text-secondary sm:text-secondary translate-y-1'
|
||||
: 'translate-y-3'
|
||||
}
|
||||
`}>
|
||||
|
@ -120,15 +126,15 @@ const SubLevel = ({ nodes={}, active }) => (
|
|||
${linkClasses}
|
||||
hover:cursor-pointer
|
||||
hover:border-secondary
|
||||
sm:hover:border-secondary-focus
|
||||
sm:hover:border-secondary
|
||||
${child.__slug === active
|
||||
? 'text-secondary border-secondary sm:text-secondary-focus sm:border-secondary-focus'
|
||||
: 'text-base-content sm:text-neutral-content'
|
||||
? 'text-secondary border-secondary sm:text-secondary sm:border-secondary'
|
||||
: 'text-base-content sm:text-base-content'
|
||||
}`}>
|
||||
<span className={`
|
||||
text-3xl mr-2 inline-block p-0 leading-3
|
||||
${child.__slug === active
|
||||
? 'text-secondary sm:text-secondary-focus translate-y-1'
|
||||
? 'text-secondary sm:text-secondary translate-y-1'
|
||||
: 'translate-y-3'
|
||||
}
|
||||
`}>
|
||||
|
@ -154,15 +160,15 @@ const TopLevel = ({ icon, title, nav, current, slug, hasChildren=false, active }
|
|||
hover:cursor-row-resize
|
||||
p-2
|
||||
text-base-content
|
||||
sm:text-neutral-content
|
||||
sm:text-base-content
|
||||
items-center
|
||||
`}>
|
||||
<span className="text-secondary-focus">{icon}</span>
|
||||
<span className="text-secondary">{icon}</span>
|
||||
<Link href={`/${slug}`}>
|
||||
<a className={`
|
||||
grow ${linkClasses} hover:cursor-pointer
|
||||
${slug === active
|
||||
? 'text-secondary sm:text-secondary-focus'
|
||||
? 'text-secondary sm:text-secondary'
|
||||
: ''
|
||||
}`}
|
||||
>
|
||||
|
@ -175,12 +181,15 @@ const TopLevel = ({ icon, title, nav, current, slug, hasChildren=false, active }
|
|||
</details>
|
||||
)
|
||||
|
||||
const Navigation = ({ app, active }) => {
|
||||
const Navigation = ({ app, active, className='' }) => {
|
||||
if (!app.navigation) return null
|
||||
const output = []
|
||||
for (const page of order(app.navigation)) output.push(<TopLevel
|
||||
key={page.__slug}
|
||||
icon={icons[page.__slug] || <span className="text-3xl mr-2 translate-y-3 inline-block p-0 leading-3">°</span>}
|
||||
icon={icons[page.__slug]
|
||||
? icons[page.__slug]('w-6 h-6')
|
||||
: <span className="text-3xl mr-2 translate-y-3 inline-block p-0 leading-3">°</span>
|
||||
}
|
||||
title={page.__title}
|
||||
slug={page.__slug}
|
||||
hasChildren={keepClosed.indexOf(page.__slug) === -1}
|
||||
|
@ -189,13 +198,44 @@ const Navigation = ({ app, active }) => {
|
|||
active={active}
|
||||
/>)
|
||||
|
||||
return <div className='pb-20'>{output}</div>
|
||||
return <div className={`pb-20 ${className}`}>{output}</div>
|
||||
}
|
||||
|
||||
const PrimaryMenu = ({ app, active }) => (
|
||||
<nav className="sm:max-w-lg grow mb-12">
|
||||
<ThemePicker app={app} className="w-full sm:hidden"/>
|
||||
<Navigation app={app} active={active} />
|
||||
export const Icons = ({
|
||||
app, active,
|
||||
ulClasses='',
|
||||
liClasses='',
|
||||
linkClasses=`grow text-lg lg:text-xl py-1 text-base-content sm:text-base-content
|
||||
hover:text-secondary sm:hover:text-secondary hover:cursor-pointer
|
||||
flex flex-col items-center`
|
||||
}) => {
|
||||
if (!app.navigation) return null
|
||||
const output = []
|
||||
for (const page of order(app.navigation)) {
|
||||
output.push(
|
||||
<li key={page.__slug} className={liClasses}>
|
||||
<Link href={`/${page.__slug}`}>
|
||||
<a className={linkClasses} title={page.__title}>
|
||||
{icons[page.__slug]
|
||||
? icons[page.__slug]('w-14 h-14')
|
||||
: <HelpIcon />
|
||||
}
|
||||
<span className='font-bold'>{page.__title}</span>
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
return <ul className={ulClasses}>{output}</ul>
|
||||
}
|
||||
|
||||
const PrimaryMenu = ({ app, active, before=[], after=[] }) => (
|
||||
<nav className="mb-12">
|
||||
{before}
|
||||
<Icons app={app} ulClasses="hidden md:block lg:hidden flex flex-col items-center"/>
|
||||
<Navigation app={app} active={active} className="md:hidden lg:block"/>
|
||||
{after}
|
||||
</nav>
|
||||
)
|
||||
|
||||
|
|
|
@ -6,10 +6,10 @@ const ThemePicker = ({ app, className }) => {
|
|||
const { t } = useTranslation(['themes'])
|
||||
|
||||
return (
|
||||
<div className={`dropdown ${className}`}>
|
||||
<div className={`dropdown ${className} w-full md:w-auto`}>
|
||||
<div tabIndex="0" className={`
|
||||
m-0 btn btn-neutral flex flex-row gap-2
|
||||
sm:btn-ghost
|
||||
m-0 btn btn-neutral flex flex-row gap-2 btn-outline
|
||||
md:btn-ghost
|
||||
hover:bg-neutral hover:border-neutral-content
|
||||
`}>
|
||||
<ThemeIcon />
|
||||
|
|
|
@ -15,7 +15,7 @@ import Part from './part'
|
|||
* where the browser will render this as zero width and height.
|
||||
*
|
||||
* To avoid that, we use the SizeMe which will report the size of the
|
||||
* grandparent element, and then we wraper our SVG in a div that we
|
||||
* grandparent element, and then we wrap our SVG in a div that we
|
||||
* set to this size. This will cause the SVG to fill in that entire
|
||||
* space, and the pan and zoom to adapt to this size.
|
||||
*
|
||||
|
@ -32,6 +32,7 @@ const SvgWrapper = props => {
|
|||
<TransformWrapper
|
||||
minScale={0.1}
|
||||
centerZoomedOut={true}
|
||||
wheel={{ activationKeys: ['Control'] }}
|
||||
>
|
||||
<TransformComponent>
|
||||
<div style={{ width: size.width+'px', }}>
|
||||
|
|
|
@ -6,9 +6,9 @@ import { useTranslation } from 'next-i18next'
|
|||
const EditCount = props => (
|
||||
<div className="form-control mb-2 w-full">
|
||||
<label className="label">
|
||||
<span className="label-text text-neutral-content">{props.min}</span>
|
||||
<span className="label-text font-bold text-neutral-content">{props.value}</span>
|
||||
<span className="label-text text-neutral-content">{props.max}</span>
|
||||
<span className="label-text text-base-content">{props.min}</span>
|
||||
<span className="label-text font-bold text-base-content">{props.value}</span>
|
||||
<span className="label-text text-base-content">{props.max}</span>
|
||||
</label>
|
||||
<label className="input-group input-group-sm">
|
||||
<input
|
||||
|
@ -19,7 +19,7 @@ const EditCount = props => (
|
|||
value={props.value}
|
||||
onChange={props.handleChange}
|
||||
/>
|
||||
<span className="text-neutral-content font-bold">#</span>
|
||||
<span className="text-base-content font-bold">#</span>
|
||||
</label>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -36,7 +36,7 @@ const DesignOptionList = props => {
|
|||
? choice === dflt
|
||||
? 'text-secondary'
|
||||
: 'text-accent'
|
||||
: 'text-neutral-content'
|
||||
: 'text-base-content'
|
||||
}
|
||||
`}
|
||||
>
|
||||
|
@ -56,7 +56,7 @@ const DesignOptionList = props => {
|
|||
disabled={val === dflt}
|
||||
onClick={reset}
|
||||
>
|
||||
<span className={val===dflt ? 'text-neutral' : 'text-accent'}><ClearIcon /></span>
|
||||
<span className={val===dflt ? 'text-base' : 'text-accent'}><ClearIcon /></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -7,9 +7,9 @@ import { useTranslation } from 'next-i18next'
|
|||
const EditOption = props => (
|
||||
<div className="form-control mb-2 w-full">
|
||||
<label className="label">
|
||||
<span className="label-text text-neutral-content">{props.min}{props.suffix}</span>
|
||||
<span className="label-text font-bold text-neutral-content">{props.value}{props.suffix}</span>
|
||||
<span className="label-text text-neutral-content">{props.max}{props.suffix}</span>
|
||||
<span className="label-text text-base-content">{props.min}{props.suffix}</span>
|
||||
<span className="label-text font-bold text-base-content">{props.value}{props.suffix}</span>
|
||||
<span className="label-text text-base-content">{props.max}{props.suffix}</span>
|
||||
</label>
|
||||
<label className="input-group input-group-sm">
|
||||
<input
|
||||
|
@ -20,7 +20,7 @@ const EditOption = props => (
|
|||
value={props.value}
|
||||
onChange={props.handleChange}
|
||||
/>
|
||||
<span className="text-neutral-content font-bold">{props.suffix}</span>
|
||||
<span className="text-base-content font-bold">{props.suffix}</span>
|
||||
</label>
|
||||
</div>
|
||||
)
|
||||
|
@ -51,7 +51,7 @@ const DesignOptionPctDeg = props => {
|
|||
|
||||
return (
|
||||
<div className="py-4 mx-6 border-l-2 pl-2">
|
||||
<p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic">
|
||||
<p className="m-0 p-0 px-2 mb-2 text-base-content opacity-60 italic">
|
||||
{props.ot(`${props.option}.d`)}
|
||||
</p>
|
||||
<div className="flex flex-row justify-between">
|
||||
|
|
|
@ -48,8 +48,7 @@ const WorkbenchMeasurements = ({ app, pattern, gist, updateGist }) => {
|
|||
<h1>
|
||||
<span className='capitalize mr-4 opacity-70'>
|
||||
{pattern.config.name}:
|
||||
</span>
|
||||
{t('measurements')}
|
||||
</span> {t('measurements')}
|
||||
</h1>
|
||||
<details open className="my-2">
|
||||
<summary><h2 className="inline pl-1">{t('cfp:preloadMeasurements')}</h2></summary>
|
||||
|
|
|
@ -24,7 +24,7 @@ const CoreSettingList = props => {
|
|||
|
||||
return (
|
||||
<div className="py-4 mx-6 border-l-2 pl-2">
|
||||
<p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic">
|
||||
<p className="m-0 p-0 px-2 mb-2 text-base-content opacity-60 italic">
|
||||
{t(`settings:${props.setting}.d`)}
|
||||
</p>
|
||||
<div className="flex flex-row">
|
||||
|
|
|
@ -27,7 +27,7 @@ const CoreSettingMm = props => {
|
|||
|
||||
return (
|
||||
<div className="py-4 mx-6 border-l-2 pl-2">
|
||||
<p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic">
|
||||
<p className="m-0 p-0 px-2 mb-2 text-base-content opacity-60 italic">
|
||||
{t(`settings:${props.setting}.d`)}
|
||||
</p>
|
||||
<div className="flex flex-row justify-between">
|
||||
|
|
|
@ -27,7 +27,7 @@ const CoreSettingNr = props => {
|
|||
|
||||
return (
|
||||
<div className="py-4 mx-6 border-l-2 pl-2">
|
||||
<p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic">
|
||||
<p className="m-0 p-0 px-2 mb-2 text-base-content opacity-60 italic">
|
||||
{t(`settings:${props.setting}.d`)}
|
||||
</p>
|
||||
<div className="flex flex-row justify-between">
|
||||
|
|
|
@ -22,7 +22,7 @@ const CoreSettingOnly = props => {
|
|||
|
||||
return (
|
||||
<div className="py-4 mx-6 border-l-2 pl-2">
|
||||
<p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic">
|
||||
<p className="m-0 p-0 px-2 mb-2 text-base-content opacity-60 italic">
|
||||
{t(`settings:only.d`)}
|
||||
</p>
|
||||
<div className="flex flex-row">
|
||||
|
|
|
@ -29,7 +29,7 @@ const CoreSettingMm = props => {
|
|||
|
||||
return (
|
||||
<div className="py-4 mx-6 border-l-2 pl-2">
|
||||
<p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic">
|
||||
<p className="m-0 p-0 px-2 mb-2 text-base-content opacity-60 italic">
|
||||
{t(`settings:sa.d`)}
|
||||
</p>
|
||||
<div className="flex flex-row justify-between">
|
||||
|
|
|
@ -24,7 +24,7 @@ export const NoSumDiv = props => (
|
|||
hover:cursor-resize
|
||||
hover:border-secondary
|
||||
sm:hover:border-secondary-focus
|
||||
text-base-content sm:text-neutral-content
|
||||
text-base-content sm:text-base-content
|
||||
`}>{props.children}</div>
|
||||
)
|
||||
export const SumDiv = props => (
|
||||
|
@ -34,7 +34,7 @@ export const SumDiv = props => (
|
|||
hover:cursor-resize
|
||||
hover:border-secondary
|
||||
sm:hover:border-secondary-focus
|
||||
text-base-content sm:text-neutral-content
|
||||
text-base-content sm:text-base-content
|
||||
`}>{props.children}</div>
|
||||
)
|
||||
export const Summary = props => (
|
||||
|
@ -42,7 +42,7 @@ export const Summary = props => (
|
|||
flex flex-row
|
||||
px-2
|
||||
text-base-content
|
||||
sm:text-neutral-content
|
||||
sm:text-base-content
|
||||
hover:cursor-row-resize
|
||||
items-center
|
||||
`}>{props.children}</summary>
|
||||
|
@ -53,7 +53,7 @@ export const TopSummary = props => (
|
|||
hover:cursor-row-resize
|
||||
p-2
|
||||
text-base-content
|
||||
sm:text-neutral-content
|
||||
sm:text-base-content
|
||||
items-center
|
||||
`}>
|
||||
<span className="text-secondary-focus mr-4">{props.icon || null}</span>
|
||||
|
@ -67,7 +67,7 @@ export const SumButton = props => (
|
|||
w-full justify-between
|
||||
text-left
|
||||
text-base-content
|
||||
sm:text-neutral-content
|
||||
sm:text-base-content
|
||||
hover:cursor-pointer
|
||||
items-center
|
||||
mr-4
|
||||
|
@ -84,7 +84,7 @@ export const SecText = props => props.raw
|
|||
|
||||
const WorkbenchMenu = props => {
|
||||
return (
|
||||
<nav className="smmax-w-96 grow mb-12">
|
||||
<nav className="grow mb-12">
|
||||
<ViewMenu {...props} />
|
||||
{props.gist?._state?.view === 'draft' && (
|
||||
<>
|
||||
|
|
|
@ -9,7 +9,7 @@ const SumButton = props => (
|
|||
w-full justify-between
|
||||
text-left
|
||||
text-base-content
|
||||
sm:text-neutral-content
|
||||
sm:text-base-content
|
||||
hover:cursor-pointer
|
||||
items-center
|
||||
mr-4
|
||||
|
@ -22,7 +22,7 @@ const SumDiv = (props) => (
|
|||
hover:cursor-resize
|
||||
hover:border-secondary
|
||||
sm:hover:border-secondary-focus
|
||||
text-base-content sm:text-neutral-content
|
||||
text-base-content sm:text-base-content
|
||||
${props.active && 'border-secondary-focus'}
|
||||
|
||||
`}>{props.children}</div>
|
||||
|
@ -42,7 +42,8 @@ const Option = props => {
|
|||
{
|
||||
type: 'option',
|
||||
option: props.option
|
||||
}
|
||||
},
|
||||
true // Close navigation on mobile
|
||||
)}>
|
||||
<SumDiv active={active}>
|
||||
<span className={`
|
||||
|
|
|
@ -8,54 +8,54 @@ const View = props => {
|
|||
{
|
||||
name: 'measurements',
|
||||
title: t('measurements'),
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'measurements')
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'measurements', true)
|
||||
},
|
||||
{
|
||||
name: 'draft',
|
||||
title: t('draftPattern', { pattern: props.pattern.config.name }),
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'draft')
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'draft', true)
|
||||
},
|
||||
{
|
||||
name: 'test',
|
||||
title: t('testPattern', { pattern: props.pattern.config.name }),
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'test')
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'test', true)
|
||||
},
|
||||
{
|
||||
name: 'printingLayout',
|
||||
title: t('layoutThing', { thing: props.pattern.config.name })
|
||||
+ ': ' + t('forPrinting'),
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'printingLayout')
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'printingLayout', true)
|
||||
},
|
||||
{
|
||||
name: 'cuttingLayout',
|
||||
title: t('layoutThing', { thing: props.pattern.config.name })
|
||||
+ ': ' + t('forCutting'),
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'cuttingLayout')
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'cuttingLayout', true)
|
||||
},
|
||||
{
|
||||
name: 'export',
|
||||
title: t('exportThing', { thing: props.pattern.config.name }),
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'export')
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'export', true)
|
||||
},
|
||||
{
|
||||
name: 'events',
|
||||
title: t('events'),
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'events')
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'events', true)
|
||||
},
|
||||
{
|
||||
name: 'yaml',
|
||||
title: t('YAML'),
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'yaml')
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'yaml', true)
|
||||
},
|
||||
{
|
||||
name: 'json',
|
||||
title: t('JSON'),
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'json')
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'json', true)
|
||||
},
|
||||
{
|
||||
name: 'edit',
|
||||
title: t('editThing', { thing: 'YAML' }),
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'edit')
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'edit', true)
|
||||
},
|
||||
{
|
||||
name: 'clear',
|
||||
|
@ -71,7 +71,7 @@ const View = props => {
|
|||
hover:cursor-row-resize
|
||||
p-2
|
||||
text-base-content
|
||||
sm:text-neutral-content
|
||||
sm:text-base-content
|
||||
items-center
|
||||
`}>
|
||||
<span className="text-secondary-focus mr-4"><MenuIcon /></span>
|
||||
|
@ -93,7 +93,7 @@ const View = props => {
|
|||
capitalize
|
||||
${entry.name === props.gist?._state?.view
|
||||
? 'text-secondary border-secondary sm:text-secondary-focus sm:border-secondary-focus'
|
||||
: 'text-base-content sm:text-neutral-content'
|
||||
: 'text-base-content sm:text-base-content'
|
||||
}
|
||||
`} onClick={entry.onClick}>
|
||||
<span className={`
|
||||
|
|
42
packages/freesewing.shared/components/wrappers/toc.js
Normal file
42
packages/freesewing.shared/components/wrappers/toc.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* This is used to wrap a Table of Contents (toc) as returned
|
||||
* from the mdxLoader method (see shared/mdx/loader.js)
|
||||
* It is NOT for wrapping plain markdown/mdx
|
||||
*/
|
||||
import { useState, useEffect, Fragment } from 'react'
|
||||
|
||||
// See: https://mdxjs.com/guides/mdx-on-demand/
|
||||
import { run } from '@mdx-js/mdx'
|
||||
import * as runtime from 'react/jsx-runtime.js'
|
||||
|
||||
// Components that are available in all MDX
|
||||
import customComponents from 'shared/components/mdx'
|
||||
|
||||
const TocWrapper = ({toc, app}) => {
|
||||
|
||||
const [mdxModule, setMdxModule] = useState()
|
||||
|
||||
useEffect(() => {
|
||||
;(async () => {
|
||||
setMdxModule(await run(toc, runtime))
|
||||
})()
|
||||
}, [toc])
|
||||
|
||||
// React component for MDX content
|
||||
const MdxContent = mdxModule ? mdxModule.default : Fragment
|
||||
|
||||
return (
|
||||
<div className={`
|
||||
mdx mdx-toc text-base-content text-lg lg:text-xl
|
||||
sticky top-8 max-h-screen overflow-y-auto
|
||||
max-w-prose
|
||||
md:border-l-4 md:pl-4 md:mb-8 md:border-base-200
|
||||
`}
|
||||
>
|
||||
{mdxModule && <MdxContent components={customComponents(app)}/>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TocWrapper
|
||||
|
|
@ -55,10 +55,10 @@ const hasRequiredMeasurements = (pattern, gist) => {
|
|||
|
||||
/*
|
||||
* This component wraps the workbench and is in charge of
|
||||
* keeping the gist state, which will trickly down
|
||||
* keeping the gist state, which will trickle down
|
||||
* to all workbench subcomponents
|
||||
*/
|
||||
const WorkbenchWrapper = ({ app, pattern, preload=false, from=false }) => {
|
||||
const WorkbenchWrapper = ({ app, pattern, preload=false, from=false, layout=false }) => {
|
||||
|
||||
// State for gist
|
||||
const [gist, setGist] = useLocalStorage(`${pattern.config.name}_gist`, defaultGist(pattern, app.locale))
|
||||
|
@ -82,10 +82,12 @@ const WorkbenchWrapper = ({ app, pattern, preload=false, from=false }) => {
|
|||
}, [preload, from])
|
||||
|
||||
// Helper methods to manage the gist state
|
||||
const updateGist = (path, content) => {
|
||||
const updateGist = (path, content, closeNav=false) => {
|
||||
const newGist = {...gist}
|
||||
set(newGist, path, content)
|
||||
setGist(newGist)
|
||||
// Force close of menu on mobile if it is open
|
||||
if (closeNav && app.primaryMenu) app.setPrimaryMenu(false)
|
||||
}
|
||||
const unsetGist = (path) => {
|
||||
const newGist = {...gist}
|
||||
|
@ -128,14 +130,19 @@ const WorkbenchWrapper = ({ app, pattern, preload=false, from=false }) => {
|
|||
AltMenu: <Menu {...componentProps }/>
|
||||
}
|
||||
|
||||
// Layout to use
|
||||
const LayoutComponent = layout
|
||||
? layout
|
||||
: Layout
|
||||
|
||||
const Component = views[gist?._state?.view]
|
||||
? views[gist._state.view]
|
||||
: views.welcome
|
||||
|
||||
return <Layout {...layoutProps}>
|
||||
return <LayoutComponent {...layoutProps}>
|
||||
{messages}
|
||||
<Component {...componentProps} />
|
||||
</Layout>
|
||||
</LayoutComponent>
|
||||
}
|
||||
|
||||
export default WorkbenchWrapper
|
||||
|
|
|
@ -7,6 +7,7 @@ module.exports = {
|
|||
'./pages/**/*.js',
|
||||
'./components/*.js',
|
||||
'./components/**/*.js',
|
||||
'./page-templates/*.js',
|
||||
'../freesewing.shared/components/**/*.js',
|
||||
],
|
||||
plugins: [require('daisyui'), require('tailwindcss/nesting')],
|
||||
|
|
|
@ -10,6 +10,7 @@ import remarkFrontmatter from 'remark-frontmatter'
|
|||
import remarkGfm from 'remark-gfm'
|
||||
import remarkCopyLinkedFiles from 'remark-copy-linked-files'
|
||||
import { remarkIntroPlugin } from './remark-intro-plugin.mjs'
|
||||
import mdxPluginToc from './mdx-plugin-toc.mjs'
|
||||
import smartypants from 'remark-smartypants'
|
||||
// Rehype plugins we want to use
|
||||
import rehypeHighlight from 'rehype-highlight'
|
||||
|
@ -61,7 +62,27 @@ const mdxLoader = async (language, site, slug) => {
|
|||
})
|
||||
)
|
||||
|
||||
return {mdx, intro}
|
||||
// This is not ideal as we're adding a second pass but for now it will do
|
||||
// See: https://github.com/remarkjs/remark-toc/issues/37
|
||||
const toc = String(
|
||||
await compile(md, {
|
||||
outputFormat: 'function-body',
|
||||
remarkPlugins: [
|
||||
remarkFrontmatter,
|
||||
remarkGfm,
|
||||
smartypants,
|
||||
[
|
||||
mdxPluginToc,
|
||||
{ language: 'en' }
|
||||
]
|
||||
],
|
||||
rehypePlugins: [
|
||||
rehypeSlug,
|
||||
],
|
||||
})
|
||||
)
|
||||
|
||||
return {mdx, intro, toc}
|
||||
}
|
||||
|
||||
export default mdxLoader
|
||||
|
|
30
packages/freesewing.shared/mdx/mdx-plugin-toc.mjs
Normal file
30
packages/freesewing.shared/mdx/mdx-plugin-toc.mjs
Normal file
|
@ -0,0 +1,30 @@
|
|||
import {toc} from 'mdast-util-toc'
|
||||
|
||||
const headings = {
|
||||
en: 'Table of contents',
|
||||
fr: 'Table des matières',
|
||||
nl: 'Inhoudsopgave',
|
||||
es: 'Tabla de contenido',
|
||||
de: 'Inhaltsverzeichnis'
|
||||
}
|
||||
|
||||
export default function mdxToc(options = {}) {
|
||||
return (node) => {
|
||||
const result = toc(node, { heading: false })
|
||||
|
||||
if (result.map) node.children = [
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 4,
|
||||
children: [{
|
||||
type: 'text',
|
||||
value: headings[options.language || 'en']
|
||||
}]
|
||||
},
|
||||
result.map
|
||||
]
|
||||
else node.children = []
|
||||
|
||||
return
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
"highlight.js": "^11.4.0",
|
||||
"lodash.orderby": "^4.6.0",
|
||||
"lodash.unset": "^4.5.2",
|
||||
"mdast-util-toc": "^6.1.0",
|
||||
"react-markdown": "^8.0.0",
|
||||
"react-sizeme": "^3.0.2",
|
||||
"react-timeago": "^6.2.1",
|
||||
|
|
|
@ -89,6 +89,7 @@ export async function getStaticProps({ locale }) {
|
|||
const l = 'prebuild'
|
||||
export const prebuildLab = async (site) => {
|
||||
const promises = []
|
||||
const availableVersions = {}
|
||||
// Load config
|
||||
const versions = JSON.parse(await fs.readFile(
|
||||
path.resolve('..', 'freesewing.lab', 'versions.json'),
|
||||
|
@ -130,6 +131,7 @@ export const prebuildLab = async (site) => {
|
|||
if (process.env.BUILD_ALL_VERSIONS) {
|
||||
// Download published versions from unpkg
|
||||
for (const version of versions) {
|
||||
if (typeof availableVersions[version] === 'undefined') availableVersions[version] = new Set()
|
||||
// Assume that if the file is on disk, it's good to go (caching)
|
||||
const file = path.resolve('..', `freesewing.lab`, 'lib', version, `${design}.mjs`)
|
||||
let cached
|
||||
|
@ -145,6 +147,7 @@ export const prebuildLab = async (site) => {
|
|||
await fs.mkdir(path.resolve('..', `freesewing.lab`, 'pages', 'v', version), { recursive: true })
|
||||
const code = (await loadFromUnpkg(design, version))
|
||||
if (code) {
|
||||
availableVersions[version].add(design)
|
||||
promises.push(
|
||||
fs.writeFile(
|
||||
path.resolve('..', `freesewing.lab`, 'lib', version, `${design}.mjs`),
|
||||
|
@ -156,6 +159,8 @@ export const prebuildLab = async (site) => {
|
|||
),
|
||||
)
|
||||
} else console.log(`No ${version} for ${design}`)
|
||||
} else {
|
||||
availableVersions[version].add(design)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -163,6 +168,15 @@ export const prebuildLab = async (site) => {
|
|||
}
|
||||
|
||||
if (process.env.BUILD_ALL_VERSIONS) {
|
||||
// Write available versions file
|
||||
const av = {}
|
||||
for (const [v, set] of Object.entries(availableVersions)) av[v] = [...set].sort()
|
||||
promises.push(
|
||||
fs.writeFile(
|
||||
path.resolve('..', `freesewing.lab`, 'available-versions.json'),
|
||||
JSON.stringify(av, null, 2)
|
||||
)
|
||||
)
|
||||
// Also add version overview pages
|
||||
for (const version of versions) {
|
||||
// Assume that if the file is on disk, it's good to go (caching)
|
||||
|
|
|
@ -35,6 +35,18 @@
|
|||
.mdx a[aria-hidden="true"] {
|
||||
text-decoration: none;
|
||||
}
|
||||
/* Watch out of P tags in the toc list */
|
||||
.mdx-toc ul li p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: inline;
|
||||
}
|
||||
/* Prevent inline code style from applying to code blocks */
|
||||
.mdx code.hljs {
|
||||
color: inherit;
|
||||
background-color: inherit;
|
||||
background-opacity: inherit;
|
||||
}
|
||||
|
||||
/* FreeSewing SVG output styles */
|
||||
.fs-stroke-fabric { stroke: var(--pattern-fabric); }
|
||||
|
@ -206,7 +218,7 @@
|
|||
}
|
||||
.theme-gradient.loading {
|
||||
animation-name: MOVE-BG;
|
||||
animation-duration: 2s;
|
||||
animation-duration: 4s;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
margin-top: 0;
|
||||
|
@ -217,7 +229,7 @@
|
|||
background-position-x: 0;
|
||||
}
|
||||
to {
|
||||
background-position-x: -300px;
|
||||
background-position-x: -200vw;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,11 +34,12 @@ module.exports = {
|
|||
'--btn-error-content': colors.neutral[50],
|
||||
|
||||
'--theme-gradient': `repeating-linear-gradient(
|
||||
-45deg,
|
||||
${colors.neutral[300]},
|
||||
${colors.neutral[300]} 10px,
|
||||
${colors.neutral[800]} 10px,
|
||||
${colors.neutral[800]} 20px
|
||||
90deg,
|
||||
${colors.violet[900]},
|
||||
${colors.violet[900]} 40%,
|
||||
${colors.pink[700]} 65%,
|
||||
${colors.violet[600]} 90%,
|
||||
${colors.violet[900]} 100%
|
||||
)`,
|
||||
|
||||
'--code-background-color': '#111',
|
||||
|
@ -50,7 +51,7 @@ module.exports = {
|
|||
'--code-border-width': 2,
|
||||
'--code-outer-padding': '0 0.5rem',
|
||||
'--code-inner-padding': '1rem',
|
||||
'--code-color-keyword': colors.pink['400'],
|
||||
'--code-color-keyword': colors.yellow['500'],
|
||||
'--code-font-weight-keyword': 'bold',
|
||||
'--code-color-entity': colors.violet['400'],
|
||||
'--code-font-weight-entity': 'bold',
|
||||
|
|
|
@ -36,11 +36,10 @@ module.exports = {
|
|||
'--rounded-btn': '0',
|
||||
|
||||
'--theme-gradient': `repeating-linear-gradient(
|
||||
-45deg,
|
||||
${colors.lime['700']},
|
||||
${colors.lime['700']} 15px,
|
||||
${bg} 15px,
|
||||
${bg} 30px
|
||||
90deg,
|
||||
${colors.lime['900']},
|
||||
${colors.lime['500']} 50%,
|
||||
${colors.lime['900']} 100%
|
||||
)`,
|
||||
|
||||
'--code-background-color': '#002407',
|
||||
|
|
|
@ -29,19 +29,19 @@ module.exports = {
|
|||
'error': colors.red['600'],
|
||||
|
||||
'--theme-gradient': `repeating-linear-gradient(
|
||||
-45deg,
|
||||
${colors.red[500]},
|
||||
${colors.red[500]} 20px,
|
||||
${colors.orange[500]} 20px,
|
||||
${colors.orange[500]} 40px,
|
||||
${colors.yellow[400]} 40px,
|
||||
${colors.yellow[400]} 60px,
|
||||
${colors.green[500]} 60px,
|
||||
${colors.green[500]} 80px,
|
||||
${colors.blue[500]} 80px,
|
||||
${colors.blue[500]} 100px,
|
||||
${colors.violet[500]} 100px,
|
||||
${colors.violet[500]} 120px
|
||||
90deg,
|
||||
${colors.red[500]},
|
||||
${colors.red[500]} 16.66%,
|
||||
${colors.orange[500]} 16.66%,
|
||||
${colors.orange[500]} 33.33%,
|
||||
${colors.yellow[400]} 33.33%,
|
||||
${colors.yellow[400]} 50%,
|
||||
${colors.green[500]} 50%,
|
||||
${colors.green[500]} 66.66%,
|
||||
${colors.blue[500]} 66.66%,
|
||||
${colors.blue[500]} 83.33%,
|
||||
${colors.violet[500]} 83.33%,
|
||||
${colors.violet[500]} 100%
|
||||
)`,
|
||||
|
||||
'--code-background-color': colors.neutral['800'],
|
||||
|
|
|
@ -131,11 +131,12 @@ module.exports = {
|
|||
* This is used as a border & loading indicator
|
||||
*/
|
||||
'--theme-gradient': `repeating-linear-gradient(
|
||||
-45deg,
|
||||
${colors.neutral[900]} 0,
|
||||
${colors.neutral[900]} 10px,
|
||||
${colors.neutral[50]} 10px,
|
||||
${colors.neutral[50]} 20px
|
||||
90deg,
|
||||
${colors.violet[600]} 0,
|
||||
${colors.violet[500]} 30%,
|
||||
${colors.yellow[500]} 50%,
|
||||
${colors.purple[500]} 75%,
|
||||
${colors.violet[600]} 100%
|
||||
)`,
|
||||
|
||||
/* CODE HIGHLIGHTING COLORS
|
||||
|
@ -158,7 +159,7 @@ module.exports = {
|
|||
/*
|
||||
* These variables are used to style the highlighted tokens themselves
|
||||
*/
|
||||
'--code-color-keyword': colors.pink['400'],
|
||||
'--code-color-keyword': colors.yellow['500'],
|
||||
'--code-font-weight-keyword': 'bold',
|
||||
'--code-color-entity': colors.violet['400'],
|
||||
'--code-font-weight-entity': 'bold',
|
||||
|
@ -168,7 +169,7 @@ module.exports = {
|
|||
'--code-color-variable': colors.indigo['400'],
|
||||
'--code-color-comment': colors.neutral['400'],
|
||||
'--code-color-tag': colors.green['400'],
|
||||
'--code-color-property': 'inherit',
|
||||
'--code-color-property': colors.yellow['200'],
|
||||
'--code-font-weight-property': 'bold',
|
||||
|
||||
/* FREESEWING PATTERN THEMEING
|
||||
|
|
|
@ -14,7 +14,7 @@ module.exports = {
|
|||
'primary': pink,
|
||||
'primary-focus': blue,
|
||||
'primary-content': colors.neutral['900'],
|
||||
'secondary': blue,
|
||||
'secondary': colors.sky['500'],
|
||||
'secondary-focus': pink,
|
||||
'secondary-content': colors.neutral['900'],
|
||||
|
||||
|
@ -32,17 +32,17 @@ module.exports = {
|
|||
'error': colors.red['600'],
|
||||
|
||||
'--theme-gradient': `repeating-linear-gradient(
|
||||
-45deg,
|
||||
90deg,
|
||||
#77cbf9,
|
||||
#77cbf9 20px,
|
||||
#ecadb9 20px,
|
||||
#ecadb9 40px,
|
||||
${colors.neutral['50']} 40px,
|
||||
${colors.neutral['50']} 60px,
|
||||
#ecadb9 60px,
|
||||
#ecadb9 80px,
|
||||
#77cbf9 80px,
|
||||
#77cbf9 100px
|
||||
#77cbf9 20%,
|
||||
#ecadb9 20%,
|
||||
#ecadb9 40%,
|
||||
${colors.neutral['50']} 40%,
|
||||
${colors.neutral['50']} 60%,
|
||||
#ecadb9 60%,
|
||||
#ecadb9 80%,
|
||||
#77cbf9 80%,
|
||||
#77cbf9 100%
|
||||
)`,
|
||||
|
||||
'--code-background-color': colors.neutral['800'],
|
||||
|
|
|
@ -9,6 +9,7 @@ import gdpr from './gdpr.yaml'
|
|||
import i18n from './i18n.yaml'
|
||||
import intro from './intro.yaml'
|
||||
import measurements from './measurements.yaml'
|
||||
import lab from './lab.yaml'
|
||||
import options from './options/'
|
||||
import optiongroups from './optiongroups.yaml'
|
||||
import parts from './parts.yaml'
|
||||
|
@ -31,6 +32,7 @@ const topics = {
|
|||
i18n,
|
||||
intro,
|
||||
measurements,
|
||||
lab,
|
||||
options,
|
||||
optiongroups,
|
||||
parts,
|
||||
|
|
5
packages/i18n/src/locales/de/lab.yaml
Normal file
5
packages/i18n/src/locales/de/lab.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
slogan: The FreeSewing lab provides
|
||||
slogan1: All our pattern designs
|
||||
slogan2: New & old version
|
||||
slogan3: Bleeding edge code
|
||||
slogan4: Unreleased designs
|
|
@ -9,6 +9,7 @@ import gdpr from './gdpr.yaml'
|
|||
import i18n from './i18n.yaml'
|
||||
import intro from './intro.yaml'
|
||||
import measurements from './measurements.yaml'
|
||||
import lab from './lab.yaml'
|
||||
import options from './options/'
|
||||
import optiongroups from './optiongroups.yaml'
|
||||
import parts from './parts.yaml'
|
||||
|
@ -31,6 +32,7 @@ const topics = {
|
|||
i18n,
|
||||
intro,
|
||||
measurements,
|
||||
lab,
|
||||
options,
|
||||
optiongroups,
|
||||
parts,
|
||||
|
|
5
packages/i18n/src/locales/en/lab.yaml
Normal file
5
packages/i18n/src/locales/en/lab.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
slogan: The FreeSewing lab provides
|
||||
slogan1: All our pattern designs
|
||||
slogan2: New & old version
|
||||
slogan3: Bleeding edge code
|
||||
slogan4: Unreleased designs
|
|
@ -9,6 +9,7 @@ import gdpr from './gdpr.yaml'
|
|||
import i18n from './i18n.yaml'
|
||||
import intro from './intro.yaml'
|
||||
import measurements from './measurements.yaml'
|
||||
import lab from './lab.yaml'
|
||||
import options from './options/'
|
||||
import optiongroups from './optiongroups.yaml'
|
||||
import parts from './parts.yaml'
|
||||
|
@ -31,6 +32,7 @@ const topics = {
|
|||
i18n,
|
||||
intro,
|
||||
measurements,
|
||||
lab,
|
||||
options,
|
||||
optiongroups,
|
||||
parts,
|
||||
|
|
5
packages/i18n/src/locales/es/lab.yaml
Normal file
5
packages/i18n/src/locales/es/lab.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
slogan: The FreeSewing lab provides
|
||||
slogan1: All our pattern designs
|
||||
slogan2: New & old version
|
||||
slogan3: Bleeding edge code
|
||||
slogan4: Unreleased designs
|
|
@ -9,6 +9,7 @@ import gdpr from './gdpr.yaml'
|
|||
import i18n from './i18n.yaml'
|
||||
import intro from './intro.yaml'
|
||||
import measurements from './measurements.yaml'
|
||||
import lab from './lab.yaml'
|
||||
import options from './options/'
|
||||
import optiongroups from './optiongroups.yaml'
|
||||
import parts from './parts.yaml'
|
||||
|
@ -31,6 +32,7 @@ const topics = {
|
|||
i18n,
|
||||
intro,
|
||||
measurements,
|
||||
lab,
|
||||
options,
|
||||
optiongroups,
|
||||
parts,
|
||||
|
|
5
packages/i18n/src/locales/fr/lab.yaml
Normal file
5
packages/i18n/src/locales/fr/lab.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
slogan: The FreeSewing lab provides
|
||||
slogan1: All our pattern designs
|
||||
slogan2: New & old version
|
||||
slogan3: Bleeding edge code
|
||||
slogan4: Unreleased designs
|
|
@ -9,6 +9,7 @@ import gdpr from './gdpr.yaml'
|
|||
import i18n from './i18n.yaml'
|
||||
import intro from './intro.yaml'
|
||||
import measurements from './measurements.yaml'
|
||||
import lab from './lab.yaml'
|
||||
import options from './options/'
|
||||
import optiongroups from './optiongroups.yaml'
|
||||
import parts from './parts.yaml'
|
||||
|
@ -31,6 +32,7 @@ const topics = {
|
|||
i18n,
|
||||
intro,
|
||||
measurements,
|
||||
lab,
|
||||
options,
|
||||
optiongroups,
|
||||
parts,
|
||||
|
|
5
packages/i18n/src/locales/nl/lab.yaml
Normal file
5
packages/i18n/src/locales/nl/lab.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
slogan: The FreeSewing lab provides
|
||||
slogan1: All our pattern designs
|
||||
slogan2: New & old version
|
||||
slogan3: Bleeding edge code
|
||||
slogan4: Unreleased designs
|
|
@ -70,7 +70,7 @@ const app = {
|
|||
"documentationForEditors": "Dokumentation für Redakteure",
|
||||
"documentationForTranslators": "Dokumentation für Übersetzer/-innen",
|
||||
"documentationOverview": "Überblick über die Dokumentation",
|
||||
"dolls": "Dolls",
|
||||
"dolls": "Puppen",
|
||||
"download": "Herunterladen",
|
||||
"draft": "Entwurf",
|
||||
"draftPattern": "{pattern} erstellen",
|
||||
|
@ -127,7 +127,7 @@ const app = {
|
|||
"newThing": "Neu {thing}",
|
||||
"newPatternForModel": "{pattern} für {model} neu erstellen",
|
||||
"noChanges": "Keine Änderungen",
|
||||
"no": "No",
|
||||
"no": "Nein",
|
||||
"noPasswordPolicy": "Wir haben keine strikten Passwort-Rictlinien",
|
||||
"noSeamAllowance": "Keine Nahtzugabe",
|
||||
"notAllOfThisContentIsAvailableInLanguage": "Nicht alle Inhalte sind auf Deutsch verfügbar",
|
||||
|
@ -228,7 +228,7 @@ const app = {
|
|||
"withBreasts": "Mit Brüsten",
|
||||
"withoutBreasts": "Ohne Brüste",
|
||||
"yay": "Juhuu!",
|
||||
"yes": "Yes",
|
||||
"yes": "Ja",
|
||||
"youAreAPatron": "Du bist ein/e Förder/in",
|
||||
"youAreNotAPatron": "Du bist kein/e Förder/in",
|
||||
"youAreNotLoggedIn": "Du bist nicht eingeloggt",
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
* All edits will be overwritten on the next (pre)build
|
||||
*/
|
||||
const common = {
|
||||
"designs": "Designs",
|
||||
"sloganCome": "Come for the sewing patterns",
|
||||
"sloganStay": "Stay for the community"
|
||||
"designs": "Entwurf",
|
||||
"sloganCome": "Komm für die Schnittmuster",
|
||||
"sloganStay": "Bleib für die Community"
|
||||
}
|
||||
|
||||
export default common
|
||||
|
|
|
@ -16,6 +16,7 @@ import gdpr from "./gdpr.mjs"
|
|||
import i18n from "./i18n.mjs"
|
||||
import intro from "./intro.mjs"
|
||||
import jargon from "./jargon.mjs"
|
||||
import lab from "./lab.mjs"
|
||||
import measurements from "./measurements.mjs"
|
||||
import optiongroups from "./optiongroups.mjs"
|
||||
import o_aaron from "./o_aaron.mjs"
|
||||
|
@ -79,6 +80,7 @@ const allNamespaces = {
|
|||
i18n,
|
||||
intro,
|
||||
jargon,
|
||||
lab,
|
||||
measurements,
|
||||
optiongroups,
|
||||
o_aaron,
|
||||
|
|
|
@ -9,7 +9,7 @@ const jargon = {
|
|||
"darts.d": "<a href='/docs/sewing/darts/'>Abnäher</a> in der <a href='/docs/sewing'>Dokumentation zum Nähen</a>",
|
||||
"doubleWeltPockets.d": "Siehe <a href='/docs/sewing/double-welt-pockets/'>Doppelpaspeltasche</a> in der <a href='/docs/sewing'>Dokumentation zum Nähen</a>",
|
||||
"ease.d": "Siehe <a href='/docs/sewing/ease/'>Zugabe</a> in der <a href='/docs/sewing'>Dokumentation zum Nähen</a>",
|
||||
"edgestitch.d": "See <a href='/docs/sewing/edgestitching/'>Edgestitching</a> in the <a href='/docs/sewing'>Sewing documentation</a>",
|
||||
"edgestitch.d": "Siehe <a href='/docs/sewing/edgestitching/'>Nähte absteppen</a> in der <a href='/docs/sewing'>Dokumentation zum Nähen</a>",
|
||||
"fabricGrain.d": "Siehe <a href='/docs/sewing/fabric-grain/'>Fadenlauf</a> in der <a href='/docs/sewing'>Dokumentation zum Nähen</a>",
|
||||
"goodSidesTogether.d": "Siehe <a href='/docs/sewing/good-sides-together/'>rechts auf rechts</a> in der <a href='/docs/sewing/'>Dokumentation zum Nähen</a>",
|
||||
"onTheFold.d": "Siehe <a href='/docs/sewing/on-the-fold/'>Im Stoffbruch</a> in der <a href='/docs/sewing/'>Dokumentation zum Nähen</a>",
|
||||
|
|
13
packages/i18n/src/next/de/lab.mjs
Normal file
13
packages/i18n/src/next/de/lab.mjs
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* This file is auto-generated by the prebuild script
|
||||
* All edits will be overwritten on the next (pre)build
|
||||
*/
|
||||
const lab = {
|
||||
"slogan": "The FreeSewing lab provides",
|
||||
"slogan1": "All our pattern designs",
|
||||
"slogan2": "New & old version",
|
||||
"slogan3": "Bleeding edge code",
|
||||
"slogan4": "Unreleased designs"
|
||||
}
|
||||
|
||||
export default lab
|
|
@ -33,7 +33,7 @@ const measurements = {
|
|||
"upperLeg": "Oberschenkelumfang",
|
||||
"waist": "Taillenweite",
|
||||
"waistBack": "Taillenweite hinten",
|
||||
"waistToArmhole": "Waist to armhole",
|
||||
"waistToArmhole": "Taille zu Armloch",
|
||||
"waistToFloor": "Taille bis Boden",
|
||||
"waistToHips": "Taille bis Hüfte",
|
||||
"waistToKnee": "Taille bis Knie",
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
const o_aaron = {
|
||||
"armholeDrop.t": "Armlochabsenkung",
|
||||
"armholeDrop.d": "Senkt das Armloch um diesen Wert. Negative Werte erhöhen es.",
|
||||
"backlineBend.t": "Armlochform hinten",
|
||||
"backlineBend.t": "Hintere Armlochform",
|
||||
"backlineBend.d": "Bestimmt die Form / Krümmung der Rückseite der Armlöcher.",
|
||||
"hipsEase.t": "Bequemlichkeitszugabe Hüfte",
|
||||
"hipsEase.d": "Die Menge an Bequemlichkeits-/Bewegungszugabe an deinen Hüften.",
|
||||
|
|
|
@ -4,55 +4,57 @@
|
|||
*/
|
||||
const o_bee = {
|
||||
"chestEase.t": "Brustzugabe",
|
||||
"chestEase.d": "Controls the chest ease in the underlying Bella block Bee is based on",
|
||||
"chestEase.d": "Kontrolliert die Brustzugabe des zugrunde liegenden Grundschnittes \"Bella\" auf welchem Bee basiert",
|
||||
"waistEase.t": "Taillenzugabe",
|
||||
"waistEase.d": "Controls the waist ease in the underlying Bella block Bee is based on",
|
||||
"bustSpanEase.t": "Büstenumfang leicht",
|
||||
"bustSpanEase.d": "Controls the bust span ease in the underlying Bella block Bee is based on",
|
||||
"topDepth.t": "Top Depth",
|
||||
"topDepth.d": "Controls how far the bikini cup extends upwards",
|
||||
"bottomCupDepth.t": "Bottom depth",
|
||||
"bottomCupDepth.d": "Controls how far the bikini cup extends downwards",
|
||||
"sideDepth.t": "Side depth",
|
||||
"sideDepth.d": "Controls how far the bikini cup extends towards the side",
|
||||
"sideCurve.t": "Side curve",
|
||||
"sideCurve.d": "Controls the curvature of the side of the bikini cup",
|
||||
"frontCurve.t": "Front curve",
|
||||
"frontCurve.d": "Controls the curvature of the front of the bikini cup",
|
||||
"bellaGuide.t": "Show Bella",
|
||||
"bellaGuide.d": "Shows the outline of the Bella block Bee is based on",
|
||||
"ties.t": "Ties",
|
||||
"ties.d": "Whether to includes ties, yes or no",
|
||||
"bandTieWidth.t": "Band (chest) tie width",
|
||||
"bandTieWidth.d": "Controls the width of the ties around your chest",
|
||||
"bandTieLength.t": "Band (chest) tie length",
|
||||
"bandTieLength.d": "Controls the length of the ties around your chest",
|
||||
"bandTieEnds.t": "Band (chest) tie ends",
|
||||
"bandTieEnds.d": "Whether you like straight or pointy ends on the ties around your chest",
|
||||
"bandTieColours.t": "Band (chest) tie length colours",
|
||||
"bandTieColours.d": "Whether you want single color ties around your chest, or dual-coloured ones",
|
||||
"neckTieWidth.t": "Neck tie width",
|
||||
"neckTieWidth.d": "Controls the width of the ties around your chest",
|
||||
"neckTieLength.t": "Neck tie length",
|
||||
"neckTieLength.d": "Controls the length of the ties around your chest",
|
||||
"neckTieEnds.t": "Neck tie ends",
|
||||
"neckTieEnds.d": "Whether you like straight or pointy ends on the ties around your chest",
|
||||
"neckTieColours.t": "Neck tie colours",
|
||||
"neckTieColours.d": "Whether you want single color ties around your chest, or dual-coloured ones",
|
||||
"crossBackTies.t": "Cross back ties",
|
||||
"crossBackTies.d": "Whether you'd like to use the cross back tie variation of Bee",
|
||||
"bandLength.t": "Band Length (Cross back ties)",
|
||||
"bandLength.d": "Controls the length of the band around your chest for the cross back ties variation of Bee",
|
||||
"backDartHeight.t": "Back dart height (Bella)",
|
||||
"backDartHeight.d": "Controls the back dart height in the underlying Bella block Bee is based on",
|
||||
"armholeDepth.t": "Armhole depth (Bella)",
|
||||
"armholeDepth.d": "Controls the armhole depth in the underlying Bella block Bee is based on",
|
||||
"frontArmholePitchDepth.t": "Front armhole pitch depth (Bella)",
|
||||
"frontArmholePitchDepth.d": "Controls the front armhole pitch depth in the underlying Bella block Bee is based on",
|
||||
"frontShoulderWidth.t": "Front shoulder width (Bella)",
|
||||
"frontShoulderWidth.d": "Controls the front shoulder width in the underlying Bella block Bee is based on",
|
||||
"highBustWidth.t": "High bust width (Bella)",
|
||||
"highBustWidth.d": "Controls the high bust width in the underlying Bella block Bee is based on"
|
||||
"waistEase.d": "Kontrolliert die Taillenzugabe des zugrunde liegenden Grundschnittes \"Bella\" auf welchem Bee basiert",
|
||||
"bustSpanEase.t": "Zugabe im Abstand der Brustpunkte",
|
||||
"bustSpanEase.d": "Kontrolliert die Zugabe des Abstandes der Brustpunkte des zugrunde liegenden Grundschnittes \"Bella\" auf welchem Bee basiert",
|
||||
"topDepth.t": "Obere Tiefe",
|
||||
"topDepth.d": "Kontrolliert, wie weit sich der Bikini-Cup nach oben erstreckt",
|
||||
"bottomCupDepth.t": "Untere Tiefe",
|
||||
"bottomCupDepth.d": "Kontrolliert, wie weit sich der Bikini-Cup nach unten erstreckt",
|
||||
"sideDepth.t": "Seitliche Tiefe",
|
||||
"sideDepth.d": "Kontrolliert, wie weit sich der Bikini-Cup zur Seite erstreckt",
|
||||
"sideCurve.t": "Seitliche Kurve",
|
||||
"sideCurve.d": "Kontrolliert die Krümmung der Seite des Bikini-Cups",
|
||||
"frontCurve.t": "Vordere Kurve",
|
||||
"frontCurve.d": "Kontrolliert die Krümmung der Vorderseite des Bikini-Cups",
|
||||
"bellaGuide.t": "Bella anzeigen",
|
||||
"bellaGuide.d": "Zeigt die Umrisse des Bella-Grundschnittes an, auf dem Bee basiert",
|
||||
"ties.t": "Bänder",
|
||||
"ties.d": "Sollen Bänder hinzugefügt werden, ja oder nein",
|
||||
"bandTieWidth.t": "Breite des Brustbandes",
|
||||
"bandTieWidth.d": "Kontrolliert die Breite des Bandes um deinen Brustkorb",
|
||||
"bandTieLength.t": "Länge des Brustbandes",
|
||||
"bandTieLength.d": "Kontrolliert die Länge des Bandes um deinen Brustkorb",
|
||||
"bandTieEnds.t": "Enden des Brustbandes",
|
||||
"bandTieEnds.d": "Möchtest du gerade oder spitze Enden des Brustbandes?",
|
||||
"bandTieColours.t": "Farben des Brustbandes",
|
||||
"bandTieColours.d": "Möchtest du ein- oder mehrfarbige Brustbänder?",
|
||||
"neckTieWidth.t": "Breite des Nackenträgers",
|
||||
"neckTieWidth.d": "Steuert die Breite des Nackenträgers",
|
||||
"neckTieLength.t": "Länge des Nackenträgers",
|
||||
"neckTieLength.d": "Steuert die Länge des Nackenträgers",
|
||||
"neckTieEnds.t": "Enden des Nackenträgers",
|
||||
"neckTieEnds.d": "Möchtest du gerade oder spitze Enden des Nackenträgers?",
|
||||
"neckTieColours.t": "Farben des Nackenträgers",
|
||||
"neckTieColours.d": "Möchtest du ein- oder mehrfarbige Nackenträger?",
|
||||
"crossBackTies.t": "Gekreuzte Rückenträger",
|
||||
"crossBackTies.d": "Möchtest du die Version von Bee mit gekreuzten Rückenträgern?",
|
||||
"bandLength.t": "Länge der gekreuzten Rückenträger",
|
||||
"bandLength.d": "Kontrolliert die Länge Brustbandes für die Variante von Bee mit gekreuzten Rückenträgern",
|
||||
"backDartHeight.t": "Höhe der Rückenabnäher (Bella)",
|
||||
"backDartHeight.d": "Kontrolliert die Höhe der Rückenabnäher des zugrunde liegenden Grundschnittes \"Bella\" auf welchem Bee basiert",
|
||||
"armholeDepth.t": "Tiefen des Armloches (Bella)",
|
||||
"armholeDepth.d": "Kontrolliert die Tiefe des Armloches des zugrunde liegenden Grundschnittes \"Bella\" auf welchem Bee basiert",
|
||||
"frontArmholePitchDepth.t": "Tiefe des vorderen Armlochdrehpunktes (Bella)",
|
||||
"frontArmholePitchDepth.d": "Kontrolliert die Tiefe des vorderen Armlochdrehpunktes des zugrunde liegenden Grundschnittes \"Bella\" auf welchem Bee basiert",
|
||||
"frontShoulderWidth.t": "Vordere Schulterbreite (Bella)",
|
||||
"frontShoulderWidth.d": "Kontrolliert die vordere Schulterbreite des zugrunde liegenden Grundschnittes \"Bella\" auf welchem Bee basiert",
|
||||
"fullChestEaseReduction.t": "Full chest reduction (Bella)",
|
||||
"fullChestEaseReduction.d": "Controls the full chest reduction in the underlying Bella block Bee is based on",
|
||||
"highBustWidth.t": "Hohe Brustweite (Bella)",
|
||||
"highBustWidth.d": "Kontrolliert die hohe Brustbreite des zugrunde liegenden Grundschnittes \"Bella\" auf welchem Bee basiert"
|
||||
}
|
||||
|
||||
export default o_bee
|
||||
|
|
|
@ -9,10 +9,10 @@ const o_bella = {
|
|||
"waistEase.d": "Steuert die Menge an Leichtigkeit in deiner Taille",
|
||||
"bustSpanEase.t": "Zugabe seitlicher Brustbereich",
|
||||
"bustSpanEase.d": "Steuert die Größe der (horizontalen) Zugabe, zu deinem seitlichen Brustbereich, \nwenn Brustpunkt berechnet wird.",
|
||||
"shoulderToShoulderEase.t": "Shoulder to Shoulder ease",
|
||||
"shoulderToShoulderEase.d": "Controls the amount of ease between your shoulders. Initially set to -.5% because Bella implements a block that is used in the industry.",
|
||||
"fullChestEaseReduction.t": "Full chest ease reduction",
|
||||
"fullChestEaseReduction.d": "Allows you to independently reduce the ease around the chest to make it fit tight(er) in that area",
|
||||
"shoulderToShoulderEase.t": "Zugabe des Schulterabstandes",
|
||||
"shoulderToShoulderEase.d": "Kontrolliert die Menge an Zugabe zwischen deinen Schultern. Liegt inital bei -0,5%, da Bella ein Grundschnitt erfüllt, welcher in der Branche verwendet wird.",
|
||||
"fullChestEaseReduction.t": "Verringerung der Brustumfangszugabe",
|
||||
"fullChestEaseReduction.d": "Ermöglicht es dir den Spielraum an der Brust zu verringern, um dort einen engeren Sitz zu ermöglichen",
|
||||
"backDartHeight.t": "Höhe Rückenabnäher",
|
||||
"backDartHeight.d": "Steuert die Höhe des Rückenabnähers",
|
||||
"bustDartLength.t": "Länge des Brustabnähers",
|
||||
|
@ -24,18 +24,18 @@ const o_bella = {
|
|||
"armholeDepth.t": "Armlochtiefe",
|
||||
"armholeDepth.d": "Steuert die Tiefe des Armloches",
|
||||
"backArmholeSlant.t": "Hintere Armlochschiebung",
|
||||
"backArmholeSlant.d": "Das Rüstungsloch dreht sich leicht um seinen Pitchpunkt",
|
||||
"backArmholeSlant.d": "Dreht das Armloch leicht in seinem Drehpunkt",
|
||||
"frontArmholeCurvature.t": "Vordere Armlochkrümmung",
|
||||
"frontArmholeCurvature.d": "Steuert wie tief das Armloch nach vorne unten ausgeschnitten ist",
|
||||
"backArmholeCurvature.t": "Hintere Armlochkrümmung",
|
||||
"backArmholeCurvature.d": "Steuert wie tief das Armloch nach hinten unten ausgeschnitten ist",
|
||||
"frontArmholePitchDepth.t": "Front-Armloch-Tiefe",
|
||||
"frontArmholePitchDepth.t": "Vordere Armlochtiefe",
|
||||
"frontArmholePitchDepth.d": "Stellt die horizontale Position des Vorderarmlochpunktes fest",
|
||||
"backArmholePitchDepth.t": "Rückenarmloch-Tiefe",
|
||||
"backArmholePitchDepth.d": "Stellt die horizontale Position des Rückenlochpunktes fest",
|
||||
"backNeckCutout.t": "Ausschnitt im Nacken",
|
||||
"backNeckCutout.d": "Steuert wie tief die Halsöffnung auf der Rückseite abgesogen wird",
|
||||
"backHemSlope.t": "Hinterer Saum Hang",
|
||||
"backNeckCutout.d": "Steuert, wie tief der Nackenausschnit am Rücken ausfällt",
|
||||
"backHemSlope.t": "Neigung des hinteren Saumes",
|
||||
"backHemSlope.d": "Steuert den Hang des Saum auf der Rückseite",
|
||||
"frontShoulderWidth.t": "Vordere Schulterbreite",
|
||||
"frontShoulderWidth.d": "Steuert die Schmalheit der vorderen Schultern relativ zum Rücken",
|
||||
|
|
|
@ -11,8 +11,8 @@ const o_charlie = {
|
|||
"backPocketWidth.d": "Steuert die Breite der hinteren Tasche",
|
||||
"backPocketDepth.t": "Tiefe der hinteren Tasche",
|
||||
"backPocketDepth.d": "Steuert die Tiefe der hinteren Tasche",
|
||||
"backPocketFacing.t": "Back pocket facing",
|
||||
"backPocketFacing.d": "Controls whether or not to include facing on the back pockets",
|
||||
"backPocketFacing.t": "Besatz der hinteren Tasche",
|
||||
"backPocketFacing.d": "Legt fest, ob die hinteren Taschen Besatz haben sollen oder nicht",
|
||||
"frontPocketSlantDepth.t": "Vordertasche Schrägtiefe",
|
||||
"frontPocketSlantDepth.d": "Steuert die Tiefe des (vorder) Taschenschlitzes",
|
||||
"frontPocketSlantWidth.t": "Fronttasche Schrägbreite",
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue