chore: Adapt sites to recent changes
77
.gitignore
vendored
|
@ -3,10 +3,12 @@
|
||||||
# .env
|
# .env
|
||||||
.env
|
.env
|
||||||
|
|
||||||
# Specifics
|
# Plugins
|
||||||
export
|
plugins/plugin-theme/src/bundle.css.js
|
||||||
packages/plugin-theme/src/bundle.css.js
|
plugins/plugin-theme/css
|
||||||
packages/plugin-theme/css
|
|
||||||
|
|
||||||
|
# Components package build artifacts
|
||||||
packages/components/Blockquote
|
packages/components/Blockquote
|
||||||
packages/components/Draft
|
packages/components/Draft
|
||||||
packages/components/DraftConfigurator
|
packages/components/DraftConfigurator
|
||||||
|
@ -27,8 +29,12 @@ packages/components/withGist
|
||||||
packages/components/withLanguage
|
packages/components/withLanguage
|
||||||
packages/components/withStorage
|
packages/components/withStorage
|
||||||
packages/components/Workbench
|
packages/components/Workbench
|
||||||
|
|
||||||
|
# Code coverage reports
|
||||||
packages/core/coverage
|
packages/core/coverage
|
||||||
packages/workbench
|
packages/*/report
|
||||||
|
|
||||||
|
# Utils package build artifacts
|
||||||
packages/utils/backend
|
packages/utils/backend
|
||||||
packages/utils/camelCase
|
packages/utils/camelCase
|
||||||
packages/utils/capitalize
|
packages/utils/capitalize
|
||||||
|
@ -54,60 +60,48 @@ packages/utils/tiler
|
||||||
packages/utils/validateEmail
|
packages/utils/validateEmail
|
||||||
packages/utils/validateTld
|
packages/utils/validateTld
|
||||||
|
|
||||||
packages/*/example/yarn.lock
|
# Any NPM or Yarn lock files
|
||||||
packages/*/report
|
designs/*/package-lock.json
|
||||||
|
designs/*/yarn.lock
|
||||||
packages/*/package-lock.json
|
packages/*/package-lock.json
|
||||||
packages/*/yarn.lock
|
packages/*/yarn.lock
|
||||||
packages/strapi/.cache
|
plugins/*/package-lock.json
|
||||||
|
plugins/*/yarn.lock
|
||||||
|
|
||||||
packages/freesewing.dev/public/locales/en/*.json
|
# NPM lock files for sites (we use yarn)
|
||||||
|
sites/*/package-lock.json
|
||||||
|
|
||||||
packages/freesewing.org/public/locales/en/*.json
|
# Strapi cache
|
||||||
packages/freesewing.org/public/locales/es/*.json
|
sites/strapi/.cache
|
||||||
packages/freesewing.org/public/locales/de/*.json
|
|
||||||
packages/freesewing.org/public/locales/fr/*.json
|
|
||||||
packages/freesewing.org/public/locales/nl/*.json
|
|
||||||
|
|
||||||
packages/freesewing.lab/public/locales/en/*.json
|
# Sites prebuild artifacts
|
||||||
packages/freesewing.lab/public/locales/es/*.json
|
sites/*/public/locales/*/*.json
|
||||||
packages/freesewing.lab/public/locales/de/*.json
|
sites/*/public/feeds/*
|
||||||
packages/freesewing.lab/public/locales/fr/*.json
|
|
||||||
packages/freesewing.lab/public/locales/nl/*.json
|
|
||||||
|
|
||||||
packages/freesewing.org/public/feeds/*
|
# Lab auto-generated pages
|
||||||
packages/freesewing.dev/public/feeds/*
|
sites/lab/lib
|
||||||
|
sites/lab/pages
|
||||||
|
|
||||||
packages/freesewing.lab/lib
|
# Node dependencies
|
||||||
packages/freesewing.lab/pages
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
node_modules
|
node_modules
|
||||||
|
|
||||||
# build
|
# Build folders
|
||||||
dist
|
dist
|
||||||
build
|
build
|
||||||
|
export
|
||||||
|
|
||||||
#prebuild
|
# Prebuild files
|
||||||
prebuild/*.json
|
prebuild/*.json
|
||||||
|
|
||||||
# yarn
|
# Yarn
|
||||||
.yarn
|
.yarn
|
||||||
.yarnrc
|
.yarnrc
|
||||||
|
|
||||||
# NextJS
|
# NextJS
|
||||||
.next
|
.next
|
||||||
packages/freesewing.dev/out
|
sites/*/out
|
||||||
packages/freesewing.lab/out
|
sites/*/public/mdx
|
||||||
packages/freesewing.org/out
|
sites/*/prebuild
|
||||||
packages/freesewing.dev/public/mdx
|
|
||||||
packages/freesewing.lab/public/mdx
|
|
||||||
packages/freesewing.org/public/mdx
|
|
||||||
packages/freesewing.dev/prebuild
|
|
||||||
packages/freesewing.lab/prebuild
|
|
||||||
packages/freesewing.org/prebuild
|
|
||||||
|
|
||||||
# Mock registry (verdaccio)
|
|
||||||
.registry
|
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
@ -127,9 +121,6 @@ packages/i18n/sort.sh
|
||||||
scripts/taskrunner.sh
|
scripts/taskrunner.sh
|
||||||
scripts/verdaccio.sh
|
scripts/verdaccio.sh
|
||||||
|
|
||||||
# Local Netlify folder
|
|
||||||
.netlify
|
|
||||||
|
|
||||||
# Don't ignore the specific Points.dist() docs folder
|
# Don't ignore the specific Points.dist() docs folder
|
||||||
!markdown/dev/reference/api/point/dist
|
!markdown/dev/reference/api/point/dist
|
||||||
|
|
||||||
|
|
906
CHANGELOG.md
|
@ -45,3 +45,5 @@ export const degreeMeasurements = ['shoulderSlope']
|
||||||
|
|
||||||
/* Helper method to determine whether a measurement uses degrees */
|
/* Helper method to determine whether a measurement uses degrees */
|
||||||
export const isDegreeMeasurement = (measie) => degreeMeasurements.indexOf(measie) !== -1
|
export const isDegreeMeasurement = (measie) => degreeMeasurements.indexOf(measie) !== -1
|
||||||
|
|
||||||
|
|
|
@ -1,51 +1,59 @@
|
||||||
{
|
{
|
||||||
"aaron": "A FreeSewing pattern for a A-shirt or tank top",
|
"accessories": {
|
||||||
"albert": "A FreeSewing pattern for an apron",
|
"benjamin": "A FreeSewing pattern for a bow tie",
|
||||||
"bee": "A FreeSewing pattern for a bikini top",
|
"florence": "A FreeSewing pattern for a face mask",
|
||||||
"bella": "A FreeSewing pattern for a womenswear bodice block",
|
"florent": "A FreeSewing pattern for a flat cap",
|
||||||
"benjamin": "A FreeSewing pattern for a bow tie",
|
"hi": "A FreeSewing pattern for a shark plush toy",
|
||||||
"bent": "A FreeSewing pattern for a menswear body block with a two-part sleeve",
|
"holmes": "A FreeSewing pattern for a Sherlock Holmes hat",
|
||||||
"breanna": "A FreeSewing pattern for a basic body block for womenswear",
|
"hortensia": "A FreeSewing pattern for a handbag",
|
||||||
"brian": "A FreeSewing pattern for a basic body block for menswear",
|
"trayvon": "A FreeSewing pattern for a tie"
|
||||||
"bruce": "A FreeSewing pattern for boxer briefs",
|
},
|
||||||
"carlita": "A FreeSewing pattern for Sherlock Holmes cosplay; Or just a nice long coat",
|
"blocks": {
|
||||||
"carlton": "A FreeSewing pattern for Sherlock Holmes cosplay; Or just a nice long coat",
|
"bella": "A FreeSewing pattern for a womenswear bodice block",
|
||||||
"cathrin": "A FreeSewing pattern for a underbust corset / waist trainer",
|
"bent": "A FreeSewing pattern for a menswear body block with a two-part sleeve",
|
||||||
"charlie": "A FreeSewing pattern for chino trousers",
|
"breanna": "A FreeSewing pattern for a basic body block for womenswear",
|
||||||
"cornelius": "A FreeSewing pattern for cycling breeches, based on the Keystone drafting system",
|
"brian": "A FreeSewing pattern for a basic body block for menswear",
|
||||||
"diana": "A FreeSewing pattern for a top with a draped neck",
|
"titan": "A FreeSewing pattern for a unisex trouser block"
|
||||||
"examples": "A FreeSewing pattern holding examples for our documentation",
|
},
|
||||||
"florence": "A FreeSewing pattern for a face mask",
|
"garments": {
|
||||||
"florent": "A FreeSewing pattern for a flat cap",
|
"aaron": "A FreeSewing pattern for a A-shirt or tank top",
|
||||||
"hi": "A FreeSewing pattern for a shark plush toy",
|
"albert": "A FreeSewing pattern for an apron",
|
||||||
"holmes": "A FreeSewing pattern for a Sherlock Holmes hat",
|
"bee": "A FreeSewing pattern for a bikini top",
|
||||||
"hortensia": "A FreeSewing pattern for a handbag",
|
"bruce": "A FreeSewing pattern for boxer briefs",
|
||||||
"huey": "A FreeSewing pattern for a zip-up hoodie",
|
"carlita": "A FreeSewing pattern for Sherlock Holmes cosplay; Or just a nice long coat",
|
||||||
"hugo": "A FreeSewing pattern for a hooded jumper with raglan sleeves",
|
"carlton": "A FreeSewing pattern for Sherlock Holmes cosplay; Or just a nice long coat",
|
||||||
"jaeger": "A FreeSewing pattern for a sport coat style jacket",
|
"cathrin": "A FreeSewing pattern for a underbust corset / waist trainer",
|
||||||
"legend": "A FreeSewing pattern to document pattern notation",
|
"charlie": "A FreeSewing pattern for chino trousers",
|
||||||
"lucy": "A FreeSewing pattern for a historical tie-on pocket",
|
"cornelius": "A FreeSewing pattern for cycling breeches, based on the Keystone drafting system",
|
||||||
"lunetius": "A FreeSewing pattern for a lacerna, a historical Roman cloak",
|
"diana": "A FreeSewing pattern for a top with a draped neck",
|
||||||
"paco": "A FreeSewing pattern for summer pants",
|
"huey": "A FreeSewing pattern for a zip-up hoodie",
|
||||||
"penelope": "A FreeSewing pattern for a pencil skirt",
|
"hugo": "A FreeSewing pattern for a hooded jumper with raglan sleeves",
|
||||||
"plugintest": "A FreeSewing pattern to test (y)our plugins",
|
"jaeger": "A FreeSewing pattern for a sport coat style jacket",
|
||||||
"rendertest": "A FreeSewing pattern to test (y)our render engine our CSS",
|
"lucy": "A FreeSewing pattern for a historical tie-on pocket",
|
||||||
"sandy": "A FreeSewing pattern for a circle skirt",
|
"lunetius": "A FreeSewing pattern for a lacerna, a historical Roman cloak",
|
||||||
"shin": "A FreeSewing pattern for swim trunks",
|
"paco": "A FreeSewing pattern for summer pants",
|
||||||
"simon": "A FreeSewing pattern for a button down shirt",
|
"penelope": "A FreeSewing pattern for a pencil skirt",
|
||||||
"simone": "A FreeSewing pattern for a button down shirt (Simone = Simon for people with breasts)",
|
"sandy": "A FreeSewing pattern for a circle skirt",
|
||||||
"sven": "A FreeSewing pattern for a straightforward sweater",
|
"shin": "A FreeSewing pattern for swim trunks",
|
||||||
"tamiko": "A FreeSewing pattern for a zero-waste top",
|
"simon": "A FreeSewing pattern for a button down shirt",
|
||||||
"teagan": "A FreeSewing pattern for a T-shirt",
|
"simone": "A FreeSewing pattern for a button down shirt (Simone = Simon for people with breasts)",
|
||||||
"theo": "A FreeSewing pattern for classic trousers",
|
"sven": "A FreeSewing pattern for a straightforward sweater",
|
||||||
"tiberius": "A FreeSewing pattern for a tunica, a historical Roman tunic",
|
"tamiko": "A FreeSewing pattern for a zero-waste top",
|
||||||
"titan": "A FreeSewing pattern for a unisex trouser block",
|
"teagan": "A FreeSewing pattern for a T-shirt",
|
||||||
"trayvon": "A FreeSewing pattern for a tie",
|
"theo": "A FreeSewing pattern for classic trousers",
|
||||||
"tutorial": "A FreeSewing pattern for a baby bib that's used in our tutorial",
|
"tiberius": "A FreeSewing pattern for a tunica, a historical Roman tunic",
|
||||||
"unice": "A FreeSewing pattern for a basic, highly-customizable underwear pattern",
|
"unice": "A FreeSewing pattern for a basic, highly-customizable underwear pattern",
|
||||||
"ursula": "A FreeSewing pattern for a basic, highly-customizable underwear pattern",
|
"ursula": "A FreeSewing pattern for a basic, highly-customizable underwear pattern",
|
||||||
"wahid": "A FreeSewing pattern for a classic fitted waistcoat",
|
"wahid": "A FreeSewing pattern for a classic fitted waistcoat",
|
||||||
"walburga": "A FreeSewing pattern for a wappenrock (tabard/surcoat), a historical European/medieval (ish) garment",
|
"walburga": "A FreeSewing pattern for a wappenrock (tabard/surcoat), a historical European/medieval (ish) garment",
|
||||||
"waralee": "A FreeSewing pattern for wrap pants",
|
"waralee": "A FreeSewing pattern for wrap pants",
|
||||||
"yuri": "A FreeSewing pattern for a fancy zipless sweater based on the Huey hoodie"
|
"yuri": "A FreeSewing pattern for a fancy zipless sweater based on the Huey hoodie"
|
||||||
|
},
|
||||||
|
"utilities": {
|
||||||
|
"examples": "A FreeSewing pattern holding examples for our documentation",
|
||||||
|
"legend": "A FreeSewing pattern to document pattern notation",
|
||||||
|
"plugintest": "A FreeSewing pattern to test (y)our plugins",
|
||||||
|
"rendertest": "A FreeSewing pattern to test (y)our render engine our CSS",
|
||||||
|
"tutorial": "A FreeSewing pattern for a baby bib that's used in our tutorial"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import designs from './designs.json'
|
import designsByType from './designs.json'
|
||||||
import packages from './packages.json'
|
import packages from './packages.json'
|
||||||
import plugins from './plugins.json'
|
import plugins from './plugins.json'
|
||||||
import sites from './sites.json'
|
import sites from './sites.json'
|
||||||
|
@ -8,8 +8,15 @@ const unpack = (obj, folder) => Object.fromEntries(
|
||||||
Object.keys(obj).map(name => [name, { name, folder, description: obj[name], type: folder.slice(0, -1) } ])
|
Object.keys(obj).map(name => [name, { name, folder, description: obj[name], type: folder.slice(0, -1) } ])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const designs = {
|
||||||
|
...designsByType.accessories,
|
||||||
|
...designsByType.blocks,
|
||||||
|
...designsByType.garments,
|
||||||
|
...designsByType.utilities,
|
||||||
|
}
|
||||||
|
|
||||||
// Re-Export imported JSON
|
// Re-Export imported JSON
|
||||||
export { designs, packages, plugins, sites }
|
export { designs, designsByType, packages, plugins, sites }
|
||||||
|
|
||||||
// All software
|
// All software
|
||||||
export const software = {
|
export const software = {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"backend": "FreeSewing backend",
|
"backend": "FreeSewing backend",
|
||||||
"freesewing.dev": "FreeSewing website with documentation for contributors & developers",
|
"dev": "FreeSewing website with documentation for contributors & developers",
|
||||||
"freesewing.lab": "FreeSewing website to test various patterns",
|
"lab": "FreeSewing website to test various patterns",
|
||||||
"freesewing.org": "FreeSewing website",
|
"org": "FreeSewing website",
|
||||||
"freesewing.shared": "Shared code and React components for different websites",
|
"shared": "Shared code and React components for different websites",
|
||||||
"strapi": "Freesewing's Strapi instance",
|
"strapi": "Freesewing's Strapi instance",
|
||||||
"svgtopdf": "FreeSewing on-demand tiler"
|
"svgtopdf": "FreeSewing on-demand tiler"
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import glob from 'glob'
|
||||||
import yaml from 'js-yaml'
|
import yaml from 'js-yaml'
|
||||||
import chalk from 'chalk'
|
import chalk from 'chalk'
|
||||||
import mustache from 'mustache'
|
import mustache from 'mustache'
|
||||||
import { capitalize } from '../sites/freesewing.shared/utils.mjs'
|
import { capitalize } from '../sites/shared/utils.mjs'
|
||||||
import conf from '../lerna.json'
|
import conf from '../lerna.json'
|
||||||
const { version } = conf
|
const { version } = conf
|
||||||
import {
|
import {
|
||||||
|
|
|
@ -4,8 +4,6 @@ const config = {
|
||||||
index: 'freesewing.dev',
|
index: 'freesewing.dev',
|
||||||
key: '589c7a7e4d9c95a4f12868581259bf3a', // Search-only API key
|
key: '589c7a7e4d9c95a4f12868581259bf3a', // Search-only API key
|
||||||
},
|
},
|
||||||
strapi: 'https://posts.freesewing.org',
|
|
||||||
monorepo: 'https://github.com/freesewing/freesewing'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default config
|
export default config
|
37
sites/dev/components/layouts/docs.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
import Link from 'next/link'
|
||||||
|
// Shared components
|
||||||
|
import Aside from 'shared/components/navigation/aside'
|
||||||
|
import ThemePicker from 'shared/components/theme-picker'
|
||||||
|
import Breadcrumbs from 'shared/components/breadcrumbs.js'
|
||||||
|
import { getCrumbs } from 'shared/utils'
|
||||||
|
|
||||||
|
const DefaultLayout = ({ app, title=false, crumbs=false, children=[] }) => {
|
||||||
|
const router = useRouter()
|
||||||
|
const slug = router.asPath.slice(1)
|
||||||
|
const breadcrumbs = crumbs
|
||||||
|
? crumbs
|
||||||
|
: getCrumbs(app, slug, title)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="m-auto flex flex-row justify-center">
|
||||||
|
<Aside app={app} slug={slug} before={<ThemePicker app={app} className="block sm:hidden"/>}/>
|
||||||
|
<section className="py-28 md:py-36 max-w-7xl px-6 xl:pl-8 2xl:pl-16">
|
||||||
|
<div>
|
||||||
|
{title && (
|
||||||
|
<>
|
||||||
|
<Breadcrumbs title={title} crumbs={breadcrumbs} />
|
||||||
|
{title
|
||||||
|
? <h1>{title}</h1>
|
||||||
|
: <h1>{app.getTitle(slug)}</h1>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DefaultLayout
|
|
@ -5,7 +5,7 @@ import { useRouter } from 'next/router'
|
||||||
import algoliasearch from 'algoliasearch/lite';
|
import algoliasearch from 'algoliasearch/lite';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook'
|
import { useHotkeys } from 'react-hotkeys-hook'
|
||||||
import { InstantSearch, connectHits, connectHighlight, connectSearchBox } from 'react-instantsearch-dom'
|
import { InstantSearch, connectHits, connectHighlight, connectSearchBox } from 'react-instantsearch-dom'
|
||||||
import config from 'site/freesewing.config.js'
|
import config from 'site/algolia.config.mjs'
|
||||||
|
|
||||||
const searchClient = algoliasearch(config.algolia.app, config.algolia.key)
|
const searchClient = algoliasearch(config.algolia.app, config.algolia.key)
|
||||||
|
|
3
sites/dev/i18n.config.mjs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import i18n from '../shared/config/i18n.config.mjs'
|
||||||
|
|
||||||
|
export default i18n()
|
|
@ -1,4 +1,4 @@
|
||||||
import configBuilder from '../freesewing.shared/config/next.mjs'
|
import configBuilder from '../shared/config/next.mjs'
|
||||||
import i18nConfig from './next-i18next.config.js'
|
import i18nConfig from './next-i18next.config.js'
|
||||||
|
|
||||||
const config = configBuilder('dev')
|
const config = configBuilder('dev')
|
|
@ -3,16 +3,14 @@
|
||||||
"version": "2.21.0-rc.0",
|
"version": "2.21.0-rc.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev -p 3002",
|
"dev": "node --experimental-json-modules ./node_modules/.bin/next dev -p 8000",
|
||||||
"develop": "next dev -p 3002",
|
"develop": "next dev -p 3002",
|
||||||
"prebuild": "SITE=dev node ../freesewing.shared/prebuild/index.mjs",
|
"prebuild": "SITE=dev node --experimental-json-modules ../shared/prebuild/index.mjs",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"export": "yarn prebuild && next build && next export && node scripts/algolia.mjs",
|
"export": "yarn prebuild && next build && next export && node scripts/algolia.mjs",
|
||||||
"start": "next start -p 3002",
|
"start": "next start -p 3002",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"testdeploy": "next build && next export && netlify-cli deploy",
|
"serve": "pm2 start npm --name 'dev' -- run start"
|
||||||
"deploy": "next build && next export && netlify-cli deploy --prod",
|
|
||||||
"serve": "pm2 start npm --name 'freesewing.dev' -- run start"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@heroicons/react": "^1.0.5",
|
"@heroicons/react": "^1.0.5",
|
107
sites/dev/pages/blog/index.js
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
import Page from 'site/components/wrappers/page.js'
|
||||||
|
import useApp from 'site/hooks/useApp.js'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import TimeAgo from 'react-timeago'
|
||||||
|
import { strapiHost } from 'shared/config/freesewing.mjs'
|
||||||
|
import { strapiImage } from 'shared/utils'
|
||||||
|
import { useTranslation } from 'next-i18next'
|
||||||
|
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||||
|
|
||||||
|
const strapi = "https://posts.freesewing.org"
|
||||||
|
const textShadow = {
|
||||||
|
style: {
|
||||||
|
textShadow: "1px 1px 1px #000000, -1px -1px 1px #000000, 1px -1px 1px #000000, -1px 1px 1px #000000, 2px 2px 1px #000000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Preview = ({ app, post }) => (
|
||||||
|
<div className="shadow rounded-lg">
|
||||||
|
<Link href={`/blog/${post.slug}`}>
|
||||||
|
<a title={post.title} className="hover:underline">
|
||||||
|
<div className="bg-base-100 w-full aspect-video shadow flex flex-column items-end rounded-lg" style={{
|
||||||
|
backgroundImage: `url(${strapi}${post.image.sizes.medium.url})`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
}}>
|
||||||
|
<div className="grow"></div>
|
||||||
|
<div className="text-right mb-3 lg:mb-8">
|
||||||
|
<div className={`
|
||||||
|
bg-neutral text-neutral-content bg-opacity-40 text-right
|
||||||
|
px-4 py-1
|
||||||
|
lg:px-8 lg:py-4
|
||||||
|
|
||||||
|
`}>
|
||||||
|
<h5 className={`
|
||||||
|
text-neutral-content
|
||||||
|
text-xl font-bold
|
||||||
|
md:text-2xl md:font-normal
|
||||||
|
xl:text-3xl
|
||||||
|
`} {...textShadow}
|
||||||
|
>
|
||||||
|
{post.title}
|
||||||
|
</h5>
|
||||||
|
<p className={`
|
||||||
|
hidden md:block
|
||||||
|
m-0 p-1 -mt-2
|
||||||
|
text-neutral-content
|
||||||
|
leading-normal text-sm font-normal
|
||||||
|
opacity-70
|
||||||
|
`}{ ...textShadow}>
|
||||||
|
<TimeAgo date={post.date} /> by <strong>{post.author}</strong>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
const BlogIndexPage = (props) => {
|
||||||
|
const app = useApp()
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Page app={app} title={t('blog')} slug='blog'>
|
||||||
|
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2 max-w-7xl">
|
||||||
|
{props.posts.map(post => <Preview app={app} post={post} key={post.slug}/>)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</Page>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BlogIndexPage
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getStaticProps() is used to fetch data at build-time.
|
||||||
|
*
|
||||||
|
* On this page, it is loading the blog content from strapi.
|
||||||
|
*
|
||||||
|
* This, in combination with getStaticPaths() below means this
|
||||||
|
* page will be used to render/generate all blog content.
|
||||||
|
*
|
||||||
|
* To learn more, see: https://nextjs.org/docs/basic-features/data-fetching
|
||||||
|
*/
|
||||||
|
export async function getStaticProps({ params, locale }) {
|
||||||
|
|
||||||
|
const posts = await fetch(
|
||||||
|
`${strapiHost}/blogposts?_locale=en&_sort=date:DESC&dev_eq=true`
|
||||||
|
)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => data)
|
||||||
|
.catch(err => console.log(err))
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
posts: posts.map(post => ({
|
||||||
|
slug: post.slug,
|
||||||
|
title: post.title,
|
||||||
|
date: post.date,
|
||||||
|
author: post.author.displayname,
|
||||||
|
image: strapiImage(post.image, ['medium']),
|
||||||
|
})),
|
||||||
|
...(await serverSideTranslations(locale)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
5
sites/dev/postcss.config.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
// Can't seem to make this work as ESM
|
||||||
|
const config = require('../shared/config/postcss.config.js')
|
||||||
|
|
||||||
|
module.exports = config
|
||||||
|
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 313 KiB After Width: | Height: | Size: 313 KiB |
4
sites/dev/tailwind.config.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
// Can't seem to make this work as ESM
|
||||||
|
const config = require('../shared/config/tailwind.config.js')
|
||||||
|
|
||||||
|
module.exports = config
|
|
@ -1,78 +0,0 @@
|
||||||
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
|
|
|
@ -1,115 +0,0 @@
|
||||||
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
|
|
|
@ -1,3 +0,0 @@
|
||||||
import i18n from '../freesewing.shared/config/i18n.config.mjs'
|
|
||||||
|
|
||||||
export default i18n()
|
|
|
@ -1,88 +0,0 @@
|
||||||
import Page from 'shared/components/wrappers/page.js'
|
|
||||||
import useApp from 'site/hooks/useApp.js'
|
|
||||||
import Link from 'next/link'
|
|
||||||
import { posts } from 'site/prebuild/strapi.blog.en.js'
|
|
||||||
import orderBy from 'lodash.orderby'
|
|
||||||
import TimeAgo from 'react-timeago'
|
|
||||||
import Head from 'next/head'
|
|
||||||
import HelpUs from 'site/components/help-us.js'
|
|
||||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
|
||||||
|
|
||||||
const strapi = "https://posts.freesewing.org"
|
|
||||||
|
|
||||||
const Preview = ({ app, post }) => (
|
|
||||||
<div className="theme-gradient p-1 hover:p-0 hover:mb-1 hover:pointer transition-all">
|
|
||||||
<Link href={`/blog/${post.slug}`}>
|
|
||||||
<a title={post.title} className="hover:underline">
|
|
||||||
<div className="bg-base-100 w-full aspect-video shadow flex flex-column items-end" style={{
|
|
||||||
backgroundImage: `url(${strapi}${post.img})`,
|
|
||||||
backgroundSize: 'cover',
|
|
||||||
}}>
|
|
||||||
<div className="grow"></div>
|
|
||||||
<div className="text-right">
|
|
||||||
<div className={`
|
|
||||||
bg-neutral text-neutral-content
|
|
||||||
bg-opacity-80
|
|
||||||
px-4 text-right
|
|
||||||
`}>
|
|
||||||
<h5 className={`
|
|
||||||
text-neutral-content
|
|
||||||
text-xl font-normal
|
|
||||||
md:text-2xl md:font-light
|
|
||||||
`}>
|
|
||||||
{post.title}
|
|
||||||
</h5>
|
|
||||||
<p className={`
|
|
||||||
m-0 p-1 -mt-2
|
|
||||||
text-neutral-content
|
|
||||||
opacity-50
|
|
||||||
leading-normal text-sm font-normal
|
|
||||||
`}>
|
|
||||||
<TimeAgo date={post.date} /> by {post.author}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
const BlogIndexPage = (props) => {
|
|
||||||
const app = useApp()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Page app={app} title='FreeSewing Development Blog' slug='blog'>
|
|
||||||
<Head>
|
|
||||||
<meta property="og:title" content="FreeSewing Developers Blog" key="title" />
|
|
||||||
<meta property="og:type" content="article" key='type' />
|
|
||||||
<meta property="og:description" content="Content for developers and contributors alike. Strictly no sewing stuff" key='type' />
|
|
||||||
<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/blog" 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/blog" key='url' />
|
|
||||||
<meta property="og:locale" content="en_US" key='locale' />
|
|
||||||
<meta property="og:site_name" content="freesewing.dev" key='site' />
|
|
||||||
</Head>
|
|
||||||
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
|
||||||
{Object.values(orderBy(posts, ['date'], ['desc']))
|
|
||||||
.map(post => <Preview app={app} post={post} key={post.slug}/>)
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<HelpUs slug='/blog' />
|
|
||||||
</Page>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default BlogIndexPage
|
|
||||||
|
|
||||||
export async function getStaticProps({ locale }) {
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
...(await serverSideTranslations('en')),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
import i18n from '../freesewing.shared/config/i18n.config.mjs'
|
|
||||||
|
|
||||||
export default i18n()
|
|
|
@ -1,46 +0,0 @@
|
||||||
import path from 'path'
|
|
||||||
import { readdirSync } from 'fs'
|
|
||||||
import i18nConfig from './next-i18next.config.js'
|
|
||||||
|
|
||||||
const getDirectories = source =>
|
|
||||||
readdirSync(source, { withFileTypes: true })
|
|
||||||
.filter(dirent => dirent.isDirectory())
|
|
||||||
.map(dirent => dirent.name)
|
|
||||||
|
|
||||||
const pkgs = getDirectories(path.resolve(`../`))
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
experimental: {
|
|
||||||
externalDir: true,
|
|
||||||
},
|
|
||||||
i18n: i18nConfig.i18n,
|
|
||||||
pageExtensions: [ 'js' ],
|
|
||||||
webpack: (config, options) => {
|
|
||||||
|
|
||||||
// YAML support
|
|
||||||
config.module.rules.push({
|
|
||||||
test: /\.ya?ml$/,
|
|
||||||
type: 'json',
|
|
||||||
use: 'yaml-loader'
|
|
||||||
})
|
|
||||||
|
|
||||||
// Suppress warnings about importing version from package.json
|
|
||||||
// We'll deal with it in v3 of FreeSewing
|
|
||||||
config.ignoreWarnings = [
|
|
||||||
/only default export is available soon/
|
|
||||||
]
|
|
||||||
|
|
||||||
// Aliases
|
|
||||||
config.resolve.alias.shared = path.resolve('../freesewing.shared/')
|
|
||||||
config.resolve.alias.site = path.resolve(`.`)
|
|
||||||
config.resolve.alias.lib = path.resolve(`./lib`)
|
|
||||||
config.resolve.alias.pkgs = path.resolve(`../`)
|
|
||||||
// This forces webpack to load the code from source, rather than compiled bundle
|
|
||||||
for (const pkg of pkgs) {
|
|
||||||
config.resolve.alias[`@freesewing/${pkg}$`] = path.resolve(`../${pkg}/src/index.js`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default config
|
|
|
@ -1,5 +0,0 @@
|
||||||
// Can't seem to make this work as ESM
|
|
||||||
const config = require('../freesewing.shared/config/postcss.config.js')
|
|
||||||
|
|
||||||
module.exports = config
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../../../freesewing.dev/public/img/splash.jpg
|
|
|
@ -1,4 +0,0 @@
|
||||||
// Can't seem to make this work as ESM
|
|
||||||
const config = require('../freesewing.shared/config/tailwind.config.js')
|
|
||||||
|
|
||||||
module.exports = config
|
|
|
@ -1,5 +0,0 @@
|
||||||
// Can't seem to make this work as ESM
|
|
||||||
const config = require('../freesewing.shared/config/postcss.config.js')
|
|
||||||
|
|
||||||
module.exports = config
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
// Can't seem to make this work as ESM
|
|
||||||
const config = require('../freesewing.shared/config/tailwind.config.js')
|
|
||||||
|
|
||||||
module.exports = config
|
|
|
@ -1,60 +0,0 @@
|
||||||
{
|
|
||||||
"accessories": [
|
|
||||||
"florence",
|
|
||||||
"florent",
|
|
||||||
"hi",
|
|
||||||
"holmes",
|
|
||||||
"hortensia",
|
|
||||||
"lucy",
|
|
||||||
"trayvon"
|
|
||||||
],
|
|
||||||
"blocks": [
|
|
||||||
"bella",
|
|
||||||
"bent",
|
|
||||||
"brian",
|
|
||||||
"titan"
|
|
||||||
],
|
|
||||||
"garments": [
|
|
||||||
"aaron",
|
|
||||||
"albert",
|
|
||||||
"bee",
|
|
||||||
"benjamin",
|
|
||||||
"breanna",
|
|
||||||
"bruce",
|
|
||||||
"carlita",
|
|
||||||
"carlton",
|
|
||||||
"cathrin",
|
|
||||||
"charlie",
|
|
||||||
"cornelius",
|
|
||||||
"diana",
|
|
||||||
"huey",
|
|
||||||
"hugo",
|
|
||||||
"jaeger",
|
|
||||||
"lunetius",
|
|
||||||
"paco",
|
|
||||||
"penelope",
|
|
||||||
"sandy",
|
|
||||||
"shin",
|
|
||||||
"simon",
|
|
||||||
"simone",
|
|
||||||
"sven",
|
|
||||||
"tamiko",
|
|
||||||
"teagan",
|
|
||||||
"theo",
|
|
||||||
"tiberius",
|
|
||||||
"unice",
|
|
||||||
"ursula",
|
|
||||||
"wahid",
|
|
||||||
"walburga",
|
|
||||||
"waralee",
|
|
||||||
"yuri"
|
|
||||||
],
|
|
||||||
"utilities": [
|
|
||||||
"examples",
|
|
||||||
"legend",
|
|
||||||
"plugintest",
|
|
||||||
"rendertest",
|
|
||||||
"tutorial"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
export const strapiHost = 'https://posts.freesewing.org'
|
|
||||||
|
|
||||||
export const monorepo = 'https://github.com/freesewing/freesewing'
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
const pitches = [
|
|
||||||
'This website does not track you',
|
|
||||||
"Come in, we're open",
|
|
||||||
'Made-to-measure sewing patterns',
|
|
||||||
]
|
|
||||||
|
|
||||||
export default pitches
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
// Stores state in local storage
|
// Stores state in local storage
|
||||||
import useLocalStorage from 'shared/hooks/useLocalStorage.js'
|
import useLocalStorage from 'shared/hooks/useLocalStorage.js'
|
||||||
// Patterns
|
// Designs
|
||||||
import patterns from 'shared/config/designs.json'
|
import { designsByType } from 'config/software/index.mjs'
|
||||||
// Locale and translation
|
// Locale and translation
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
import { capitalize } from 'shared/utils'
|
import { capitalize } from 'shared/utils.mjs'
|
||||||
import { formatVersionUri } from '../components/version-picker.js'
|
import { formatVersionUri } from '../components/version-picker.js'
|
||||||
import useVersion from 'site/hooks/useVersion.js'
|
import useVersion from 'site/hooks/useVersion.js'
|
||||||
import useTheme from 'shared/hooks/useTheme'
|
import useTheme from 'shared/hooks/useTheme'
|
||||||
|
@ -14,44 +14,46 @@ import useTheme from 'shared/hooks/useTheme'
|
||||||
const initialNavigation = (t, version) => {
|
const initialNavigation = (t, version) => {
|
||||||
const base = {
|
const base = {
|
||||||
accessories: {
|
accessories: {
|
||||||
__title: t('accessoryPatterns'),
|
__title: t('accessoryDesigns'),
|
||||||
__order: t('accessoryPatterns'),
|
|
||||||
__linktitle: t('accessoryPatterns'),
|
|
||||||
__slug: 'accessories',
|
__slug: 'accessories',
|
||||||
},
|
},
|
||||||
blocks: {
|
blocks: {
|
||||||
__title: t('blockPatterns'),
|
__title: t('blockDesigns'),
|
||||||
__order: t('blockPatterns'),
|
|
||||||
__linktitle: t('blockPatterns'),
|
|
||||||
__slug: 'blocks',
|
__slug: 'blocks',
|
||||||
},
|
},
|
||||||
garments: {
|
garments: {
|
||||||
__title: t('garmentPatterns'),
|
__title: t('garmentDesigns'),
|
||||||
__order: t('garmentPatterns'),
|
|
||||||
__linktitle: t('garmentPatterns'),
|
|
||||||
__slug: t('garments'),
|
__slug: t('garments'),
|
||||||
},
|
},
|
||||||
utilities: {
|
utilities: {
|
||||||
__title: t('utilityPatterns'),
|
__title: t('utilityDesigns'),
|
||||||
__order: t('utilityPatterns'),
|
|
||||||
__linktitle: t('utilityPatterns'),
|
|
||||||
__slug: 'utilities',
|
__slug: 'utilities',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for (const type in patterns) {
|
for (const type in designsByType) {
|
||||||
for (const design of patterns[type]) {
|
for (const design in designsByType[type]) {
|
||||||
base[type][design] = {
|
base[type][design] = {
|
||||||
__title: capitalize(design),
|
__title: capitalize(design),
|
||||||
__order: design,
|
|
||||||
__linktitle: capitalize(design),
|
|
||||||
__slug: formatVersionUri(version,design)
|
__slug: formatVersionUri(version,design)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (const key in base) {
|
||||||
|
base[key].__order = base[key].__title
|
||||||
|
base[key].__linktitle = base[key].__title
|
||||||
|
}
|
||||||
|
|
||||||
return base
|
return base
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const designs = {}
|
||||||
|
for (const type in designsByType) {
|
||||||
|
designs[type] = []
|
||||||
|
for (const design in designsByType[type]) {
|
||||||
|
designs[type].push(design)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function useApp(full = true) {
|
function useApp(full = true) {
|
||||||
|
|
||||||
// Version
|
// Version
|
||||||
|
@ -68,7 +70,7 @@ function useApp(full = true) {
|
||||||
const [primaryMenu, setPrimaryMenu] = useState(false)
|
const [primaryMenu, setPrimaryMenu] = useState(false)
|
||||||
const [navigation, setNavigation] = useState(initialNavigation(t, version))
|
const [navigation, setNavigation] = useState(initialNavigation(t, version))
|
||||||
const [slug, setSlug] = useState('/')
|
const [slug, setSlug] = useState('/')
|
||||||
const [pattern, setPattern] = useState(false)
|
const [design, setDesign] = useState(false)
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
|
|
||||||
// State methods
|
// State methods
|
||||||
|
@ -77,12 +79,12 @@ function useApp(full = true) {
|
||||||
return {
|
return {
|
||||||
// Static vars
|
// Static vars
|
||||||
site: 'lab',
|
site: 'lab',
|
||||||
patterns,
|
designs,
|
||||||
|
|
||||||
// State
|
// State
|
||||||
loading,
|
loading,
|
||||||
navigation,
|
navigation,
|
||||||
pattern,
|
design,
|
||||||
primaryMenu,
|
primaryMenu,
|
||||||
slug,
|
slug,
|
||||||
theme,
|
theme,
|
||||||
|
@ -90,7 +92,7 @@ function useApp(full = true) {
|
||||||
// State setters
|
// State setters
|
||||||
setLoading,
|
setLoading,
|
||||||
setNavigation,
|
setNavigation,
|
||||||
setPattern,
|
setDesign,
|
||||||
setPrimaryMenu,
|
setPrimaryMenu,
|
||||||
setSlug,
|
setSlug,
|
||||||
setTheme,
|
setTheme,
|
3
sites/lab/i18n.config.mjs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import i18n from '../shared/config/i18n.config.mjs'
|
||||||
|
|
||||||
|
export default i18n()
|
59
sites/lab/next.config.mjs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import path from 'path'
|
||||||
|
import { readdirSync } from 'fs'
|
||||||
|
import i18nConfig from './next-i18next.config.js'
|
||||||
|
import { designs, plugins, packages } from '../../config/software/index.mjs'
|
||||||
|
|
||||||
|
const getDirectories = source =>
|
||||||
|
readdirSync(source, { withFileTypes: true })
|
||||||
|
.filter(dirent => dirent.isDirectory())
|
||||||
|
.map(dirent => dirent.name)
|
||||||
|
|
||||||
|
const pkgs = getDirectories(path.resolve(`../`))
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
experimental: {
|
||||||
|
externalDir: true,
|
||||||
|
},
|
||||||
|
i18n: i18nConfig.i18n,
|
||||||
|
pageExtensions: [ 'js' ],
|
||||||
|
webpack: (config, options) => {
|
||||||
|
|
||||||
|
// YAML support
|
||||||
|
config.module.rules.push({
|
||||||
|
test: /\.ya?ml$/,
|
||||||
|
type: 'json',
|
||||||
|
use: 'yaml-loader'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Suppress warnings about importing version from package.json
|
||||||
|
// We'll deal with it in v3 of FreeSewing
|
||||||
|
config.ignoreWarnings = [
|
||||||
|
/only default export is available soon/
|
||||||
|
]
|
||||||
|
|
||||||
|
// Aliases
|
||||||
|
config.resolve.alias.shared = path.resolve('../shared/')
|
||||||
|
config.resolve.alias.site = path.resolve('.')
|
||||||
|
config.resolve.alias.lib = path.resolve('./lib')
|
||||||
|
config.resolve.alias.config = path.resolve('../../config/')
|
||||||
|
config.resolve.alias.designs = path.resolve('../../designs/')
|
||||||
|
config.resolve.alias.plugins = path.resolve('../../plugins/')
|
||||||
|
config.resolve.alias.pkgs = path.resolve('../../packages/')
|
||||||
|
|
||||||
|
// Load designs from source, rather than compiled package
|
||||||
|
for (const design in designs) {
|
||||||
|
config.resolve.alias[`@freesewing/${design}$`] = path.resolve(`../../designs/${design}/src/index.js`)
|
||||||
|
}
|
||||||
|
// Load plugins from source, rather than compiled package
|
||||||
|
for (const plugin in plugins) {
|
||||||
|
config.resolve.alias[`@freesewing/${plugin}$`] = path.resolve(`../../plugins/${plugin}/src/index.js`)
|
||||||
|
}
|
||||||
|
// Load these from source, rather than compiled package
|
||||||
|
for (const pkg of ['core', 'config-helpers', 'i18n', 'models']) {
|
||||||
|
config.resolve.alias[`@freesewing/${pkg}$`] = path.resolve(`../../packages/${pkg}/src/index.js`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default config
|
|
@ -3,17 +3,15 @@
|
||||||
"version": "2.21.0-rc.0",
|
"version": "2.21.0-rc.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev -p 3002",
|
"dev": "node --experimental-json-modules ./node_modules/.bin/next dev -p 8000",
|
||||||
"develop": "next dev -p 3002",
|
"develop": "next dev -p 8000",
|
||||||
"prebuild": "cd ../utils && npm run build && cd - && SITE=lab node ../freesewing.shared/prebuild/index.mjs",
|
"prebuild": "SITE=lab node --experimental-json-modules ../shared/prebuild/index.mjs",
|
||||||
"cibuild": "yarn prebuild && next build",
|
"cibuild": "yarn prebuild && next build",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"export": "yarn prebuild && next build && next export",
|
"export": "yarn prebuild && next build && next export",
|
||||||
"start": "next start -p 3002",
|
"start": "next start -p 3002",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"testdeploy": "next build && next export && netlify-cli deploy",
|
"serve": "pm2 start npm --name 'dev' -- run start"
|
||||||
"deploy": "next build && next export && netlify-cli deploy --prod",
|
|
||||||
"serve": "pm2 start npm --name 'freesewing.dev' -- run start"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@heroicons/react": "^1.0.5",
|
"@heroicons/react": "^1.0.5",
|
|
@ -4,14 +4,14 @@ import WorkbenchWrapper from 'shared/components/wrappers/workbench.js'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import Layout from 'site/components/layouts/lab'
|
import Layout from 'site/components/layouts/lab'
|
||||||
|
|
||||||
const WorkbenchPage = ({ pattern }) => {
|
const WorkbenchPage = ({ design }) => {
|
||||||
const app = useApp()
|
const app = useApp()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { preload, from } = router.query
|
const { preload, from } = router.query
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page app={app}>
|
<Page app={app}>
|
||||||
<WorkbenchWrapper {...{ app, pattern, preload, from }} layout={Layout} />
|
<WorkbenchWrapper {...{ app, design, preload, from }} layout={Layout} />
|
||||||
</Page>
|
</Page>
|
||||||
)
|
)
|
||||||
}
|
}
|