-
-
{t('mainSections')}
-
-
-
-
{t('currentSection')}
-
-
+export const ModalMenu = () => (
+
+
+
+
+
+
+ The sitemap lists all pages on this website. It can give you a good idea of what you can
+ find here.
+
-
- )
-}
+
+
+)
diff --git a/sites/lab/components/navigation/sections-menu.mjs b/sites/lab/components/navigation/sections-menu.mjs
deleted file mode 100644
index 5472803a021..00000000000
--- a/sites/lab/components/navigation/sections-menu.mjs
+++ /dev/null
@@ -1,46 +0,0 @@
-import { useContext } from 'react'
-import Link from 'next/link'
-import { icons, ns as sectionsNs } from 'shared/components/navigation/primary.mjs'
-import { useTranslation } from 'next-i18next'
-import orderBy from 'lodash.orderby'
-import { colors } from 'shared/components/header.mjs'
-import { NavigationContext } from 'shared/context/navigation-context.mjs'
-import { HelpIcon } from 'shared/components/icons.mjs'
-
-export const ns = sectionsNs
-
-export const SectionsMenu = () => {
- const { t } = useTranslation(ns)
- const { sections = false } = useContext(NavigationContext)
- if (!sections) return null
-
- // Ensure each page as an `o` key so we can put them in order
- const sortableSections = sections.map((s) => ({ ...s, o: s.o ? s.o : s.t }))
- const output = []
- let i = 1
- for (const page of orderBy(sortableSections, ['o', 't'])) {
- const item = (
-
-
-
-
{page.t}
- {icons[page.s] ? icons[page.s]('w-10 h-10') : }
-
-
- {t(page.s + 'About')}
-
-
-
- )
- i++
- output.push(item)
- }
-
- return
{output}
-}
diff --git a/sites/lab/prebuild.mjs b/sites/lab/prebuild.mjs
new file mode 100644
index 00000000000..b43b205f9a5
--- /dev/null
+++ b/sites/lab/prebuild.mjs
@@ -0,0 +1,27 @@
+import { prebuildRunner } from '../shared/prebuild/runner.mjs'
+
+/*
+ * This handles the prebuild step for FreeSewing.dev
+ * It runs via an NPM run script, so in a pure NodeJS context
+ *
+ * See the org or dev site for an example with inline-comments
+ */
+prebuildRunner({
+ site: 'lab',
+ prebuild: {
+ // Always prebuild
+ designs: true,
+ i18n: true,
+ navigation: true,
+ // Prebuild in production
+ favicon: 'productionOnly',
+ ogImages: 'productionOnly',
+ // Never prebuild
+ docs: false,
+ contributors: false,
+ crowdin: false,
+ git: false,
+ patrons: false,
+ posts: false,
+ },
+})
diff --git a/sites/shared/prebuild/navigation.mjs b/sites/shared/prebuild/navigation.mjs
index b54b6379cbb..12fb003a926 100644
--- a/sites/shared/prebuild/navigation.mjs
+++ b/sites/shared/prebuild/navigation.mjs
@@ -1,13 +1,15 @@
+import allLanguages from '../../../config/languages.json' assert { type: 'json' }
import path from 'path'
import fs from 'fs'
import set from 'lodash.set'
import orderBy from 'lodash.orderby'
import { extendSiteNav as dev } from './sitenav-dev.mjs'
import { extendSiteNav as org } from './sitenav-org.mjs'
+import { extendSiteNav as lab } from './sitenav-lab.mjs'
import { pageHasChildren } from '../utils.mjs'
import { header } from './shared.mjs'
-const extendNav = { dev, org }
+const extendNav = { dev, org, lab }
/*
* A method to recursively add the ordered slugs to the LUT
@@ -47,7 +49,7 @@ export const orderedSlugLut = (nav) => {
* Main method that does what needs doing
*/
export const prebuildNavigation = async (store) => {
- const { docs, site, posts = false } = store
+ const { site, docs = false, posts = false } = store
/*
* Since this is written to disk and loaded as JSON, we minimize
* the data to load by using the following 1-character keys:
@@ -60,23 +62,24 @@ export const prebuildNavigation = async (store) => {
const all = {
sitenav: '',
}
- const locales = []
- for (const lang in docs) {
- locales.push(lang)
+ const locales = docs ? Object.keys(docs) : allLanguages
+ for (const lang of locales) {
sitenav[lang] = {}
- // Handle docs
- for (const slug of Object.keys(docs[lang]).sort()) {
- const page = docs[lang][slug]
- const val = {
- t: page.t,
- s: slug,
+ // Handle docs if there are any
+ if (docs[lang]) {
+ for (const slug of Object.keys(docs[lang]).sort()) {
+ const page = docs[lang][slug]
+ const val = {
+ t: page.t,
+ s: slug,
+ }
+ if (page.o) val.o = page.o
+ set(sitenav, [lang, ...slug.split('/')], val)
}
- if (page.o) val.o = page.o
- set(sitenav, [lang, ...slug.split('/')], val)
}
- // Handle posts
+ // Handle posts if there are any
if (posts) {
for (const type in posts) {
for (const [slug, post] of Object.entries(posts[type].posts[lang])) {
@@ -118,6 +121,9 @@ export const prebuildNavigation = async (store) => {
`${header}${all.sitenav}export const siteNav = { ${locales.join(',')} }`
)
+ // In the lab, there will be no navigation set in the store
+ if (!store.navigation) store.navigation = {}
+
// Update the store
store.navigation.sitenav = sitenav
diff --git a/sites/shared/prebuild/sitenav-lab.mjs b/sites/shared/prebuild/sitenav-lab.mjs
new file mode 100644
index 00000000000..ed325b73789
--- /dev/null
+++ b/sites/shared/prebuild/sitenav-lab.mjs
@@ -0,0 +1,205 @@
+import { freeSewingConfig as conf } from '../config/freesewing.config.mjs'
+import { designs, tags } from '../config/designs.mjs'
+// Translation via i18next directly
+import i18next from 'i18next'
+// Actual translations for various languages
+// EN
+import accountEn from '../../lab/public/locales/en/sections.json' assert { type: 'json' }
+import designsEn from '../../lab/public/locales/en/sections.json' assert { type: 'json' }
+import sectionsEn from '../../lab/public/locales/en/sections.json' assert { type: 'json' }
+import tagsEn from '../../lab/public/locales/en/sections.json' assert { type: 'json' }
+// DE
+import accountDe from '../../lab/public/locales/de/sections.json' assert { type: 'json' }
+import designsDe from '../../lab/public/locales/de/sections.json' assert { type: 'json' }
+import sectionsDe from '../../lab/public/locales/de/sections.json' assert { type: 'json' }
+import tagsDe from '../../lab/public/locales/de/sections.json' assert { type: 'json' }
+// ES
+import accountEs from '../../lab/public/locales/es/sections.json' assert { type: 'json' }
+import designsEs from '../../lab/public/locales/es/sections.json' assert { type: 'json' }
+import sectionsEs from '../../lab/public/locales/es/sections.json' assert { type: 'json' }
+import tagsEs from '../../lab/public/locales/es/sections.json' assert { type: 'json' }
+// FR
+import accountFr from '../../lab/public/locales/fr/sections.json' assert { type: 'json' }
+import designsFr from '../../lab/public/locales/fr/sections.json' assert { type: 'json' }
+import sectionsFr from '../../lab/public/locales/fr/sections.json' assert { type: 'json' }
+import tagsFr from '../../lab/public/locales/fr/sections.json' assert { type: 'json' }
+// NL
+import accountNl from '../../lab/public/locales/nl/sections.json' assert { type: 'json' }
+import designsNl from '../../lab/public/locales/nl/sections.json' assert { type: 'json' }
+import sectionsNl from '../../lab/public/locales/nl/sections.json' assert { type: 'json' }
+import tagsNl from '../../lab/public/locales/nl/sections.json' assert { type: 'json' }
+// UK
+import accountUk from '../../lab/public/locales/uk/sections.json' assert { type: 'json' }
+import designsUk from '../../lab/public/locales/uk/sections.json' assert { type: 'json' }
+import sectionsUk from '../../lab/public/locales/uk/sections.json' assert { type: 'json' }
+import tagsUk from '../../lab/public/locales/uk/sections.json' assert { type: 'json' }
+
+/*
+ * Construct an object we can load the translations from
+ */
+const translations = {
+ en: {
+ account: accountEn,
+ design: designsEn,
+ sections: sectionsEn,
+ tags: tagsEn,
+ },
+ de: {
+ account: accountDe,
+ design: designsDe,
+ sections: sectionsDe,
+ tags: tagsDe,
+ },
+ es: {
+ account: accountEs,
+ design: designsEs,
+ sections: sectionsEs,
+ tags: tagsEs,
+ },
+ fr: {
+ account: accountFr,
+ design: designsFr,
+ sections: sectionsFr,
+ tags: tagsFr,
+ },
+ nl: {
+ account: accountNl,
+ design: designsNl,
+ sections: sectionsNl,
+ tags: tagsNl,
+ },
+ uk: {
+ account: accountUk,
+ design: designsUk,
+ sections: sectionsUk,
+ tags: tagsUk,
+ },
+}
+
+/* Remember Mc_Shifton:
+ * Note: Set 'm' to truthy to show this as a main section in the side-navigation (optional)
+ * Note: Set 'c' to set the control level to hide things from users (optional)
+ * Note: Set 's' to the slug (optional insofar as it's not a real page (a spacer for the header))
+ * Note: Set '_' to never show the page in the site navigation (like the tags pages)
+ * Note: Set 'h' to indicate this is a top-level page that should be hidden from the side-nav (like search)
+ * Note: Set 'i' when something should be included as top-level in the collapse side-navigation (optional)
+ * Note: Set 'f' to add the page to the footer
+ * Note: Set 't' to the title
+ * Note: Set 'o' to set the order (optional)
+ * Note: Set 'n' to mark this as a noisy entry that should always be closed unless active (like blog)
+ */
+export const extendSiteNav = (pages, lang) => {
+ const resources = {}
+ resources[lang] = translations[lang]
+ i18next.init({
+ lng: lang,
+ resources,
+ })
+ const { t } = i18next
+
+ const addThese = {
+ designs: {
+ m: 1,
+ s: 'designs',
+ t: t('sections:designs'),
+ n: 1,
+ tags: {
+ _: 1,
+ s: 'designs/tags',
+ t: t('design:tags'),
+ o: 'aaa',
+ },
+ },
+ patterns: {
+ m: 1,
+ s: 'patterns',
+ t: t('sections:patterns'),
+ },
+ sets: {
+ m: 1,
+ s: 'sets',
+ t: t('sections:sets'),
+ },
+ docs: {
+ m: 1,
+ s: 'docs',
+ t: t('sections:docs'),
+ },
+ code: {
+ m: 1,
+ s: 'code',
+ t: t('sections:code'),
+ },
+ account: {
+ m: 1,
+ s: 'account',
+ t: t('sections:account'),
+ n: 1,
+ reload: {
+ s: `account/reload`,
+ t: t(`account:reload`),
+ },
+ },
+ // Top-level pages that are not in the sections menu
+ new: {
+ m: 1,
+ s: 'new',
+ h: 1,
+ t: t('sections:new'),
+ pattern: {
+ t: t('patternNew'),
+ s: 'new/pattern',
+ o: 10,
+ },
+ },
+ profile: {
+ s: 'profile',
+ h: 1,
+ t: t('yourProfile'),
+ },
+ sitemap: {
+ s: 'sitemap',
+ h: 1,
+ t: t('sitemap'),
+ },
+ }
+
+ for (const section in conf.account.fields) {
+ for (const [field, controlScore] of Object.entries(conf.account.fields[section])) {
+ addThese.account[field] = {
+ s: `account/${field}`,
+ t: t(`account:${field}`),
+ c: controlScore,
+ }
+ }
+ }
+
+ for (const design in designs) {
+ // addThese.designs[design] = {
+ // t: t(`designs:${design}.t`),
+ // s: `designs/${design}`,
+ // }
+ addThese.new.pattern[design] = {
+ s: `new/${design}`,
+ t: t(`account:generateANewThing`, { thing: t(`designs:${design}.t`) }),
+ }
+ }
+
+ for (const tag of tags) {
+ addThese.designs.tags[tag] = {
+ s: `designs/tags/${tag}`,
+ t: t(`tags:${tag}`),
+ }
+ }
+
+ // Set order on main sections
+ addThese.designs.o = 10
+ addThese.patterns.o = 20
+ addThese.sets.o = 30
+ addThese.docs.o = 40
+ addThese.code.o = 50
+ addThese.account.o = 80
+ addThese.new.o = 90
+
+ return { ...pages, ...addThese }
+}