1
0
Fork 0

wip: Updates to lab to support v3 patterns

This commit is contained in:
Joost De Cock 2022-08-29 17:44:50 +02:00
parent d59bab6a6c
commit a023f1810c
19 changed files with 101 additions and 155 deletions

View file

@ -3,7 +3,6 @@ import Link from 'next/link'
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'
import CloseIcon from 'shared/components/icons/close.js'
import MenuIcon from 'shared/components/icons/menu.js'
@ -69,7 +68,6 @@ const Header = ({ app }) => {
</button>
<div className="hidden md:flex flex-row items-center gap-2">
<PatternPicker app={app} />
<VersionPicker app={app} />
</div>
<div className="hidden md:flex md:flex-row gap-2">
<Link href="/">

View file

@ -1,6 +1,5 @@
import ThemePicker from 'shared/components/theme-picker.js'
import LocalePicker from 'shared/components/locale-picker.js'
import VersionPicker from 'site/components/version-picker.js'
export const BeforeNav = ({ app }) => (
<>
@ -9,7 +8,6 @@ export const BeforeNav = ({ app }) => (
<LocalePicker app={app} />
</div>
<div className="md:hidden flex flex-row flex-wrap sm:flex-nowrap gap-2 mb-2">
<VersionPicker app={app} />
</div>
</>
)

View file

@ -1,39 +0,0 @@
import React from 'react'
import VersionsIcon from 'shared/components/icons/versions.js'
import { useTranslation } from 'next-i18next'
import versions from 'site/versions.json'
import useVersion from 'site/hooks/useVersion.js'
import {Picker, PickerLink} from 'shared/components/picker'
export const defaultVersion = 'next'
export const formatVersionTitle = version => (!version || version === defaultVersion)
? `${defaultVersion} version`
: `Version ${version}`
export const formatVersionUri = (version=false, design=false) => {
if (!version && !design) return '/'
if (!version && design) return `/${design}`
if (version && !design) return `/v/${version}`
return `/v/${version}/${design}`
}
const PatternPicker = ({ app }) => {
const { t } = useTranslation(['common'])
const version = useVersion()
const pickerProps = {
title: formatVersionTitle(version),
Icon: VersionsIcon,
ariaLabel: t('versionPicker')
}
return (<Picker {...pickerProps}>
{[defaultVersion, ...versions].map(v => (
<PickerLink key={v} href={formatVersionUri(v)}>{formatVersionTitle(v)}</PickerLink>
))}
</Picker>)
}
export default PatternPicker

View file

@ -2,17 +2,15 @@ import { useState } from 'react'
// Stores state in local storage
import useLocalStorage from 'shared/hooks/useLocalStorage.js'
// Designs
import { designsByType } from 'config/software/index.mjs'
import { designsByType } from 'prebuild/designs-by-type.mjs'
// Locale and translation
import { useRouter } from 'next/router'
import { useTranslation } from 'next-i18next'
import { capitalize } from 'shared/utils.mjs'
import { formatVersionUri } from '../components/version-picker.js'
import useVersion from 'site/hooks/useVersion.js'
import useTheme from 'shared/hooks/useTheme'
// Initial navigation
const initialNavigation = (t, version) => {
const initialNavigation = t => {
const base = {
accessories: {
__title: t('accessoryDesigns'),
@ -35,7 +33,7 @@ const initialNavigation = (t, version) => {
for (const design in designsByType[type]) {
base[type][design] = {
__title: capitalize(design),
__slug: formatVersionUri(version,design)
__slug: design
}
}
}
@ -57,9 +55,6 @@ for (const type in designsByType) {
function useApp(full = true) {
// Version
const version = useVersion()
// Load translation method
const locale = useRouter().locale
const { t } = useTranslation(['app'])
@ -70,7 +65,7 @@ function useApp(full = true) {
// React State
const [primaryMenu, setPrimaryMenu] = useState(false)
const [navigation, setNavigation] = useState(initialNavigation(t, version))
const [navigation, setNavigation] = useState(initialNavigation(t))
const [slug, setSlug] = useState('/')
const [design, setDesign] = useState(false)
const [loading, setLoading] = useState(false)

View file

@ -1,16 +0,0 @@
import { useRouter } from 'next/router'
export const defaultVersion = 'next'
const useVersion = () => {
const { pathname } = useRouter()
const chunks = pathname.split('/')
const version = (chunks[1] === 'v')
? chunks[2]
: defaultVersion
return version
}
export default useVersion

View file

View file

@ -1,6 +1,7 @@
import path from 'path'
import i18nConfig from './next-i18next.config.js'
import { designs, plugins } from '../../config/software/index.mjs'
import { designs } from './prebuild/designs.mjs'
import { plugins } from './prebuild/plugins.mjs'
import { banner } from '../../scripts/banner.mjs'
let greeting = false
@ -14,11 +15,11 @@ const config = {
webpack: (config, options) => {
// JSON support
config.module.rules.push({
test: /\.json$/,
type: 'json',
use: 'json-loader'
})
//config.module.rules.push({
// test: /\.json$/,
// type: 'json',
// use: 'json-loader'
//})
// YAML support
config.module.rules.push({
@ -36,7 +37,7 @@ const config = {
// Aliases
config.resolve.alias.shared = path.resolve('../shared/')
config.resolve.alias.site = path.resolve('.')
config.resolve.alias.lib = path.resolve('./lib')
config.resolve.alias.prebuild = path.resolve('./prebuild')
config.resolve.alias.config = path.resolve('../../config/')
config.resolve.alias.designs = path.resolve('../../designs/')
config.resolve.alias.plugins = path.resolve('../../plugins/')

View file

@ -2,12 +2,10 @@ import Page from 'site/components/wrappers/page.js'
import useApp from 'site/hooks/useApp.js'
import Link from 'next/link'
import { useTranslation } from 'next-i18next'
import { formatVersionTitle } from 'site/components/version-picker.js'
import Layout from 'site/components/layouts/bare'
import { PageTitle } from 'shared/components/layouts/default'
import availableVersions from 'site/available-versions.json'
const DesignLinks = ({ list, prefix='', version=false }) => {
const DesignLinks = ({ list, prefix='' }) => {
const { t } = useTranslation(['patterns'])
return (
@ -27,7 +25,7 @@ const DesignLinks = ({ list, prefix='', version=false }) => {
)
}
const PatternListPageTemplate = ({ section=false, version=false }) => {
const PatternListPageTemplate = ({ section=false }) => {
const app = useApp()
const { t } = useTranslation(['app'])
@ -35,45 +33,22 @@ const PatternListPageTemplate = ({ section=false, version=false }) => {
? app.navigation[section].__title
: t('designs')
const sectionDesigns = (section=false, version=false) => {
const sectionDesigns = (section=false) => {
if (!section) {
const all = []
if (!version || version === 'next') {
for (const section in app.designs) all.push(...app.designs[section])
return all
}
else if (availableVersions[version]) return availableVersions[version]
} else {
if (!version || version === 'next') return app.designs[section]
else if (availableVersions[version]) return availableVersions[version]
}
for (const section in app.designs) all.push(...app.designs[section])
return all
} else return app.designs[section]
return []
}
return (
<Page app={app} title={`FreeSewing Lab: ${formatVersionTitle(version)}`} layout={Layout}>
<Page app={app} title={`FreeSewing Lab: ${title}`} layout={Layout}>
<div className="max-w-7xl m-auto py-20 md:py-36 min-h-screen">
<section className="px-8">
<PageTitle app={app} slug={section ? app.navigation[section].__slug : '/' } title={title} />
{version && version !== 'next'
? (
<ul className="flex flex-col flex-wrap gap-2">
{availableVersions[version].map( d => (
<li key={d} className="p-2">
<Link href={`/v/${version}/${d}`}>
<a className="capitalize text-xl p-4 font-bold text-secondary hover:text-secondary-focus hover:underline">
{t(`patterns:${d}.t`)}
<br />
<span className="text-lg font-normal p-4 text-base-content">{t(`patterns:${d}.d`)}</span>
</a>
</Link>
</li>
))}
</ul>
)
: <DesignLinks list={sectionDesigns(section)} />
}
<DesignLinks list={sectionDesigns(section)} />
</section>
</div>
</Page>

View file

@ -1,4 +1,4 @@
import Json from 'shared/components/json.js'
import Json from 'shared/components/json-highlight.js'
const GistAsJson = props => (
<div className="max-w-screen-xl m-auto">

View file

@ -1,33 +1,33 @@
import React, {useMemo, useEffect, useState} from 'react'
import MeasurementInput from '../inputs/measurement.js'
import { withBreasts, withoutBreasts } from '@freesewing/models'
import { menswear, womenswear } from '@freesewing/models'
import nonHuman from './non-human.js'
import WithBreastsIcon from 'shared/components/icons/with-breasts.js'
import WithoutBreastsIcon from 'shared/components/icons/without-breasts.js'
import WomenswearIcon from 'shared/components/icons/womenswear.js'
import MenswearIcon from 'shared/components/icons/menswear.js'
import { useTranslation } from 'next-i18next'
import Setting from '../menu/core-settings/setting';
import {settings} from '../menu/core-settings/index';
import { Tab, Tabs } from 'shared/components/mdx/tabs.js'
const groups = {
people: {
with: withBreasts,
without: withoutBreasts,
},
people: { menswear, womenswear },
dolls: {
with: nonHuman.withBreasts.dolls,
without: nonHuman.withoutBreasts.dolls,
menswear: nonHuman.menswear.dolls,
womenswear: nonHuman.womenswear.dolls,
},
giants: {
with: nonHuman.withBreasts.giants,
without: nonHuman.withoutBreasts.giants,
menswear: nonHuman.menswear.giants,
womenswear: nonHuman.womenswear.giants,
}
}
const icons = {
with: <WithBreastsIcon />,
without: <WithoutBreastsIcon />,
menswear: <MenswearIcon />,
womenswear: <WomenswearIcon />,
}
const WorkbenchMeasurements = ({ app, design, gist, updateGist, gistReady }) => {
const { t } = useTranslation(['app', 'cfp'])
@ -72,7 +72,7 @@ const WorkbenchMeasurements = ({ app, design, gist, updateGist, gistReady }) =>
<Tab tabId={group}>
{Object.keys(icons).map(type => (
<React.Fragment key={type}>
<h4 className="mt-4">{t(`${type}Breasts`)}</h4>
<h4 className="mt-4">{t(type)}</h4>
<ul className="flex flex-row flex-wrap gap-2">
{Object.keys(groups[group][type]).map((m) => (
<li key={`${m}-${type}-${group}`} className="">
@ -81,9 +81,8 @@ const WorkbenchMeasurements = ({ app, design, gist, updateGist, gistReady }) =>
onClick={() => updateMeasurements(groups[group][type][m], false)}
>
{icons[type]}
{t('size')}&nbsp;
{ group === 'people'
? m.replace('size', '')
? m.slice(-2)
: m
}
</button>

View file

@ -1,11 +1,11 @@
import { withBreasts, withoutBreasts } from '@freesewing/models'
import { menswear42, womenswear34 } from '@freesewing/models'
const nonHuman = {
withoutBreasts: {
menswear: {
dolls: {},
giants: {}
},
withBreasts: {
womenswear: {
dolls: {},
giants: {}
}
@ -14,34 +14,34 @@ const round = val => Math.round(val*10)/10
for (let i=0.1;i<0.7;i+=0.1) {
const name = `${Math.round(i*10)}/10`
nonHuman.withBreasts.dolls[name] = {}
// withBreasts: Based on Anneke (size 34)
for (const [m, val] of Object.entries(withBreasts.size34)) {
nonHuman.withBreasts.dolls[name][m] = (m === 'shoulderSlope')
nonHuman.womenswear.dolls[name] = {}
// womenswear: Based on womenswear34
for (const [m, val] of Object.entries(womenswear34)) {
nonHuman.womenswear.dolls[name][m] = (m === 'shoulderSlope')
? val
: round(val * i)
}
// withoutBreasts: Based on Ronan (size 42)
nonHuman.withoutBreasts.dolls[name] = {}
for (const [m, val] of Object.entries(withoutBreasts.size42)) {
nonHuman.withoutBreasts.dolls[name][m] = (m === 'shoulderSlope')
nonHuman.menswear.dolls[name] = {}
// menswear: Based on menswear42
for (const [m, val] of Object.entries(menswear42)) {
nonHuman.menswear.dolls[name][m] = (m === 'shoulderSlope')
? val
: round(val * i)
}
}
for (let i=1.5;i<=3;i+=0.5) {
const name = `${i}/1`
nonHuman.withBreasts.giants[name] = {}
// withBreasts: Based on Anneke (size 34)
for (const [m, val] of Object.entries(withBreasts.size34)) {
nonHuman.withBreasts.giants[name][m] = (m === 'shoulderSlope')
nonHuman.womenswear.giants[name] = {}
// womenswear: Based on womenswear34
for (const [m, val] of Object.entries(womenswear34)) {
nonHuman.womenswear.giants[name][m] = (m === 'shoulderSlope')
? val
: round(val * i)
}
nonHuman.withoutBreasts.giants[name] = {}
// withoutBreasts: Based on Ronan (size 42)
for (const [m, val] of Object.entries(withoutBreasts.size42)) {
nonHuman.withoutBreasts.giants[name][m] = (m === 'shoulderSlope')
nonHuman.menswear.giants[name] = {}
// menswear: Based on menswear42
for (const [m, val] of Object.entries(menswear42)) {
nonHuman.menswear.giants[name][m] = (m === 'shoulderSlope')
? val
: round(val * i)
}

View file

@ -3,9 +3,11 @@ import { Chevron } from 'shared/components/navigation/primary.js'
import OptionGroup from './option-group'
import { Ul, Details, TopSummary, TopSumTitle } from 'shared/components/workbench/menu'
import { useTranslation } from 'next-i18next'
import { optionsMenuStructure } from 'shared/utils.mjs'
const DesignOptions = props => {
const { t } = useTranslation(['app'])
const optionsMenu = optionsMenuStructure(props.design.config.options)
return (
<Details open>
@ -14,12 +16,14 @@ const DesignOptions = props => {
<Chevron />
</TopSummary>
<Ul className="pl-5 list-inside">
{Object.keys(props.design.config.optionGroups).map(group => (
<OptionGroup {...props} group={group} key={group} />
))}
{Object.entries(optionsMenu).map(([group, options]) => typeof options === "string"
? <p>top-level option</p>
: <OptionGroup {...props} group={group} options={options} key={group} />
)}
</Ul>
</Details>
)
}
export default DesignOptions

View file

@ -5,7 +5,7 @@ import { useTranslation } from 'next-i18next'
const OptionGroup = props => {
const { t } = useTranslation(['optiongroups'])
const config = props.config || props.design.config.optionGroups[props.group]
return (
<Li>
<Details>
@ -19,10 +19,10 @@ const OptionGroup = props => {
<Chevron />
</Summary>
<Ul>
{config.map(option =>
typeof option === 'string' ? <Option {...props} option={option} key={option} />
: Object.keys(option).map((sub) => <OptionGroup {...props} config={option[sub]} group={sub} key={sub}/>)
)}
{Object.entries(props.options).map(([option, type]) => typeof type === "string"
? <Option {...props} type={type} option={option} key={option} />
: <OptionGroup {...props} group={option} options={type} key={option}/>)
}
</Ul>
</Details>
</Li>

View file

@ -12,7 +12,7 @@ import Measurements from 'shared/components/workbench/measurements/index.js'
import LabDraft from 'shared/components/workbench/draft/index.js'
import LabSample from 'shared/components/workbench/sample.js'
import ExportDraft from 'shared/components/workbench/exporting/index.js'
import GistAsJson from 'shared/components/workbench/json.js'
import GistAsJson from 'shared/components/workbench/gist-as-json.js'
import GistAsYaml from 'shared/components/workbench/yaml.js'
import DraftEvents from 'shared/components/workbench/events.js'
import CutLayout from 'shared/components/workbench/layout/cut'

View file

@ -1,7 +1,7 @@
import fs_ from 'fs'
import path from 'path'
import { capitalize } from '../utils.mjs'
import { designsByType } from '../../../config/software/index.mjs'
import { designsByType, plugins, designs } from '../../../config/software/index.mjs'
const fs = fs_.promises
@ -43,7 +43,6 @@ export const prebuildLab = async (site) => {
// Iterate over sections
console.log(`Generating pages for ${section} designs`)
for (const design in designsByType[section]) {
// Generate pattern pages for next
console.log(` - ${design}`)
const page = pageTemplate(design)
@ -62,6 +61,24 @@ export const prebuildLab = async (site) => {
}
}
// Write designs file
const header = "// This file is auto-generated by the prebuild script | Any changes will be overwritten\n"
const nl = "\n"
promises.push(
fs.writeFile(
path.resolve('..', 'lab', 'prebuild', 'designs.mjs'),
`${header}export const designs = ${JSON.stringify(Object.keys(designs))}${nl}`
),
fs.writeFile(
path.resolve('..', 'lab', 'prebuild', 'plugins.mjs'),
`${header}export const plugins = ${JSON.stringify(Object.keys(plugins))}${nl}`
),
fs.writeFile(
path.resolve('..', 'lab', 'prebuild', 'designs-by-type.mjs'),
`${header}export const designsByType = ${JSON.stringify(designsByType)}${nl}`
),
)
await Promise.all(promises)
}

View file

@ -1,4 +1,5 @@
import get from 'lodash.get'
import set from 'lodash.set'
// Generic rounding method
export const round = (val, decimals=1) => Math.round(val*Math.pow(10, decimals))/Math.pow(10, decimals)
@ -159,3 +160,16 @@ export const measurementAsMm = (value, units = "metric") => {
}
return false;
}
export const optionsMenuStructure = options => {
if (!options) return options
const menu = {}
for (const [name, option] of Object.entries(options)) {
if (typeof option === 'object') {
set(menu, (option.menu ? `${option.menu}.${name}` : name), optionType(option))
}
}
return menu
}